deltacloud-core 1.0.5 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/Rakefile +10 -2
  2. data/bin/deltacloudd +10 -10
  3. data/config.ru +2 -1
  4. data/config/drivers/digitalocean.yaml +3 -0
  5. data/deltacloud-core.gemspec +13 -6
  6. data/lib/cimi/collections.rb +1 -1
  7. data/lib/cimi/collections/address_templates.rb +27 -3
  8. data/lib/cimi/collections/addresses.rb +1 -1
  9. data/lib/cimi/collections/base.rb +1 -0
  10. data/lib/cimi/collections/cloud_entry_point.rb +4 -0
  11. data/lib/cimi/collections/credentials.rb +2 -2
  12. data/lib/cimi/collections/machine_images.rb +20 -0
  13. data/lib/cimi/collections/machine_templates.rb +72 -0
  14. data/lib/cimi/collections/machines.rb +50 -41
  15. data/lib/cimi/collections/network_ports.rb +3 -3
  16. data/lib/cimi/collections/networks.rb +4 -4
  17. data/lib/cimi/collections/resource_metadata.rb +1 -1
  18. data/lib/cimi/collections/volume_configurations.rb +25 -0
  19. data/lib/cimi/collections/volume_images.rb +21 -1
  20. data/lib/cimi/collections/volume_templates.rb +69 -0
  21. data/lib/cimi/collections/volumes.rb +5 -10
  22. data/lib/cimi/dependencies.rb +0 -1
  23. data/lib/cimi/helpers.rb +4 -1
  24. data/lib/cimi/helpers/cimi_helper.rb +62 -0
  25. data/lib/cimi/helpers/database_helper.rb +95 -0
  26. data/lib/cimi/models.rb +15 -1
  27. data/lib/cimi/models/address.rb +10 -5
  28. data/lib/cimi/models/address_template.rb +67 -3
  29. data/lib/cimi/models/base.rb +8 -5
  30. data/lib/cimi/models/cloud_entry_point.rb +6 -1
  31. data/lib/cimi/models/collection.rb +9 -4
  32. data/lib/cimi/models/disk.rb +6 -1
  33. data/lib/cimi/models/errors.rb +8 -0
  34. data/lib/cimi/models/machine.rb +68 -42
  35. data/lib/cimi/models/machine_configuration.rb +2 -2
  36. data/lib/cimi/models/machine_image.rb +41 -6
  37. data/lib/cimi/models/machine_template.rb +58 -0
  38. data/lib/cimi/models/machine_volume.rb +51 -3
  39. data/lib/cimi/models/resource_metadata.rb +88 -25
  40. data/lib/cimi/models/schema.rb +19 -5
  41. data/lib/cimi/models/volume.rb +66 -30
  42. data/lib/cimi/models/volume_configuration.rb +53 -21
  43. data/lib/cimi/models/volume_image.rb +24 -9
  44. data/lib/cimi/models/volume_template.rb +61 -0
  45. data/lib/cimi/server.rb +0 -6
  46. data/lib/db.rb +82 -0
  47. data/lib/db/address_template.rb +15 -0
  48. data/lib/db/entity.rb +22 -0
  49. data/lib/db/machine_template.rb +10 -0
  50. data/lib/db/provider.rb +13 -0
  51. data/lib/db/volume_configuration.rb +10 -0
  52. data/lib/db/volume_template.rb +10 -0
  53. data/lib/deltacloud/collections/addresses.rb +1 -1
  54. data/lib/deltacloud/collections/base.rb +12 -1
  55. data/lib/deltacloud/collections/buckets.rb +41 -8
  56. data/lib/deltacloud/collections/drivers.rb +1 -1
  57. data/lib/deltacloud/collections/firewalls.rb +2 -2
  58. data/lib/deltacloud/collections/images.rb +1 -1
  59. data/lib/deltacloud/collections/instances.rb +7 -1
  60. data/lib/deltacloud/collections/keys.rb +1 -1
  61. data/lib/deltacloud/collections/load_balancers.rb +4 -4
  62. data/lib/deltacloud/collections/storage_snapshots.rb +5 -1
  63. data/lib/deltacloud/collections/storage_volumes.rb +7 -3
  64. data/lib/deltacloud/drivers/base_driver.rb +10 -9
  65. data/lib/deltacloud/drivers/cimi_features.rb +42 -0
  66. data/lib/deltacloud/drivers/digitalocean/digitalocean_driver.rb +307 -0
  67. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +40 -14
  68. data/lib/deltacloud/drivers/exceptions.rb +8 -0
  69. data/lib/deltacloud/drivers/features.rb +19 -2
  70. data/lib/deltacloud/drivers/fgcp/fgcp_client.rb +11 -0
  71. data/lib/deltacloud/drivers/fgcp/fgcp_driver.rb +83 -11
  72. data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +1 -1
  73. data/lib/deltacloud/drivers/mock/mock_client.rb +2 -4
  74. data/lib/deltacloud/drivers/mock/mock_driver.rb +29 -0
  75. data/lib/deltacloud/drivers/openstack/openstack_driver.rb +153 -36
  76. data/lib/deltacloud/drivers/rackspace/anti_cache_monkey_patch.rb +20 -0
  77. data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +1 -0
  78. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +30 -12
  79. data/lib/deltacloud/drivers/sbc/sbc_client.rb +0 -1
  80. data/lib/deltacloud/drivers/sbc/sbc_driver.rb +5 -1
  81. data/lib/deltacloud/drivers/vsphere/vsphere_client.rb +1 -1
  82. data/lib/deltacloud/drivers/vsphere/vsphere_driver.rb +19 -9
  83. data/lib/deltacloud/helpers/blob_stream_helper.rb +42 -3
  84. data/lib/deltacloud/helpers/deltacloud_helper.rb +31 -14
  85. data/lib/deltacloud/models/address.rb +9 -0
  86. data/lib/deltacloud/models/base_model.rb +4 -0
  87. data/lib/deltacloud/models/blob.rb +12 -0
  88. data/lib/deltacloud/models/bucket.rb +9 -0
  89. data/lib/deltacloud/models/firewall.rb +13 -1
  90. data/lib/deltacloud/models/firewall_rule.rb +14 -0
  91. data/lib/deltacloud/models/hardware_profile.rb +14 -0
  92. data/lib/deltacloud/models/image.rb +15 -0
  93. data/lib/deltacloud/models/instance.rb +40 -1
  94. data/lib/deltacloud/models/instance_address.rb +9 -0
  95. data/lib/deltacloud/models/key.rb +15 -0
  96. data/lib/deltacloud/models/load_balancer.rb +20 -0
  97. data/lib/deltacloud/models/metric.rb +15 -0
  98. data/lib/deltacloud/models/provider.rb +8 -0
  99. data/lib/deltacloud/models/realm.rb +9 -0
  100. data/lib/deltacloud/models/state_machine.rb +8 -0
  101. data/lib/deltacloud/models/storage_snapshot.rb +11 -0
  102. data/lib/deltacloud/models/storage_volume.rb +24 -0
  103. data/lib/deltacloud/server.rb +1 -3
  104. data/lib/deltacloud/version.rb +2 -1
  105. data/lib/deltacloud_rack.rb +1 -1
  106. data/tests/cimi/db/database_helper_test.rb +190 -0
  107. data/tests/cimi/db/db_helper.rb +30 -0
  108. data/tests/cimi/db/schema_test.rb +94 -0
  109. data/tests/cimi/model/collection_spec.rb +0 -1
  110. data/tests/cimi/model/machine_spec.rb +17 -0
  111. data/tests/cimi/spec_helper.rb +3 -2
  112. data/tests/deltacloud/collections/buckets_collection_test.rb +3 -0
  113. data/tests/deltacloud/collections/drivers_collection_test.rb +10 -0
  114. data/tests/deltacloud/collections/hardware_profiles_collection_test.rb +4 -0
  115. data/tests/deltacloud/collections/images_collection_test.rb +4 -0
  116. data/tests/deltacloud/collections/instances_collection_test.rb +14 -1
  117. data/tests/deltacloud/collections/keys_collection_test.rb +4 -0
  118. data/tests/deltacloud/collections/realms_collection_test.rb +47 -0
  119. data/tests/deltacloud/collections/storage_snapshots_collection_test.rb +47 -0
  120. data/tests/deltacloud/collections/storage_volumes_collection_test.rb +47 -0
  121. data/tests/deltacloud/common.rb +15 -0
  122. data/tests/deltacloud/deltacloud_helper_test.rb +0 -4
  123. data/tests/deltacloud/launcher_test.rb +108 -0
  124. data/tests/drivers/ec2/buckets_test.rb +2 -1
  125. data/tests/drivers/mock/buckets_test.rb +27 -0
  126. data/tests/drivers/mock/instances_test.rb +6 -0
  127. data/tests/drivers/openstack/common.rb +1 -1
  128. data/tests/drivers/openstack/hardware_profiles_test.rb +2 -1
  129. data/tests/drivers/openstack/instances_test.rb +18 -17
  130. data/tests/drivers/rhevm/common.rb +1 -0
  131. data/tests/drivers/rhevm/images_test.rb +1 -1
  132. data/tests/drivers/rhevm/instance_test.rb +7 -7
  133. data/tests/helpers/rack/rack_matrix_params_test.rb +0 -2
  134. data/tests/test_helper.rb +2 -1
  135. data/views/errors/403.xml.haml +6 -0
  136. data/views/errors/409.html.haml +47 -0
  137. data/views/errors/409.xml.haml +11 -0
  138. data/views/errors/502.html.haml +6 -5
  139. data/views/images/show.xml.haml +3 -2
  140. data/views/instances/new.html.haml +1 -1
  141. metadata +77 -30
@@ -51,7 +51,7 @@ class CIMI::Model::Address < CIMI::Model::Base
51
51
 
52
52
  def self.create(request_body, context, type)
53
53
  input = (type == :xml)? XmlSimple.xml_in(request_body, {"ForceArray"=>false, "NormaliseSpace"=>2}) : JSON.parse(request_body)
54
- if input["addressTemplate"]["href"] #by reference
54
+ if input['addressTemplate'] and input["addressTemplate"]["href"] #by reference
55
55
  address_template = CIMI::Model::AddressTemplate.find(context.href_id(input["addressTemplate"]["href"], :address_templates), context)
56
56
  else
57
57
  case type
@@ -64,27 +64,32 @@ class CIMI::Model::Address < CIMI::Model::Base
64
64
  end
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
- context.driver.create_address(context.credentials, params)
67
+ address = context.driver.create_address(context.credentials, params)
68
+ store_attributes_for(address, input)
69
+ from_address(address, context)
68
70
  end
69
71
 
70
72
  def self.delete!(id, context)
71
73
  context.driver.delete_address(context.credentials, id)
74
+ delete_attributes_for(::Address.new(:id => id))
72
75
  end
73
76
 
74
77
  private
75
78
 
76
79
  def self.from_address(address, context)
80
+ stored_attributes = load_attributes_for(address)
77
81
  self.new(
78
- :name => address.id,
82
+ :name => stored_attributes[:name] || address.id,
79
83
  :id => context.address_url(address.id),
80
- :description => "Address #{address.id}",
84
+ :description => stored_attributes[:description] || "Address #{address.id}",
81
85
  :ip => address.id,
82
86
  :allocation => "dynamic", #or "static"
83
- :default_gateway => "unkown", #wtf
87
+ :default_gateway => "unknown", #wtf
84
88
  :dns => "unknown", #wtf
85
89
  :protocol => protocol_from_address(address.id),
86
90
  :mask => "unknown",
87
91
  :resource => (address.instance_id) ? {:href=> context.machine_url(address.instance_id)} : nil,
92
+ :property => stored_attributes[:property],
88
93
  :network => nil #unknown
89
94
  #optional:
90
95
  #:hostname =>
@@ -39,16 +39,80 @@ class CIMI::Model::AddressTemplate < CIMI::Model::Base
39
39
 
40
40
  def self.find(id, context)
41
41
  if id==:all
42
- context.driver.address_templates(context.credentials, {:env=>context})
42
+ if context.driver.respond_to? :address_templates
43
+ context.driver.address_templates(context.credentials, {:env=>context})
44
+ else
45
+ current_db.address_teplates.map { |t| from_db(t, context) }
46
+ end
43
47
  else
44
- context.driver.address_templates(context.credentials, {:id=>id, :env=>context})
48
+ if context.driver.respond_to? :address_template
49
+ context.driver.address_template(context.credentials, id, :env=>context)
50
+ else
51
+ template = current_db.address_templates_dataset.first(:id => id)
52
+ raise CIMI::Model::NotFound unless template
53
+ from_db(template, context)
54
+ end
45
55
  end
46
56
  end
47
57
 
48
- def self.create(request_body, context, type)
58
+ def self.create_from_json(body, context)
59
+ json = JSON.parse(body)
60
+ new_template = current_db.add_address_template(
61
+ :name => json['name'],
62
+ :description => json['description'],
63
+ :hostname => json['hostname'],
64
+ :ip => json['ip'],
65
+ :allocation => json['allocation'],
66
+ :default_gateway => json['default_gateway'],
67
+ :dns => json['dns'],
68
+ :protocol => json['protocol'],
69
+ :mask => json['mask'],
70
+ :ent_properties => json['properties'].to_json
71
+ )
72
+ from_db(new_template, context)
73
+ end
74
+
75
+ def self.create_from_xml(body, context)
76
+ xml = XmlSimple.xml_in(body)
77
+ xml['property'] ||= []
78
+ new_template = current_db.add_address_template(
79
+ :name => xml['name'].first,
80
+ :description => xml['description'].first,
81
+ :ip => xml['ip'].first,
82
+ :hostname => xml['hostname'].first,
83
+ :allocation => xml['allocation'].first,
84
+ :default_gateway => xml['default_gateway'].first,
85
+ :dns => xml['dns'].first,
86
+ :protocol => xml['protocol'].nil? ? nil : xml['protocol'].first,
87
+ :mask => xml['mask'].first,
88
+ :ent_properties => JSON::dump(xml['property'].inject({}) { |r, p| r[p['key']]=p['content']; r })
89
+ )
90
+ from_db(new_template, context)
49
91
  end
50
92
 
51
93
  def self.delete!(id, context)
94
+ current_db.address_templates.first(:id => id).destroy
95
+ end
96
+
97
+ private
98
+
99
+ def self.from_db(model, context)
100
+ self.new(
101
+ :id => context.address_template_url(model.id),
102
+ :name => model.name,
103
+ :description => model.description,
104
+ :ip => model.ip,
105
+ :hostname => model.hostname,
106
+ :allocation => model.allocation,
107
+ :default_gateway => model.default_gateway,
108
+ :dns => model.dns,
109
+ :protocol => model.protocol,
110
+ :mask => model.mask,
111
+ :property => JSON::parse(model.ent_properties),
112
+ :operations => [
113
+ { :href => context.destroy_address_template_url(model.id), :rel => 'http://schemas.dmtf.org/cimi/1/action/delete' }
114
+ ]
115
+ )
52
116
  end
53
117
 
54
118
  end
@@ -14,7 +14,6 @@
14
14
  # under the License.
15
15
 
16
16
  require 'xmlsimple'
17
- require 'json'
18
17
 
19
18
  # The base class for any CIMI object that we either read from a request or
20
19
  # write as a response. This class handles serializing/deserializing XML and
@@ -73,7 +72,7 @@ require 'json'
73
72
  module CIMI::Model
74
73
 
75
74
  def self.register_as_root_entity!(klass, opts = {})
76
- @root_entities ||= []
75
+ @root_entities ||= [CIMI::Model::CloudEntryPoint]
77
76
  @root_entities << klass
78
77
  name = klass.name.split("::").last.pluralize
79
78
  unless CIMI::Model::CloudEntryPoint.href_defined?(name)
@@ -109,7 +108,6 @@ class CIMI::Model::Resource
109
108
  clone_base_schema unless base_schema_cloned?
110
109
  member_name = model.name.split("::").last
111
110
  if ::Struct.const_defined?("CIMI_#{member_name}")
112
- puts "Removing struct"
113
111
  ::Struct.send(:remove_const, "CIMI_#{member_name}")
114
112
  end
115
113
  member_symbol = member_name.underscore.pluralize.to_sym
@@ -182,7 +180,7 @@ class CIMI::Model::Resource
182
180
  #
183
181
  def initialize(values = {})
184
182
  names = self.class.schema.attribute_names
185
- @attribute_values = names.inject({}) do |hash, name|
183
+ @attribute_values = names.inject(OrderedHash.new) do |hash, name|
186
184
  hash[name] = self.class.schema.convert(name, values[name])
187
185
  hash
188
186
  end
@@ -270,7 +268,10 @@ class CIMI::Model::Resource
270
268
  end
271
269
  end
272
270
 
271
+ require_relative '../helpers/database_helper'
272
+
273
273
  class CIMI::Model::Base < CIMI::Model::Resource
274
+ extend Deltacloud::Helpers::Database
274
275
  #
275
276
  # Common attributes for all resources
276
277
  #
@@ -280,9 +281,11 @@ class CIMI::Model::Base < CIMI::Model::Resource
280
281
 
281
282
  def filter_attributes(attr_list)
282
283
  attrs = attr_list.inject({}) do |result, attr|
283
- result[attr] = self.send(attr) if self.respond_to?(attr)
284
+ attr = attr.to_s.underscore
285
+ result[attr.to_sym] = self.send(attr) if self.respond_to?(attr)
284
286
  result
285
287
  end
286
288
  self.class.new(attrs)
287
289
  end
290
+
288
291
  end
@@ -15,6 +15,9 @@
15
15
 
16
16
  class CIMI::Model::CloudEntryPoint < CIMI::Model::Base
17
17
 
18
+ resource_attr :driver, :required => true
19
+ resource_attr :provider, :required => true
20
+
18
21
  # All possible CIMI collections, in the order in which they should appear
19
22
  # in the CEP
20
23
  COLLECTIONS = [ "resourceMetadata", "systems", "systemTemplates",
@@ -38,8 +41,10 @@ class CIMI::Model::CloudEntryPoint < CIMI::Model::Base
38
41
  self.new(entities(context).merge({
39
42
  :name => context.driver.name,
40
43
  :description => "Cloud Entry Point for the Deltacloud #{context.driver.name} driver",
44
+ :driver => context.driver.name,
45
+ :provider => context.current_provider,
41
46
  :id => context.cloudEntryPoint_url,
42
- :base_uri => context.base_uri,
47
+ :base_uri => context.base_uri + "/",
43
48
  :created => Time.now.xmlschema
44
49
  }))
45
50
  end
@@ -116,14 +116,19 @@ module CIMI::Model
116
116
  def list(context)
117
117
  entries = find(:all, context)
118
118
  desc = "#{self.name.split("::").last} Collection for the #{context.driver.name.capitalize} driver"
119
+ acts_as_root_entity unless collection_class
119
120
  id = context.send("#{collection_class.entry_name}_url")
120
121
  ops = []
121
- create = "create_#{collection_class.entry_name.to_s.singularize}_url"
122
- if context.respond_to?(create)
123
- url = context.send(create)
122
+ cimi_entity = collection_class.entry_name.to_s.singularize
123
+ cimi_create = "create_#{cimi_entity}_url"
124
+ dcloud_create = context.deltacloud_create_method_for(cimi_entity)
125
+ if(context.respond_to?(cimi_create) &&
126
+ context.driver.respond_to?(dcloud_create)) ||
127
+ provides?(cimi_entity)
128
+ url = context.send(cimi_create)
124
129
  ops << { :rel => "add", :href => url }
125
130
  end
126
- collection_class.new(:id => id, :name => 'default',
131
+ collection_class.new(:id => id,
127
132
  :count => entries.size,
128
133
  :entries => entries,
129
134
  :operations => ops,
@@ -57,7 +57,12 @@ class CIMI::Model::Disk < CIMI::Model::Base
57
57
  def self.collection_for_instance(instance_id, context)
58
58
  instance = context.driver.instance(context.credentials, :id => instance_id)
59
59
  disks = find(instance, nil, context)
60
- CIMI::Model::DiskCollection.new(
60
+ unless CIMI::Model.const_defined?('DiskCollection')
61
+ collection_class = CIMI::Model::Collection.generate(self)
62
+ else
63
+ collection_class = CIMI::Model::DiskCollection
64
+ end
65
+ collection_class.new(
61
66
  :id => context.url("/machines/#{instance_id}/disks"),
62
67
  :name => 'default',
63
68
  :count => disks.size,
@@ -33,6 +33,14 @@ module CIMI::Model
33
33
  end
34
34
  end
35
35
 
36
+ class UnsupportedMediaType < StandardError
37
+ attr_accessor :code
38
+ def initialize(msg="")
39
+ super(msg)
40
+ self.code=415
41
+ end
42
+ end
43
+
36
44
  class NotImplemented < StandardError
37
45
  attr_accessor :code
38
46
 
@@ -17,6 +17,11 @@ class CIMI::Model::Machine < CIMI::Model::Base
17
17
 
18
18
  acts_as_root_entity
19
19
 
20
+ resource_attr :realm, :required => false,
21
+ :constraints => lambda { |c| c.driver.realms(c.credentials).map { |r| r.id } }
22
+
23
+ resource_attr :machine_image, :required => false, :type => :href
24
+
20
25
  text :state
21
26
  text :cpu
22
27
 
@@ -48,38 +53,60 @@ class CIMI::Model::Machine < CIMI::Model::Base
48
53
  def self.create_from_json(body, context)
49
54
  json = JSON.parse(body)
50
55
  machine_template = json['machineTemplate']
51
- hardware_profile_id = machine_template['machineConfig']["href"].split('/').last
52
- image_id = machine_template['machineImage']["href"].split('/').last
56
+ if !machine_template['href'].nil?
57
+ template = current_db.machine_templates.first(:id => machine_template['href'].split('/').last)
58
+ raise 'Could not find the MachineTemplate' if template.nil?
59
+ hardware_profile_id = template.machine_config.split('/').last
60
+ image_id = template.machine_image.split('/').last
61
+ else
62
+ hardware_profile_id = machine_template['machineConfig']["href"].split('/').last
63
+ image_id = machine_template['machineImage']["href"].split('/').last
64
+ if machine_template.has_key? 'credential'
65
+ additional_params[:keyname] = machine_template['credential']["href"].split('/').last
66
+ end
67
+ end
68
+
53
69
  additional_params = {}
54
70
  additional_params[:name] = json['name'] if json['name']
55
- if machine_template.has_key? 'credential'
56
- additional_params[:keyname] = machine_template['credential']["href"].split('/').last
57
- end
58
71
  instance = context.driver.create_instance(context.credentials, image_id, {
59
72
  :hwp_id => hardware_profile_id
60
73
  }.merge(additional_params))
74
+
75
+ # Store attributes that are not supported by the backend cloud to local
76
+ # database:
77
+ store_attributes_for(instance, json)
61
78
  from_instance(instance, context)
62
79
  end
63
80
 
64
81
  def self.create_from_xml(body, context)
65
82
  xml = XmlSimple.xml_in(body)
66
- machine_template = xml['machineTemplate'][0]
67
- hardware_profile_id = machine_template['machineConfig'][0]["href"].split('/').last
68
- image_id = machine_template['machineImage'][0]["href"].split('/').last
83
+ if xml['machineTemplate'][0]['href']
84
+ template = current_db.machine_templates_dataset.first(:id => xml['machineTemplate'][0]['href'].split('/').last)
85
+ hardware_profile_id = template.machine_config.split('/').last
86
+ image_id = template.machine_image.split('/').last
87
+ else
88
+ machine_template = xml['machineTemplate'][0]
89
+ hardware_profile_id = machine_template['machineConfig'].first["href"].split('/').last
90
+ image_id = machine_template['machineImage'].first["href"].split('/').last
91
+ if machine_template.has_key? 'credential'
92
+ additional_params[:keyname] = machine_template['credential'][0]["href"].split('/').last
93
+ end
94
+ end
69
95
  additional_params = {}
70
96
  additional_params[:name] = xml['name'][0] if xml['name']
71
- if machine_template.has_key? 'credential'
72
- additional_params[:keyname] = machine_template['credential'][0]["href"].split('/').last
73
- end
74
97
  instance = context.driver.create_instance(context.credentials, image_id, {
75
98
  :hwp_id => hardware_profile_id
76
99
  }.merge(additional_params))
77
- from_instance(instance, context)
100
+
101
+ # Store attributes that are not supported by the backend cloud to local
102
+ # database:
103
+ entity = store_attributes_for(instance, xml)
104
+ from_instance(instance, context, entity.to_hash)
78
105
  end
79
106
 
80
107
  def perform(action, context, &block)
81
108
  begin
82
- if context.driver.send(:"#{action.name}_instance", context.credentials, self.name)
109
+ if context.driver.send(:"#{action.name}_instance", context.credentials, self.id.split("/").last)
83
110
  block.callback :success
84
111
  else
85
112
  raise "Operation failed to execute on given Machine"
@@ -90,42 +117,38 @@ class CIMI::Model::Machine < CIMI::Model::Base
90
117
  end
91
118
 
92
119
  def self.delete!(id, context)
120
+ delete_attributes_for Instance.new(:id => id)
93
121
  context.driver.destroy_instance(context.credentials, id)
94
122
  end
95
123
 
96
- def self.create_resource_metadata(context)
97
- cimi_resource = self.name.split("::").last
98
- metadata = CIMI::Model::ResourceMetadata.metadata_from_deltacloud_features(cimi_resource, :instances, context)
99
- unless metadata.includes_attribute?(:name)
100
- metadata.attributes << {:name=>"name", :required=>"false",
101
- :constraints=>"Determined by the cloud provider", :type=>"xs:string"}
102
- end
103
- metadata
104
- end
105
-
106
- def self.attach_volumes(volumes, context)
107
- volumes.each do |vol|
108
- context.driver.attach_storage_volume(context.credentials,
109
- {:id=>vol[:volume].name, :instance_id=>context.params[:id], :device=>vol[:attachment_point]})
110
- end
111
- self.find(context.params[:id], context)
124
+ #returns the newly attach machine_volume
125
+ def self.attach_volume(volume, location, context)
126
+ context.driver.attach_storage_volume(context.credentials,
127
+ {:id=>volume, :instance_id=>context.params[:id], :device=>location})
128
+ CIMI::Model::MachineVolume.find(context.params[:id], context, volume)
112
129
  end
113
130
 
114
- def self.detach_volumes(volumes, context)
115
- volumes.each do |vol|
116
- context.driver.detach_storage_volume(context.credentials, {:id=>vol[:volume].name, :instance_id => context.params[:id]})
117
- end
118
- self.find(context.params[:id], context)
131
+ #returns the machine_volume_collection for the given machine
132
+ def self.detach_volume(volume, location, context)
133
+ context.driver.detach_storage_volume(context.credentials,
134
+ {:id=>volume, :instance_id=>context.params[:id], :device=>location})
135
+ CIMI::Model::MachineVolume.collection_for_instance(context.params[:id], context)
119
136
  end
120
137
 
121
138
  private
122
- def self.from_instance(instance, context)
139
+ def self.from_instance(instance, context, stored_attributes=nil)
123
140
  cpu = memory = (instance.instance_profile.id == "opaque")? "n/a" : nil
124
141
  machine_conf = CIMI::Model::MachineConfiguration.find(instance.instance_profile.name, context)
142
+ stored_attributes ||= load_attributes_for(instance)
143
+ if stored_attributes[:property]
144
+ stored_attributes[:property].merge!(convert_instance_properties(instance, context))
145
+ else
146
+ stored_attributes[:property] = convert_instance_properties(instance, context)
147
+ end
125
148
  machine_spec = {
126
149
  :name => instance.name,
127
- :description => "Instance #{instance.name}",
128
- :created => instance.launch_time.nil? ? Time.now.xmlschema : Time.parse(instance.launch_time).xmlschema,
150
+ :created => instance.launch_time.nil? ? Time.now.xmlschema : Time.parse(instance.launch_time.to_s).xmlschema,
151
+ :description => "No description set for Machine #{instance.name}",
129
152
  :id => context.machine_url(instance.id),
130
153
  :state => convert_instance_state(instance.state),
131
154
  :cpu => cpu || convert_instance_cpu(instance.instance_profile, context),
@@ -133,14 +156,16 @@ class CIMI::Model::Machine < CIMI::Model::Base
133
156
  :disks => { :href => context.machine_url(instance.id)+"/disks"},
134
157
  :volumes => { :href=>context.machine_url(instance.id)+"/volumes"},
135
158
  :operations => convert_instance_actions(instance, context),
136
- :property => convert_instance_properties(instance, context)
137
- }
159
+ :property => stored_attributes
160
+ }.merge(stored_attributes)
138
161
  if context.expand? :disks
139
162
  machine_spec[:disks] = CIMI::Model::Disk.find(instance, machine_conf, context, :all)
140
163
  end
141
164
  if context.expand? :volumes
142
165
  machine_spec[:volumes] = CIMI::Model::MachineVolume.find(instance.id, context, :all)
143
166
  end
167
+ machine_spec[:realm] = instance.realm_id if instance.realm_id
168
+ machine_spec[:machine_image] = { :href => context.machine_image_url(instance.image_id) } if instance.image_id
144
169
  machine = self.new(machine_spec)
145
170
  machine
146
171
  end
@@ -195,9 +220,10 @@ class CIMI::Model::Machine < CIMI::Model::Base
195
220
 
196
221
  def self.convert_instance_actions(instance, context)
197
222
  actions = instance.actions.collect do |action|
198
- action = :destroy if action == :delete # In CIMI destroy operation become delete
199
- action = :restart if action == :reboot # In CIMI reboot operation become restart
200
- { :href => context.send(:"#{action}_machine_url", instance.id), :rel => "http://schemas.dmtf.org/cimi/1/action/#{action}" }
223
+ action = :restart if action == :reboot
224
+ name = action
225
+ name = :delete if action == :destroy # In CIMI destroy operation become delete
226
+ { :href => context.send(:"#{action}_machine_url", instance.id), :rel => "http://schemas.dmtf.org/cimi/1/action/#{name}" }
201
227
  end
202
228
  actions << { :href => context.send(:"machine_images_url"), :rel => "http://schemas.dmtf.org/cimi/1/action/capture" } if instance.can_create_image?
203
229
  actions
@@ -52,11 +52,11 @@ class CIMI::Model::MachineConfiguration < CIMI::Model::Base
52
52
  :name => profile.name,
53
53
  :description => "Machine Configuration with #{memory} KiB "+
54
54
  "of memory and #{cpu} CPU",
55
- :cpu => ( cpu if cpu ) ,
55
+ :cpu => ( cpu.to_i.to_s if cpu ) ,
56
56
  :created => Time.now.xmlschema, # FIXME: DC hardware_profile has no mention about created_at
57
57
  :memory => (memory if memory),
58
58
  :disks => ( [ { :capacity => storage, :format => (profile.storage.respond_to?(:format) ? profile.storage.format : "unknown") } ] if storage ), #no format attr for hwp - may be added if providers support...,
59
- :id => context.machine_configuration_url(profile.name)
59
+ :id => context.machine_configuration_url(profile.id)
60
60
  }
61
61
  self.new(machine_hash)
62
62
  end