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 +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
|