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.
Files changed (3) hide show
  1. data/CHANGELOG.md +22 -0
  2. data/lib/vcloud-rest/connection.rb +145 -13
  3. 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 = convert_status(vapp_node['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 => convert_status(vm['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
- response
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
- # TODO: track Task using headers[:location]
282
- [response, headers]
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" => "true") {
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 convert_status(status_code)
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 3
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.1.1
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-19 00:00:00.000000000 Z
12
+ date: 2012-12-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri