vcloud-core 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG.md CHANGED
@@ -1,6 +1,15 @@
1
+ ## 0.12.0 (2014-10-03)
2
+
3
+ Features:
4
+
5
+ - Adds custom fields support to vApps. Thanks @geriBatai
6
+ - Adds IndependentDisk entity class, for creation and discovery of Independent Disks. Thanks @mikepea
7
+ - Adds methods to attach and detach IndependentDisk objects to/from an existing VM. Thanks @mikepea
8
+ - Add Vapp.get_by_child_vm_id method, to find a vApp by its child VM id. Thanks @mikepea
9
+
1
10
  ## 0.11.0 (2014-09-11)
2
11
 
3
- Changes:
12
+ Features:
4
13
 
5
14
  - As deprecated in 0.7.0, it is now impossible to specify a plaintext
6
15
  password in a FOG_RC file. Please use tokens via vcloud-login as per
@@ -10,7 +19,7 @@ Changes:
10
19
 
11
20
  API changes:
12
21
 
13
- - removes the temporary files used for transitioning vCloud Tools Tester to use the new API.
22
+ - Removes the temporary files used for transitioning vCloud Tools Tester to use the new API.
14
23
 
15
24
  ## 0.9.0 (2014-08-08)
16
25
 
data/CONTRIBUTING.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  We really welcome contributions.
4
4
 
5
+ ## Issues list
6
+
7
+ Issues we know about are [listed here](https://github.com/gds-operations/vcloud-core/issues). We have a [`newcomer-friendly label`](https://github.com/gds-operations/vcloud-core/labels/newcomer-friendly) for issues that we feel would be a good place to start, because they do not touch a lot of other vCloud Tools code and do not require an environment to work on. This label is just a suggestion.
8
+
5
9
  ## A quick guide on how to contribute
6
10
 
7
11
  1. Clone the repo:
data/README.md CHANGED
@@ -103,6 +103,28 @@ If you want to be sure you are pinning to 5.1, or use 5.5, you can set the API v
103
103
 
104
104
  `vcloud_director_api_version: 5.1`
105
105
 
106
+ ## Working with Independent Disks
107
+
108
+ vCloud Core now supports the management of Independent Disks -- block devices
109
+ stored and managed separately from the VMs they are attached to. We have
110
+ noticed that this bring some limitations/caveats into play that API users
111
+ should be aware of:
112
+
113
+ * It is not possible to move the VM from one Storage Profile to another with
114
+ Vm#update_storage_profile if an Independent Disk is attached. This appears to
115
+ be a limitation in vCloud Director itself. To work around this, detach the
116
+ disks before updating, and reattach afterwards.
117
+
118
+ * It is not possible to add additional *local* disks via Vm#add_extra_disks
119
+ when Independent Disks are attached to a VM. This appears to be a limitation with
120
+ Fog, as the vCD UI permits it. See https://github.com/fog/fog/issues/3179
121
+ for progress on this issue.
122
+
123
+ * Extreme care should be taken when detaching Independent Disks from a VM, as
124
+ vCloud Director will detach them without warning from running VMs, and hence
125
+ with no notification to the running OS. It is recommended to simply use them for
126
+ persistence across VM delete/recreate operations.
127
+
106
128
  ## Debugging
107
129
 
108
130
  `export EXCON_DEBUG=true` - this will print out the API requests and responses.
data/lib/vcloud/core.rb CHANGED
@@ -16,6 +16,7 @@ require 'vcloud/core/login_cli'
16
16
  require 'vcloud/core/vm'
17
17
  require 'vcloud/core/vapp'
18
18
  require 'vcloud/core/vapp_template'
19
+ require 'vcloud/core/independent_disk'
19
20
  require 'vcloud/core/org_vdc_network'
20
21
  require 'vcloud/core/query'
21
22
  require 'vcloud/core/query_cli'
@@ -8,6 +8,7 @@ module Vcloud
8
8
  module ContentTypes
9
9
  ORG = 'application/vnd.vmware.vcloud.org+xml'
10
10
  VDC = 'application/vnd.vmware.vcloud.vdc+xml'
11
+ VAPP = 'application/vnd.vmware.vcloud.vApp+xml'
11
12
  NETWORK = 'application/vnd.vmware.vcloud.network+xml'
12
13
  METADATA = 'application/vnd.vmware.vcloud.metadata.value+xml'
13
14
  end
@@ -16,7 +16,9 @@ module Vcloud
16
16
  :get_execute_query, :get_vapp_metadata, :power_off_vapp, :shutdown_vapp, :session,
17
17
  :post_instantiate_vapp_template, :put_memory, :put_cpu, :power_on_vapp, :put_vapp_metadata_value,
18
18
  :put_vm, :get_edge_gateway, :get_network_complete, :delete_network, :post_create_org_vdc_network,
19
- :post_configure_edge_gateway_services, :get_vdc, :post_undeploy_vapp
19
+ :post_configure_edge_gateway_services, :get_vdc, :post_undeploy_vapp,
20
+ :post_create_disk, :get_disk, :delete_disk, :post_attach_disk,
21
+ :get_vms_disk_attached_to, :post_detach_disk, :put_product_sections
20
22
 
21
23
  #########################
22
24
  # FogFacade Inner class to represent a logic free facade over our interactions with Fog
@@ -125,6 +127,37 @@ module Vcloud
125
127
  @vcloud.process_task(task)
126
128
  end
127
129
 
130
+ def get_disk(id)
131
+ @vcloud.get_disk(id).body
132
+ end
133
+
134
+ def delete_disk(id)
135
+ task = @vcloud.delete_disk(id).body
136
+ @vcloud.process_task(task)
137
+ end
138
+
139
+ def post_create_disk(vdc_id, disk_id, size_in_bytes, options = {})
140
+ # Fog method is incorrectly named 'post_upload_disk', and will be fixed
141
+ # in a future version to match our post_create_disk method name.
142
+ attrs = @vcloud.post_upload_disk(vdc_id, disk_id, size_in_bytes, options).body
143
+ @vcloud.process_task(attrs[:Tasks][:Task])
144
+ get_disk(extract_id(attrs))
145
+ end
146
+
147
+ def post_attach_disk(vm_id, disk_id, options = {})
148
+ task = @vcloud.post_attach_disk(vm_id, disk_id, options).body
149
+ @vcloud.process_task(task)
150
+ end
151
+
152
+ def post_detach_disk(vm_id, disk_id)
153
+ task = @vcloud.post_detach_disk(vm_id, disk_id).body
154
+ @vcloud.process_task(task)
155
+ end
156
+
157
+ def get_vms_disk_attached_to(disk_id)
158
+ @vcloud.get_vms_disk_attached_to(disk_id).body
159
+ end
160
+
128
161
  def post_create_org_vdc_network(vdc_id, name, options)
129
162
  Vcloud::Core.logger.debug("creating #{options[:fence_mode]} OrgVdcNetwork #{name} in vDC #{vdc_id}")
130
163
  attrs = @vcloud.post_create_org_vdc_network(vdc_id, name, options).body
@@ -170,6 +203,11 @@ module Vcloud
170
203
  @vcloud.get_edge_gateway(id).body
171
204
  end
172
205
 
206
+ def put_product_sections(id, items)
207
+ task = @vcloud.put_product_sections(id, items).body
208
+ @vcloud.process_task(task)
209
+ end
210
+
173
211
  private
174
212
  def extract_id(link)
175
213
  link[:href].split('/').last
@@ -0,0 +1,95 @@
1
+ module Vcloud
2
+ module Core
3
+ class IndependentDisk
4
+
5
+ class QueryExecutionError < RuntimeError; end
6
+ class DiskNotFoundException < RuntimeError; end
7
+ class MultipleDisksFoundException < RuntimeError; end
8
+ class DiskAlreadyExistsException < RuntimeError; end
9
+
10
+ attr_reader :id
11
+
12
+ def initialize(id)
13
+ unless id =~ /^[-0-9a-f]+$/
14
+ raise "IndependentDisk id : #{id} is not in correct format"
15
+ end
16
+ @id = id
17
+ end
18
+
19
+ def self.get_by_name_and_vdc_name(name, vdc_name)
20
+ q = Vcloud::Core::QueryRunner.new
21
+ query_results = q.run('disk', :filter => "name==#{name};vdcName==#{vdc_name}")
22
+ unless query_results
23
+ raise QueryExecutionError,
24
+ "Error finding IndependentDisk by name '#{name}' & vdc '#{vdc_name}'"
25
+ end
26
+ raise DiskNotFoundException,
27
+ "IndependentDisk '#{name}' not found in vDC '#{vdc_name}'" if query_results.size == 0
28
+ if query_results.size > 1
29
+ raise MultipleDisksFoundException,
30
+ "Multiple IndependentDisks matching '#{name}' found in vDC '#{vdc_name}. " +
31
+ "Create disks via IndependentDisk.new(disk_id) instead."
32
+ end
33
+ return self.new(query_results.first[:href].split('/').last)
34
+ end
35
+
36
+ def self.create(vdc, name, size)
37
+ vdc_name = vdc.name
38
+ begin
39
+ self.get_by_name_and_vdc_name(name, vdc_name)
40
+ rescue DiskNotFoundException
41
+ ok_to_create = true
42
+ end
43
+
44
+ unless ok_to_create
45
+ raise DiskAlreadyExistsException,
46
+ "Cannot create Independent Disk '#{name}' in vDC '#{vdc_name}' - a disk with " +
47
+ "that name is already present"
48
+ end
49
+
50
+ size_in_bytes = convert_size_to_bytes(size)
51
+ body = Vcloud::Core::Fog::ServiceInterface.new.post_create_disk(vdc.id, name, size_in_bytes)
52
+ return self.new(body[:href].split('/').last)
53
+ end
54
+
55
+ def vcloud_attributes
56
+ Vcloud::Core::Fog::ServiceInterface.new.get_disk(id)
57
+ end
58
+
59
+ def name
60
+ vcloud_attributes[:name]
61
+ end
62
+
63
+ def href
64
+ vcloud_attributes[:href]
65
+ end
66
+
67
+ def attached_vms
68
+ body = Vcloud::Core::Fog::ServiceInterface.new.get_vms_disk_attached_to(id)
69
+ vms = body.fetch(:VmReference)
70
+ vms.map do |vm|
71
+ id = vm.fetch(:href).split('/').last
72
+ parent_vapp = Vcloud::Core::Vapp.get_by_child_vm_id(id)
73
+ Vcloud::Core::Vm.new(id, parent_vapp)
74
+ end
75
+ end
76
+
77
+ def self.convert_size_to_bytes(size)
78
+ if size.to_s =~ /^(\d+)mb$/i
79
+ Integer($1) * (10**6)
80
+ elsif size.to_s =~ /^(\d+)gb$/i
81
+ Integer($1) * (10**9)
82
+ elsif size.to_s =~ /^(\d+)mib$/i
83
+ Integer($1) * (2**20)
84
+ elsif size.to_s =~ /^(\d+)gib$/i
85
+ Integer($1) * (2**30)
86
+ elsif size.to_s =~ /^(\d+)$/i
87
+ Integer($1)
88
+ else
89
+ raise ArgumentError, "Cannot convert size string '#{size}' into a number of bytes"
90
+ end
91
+ end
92
+
93
+ end
94
+ end
95
+ end
@@ -26,6 +26,18 @@ module Vcloud
26
26
  end
27
27
  end
28
28
 
29
+ def self.get_by_child_vm_id(vm_id)
30
+ raise ArgumentError, "Must supply a valid Vm id" unless vm_id =~ /^vm-[-0-9a-f]+$/
31
+ vm_body = Vcloud::Core::Fog::ServiceInterface.new.get_vapp(vm_id)
32
+ parent_vapp_link = vm_body.fetch(:Link).detect do |link|
33
+ link[:rel] == Fog::RELATION::PARENT && link[:type] == Fog::ContentTypes::VAPP
34
+ end
35
+ unless parent_vapp_link
36
+ raise RuntimeError, "Could not find parent vApp for VM '#{vm_id}'"
37
+ end
38
+ return self.new(parent_vapp_link.fetch(:href).split('/').last)
39
+ end
40
+
29
41
  def vcloud_attributes
30
42
  Vcloud::Core::Fog::ServiceInterface.new.get_vapp(id)
31
43
  end
@@ -76,6 +88,26 @@ module Vcloud
76
88
  self.new(attrs[:href].split('/').last) if attrs and attrs.key?(:href)
77
89
  end
78
90
 
91
+ def update_custom_fields(custom_fields)
92
+ return if custom_fields.nil?
93
+ fields = custom_fields.collect do |field|
94
+ user_configurable = field[:user_configurable] || true
95
+ type = field[:type] || 'string'
96
+ password = field[:password] || false
97
+
98
+ {
99
+ :id => field[:name],
100
+ :value => field[:value],
101
+ :user_configurable => user_configurable,
102
+ :type => type,
103
+ :password => password
104
+ }
105
+ end
106
+
107
+ Vcloud::Core.logger.debug("adding custom fields #{fields.inspect} to vapp #{@id}")
108
+ Vcloud::Core::Fog::ServiceInterface.new.put_product_sections(@id, fields)
109
+ end
110
+
79
111
  def power_on
80
112
  raise "Cannot power on a missing vApp." unless id
81
113
  return true if running?
@@ -1,5 +1,5 @@
1
1
  module Vcloud
2
2
  module Core
3
- VERSION = '0.11.0'
3
+ VERSION = '0.12.0'
4
4
  end
5
5
  end
@@ -69,6 +69,20 @@ module Vcloud
69
69
  end
70
70
  end
71
71
 
72
+ def attach_independent_disks(disk_list)
73
+ disk_list = Array(disk_list) # ensure we have an array
74
+ disk_list.each do |disk|
75
+ Vcloud::Core::Fog::ServiceInterface.new.post_attach_disk(id, disk.id)
76
+ end
77
+ end
78
+
79
+ def detach_independent_disks(disk_list)
80
+ disk_list = Array(disk_list) # ensure we have an array
81
+ disk_list.each do |disk|
82
+ Vcloud::Core::Fog::ServiceInterface.new.post_detach_disk(id, disk.id)
83
+ end
84
+ end
85
+
72
86
  def add_extra_disks(extra_disks)
73
87
  vm = Vcloud::Core::Fog::ModelInterface.new.get_vm_by_href(href)
74
88
  if extra_disks
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+
3
+ describe Vcloud::Core::IndependentDisk do
4
+
5
+ let(:uuid_matcher) { "[-0-9a-f]+" }
6
+
7
+ before(:all) do
8
+ config_file = File.join(File.dirname(__FILE__), "../vcloud_tools_testing_config.yaml")
9
+ required_user_params = [
10
+ "vdc_1_name",
11
+ ]
12
+
13
+ @test_params = Vcloud::Tools::Tester::TestSetup.new(config_file, required_user_params).test_params
14
+ @disk_name_prefix = "vcloud-core-independent-disk-tests"
15
+ quantity_of_test_case_disks = 1
16
+ @vdc_name = @test_params.vdc_1_name
17
+ @vdc = Vcloud::Core::Vdc.get_by_name(@vdc_name)
18
+ @test_disk_size = 12000000 # bytes
19
+ @test_case_disks = IntegrationHelper.create_test_case_independent_disks(
20
+ quantity_of_test_case_disks,
21
+ @vdc_name,
22
+ @test_disk_size,
23
+ @disk_name_prefix
24
+ )
25
+ @test_disk = @test_case_disks.first
26
+ end
27
+
28
+ subject(:fixture_disk) { @test_disk }
29
+
30
+ context "before the integration tests run" do
31
+
32
+ it "ensures we have a valid IndependentDisk fixture, for subsequent tests to run against" do
33
+ expect(fixture_disk).to be_instance_of(Vcloud::Core::IndependentDisk)
34
+ end
35
+
36
+ end
37
+
38
+ describe "#vcloud_attributes" do
39
+
40
+ it "has a :href element containing the expected Independent Disk id" do
41
+ expect(fixture_disk.vcloud_attributes[:href].split('/').last).to eq(fixture_disk.id)
42
+ end
43
+
44
+ end
45
+
46
+ describe "#id" do
47
+
48
+ it "returns the a valid Independent Disk id" do
49
+ expect(fixture_disk.id).to match(/^#{uuid_matcher}$/)
50
+ end
51
+
52
+ end
53
+
54
+ describe "#name" do
55
+
56
+ it "returns the name of the Independent Disk" do
57
+ expect(fixture_disk.name).to include(@disk_name_prefix)
58
+ end
59
+
60
+ end
61
+
62
+ describe "#get_by_name_and_vdc_name" do
63
+
64
+ it "can find our fixture Independent Disk by its name & vdcName" do
65
+ retrieved_disk = Vcloud::Core::IndependentDisk.get_by_name_and_vdc_name(
66
+ fixture_disk.name, @vdc_name)
67
+ expect(retrieved_disk.id).to eq(fixture_disk.id)
68
+ end
69
+
70
+ it "raises an error if it cannot find the named Independent Disk" do
71
+ bogus_disk_name = "bogus-disk-name-wefoiuhwef"
72
+ expect {
73
+ Vcloud::Core::IndependentDisk.get_by_name_and_vdc_name(
74
+ bogus_disk_name, @vdc_name)
75
+ }.to raise_error(RuntimeError,
76
+ "IndependentDisk '#{bogus_disk_name}' not found in vDC '#{@vdc_name}'"
77
+ )
78
+ end
79
+
80
+ end
81
+
82
+ describe "#create" do
83
+
84
+ let(:disk_name) { "#{@disk_name_prefix}-instantiate-test-disk" }
85
+
86
+ it "can create a Independent Disk" do
87
+ new_disk = Vcloud::Core::IndependentDisk.create(
88
+ @vdc,
89
+ disk_name,
90
+ 10000000,
91
+ )
92
+ @test_case_disks << new_disk
93
+ expect(new_disk.name).to eq(disk_name)
94
+ end
95
+
96
+ it "raises a DiskAlreadyExistsException if we try to create a disk with the same " +
97
+ "name in the same vDC" do
98
+ expect { Vcloud::Core::IndependentDisk.create(
99
+ @vdc,
100
+ disk_name,
101
+ 10000000)
102
+ }.to raise_error(Vcloud::Core::IndependentDisk::DiskAlreadyExistsException)
103
+ end
104
+
105
+ end
106
+
107
+ after(:all) do
108
+ IntegrationHelper.delete_independent_disks(@test_case_disks)
109
+ end
110
+
111
+
112
+ end
@@ -30,6 +30,12 @@ describe Vcloud::Core::Vm do
30
30
  @network_names,
31
31
  "vcloud-core-vm-tests"
32
32
  )
33
+ @test_case_independent_disk_list = IntegrationHelper.create_test_case_independent_disks(
34
+ 1,
35
+ @test_params.vdc_1_name,
36
+ "100MB",
37
+ "vcloud-core-vm-test-disk"
38
+ )
33
39
  @vapp = @test_case_vapps.first
34
40
  vapp_vms = @vapp.vms.map do |vm|
35
41
  vm_id = vm[:href].split('/').last
@@ -46,6 +52,7 @@ describe Vcloud::Core::Vm do
46
52
 
47
53
  end
48
54
 
55
+
49
56
  context "#update_memory_size_in_mb" do
50
57
 
51
58
  it "can increase the memory size by 512MB" do
@@ -231,26 +238,86 @@ describe Vcloud::Core::Vm do
231
238
 
232
239
  end
233
240
 
234
- context "#update_storage_profile" do
241
+ context "#attach_independent_disks" do
242
+ it "can attach our fixture disk" do
243
+ disk = @test_case_independent_disk_list.first
244
+ expect(disk.attached_vms).to be_empty
245
+ @vm.attach_independent_disks(@test_case_independent_disk_list)
246
+ expect(disk.attached_vms.first.id).to eq(@vm.id)
247
+ end
248
+ end
249
+
250
+ # NB: It is suspected that this behaviour is caused by the Fog Model, not
251
+ # vCloud Director itself. Issue raised on fog/fog to investigate/fix:
252
+ # https://github.com/fog/fog/issues/3179
253
+ context "local disks cannot be added whilst an independent disk is attached" do
254
+
255
+ it "raises an error if we now try to add an extra local disk" do
256
+ extra_disks = [ { size: '10240' } ]
257
+ expect { @vm.add_extra_disks(extra_disks) }.
258
+ to raise_error(
259
+ Fog::Compute::VcloudDirector::BadRequest,
260
+ "The attached disks on VM \"#{@vm.name}\" cannot be modified."
261
+ )
262
+ end
263
+
264
+ end
265
+
266
+ describe "cannot update the storage profile of a VM with an independent disk attached" do
267
+ context "#update_storage_profile" do
268
+
269
+ it "throws an error when trying to update the storage profile of a VM with an " +
270
+ "independent disk attached" do
271
+ available_storage_profiles = Vcloud::Core::QueryRunner.new.run(
272
+ 'orgVdcStorageProfile',
273
+ filter: "vdcName==#{@test_params.vdc_1_name}"
274
+ )
275
+ if available_storage_profiles.size == 1
276
+ pending("There is only one StorageProfile in vDC #{@test_params.vdc_1_name}: cannot test.")
277
+ end
278
+ expect{ @vm.update_storage_profile(@test_params.storage_profile) }.
279
+ to raise_error(Fog::Compute::VcloudDirector::TaskError)
280
+ end
281
+ end
282
+ end
283
+
284
+ describe "detach the independent disk causing the storage profile problem" do
285
+ context "#detach_independent_disks" do
286
+ it "can detach independent disks from the VM" do
287
+ disk = @test_case_independent_disk_list.first
288
+ expect(disk.attached_vms.first.id).to eq(@vm.id)
289
+ @vm.detach_independent_disks(@test_case_independent_disk_list)
290
+ expect(disk.attached_vms).to be_empty
291
+ end
292
+ end
293
+ end
235
294
 
236
- it "can update the storage profile of a VM" do
237
- available_storage_profiles = Vcloud::Core::QueryRunner.new.run(
238
- 'orgVdcStorageProfile',
239
- filter: "vdcName==#{@test_params.vdc_1_name}"
240
- )
241
- if available_storage_profiles.size == 1
242
- pending("There is only one StorageProfile in vDC #{@test_params.vdc_1_name}: cannot test.")
295
+ describe "can now update the storage profile" do
296
+
297
+ context "#update_storage_profile" do
298
+
299
+ it "can update the storage profile of a VM" do
300
+ available_storage_profiles = Vcloud::Core::QueryRunner.new.run(
301
+ 'orgVdcStorageProfile',
302
+ filter: "vdcName==#{@test_params.vdc_1_name}"
303
+ )
304
+ if available_storage_profiles.size == 1
305
+ pending("There is only one StorageProfile in vDC #{@test_params.vdc_1_name}: cannot test.")
306
+ end
307
+ original_storage_profile_name = @vm.vcloud_attributes[:StorageProfile][:name]
308
+ expect(original_storage_profile_name).to eq(@test_params.default_storage_profile_name)
309
+ @vm.update_storage_profile(@test_params.storage_profile)
310
+ expect(@vm.vcloud_attributes[:StorageProfile][:name]).to eq(@test_params.storage_profile)
243
311
  end
244
- original_storage_profile_name = @vm.vcloud_attributes[:StorageProfile][:name]
245
- expect(original_storage_profile_name).to eq(@test_params.default_storage_profile_name)
246
- @vm.update_storage_profile(@test_params.storage_profile)
247
- expect(@vm.vcloud_attributes[:StorageProfile][:name]).to eq(@test_params.storage_profile)
312
+
248
313
  end
249
314
 
250
315
  end
251
316
 
317
+
252
318
  after(:all) do
253
319
  IntegrationHelper.delete_vapps(@test_case_vapps)
320
+ IntegrationHelper.delete_independent_disks(@test_case_independent_disk_list)
254
321
  end
255
322
 
256
323
  def get_vm_hard_disks(fog_model_vm)
@@ -32,6 +32,32 @@ module IntegrationHelper
32
32
  end
33
33
  end
34
34
 
35
+ def self.create_test_case_independent_disks(number_of_disks,
36
+ vdc_name,
37
+ size,
38
+ prefix = "vcloud-core-tests"
39
+ )
40
+ timestamp_in_s = Time.new.to_i
41
+ base_disk_name = "#{prefix}-#{timestamp_in_s}-"
42
+ disk_list = []
43
+ vdc = Vcloud::Core::Vdc.get_by_name(vdc_name)
44
+ number_of_disks.times do |index|
45
+ disk_list << Vcloud::Core::IndependentDisk.create(
46
+ vdc,
47
+ base_disk_name + index.to_s,
48
+ size,
49
+ )
50
+ end
51
+ disk_list
52
+ end
53
+
54
+ def self.delete_independent_disks(disk_list)
55
+ fsi = Vcloud::Core::Fog::ServiceInterface.new()
56
+ disk_list.each do |disk|
57
+ fsi.delete_disk(disk.id)
58
+ end
59
+ end
60
+
35
61
  def self.reset_edge_gateway(edge_gateway)
36
62
  configuration = {
37
63
  :FirewallService =>
@@ -1,4 +1,5 @@
1
1
  require 'ostruct'
2
+ require 'securerandom'
2
3
 
3
4
  class StubFogInterface
4
5
 
@@ -50,6 +51,14 @@ class StubFogInterface
50
51
  }
51
52
  end
52
53
 
54
+ def post_create_disk(_vdc_id, name, size)
55
+ {
56
+ :name => name,
57
+ :href => "https://api.example.com/disk/#{SecureRandom.uuid}",
58
+ :size => size,
59
+ }
60
+ end
61
+
53
62
  def get_vapp_by_vdc_and_name
54
63
  { }
55
64
  end
@@ -0,0 +1,239 @@
1
+ require 'spec_helper'
2
+
3
+ describe Vcloud::Core::IndependentDisk do
4
+ before(:each) do
5
+ @disk_id = '12345678-1234-1234-1234-112112112112'
6
+ @disk_name = 'test-disk-1'
7
+ @vdc_name = 'test-vdc-1'
8
+ @mock_fog_interface = StubFogInterface.new
9
+ allow(Vcloud::Core::Fog::ServiceInterface).to receive(:new).and_return(@mock_fog_interface)
10
+ end
11
+
12
+ context "Class public interface" do
13
+ it { expect(Vcloud::Core::IndependentDisk).to respond_to(:get_by_name_and_vdc_name) }
14
+ end
15
+
16
+ context "Instance public interface" do
17
+ subject { Vcloud::Core::IndependentDisk.new(@disk_id) }
18
+ it { should respond_to(:id) }
19
+ it { should respond_to(:vcloud_attributes) }
20
+ it { should respond_to(:name) }
21
+ it { should respond_to(:href) }
22
+ it { should respond_to(:attached_vms) }
23
+ end
24
+
25
+ context "#initialize" do
26
+
27
+ it "should be constructable from just an id reference" do
28
+ obj = Vcloud::Core::IndependentDisk.new(@disk_id)
29
+ expect(obj.class).to be(Vcloud::Core::IndependentDisk)
30
+ end
31
+
32
+ it "should store the id specified" do
33
+ obj = Vcloud::Core::IndependentDisk.new(@disk_id)
34
+ expect(obj.id).to eq(@disk_id)
35
+ end
36
+
37
+ it "should raise error if id is not in correct format" do
38
+ bogus_id = 'foo-12314124-ede5-4d07-bad5-000000111111'
39
+ expect{
40
+ Vcloud::Core::IndependentDisk.new(bogus_id)
41
+ }.to raise_error("IndependentDisk id : #{bogus_id} is not in correct format" )
42
+ end
43
+
44
+ end
45
+
46
+ context "#get_by_name_and_vdc_name" do
47
+
48
+ it "should return a Disk object if disk is found" do
49
+ q_results = [
50
+ { :name => @disk_name, :href => @disk_id }
51
+ ]
52
+ mock_query = double(:query)
53
+ expect(Vcloud::Core::QueryRunner).to receive(:new).and_return(mock_query)
54
+ expect(mock_query).to receive(:run).with(
55
+ 'disk',
56
+ :filter => "name==#{@disk_name};vdcName==#{@vdc_name}"
57
+ ).and_return(q_results)
58
+ obj = Vcloud::Core::IndependentDisk.get_by_name_and_vdc_name(@disk_name, @vdc_name)
59
+ expect(obj.class).to be(Vcloud::Core::IndependentDisk)
60
+ end
61
+
62
+ it "should raise an error if no Independent Disk with that name exists" do
63
+ q_results = [ ]
64
+ mock_query = double(:query_runner)
65
+ expect(Vcloud::Core::QueryRunner).to receive(:new).and_return(mock_query)
66
+ expect(mock_query).to receive(:run).with(
67
+ 'disk',
68
+ :filter => "name==#{@disk_name};vdcName==#{@vdc_name}"
69
+ ).and_return(q_results)
70
+ expect {
71
+ Vcloud::Core::IndependentDisk.get_by_name_and_vdc_name(@disk_name, @vdc_name)
72
+ }.to raise_exception(Vcloud::Core::IndependentDisk::DiskNotFoundException)
73
+ end
74
+
75
+ it "should raise an error if multiple Independent Disks with " +
76
+ "that name exists (NB: prescribes unique disk names!)" do
77
+ q_results = [
78
+ { :name => @disk_name, :href => @disk_id },
79
+ { :name => @disk_name, :href => '12341234-1234-1234-1234-123456789012' },
80
+ ]
81
+ mock_query = double(:query)
82
+ expect(Vcloud::Core::QueryRunner).to receive(:new).and_return(mock_query)
83
+ expect(mock_query).to receive(:run).with(
84
+ 'disk',
85
+ :filter => "name==#{@disk_name};vdcName==#{@vdc_name}"
86
+ ).and_return(q_results)
87
+ expect {
88
+ Vcloud::Core::IndependentDisk.get_by_name_and_vdc_name(@disk_name, @vdc_name)
89
+ }.to raise_exception(RuntimeError)
90
+ end
91
+
92
+ end
93
+
94
+ describe "#convert_size_to_bytes" do
95
+
96
+ it "accepts integers, passing through as bytes" do
97
+ expect(Vcloud::Core::IndependentDisk.convert_size_to_bytes(100_000_000)).to eq(100_000_000)
98
+ end
99
+
100
+ it "accepts suffixless strings, passing through as bytes" do
101
+ expect(Vcloud::Core::IndependentDisk.convert_size_to_bytes('100000000')).to eq(100_000_000)
102
+ end
103
+
104
+ it "converts 100MB to 100_000_000 bytes" do
105
+ expect(Vcloud::Core::IndependentDisk.convert_size_to_bytes('100MB')).to eq(100_000_000)
106
+ end
107
+
108
+ it "converts 10MiB to 104_857_600 bytes" do
109
+ expect(Vcloud::Core::IndependentDisk.convert_size_to_bytes('100MiB')).to eq(104_857_600)
110
+ end
111
+
112
+ it "converts 10GB to 100_000_000_000 bytes" do
113
+ expect(Vcloud::Core::IndependentDisk.convert_size_to_bytes('100GB')).to eq(100_000_000_000)
114
+ end
115
+
116
+ it "converts 10GiB to 100_000_000_000 bytes" do
117
+ expect(Vcloud::Core::IndependentDisk.convert_size_to_bytes('100GiB')).to eq(107_374_182_400)
118
+ end
119
+
120
+ it "raises an ArgumentError if numeric component is not an integer" do
121
+ expect{Vcloud::Core::IndependentDisk.convert_size_to_bytes('10.5GB')}.
122
+ to raise_error(ArgumentError)
123
+ end
124
+
125
+ it "raises an ArgumentError if it does not understand the input" do
126
+ expect{Vcloud::Core::IndependentDisk.convert_size_to_bytes('10wibbles')}.
127
+ to raise_error(ArgumentError)
128
+ end
129
+
130
+ end
131
+
132
+ describe "#create" do
133
+
134
+ let(:vdc) { double(:vdc, :id => "12341234-1234-1234-1234-123412341234", :name => @vdc_name)}
135
+
136
+ context "when there is no disk already present with that name" do
137
+
138
+ before(:each) do
139
+ mock_query = double(:query_runner)
140
+ expect(Vcloud::Core::QueryRunner).to receive(:new).and_return(mock_query)
141
+ expect(mock_query).to receive(:run).with(
142
+ 'disk',
143
+ :filter => "name==new-disk-1;vdcName==#{@vdc_name}"
144
+ ).and_return([])
145
+ end
146
+
147
+ it "returns an IndependentDisk object if successful" do
148
+ size_in_bytes = 1000_000_000
149
+ obj = Vcloud::Core::IndependentDisk.create(vdc, "new-disk-1", size_in_bytes)
150
+ expect(obj.class).to be(Vcloud::Core::IndependentDisk)
151
+ end
152
+
153
+ it "handles size parameter suffixes (MB, GB, ...)" do
154
+ size = "100MB"
155
+ expect(@mock_fog_interface).to receive(:post_create_disk).with(
156
+ vdc.id, "new-disk-1", 100_000_000
157
+ ).and_return({ :href => "/#{12341234-1234-1234-1234-123412341234}" })
158
+ obj = Vcloud::Core::IndependentDisk.create(vdc, "new-disk-1", size)
159
+ expect(obj.class).to be(Vcloud::Core::IndependentDisk)
160
+ end
161
+
162
+ it "handles size parameter given as an Integer (in bytes)" do
163
+ size = 100_000_000_000
164
+ expect(@mock_fog_interface).to receive(:post_create_disk).with(
165
+ vdc.id, "new-disk-1", 100_000_000_000
166
+ ).and_return({ :href => "/#{12341234-1234-1234-1234-123412341234}" })
167
+ obj = Vcloud::Core::IndependentDisk.create(vdc, "new-disk-1", size)
168
+ expect(obj.class).to be(Vcloud::Core::IndependentDisk)
169
+ end
170
+
171
+ end
172
+
173
+ context "when there is a disk present in the vDC with the same name" do
174
+
175
+ it "raises an error" do
176
+ mock_query = double(:query_runner)
177
+ q_results = [ { :name => @disk_name, :href => @disk_id } ]
178
+ expect(Vcloud::Core::QueryRunner).to receive(:new).and_return(mock_query)
179
+ expect(mock_query).to receive(:run).with(
180
+ 'disk',
181
+ :filter => "name==#{@disk_name};vdcName==#{@vdc_name}"
182
+ ).and_return(q_results)
183
+ expect{ Vcloud::Core::IndependentDisk.create(vdc, @disk_name, 100_000) }.
184
+ to raise_error(Vcloud::Core::IndependentDisk::DiskAlreadyExistsException)
185
+ end
186
+
187
+ end
188
+
189
+ end
190
+
191
+ context "attributes" do
192
+
193
+ before(:each) {
194
+ @stub_attrs = {
195
+ :name => @disk_name,
196
+ :href => "https://api.vcloud-director.example.com/api/disk/#{@disk_id}",
197
+ :Link => [{
198
+ :rel => 'up',
199
+ :type => 'application/vnd.vmware.vcloud.vdc+xml',
200
+ :href => 'https://api.vcloud-director.example.com/api/vdc/074aea1e-a5e9-4dd1-a028-40db8c98d237'
201
+ }]
202
+ }
203
+ allow_any_instance_of(StubFogInterface).to receive(:get_disk).and_return(@stub_attrs)
204
+ @disk = Vcloud::Core::IndependentDisk.new(@disk_id)
205
+ }
206
+
207
+ it { expect(@disk.name).to eq(@disk_name) }
208
+ it { expect(@disk.id).to eq(@disk_id) }
209
+
210
+ end
211
+
212
+ context "#attached_vms" do
213
+
214
+ subject { Vcloud::Core::IndependentDisk.new(@disk_id) }
215
+
216
+ it "returns an empty list if there are no attached vms" do
217
+ expect(@mock_fog_interface).to receive(:get_vms_disk_attached_to).
218
+ with(subject.id).and_return({:VmReference=>[]})
219
+ expect(subject.attached_vms).to eq([])
220
+ end
221
+
222
+ it "returns a list of Core::Vm objects that are attached" do
223
+ expect(Vcloud::Core::Vapp).to receive(:get_by_child_vm_id).exactly(2).times.and_return({
224
+ :href => "/vapp-12341234-1234-1234-1234-123412340000"
225
+ })
226
+ expect(@mock_fog_interface).to receive(:get_vms_disk_attached_to).
227
+ with(subject.id).and_return({:VmReference=>[
228
+ { :href => '/vm-12341234-1234-1234-1234-123412340001' },
229
+ { :href => '/vm-12341234-1234-1234-1234-123412340002' },
230
+ ]})
231
+ vms = subject.attached_vms
232
+ expect(vms[0].id).to eq('vm-12341234-1234-1234-1234-123412340001')
233
+ expect(vms[1].id).to eq('vm-12341234-1234-1234-1234-123412340002')
234
+ end
235
+
236
+ end
237
+
238
+ end
239
+
@@ -175,6 +175,34 @@ module Vcloud
175
175
 
176
176
  end
177
177
 
178
+ context "#get_by_child_vm_id" do
179
+
180
+ it "should raise an ArgumentError if an invalid VM id is supplied" do
181
+ vm_id = 'vapp-12341234-1234-1234-1234-123412341234'
182
+ expect {Vapp.get_by_child_vm_id(vm_id)}.to raise_error(ArgumentError)
183
+ end
184
+
185
+ it "should return a vApp object if we supply an existing VM id" do
186
+ vm_id = "vm-12341234-1234-1234-1234-123412340001"
187
+ vapp_id = "vapp-12341234-1234-1234-1234-123412349999"
188
+ expect(@mock_fog_interface).to receive(:get_vapp).with(vm_id).and_return({
189
+ :Link => [
190
+ { :rel => 'down',
191
+ :type => "application/vnd.vmware.vcloud.metadata+xml",
192
+ :href => "/api/vApp/#{vm_id}/metadata"
193
+ },
194
+ { :rel => 'up',
195
+ :type => "application/vnd.vmware.vcloud.vApp+xml",
196
+ :href => "/api/vApp/#{vapp_id}"
197
+ }
198
+ ]
199
+ })
200
+ obj = Vapp.get_by_child_vm_id(vm_id)
201
+ expect(obj.id).to eq(vapp_id)
202
+ end
203
+
204
+ end
205
+
178
206
  end
179
207
  end
180
208
  end
@@ -56,6 +56,8 @@ module Vcloud
56
56
  it { should respond_to(:update_metadata) }
57
57
  it { should respond_to(:update_storage_profile) }
58
58
  it { should respond_to(:add_extra_disks) }
59
+ it { should respond_to(:attach_independent_disks) }
60
+ it { should respond_to(:detach_independent_disks) }
59
61
  it { should respond_to(:configure_network_interfaces) }
60
62
  it { should respond_to(:configure_guest_customization_section) }
61
63
  end
@@ -327,6 +329,48 @@ module Vcloud
327
329
 
328
330
  end
329
331
 
332
+ context "#attach_independent_disks" do
333
+
334
+ let(:disk1) { double(:disk, :name => 'test-disk-1',
335
+ :id => '12341234-1234-1234-1234-12345678900')
336
+ }
337
+ let(:disk2) { double(:disk, :name => 'test-disk-2',
338
+ :id => '12341234-1234-1234-1234-12345678901')
339
+ }
340
+ let(:disk3) { double(:disk, :name => 'test-disk-3',
341
+ :id => '12341234-1234-1234-1234-12345678902')
342
+ }
343
+
344
+ it "handles attaching an array of Independent Disk objects" do
345
+ vm = Vm.new(@vm_id, @mock_vapp)
346
+ disk_array = [disk1, disk2, disk3]
347
+ expect(@fog_interface).to receive(:post_attach_disk).exactly(disk_array.size).times
348
+ vm.attach_independent_disks(disk_array)
349
+ end
350
+
351
+ end
352
+
353
+ context "#detach_independent_disks" do
354
+
355
+ let(:disk1) { double(:disk, :name => 'test-disk-1',
356
+ :id => '12341234-1234-1234-1234-12345678900')
357
+ }
358
+ let(:disk2) { double(:disk, :name => 'test-disk-2',
359
+ :id => '12341234-1234-1234-1234-12345678901')
360
+ }
361
+ let(:disk3) { double(:disk, :name => 'test-disk-3',
362
+ :id => '12341234-1234-1234-1234-12345678902')
363
+ }
364
+
365
+ it "handles detaching an array of Independent Disk objects" do
366
+ vm = Vm.new(@vm_id, @mock_vapp)
367
+ disk_array = [disk1, disk2, disk3]
368
+ expect(@fog_interface).to receive(:post_detach_disk).exactly(disk_array.size).times
369
+ vm.detach_independent_disks(disk_array)
370
+ end
371
+
372
+ end
373
+
330
374
  end
331
375
  end
332
376
  end
data/vcloud-core.gemspec CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.required_ruby_version = '>= 1.9.3'
24
24
 
25
- s.add_runtime_dependency 'fog', '>= 1.22.0'
25
+ s.add_runtime_dependency 'fog', '>= 1.23.0'
26
26
  s.add_runtime_dependency 'mustache'
27
27
  s.add_runtime_dependency 'highline'
28
28
  s.add_development_dependency 'gem_publisher', '1.2.0'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vcloud-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,22 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-09-11 00:00:00.000000000 Z
12
+ date: 2014-10-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fog
16
- requirement: &5442080 !ruby/object:Gem::Requirement
16
+ requirement: &8805340 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
- version: 1.22.0
21
+ version: 1.23.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *5442080
24
+ version_requirements: *8805340
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: mustache
27
- requirement: &5461800 !ruby/object:Gem::Requirement
27
+ requirement: &8804180 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *5461800
35
+ version_requirements: *8804180
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: highline
38
- requirement: &5459000 !ruby/object:Gem::Requirement
38
+ requirement: &8803000 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *5459000
46
+ version_requirements: *8803000
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: gem_publisher
49
- requirement: &5455320 !ruby/object:Gem::Requirement
49
+ requirement: &8821020 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - =
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 1.2.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *5455320
57
+ version_requirements: *8821020
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: pry
60
- requirement: &5473200 !ruby/object:Gem::Requirement
60
+ requirement: &8820120 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *5473200
68
+ version_requirements: *8820120
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
- requirement: &5471980 !ruby/object:Gem::Requirement
71
+ requirement: &8819460 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *5471980
79
+ version_requirements: *8819460
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec
82
- requirement: &5469500 !ruby/object:Gem::Requirement
82
+ requirement: &8818720 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: 2.14.1
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *5469500
90
+ version_requirements: *8818720
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rubocop
93
- requirement: &5496580 !ruby/object:Gem::Requirement
93
+ requirement: &8813100 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ~>
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: 0.23.0
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *5496580
101
+ version_requirements: *8813100
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: simplecov
104
- requirement: &5495720 !ruby/object:Gem::Requirement
104
+ requirement: &8897220 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ~>
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: 0.7.1
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *5495720
112
+ version_requirements: *8897220
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: vcloud-tools-tester
115
- requirement: &5493500 !ruby/object:Gem::Requirement
115
+ requirement: &8895540 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ~>
@@ -120,7 +120,7 @@ dependencies:
120
120
  version: 0.2.0
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *5493500
123
+ version_requirements: *8895540
124
124
  description: Core tools for interacting with VMware vCloud Director. Includes VCloud
125
125
  Query, a light wrapper round the vCloud Query API.
126
126
  email:
@@ -156,6 +156,7 @@ files:
156
156
  - lib/vcloud/core/fog/login.rb
157
157
  - lib/vcloud/core/fog/model_interface.rb
158
158
  - lib/vcloud/core/fog/service_interface.rb
159
+ - lib/vcloud/core/independent_disk.rb
159
160
  - lib/vcloud/core/login_cli.rb
160
161
  - lib/vcloud/core/metadata_helper.rb
161
162
  - lib/vcloud/core/org_vdc_network.rb
@@ -170,6 +171,7 @@ files:
170
171
  - spec/integration/README.md
171
172
  - spec/integration/core/edge_gateway_spec.rb
172
173
  - spec/integration/core/fog/login_spec.rb
174
+ - spec/integration/core/independent_disk_spec.rb
173
175
  - spec/integration/core/query_runner_spec.rb
174
176
  - spec/integration/core/vapp_spec.rb
175
177
  - spec/integration/core/vdc_spec.rb
@@ -194,6 +196,7 @@ files:
194
196
  - spec/vcloud/core/fog/login_spec.rb
195
197
  - spec/vcloud/core/fog/service_interface_spec.rb
196
198
  - spec/vcloud/core/fog_spec.rb
199
+ - spec/vcloud/core/independent_disk_spec.rb
197
200
  - spec/vcloud/core/login_cli_spec.rb
198
201
  - spec/vcloud/core/metadata_helper_spec.rb
199
202
  - spec/vcloud/core/org_vdc_network_spec.rb
@@ -226,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
226
229
  version: '0'
227
230
  segments:
228
231
  - 0
229
- hash: 728476648198716353
232
+ hash: -425281742654841245
230
233
  requirements: []
231
234
  rubyforge_project:
232
235
  rubygems_version: 1.8.11
@@ -237,6 +240,7 @@ test_files:
237
240
  - spec/integration/README.md
238
241
  - spec/integration/core/edge_gateway_spec.rb
239
242
  - spec/integration/core/fog/login_spec.rb
243
+ - spec/integration/core/independent_disk_spec.rb
240
244
  - spec/integration/core/query_runner_spec.rb
241
245
  - spec/integration/core/vapp_spec.rb
242
246
  - spec/integration/core/vdc_spec.rb
@@ -261,6 +265,7 @@ test_files:
261
265
  - spec/vcloud/core/fog/login_spec.rb
262
266
  - spec/vcloud/core/fog/service_interface_spec.rb
263
267
  - spec/vcloud/core/fog_spec.rb
268
+ - spec/vcloud/core/independent_disk_spec.rb
264
269
  - spec/vcloud/core/login_cli_spec.rb
265
270
  - spec/vcloud/core/metadata_helper_spec.rb
266
271
  - spec/vcloud/core/org_vdc_network_spec.rb