vcloud-core 0.11.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +11 -2
- data/CONTRIBUTING.md +4 -0
- data/README.md +22 -0
- data/lib/vcloud/core.rb +1 -0
- data/lib/vcloud/core/fog/fog_constants.rb +1 -0
- data/lib/vcloud/core/fog/service_interface.rb +39 -1
- data/lib/vcloud/core/independent_disk.rb +95 -0
- data/lib/vcloud/core/vapp.rb +32 -0
- data/lib/vcloud/core/version.rb +1 -1
- data/lib/vcloud/core/vm.rb +14 -0
- data/spec/integration/core/independent_disk_spec.rb +112 -0
- data/spec/integration/core/vm_spec.rb +79 -12
- data/spec/support/integration_helper.rb +26 -0
- data/spec/support/stub_fog_interface.rb +9 -0
- data/spec/vcloud/core/independent_disk_spec.rb +239 -0
- data/spec/vcloud/core/vapp_spec.rb +28 -0
- data/spec/vcloud/core/vm_spec.rb +44 -0
- data/vcloud-core.gemspec +1 -1
- metadata +29 -24
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
|
-
|
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
|
-
-
|
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
|
data/lib/vcloud/core/vapp.rb
CHANGED
@@ -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?
|
data/lib/vcloud/core/version.rb
CHANGED
data/lib/vcloud/core/vm.rb
CHANGED
@@ -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 "#
|
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
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
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
|
-
|
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
|
data/spec/vcloud/core/vm_spec.rb
CHANGED
@@ -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.
|
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.
|
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-
|
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: &
|
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.
|
21
|
+
version: 1.23.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *8805340
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: mustache
|
27
|
-
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: *
|
35
|
+
version_requirements: *8804180
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: highline
|
38
|
-
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: *
|
46
|
+
version_requirements: *8803000
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: gem_publisher
|
49
|
-
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: *
|
57
|
+
version_requirements: *8821020
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: pry
|
60
|
-
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: *
|
68
|
+
version_requirements: *8820120
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
|
-
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: *
|
79
|
+
version_requirements: *8819460
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rspec
|
82
|
-
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: *
|
90
|
+
version_requirements: *8818720
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: rubocop
|
93
|
-
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: *
|
101
|
+
version_requirements: *8813100
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: simplecov
|
104
|
-
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: *
|
112
|
+
version_requirements: *8897220
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: vcloud-tools-tester
|
115
|
-
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: *
|
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:
|
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
|