deltacloud-core 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/Rakefile +2 -2
  2. data/config/drivers/aruba.yaml +3 -3
  3. data/deltacloud-core.gemspec +2 -2
  4. data/lib/cimi/collections/address_templates.rb +1 -2
  5. data/lib/cimi/collections/addresses.rb +1 -2
  6. data/lib/cimi/collections/base.rb +1 -1
  7. data/lib/cimi/collections/credentials.rb +2 -3
  8. data/lib/cimi/collections/forwarding_group_templates.rb +1 -2
  9. data/lib/cimi/collections/forwarding_groups.rb +1 -2
  10. data/lib/cimi/collections/machine_configurations.rb +1 -2
  11. data/lib/cimi/collections/machine_images.rb +1 -2
  12. data/lib/cimi/collections/machines.rb +9 -9
  13. data/lib/cimi/collections/network_configurations.rb +1 -2
  14. data/lib/cimi/collections/network_port_configurations.rb +1 -2
  15. data/lib/cimi/collections/network_port_templates.rb +1 -2
  16. data/lib/cimi/collections/network_ports.rb +1 -2
  17. data/lib/cimi/collections/network_templates.rb +1 -2
  18. data/lib/cimi/collections/networks.rb +2 -3
  19. data/lib/cimi/collections/volume_configurations.rb +1 -2
  20. data/lib/cimi/collections/volume_images.rb +1 -2
  21. data/lib/cimi/collections/volumes.rb +3 -4
  22. data/lib/cimi/helpers/cimi_helper.rb +7 -2
  23. data/lib/cimi/models.rb +6 -10
  24. data/lib/cimi/models/base.rb +48 -35
  25. data/lib/cimi/models/cloud_entry_point.rb +22 -1
  26. data/lib/cimi/models/collection.rb +42 -5
  27. data/lib/cimi/models/credential.rb +1 -1
  28. data/lib/cimi/models/disk.rb +39 -10
  29. data/lib/cimi/models/machine.rb +39 -22
  30. data/lib/cimi/models/machine_configuration.rb +4 -5
  31. data/lib/cimi/models/machine_image.rb +1 -1
  32. data/lib/cimi/models/machine_volume.rb +1 -1
  33. data/lib/cimi/models/network.rb +6 -3
  34. data/lib/cimi/models/network_port.rb +13 -2
  35. data/lib/cimi/models/schema.rb +66 -5
  36. data/lib/cimi/models/volume.rb +17 -16
  37. data/lib/cimi/models/volume_configuration.rb +7 -10
  38. data/lib/cimi/models/volume_image.rb +1 -1
  39. data/lib/deltacloud/collections/base.rb +1 -1
  40. data/lib/deltacloud/collections/firewalls.rb +2 -2
  41. data/lib/deltacloud/collections/load_balancers.rb +8 -2
  42. data/lib/deltacloud/core_ext.rb +1 -0
  43. data/lib/deltacloud/core_ext/base.rb +30 -0
  44. data/lib/deltacloud/drivers.rb +1 -1
  45. data/lib/deltacloud/drivers/base_driver.rb +1 -1
  46. data/lib/deltacloud/drivers/condor/condor_driver.rb +1 -1
  47. data/lib/deltacloud/drivers/exceptions.rb +24 -14
  48. data/lib/deltacloud/drivers/features.rb +3 -3
  49. data/lib/deltacloud/drivers/fgcp/fgcp_driver.rb +163 -92
  50. data/lib/deltacloud/drivers/mock/data/images/img1.yml +1 -0
  51. data/lib/deltacloud/drivers/mock/data/images/img2.yml +1 -0
  52. data/lib/deltacloud/drivers/mock/data/images/img3.yml +1 -0
  53. data/lib/deltacloud/drivers/mock/mock_client.rb +4 -4
  54. data/lib/deltacloud/drivers/mock/mock_driver.rb +16 -16
  55. data/lib/deltacloud/drivers/openstack/openstack_driver.rb +25 -9
  56. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +2 -1
  57. data/lib/deltacloud/drivers/terremark/terremark_driver.rb +1 -1
  58. data/lib/deltacloud/drivers/vsphere/vsphere_driver.rb +2 -0
  59. data/lib/deltacloud/helpers/deltacloud_helper.rb +29 -8
  60. data/lib/deltacloud/models/image.rb +1 -0
  61. data/lib/deltacloud/models/instance_profile.rb +4 -0
  62. data/lib/deltacloud/version.rb +1 -1
  63. data/lib/ec2/query_parser.rb +1 -1
  64. data/lib/sinatra/rack_accept.rb +5 -1
  65. data/lib/sinatra/rack_logger.rb +9 -2
  66. data/tests/cimi/collections/machine_images_test.rb +23 -6
  67. data/tests/cimi/collections/machines_test.rb +39 -0
  68. data/tests/cimi/model/collection_spec.rb +109 -0
  69. data/tests/cimi/{spec/cimi/model → model}/credential_spec.rb +1 -1
  70. data/tests/cimi/{spec/cimi/model → model}/machine_configuration_spec.rb +1 -1
  71. data/tests/cimi/{spec/cimi/model → model}/machine_image_spec.rb +1 -1
  72. data/tests/cimi/{spec/cimi/model → model}/machine_spec.rb +1 -1
  73. data/tests/cimi/{spec/cimi/model → model}/machine_template_spec.rb +1 -1
  74. data/tests/cimi/{spec/cimi/model → model}/schema_spec.rb +1 -1
  75. data/tests/cimi/{spec/cimi/model → model}/volume_configuration_spec.rb +1 -1
  76. data/tests/cimi/{spec/cimi/model → model}/volume_image_spec.rb +1 -1
  77. data/tests/cimi/{spec/cimi/model → model}/volume_spec.rb +1 -1
  78. data/tests/cimi/{spec/cimi/model → model}/volume_template_spec.rb +1 -1
  79. data/tests/cimi/{spec/spec_helper.rb → spec_helper.rb} +7 -4
  80. data/tests/drivers/base/exceptions_test.rb +8 -8
  81. data/tests/drivers/ec2/buckets_test.rb +1 -1
  82. data/tests/drivers/ec2/images_test.rb +1 -1
  83. data/tests/drivers/ec2/instance_test.rb +1 -1
  84. data/tests/drivers/ec2/keys_test.rb +2 -2
  85. data/tests/drivers/ec2/realms_test.rb +1 -1
  86. data/tests/drivers/ec2/storage_snapshots_test.rb +1 -1
  87. data/tests/drivers/gogrid/hardware_profiles_test.rb +1 -1
  88. data/tests/drivers/gogrid/images_test.rb +1 -1
  89. data/tests/drivers/gogrid/instances_test.rb +1 -1
  90. data/tests/drivers/gogrid/realms_test.rb +1 -1
  91. data/tests/drivers/mock/images_test.rb +7 -2
  92. data/tests/drivers/mock/instances_test.rb +1 -1
  93. data/tests/drivers/mock/keys_test.rb +2 -2
  94. data/tests/drivers/mock/realms_test.rb +1 -1
  95. data/tests/drivers/mock/storage_snapshots_test.rb +1 -1
  96. data/tests/drivers/mock/storage_volumes_test.rb +1 -1
  97. data/tests/drivers/openstack/hardware_profiles_test.rb +3 -3
  98. data/tests/drivers/openstack/images_test.rb +1 -1
  99. data/tests/drivers/openstack/instances_test.rb +1 -1
  100. data/tests/drivers/openstack/keys_test.rb +2 -2
  101. data/tests/drivers/openstack/realms_test.rb +1 -1
  102. data/tests/drivers/rhevm/common.rb +3 -3
  103. data/tests/drivers/rhevm/images_test.rb +13 -13
  104. data/tests/drivers/rhevm/instance_test.rb +22 -22
  105. data/tests/drivers/rhevm/provider_test.rb +3 -3
  106. data/tests/drivers/rhevm/realms_test.rb +7 -7
  107. data/tests/test_helper.rb +0 -5
  108. data/views/api/show.xml.haml +6 -3
  109. data/views/errors/401.html.haml +0 -16
  110. data/views/errors/404.html.haml +2 -3
  111. data/views/errors/500.html.haml +6 -5
  112. data/views/images/show.html.haml +5 -1
  113. data/views/images/show.xml.haml +8 -3
  114. data/views/instances/new.html.haml +1 -1
  115. data/views/instances/show.xml.haml +1 -1
  116. data/views/load_balancers/show.html.haml +1 -1
  117. metadata +761 -778
  118. data/lib/cimi/models/disk_collection.rb +0 -37
  119. data/lib/cimi/models/machine_volume_collection.rb +0 -34
  120. data/lib/cimi/models/network_port_collection.rb +0 -51
  121. data/lib/cimi/models/network_port_configuration_collection.rb +0 -35
  122. data/lib/cimi/models/network_port_template_collection.rb +0 -37
@@ -15,15 +15,32 @@
15
15
 
16
16
  class CIMI::Model::CloudEntryPoint < CIMI::Model::Base
17
17
 
18
+ # All possible CIMI collections, in the order in which they should appear
19
+ # in the CEP
20
+ COLLECTIONS = [ "resourceMetadata", "systems", "systemTemplates",
21
+ "machines" , "machineTemplates", "machineConfigs",
22
+ "machineImages", "credentials", "credentialTemplates",
23
+ "volumes", "volumeTemplates", "volumeConfigs", "volumeImages",
24
+ "networks", "networkTemplates", "networkConfigs", "networkPorts",
25
+ "networkPortTemplates", "networkPortConfigs",
26
+ "addresses", "addressTemplates", "forwardingGroups",
27
+ "forwardingGroupTemplates",
28
+ "jobs", "meters", "meterTemplates", "meterConfigs",
29
+ "eventLogs", "eventLogTemplates" ]
30
+
18
31
  text :base_uri, :xml_name => "baseURI", :json_name => "baseURI"
19
32
 
33
+ COLLECTIONS.each do |coll|
34
+ href coll.underscore
35
+ end
36
+
20
37
  def self.create(context)
21
38
  self.new(entities(context).merge({
22
39
  :name => context.driver.name,
23
40
  :description => "Cloud Entry Point for the Deltacloud #{context.driver.name} driver",
24
41
  :id => context.cloudEntryPoint_url,
25
42
  :base_uri => context.base_uri,
26
- :created => Time.now
43
+ :created => Time.now.xmlschema
27
44
  }))
28
45
  end
29
46
 
@@ -39,6 +56,10 @@ class CIMI::Model::CloudEntryPoint < CIMI::Model::Base
39
56
  end
40
57
  end
41
58
 
59
+ def entities
60
+ @attribute_values.clone.delete_if { |key, value| !value.respond_to? :href }
61
+ end
62
+
42
63
  private
43
64
 
44
65
  def self.href_defined?(resource)
@@ -14,10 +14,10 @@
14
14
  # under the License.
15
15
 
16
16
  module CIMI::Model
17
- class Collection < Base
17
+ class Collection < Resource
18
18
 
19
19
  class << self
20
- attr_accessor :entry_name
20
+ attr_accessor :entry_name, :embedded
21
21
  end
22
22
 
23
23
  # Make sure the base schema gets cloned
@@ -27,11 +27,29 @@ module CIMI::Model
27
27
  if values[:entries]
28
28
  values[self.class.entry_name] = values.delete(:entries)
29
29
  end
30
+ values[self.class.entry_name] ||= []
30
31
  super(values)
31
32
  end
32
33
 
33
34
  def entries
34
- self[entry_name]
35
+ self[self.class.entry_name]
36
+ end
37
+
38
+ # Prepare to serialize
39
+ def prepare
40
+ self.count = self.entries.size
41
+ if self.class.embedded
42
+ ["id", "href"].each { |a| self[a] = nil if self[a] == "" }
43
+ # Handle href and id, which are really just aliases of one another
44
+ unless self.href || self.id
45
+ raise "Collection #{self.class.name} must have one of id and href set"
46
+ end
47
+ if self.href && self.id && self.href != self.id
48
+ raise "id and href must be identical for collection #{self.class.name}, id = #{id.inspect}, href = #{href.inspect}"
49
+ end
50
+ self.href ||= self.id
51
+ self.id ||= self.href
52
+ end
35
53
  end
36
54
 
37
55
  def [](a)
@@ -44,18 +62,30 @@ module CIMI::Model
44
62
  super(a, v)
45
63
  end
46
64
 
65
+ def filter_attributes(attr_list)
66
+ self[self.class.entry_name] = entries.map do |e|
67
+ e.filter_attributes(attr_list)
68
+ end
69
+ self
70
+ end
71
+
47
72
  def self.xml_tag_name
48
73
  "Collection"
49
74
  end
50
75
 
51
- def self.generate(model_class)
76
+ def self.generate(model_class, opts = {})
52
77
  model_name = model_class.name.split("::").last
78
+ scope = opts[:scope] || CIMI::Model
53
79
  coll_class = Class.new(CIMI::Model::Collection)
54
- CIMI::Model.const_set(:"#{model_name}Collection", coll_class)
80
+ scope.const_set(:"#{model_name}Collection", coll_class)
55
81
  coll_class.entry_name = model_name.underscore.pluralize.to_sym
82
+ coll_class.embedded = opts[:embedded]
56
83
  entry_schema = model_class.schema
57
84
  coll_class.instance_eval do
85
+ text :id
86
+ scalar :href
58
87
  text :count
88
+ scalar :href if opts[:embedded]
59
89
  array self.entry_name, :schema => entry_schema, :xml_name => model_name
60
90
  array :operations do
61
91
  scalar :rel, :href
@@ -87,9 +117,16 @@ module CIMI::Model
87
117
  entries = find(:all, context)
88
118
  desc = "#{self.name.split("::").last} Collection for the #{context.driver.name.capitalize} driver"
89
119
  id = context.send("#{collection_class.entry_name}_url")
120
+ ops = []
121
+ create = "create_#{collection_class.entry_name.to_s.singularize}_url"
122
+ if context.respond_to?(create)
123
+ url = context.send(create)
124
+ ops << { :rel => "add", :href => url }
125
+ end
90
126
  collection_class.new(:id => id, :name => 'default',
91
127
  :count => entries.size,
92
128
  :entries => entries,
129
+ :operations => ops,
93
130
  :description => desc)
94
131
  end
95
132
  end
@@ -55,7 +55,7 @@ class CIMI::Model::Credential < CIMI::Model::Base
55
55
  :password => key.is_password? ? key.password : key.fingerprint,
56
56
  :key => key.is_key? ? key.pem_rsa_key : nil,
57
57
  :id => context.credential_url(key.id),
58
- :created => Time.now
58
+ :created => Time.now.xmlschema
59
59
  )
60
60
  end
61
61
 
@@ -24,17 +24,46 @@ class CIMI::Model::Disk < CIMI::Model::Base
24
24
 
25
25
  def self.find(instance, machine_config, context, id=:all)
26
26
  if id == :all
27
- storage_override = instance.instance_profile.overrides.find { |p, v| p == :storage }
28
- capacity = storage_override.nil? ? machine_config.disks[0][:capacity] : context.to_kibibyte(storage_override[1].to_i, "MB")
29
- name = instance.id+"_disk_#{capacity}" #assuming one disk for now...
30
- [ self.new(
31
- :id => context.machine_url(instance.id)+"/disks/#{name}",
32
- :name => name,
33
- :description => "DiskCollection for Machine #{instance.id}",
34
- :created => instance.launch_time,
35
- :capacity => capacity
36
- ) ]
27
+ return machine_config.disks if machine_config
28
+
29
+ capacity = false
30
+
31
+ if instance
32
+ if instance.instance_profile.override? :storage
33
+ capacity = context.to_kibibyte(instance.instance_profile.storage, 'MB')
34
+ else
35
+ hw_profile = context.driver.hardware_profile(context.credentials, :id => instance.instance_profile.name)
36
+ if hw_profile.storage
37
+ capacity = context.to_kibibyte(hw_profile.storage.value, 'MB')
38
+ end
39
+ end
40
+
41
+ return [] unless capacity
42
+
43
+ name = instance.id+"_disk_#{capacity}" #assuming one disk for now...
44
+
45
+ [self.new(
46
+ :id => context.machine_url(instance.id)+"/disks/#{name}",
47
+ :name => name,
48
+ :description => "Disk for Machine #{instance.id}",
49
+ :created => instance.launch_time.nil? ? Time.now.xmlschema : Time.parse(instance.launch_time).xmlschema,
50
+ :capacity => capacity
51
+ )]
52
+ end
37
53
  else
38
54
  end
39
55
  end
56
+
57
+ def self.collection_for_instance(instance_id, context)
58
+ instance = context.driver.instance(context.credentials, :id => instance_id)
59
+ disks = find(instance, nil, context)
60
+ CIMI::Model::DiskCollection.new(
61
+ :id => context.url("/machines/#{instance_id}/disks"),
62
+ :name => 'default',
63
+ :count => disks.size,
64
+ :description => "Disk collection for Machine #{instance_id}",
65
+ :entries => disks
66
+ )
67
+ end
68
+
40
69
  end
@@ -22,13 +22,8 @@ class CIMI::Model::Machine < CIMI::Model::Base
22
22
 
23
23
  text :memory
24
24
 
25
- href :event_log
26
-
27
- href :disks
28
-
29
- href :volumes
30
-
31
- href :network_interfaces
25
+ collection :disks, :class => CIMI::Model::Disk
26
+ collection :volumes, :class => CIMI::Model::MachineVolume
32
27
 
33
28
  array :meters do
34
29
  scalar :href
@@ -52,9 +47,17 @@ class CIMI::Model::Machine < CIMI::Model::Base
52
47
 
53
48
  def self.create_from_json(body, context)
54
49
  json = JSON.parse(body)
55
- hardware_profile_id = xml['machineTemplate']['machineConfig']["href"].split('/').last
56
- image_id = xml['machineTemplate']['machineImage']["href"].split('/').last
57
- instance = context.create_instance(context.credentials, image_id, { :hwp_id => hardware_profile_id })
50
+ machine_template = json['machineTemplate']
51
+ hardware_profile_id = machine_template['machineConfig']["href"].split('/').last
52
+ image_id = machine_template['machineImage']["href"].split('/').last
53
+ additional_params = {}
54
+ 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
+ instance = context.driver.create_instance(context.credentials, image_id, {
59
+ :hwp_id => hardware_profile_id
60
+ }.merge(additional_params))
58
61
  from_instance(instance, context)
59
62
  end
60
63
 
@@ -64,7 +67,7 @@ class CIMI::Model::Machine < CIMI::Model::Base
64
67
  hardware_profile_id = machine_template['machineConfig'][0]["href"].split('/').last
65
68
  image_id = machine_template['machineImage'][0]["href"].split('/').last
66
69
  additional_params = {}
67
- additional_params[:name] =xml['name'][0] if xml['name']
70
+ additional_params[:name] = xml['name'][0] if xml['name']
68
71
  if machine_template.has_key? 'credential'
69
72
  additional_params[:keyname] = machine_template['credential'][0]["href"].split('/').last
70
73
  end
@@ -118,27 +121,39 @@ class CIMI::Model::Machine < CIMI::Model::Base
118
121
  private
119
122
  def self.from_instance(instance, context)
120
123
  cpu = memory = (instance.instance_profile.id == "opaque")? "n/a" : nil
121
- self.new(
122
- :name => instance.id,
123
- :description => instance.name,
124
- :created => instance.launch_time,
124
+ machine_conf = CIMI::Model::MachineConfiguration.find(instance.instance_profile.name, context)
125
+ machine_spec = {
126
+ :name => instance.name,
127
+ :description => "Instance #{instance.name}",
128
+ :created => instance.launch_time.nil? ? Time.now.xmlschema : Time.parse(instance.launch_time).xmlschema,
125
129
  :id => context.machine_url(instance.id),
126
130
  :state => convert_instance_state(instance.state),
127
131
  :cpu => cpu || convert_instance_cpu(instance.instance_profile, context),
128
132
  :memory => memory || convert_instance_memory(instance.instance_profile, context),
129
- :disks => {:href => context.machine_url(instance.id)+"/disks"},
130
- :network_interfaces => {:href => context.machine_url(instance.id+"/network_interfaces")},
133
+ :disks => { :href => context.machine_url(instance.id)+"/disks"},
134
+ :volumes => { :href=>context.machine_url(instance.id)+"/volumes"},
131
135
  :operations => convert_instance_actions(instance, context),
132
- :volumes=>{:href=>context.machine_url(instance.id)+"/volumes"},
133
136
  :property => convert_instance_properties(instance, context)
134
- )
137
+ }
138
+ if context.expand? :disks
139
+ machine_spec[:disks] = CIMI::Model::Disk.find(instance, machine_conf, context, :all)
140
+ end
141
+ if context.expand? :volumes
142
+ machine_spec[:volumes] = CIMI::Model::MachineVolume.find(instance.id, context, :all)
143
+ end
144
+ machine = self.new(machine_spec)
145
+ machine
135
146
  end
136
147
 
137
148
  # FIXME: This will convert 'RUNNING' state to 'STARTED'
138
149
  # which is defined in CIMI (p65)
139
150
  #
140
151
  def self.convert_instance_state(state)
141
- ('RUNNING' == state) ? 'STARTED' : state
152
+ case state
153
+ when "RUNNING" then "STARTED"
154
+ when "PENDING" then "CREATING" #aruba only exception... could be "STARTING" here
155
+ else state
156
+ end
142
157
  end
143
158
 
144
159
  def self.convert_instance_properties(instance, context)
@@ -162,7 +177,7 @@ class CIMI::Model::Machine < CIMI::Model::Base
162
177
  def self.convert_instance_memory(profile, context)
163
178
  machine_conf = CIMI::Model::MachineConfiguration.find(profile.name, context)
164
179
  memory_override = profile.overrides.find { |p, v| p == :memory }
165
- memory_override.nil? ? machine_conf.memory : context.to_kibibyte(memory_override[1].to_i,"MB")
180
+ memory_override.nil? ? machine_conf.memory.to_i : context.to_kibibyte(memory_override[1].to_i,"MB")
166
181
  end
167
182
 
168
183
  def self.convert_instance_addresses(instance)
@@ -179,11 +194,13 @@ class CIMI::Model::Machine < CIMI::Model::Base
179
194
  end
180
195
 
181
196
  def self.convert_instance_actions(instance, context)
182
- instance.actions.collect do |action|
197
+ actions = instance.actions.collect do |action|
183
198
  action = :destroy if action == :delete # In CIMI destroy operation become delete
184
199
  action = :restart if action == :reboot # In CIMI reboot operation become restart
185
200
  { :href => context.send(:"#{action}_machine_url", instance.id), :rel => "http://schemas.dmtf.org/cimi/1/action/#{action}" }
186
201
  end
202
+ actions << { :href => context.send(:"machine_images_url"), :rel => "http://schemas.dmtf.org/cimi/1/action/capture" } if instance.can_create_image?
203
+ actions
187
204
  end
188
205
 
189
206
  def self.convert_storage_volumes(instance, context)
@@ -17,8 +17,8 @@ class CIMI::Model::MachineConfiguration < CIMI::Model::Base
17
17
 
18
18
  acts_as_root_entity :as => "machineConfigs"
19
19
 
20
- text :memory
21
20
  text :cpu
21
+ text :memory
22
22
 
23
23
  array :disks do
24
24
  text :capacity
@@ -42,7 +42,6 @@ class CIMI::Model::MachineConfiguration < CIMI::Model::Base
42
42
  end
43
43
 
44
44
  private
45
-
46
45
  def self.from_hardware_profile(profile, context)
47
46
  # We accept just profiles with all properties set
48
47
  return unless profile.memory or profile.cpu or profile.storage
@@ -51,12 +50,12 @@ class CIMI::Model::MachineConfiguration < CIMI::Model::Base
51
50
  storage = profile.storage ? context.to_kibibyte((profile.storage.value || profile.storage.default), profile.storage.unit) : nil
52
51
  machine_hash = {
53
52
  :name => profile.name,
54
- :description => "Machine Configuration with #{memory} #{profile.memory.unit} "+
53
+ :description => "Machine Configuration with #{memory} KiB "+
55
54
  "of memory and #{cpu} CPU",
56
55
  :cpu => ( cpu if cpu ) ,
57
- :created => Time.now.to_s, # FIXME: DC hardware_profile has no mention about created_at
56
+ :created => Time.now.xmlschema, # FIXME: DC hardware_profile has no mention about created_at
58
57
  :memory => (memory if memory),
59
- :disks => ( [ { :capacity => storage } ] if storage ),
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...,
60
59
  :id => context.machine_configuration_url(profile.name)
61
60
  }
62
61
  self.new(machine_hash)
@@ -40,7 +40,7 @@ class CIMI::Model::MachineImage < CIMI::Model::Base
40
40
  :name => image.id,
41
41
  :id => context.machine_image_url(image.id),
42
42
  :description => image.description,
43
- :created => Time.now.to_s,
43
+ :created => Time.now.xmlschema,
44
44
  :image_location => { :href => "#{context.driver.name}://#{image.id}" } # FIXME
45
45
  )
46
46
  end
@@ -30,7 +30,7 @@ class CIMI::Model::MachineVolume < CIMI::Model::Base
30
30
  :id => context.machine_url(instance_id)+"/volumes/#{vol.id}",
31
31
  :name => vol.id,
32
32
  :description => "MachineVolume #{vol.id} for Machine #{instance_id}",
33
- :created => vol.created,
33
+ :created => Time.parse(vol.created).xmlschema,
34
34
  :initial_location => vol.device,
35
35
  :volume => {:href=>context.volume_url(vol.id)}
36
36
  ) if vol.instance_id == instance_id
@@ -25,12 +25,10 @@ class CIMI::Model::Network < CIMI::Model::Base
25
25
 
26
26
  text :class_of_service
27
27
 
28
- href :network_ports
28
+ collection :network_ports, :class => CIMI::Model::NetworkPort
29
29
 
30
30
  href :forwarding_group
31
31
 
32
- href :event_log
33
-
34
32
  array :meters do
35
33
  scalar :href
36
34
  end
@@ -46,6 +44,11 @@ class CIMI::Model::Network < CIMI::Model::Base
46
44
  else
47
45
  networks = context.driver.networks(context.credentials, {:id=>id, :env=>context})
48
46
  end
47
+ if context.expand? :networkPorts
48
+ networks.each do |network|
49
+ network.network_ports = CIMI::Model::NetworkPort.collection_for_network(network.id, context)
50
+ end
51
+ end
49
52
  networks
50
53
  end
51
54
 
@@ -25,8 +25,6 @@ class CIMI::Model::NetworkPort < CIMI::Model::Base
25
25
 
26
26
  text :class_of_service
27
27
 
28
- href :event_log
29
-
30
28
  array :meters do
31
29
  scalar :href
32
30
  end
@@ -76,6 +74,19 @@ class CIMI::Model::NetworkPort < CIMI::Model::Base
76
74
  end
77
75
  end
78
76
 
77
+ def self.collection_for_network(network_id, context)
78
+ net_url = context.network_url(network_id)
79
+ network_ports = CIMI::Model::NetworkPort.all(context)
80
+ ports_collection = network_ports.inject([]){|res, current| res << current if current.network.href == net_url ; res}
81
+ CIMI::Model::NetworkPortCollection.new(
82
+ :id => net_url+"/network_ports",
83
+ :name => 'default',
84
+ :created => Time.now,
85
+ :description => "#{context.driver.name.capitalize} NetworkPortCollection",
86
+ :count => ports_collection.size,
87
+ :network_ports => ports_collection
88
+ )
89
+ end
79
90
 
80
91
  private
81
92
 
@@ -46,6 +46,10 @@ class CIMI::Model::Schema
46
46
  def to_json(model, json)
47
47
  json[@json_name] = model[@name] if model and model[@name]
48
48
  end
49
+
50
+ def convert(value)
51
+ value
52
+ end
49
53
  end
50
54
 
51
55
  class Scalar < Attribute
@@ -212,6 +216,54 @@ class CIMI::Model::Schema
212
216
  end
213
217
  end
214
218
 
219
+ class Collection < Attribute
220
+ def initialize(name, opts = {})
221
+ params = {}
222
+ params[:scope] = opts.delete(:scope)
223
+ super(name, opts)
224
+ unless opts[:class]
225
+ raise "Specify the class of collection entries using :class"
226
+ end
227
+ params[:embedded] = true
228
+ @collection_class = CIMI::Model::Collection.generate(opts[:class], params)
229
+ end
230
+
231
+ def from_xml(xml, model)
232
+ model[name] = @collection_class.schema.from_xml(xml[xml_name].first, {})
233
+ end
234
+
235
+ def from_json(json, model)
236
+ model[name] = @collection_class.schema.from_json(json[json_name], {})
237
+ end
238
+
239
+ def to_xml(model, xml)
240
+ model[name].prepare
241
+ if model[name].entries.empty?
242
+ xml[xml_name] = { "href" => model[name].href }
243
+ else
244
+ xml[xml_name] = @collection_class.schema.to_xml(model[name])
245
+ end
246
+ end
247
+
248
+ def to_json(model, json)
249
+ model[name].prepare
250
+ if model[name].entries.empty?
251
+ json[json_name] = { "href" => model[name].href }
252
+ else
253
+ json[json_name] = @collection_class.schema.to_json(model[name])
254
+ end
255
+ end
256
+
257
+ # Convert a Hash or Array to an instance of the collection class
258
+ def convert(value)
259
+ if value.is_a?(::Array)
260
+ @collection_class.new(:entries => value)
261
+ else
262
+ @collection_class.new(value || {})
263
+ end
264
+ end
265
+ end
266
+
215
267
  #
216
268
  # The actual Schema class
217
269
  #
@@ -222,6 +274,16 @@ class CIMI::Model::Schema
222
274
  @attributes = []
223
275
  end
224
276
 
277
+ def collections
278
+ @attributes.select { |a| a.is_a?(Collection) }
279
+ end
280
+
281
+ def convert(name, value)
282
+ attr = @attributes.find { |a| a.name == name }
283
+ raise "Unknown attribute #{name}" unless attr
284
+ attr.convert(value)
285
+ end
286
+
225
287
  def from_xml(xml, model = {})
226
288
  @attributes.freeze
227
289
  @attributes.each { |attr| attr.from_xml(xml, model) }
@@ -237,6 +299,7 @@ class CIMI::Model::Schema
237
299
  def to_xml(model, xml = nil)
238
300
  xml ||= OrderedHash.new
239
301
  @attributes.freeze
302
+ model.prepare if model.respond_to?(:prepare)
240
303
  @attributes.each { |attr| attr.to_xml(model, xml) }
241
304
  xml
242
305
  end
@@ -252,6 +315,7 @@ class CIMI::Model::Schema
252
315
 
253
316
  def to_json(model, json = {})
254
317
  @attributes.freeze
318
+ model.prepare if model.respond_to?(:prepare)
255
319
  @attributes.each { |attr| attr.to_json(model, json) }
256
320
  json
257
321
  end
@@ -293,11 +357,8 @@ class CIMI::Model::Schema
293
357
  end
294
358
 
295
359
  def collection(name, opts={})
296
- text :count
297
-
298
- array :operations do
299
- scalar :rel, :href
300
- end
360
+ opts[:scope] = self.class
361
+ add_attributes!([name, opts], Collection)
301
362
  end
302
363
  end
303
364