bosh_vcloud_cpi 0.7.10 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/cloud/vcloud/cloud.rb +20 -21
- data/lib/cloud/vcloud/steps/create_disk.rb +1 -1
- data/lib/cloud/vcloud/steps/create_template.rb +13 -2
- data/lib/cloud/vcloud/steps/insert_catalog_media.rb +25 -0
- data/lib/cloud/vcloud/steps/save_agent_env.rb +12 -5
- data/lib/cloud/vcloud/vcd_client.rb +29 -17
- data/lib/cloud/vcloud/version.rb +1 -3
- data/lib/cloud/vcloud/xml/wrapper.rb +1 -2
- data/lib/cloud/vcloud/xml/wrapper_classes/catalog.rb +5 -0
- data/lib/cloud/vcloud/xml/wrapper_classes/task.rb +6 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c4d97d94d84c1a9a705a9ba642388c1f47b34cf7
|
4
|
+
data.tar.gz: 34d48cd6dfe0feb24ed2e726b4787f852c50b4c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33d7e13c598313b197ee41be1979e3d86ad3de71c5584575f192708fa6b7840c5193dd98579a6b3e4e7e3a4a95a60c92cf111bbf889b1a2f76fd8ec89bb2a7be
|
7
|
+
data.tar.gz: d2d62fa77096ee532349c274d64f9e8ec3425cc34dba3771e43a55f5969b5b1d6b36b2903ebd1d211445eb96f0dd3bb52c6651b2dc119022f2de172bdba16825
|
data/lib/cloud/vcloud/cloud.rb
CHANGED
@@ -29,10 +29,15 @@ module VCloudCloud
|
|
29
29
|
def create_stemcell(image, _)
|
30
30
|
(steps "create_stemcell(#{image}, _)" do |s|
|
31
31
|
s.next Steps::StemcellInfo, image
|
32
|
-
|
33
|
-
s.next Steps::
|
34
|
-
s.next Steps::
|
35
|
-
|
32
|
+
catalog_type = :vapp
|
33
|
+
s.next Steps::AddCatalog, @client.catalog_name(catalog_type)
|
34
|
+
s.next Steps::CreateTemplate, "sc-#{unique_name}", catalog_type
|
35
|
+
|
36
|
+
# Retry upload template file in case of timeout
|
37
|
+
errors = [Timeout::Error]
|
38
|
+
Bosh::Common.retryable(sleep: cpi_call_wait_time, tries: cpi_retries, on: errors) do |tries, error|
|
39
|
+
s.next Steps::UploadTemplateFiles
|
40
|
+
end
|
36
41
|
end)[:catalog_item].urn
|
37
42
|
end
|
38
43
|
|
@@ -60,6 +65,10 @@ module VCloudCloud
|
|
60
65
|
2
|
61
66
|
end
|
62
67
|
|
68
|
+
def cpi_retries
|
69
|
+
10
|
70
|
+
end
|
71
|
+
|
63
72
|
def create_vm(agent_id, catalog_vapp_id, resource_pool, networks, disk_locality = nil, environment = nil)
|
64
73
|
(steps "create_vm(#{agent_id}, #{catalog_vapp_id}, #{resource_pool}, ...)" do |s|
|
65
74
|
# disk_locality should be an array of disk ids
|
@@ -92,7 +101,7 @@ module VCloudCloud
|
|
92
101
|
container_vapp = nil
|
93
102
|
|
94
103
|
errors = [RuntimeError]
|
95
|
-
Bosh::Common.retryable(sleep: cpi_call_wait_time, tries:
|
104
|
+
Bosh::Common.retryable(sleep: cpi_call_wait_time, tries: cpi_retries, on: errors) do |tries, error|
|
96
105
|
begin
|
97
106
|
begin
|
98
107
|
@logger.debug "Requesting container vApp: #{requested_name}"
|
@@ -152,7 +161,7 @@ module VCloudCloud
|
|
152
161
|
# TODO refact this
|
153
162
|
if requested_name
|
154
163
|
errors = [RuntimeError]
|
155
|
-
Bosh::Common.retryable(sleep: cpi_call_wait_time, tries:
|
164
|
+
Bosh::Common.retryable(sleep: cpi_call_wait_time, tries: cpi_retries, on: errors) do |tries, error|
|
156
165
|
begin
|
157
166
|
save_agent_env s
|
158
167
|
s.next Steps::PowerOn, :vm
|
@@ -177,7 +186,7 @@ module VCloudCloud
|
|
177
186
|
vm = s.state[:vm] = client.resolve_entity(vm_id)
|
178
187
|
|
179
188
|
errors = [RuntimeError]
|
180
|
-
Bosh::Common.retryable(sleep: cpi_call_wait_time, tries:
|
189
|
+
Bosh::Common.retryable(sleep: cpi_call_wait_time, tries: cpi_retries, on: errors) do |tries, error|
|
181
190
|
begin
|
182
191
|
if vm['status'] == VCloudSdk::Xml::RESOURCE_ENTITY_STATUS[:SUSPENDED].to_s
|
183
192
|
s.next Steps::DiscardSuspendedState, :vm
|
@@ -219,18 +228,8 @@ module VCloudCloud
|
|
219
228
|
|
220
229
|
# poweroff vm before we are able to delete it
|
221
230
|
s.next Steps::PowerOff, :vm, true
|
222
|
-
|
223
|
-
|
224
|
-
if vapp.vms.size == 1
|
225
|
-
# Hack: if vApp is running, and the last VM is deleted, it is no longer stoppable and removable
|
226
|
-
# even from dashboard. So if there's only one VM, just stop and delete the vApp
|
227
|
-
s.next Steps::PowerOff, :vapp, true
|
228
|
-
s.next Steps::Undeploy, :vapp
|
229
|
-
s.next Steps::Delete, s.state[:vapp], true
|
230
|
-
else
|
231
|
-
s.next Steps::Undeploy, :vm
|
232
|
-
s.next Steps::Delete, s.state[:vm], true
|
233
|
-
end
|
231
|
+
s.next Steps::Undeploy, :vm
|
232
|
+
s.next Steps::Delete, s.state[:vm], true
|
234
233
|
|
235
234
|
s.next Steps::DeleteCatalogMedia, vm.name
|
236
235
|
rescue RestClient::Forbidden, ObjectNotFoundError => e
|
@@ -264,7 +263,7 @@ module VCloudCloud
|
|
264
263
|
s.state[:disk] = client.resolve_entity disk_id
|
265
264
|
|
266
265
|
errors = [RuntimeError]
|
267
|
-
Bosh::Common.retryable(sleep: cpi_call_wait_time, tries:
|
266
|
+
Bosh::Common.retryable(sleep: cpi_call_wait_time, tries: cpi_retries, on: errors) do |tries, error|
|
268
267
|
begin
|
269
268
|
s.next Steps::AttachDetachDisk, :attach
|
270
269
|
|
@@ -293,7 +292,7 @@ module VCloudCloud
|
|
293
292
|
next unless vm.find_attached_disk s.state[:disk]
|
294
293
|
|
295
294
|
errors = [RuntimeError]
|
296
|
-
Bosh::Common.retryable(sleep: cpi_call_wait_time, tries:
|
295
|
+
Bosh::Common.retryable(sleep: cpi_call_wait_time, tries: cpi_retries, on: errors) do |tries, error|
|
297
296
|
begin
|
298
297
|
if vm['status'] == VCloudSdk::Xml::RESOURCE_ENTITY_STATUS[:SUSPENDED].to_s
|
299
298
|
s.next Steps::DiscardSuspendedState, :vm
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module VCloudCloud
|
2
2
|
module Steps
|
3
3
|
class CreateDisk < Step
|
4
|
-
def perform(name, size_mb, vm, storage_profile, &
|
4
|
+
def perform(name, size_mb, vm, storage_profile, &_block)
|
5
5
|
params = VCloudSdk::Xml::WrapperFactory.create_instance 'DiskCreateParams'
|
6
6
|
params.name = name
|
7
7
|
params.size_bytes = size_mb << 20 # VCD expects bytes
|
@@ -1,12 +1,23 @@
|
|
1
1
|
module VCloudCloud
|
2
2
|
module Steps
|
3
3
|
class CreateTemplate < Step
|
4
|
-
def perform(name, &block)
|
4
|
+
def perform(name, catalog_type, &block)
|
5
|
+
catalog = client.catalog catalog_type
|
6
|
+
|
5
7
|
params = VCloudSdk::Xml::WrapperFactory.create_instance 'UploadVAppTemplateParams'
|
6
8
|
params.name = name
|
7
|
-
|
9
|
+
upload_link = catalog.add_vapp_template_link
|
10
|
+
catalog_item = client.invoke(
|
11
|
+
:post,
|
12
|
+
upload_link,
|
13
|
+
:payload => params,
|
14
|
+
:headers => {:content_type => upload_link.type}
|
15
|
+
)
|
16
|
+
|
17
|
+
template = client.invoke :get, catalog_item.entity.href
|
8
18
|
|
9
19
|
# commit states
|
20
|
+
state[:catalog_item] = catalog_item
|
10
21
|
state[:vapp_template] = template
|
11
22
|
end
|
12
23
|
|
@@ -21,6 +21,31 @@ module VCloudCloud
|
|
21
21
|
end
|
22
22
|
state[:vm] = client.reload vm
|
23
23
|
end
|
24
|
+
|
25
|
+
def rollback
|
26
|
+
vm = state[:vm]
|
27
|
+
name = vm.name
|
28
|
+
|
29
|
+
catalog_media = client.catalog_item :media, name, VCloudSdk::Xml::MEDIA_TYPE[:MEDIA]
|
30
|
+
# return if doesn't exist
|
31
|
+
return unless catalog_media
|
32
|
+
media = client.resolve_link catalog_media.entity
|
33
|
+
params = VCloudSdk::Xml::WrapperFactory.create_instance 'MediaInsertOrEjectParams'
|
34
|
+
params.media_href = media.href
|
35
|
+
vm = state[:vm]
|
36
|
+
client.timed_loop do
|
37
|
+
media = client.reload media
|
38
|
+
vm = client.reload vm
|
39
|
+
if media.running_tasks.empty?
|
40
|
+
client.invoke_and_wait :post, vm.eject_media_link,
|
41
|
+
:payload => params,
|
42
|
+
:headers => { :content_type => VCloudSdk::Xml::MEDIA_TYPE[:MEDIA_INSERT_EJECT_PARAMS] }
|
43
|
+
break
|
44
|
+
else
|
45
|
+
media = client.wait_entity media
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
24
49
|
end
|
25
50
|
end
|
26
51
|
end
|
@@ -16,9 +16,11 @@ module VCloudCloud
|
|
16
16
|
env_path = File.join tmpdir, 'env'
|
17
17
|
iso_path = File.join tmpdir, 'env.iso'
|
18
18
|
File.open(env_path, 'w') { |f| f.write env_json }
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
command = "#{create_iso_cmd} -o #{iso_path} #{env_path} 2>&1"
|
20
|
+
output = `#{command}`
|
21
|
+
message = "command `#{command}`: exited with stats: `#{$?.exitstatus}`: and output `#{output}`"
|
22
|
+
@logger.debug message
|
23
|
+
raise message unless $?.success?
|
22
24
|
|
23
25
|
metadata = VCloudSdk::Xml::WrapperFactory.create_instance 'MetadataValue'
|
24
26
|
metadata.value = env_json
|
@@ -35,8 +37,13 @@ module VCloudCloud
|
|
35
37
|
|
36
38
|
private
|
37
39
|
|
38
|
-
def
|
39
|
-
@
|
40
|
+
def create_iso_cmd # TODO: this should exist in bosh_common, eventually
|
41
|
+
@create_iso_cmd ||= begin
|
42
|
+
possibilities = %w{genisoimage mkisofs}
|
43
|
+
cmd = Bosh::Common.which(possibilities)
|
44
|
+
raise("Unable to find a iso creation utility `#{possibilities.inspect}`") unless cmd
|
45
|
+
cmd
|
46
|
+
end
|
40
47
|
end
|
41
48
|
end
|
42
49
|
end
|
@@ -12,7 +12,7 @@ module VCloudCloud
|
|
12
12
|
class VCloudClient
|
13
13
|
attr_reader :logger
|
14
14
|
|
15
|
-
VCLOUD_VERSION_NUMBER = '5.
|
15
|
+
VCLOUD_VERSION_NUMBER = '5.5'
|
16
16
|
|
17
17
|
def initialize(vcd_settings, logger)
|
18
18
|
@logger = logger
|
@@ -144,7 +144,7 @@ module VCloudCloud
|
|
144
144
|
return task if status == VCloudSdk::Xml::TASK_STATUS[:SUCCESS]
|
145
145
|
if [:ABORTED, :ERROR, :CANCELED].any? { |s| status == VCloudSdk::Xml::TASK_STATUS[s] }
|
146
146
|
return task if accept_failure
|
147
|
-
raise "Task #{task.urn} #{task.operation} completed unsuccessfully"
|
147
|
+
raise "Task #{task.urn} #{task.operation} completed unsuccessfully, Details:#{task.details}"
|
148
148
|
end
|
149
149
|
end
|
150
150
|
task
|
@@ -164,12 +164,14 @@ module VCloudCloud
|
|
164
164
|
entity = reload entity
|
165
165
|
|
166
166
|
# verify all tasks succeeded
|
167
|
-
unless
|
167
|
+
unless entity.tasks.nil? || entity.tasks.empty?
|
168
168
|
failed_tasks = entity.tasks.find_all { |task| task.status.downcase != VCloudSdk::Xml::TASK_STATUS[:SUCCESS] }
|
169
169
|
unless failed_tasks.empty?
|
170
|
-
@logger.
|
171
|
-
|
172
|
-
|
170
|
+
@logger.debug "Failed tasks: #{failed_tasks}"
|
171
|
+
unless accept_failure
|
172
|
+
failed_tasks_info = failed_tasks.map { |t| "Task #{t.urn} #{t.operation}, Details:#{t.details}" }
|
173
|
+
raise "Some tasks failed: #{failed_tasks_info.join('; ')}"
|
174
|
+
end
|
173
175
|
end
|
174
176
|
end
|
175
177
|
|
@@ -247,13 +249,14 @@ module VCloudCloud
|
|
247
249
|
params = {
|
248
250
|
:method => method,
|
249
251
|
:url => if path.start_with?('/')
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
252
|
+
@url + path
|
253
|
+
else
|
254
|
+
path
|
255
|
+
end,
|
254
256
|
:headers => {
|
255
|
-
|
256
|
-
|
257
|
+
:Accept => "application/*+xml;version=#{VCLOUD_VERSION_NUMBER}",
|
258
|
+
:content_type => '*/*',
|
259
|
+
'X-VMWARE-VCLOUD-CLIENT-REQUEST-ID' => SecureRandom.uuid
|
257
260
|
}
|
258
261
|
}
|
259
262
|
params[:headers][:x_vcloud_authorization] = @auth_token if !options[:login] && @auth_token
|
@@ -280,11 +283,20 @@ module VCloudCloud
|
|
280
283
|
def session
|
281
284
|
unless cookie_available?
|
282
285
|
auth = "#{@user}@#{@entities['organization']}:#{@pass}"
|
283
|
-
auth_header = "Basic #{Base64.
|
284
|
-
response = send_request
|
285
|
-
|
286
|
-
|
287
|
-
|
286
|
+
auth_header = "Basic #{Base64.strict_encode64(auth)}"
|
287
|
+
response = send_request(
|
288
|
+
:post,
|
289
|
+
login_url,
|
290
|
+
:headers => {
|
291
|
+
:Authorization => auth_header,
|
292
|
+
:content_type => 'application/x-www-form-urlencoded'
|
293
|
+
},
|
294
|
+
:payload => URI.encode_www_form({
|
295
|
+
:Authorization => auth_header,
|
296
|
+
:Accept => "application/*+xml;version=#{VCLOUD_VERSION_NUMBER}"
|
297
|
+
}),
|
298
|
+
:with_response => true
|
299
|
+
)
|
288
300
|
|
289
301
|
@auth_token = response.headers[:x_vcloud_authorization]
|
290
302
|
@cookie = response.cookies
|
data/lib/cloud/vcloud/version.rb
CHANGED
@@ -35,8 +35,7 @@ module VCloudSdk
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
def create_instance(type_name, ns = nil, namespace_defintions = nil,
|
39
|
-
*args)
|
38
|
+
def create_instance(type_name, ns = nil, namespace_defintions = nil, *args)
|
40
39
|
xml = @@xml_dictionary[type_name]
|
41
40
|
if (xml)
|
42
41
|
wrap_document(xml, ns, namespace_defintions, *args)
|
@@ -7,6 +7,11 @@ module VCloudSdk
|
|
7
7
|
"rel"=>"add"}).first
|
8
8
|
end
|
9
9
|
|
10
|
+
def add_vapp_template_link
|
11
|
+
get_nodes("Link", {"type" => MEDIA_TYPE[:UPLOAD_VAPP_TEMPLATE_PARAMS],
|
12
|
+
"rel"=>"add"}).first
|
13
|
+
end
|
14
|
+
|
10
15
|
def catalog_items(name = nil)
|
11
16
|
if name
|
12
17
|
get_nodes("CatalogItem", {"name" => name})
|
@@ -15,6 +15,12 @@ module VCloudSdk
|
|
15
15
|
self["operation"]
|
16
16
|
end
|
17
17
|
|
18
|
+
def details
|
19
|
+
details = get_nodes("Details")
|
20
|
+
return nil if details.nil?
|
21
|
+
return details.collect {|d| d.content}.join
|
22
|
+
end
|
23
|
+
|
18
24
|
# Short form name of the operation
|
19
25
|
def operation_name
|
20
26
|
self["operationName"]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bosh_vcloud_cpi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- VMware
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-08-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bosh_common
|
@@ -124,7 +124,7 @@ dependencies:
|
|
124
124
|
version: '0'
|
125
125
|
description: |-
|
126
126
|
BOSH vCloud CPI
|
127
|
-
|
127
|
+
b1e960
|
128
128
|
email: support@cloudfoundry.com
|
129
129
|
executables: []
|
130
130
|
extensions: []
|