deltacloud-core 1.1.0 → 1.1.1
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/Rakefile +10 -12
- data/config/drivers/{aruba.yaml → arubacloud.yaml} +2 -2
- data/deltacloud-core.gemspec +4 -4
- data/lib/cimi/collections/address_templates.rb +1 -1
- data/lib/cimi/collections/addresses.rb +2 -2
- data/lib/cimi/collections/base.rb +1 -0
- data/lib/cimi/collections/credentials.rb +1 -1
- data/lib/cimi/collections/forwarding_group_templates.rb +1 -1
- data/lib/cimi/collections/forwarding_groups.rb +1 -1
- data/lib/cimi/collections/machine_configurations.rb +1 -1
- data/lib/cimi/collections/machine_images.rb +1 -1
- data/lib/cimi/collections/machine_templates.rb +1 -1
- data/lib/cimi/collections/machines.rb +2 -2
- data/lib/cimi/collections/network_configurations.rb +1 -1
- data/lib/cimi/collections/network_port_configurations.rb +1 -1
- data/lib/cimi/collections/network_port_templates.rb +1 -1
- data/lib/cimi/collections/network_ports.rb +1 -1
- data/lib/cimi/collections/network_templates.rb +1 -1
- data/lib/cimi/collections/networks.rb +1 -1
- data/lib/cimi/collections/volume_configurations.rb +1 -1
- data/lib/cimi/collections/volume_images.rb +1 -1
- data/lib/cimi/collections/volume_templates.rb +1 -1
- data/lib/cimi/collections/volumes.rb +1 -1
- data/lib/cimi/helpers/database_helper.rb +16 -61
- data/lib/cimi/helpers/filter_helper.rb +41 -0
- data/lib/cimi/helpers/select_helper.rb +62 -0
- data/lib/cimi/models.rb +21 -2
- data/lib/cimi/models/address.rb +9 -7
- data/lib/cimi/models/address_template.rb +4 -4
- data/lib/cimi/models/base.rb +62 -197
- data/lib/cimi/models/collection.rb +78 -70
- data/lib/cimi/models/disk.rb +15 -8
- data/lib/cimi/models/machine.rb +27 -29
- data/lib/cimi/models/machine_image.rb +10 -13
- data/lib/cimi/models/machine_template.rb +3 -3
- data/lib/cimi/models/resource.rb +190 -0
- data/lib/cimi/models/schema.rb +9 -0
- data/lib/cimi/models/volume.rb +10 -13
- data/lib/cimi/models/volume_configuration.rb +3 -3
- data/lib/cimi/models/volume_template.rb +2 -2
- data/lib/cimi/server.rb +1 -0
- data/lib/db.rb +15 -0
- data/lib/db/address_template.rb +15 -0
- data/lib/db/entity.rb +55 -0
- data/lib/db/machine_template.rb +15 -0
- data/lib/db/provider.rb +40 -0
- data/lib/db/volume_configuration.rb +15 -0
- data/lib/db/volume_template.rb +15 -0
- data/lib/deltacloud/collections/base.rb +1 -0
- data/lib/deltacloud/collections/instances.rb +2 -1
- data/lib/deltacloud/collections/storage_snapshots.rb +3 -1
- data/lib/deltacloud/core_ext/array.rb +5 -0
- data/lib/deltacloud/drivers/{aruba/aruba_driver.rb → arubacloud/arubacloud_driver.rb} +3 -6
- data/lib/deltacloud/drivers/digitalocean/digitalocean_driver.rb +48 -75
- data/lib/deltacloud/drivers/ec2/ec2_driver.rb +18 -3
- data/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb +25 -0
- data/lib/deltacloud/drivers/fgcp/fgcp_client.rb +1 -1
- data/lib/deltacloud/drivers/fgcp/fgcp_driver.rb +34 -14
- data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +2 -0
- data/lib/deltacloud/drivers/mock/mock_driver.rb +3 -3
- data/lib/deltacloud/drivers/openstack/openstack_driver.rb +93 -33
- data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +2 -0
- data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +2 -2
- data/lib/deltacloud/helpers/deltacloud_helper.rb +3 -1
- data/lib/deltacloud/helpers/rabbit_helper.rb +1 -2
- data/lib/deltacloud/models/address.rb +1 -0
- data/lib/deltacloud/models/blob.rb +1 -0
- data/lib/deltacloud/models/bucket.rb +1 -0
- data/lib/deltacloud/models/firewall.rb +1 -0
- data/lib/deltacloud/models/hardware_profile.rb +3 -1
- data/lib/deltacloud/models/image.rb +7 -0
- data/lib/deltacloud/models/instance.rb +12 -3
- data/lib/deltacloud/models/key.rb +1 -0
- data/lib/deltacloud/models/load_balancer.rb +1 -0
- data/lib/deltacloud/models/metric.rb +1 -0
- data/lib/deltacloud/models/realm.rb +10 -1
- data/lib/deltacloud/models/storage_snapshot.rb +1 -0
- data/lib/deltacloud/models/storage_volume.rb +2 -1
- data/lib/deltacloud/runner.rb +2 -1
- data/lib/deltacloud/server.rb +1 -0
- data/lib/deltacloud/version.rb +1 -1
- data/lib/deltacloud_rack.rb +4 -0
- data/tests/cimi/collections/machines_test.rb +80 -0
- data/tests/cimi/db/database_helper_test.rb +54 -99
- data/tests/cimi/db/db_helper.rb +2 -0
- data/tests/cimi/db/entity_test.rb +29 -0
- data/tests/cimi/model/collection_spec.rb +2 -2
- data/tests/cimi/model/credential_spec.rb +2 -2
- data/tests/cimi/model/machine_configuration_spec.rb +2 -2
- data/tests/cimi/model/machine_image_spec.rb +2 -2
- data/tests/cimi/model/machine_spec.rb +4 -4
- data/tests/cimi/model/machine_template_spec.rb +2 -2
- data/tests/cimi/model/volume_configuration_spec.rb +2 -2
- data/tests/cimi/model/volume_image_spec.rb +2 -2
- data/tests/cimi/model/volume_spec.rb +2 -2
- data/tests/cimi/model/volume_template_spec.rb +2 -2
- data/tests/cimi/spec_helper.rb +4 -0
- data/tests/deltacloud/collections/instances_collection_test.rb +3 -1
- data/tests/deltacloud/launcher_test.rb +3 -5
- data/tests/drivers/ec2/images_test.rb +7 -0
- data/tests/drivers/gogrid/images_test.rb +7 -0
- data/tests/drivers/openstack/instances_test.rb +8 -8
- data/tests/drivers/openstack/realms_test.rb +13 -13
- data/views/errors/403.xml.haml +2 -1
- data/views/images/show.html.haml +4 -1
- data/views/images/show.xml.haml +1 -0
- data/views/instances/new.html.haml +1 -1
- data/views/instances/show.html.haml +3 -0
- data/views/realms/index.html.haml +2 -0
- data/views/realms/show.html.haml +4 -0
- data/views/realms/show.xml.haml +3 -0
- metadata +19 -14
data/lib/cimi/models.rb
CHANGED
|
@@ -13,8 +13,26 @@
|
|
|
13
13
|
# License for the specific language governing permissions and limitations
|
|
14
14
|
# under the License.
|
|
15
15
|
#
|
|
16
|
+
|
|
16
17
|
module CIMI
|
|
17
|
-
module Model
|
|
18
|
+
module Model
|
|
19
|
+
def self.register_as_root_entity!(klass, opts = {})
|
|
20
|
+
@root_entities ||= [CIMI::Model::CloudEntryPoint]
|
|
21
|
+
@root_entities << klass
|
|
22
|
+
name = klass.name.split("::").last.pluralize
|
|
23
|
+
unless CIMI::Model::CloudEntryPoint.href_defined?(name)
|
|
24
|
+
params = {}
|
|
25
|
+
if opts[:as]
|
|
26
|
+
params[:xml_name] = params[:json_name] = opts[:as]
|
|
27
|
+
end
|
|
28
|
+
CIMI::Model::CloudEntryPoint.send(:href, name.underscore, params)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.root_entities
|
|
33
|
+
@root_entities || []
|
|
34
|
+
end
|
|
35
|
+
end
|
|
18
36
|
end
|
|
19
37
|
|
|
20
38
|
require 'require_relative' if RUBY_VERSION < '1.9'
|
|
@@ -31,8 +49,9 @@ unless Deltacloud.test_environment?
|
|
|
31
49
|
end
|
|
32
50
|
|
|
33
51
|
require_relative './models/schema'
|
|
34
|
-
require_relative './models/
|
|
52
|
+
require_relative './models/resource'
|
|
35
53
|
require_relative './models/collection'
|
|
54
|
+
require_relative './models/base'
|
|
36
55
|
require_relative './models/errors'
|
|
37
56
|
require_relative './models/action'
|
|
38
57
|
require_relative './models/machine_volume'
|
data/lib/cimi/models/address.rb
CHANGED
|
@@ -65,23 +65,26 @@ class CIMI::Model::Address < CIMI::Model::Base
|
|
|
65
65
|
params = {:name=>input["name"], :description=>input["description"], :address_template=>address_template, :env=>context }
|
|
66
66
|
raise CIMI::Model::BadRequest.new("Bad request - missing required parameters. Client sent: #{request_body} which produced #{params.inspect}") if params.has_value?(nil)
|
|
67
67
|
address = context.driver.create_address(context.credentials, params)
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
result = from_address(address, context)
|
|
69
|
+
result.name = input['name'] if input['name']
|
|
70
|
+
result.description = input['description'] if input['description']
|
|
71
|
+
result.extract_properties!(input)
|
|
72
|
+
result.save
|
|
73
|
+
result
|
|
70
74
|
end
|
|
71
75
|
|
|
72
76
|
def self.delete!(id, context)
|
|
73
77
|
context.driver.delete_address(context.credentials, id)
|
|
74
|
-
|
|
78
|
+
new(:id => id).destroy
|
|
75
79
|
end
|
|
76
80
|
|
|
77
81
|
private
|
|
78
82
|
|
|
79
83
|
def self.from_address(address, context)
|
|
80
|
-
stored_attributes = load_attributes_for(address)
|
|
81
84
|
self.new(
|
|
82
|
-
:name =>
|
|
85
|
+
:name => address.id,
|
|
83
86
|
:id => context.address_url(address.id),
|
|
84
|
-
:description =>
|
|
87
|
+
:description => "Address #{address.id}",
|
|
85
88
|
:ip => address.id,
|
|
86
89
|
:allocation => "dynamic", #or "static"
|
|
87
90
|
:default_gateway => "unknown", #wtf
|
|
@@ -89,7 +92,6 @@ class CIMI::Model::Address < CIMI::Model::Base
|
|
|
89
92
|
:protocol => protocol_from_address(address.id),
|
|
90
93
|
:mask => "unknown",
|
|
91
94
|
:resource => (address.instance_id) ? {:href=> context.machine_url(address.instance_id)} : nil,
|
|
92
|
-
:property => stored_attributes[:property],
|
|
93
95
|
:network => nil #unknown
|
|
94
96
|
#optional:
|
|
95
97
|
#:hostname =>
|
|
@@ -42,7 +42,7 @@ class CIMI::Model::AddressTemplate < CIMI::Model::Base
|
|
|
42
42
|
if context.driver.respond_to? :address_templates
|
|
43
43
|
context.driver.address_templates(context.credentials, {:env=>context})
|
|
44
44
|
else
|
|
45
|
-
current_db.
|
|
45
|
+
current_db.address_templates.map { |t| from_db(t, context) }
|
|
46
46
|
end
|
|
47
47
|
else
|
|
48
48
|
if context.driver.respond_to? :address_template
|
|
@@ -67,7 +67,7 @@ class CIMI::Model::AddressTemplate < CIMI::Model::Base
|
|
|
67
67
|
:dns => json['dns'],
|
|
68
68
|
:protocol => json['protocol'],
|
|
69
69
|
:mask => json['mask'],
|
|
70
|
-
:ent_properties => json['properties'].to_json
|
|
70
|
+
:ent_properties => json['properties'] ? json['properties'].to_json : {}
|
|
71
71
|
)
|
|
72
72
|
from_db(new_template, context)
|
|
73
73
|
end
|
|
@@ -85,7 +85,7 @@ class CIMI::Model::AddressTemplate < CIMI::Model::Base
|
|
|
85
85
|
:dns => xml['dns'].first,
|
|
86
86
|
:protocol => xml['protocol'].nil? ? nil : xml['protocol'].first,
|
|
87
87
|
:mask => xml['mask'].first,
|
|
88
|
-
:ent_properties => JSON::dump(xml['property'].inject({}) { |r, p| r[p['key']]=p['content']; r })
|
|
88
|
+
:ent_properties => xml['property'] ? JSON::dump(xml['property'].inject({}) { |r, p| r[p['key']]=p['content']; r }) : {}
|
|
89
89
|
)
|
|
90
90
|
from_db(new_template, context)
|
|
91
91
|
end
|
|
@@ -108,7 +108,7 @@ class CIMI::Model::AddressTemplate < CIMI::Model::Base
|
|
|
108
108
|
:dns => model.dns,
|
|
109
109
|
:protocol => model.protocol,
|
|
110
110
|
:mask => model.mask,
|
|
111
|
-
:property => JSON::parse(model.ent_properties),
|
|
111
|
+
:property => (model.ent_properties ? JSON::parse(model.ent_properties) : nil),
|
|
112
112
|
:operations => [
|
|
113
113
|
{ :href => context.destroy_address_template_url(model.id), :rel => 'http://schemas.dmtf.org/cimi/1/action/delete' }
|
|
114
114
|
]
|
data/lib/cimi/models/base.rb
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
require 'xmlsimple'
|
|
17
17
|
|
|
18
|
+
require_relative '../helpers/database_helper'
|
|
19
|
+
|
|
18
20
|
# The base class for any CIMI object that we either read from a request or
|
|
19
21
|
# write as a response. This class handles serializing/deserializing XML and
|
|
20
22
|
# JSON into a common form.
|
|
@@ -61,7 +63,7 @@ require 'xmlsimple'
|
|
|
61
63
|
# [struct(name, opts, &block)]
|
|
62
64
|
# A structured subobject; the block defines the schema of the
|
|
63
65
|
# subobject. The +:content+ option can be used to specify the attribute
|
|
64
|
-
# that should receive the content of
|
|
66
|
+
# that should receive the content of the corresponding XML element
|
|
65
67
|
# [array(name, opts, &block)]
|
|
66
68
|
# An array of structured subobjects; the block defines the schema of
|
|
67
69
|
# the subobjects.
|
|
@@ -71,221 +73,84 @@ require 'xmlsimple'
|
|
|
71
73
|
|
|
72
74
|
module CIMI::Model
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
@root_entities ||= [CIMI::Model::CloudEntryPoint]
|
|
76
|
-
@root_entities << klass
|
|
77
|
-
name = klass.name.split("::").last.pluralize
|
|
78
|
-
unless CIMI::Model::CloudEntryPoint.href_defined?(name)
|
|
79
|
-
params = {}
|
|
80
|
-
if opts[:as]
|
|
81
|
-
params[:xml_name] = params[:json_name] = opts[:as]
|
|
82
|
-
end
|
|
83
|
-
CIMI::Model::CloudEntryPoint.send(:href, name.underscore, params)
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def self.root_entities
|
|
88
|
-
@root_entities || []
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
class CIMI::Model::Resource
|
|
76
|
+
class Base < Resource
|
|
94
77
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
#
|
|
98
|
-
attr_reader :attribute_values
|
|
78
|
+
# Extend the base model with database methods
|
|
79
|
+
extend Deltacloud::Helpers::Database
|
|
99
80
|
|
|
100
|
-
|
|
81
|
+
# Extend the base model with the collection handling methods
|
|
82
|
+
extend CIMI::Model::CollectionMethods
|
|
101
83
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
84
|
+
# Include methods needed to handle the $select query parameter
|
|
85
|
+
include CIMI::Helpers::SelectBaseMethods
|
|
86
|
+
#
|
|
87
|
+
# Common attributes for all resources
|
|
88
|
+
#
|
|
89
|
+
text :id, :name, :description, :created, :updated
|
|
90
|
+
hash :property
|
|
106
91
|
|
|
107
|
-
def
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if ::Struct.const_defined?("CIMI_#{member_name}")
|
|
111
|
-
::Struct.send(:remove_const, "CIMI_#{member_name}")
|
|
112
|
-
end
|
|
113
|
-
member_symbol = member_name.underscore.pluralize.to_sym
|
|
114
|
-
members = CIMI::Model::Schema::Array.new(member_symbol)
|
|
115
|
-
members.struct.schema.attributes = model.schema.attributes
|
|
116
|
-
base_schema.attributes << members
|
|
92
|
+
def initialize(values = {})
|
|
93
|
+
super(values)
|
|
94
|
+
retrieve_entity
|
|
117
95
|
end
|
|
118
96
|
|
|
119
|
-
def
|
|
120
|
-
|
|
97
|
+
def []=(a, v)
|
|
98
|
+
v = super
|
|
99
|
+
retrieve_entity if a == :id
|
|
100
|
+
v
|
|
121
101
|
end
|
|
122
102
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
103
|
+
# Save the common attributes name, description, and properties to the
|
|
104
|
+
# database
|
|
105
|
+
def save
|
|
106
|
+
if @entity
|
|
107
|
+
@entity.name = name
|
|
108
|
+
@entity.description = description
|
|
109
|
+
@entity.properties = property
|
|
110
|
+
@entity.save
|
|
111
|
+
end
|
|
112
|
+
self
|
|
126
113
|
end
|
|
127
114
|
|
|
128
|
-
|
|
129
|
-
|
|
115
|
+
# Destroy the database attributes for this model
|
|
116
|
+
def destroy
|
|
117
|
+
@entity.destroy
|
|
118
|
+
self
|
|
130
119
|
end
|
|
131
120
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
121
|
+
# FIXME: Kludge around the fact that we do not have proper *Create
|
|
122
|
+
# objects that deserialize properties by themselves
|
|
123
|
+
def extract_properties!(data)
|
|
124
|
+
h = {}
|
|
125
|
+
if data['property']
|
|
126
|
+
# Data came from XML
|
|
127
|
+
h = data['property'].inject({}) do |r,v|
|
|
128
|
+
r[v['key']] = v['content']
|
|
129
|
+
r
|
|
138
130
|
end
|
|
131
|
+
elsif data['properties']
|
|
132
|
+
h = data['properties']
|
|
139
133
|
end
|
|
134
|
+
property ||= {}
|
|
135
|
+
property.merge!(h)
|
|
140
136
|
end
|
|
141
137
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
138
|
+
private
|
|
139
|
+
|
|
140
|
+
# Load an existing database entity for this object, or create a new one
|
|
141
|
+
def retrieve_entity
|
|
142
|
+
if self.id
|
|
143
|
+
@entity = Deltacloud::Database::Entity::retrieve(self)
|
|
144
|
+
if @entity.exists?
|
|
145
|
+
self.name = @entity.name
|
|
146
|
+
self.description = @entity.description
|
|
147
|
+
self.property ||= {}
|
|
148
|
+
self.property.merge!(@entity.properties)
|
|
149
|
+
end
|
|
145
150
|
else
|
|
146
|
-
|
|
151
|
+
@entity = nil
|
|
147
152
|
end
|
|
148
|
-
names.each do |name|
|
|
149
|
-
define_method(name) { self[name] }
|
|
150
|
-
define_method(:"#{name}=") { |newval| self[name] = newval }
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
# Return Array of links to current CIMI object
|
|
155
|
-
def all_uri(context)
|
|
156
|
-
self.all(context).map { |e| { :href => e.id } }
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
extend CIMI::Model::Schema::DSL
|
|
161
|
-
|
|
162
|
-
def [](a)
|
|
163
|
-
@attribute_values[a]
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def []=(a, v)
|
|
167
|
-
@attribute_values[a] = self.class.schema.convert(a, v)
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
# Prepare to serialize
|
|
171
|
-
def prepare
|
|
172
|
-
self.class.schema.collections.map { |coll| coll.name }.each do |n|
|
|
173
|
-
self[n].href = "#{self.id}/#{n}" unless self[n].href
|
|
174
|
-
self[n].id = "#{self.id}/#{n}" if !self[n].entries.empty?
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
#
|
|
179
|
-
# Factory methods
|
|
180
|
-
#
|
|
181
|
-
def initialize(values = {})
|
|
182
|
-
names = self.class.schema.attribute_names
|
|
183
|
-
@attribute_values = names.inject(OrderedHash.new) do |hash, name|
|
|
184
|
-
hash[name] = self.class.schema.convert(name, values[name])
|
|
185
|
-
hash
|
|
186
153
|
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
# Construct a new object from the XML representation +xml+
|
|
190
|
-
def self.from_xml(text)
|
|
191
|
-
xml = XmlSimple.xml_in(text, :force_content => true)
|
|
192
|
-
model = self.new
|
|
193
|
-
@schema.from_xml(xml, model)
|
|
194
|
-
model
|
|
195
|
-
end
|
|
196
154
|
|
|
197
|
-
# Construct a new object
|
|
198
|
-
def self.from_json(text)
|
|
199
|
-
json = JSON::parse(text)
|
|
200
|
-
model = self.new
|
|
201
|
-
@schema.from_json(json, model)
|
|
202
|
-
model
|
|
203
155
|
end
|
|
204
|
-
|
|
205
|
-
def self.parse(text, content_type)
|
|
206
|
-
if content_type == "application/xml"
|
|
207
|
-
from_xml(text)
|
|
208
|
-
elsif content_type == "application/json"
|
|
209
|
-
from_json(text)
|
|
210
|
-
else
|
|
211
|
-
raise "Can not parse content type #{content_type}"
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
#
|
|
216
|
-
# Serialize
|
|
217
|
-
#
|
|
218
|
-
|
|
219
|
-
def self.xml_tag_name
|
|
220
|
-
self.name.split("::").last
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
def self.resource_uri
|
|
224
|
-
CMWG_NAMESPACE + "/" + self.name.split("::").last
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
def self.to_json(model)
|
|
228
|
-
json = @schema.to_json(model)
|
|
229
|
-
json[:resourceURI] = resource_uri
|
|
230
|
-
JSON::unparse(json)
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
def self.to_xml(model)
|
|
234
|
-
xml = @schema.to_xml(model)
|
|
235
|
-
xml["xmlns"] = CMWG_NAMESPACE
|
|
236
|
-
xml["resourceURI"] = resource_uri
|
|
237
|
-
XmlSimple.xml_out(xml, :root_name => xml_tag_name)
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
def to_json
|
|
241
|
-
self.class.to_json(self)
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
def to_xml
|
|
245
|
-
self.class.to_xml(self)
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
def filter_by(filter_opts)
|
|
249
|
-
return self if filter_opts.nil?
|
|
250
|
-
return filter_attributes(filter_opts.split(',').map{ |a| a.intern }) if filter_opts.include? ','
|
|
251
|
-
case filter_opts
|
|
252
|
-
when /^([\w\_]+)$/ then filter_attributes([$1.intern])
|
|
253
|
-
when /^([\w\_]+)\[(\d+\-\d+)\]$/ then filter_by_arr_range($1.intern, $2)
|
|
254
|
-
when /^([\w\_]+)\[(\d+)\]$/ then filter_by_arr_index($1.intern, $2)
|
|
255
|
-
else self
|
|
256
|
-
end
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
def filter_by_arr_index(attr, filter)
|
|
260
|
-
return self unless self.respond_to?(attr)
|
|
261
|
-
self.class.new(attr => [self.send(attr)[filter.to_i]])
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
def filter_by_arr_range(attr, filter)
|
|
265
|
-
return self unless self.respond_to?(attr)
|
|
266
|
-
filter = filter.split('-').inject { |s,e| s.to_i..e.to_i }
|
|
267
|
-
self.class.new(attr => self.send(attr)[filter])
|
|
268
|
-
end
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
require_relative '../helpers/database_helper'
|
|
272
|
-
|
|
273
|
-
class CIMI::Model::Base < CIMI::Model::Resource
|
|
274
|
-
extend Deltacloud::Helpers::Database
|
|
275
|
-
#
|
|
276
|
-
# Common attributes for all resources
|
|
277
|
-
#
|
|
278
|
-
text :id, :name, :description, :created
|
|
279
|
-
|
|
280
|
-
hash :property
|
|
281
|
-
|
|
282
|
-
def filter_attributes(attr_list)
|
|
283
|
-
attrs = attr_list.inject({}) do |result, attr|
|
|
284
|
-
attr = attr.to_s.underscore
|
|
285
|
-
result[attr.to_sym] = self.send(attr) if self.respond_to?(attr)
|
|
286
|
-
result
|
|
287
|
-
end
|
|
288
|
-
self.class.new(attrs)
|
|
289
|
-
end
|
|
290
|
-
|
|
291
156
|
end
|
|
@@ -13,22 +13,56 @@
|
|
|
13
13
|
# License for the specific language governing permissions and limitations
|
|
14
14
|
# under the License.
|
|
15
15
|
|
|
16
|
+
|
|
16
17
|
module CIMI::Model
|
|
17
18
|
class Collection < Resource
|
|
18
19
|
|
|
19
20
|
class << self
|
|
20
21
|
attr_accessor :entry_name, :embedded
|
|
22
|
+
|
|
23
|
+
def xml_tag_name
|
|
24
|
+
'Collection'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def generate(model_class, opts = {})
|
|
28
|
+
model_name = model_class.name.split("::").last
|
|
29
|
+
scope = opts[:scope] || CIMI::Model
|
|
30
|
+
coll_class = Class.new(CIMI::Model::Collection)
|
|
31
|
+
scope.const_set(:"#{model_name}Collection", coll_class)
|
|
32
|
+
coll_class.entry_name = model_name.underscore.pluralize.to_sym
|
|
33
|
+
coll_class.embedded = opts[:embedded]
|
|
34
|
+
entry_schema = model_class.schema
|
|
35
|
+
coll_class.instance_eval do
|
|
36
|
+
text :id
|
|
37
|
+
scalar :href
|
|
38
|
+
text :count
|
|
39
|
+
scalar :href if opts[:embedded]
|
|
40
|
+
array self.entry_name, :schema => entry_schema, :xml_name => model_name
|
|
41
|
+
array :operations do
|
|
42
|
+
scalar :rel, :href
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
coll_class
|
|
46
|
+
end
|
|
47
|
+
|
|
21
48
|
end
|
|
22
49
|
|
|
23
50
|
# Make sure the base schema gets cloned
|
|
24
|
-
|
|
51
|
+
schema
|
|
25
52
|
|
|
53
|
+
# You can initialize collection by passing the Hash representation of the
|
|
54
|
+
# collection or passing another Collection object.
|
|
55
|
+
#
|
|
26
56
|
def initialize(values = {})
|
|
27
|
-
if values
|
|
28
|
-
values[
|
|
57
|
+
if values.kind_of?(Hash)
|
|
58
|
+
if values[:entries]
|
|
59
|
+
values[self.class.entry_name] = values.delete(:entries)
|
|
60
|
+
end
|
|
61
|
+
values[self.class.entry_name] ||= []
|
|
62
|
+
super(values)
|
|
63
|
+
else
|
|
64
|
+
super
|
|
29
65
|
end
|
|
30
|
-
values[self.class.entry_name] ||= []
|
|
31
|
-
super(values)
|
|
32
66
|
end
|
|
33
67
|
|
|
34
68
|
def entries
|
|
@@ -53,91 +87,65 @@ module CIMI::Model
|
|
|
53
87
|
end
|
|
54
88
|
|
|
55
89
|
def [](a)
|
|
56
|
-
a = entry_name if a == :entries
|
|
90
|
+
a = self.class.entry_name if a == :entries
|
|
57
91
|
super(a)
|
|
58
92
|
end
|
|
59
93
|
|
|
60
94
|
def []=(a, v)
|
|
61
|
-
a = entry_name if a == :entries
|
|
95
|
+
a = self.class.entry_name if a == :entries
|
|
62
96
|
super(a, v)
|
|
63
97
|
end
|
|
64
98
|
|
|
65
|
-
def
|
|
99
|
+
def select_attributes(attr_list)
|
|
66
100
|
self[self.class.entry_name] = entries.map do |e|
|
|
67
|
-
e.
|
|
101
|
+
e.select_attributes(attr_list)
|
|
68
102
|
end
|
|
69
103
|
self
|
|
70
104
|
end
|
|
71
|
-
|
|
72
|
-
def self.xml_tag_name
|
|
73
|
-
"Collection"
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def self.generate(model_class, opts = {})
|
|
77
|
-
model_name = model_class.name.split("::").last
|
|
78
|
-
scope = opts[:scope] || CIMI::Model
|
|
79
|
-
coll_class = Class.new(CIMI::Model::Collection)
|
|
80
|
-
scope.const_set(:"#{model_name}Collection", coll_class)
|
|
81
|
-
coll_class.entry_name = model_name.underscore.pluralize.to_sym
|
|
82
|
-
coll_class.embedded = opts[:embedded]
|
|
83
|
-
entry_schema = model_class.schema
|
|
84
|
-
coll_class.instance_eval do
|
|
85
|
-
text :id
|
|
86
|
-
scalar :href
|
|
87
|
-
text :count
|
|
88
|
-
scalar :href if opts[:embedded]
|
|
89
|
-
array self.entry_name, :schema => entry_schema, :xml_name => model_name
|
|
90
|
-
array :operations do
|
|
91
|
-
scalar :rel, :href
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
coll_class
|
|
95
|
-
end
|
|
96
105
|
end
|
|
97
106
|
|
|
98
|
-
|
|
99
|
-
# We need to reopen Base and add some stuff to avoid circular dependencies
|
|
100
|
-
#
|
|
101
|
-
class Base
|
|
102
|
-
#
|
|
103
|
-
# Toplevel collections
|
|
104
|
-
#
|
|
107
|
+
module CollectionMethods
|
|
105
108
|
|
|
106
|
-
|
|
109
|
+
def collection_class=(klass)
|
|
110
|
+
@collection_class = klass
|
|
111
|
+
end
|
|
107
112
|
|
|
108
|
-
|
|
113
|
+
def collection_class
|
|
114
|
+
@collection_class
|
|
115
|
+
end
|
|
109
116
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
def acts_as_root_entity(opts = {})
|
|
118
|
+
self.collection_class = Collection.generate(self)
|
|
119
|
+
CIMI::Model.register_as_root_entity! self, opts
|
|
120
|
+
end
|
|
114
121
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
end
|
|
131
|
-
collection_class.new(:id => id,
|
|
132
|
-
:count => entries.size,
|
|
133
|
-
:entries => entries,
|
|
134
|
-
:operations => ops,
|
|
135
|
-
:description => desc)
|
|
122
|
+
# Return a collection of entities
|
|
123
|
+
def list(context)
|
|
124
|
+
entries = find(:all, context)
|
|
125
|
+
desc = "#{self.name.split("::").last} Collection for the #{context.driver.name.capitalize} driver"
|
|
126
|
+
acts_as_root_entity unless collection_class
|
|
127
|
+
id = context.send("#{collection_class.entry_name}_url")
|
|
128
|
+
ops = []
|
|
129
|
+
cimi_entity = collection_class.entry_name.to_s.singularize
|
|
130
|
+
cimi_create = "create_#{cimi_entity}_url"
|
|
131
|
+
dcloud_create = context.deltacloud_create_method_for(cimi_entity)
|
|
132
|
+
if(context.respond_to?(cimi_create) &&
|
|
133
|
+
context.driver.respond_to?(dcloud_create)) ||
|
|
134
|
+
provides?(cimi_entity)
|
|
135
|
+
url = context.send(cimi_create)
|
|
136
|
+
ops << { :rel => "add", :href => url }
|
|
136
137
|
end
|
|
138
|
+
collection_class.new(:id => id,
|
|
139
|
+
:count => entries.size,
|
|
140
|
+
:entries => entries,
|
|
141
|
+
:operations => ops,
|
|
142
|
+
:description => desc)
|
|
137
143
|
end
|
|
138
144
|
|
|
139
|
-
def
|
|
140
|
-
find
|
|
145
|
+
def all(context)
|
|
146
|
+
find :all, context
|
|
141
147
|
end
|
|
148
|
+
|
|
142
149
|
end
|
|
150
|
+
|
|
143
151
|
end
|