vcloud-rest 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|