vcloud-rest 0.1.1 → 0.2.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 +22 -0
- data/lib/vcloud-rest/connection.rb +145 -13
- metadata +2 -2
data/CHANGELOG.md
CHANGED
@@ -1,13 +1,35 @@
|
|
1
1
|
Changes
|
2
2
|
==
|
3
|
+
2012-12-21 (0.2.0)
|
4
|
+
--
|
5
|
+
|
6
|
+
FEATURES:
|
7
|
+
|
8
|
+
* Allow Task tracking for vApp startup & shutdown
|
9
|
+
* Improve error message for operations on vApp not running
|
10
|
+
* Improve error message for access forbidden
|
11
|
+
* Extend vApp status codes handling
|
12
|
+
* Add method to show VM's details
|
13
|
+
* Basic vApp network configuration
|
14
|
+
* Basic VM network configuration
|
15
|
+
* Basic Guest Customization configuration
|
16
|
+
|
17
|
+
FIXES:
|
18
|
+
|
19
|
+
* Show catalog item: fix ID parsing
|
20
|
+
|
3
21
|
2012-12-19 (0.1.1)
|
4
22
|
--
|
5
23
|
|
24
|
+
FIXES:
|
25
|
+
|
6
26
|
* Fix gemspec URL
|
7
27
|
|
8
28
|
2012-12-19 (0.1.0)
|
9
29
|
--
|
10
30
|
|
31
|
+
FEATURES:
|
32
|
+
|
11
33
|
* Add support for main operations:
|
12
34
|
* login/logout
|
13
35
|
* organization _list/show_
|
@@ -184,7 +184,7 @@ module VCloudClient
|
|
184
184
|
|
185
185
|
items = {}
|
186
186
|
response.css("Entity[type='application/vnd.vmware.vcloud.vAppTemplate+xml']").each do |item|
|
187
|
-
items[item['name']] = item['href'].gsub("#{@api_url}/vAppTemplate/", "")
|
187
|
+
items[item['name']] = item['href'].gsub("#{@api_url}/vAppTemplate/vappTemplate-", "")
|
188
188
|
end
|
189
189
|
|
190
190
|
[description, items]
|
@@ -211,7 +211,7 @@ module VCloudClient
|
|
211
211
|
vapp_node = response.css('VApp').first
|
212
212
|
if vapp_node
|
213
213
|
name = vapp_node['name']
|
214
|
-
status =
|
214
|
+
status = convert_vapp_status(vapp_node['status'])
|
215
215
|
end
|
216
216
|
|
217
217
|
description = response.css("Description").first
|
@@ -225,7 +225,7 @@ module VCloudClient
|
|
225
225
|
vms.each do |vm|
|
226
226
|
addresses = vm.css('rasd|Connection').collect{|n| n['ipAddress']}
|
227
227
|
vms_hash[vm['name']] = {:addresses => addresses,
|
228
|
-
:status =>
|
228
|
+
:status => convert_vapp_status(vm['status']),
|
229
229
|
:id => vm['href'].gsub("#{@api_url}/vApp/vm-", '')
|
230
230
|
}
|
231
231
|
end
|
@@ -265,8 +265,8 @@ module VCloudClient
|
|
265
265
|
|
266
266
|
response, headers = send_request(params, builder.to_xml,
|
267
267
|
"application/vnd.vmware.vcloud.undeployVAppParams+xml")
|
268
|
-
|
269
|
-
|
268
|
+
task_id = headers[:location].gsub("#{@api_url}/task/", "")
|
269
|
+
task_id
|
270
270
|
end
|
271
271
|
|
272
272
|
##
|
@@ -278,8 +278,8 @@ module VCloudClient
|
|
278
278
|
}
|
279
279
|
|
280
280
|
response, headers = send_request(params)
|
281
|
-
|
282
|
-
|
281
|
+
task_id = headers[:location].gsub("#{@api_url}/task/", "")
|
282
|
+
task_id
|
283
283
|
end
|
284
284
|
|
285
285
|
##
|
@@ -290,7 +290,7 @@ module VCloudClient
|
|
290
290
|
# - vapp_name: name of the target vapp
|
291
291
|
# - vapp_description: description of the target vapp
|
292
292
|
# - vapp_templateid: ID of the vapp template
|
293
|
-
def create_vapp_from_template(vdc, vapp_name, vapp_description, vapp_templateid)
|
293
|
+
def create_vapp_from_template(vdc, vapp_name, vapp_description, vapp_templateid, poweron=false)
|
294
294
|
builder = Nokogiri::XML::Builder.new do |xml|
|
295
295
|
xml.InstantiateVAppTemplateParams(
|
296
296
|
"xmlns" => "http://www.vmware.com/vcloud/v1.5",
|
@@ -298,7 +298,7 @@ module VCloudClient
|
|
298
298
|
"xmlns:ovf" => "http://schemas.dmtf.org/ovf/envelope/1",
|
299
299
|
"name" => vapp_name,
|
300
300
|
"deploy" => "true",
|
301
|
-
"powerOn" =>
|
301
|
+
"powerOn" => poweron) {
|
302
302
|
xml.Description vapp_description
|
303
303
|
xml.Source("href" => "#{@api_url}/vAppTemplate/#{vapp_templateid}")
|
304
304
|
}
|
@@ -355,6 +355,128 @@ module VCloudClient
|
|
355
355
|
[status, errormsg, start_time, end_time]
|
356
356
|
end
|
357
357
|
|
358
|
+
##
|
359
|
+
# Set vApp Network Config
|
360
|
+
def set_vapp_network_config(vappid, network_name, config={})
|
361
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
362
|
+
xml.NetworkConfigSection(
|
363
|
+
"xmlns" => "http://www.vmware.com/vcloud/v1.5",
|
364
|
+
"xmlns:ovf" => "http://schemas.dmtf.org/ovf/envelope/1") {
|
365
|
+
xml['ovf'].Info "Network configuration"
|
366
|
+
xml.NetworkConfig("networkName" => network_name) {
|
367
|
+
xml.Configuration {
|
368
|
+
xml.FenceMode (config[:fence_mode] || 'isolated')
|
369
|
+
xml.RetainNetInfoAcrossDeployments (config[:retain_net] || true)
|
370
|
+
}
|
371
|
+
}
|
372
|
+
}
|
373
|
+
end
|
374
|
+
|
375
|
+
params = {
|
376
|
+
'method' => :put,
|
377
|
+
'command' => "/vApp/vapp-#{vappid}/networkConfigSection"
|
378
|
+
}
|
379
|
+
|
380
|
+
response, headers = send_request(params, builder.to_xml, "application/vnd.vmware.vcloud.networkConfigSection+xml")
|
381
|
+
|
382
|
+
task_id = headers[:location].gsub("#{@api_url}/task/", "")
|
383
|
+
task_id
|
384
|
+
end
|
385
|
+
|
386
|
+
##
|
387
|
+
# Set VM Network Config
|
388
|
+
def set_vm_network_config(vmid, network_name, config={})
|
389
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
390
|
+
xml.NetworkConnectionSection(
|
391
|
+
"xmlns" => "http://www.vmware.com/vcloud/v1.5",
|
392
|
+
"xmlns:ovf" => "http://schemas.dmtf.org/ovf/envelope/1") {
|
393
|
+
xml['ovf'].Info "VM Network configuration"
|
394
|
+
xml.PrimaryNetworkConnectionIndex (config[:primary_index] || 0)
|
395
|
+
xml.NetworkConnection("network" => network_name, "needsCustomization" => true) {
|
396
|
+
xml.NetworkConnectionIndex (config[:network_index] || 0)
|
397
|
+
xml.IpAddress config[:ip] if config[:ip]
|
398
|
+
xml.IsConnected (config[:is_connected] || true)
|
399
|
+
xml.IpAddressAllocationMode config[:ip_allocation_mode] if config[:ip_allocation_mode]
|
400
|
+
}
|
401
|
+
}
|
402
|
+
end
|
403
|
+
|
404
|
+
params = {
|
405
|
+
'method' => :put,
|
406
|
+
'command' => "/vApp/vm-#{vmid}/networkConnectionSection"
|
407
|
+
}
|
408
|
+
|
409
|
+
response, headers = send_request(params, builder.to_xml, "application/vnd.vmware.vcloud.networkConnectionSection+xml")
|
410
|
+
|
411
|
+
task_id = headers[:location].gsub("#{@api_url}/task/", "")
|
412
|
+
task_id
|
413
|
+
end
|
414
|
+
|
415
|
+
|
416
|
+
##
|
417
|
+
# Set VM Guest Customization Config
|
418
|
+
def set_vm_guest_customization(vmid, computer_name, config={})
|
419
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
420
|
+
xml.GuestCustomizationSection(
|
421
|
+
"xmlns" => "http://www.vmware.com/vcloud/v1.5",
|
422
|
+
"xmlns:ovf" => "http://schemas.dmtf.org/ovf/envelope/1") {
|
423
|
+
xml['ovf'].Info "VM Guest Customization configuration"
|
424
|
+
xml.Enabled config[:enabled] if config[:enabled]
|
425
|
+
xml.AdminPasswordEnabled config[:admin_passwd_enabled] if config[:admin_passwd_enabled]
|
426
|
+
xml.AdminPassword config[:admin_passwd] if config[:admin_passwd]
|
427
|
+
xml.ComputerName computer_name
|
428
|
+
}
|
429
|
+
end
|
430
|
+
|
431
|
+
params = {
|
432
|
+
'method' => :put,
|
433
|
+
'command' => "/vApp/vm-#{vmid}/guestCustomizationSection"
|
434
|
+
}
|
435
|
+
|
436
|
+
response, headers = send_request(params, builder.to_xml, "application/vnd.vmware.vcloud.guestCustomizationSection+xml")
|
437
|
+
|
438
|
+
task_id = headers[:location].gsub("#{@api_url}/task/", "")
|
439
|
+
task_id
|
440
|
+
end
|
441
|
+
|
442
|
+
##
|
443
|
+
# Show details about a given VM
|
444
|
+
def show_vm(vmId)
|
445
|
+
params = {
|
446
|
+
'method' => :get,
|
447
|
+
'command' => "/vApp/vm-#{vmId}"
|
448
|
+
}
|
449
|
+
|
450
|
+
response, headers = send_request(params)
|
451
|
+
|
452
|
+
os_desc = response.css('ovf|OperatingSystemSection ovf|Description').first.text
|
453
|
+
|
454
|
+
networks = {}
|
455
|
+
response.css('NetworkConnection').each do |network|
|
456
|
+
ip = network.css('IpAddress').first
|
457
|
+
ip = ip.text if ip
|
458
|
+
|
459
|
+
networks[network['network']] = {
|
460
|
+
:index => network.css('NetworkConnectionIndex').first.text,
|
461
|
+
:ip => ip,
|
462
|
+
:is_connected => network.css('IsConnected').first.text,
|
463
|
+
:mac_address => network.css('MACAddress').first.text,
|
464
|
+
:ip_allocation_mode => network.css('IpAddressAllocationMode').first.text
|
465
|
+
}
|
466
|
+
end
|
467
|
+
|
468
|
+
guest_customizations = {
|
469
|
+
:enabled => response.css('GuestCustomizationSection Enabled').first.text,
|
470
|
+
:admin_passwd_enabled => response.css('GuestCustomizationSection AdminPasswordEnabled').first.text,
|
471
|
+
:admin_passwd_auto => response.css('GuestCustomizationSection AdminPasswordAuto').first.text,
|
472
|
+
:admin_passwd => response.css('GuestCustomizationSection AdminPassword').first.text,
|
473
|
+
:reset_passwd_required => response.css('GuestCustomizationSection ResetPasswordRequired').first.text,
|
474
|
+
:computer_name => response.css('GuestCustomizationSection ComputerName').first.text
|
475
|
+
}
|
476
|
+
|
477
|
+
[os_desc, networks, guest_customizations]
|
478
|
+
end
|
479
|
+
|
358
480
|
private
|
359
481
|
##
|
360
482
|
# Sends a synchronous request to the vCloud API and returns the response as parsed XML + headers.
|
@@ -394,23 +516,33 @@ module VCloudClient
|
|
394
516
|
when /validation error on field 'id': String value has invalid format or length/
|
395
517
|
raise WrongItemIDError, "Invalid ID specified. Please verify that the item exists and correctly typed."
|
396
518
|
when /The requested operation could not be executed on vApp "(.*)". Stop the vApp and try again/
|
397
|
-
raise InvalidStateError, "Invalid request. Stop vApp '#{$1}' and try again."
|
519
|
+
raise InvalidStateError, "Invalid request because vApp is running. Stop vApp '#{$1}' and try again."
|
520
|
+
when /The requested operation could not be executed since vApp "(.*)" is not running/
|
521
|
+
raise InvalidStateError, "Invalid request because vApp is stopped. Start vApp '#{$1}' and try again."
|
398
522
|
else
|
399
523
|
raise UnhandledError, "BadRequest - unhandled error: #{message}.\nPlease report this issue."
|
400
524
|
end
|
525
|
+
rescue RestClient::Forbidden => e
|
526
|
+
body = Nokogiri.parse(e.http_body)
|
527
|
+
message = body.css("Error").first["message"]
|
528
|
+
raise UnauthorizedAccess, "Operation not permitted: #{message}."
|
401
529
|
end
|
402
530
|
end
|
403
531
|
|
404
532
|
##
|
405
|
-
# Convert status codes into human readable description
|
406
|
-
def
|
533
|
+
# Convert vApp status codes into human readable description
|
534
|
+
def convert_vapp_status(status_code)
|
407
535
|
case status_code.to_i
|
408
|
-
when
|
536
|
+
when 0
|
409
537
|
'suspended'
|
538
|
+
when 3
|
539
|
+
'paused'
|
410
540
|
when 4
|
411
541
|
'running'
|
412
542
|
when 8
|
413
543
|
'stopped'
|
544
|
+
when 10
|
545
|
+
'mixed'
|
414
546
|
else
|
415
547
|
"Unknown #{status_code}"
|
416
548
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vcloud-rest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|