deltacloud-core 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. data/Rakefile +63 -7
  2. data/bin/deltacloudd +29 -17
  3. data/config.ru +5 -3
  4. data/config/drivers/ec2.yaml +9 -0
  5. data/config/drivers/google.yaml +3 -0
  6. data/config/drivers/openstack.yaml +3 -0
  7. data/deltacloud-core.gemspec +1 -1
  8. data/lib/cimi/dependencies.rb +62 -0
  9. data/lib/cimi/helpers/cimi_helper.rb +50 -0
  10. data/lib/cimi/model.rb +52 -0
  11. data/lib/cimi/model/action.rb +24 -0
  12. data/lib/cimi/model/base.rb +249 -0
  13. data/lib/cimi/model/cloud_entry_point.rb +48 -0
  14. data/lib/cimi/model/entity_metadata.rb +83 -0
  15. data/lib/cimi/model/entity_metadata_collection.rb +31 -0
  16. data/lib/cimi/model/errors.rb +40 -0
  17. data/lib/cimi/model/machine.rb +227 -0
  18. data/lib/cimi/model/machine_admin.rb +59 -0
  19. data/lib/cimi/model/machine_admin_collection.rb +34 -0
  20. data/lib/cimi/model/machine_collection.rb +34 -0
  21. data/lib/cimi/model/machine_configuration.rb +67 -0
  22. data/lib/cimi/model/machine_configuration_collection.rb +34 -0
  23. data/lib/cimi/model/machine_image.rb +46 -0
  24. data/lib/cimi/model/machine_image_collection.rb +34 -0
  25. data/lib/cimi/model/machine_template.rb +41 -0
  26. data/lib/cimi/model/machine_template_collection.rb +34 -0
  27. data/lib/cimi/model/network.rb +69 -0
  28. data/lib/cimi/model/network_collection.rb +34 -0
  29. data/lib/cimi/model/network_configuration.rb +50 -0
  30. data/lib/cimi/model/network_configuration_collection.rb +34 -0
  31. data/lib/cimi/model/network_template.rb +26 -0
  32. data/lib/cimi/model/schema.rb +277 -0
  33. data/lib/cimi/model/volume.rb +103 -0
  34. data/lib/cimi/model/volume_collection.rb +34 -0
  35. data/lib/cimi/model/volume_configuration.rb +60 -0
  36. data/lib/cimi/model/volume_configuration_collection.rb +34 -0
  37. data/lib/cimi/model/volume_image.rb +49 -0
  38. data/lib/cimi/model/volume_image_collection.rb +34 -0
  39. data/lib/cimi/model/volume_template.rb +23 -0
  40. data/lib/cimi/model/volume_template_collection.rb +34 -0
  41. data/lib/cimi/server.rb +575 -0
  42. data/lib/deltacloud/base_driver/base_driver.rb +11 -1
  43. data/lib/deltacloud/core_ext.rb +2 -0
  44. data/lib/deltacloud/core_ext/array.rb +25 -0
  45. data/lib/deltacloud/core_ext/hash.rb +7 -0
  46. data/lib/deltacloud/core_ext/proc.rb +31 -0
  47. data/lib/deltacloud/core_ext/string.rb +15 -0
  48. data/lib/deltacloud/drivers/condor/condor_driver.rb +2 -1
  49. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +32 -10
  50. data/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb +1 -1
  51. data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +1 -1
  52. data/lib/deltacloud/drivers/google/google_driver.rb +233 -0
  53. data/lib/deltacloud/drivers/mock/data/instances/inst0.yml +7 -2
  54. data/lib/deltacloud/drivers/mock/data/instances/inst1.yml +7 -2
  55. data/lib/deltacloud/drivers/mock/data/instances/inst2.yml +7 -2
  56. data/lib/deltacloud/drivers/mock/mock_client.rb +17 -0
  57. data/lib/deltacloud/drivers/mock/mock_driver.rb +82 -8
  58. data/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +1 -1
  59. data/lib/deltacloud/drivers/openstack/openstack_driver.rb +47 -0
  60. data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +8 -8
  61. data/lib/deltacloud/drivers/rhevm/rhevm_client.rb +122 -49
  62. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +42 -22
  63. data/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb +1 -1
  64. data/lib/deltacloud/drivers/sbc/sbc_driver.rb +3 -2
  65. data/lib/deltacloud/drivers/terremark/terremark_driver.rb +2 -2
  66. data/lib/deltacloud/drivers/vsphere/vsphere_client.rb +25 -4
  67. data/lib/deltacloud/drivers/vsphere/vsphere_driver.rb +35 -12
  68. data/lib/deltacloud/hardware_profile.rb +34 -10
  69. data/lib/deltacloud/helpers/application_helper.rb +3 -28
  70. data/lib/deltacloud/helpers/blob_stream.rb +2 -1
  71. data/lib/deltacloud/models.rb +2 -0
  72. data/lib/deltacloud/models/bucket.rb +1 -1
  73. data/lib/deltacloud/models/image.rb +1 -1
  74. data/lib/deltacloud/models/instance.rb +2 -1
  75. data/lib/deltacloud/models/instance_address.rb +56 -0
  76. data/lib/deltacloud/models/provider.rb +27 -0
  77. data/{server.rb → lib/deltacloud/server.rb} +72 -14
  78. data/lib/deltacloud/validation.rb +31 -10
  79. data/lib/sinatra/rabbit.rb +34 -26
  80. data/lib/sinatra/rack_accept.rb +5 -5
  81. data/lib/sinatra/rack_matrix_params.rb +6 -2
  82. data/lib/sinatra/rack_syslog.rb +3 -3
  83. data/lib/sinatra/static_assets.rb +1 -1
  84. data/lib/sinatra/url_for.rb +1 -7
  85. data/public/images/bread-bg.png +0 -0
  86. data/public/images/logo-wide.png +0 -0
  87. data/public/images/topbar-bg.png +0 -0
  88. data/public/javascripts/application.js +5 -0
  89. data/public/javascripts/cmwgapp.js +249 -0
  90. data/public/javascripts/jquery-1.4.2.min.js +154 -0
  91. data/public/javascripts/jquery.mobile-1.0rc1.min.js +170 -0
  92. data/public/stylesheets/images/icons-18-black.png +0 -0
  93. data/public/stylesheets/images/icons-18-white.png +0 -0
  94. data/public/stylesheets/images/icons-36-black.png +0 -0
  95. data/public/stylesheets/images/icons-36-white.png +0 -0
  96. data/public/stylesheets/jquery.mobile-1.0rc1.min.css +12 -0
  97. data/public/stylesheets/new.css +4 -0
  98. data/support/fedora/deltacloud-core.init +20 -13
  99. data/tests/cimi/features/step_definitions/common_steps.rb +59 -0
  100. data/tests/cimi/features/step_definitions/machine_images_steps.rb +0 -0
  101. data/tests/cimi/features/step_definitions/machines_steps.rb +99 -0
  102. data/tests/cimi/features/step_definitions/volumes_steps.rb +115 -0
  103. data/tests/cimi/features/support/env.rb +53 -0
  104. data/tests/common.rb +89 -11
  105. data/tests/core_ext/string.rb +31 -0
  106. data/tests/drivers/google/api_test.rb +35 -0
  107. data/tests/drivers/google/buckets_test.rb +116 -0
  108. data/tests/drivers/google/setup.rb +38 -0
  109. data/tests/drivers/mock/instances_test.rb +20 -5
  110. data/tests/drivers/openstack/api_test.rb +41 -0
  111. data/tests/drivers/openstack/hardware_profiles_test.rb +53 -0
  112. data/tests/drivers/openstack/images_test.rb +40 -0
  113. data/tests/drivers/openstack/instances_test.rb +163 -0
  114. data/tests/drivers/openstack/realms_test.rb +36 -0
  115. data/tests/drivers/openstack/setup.rb +20 -0
  116. data/tests/drivers/rackspace/buckets_test.rb +145 -0
  117. data/tests/drivers/rackspace/setup.rb +3 -3
  118. data/tests/drivers/rhevm/api_test.rb +1 -1
  119. data/tests/drivers/rhevm/images_test.rb +2 -2
  120. data/tests/drivers/rhevm/instances_test.rb +10 -12
  121. data/tests/drivers/rhevm/realms_test.rb +4 -4
  122. data/tests/drivers/rhevm/setup.rb +3 -3
  123. data/tests/rabbit_test.rb +1 -1
  124. data/views/api/show.html.haml +13 -0
  125. data/views/cimi/cloudEntryPoint/index.html.haml +5 -0
  126. data/views/cimi/cloudEntryPoint/index.xml.haml +9 -0
  127. data/views/cimi/collection/index.html.haml +45 -0
  128. data/views/cimi/collection/response.xml.haml +3 -0
  129. data/views/cimi/error.html.haml +31 -0
  130. data/views/cimi/errors/400.html.haml +41 -0
  131. data/views/cimi/errors/400.xml.haml +3 -0
  132. data/views/cimi/errors/401.html.haml +41 -0
  133. data/views/cimi/errors/401.xml.haml +2 -0
  134. data/views/cimi/errors/403.html.haml +42 -0
  135. data/views/cimi/errors/403.xml.haml +2 -0
  136. data/views/cimi/errors/404.html.haml +29 -0
  137. data/views/cimi/errors/404.xml.haml +2 -0
  138. data/views/cimi/errors/405.html.haml +29 -0
  139. data/views/cimi/errors/405.xml.haml +5 -0
  140. data/views/cimi/errors/500.html.haml +43 -0
  141. data/views/cimi/errors/500.xml.haml +6 -0
  142. data/views/cimi/errors/502.html.haml +43 -0
  143. data/views/cimi/errors/502.xml.haml +7 -0
  144. data/views/cimi/errors/backend_capability_failure.html.haml +29 -0
  145. data/views/cimi/layout.html.haml +32 -0
  146. data/views/cimi/machine_configurations/show.html.haml +159 -0
  147. data/views/cimi/machine_configurations/show.xml.haml +27 -0
  148. data/views/cimi/machine_images/show.html.haml +79 -0
  149. data/views/cimi/machine_images/show.xml.haml +17 -0
  150. data/views/cimi/machines/show.html.haml +177 -0
  151. data/views/cimi/machines/show.xml.haml +28 -0
  152. data/views/cimi/volumes/show.html.haml +68 -0
  153. data/views/cimi/volumes/show.xml.haml +17 -0
  154. data/views/drivers/show.html.haml +10 -5
  155. data/views/drivers/show.xml.haml +9 -4
  156. data/views/error.html.haml +2 -2
  157. data/views/errors/500.xml.haml +7 -1
  158. data/views/instances/index.html.haml +1 -1
  159. data/views/instances/new.html.haml +19 -16
  160. data/views/instances/show.html.haml +7 -2
  161. data/views/instances/show.xml.haml +8 -7
  162. data/views/layout.html.haml +2 -2
  163. data/views/storage_volumes/show.html.haml +1 -1
  164. metadata +296 -204
  165. data/public/javascripts/jquery.mobile-1.0b1.min.js +0 -146
  166. data/public/stylesheets/jquery.mobile-1.0b1.min.css +0 -8
@@ -8,11 +8,16 @@
8
8
  - :stop
9
9
  :owner_id: mockuser
10
10
  :public_addresses:
11
- - img1.inst0.public.com
11
+ - !ruby/object:InstanceAddress
12
+ address: img1.inst0.public.com
13
+ address_type: :hostname
12
14
  :private_addresses:
13
- - img1.inst0.private.com
15
+ - !ruby/object:InstanceAddress
16
+ address: img1.inst0.private.com
17
+ address_type: :hostname
14
18
  :create_image: true
15
19
  :image_id: img1
16
20
  :name: Mock Instance With Profile Change
17
21
  :id: inst0
18
22
  :state: RUNNING
23
+ :storage_volumes: []
@@ -4,9 +4,13 @@
4
4
  :realm_id: us
5
5
  :owner_id: mockuser
6
6
  :public_addresses:
7
- - img3.inst1.public.com
7
+ - !ruby/object:InstanceAddress
8
+ address: img1.inst1.public.com
9
+ address_type: :hostname
8
10
  :private_addresses:
9
- - img3.inst1.private.com
11
+ - !ruby/object:InstanceAddress
12
+ address: img1.inst1.private.com
13
+ address_type: :hostname
10
14
  :create_image: true
11
15
  :image_id: img3
12
16
  :name: MockUserInstance
@@ -15,3 +19,4 @@
15
19
  :actions:
16
20
  - :reboot
17
21
  - :stop
22
+ :storage_volumes: []
@@ -4,9 +4,13 @@
4
4
  :realm_id: us
5
5
  :owner_id: anotheruser
6
6
  :public_addresses:
7
- - img1.inst2.public.com
7
+ - !ruby/object:InstanceAddress
8
+ address: img1.inst2.public.com
9
+ address_type: :hostname
8
10
  :private_addresses:
9
- - img1.inst2.private.com
11
+ - !ruby/object:InstanceAddress
12
+ address: img1.inst2.private.com
13
+ address_type: :hostname
10
14
  :create_image: true
11
15
  :image_id: img1
12
16
  :name: AnotherInstance
@@ -15,3 +19,4 @@
15
19
  :actions:
16
20
  - :reboot
17
21
  - :stop
22
+ :storage_volumes: []
@@ -91,6 +91,23 @@ module Deltacloud::Drivers::Mock
91
91
  FileUtils.rm(fname) if File::exists?(fname)
92
92
  end
93
93
 
94
+ def load_all_cimi(model_name)
95
+ model_files = Dir[File::join(cimi_dir(model_name), "*.json")]
96
+ model_files.map{|f| File.read(f)}
97
+ end
98
+
99
+ def load_cimi(model_name, id)
100
+ File.read(cimi_file(model_name, id))
101
+ end
102
+
103
+ def cimi_file(collection, id)
104
+ File::join(cimi_dir(collection), "#{id}.json")
105
+ end
106
+
107
+ def cimi_dir(collection)
108
+ File::join(@storage_root, "cimi", collection.to_s)
109
+ end
110
+
94
111
  private
95
112
 
96
113
  def collection_name(klass)
@@ -15,10 +15,11 @@
15
15
  # under the License.
16
16
 
17
17
 
18
- require 'deltacloud/base_driver'
19
18
  require 'yaml'
20
- require 'deltacloud/drivers/mock/mock_client'
21
19
  require 'base64'
20
+ require 'etc'
21
+ require 'deltacloud/base_driver'
22
+ require 'deltacloud/drivers/mock/mock_client'
22
23
 
23
24
  module Deltacloud::Drivers::Mock
24
25
 
@@ -55,8 +56,8 @@ module Deltacloud::Drivers::Mock
55
56
  end
56
57
 
57
58
  define_hardware_profile('m1-large') do
58
- cpu 2
59
- memory (7.5*1024 .. 15*1024), :default => 10 * 1024
59
+ cpu (1..6)
60
+ memory ( 7680.. 15*1024), :default => 10 * 1024
60
61
  storage [ 850, 1024 ]
61
62
  architecture 'x86_64'
62
63
  end
@@ -90,7 +91,7 @@ module Deltacloud::Drivers::Mock
90
91
  def initialize
91
92
  if ENV["DELTACLOUD_MOCK_STORAGE"]
92
93
  storage_root = ENV["DELTACLOUD_MOCK_STORAGE"]
93
- elsif ENV["USER"]
94
+ elsif Etc.getlogin
94
95
  storage_root = File::join("/var/tmp", "deltacloud-mock-#{ENV["USER"]}")
95
96
  else
96
97
  raise "Please set either the DELTACLOUD_MOCK_STORAGE or USER environment variable"
@@ -195,8 +196,8 @@ module Deltacloud::Drivers::Mock
195
196
  :keyname => opts[:keyname],
196
197
  :image_id=>image_id,
197
198
  :owner_id=>credentials.user,
198
- :public_addresses=>["#{image_id}.#{next_id}.public.com"],
199
- :private_addresses=>["#{image_id}.#{next_id}.private.com"],
199
+ :public_addresses=>[ InstanceAddress.new("#{image_id}.#{next_id}.public.com", :type => :hostname) ],
200
+ :private_addresses=>[ InstanceAddress.new("#{image_id}.#{next_id}.private.com", :type => :hostname) ],
200
201
  :instance_profile => InstanceProfile.new(hwp.name, opts),
201
202
  :realm_id=>realm_id,
202
203
  :create_image=>true,
@@ -236,7 +237,6 @@ module Deltacloud::Drivers::Mock
236
237
  #
237
238
  # Storage Volumes
238
239
  #
239
-
240
240
  def storage_volumes(credentials, opts=nil)
241
241
  check_credentials( credentials )
242
242
  volumes = @client.build_all(StorageVolume)
@@ -244,6 +244,36 @@ module Deltacloud::Drivers::Mock
244
244
  volumes
245
245
  end
246
246
 
247
+ def create_storage_volume(credentials, opts=nil)
248
+ check_credentials(credentials)
249
+ opts ||= {}
250
+ opts[:capacity] ||= "1"
251
+ volume = {
252
+ :id => "Volume#{Time.now.to_i}",
253
+ :created => Time.now.to_s,
254
+ :state => "AVAILABLE",
255
+ :capacity => opts[:capacity],
256
+ }
257
+ @client.store(:storage_volumes, volume)
258
+ StorageVolume.new(volume)
259
+ end
260
+
261
+ def destroy_storage_volume(credentials, opts=nil)
262
+ check_credentials(credentials)
263
+ @client.destroy(:storage_volumes, opts[:id])
264
+ end
265
+
266
+ #opts: {:id=,:instance_id,:device}
267
+ def attach_storage_volume(credentials, opts)
268
+ check_credentials(credentials)
269
+ attach_volume_instance(opts[:id], opts[:device], opts[:instance_id])
270
+ end
271
+
272
+ def detach_storage_volume(credentials, opts)
273
+ check_credentials(credentials)
274
+ detach_volume_instance(opts[:id], opts[:instance_id])
275
+ end
276
+
247
277
  #
248
278
  # Storage Snapshots
249
279
  #
@@ -410,6 +440,17 @@ module Deltacloud::Drivers::Mock
410
440
  return false
411
441
  end
412
442
 
443
+ def networks(credentials, opts={})
444
+ check_credentials(credentials)
445
+ if opts[:id].nil?
446
+ networks = @client.load_all_cimi(:network).map{|net| CIMI::Model::Network.from_json(net)}
447
+ networks.map{|net|convert_cimi_network(net,opts[:env])}.flatten
448
+ else
449
+ network = CIMI::Model::Network.from_json(@client.load_cimi(:network, opts[:id]))
450
+ convert_cimi_network(network, opts[:env])
451
+ end
452
+ end
453
+
413
454
  private
414
455
 
415
456
  def check_credentials(credentials)
@@ -420,6 +461,39 @@ module Deltacloud::Drivers::Mock
420
461
  end
421
462
  end
422
463
 
464
+ def attach_volume_instance(volume_id, device, instance_id)
465
+ volume = @client.load(:storage_volumes, volume_id)
466
+ instance = @client.load(:instances, instance_id)
467
+ volume[:instance_id] = instance_id
468
+ volume[:device] = device
469
+ volume[:state] = "IN-USE"
470
+ instance[:storage_volumes] ||= []
471
+ instance[:storage_volumes] << {volume_id=>device}
472
+ @client.store(:storage_volumes, volume)
473
+ @client.store(:instances, instance)
474
+ StorageVolume.new(volume)
475
+ end
476
+
477
+ def detach_volume_instance(volume_id, instance_id)
478
+ volume = @client.load(:storage_volumes, volume_id)
479
+ instance = @client.load(:instances, instance_id)
480
+ volume[:instance_id] = nil
481
+ device = volume[:device]
482
+ volume[:device] = nil
483
+ volume[:state] = "AVAILABLE"
484
+ instance[:storage_volumes].delete({volume_id => device}) unless instance[:storage_volumes].nil?
485
+ @client.store(:storage_volumes, volume)
486
+ @client.store(:instances, instance)
487
+ StorageVolume.new(volume)
488
+ end
489
+
490
+ def convert_cimi_network(network, context)
491
+ uri=context.network_url(network.name)
492
+ network.uri=uri
493
+ network.operations.each{|op| op.href=uri}
494
+ network
495
+ end
496
+
423
497
  exceptions do
424
498
 
425
499
  on /AuthFailure/ do
@@ -190,7 +190,7 @@ class OpennebulaDriver < Deltacloud::BaseDriver
190
190
 
191
191
  networks = []
192
192
  (computehash['NETWORK'].each do |n|
193
- networks << n.attributes['ip']
193
+ networks << InstanceAddress.new(n.attributes['ip'])
194
194
  end) unless computehash['NETWORK'].nil?
195
195
 
196
196
  Instance.new( {
@@ -0,0 +1,47 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright ownership. The
4
+ # ASF licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the
6
+ # License. You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations
14
+ # under the License.
15
+ #
16
+
17
+ require 'deltacloud/drivers/rackspace/rackspace_driver.rb'
18
+ module Deltacloud
19
+ module Drivers
20
+ module Openstack
21
+ class OpenstackDriver < Rackspace::RackspaceDriver
22
+
23
+ feature :instances, :user_name
24
+ feature :instances, :authentication_password
25
+ feature :instances, :user_files
26
+
27
+ define_instance_states do
28
+ start.to( :pending ) .on( :create )
29
+ pending.to( :running ) .automatically
30
+ running.to( :running ) .on( :reboot )
31
+ running.to( :shutting_down ) .on( :stop )
32
+ shutting_down.to( :stopped ) .automatically
33
+ stopped.to( :finish ) .automatically
34
+ end
35
+
36
+ def new_client(credentials)
37
+ safely do
38
+ CloudServers::Connection.new(:username => credentials.user, :api_key => credentials.password, :auth_url => api_provider)
39
+ end
40
+ end
41
+
42
+ private :new_client
43
+ end
44
+ end
45
+ end
46
+ end
47
+
@@ -356,8 +356,7 @@ class RackspaceDriver < Deltacloud::BaseDriver
356
356
  return http, request
357
357
  end
358
358
 
359
- private
360
-
359
+ private
361
360
 
362
361
  def new_client(credentials)
363
362
  safely do
@@ -366,10 +365,11 @@ private
366
365
  end
367
366
 
368
367
  def convert_container(cf_container)
368
+ blob_list=cf_container.objects
369
369
  Bucket.new({ :id => cf_container.name,
370
370
  :name => cf_container.name,
371
- :size => cf_container.count,
372
- :blob_list => cf_container.objects
371
+ :size => blob_list.size,
372
+ :blob_list => blob_list
373
373
  })
374
374
  end
375
375
 
@@ -394,8 +394,8 @@ private
394
394
  :architecture => 'x86_64',
395
395
  :image_id => server.imageId.to_s,
396
396
  :instance_profile => InstanceProfile::new(server.flavorId.to_s),
397
- :public_addresses => server.addresses[:public],
398
- :private_addresses => server.addresses[:private],
397
+ :public_addresses => server.addresses[:public].collect { |ip| InstanceAddress.new(ip) },
398
+ :private_addresses => server.addresses[:private].collect { |ip| InstanceAddress.new(ip) },
399
399
  :username => 'root',
400
400
  :password => password ? password : nil
401
401
  )
@@ -415,8 +415,8 @@ private
415
415
  :architecture => 'x86_64',
416
416
  :image_id => server[:imageId].to_s,
417
417
  :instance_profile => InstanceProfile::new(server[:flavorId].to_s),
418
- :public_addresses => server[:addresses][:public],
419
- :private_addresses => server[:addresses][:private]
418
+ :public_addresses => server[:addresses][:public].collect { |ip| InstanceAddress.new(ip) },
419
+ :private_addresses => server[:addresses][:private].collect { |ip| InstanceAddress.new(ip) }
420
420
  )
421
421
  inst.create_image = 'RUNNING'.eql?(inst.state)
422
422
  inst.actions = instance_actions_for(inst.state)
@@ -15,7 +15,6 @@
15
15
  #
16
16
 
17
17
  require 'rubygems'
18
- require 'base64'
19
18
  require 'restclient'
20
19
  require 'nokogiri'
21
20
  require 'digest/md5'
@@ -45,10 +44,11 @@ module RHEVM
45
44
 
46
45
  class Client
47
46
 
48
- attr_reader :credentials, :api_entrypoint
47
+ attr_reader :credentials, :api_entrypoint, :datacenter_id
49
48
 
50
- def initialize(username, password, api_entrypoint)
49
+ def initialize(username, password, api_entrypoint, datacenter_id=nil)
51
50
  @credentials = { :username => username, :password => password }
51
+ @datacenter_id = datacenter_id
52
52
  @api_entrypoint = api_entrypoint
53
53
  end
54
54
 
@@ -59,24 +59,37 @@ module RHEVM
59
59
  headers.merge!(auth_header)
60
60
  if opts[:id]
61
61
  vm = Client::parse_response(RHEVM::client(@api_entrypoint)["/vms/%s" % opts[:id]].get(headers)).root
62
+ return [] unless current_datacenter.cluster_ids.include?((vm/'cluster').first[:id])
62
63
  [ RHEVM::VM::new(self, vm)]
63
64
  else
64
65
  Client::parse_response(RHEVM::client(@api_entrypoint)["/vms"].get(headers)).xpath('/vms/vm').collect do |vm|
66
+ next unless current_datacenter.cluster_ids.include?((vm/'cluster').first[:id])
65
67
  RHEVM::VM::new(self, vm)
66
- end
68
+ end.compact
67
69
  end
68
70
  end
69
71
 
70
72
  def vm_action(id, action, headers={})
71
73
  headers.merge!(auth_header)
72
- headers.merge!({
73
- :content_type => 'application/xml',
74
- :accept => 'application/xml',
75
- })
74
+ headers.merge!({:accept => 'application/xml'})
75
+ vm = vms(:id => id)
76
+ raise RHEVMBackendException::new("Requested VM not found in datacenter #{self.current_datacenter.id}") if vm.empty?
76
77
  if action==:delete
77
78
  RHEVM::client(@api_entrypoint)["/vms/%s" % id].delete(headers)
78
79
  else
79
- xml_response = Client::parse_response(RHEVM::client(@api_entrypoint)["/vms/%s/%s" % [id, action]].post('<action/>', headers))
80
+ headers.merge!({ :content_type => 'application/xml' })
81
+ begin
82
+ client_response = RHEVM::client(@api_entrypoint)["/vms/%s/%s" % [id, action]].post('<action/>', headers)
83
+ rescue
84
+ if $!.is_a?(RestClient::BadRequest)
85
+ fault = (Nokogiri::XML($!.http_body)/'//fault/detail')
86
+ fault = fault.text.gsub(/\[|\]/, '') if fault
87
+ end
88
+ fault ||= $!.message
89
+ raise RHEVMBackendException::new(fault)
90
+ end
91
+ xml_response = Client::parse_response(client_response)
92
+
80
93
  return false if (xml_response/'action/status').first.text.strip.upcase!="COMPLETE"
81
94
  end
82
95
  return true
@@ -89,7 +102,11 @@ module RHEVM
89
102
  }
90
103
  headers.merge!(auth_header)
91
104
  result_xml = Nokogiri::XML(RHEVM::client(@api_entrypoint)["/"].get(headers))
92
- (result_xml/'/api/system_version').first[:major].strip == major
105
+ if (result_xml/'api/system_version').empty?
106
+ (result_xml/'/api/product_info/version').first[:major].strip == major
107
+ else
108
+ (result_xml/'/api/system_version').first[:major].strip == major
109
+ end
93
110
  end
94
111
 
95
112
  def cluster_version?(cluster_id, major)
@@ -102,13 +119,25 @@ module RHEVM
102
119
  (result_xml/'/cluster/version').first[:major].strip == major
103
120
  end
104
121
 
122
+ def capability?(name)
123
+ headers = {
124
+ :content_type => 'application/xml',
125
+ :accept => 'application/xml'
126
+ }
127
+ headers.merge!(auth_header)
128
+ result_xml = Nokogiri::XML(RHEVM::client(@api_entrypoint)["/capabilities"].get(headers))
129
+ !(result_xml/"/capabilities/version/custom_properties/custom_property[@name='#{name}']").empty?
130
+ end
131
+
105
132
  def create_vm(template_id, opts={})
106
133
  opts ||= {}
134
+ templ = template(template_id)
135
+ raise RHEVMBackendException::new("Requested VM not found in datacenter #{self.current_datacenter.id}") unless templ
107
136
  builder = Nokogiri::XML::Builder.new do
108
137
  vm {
109
138
  name opts[:name] || "i-#{Time.now.to_i}"
110
139
  template_(:id => template_id)
111
- cluster(:id => opts[:realm_id] || clusters.first.id)
140
+ cluster_(:id => opts[:realm_id].nil? ? templ.cluster.id : opts[:realm_id])
112
141
  type_ opts[:hwp_id] || 'desktop'
113
142
  memory opts[:hwp_memory] ? (opts[:hwp_memory].to_i*1024*1024).to_s : (512*1024*1024).to_s
114
143
  cpu {
@@ -116,15 +145,11 @@ module RHEVM
116
145
  }
117
146
  if opts[:user_data] and not opts[:user_data].empty?
118
147
  if api_version?('3') and cluster_version?((opts[:realm_id] || clusters.first.id), '3')
148
+ raise "Required VDSM hook 'floppyinject' not supported by RHEV-M" unless capability?(:floppyinject)
119
149
  custom_properties {
120
- #
121
- # FIXME: 'regexp' parameter is just a temporary workaround. This
122
- # is a reported and verified bug and should be fixed in next
123
- # RHEV-M release.
124
- #
125
150
  custom_property({
126
151
  :name => "floppyinject",
127
- :value => "#{RHEVM::FILEINJECT_PATH}:#{Base64.decode64(opts[:user_data])}",
152
+ :value => "#{RHEVM::FILEINJECT_PATH}:#{opts[:user_data]}",
128
153
  :regexp => "^([^:]+):(.*)$"})
129
154
  }
130
155
  else
@@ -138,6 +163,8 @@ module RHEVM
138
163
  :content_type => 'application/xml',
139
164
  :accept => 'application/xml',
140
165
  })
166
+ templates = templates(:id => template_id)
167
+ raise RHEVMBackendException::new("Requested VM not found in datacenter #{self.current_datacenter.id}") if templates.empty?
141
168
  headers.merge!(auth_header)
142
169
  begin
143
170
  vm = RHEVM::client(@api_entrypoint)["/vms"].post(Nokogiri::XML(builder.to_xml).root.to_s, headers)
@@ -176,6 +203,8 @@ module RHEVM
176
203
  :content_type => 'application/xml',
177
204
  :accept => 'application/xml',
178
205
  })
206
+ tmpl = template(id)
207
+ raise RHEVMBackendException::new("Requested VM not found in datacenter #{self.current_datacenter.id}") unless tmpl
179
208
  headers.merge!(auth_header)
180
209
  RHEVM::client(@api_entrypoint)["/templates/%s" % id].delete(headers)
181
210
  return true
@@ -186,29 +215,20 @@ module RHEVM
186
215
  :accept => "application/xml"
187
216
  }
188
217
  headers.merge!(auth_header)
189
- if opts[:id]
190
- vm = Client::parse_response(RHEVM::client(@api_entrypoint)["/templates/%s" % opts[:id]].get(headers)).root
191
- [ RHEVM::Template::new(self, vm)]
192
- else
193
- Client::parse_response(RHEVM::client(@api_entrypoint)["/templates"].get(headers)).xpath('/templates/template').collect do |vm|
194
- RHEVM::Template::new(self, vm)
195
- end
196
- end
218
+ rhevm_templates = RHEVM::client(@api_entrypoint)["/templates"].get(headers)
219
+ Client::parse_response(rhevm_templates).xpath('/templates/template').collect do |t|
220
+ next unless current_datacenter.cluster_ids.include?((t/'cluster').first[:id])
221
+ RHEVM::Template::new(self, t)
222
+ end.compact
197
223
  end
198
224
 
199
- def clusters(opts={})
225
+ def template(template_id)
200
226
  headers = {
201
- :accept => "application/xml; detail=datacenters"
227
+ :accept => "application/xml"
202
228
  }
203
229
  headers.merge!(auth_header)
204
- if opts[:id]
205
- vm = Client::parse_response(RHEVM::client(@api_entrypoint)["/clusters/%s" % opts[:id]].get(headers)).root
206
- [ RHEVM::Cluster::new(self, vm)]
207
- else
208
- Client::parse_response(RHEVM::client(@api_entrypoint)["/clusters"].get(headers)).xpath('/clusters/cluster').collect do |vm|
209
- RHEVM::Cluster::new(self, vm) if has_datacenter?(vm)
210
- end.compact
211
- end
230
+ rhevm_template = RHEVM::client(@api_entrypoint)["/templates/%s" % template_id].get(headers)
231
+ RHEVM::Template::new(self, Client::parse_response(rhevm_template).root)
212
232
  end
213
233
 
214
234
  def datacenters(opts={})
@@ -216,16 +236,33 @@ module RHEVM
216
236
  :accept => "application/xml"
217
237
  }
218
238
  headers.merge!(auth_header)
219
- if opts[:id]
220
- vm = Client::parse_response(RHEVM::client(@api_entrypoint)["/datacenters/%s" % opts[:id]].get(headers)).root
221
- [ RHEVM::DataCenter::new(self, vm)]
222
- else
223
- Client::parse_response(RHEVM::client(@api_entrypoint)["/datacenters"].get(headers)).xpath('/data_centers/data_center').collect do |vm|
224
- RHEVM::DataCenter::new(self, vm)
225
- end
239
+ rhevm_datacenters = RHEVM::client(@api_entrypoint)["/datacenters"].get(headers)
240
+ Client::parse_response(rhevm_datacenters).xpath('/data_centers/data_center').collect do |dc|
241
+ RHEVM::DataCenter::new(self, dc)
226
242
  end
227
243
  end
228
244
 
245
+ def clusters
246
+ current_datacenter.clusters
247
+ end
248
+
249
+ def cluster(cluster_id)
250
+ current_datacenter.cluster(cluster_id)
251
+ end
252
+
253
+ def current_datacenter
254
+ @current_datacenter ||= self.datacenter_id ? datacenter(self.datacenter_id) : datacenters.first
255
+ end
256
+
257
+ def datacenter(datacenter_id)
258
+ headers = {
259
+ :accept => "application/xml"
260
+ }
261
+ headers.merge!(auth_header)
262
+ rhevm_datacenter = RHEVM::client(@api_entrypoint)["/datacenters/%s" % datacenter_id].get(headers)
263
+ RHEVM::DataCenter::new(self, Client::parse_response(rhevm_datacenter).root)
264
+ end
265
+
229
266
  def hosts(opts={})
230
267
  headers = {
231
268
  :accept => "application/xml"
@@ -336,11 +373,11 @@ module RHEVM
336
373
  @storage = ((xml/'disks/disk/size').first.text rescue nil)
337
374
  @macs = (xml/'nics/nic/mac').collect { |mac| mac[:address] }
338
375
  @creation_time = (xml/'creation_time').text
339
- @ip = ((xml/'guest_info/ip').first[:address] rescue nil)
340
- unless @ip
341
- @vnc = ((xml/'display/address').first.text rescue "127.0.0.1")
342
- @vnc += ":#{((xml/'display/port').first.text rescue "5890")}"
343
- end
376
+ @ip = ((xml/'guest_info/ips/ip').first[:address] rescue nil)
377
+ @vnc = {
378
+ :address => ((xml/'display/address').first.text rescue "127.0.0.1"),
379
+ :port => ((xml/'display/port').first.text rescue "5890")
380
+ } unless @ip
344
381
  end
345
382
 
346
383
  end
@@ -364,7 +401,7 @@ module RHEVM
364
401
  end
365
402
 
366
403
  class Cluster < BaseObject
367
- attr_reader :description, :datacenter
404
+ attr_reader :description, :datacenter, :version
368
405
 
369
406
  def initialize(client, xml)
370
407
  super(client, xml[:id], xml[:href], (xml/'name').first.text)
@@ -376,7 +413,10 @@ module RHEVM
376
413
 
377
414
  def parse_xml_attributes!(xml)
378
415
  @description = ((xml/'description').first.text rescue nil)
379
- @datacenter = Link::new(@client, (xml/'data_center').first[:id], (xml/'data_center').first[:href])
416
+ @version =((xml/'version').first[:major].strip rescue nil)
417
+ unless (xml/'data_center').empty?
418
+ @datacenter = Link::new(@client, (xml/'data_center').first[:id], (xml/'data_center').first[:href])
419
+ end
380
420
  end
381
421
 
382
422
  end
@@ -390,6 +430,39 @@ module RHEVM
390
430
  self
391
431
  end
392
432
 
433
+ def clusters
434
+ headers = {
435
+ :accept => "application/xml; detail=datacenters"
436
+ }
437
+ headers.merge!(client.auth_header)
438
+ clusters_list = RHEVM::client(client.api_entrypoint)["/clusters"].get(headers)
439
+ cluster_arr = Client::parse_response(clusters_list).xpath('/clusters/cluster')
440
+ clusters_arr = []
441
+ cluster_arr.each do |cluster|
442
+ cluster = RHEVM::Cluster.new(self.client, cluster)
443
+ clusters_arr << cluster if cluster.datacenter && cluster.datacenter.id == client.datacenter_id
444
+ end
445
+ clusters_arr
446
+ end
447
+
448
+ def cluster(cluster_id)
449
+ headers = {
450
+ :accept => "application/xml; detail=datacenters"
451
+ }
452
+ headers.merge!(client.auth_header)
453
+ cluster_xml = RHEVM::client(client.api_entrypoint)["/clusters/%s" % cluster_id].get(headers)
454
+ cluster = RHEVM::Cluster.new(self.client, cluster_xml)
455
+ if cluster.datacenter && cluster.datacenter.id == client.datacenter_id
456
+ cluster
457
+ else
458
+ nil
459
+ end
460
+ end
461
+
462
+ def cluster_ids
463
+ @cluster_ids ||= clusters.collect { |c| c.id }
464
+ end
465
+
393
466
  private
394
467
 
395
468
  def parse_xml_attributes!(xml)