occi 2.2.2 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +2 -2
- data/README.md +48 -18
- data/lib/occi/client.rb +54 -17
- data/lib/occi/collection.rb +25 -7
- data/lib/occi/core/action.rb +7 -0
- data/lib/occi/core/attribute_properties.rb +2 -2
- data/lib/occi/core/attributes.rb +2 -2
- data/lib/occi/core/category.rb +43 -23
- data/lib/occi/core/entity.rb +62 -67
- data/lib/occi/core/kind.rb +32 -5
- data/lib/occi/core/link.rb +14 -51
- data/lib/occi/core/mixin.rb +31 -5
- data/lib/occi/core/resource.rb +34 -33
- data/lib/occi/log.rb +16 -4
- data/lib/occi/model.rb +53 -47
- data/lib/occi/parser.rb +192 -65
- data/lib/occi/version.rb +1 -1
- data/spec/occi/client_spec.rb +12 -0
- data/spec/occi/log_spec.rb +2 -1
- data/spec/occi/model_spec.rb +43 -14
- data/spec/occi/parser_spec.rb +18 -3
- data/spec/occi/test.ova +0 -0
- metadata +6 -3
data/.yardopts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
--title "Documentation of the OCCI gem" --markup markdown
|
1
|
+
--title "Documentation of the OCCI gem" --markup markdown --private
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -31,7 +31,7 @@ GEM
|
|
31
31
|
multi_json (~> 1.0)
|
32
32
|
simplecov-html (~> 0.5.3)
|
33
33
|
simplecov-html (0.5.3)
|
34
|
-
uuidtools (2.1.
|
34
|
+
uuidtools (2.1.3)
|
35
35
|
yard (0.7.5)
|
36
36
|
yard-sinatra (1.0.0)
|
37
37
|
yard (~> 0.7)
|
@@ -51,6 +51,6 @@ DEPENDENCIES
|
|
51
51
|
rspec
|
52
52
|
rspec-http
|
53
53
|
simplecov
|
54
|
-
uuidtools
|
54
|
+
uuidtools (>= 2.1.3)
|
55
55
|
yard
|
56
56
|
yard-sinatra
|
data/README.md
CHANGED
@@ -17,24 +17,11 @@ Installation
|
|
17
17
|
|
18
18
|
gem install occi
|
19
19
|
|
20
|
-
### Latest version
|
21
|
-
|
22
|
-
Checkout latest version from GIT:
|
23
|
-
|
24
|
-
git clone git://github.com/gwdg/rOCCI.git
|
25
|
-
|
26
|
-
Change to rOCCI folder
|
27
|
-
|
28
|
-
cd rOCCI
|
29
|
-
|
30
|
-
Install dependencies for deployment
|
31
|
-
|
32
|
-
bundle install --deployment
|
33
|
-
|
34
20
|
Usage
|
35
21
|
-----
|
36
22
|
|
37
|
-
First require the gem
|
23
|
+
First require the gem, for Ruby 1.8.7 you also have to require rubygems
|
24
|
+
require 'rubygems'
|
38
25
|
require 'occi'
|
39
26
|
|
40
27
|
### Client
|
@@ -43,7 +30,7 @@ The OCCI gem includes a Client to simplify the usage of an OCCI endpoint.
|
|
43
30
|
|
44
31
|
To connect to an OCCI endpoint/server (e.g. running at http://localhost:3000/ ) use
|
45
32
|
|
46
|
-
client = OCCI::Client.new('http://
|
33
|
+
client = OCCI::Client.new('http://occi.cloud.gwdg.de:3300')
|
47
34
|
|
48
35
|
All available categories are automatically registered to the OCCI model during client initialization. You can get them via
|
49
36
|
|
@@ -112,11 +99,35 @@ the message header. As the text/plain and text/occi media type do not clearly di
|
|
112
99
|
category and a message with an entity which has a kind, it has to be specified if the message contains a category (e
|
113
100
|
.g. for user defined mixins)
|
114
101
|
|
115
|
-
OCCI messages can be parsed for example like
|
102
|
+
OCCI messages can be parsed to an OCCI collection for example like
|
116
103
|
|
117
104
|
media_type = text/plain
|
118
105
|
body = %Q|Category: compute; scheme="http://schemas.ogf.org/occi/infrastructure#"; class="kind"|
|
119
|
-
OCCI::Parser.parse(media_type,body)
|
106
|
+
collection=OCCI::Parser.parse(media_type,body)
|
107
|
+
|
108
|
+
### Parsing OVF / OVA files
|
109
|
+
|
110
|
+
Parsing of OVF/OVA files is partly supported and will be improved in future versions.
|
111
|
+
|
112
|
+
The example in [DMTF DSP 2021](http://www.dmtf.org/sites/default/files/standards/documents/DSP2021_1.0.0.tar) is
|
113
|
+
bundled with rOCCI and can be parsed to an OCCI collection with
|
114
|
+
|
115
|
+
require 'open-uri'
|
116
|
+
ova=open 'https://raw.github.com/gwdg/rOCCI/master/spec/occi/test.ova'
|
117
|
+
collection=OCCI::Parser.ova(ova.read)
|
118
|
+
|
119
|
+
Currently only the following entries of OVF files are parsed
|
120
|
+
|
121
|
+
* File in References
|
122
|
+
* Disk in the DiskSection
|
123
|
+
* Network in the NetworkSection
|
124
|
+
* in the VirutalSystemSection:
|
125
|
+
** Info
|
126
|
+
** in the VirtualHardwareSection the items regarding
|
127
|
+
*** Processor
|
128
|
+
*** Memory
|
129
|
+
*** Ethernet Adapter
|
130
|
+
*** Parallel port
|
120
131
|
|
121
132
|
### Using the OCCI model
|
122
133
|
|
@@ -125,6 +136,13 @@ The OCCI gem includes all OCCI Core classes necessary to handly arbitrary OCCI o
|
|
125
136
|
Changelog
|
126
137
|
---------
|
127
138
|
|
139
|
+
### Version 2.3
|
140
|
+
|
141
|
+
* OCCI objects are now initialized with a list of attributes instead of a hash. Thus it is easier to check which
|
142
|
+
attributes are expected by a class and helps prevent errors.
|
143
|
+
* Parsing of a subset of the OVF specification is supported. Further parts of the specification will be covered in
|
144
|
+
future versions of rOCCI.
|
145
|
+
|
128
146
|
### Version 2.2
|
129
147
|
|
130
148
|
OCCI Client added. The client simplifies the execution of OCCI commands and provides shortcuts for often used steps.
|
@@ -144,6 +162,18 @@ Version 1.X of the OCCI gem has been developed by retr0h and served as a simple
|
|
144
162
|
Development
|
145
163
|
-----------
|
146
164
|
|
165
|
+
Checkout latest version from GIT:
|
166
|
+
|
167
|
+
git clone git://github.com/gwdg/rOCCI.git
|
168
|
+
|
169
|
+
Change to rOCCI folder
|
170
|
+
|
171
|
+
cd rOCCI
|
172
|
+
|
173
|
+
Install dependencies for deployment
|
174
|
+
|
175
|
+
bundle install --deployment
|
176
|
+
|
147
177
|
### Code Documentation
|
148
178
|
|
149
179
|
[Code Documentation for rOCCI by YARD](http://rubydoc.info/github/gwdg/rOCCI/)
|
data/lib/occi/client.rb
CHANGED
@@ -8,22 +8,15 @@ module OCCI
|
|
8
8
|
headers 'Accept' => 'application/occi+json'
|
9
9
|
|
10
10
|
attr_reader :endpoint
|
11
|
-
|
12
|
-
attr_reader :compute
|
13
|
-
attr_reader :storage
|
14
|
-
attr_reader :network
|
11
|
+
attr_reader :model
|
15
12
|
|
16
13
|
def initialize(endpoint)
|
17
|
-
@endpoint
|
18
|
-
|
19
|
-
OCCI::Model.register_collection(collection)
|
20
|
-
@compute = OCCI::Model.get_by_id('http://schemas.ogf.org/occi/infrastructure#compute')
|
21
|
-
@storage = OCCI::Model.get_by_id('http://schemas.ogf.org/occi/infrastructure#storage')
|
22
|
-
@network = OCCI::Model.get_by_id('http://schemas.ogf.org/occi/infrastructure#network')
|
14
|
+
@endpoint = endpoint
|
15
|
+
@model = OCCI::Model.new(OCCI::Collection.new(get_model))
|
23
16
|
end
|
24
17
|
|
25
18
|
def get_model
|
26
|
-
|
19
|
+
get(@endpoint + '/-/').body
|
27
20
|
end
|
28
21
|
|
29
22
|
def post_mixin
|
@@ -60,15 +53,15 @@ module OCCI
|
|
60
53
|
resource.links = []
|
61
54
|
resources_to_link.each do |res|
|
62
55
|
link = OCCI::Link.new
|
63
|
-
link.kind = 'http://schemas.ogf.org/occi/infrastructure#storagelink' if
|
64
|
-
link.kind = 'http://schemas.ogf.org/occi/infrastructure#networkinterface' if
|
56
|
+
link.kind = 'http://schemas.ogf.org/occi/infrastructure#storagelink' if @model.get_by_id(res.kind).related_to? 'http://schemas.ogf.org/occi/infrastructure#storage'
|
57
|
+
link.kind = 'http://schemas.ogf.org/occi/infrastructure#networkinterface' if @model.get_by_id(res.kind).related_to? 'http://schemas.ogf.org/occi/infrastructure#network'
|
65
58
|
link.titlte "Link to #{res.title}"
|
66
59
|
link.target = res.location
|
67
60
|
resource.links << link
|
68
61
|
end
|
69
62
|
resource.check
|
70
63
|
collection = OCCI::Collection.new(:resources => [resource])
|
71
|
-
self.class.post(@endpoint + kind.location, { :body => collection.to_json, :headers => { 'Content-Type' => 'application/occi+json', 'Accept' => 'text/uri-list' }, :format => 'text/plain' }).
|
64
|
+
self.class.post(@endpoint + kind.location, { :body => collection.to_json, :headers => { 'Content-Type' => 'application/occi+json', 'Accept' => 'text/uri-list' }, :format => 'text/plain' }).body
|
72
65
|
end
|
73
66
|
|
74
67
|
def delete_resources
|
@@ -84,7 +77,7 @@ module OCCI
|
|
84
77
|
|
85
78
|
|
86
79
|
def get_compute_list
|
87
|
-
self.class.get(@endpoint + @compute.location, {:headers => { 'Accept' => 'text/uri-list' }, :format => 'text/plain'}).split("\n").compact
|
80
|
+
self.class.get(@endpoint + @compute.location, { :headers => { 'Accept' => 'text/uri-list' }, :format => 'text/plain' }).split("\n").compact
|
88
81
|
end
|
89
82
|
|
90
83
|
def get_compute_resources
|
@@ -148,7 +141,7 @@ module OCCI
|
|
148
141
|
def get_attributes(categories)
|
149
142
|
attributes = Hashie::Mash.new
|
150
143
|
[categories].flatten.each do |category|
|
151
|
-
category =
|
144
|
+
category = @model.get_by_id(category) if category.kind_of? String
|
152
145
|
attributes.merge! category.attributes.combine_with_defaults
|
153
146
|
end
|
154
147
|
attributes
|
@@ -157,11 +150,55 @@ module OCCI
|
|
157
150
|
def get_attribute_definitions(categories)
|
158
151
|
definitions = OCCI::Core::AttributeProperties.new
|
159
152
|
[categories].flatten.each do |category|
|
160
|
-
category =
|
153
|
+
category = @model.get_by_id(category) if category.kind_of? String
|
161
154
|
definitions.merge! category.attributes
|
162
155
|
end
|
163
156
|
definitions
|
164
157
|
end
|
165
158
|
|
159
|
+
private
|
160
|
+
|
161
|
+
def get(path, collection=nil)
|
162
|
+
accept = head(path).headers['accept']
|
163
|
+
if accept.include? 'application/occi+json'
|
164
|
+
if collection
|
165
|
+
response = self.class.get(path, :body => collection.to_json)
|
166
|
+
else
|
167
|
+
response = self.class.get(path)
|
168
|
+
end
|
169
|
+
OCCI::Parser.parse(response.env['Content-Type'], response.body)
|
170
|
+
else
|
171
|
+
if collection
|
172
|
+
response = self.class.get(path, :headers => { 'Accept' => 'text/plain', 'Content-Type' => 'text/occi', 'Category ' => collection.categories.collect { |category| category.to_text }.join(','), 'X-OCCI-Attributes' => collection.entities.collect { |entity| entity.attributes.combine.collect { |k, v| k + '=' + v } }.join(',') })
|
173
|
+
else
|
174
|
+
response = self.class.get(path, :headers => { 'Accept' => 'text/plain' })
|
175
|
+
end
|
176
|
+
OCCI::Parser.parse(response.env['Content-Type'], response.body, true)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def post(path, collection)
|
181
|
+
accept = self.class.head(path).headers['accept']
|
182
|
+
if accept.include? 'application/occi+json'
|
183
|
+
self.class.post(path, :body => collection.to_json)
|
184
|
+
else
|
185
|
+
self.class.post(path, { :body => collection.to_text, :headers => { 'Accept' => 'text/plain', 'Content-Type' => 'text/plain' } })
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def put(path, collection)
|
190
|
+
accept = self.class.head(path).headers['accept']
|
191
|
+
if accept.include? 'application/occi+json'
|
192
|
+
self.class.put(path, :body => collection.to_json)
|
193
|
+
else
|
194
|
+
self.class.put(path, { :body => collection.to_text, :headers => { 'Accept' => 'text/plain', 'Content-Type' => 'text/plain' } })
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def delete(path, collection)
|
199
|
+
accept = self.class.head(path).headers['accept']
|
200
|
+
self.class.delete(path)
|
201
|
+
end
|
202
|
+
|
166
203
|
end
|
167
204
|
end
|
data/lib/occi/collection.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'hashie/mash'
|
2
|
+
require 'active_support/json'
|
2
3
|
|
3
4
|
module OCCI
|
4
5
|
class Collection
|
@@ -18,11 +19,11 @@ module OCCI
|
|
18
19
|
@actions = []
|
19
20
|
@resources = []
|
20
21
|
@links = []
|
21
|
-
@kinds = collection.kinds.collect { |kind| OCCI::Core::Kind.new(kind) } if collection.kinds.instance_of? Array
|
22
|
-
@mixins = collection.mixins.collect { |mixin| OCCI::Core::Mixin.new(mixin) } if collection.mixins.instance_of? Array
|
23
|
-
@actions = collection.actions.collect { |action| OCCI::Core::Action.new(action) } if collection.actions.instance_of? Array
|
24
|
-
@resources = collection.resources.collect { |resource| OCCI::Core::Resource.new(resource) } if collection.resources.instance_of? Array
|
25
|
-
@links = collection.links { |link| OCCI::Core::Link.new(link) } if collection.links.instance_of? Array
|
22
|
+
@kinds = collection.kinds.collect { |kind| OCCI::Core::Kind.new(kind.scheme, kind.term, kind.title, kind.attributes, kind.related, kind.actions) } if collection.kinds.instance_of? Array
|
23
|
+
@mixins = collection.mixins.collect { |mixin| OCCI::Core::Mixin.new(mixin.scheme, mixin.term, mixin.title, mixin.attributes, mixin.related, mixin.actions) } if collection.mixins.instance_of? Array
|
24
|
+
@actions = collection.actions.collect { |action| OCCI::Core::Action.new(action.scheme, action.term, action.title, action.attributes) } if collection.actions.instance_of? Array
|
25
|
+
@resources = collection.resources.collect { |resource| OCCI::Core::Resource.new(resource.kind, resource.mixins, resource.attributes, resource.links) } if collection.resources.instance_of? Array
|
26
|
+
@links = collection.links { |link| OCCI::Core::Link.new(link.kind, link.mixins, link.attributes) } if collection.links.instance_of? Array
|
26
27
|
end
|
27
28
|
|
28
29
|
# @return [Array] categories combined list of all kinds, mixins and actions
|
@@ -35,12 +36,29 @@ module OCCI
|
|
35
36
|
@resources + @links
|
36
37
|
end
|
37
38
|
|
39
|
+
# @return [true,false] true if collection is empty, false otherwise
|
38
40
|
def empty?
|
39
41
|
@kinds.empty? && @mixins.empty? && @actions.empty? && @resources.empty? && @links.empty?
|
40
42
|
end
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
+
# @return [Hashie::Mash] returns collection as Hashie::Mash which can be converted to json
|
45
|
+
def as_json(options = { })
|
46
|
+
collection = Hashie::Mash.new
|
47
|
+
collection.kinds = @kinds.collect { |kind| kind.as_json } if @kinds.any?
|
48
|
+
collection.mixins = @mixins.collect { |mixin| mixin.as_json } if @mixins.any?
|
49
|
+
collection.actions = @actions.collect { |action| action.as_json } if @actions.any?
|
50
|
+
collection.resources = @resources.collect { |resource| resource.as_json } if @resources.any?
|
51
|
+
collection.links = @links.collect { |link| link.as_json } if @links.any?
|
52
|
+
collection
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_text
|
56
|
+
body = ""
|
57
|
+
body << self.categories.collect { |category| category.to_text }.join("\n")
|
58
|
+
body << "\n" if self.categories.any?
|
59
|
+
raise "Only one entity allowed for rendering to plain text" if body.entities.size > 1
|
60
|
+
body << self.entities.collect {|entity| entity.to_text}.join("\n")
|
61
|
+
body
|
44
62
|
end
|
45
63
|
|
46
64
|
end
|
data/lib/occi/core/action.rb
CHANGED
@@ -23,7 +23,7 @@ module OCCI
|
|
23
23
|
self[key].combine.each { |attr| array << key + '.' + attr }
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
26
|
+
array
|
27
27
|
end
|
28
28
|
|
29
29
|
def combine_with_defaults
|
@@ -35,7 +35,7 @@ module OCCI
|
|
35
35
|
self[key].combine_with_defaults.each { |k,v| hash[key + '.' + k] = v }
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
38
|
+
hash
|
39
39
|
end
|
40
40
|
|
41
41
|
end
|
data/lib/occi/core/attributes.rb
CHANGED
@@ -13,14 +13,14 @@ module OCCI
|
|
13
13
|
hash[key] = self[key]
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
16
|
+
hash
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.split(attributes)
|
20
20
|
attribute = Attributes.new
|
21
21
|
attributes.each do |name,value|
|
22
22
|
puts name
|
23
|
-
key,
|
23
|
+
key, _, rest = name.partition('.')
|
24
24
|
if rest.empty?
|
25
25
|
attribute[key] = value
|
26
26
|
else
|
data/lib/occi/core/category.rb
CHANGED
@@ -1,41 +1,61 @@
|
|
1
|
-
require 'json'
|
1
|
+
require 'active_support/json'
|
2
|
+
require 'active_support/inflector'
|
2
3
|
require 'hashie/mash'
|
3
4
|
|
4
5
|
module OCCI
|
5
6
|
module Core
|
6
|
-
class Category
|
7
|
+
class Category
|
7
8
|
|
8
|
-
|
9
|
-
category.attributes = OCCI::Core::AttributeProperties.new(category.attributes) if category
|
10
|
-
super(category, default)
|
11
|
-
end
|
9
|
+
attr_accessor :scheme, :term, :title, :attributes
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
val.collect { |e| convert_value(e) }
|
23
|
-
else
|
24
|
-
val
|
25
|
-
end
|
11
|
+
# @param [String ] scheme
|
12
|
+
# @param [String] term
|
13
|
+
# @param [String] title
|
14
|
+
# @param [OCCI::Core::AttributeProperties] attributes
|
15
|
+
def initialize(scheme, term, title=nil, attributes=nil)
|
16
|
+
@scheme = scheme
|
17
|
+
@term = term
|
18
|
+
@title = title
|
19
|
+
@attributes = OCCI::Core::AttributeProperties.new(attributes)
|
26
20
|
end
|
27
21
|
|
22
|
+
# @return [String] Type identifier of the category
|
28
23
|
def type_identifier
|
29
|
-
|
24
|
+
@scheme + @term
|
25
|
+
end
|
26
|
+
|
27
|
+
# converts and adds supplied attributes to attributes of the category
|
28
|
+
# @param [Hash] attributes
|
29
|
+
# @return [OCCI::Core::AttributeProperties] attributes hash converted to attribute properties
|
30
|
+
def attributes=(attributes)
|
31
|
+
@attributes = OCCI::Core::AttributeProperties.new(attributes)
|
30
32
|
end
|
31
33
|
|
32
|
-
|
34
|
+
# check if category is related to another category
|
35
|
+
# @param [String] category_id Type identifier of a related category
|
36
|
+
# @return [true,false] true if category is related to category_id else false
|
37
|
+
def related_to?(category_id, model)
|
33
38
|
self.related.each do |rel_id|
|
34
|
-
return true if rel_id == category_id ||
|
35
|
-
end if self.related
|
39
|
+
return true if rel_id == category_id || model.get_by_id(rel_id).related_to?(category_id, model)
|
40
|
+
end if self.class.method_defined? 'related'
|
36
41
|
false
|
37
42
|
end
|
38
43
|
|
44
|
+
def as_json(options={ })
|
45
|
+
category = Hashie::Mash.new
|
46
|
+
category.scheme = @scheme if @scheme
|
47
|
+
category.term = @term if @term
|
48
|
+
category.title = @title if @title
|
49
|
+
category.attributes = @attributes if @attributes.any?
|
50
|
+
category
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_text
|
54
|
+
text = @term + ';scheme=' + @scheme.inspect + ';class=' + self.class.name.demodulize.downcase.inspect
|
55
|
+
text << ';title=' + @title.inspect if @title
|
56
|
+
text
|
57
|
+
end
|
58
|
+
|
39
59
|
end
|
40
60
|
end
|
41
61
|
end
|
data/lib/occi/core/entity.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'uuidtools'
|
3
3
|
require 'hashie/mash'
|
4
|
+
require 'active_support/json'
|
4
5
|
require 'occi/model'
|
5
6
|
require 'occi/core/attributes'
|
6
7
|
require 'occi/core/kind'
|
@@ -8,90 +9,89 @@ require 'occi/core/attribute_properties'
|
|
8
9
|
|
9
10
|
module OCCI
|
10
11
|
module Core
|
11
|
-
class Entity
|
12
|
-
|
13
|
-
# Define appropriate kind
|
14
|
-
def self.register
|
15
|
-
data = Hashie::Mash.new
|
16
|
-
data[:term] = "entity"
|
17
|
-
data[:scheme] = "http://schemas.ogf.org/occi/core#"
|
18
|
-
data[:title] = "Entity"
|
19
|
-
data.attributes!.occi!.core!.id!.type = "string"
|
20
|
-
data.attributes!.occi!.core!.id!.pattern = "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"
|
21
|
-
data.attributes!.occi!.core!.id!.required = false
|
22
|
-
data.attributes!.occi!.core!.id!.mutable = false
|
23
|
-
data.attributes!.occi!.core!.title!.type = "string"
|
24
|
-
data.attributes!.occi!.core!.title!.pattern = ".*"
|
25
|
-
data.attributes!.occi!.core!.title!.required = false
|
26
|
-
data.attributes!.occi!.core!.title!.mutable = true
|
27
|
-
|
28
|
-
kind = OCCI::Core::Kind.new(data)
|
29
|
-
OCCI::Model.register(kind)
|
30
|
-
end
|
12
|
+
class Entity
|
31
13
|
|
32
|
-
|
33
|
-
super(entity, default)
|
34
|
-
self.check
|
35
|
-
end
|
14
|
+
attr_accessor :kind, :mixins, :attributes
|
36
15
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
16
|
+
# @return [OCCI::Core::Kind] kind definition of Entity type
|
17
|
+
def self.kind_definition
|
18
|
+
kind = OCCI::Core::Kind.new('http://schemas.ogf.org/occi/core#', 'entity')
|
41
19
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
20
|
+
kind.title = "Entity"
|
21
|
+
|
22
|
+
kind.attributes.occi!.core!.id!.type = "string"
|
23
|
+
kind.attributes.occi!.core!.id!.pattern = "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"
|
24
|
+
kind.attributes.occi!.core!.id!.required = false
|
25
|
+
kind.attributes.occi!.core!.id!.mutable = false
|
26
|
+
|
27
|
+
kind.attributes.occi!.core!.title!.type = "string"
|
28
|
+
kind.attributes.occi!.core!.title!.pattern = ".*"
|
29
|
+
kind.attributes.occi!.core!.title!.required = false
|
30
|
+
kind.attributes.occi!.core!.title!.mutable = true
|
31
|
+
|
32
|
+
kind
|
46
33
|
end
|
47
34
|
|
48
|
-
|
49
|
-
|
50
|
-
|
35
|
+
# @param [String] kind
|
36
|
+
# @param [String] mixins
|
37
|
+
# @param [OCCI::Core::Attributes] attributes
|
38
|
+
def initialize(kind, mixins=nil, attributes=nil)
|
39
|
+
@kind = kind
|
40
|
+
@mixins = mixins.to_a
|
41
|
+
@attributes = OCCI::Core::Attributes.new(attributes)
|
42
|
+
self.id = UUIDTools::UUID.timestamp_create.to_s
|
51
43
|
end
|
52
44
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
45
|
+
# set id for entity
|
46
|
+
# @param [UUIDTools::UUID] id
|
47
|
+
def id=(id)
|
48
|
+
@attributes.occi!.core!.id = id
|
57
49
|
end
|
58
50
|
|
59
|
-
|
60
|
-
|
51
|
+
# @return [UUIDTools::UUID] id of the entity
|
52
|
+
def id
|
53
|
+
@attributes.occi!.core!.id
|
61
54
|
end
|
62
55
|
|
63
|
-
|
64
|
-
|
56
|
+
# @return [String] location of the entity
|
57
|
+
def location
|
58
|
+
'/' + @kind.split('#').last + '/' + @attributes.occi!.core!.id
|
65
59
|
end
|
66
60
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
61
|
+
# check attributes against their definitions and set defaults
|
62
|
+
# @param [OCCI::Model] model representation of the OCCI model to check the attributes against
|
63
|
+
def check(model)
|
64
|
+
raise "No kind defined" unless @kind
|
65
|
+
definitions = model.get_by_id(@kind).attributes
|
66
|
+
@mixins.each do |mixin_id|
|
67
|
+
mixin = model.get_by_id(mixin_id)
|
71
68
|
next if mixin.nil?
|
72
69
|
definitions.merge!(mixin.attributes) if mixin.attributes
|
73
|
-
end if
|
70
|
+
end if @mixins
|
74
71
|
|
75
|
-
|
72
|
+
@attributes = Entity.check(@attributes, definitions) if definitions
|
76
73
|
end
|
77
74
|
|
75
|
+
# @param [OCCI::Core::Attributes] attributes
|
76
|
+
# @param [OCCI::Core::AttributeProperties] definitions
|
77
|
+
# @return [OCCI::Core::Attributes] attributes with their defaults set
|
78
78
|
def self.check(attributes, definitions)
|
79
79
|
attributes = OCCI::Core::Attributes.new(attributes)
|
80
80
|
definitions.each_key do |key|
|
81
81
|
properties = definitions[key]
|
82
|
-
value
|
82
|
+
value = attributes[key] ||= properties[:default]
|
83
83
|
if properties.include?(:type)
|
84
84
|
raise "required attribute #{key} not found" if value.nil? && properties.required
|
85
85
|
next if value.nil? && !properties.required
|
86
86
|
case properties.type
|
87
|
-
when 'string'
|
88
|
-
raise "attribute #{key} with value #{value} from class #{value.class.name} does not match attribute property type #{properties.type}" unless value.kind_of?(String)
|
89
|
-
raise "attribute #{key} with length #{value.length} not in range #{properties.minimum}-#{properties.maximum}" unless (properties.minimum..properties.maximum) === value.length if properties.minimum && properties.maximum
|
90
87
|
when 'number'
|
91
88
|
raise "attribute #{key} value #{value} from class #{value.class.name} does not match attribute property type #{properties.type}" unless value.kind_of?(Numeric)
|
92
89
|
raise "attribute #{key} with value #{value} not in range #{properties.minimum}-#{properties.maximum}" unless (properties.minimum..properties.maximum) === value if properties.minimum && properties.maximum
|
93
90
|
when 'boolean'
|
94
91
|
raise "attribute #{key} value #{value} from class #{value.class.name} does not match attribute property type #{properties.type}" unless !!value == value
|
92
|
+
else
|
93
|
+
raise "attribute #{key} with value #{value} from class #{value.class.name} does not match attribute property type #{properties.type}" unless value.kind_of?(String)
|
94
|
+
raise "attribute #{key} with length #{value.length} not in range #{properties.minimum}-#{properties.maximum}" unless (properties.minimum..properties.maximum) === value.length if properties.minimum && properties.maximum
|
95
95
|
end
|
96
96
|
raise "attribute #{key} with value #{value} does not match pattern #{properties.pattern}" if value.to_s.scan(Regexp.new(properties.pattern)).empty? if properties.pattern
|
97
97
|
attributes[key] = value
|
@@ -99,23 +99,18 @@ module OCCI
|
|
99
99
|
attributes[key] = check(value, definitions[key])
|
100
100
|
end
|
101
101
|
end
|
102
|
-
attributes.delete_if { |
|
102
|
+
attributes.delete_if { |_, v| v.nil? } # remove empty attributes
|
103
103
|
return attributes
|
104
104
|
end
|
105
105
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
when Array
|
115
|
-
val.collect { |e| convert_value(e) }
|
116
|
-
else
|
117
|
-
val
|
118
|
-
end
|
106
|
+
# @param [Hash] options
|
107
|
+
# @return [Hashie::Mash] entity as Hashie::Mash to be parsed into a JSON object
|
108
|
+
def as_json(options={ })
|
109
|
+
entity = Hashie::Mash.new
|
110
|
+
entity.kind = @kind if @kind
|
111
|
+
entity.mixins = @mixins if @mixins.any?
|
112
|
+
entity.attributes = @attributes if @attributes.any?
|
113
|
+
entity
|
119
114
|
end
|
120
115
|
|
121
116
|
end
|