occi 2.2.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|