knife-vsphere 1.2.14 → 1.2.16

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5568fb262d8a952f210fb7a7100f54bbc4c0c989
4
- data.tar.gz: 2d103c82c324bf3f9577adc8a92583771ce5ccd1
3
+ metadata.gz: ffde4a9240d703c519b66c4d7bddf1a26b5fdc2d
4
+ data.tar.gz: df28bd7b23377431778c93d79a6d04ec358dccbc
5
5
  SHA512:
6
- metadata.gz: 96ccd1409e9573d2c26038163c32bfecb2d3d365d1b2af493ca1d0eb475fcd5f7a2a60a48a656f2d1dd26775da9f692fed192abdfe5281c9c159523cc3ff63a4
7
- data.tar.gz: 9106e7eb45638e26928413b0fc2a6406bb79ab2023515edda7e5c8415e0e686ad137ba5fc54d834df694bb70033707e8bcd37489e7b40920d420ec6d900d72f4
6
+ metadata.gz: bf661f541572092f3a3746cc130ac5d04c7341cffee903e96118aa3ae813f5be37654d6effb654bb39de782ebb64e9a98ba2a59542dd8bf8912b026a2f385680
7
+ data.tar.gz: 7e641d48b040865eace2e255c29f149b2ebc66dcbf1d3af9509a63c230ca202a73bd933dcd5bd5561591eeaf428e7757341b01f608482181e43bc6b864ff2e34
@@ -9,6 +9,10 @@ require 'rbvmomi'
9
9
  require 'base64'
10
10
  require 'filesize'
11
11
 
12
+ PS_ON ||= 'poweredOn'.freeze
13
+ PS_OFF ||= 'poweredOff'.freeze
14
+ PS_SUSPENDED ||= 'suspended'.freeze
15
+
12
16
  # Base class for vsphere knife commands
13
17
  class Chef
14
18
  class Knife
@@ -110,7 +114,7 @@ class Chef
110
114
  end
111
115
 
112
116
  def vim_connection
113
- config[:vim] = RbVmomi::VIM.connect conn_opts
117
+ config[:vim] ||= RbVmomi::VIM.connect conn_opts
114
118
  end
115
119
 
116
120
  def get_password_from_stdin
@@ -183,7 +187,7 @@ class Chef
183
187
 
184
188
  def datacenter
185
189
  dcname = get_config(:vsphere_dc)
186
- traverse_folders_for_dc(config[:vim].rootFolder, dcname) || abort('datacenter not found')
190
+ traverse_folders_for_dc(vim_connection.rootFolder, dcname) || abort('datacenter not found')
187
191
  end
188
192
 
189
193
  def find_folder(folderName)
@@ -373,6 +377,7 @@ class Chef
373
377
  def linux?(config)
374
378
  gid = config.guestId.downcase
375
379
  # This makes the assumption that if it isn't mac or windows it's linux
380
+ # See https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html for values
376
381
  is_linux_bool = !gid.include?('windows') && !gid.include?('darwin')
377
382
  Chef::Log.debug('Identified os as linux.') if is_linux_bool
378
383
  is_linux_bool
@@ -16,14 +16,12 @@ require 'chef/knife/winrm_base'
16
16
  require 'chef/knife/customization_helper'
17
17
  require 'ipaddr'
18
18
 
19
- # Clone an existing template into a new VM, optionally applying a customization specification.
20
- # usage:
21
- # knife vsphere vm clone NewNode UbuntuTemplate --cspec StaticSpec \
22
- # --cips 192.168.0.99/24,192.168.1.99/24 \
23
- # --chostname NODENAME --cdomain NODEDOMAIN
24
19
  class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
25
20
  banner 'knife vsphere vm clone VMNAME (options)'
26
21
 
22
+ AUTO_MAC = 'auto'
23
+ NO_IPS = ''
24
+
27
25
  include Chef::Knife::WinrmBase
28
26
  include CustomizationHelper
29
27
  deps do
@@ -91,11 +89,12 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
91
89
  option :customization_macs,
92
90
  long: '--cmacs CUST_MACS',
93
91
  description: 'Comma-delimited list of MAC addresses for network adapters',
94
- default: 'auto'
92
+ default: AUTO_MAC
95
93
 
96
94
  option :customization_ips,
97
95
  long: '--cips CUST_IPS',
98
- description: 'Comma-delimited list of CIDR IPs for customization'
96
+ description: 'Comma-delimited list of CIDR IPs for customization',
97
+ default: NO_IPS
99
98
 
100
99
  option :customization_dns_ips,
101
100
  long: '--cdnsips CUST_DNS_IPS',
@@ -147,6 +146,10 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
147
146
  long: '--fqdn SERVER_FQDN',
148
147
  description: 'Fully qualified hostname for bootstrapping'
149
148
 
149
+ option :bootstrap_msi_url,
150
+ long: '--bootstrap-msi-url URL',
151
+ description: 'Location of the Chef Client MSI. The default templates will prefer to download from this location.'
152
+
150
153
  option :bootstrap_protocol,
151
154
  long: '--bootstrap-protocol protocol',
152
155
  description: 'Protocol to bootstrap windows servers. options: winrm/ssh',
@@ -311,6 +314,16 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
311
314
  fatal_exit('You must specify a virtual machine name OR use --random-vmname')
312
315
  end
313
316
 
317
+ abort '--template or knife[:source_vm] must be specified' unless config[:source_vm]
318
+
319
+ if get_config(:datastore) && get_config(:datastorecluster)
320
+ abort 'Please select either datastore or datastorecluster'
321
+ end
322
+
323
+ if get_config(:customization_macs) != AUTO_MAC && get_config(:customization_ips) == NO_IPS
324
+ abort('Must specify IP numbers with --cips when specifying MAC addresses with --cmacs, can use "dhcp" as placeholder')
325
+ end
326
+
314
327
  config[:chef_node_name] = vmname unless get_config(:chef_node_name)
315
328
  config[:vmname] = vmname
316
329
 
@@ -321,8 +334,6 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
321
334
 
322
335
  src_folder = find_folder(get_config(:folder)) || dc.vmFolder
323
336
 
324
- abort '--template or knife[:source_vm] must be specified' unless config[:source_vm]
325
-
326
337
  src_vm = find_in_folder(src_folder, RbVmomi::VIM::VirtualMachine, config[:source_vm]) ||
327
338
  abort('VM/Template not found')
328
339
 
@@ -395,19 +406,18 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
395
406
  puts 'Waiting for network interfaces to become available...'
396
407
  sleep 2 while vm.guest.net.empty? || !vm.guest.ipAddress
397
408
  ui.info "Found address #{vm.guest.ipAddress}" if log_verbose?
398
- guest_address ||=
399
- config[:fqdn] = if config[:bootstrap_ipv4]
400
- ipv4_address(vm)
401
- elsif config[:fqdn]
402
- get_config(:fqdn)
403
- else
404
- # Use the first IP which is not a link-local address.
405
- # This is the closest thing to vm.guest.ipAddress but
406
- # allows specifying a NIC.
407
- vm.guest.net[bootstrap_nic_index].ipConfig.ipAddress.detect do |addr|
408
- addr.origin != 'linklayer'
409
- end.ipAddress
410
- end
409
+ config[:fqdn] = if config[:bootstrap_ipv4]
410
+ ipv4_address(vm)
411
+ elsif config[:fqdn]
412
+ get_config(:fqdn)
413
+ else
414
+ # Use the first IP which is not a link-local address.
415
+ # This is the closest thing to vm.guest.ipAddress but
416
+ # allows specifying a NIC.
417
+ vm.guest.net[bootstrap_nic_index].ipConfig.ipAddress.detect do |addr|
418
+ addr.origin != 'linklayer'
419
+ end.ipAddress
420
+ end
411
421
  end
412
422
 
413
423
  def wait_for_access(connect_host, connect_port, protocol)
@@ -417,7 +427,7 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
417
427
  config[:winrm_port] = '5986'
418
428
  end
419
429
  connect_port = get_config(:winrm_port)
420
- print "\n#{ui.color("Waiting for winrm access to become available on #{connect_host}:#{connect_port}",:magenta)}"
430
+ print "\n#{ui.color("Waiting for winrm access to become available on #{connect_host}:#{connect_port}", :magenta)}"
421
431
  print('.') until tcp_test_winrm(connect_host, connect_port) do
422
432
  sleep 10
423
433
  puts('done')
@@ -456,51 +466,47 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
456
466
  end
457
467
  end
458
468
 
459
- # Builds a CloneSpec
460
- def generate_clone_spec(src_config)
461
- rspec = nil
462
- if get_config(:resource_pool)
463
- rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(pool: find_pool(get_config(:resource_pool)))
464
- else
465
- dc = datacenter
466
- hosts = traverse_folders_for_computeresources(dc.hostFolder)
467
- fatal_exit('No ComputeResource found - Use --resource-pool to specify a resource pool or a cluster') if hosts.empty?
468
- hosts.reject!(&:nil?)
469
- hosts.reject! { |host| host.host.all? { |h| h.runtime.inMaintenanceMode } }
470
- fatal_exit 'All hosts in maintenance mode!' if hosts.empty?
471
-
472
- if get_config(:datastore)
473
- hosts.reject! { |host| !host.datastore.include?(find_datastore(get_config(:datastore))) }
474
- end
469
+ def find_available_hosts
470
+ hosts = traverse_folders_for_computeresources(datacenter.hostFolder)
471
+ fatal_exit('No ComputeResource found - Use --resource-pool to specify a resource pool or a cluster') if hosts.empty?
472
+ hosts.reject!(&:nil?)
473
+ hosts.reject! { |host| host.host.all? { |h| h.runtime.inMaintenanceMode } }
474
+ fatal_exit 'All hosts in maintenance mode!' if hosts.empty?
475
+ if get_config(:datastore)
476
+ hosts.reject! { |host| !host.datastore.include?(find_datastore(get_config(:datastore))) }
477
+ end
475
478
 
476
- fatal_exit "No hosts have the requested Datastore available! #{get_config(:datastore)}" if hosts.empty?
479
+ fatal_exit "No hosts have the requested Datastore available! #{get_config(:datastore)}" if hosts.empty?
477
480
 
478
- if get_config(:datastorecluster)
479
- hosts.reject! { |host| !host.datastore.include?(find_datastorecluster(get_config(:datastorecluster))) }
480
- end
481
+ if get_config(:datastorecluster)
482
+ hosts.reject! { |host| !host.datastore.include?(find_datastorecluster(get_config(:datastorecluster))) }
483
+ end
481
484
 
482
- fatal_exit "No hosts have the requested DatastoreCluster available! #{get_config(:datastorecluster)}" if hosts.empty?
485
+ fatal_exit "No hosts have the requested DatastoreCluster available! #{get_config(:datastorecluster)}" if hosts.empty?
483
486
 
484
- if get_config(:customization_vlan)
485
- vlan_list = get_config(:customization_vlan).split(',')
486
- vlan_list.each do |network|
487
- hosts.reject! { |host| !host.network.include?(find_network(network)) }
488
- end
487
+ if get_config(:customization_vlan)
488
+ vlan_list = get_config(:customization_vlan).split(',')
489
+ vlan_list.each do |network|
490
+ hosts.reject! { |host| !host.network.include?(find_network(network)) }
489
491
  end
492
+ end
490
493
 
491
- fatal_exit "No hosts have the requested Network available! #{get_config(:customization_vlan)}" if hosts.empty?
494
+ fatal_exit "No hosts have the requested Network available! #{get_config(:customization_vlan)}" if hosts.empty?
495
+ hosts
496
+ end
492
497
 
493
- rp = hosts.first.resourcePool
494
- rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(pool: rp)
495
- end
498
+ # Builds a CloneSpec
499
+ def generate_clone_spec(src_config)
500
+ rspec = RbVmomi::VIM.VirtualMachineRelocateSpec
496
501
 
497
- if get_config(:linked_clone)
498
- rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(diskMoveType: :moveChildMostDiskBacking)
499
- end
502
+ rspec.pool = if get_config(:resource_pool)
503
+ find_pool(get_config(:resource_pool))
504
+ else
505
+ hosts = find_available_hosts
506
+ hosts.first.resourcePool
507
+ end
500
508
 
501
- if get_config(:datastore) && get_config(:datastorecluster)
502
- abort 'Please select either datastore or datastorecluster'
503
- end
509
+ rspec.diskMoveType = :moveChildMostDiskBacking if get_config(:linked_clone)
504
510
 
505
511
  if get_config(:datastore)
506
512
  rspec.datastore = find_datastore(get_config(:datastore))
@@ -516,9 +522,7 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
516
522
  end
517
523
  end
518
524
 
519
- if get_config(:thin_provision)
520
- rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(transform: :sparse, pool: find_pool(get_config(:resource_pool)))
521
- end
525
+ rspec.transform = :sparse if get_config(:thin_provision)
522
526
 
523
527
  is_template = !get_config(:mark_as_template).nil?
524
528
  clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(location: rspec, powerOn: false, template: is_template)
@@ -537,12 +541,8 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
537
541
  clone_spec.config.memoryMB = Integer(get_config(:customization_memory)) * 1024
538
542
  end
539
543
 
540
- if get_config(:customization_macs) && !get_config(:customization_ips)
541
- abort('Must specify IP numbers with --cips when specifying MAC addresses with --cmacs, can use "dhcp" as placeholder')
542
- end
543
-
544
- mac_list = if get_config(:customization_macs) == 'auto'
545
- ['auto'] * get_config(:customization_ips).split(',').length
544
+ mac_list = if get_config(:customization_macs) == AUTO_MAC
545
+ [AUTO_MAC] * get_config(:customization_ips).split(',').length
546
546
  else
547
547
  get_config(:customization_macs).split(',')
548
548
  end
@@ -581,21 +581,26 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
581
581
  # not connected to a distibuted switch?
582
582
  card.backing = RbVmomi::VIM::VirtualEthernetCardNetworkBackingInfo(network: network, deviceName: network.name)
583
583
  end
584
- card.macAddress = mac_list[index] if get_config(:customization_macs) && mac_list[index] != 'auto'
584
+ card.macAddress = mac_list[index] if get_config(:customization_macs) && mac_list[index] != AUTO_MAC
585
585
  dev_spec = RbVmomi::VIM.VirtualDeviceConfigSpec(device: card, operation: 'edit')
586
586
  clone_spec.config.deviceChange.push dev_spec
587
587
  end
588
588
  end
589
589
 
590
- if get_config(:customization_spec)
591
- csi = find_customization(get_config(:customization_spec)) ||
592
- fatal_exit("failed to find customization specification named #{get_config(:customization_spec)}")
590
+ cust_spec = if get_config(:customization_spec)
591
+ csi = find_customization(get_config(:customization_spec)) ||
592
+ fatal_exit("failed to find customization specification named #{get_config(:customization_spec)}")
593
593
 
594
- cust_spec = csi.spec
595
- else
596
- global_ipset = RbVmomi::VIM.CustomizationGlobalIPSettings
597
- identity_settings = RbVmomi::VIM.CustomizationIdentitySettings
598
- cust_spec = RbVmomi::VIM.CustomizationSpec(globalIPSettings: global_ipset, identity: identity_settings)
594
+ csi.spec
595
+ else
596
+ global_ipset = RbVmomi::VIM.CustomizationGlobalIPSettings
597
+ identity_settings = RbVmomi::VIM.CustomizationIdentitySettings
598
+ RbVmomi::VIM.CustomizationSpec(globalIPSettings: global_ipset, identity: identity_settings)
599
+ end
600
+
601
+ if get_config(:disable_customization)
602
+ clone_spec.customization = get_config(:customization_spec) ? cust_spec : nil
603
+ return clone_spec
599
604
  end
600
605
 
601
606
  if get_config(:customization_dns_ips)
@@ -612,71 +617,67 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
612
617
  }
613
618
  end
614
619
 
615
- if get_config(:disable_customization)
616
- clone_spec.customization = cust_spec
617
- else
618
- use_ident = !config[:customization_hostname].nil? || !get_config(:customization_domain).nil? || cust_spec.identity.nil?
619
-
620
- if use_ident
621
- hostname = if config[:customization_hostname]
622
- config[:customization_hostname]
623
- else
624
- config[:vmname]
625
- end
626
- if windows?(src_config)
627
- identification = RbVmomi::VIM.CustomizationIdentification(
628
- joinWorkgroup: cust_spec.identity.identification.joinWorkgroup
629
- )
630
- license_file_print_data = RbVmomi::VIM.CustomizationLicenseFilePrintData(
631
- autoMode: cust_spec.identity.licenseFilePrintData.autoMode
632
- )
633
-
634
- user_data = RbVmomi::VIM.CustomizationUserData(
635
- fullName: cust_spec.identity.userData.fullName,
636
- orgName: cust_spec.identity.userData.orgName,
637
- productId: cust_spec.identity.userData.productId,
638
- computerName: RbVmomi::VIM.CustomizationFixedName(name: hostname)
639
- )
640
-
641
- gui_unattended = RbVmomi::VIM.CustomizationGuiUnattended(
642
- autoLogon: cust_spec.identity.guiUnattended.autoLogon,
643
- autoLogonCount: cust_spec.identity.guiUnattended.autoLogonCount,
644
- password: RbVmomi::VIM.CustomizationPassword(
645
- plainText: cust_spec.identity.guiUnattended.password.plainText,
646
- value: cust_spec.identity.guiUnattended.password.value
647
- ),
648
- timeZone: cust_spec.identity.guiUnattended.timeZone
649
- )
650
- runonce = RbVmomi::VIM.CustomizationGuiRunOnce(
651
- commandList: ['cust_spec.identity.guiUnattended.commandList']
652
- )
653
- ident = RbVmomi::VIM.CustomizationSysprep
654
- ident.guiRunOnce = runonce
655
- ident.guiUnattended = gui_unattended
656
- ident.identification = identification
657
- ident.licenseFilePrintData = license_file_print_data
658
- ident.userData = user_data
659
- cust_spec.identity = ident
660
- elsif linux?(src_config)
661
- ident = RbVmomi::VIM.CustomizationLinuxPrep
662
- ident.hostName = RbVmomi::VIM.CustomizationFixedName(name: hostname)
663
-
664
- ident.domain = if get_config(:customization_domain)
665
- get_config(:customization_domain)
666
- else
667
- ''
668
- end
669
- cust_spec.identity = ident
670
- else
671
- ui.error('Customization only supports Linux and Windows currently.')
672
- exit 1
673
- end
620
+ # TODO: why does the domain matter?
621
+ use_ident = config[:customization_hostname] || get_config(:customization_domain) || cust_spec.identity.props.empty?
622
+
623
+ # TODO: How could we not take this? Only if the identity were empty, but that's statically defined as empty above
624
+ if use_ident
625
+ hostname = config[:customization_hostname] || config[:vmname]
626
+
627
+ if windows?(src_config)
628
+ # TODO: This is just copying itself onto itself, isn't it?
629
+ identification = RbVmomi::VIM.CustomizationIdentification(
630
+ joinWorkgroup: cust_spec.identity.identification.joinWorkgroup
631
+ )
632
+ license_file_print_data = RbVmomi::VIM.CustomizationLicenseFilePrintData(
633
+ autoMode: cust_spec.identity.licenseFilePrintData.autoMode
634
+ )
635
+
636
+ user_data = RbVmomi::VIM.CustomizationUserData(
637
+ fullName: cust_spec.identity.userData.fullName,
638
+ orgName: cust_spec.identity.userData.orgName,
639
+ productId: cust_spec.identity.userData.productId,
640
+ computerName: RbVmomi::VIM.CustomizationFixedName(name: hostname)
641
+ )
642
+
643
+ gui_unattended = RbVmomi::VIM.CustomizationGuiUnattended(
644
+ autoLogon: cust_spec.identity.guiUnattended.autoLogon,
645
+ autoLogonCount: cust_spec.identity.guiUnattended.autoLogonCount,
646
+ password: RbVmomi::VIM.CustomizationPassword(
647
+ plainText: cust_spec.identity.guiUnattended.password.plainText,
648
+ value: cust_spec.identity.guiUnattended.password.value
649
+ ),
650
+ timeZone: cust_spec.identity.guiUnattended.timeZone
651
+ )
652
+ runonce = RbVmomi::VIM.CustomizationGuiRunOnce(
653
+ commandList: ['cust_spec.identity.guiUnattended.commandList']
654
+ )
655
+ ident = RbVmomi::VIM.CustomizationSysprep
656
+ ident.guiRunOnce = runonce
657
+ ident.guiUnattended = gui_unattended
658
+ ident.identification = identification
659
+ ident.licenseFilePrintData = license_file_print_data
660
+ ident.userData = user_data
661
+ cust_spec.identity = ident
662
+ elsif linux?(src_config)
663
+ ident = RbVmomi::VIM.CustomizationLinuxPrep
664
+ ident.hostName = RbVmomi::VIM.CustomizationFixedName(name: hostname)
665
+
666
+ ident.domain = if get_config(:customization_domain)
667
+ get_config(:customization_domain)
668
+ else
669
+ ''
670
+ end
671
+ cust_spec.identity = ident
672
+ else
673
+ ui.error('Customization only supports Linux and Windows currently.')
674
+ exit 1
674
675
  end
675
- clone_spec.customization = cust_spec
676
+ end
677
+ clone_spec.customization = cust_spec
676
678
 
677
- if customization_plugin && customization_plugin.respond_to?(:customize_clone_spec)
678
- clone_spec = customization_plugin.customize_clone_spec(src_config, clone_spec)
679
- end
679
+ if customization_plugin && customization_plugin.respond_to?(:customize_clone_spec)
680
+ clone_spec = customization_plugin.customize_clone_spec(src_config, clone_spec)
680
681
  end
681
682
  clone_spec
682
683
  end
@@ -717,7 +718,7 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
717
718
  # @param name [String] name of customization
718
719
  # @return [RbVmomi::VIM::CustomizationSpecItem]
719
720
  def find_customization(name)
720
- csm = config[:vim].serviceContent.customizationSpecManager
721
+ csm = vim_connection.serviceContent.customizationSpecManager
721
722
  csm.GetCustomizationSpec(name: name)
722
723
  end
723
724
 
@@ -748,7 +749,7 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
748
749
  end
749
750
 
750
751
  adapter_map = RbVmomi::VIM.CustomizationAdapterMapping
751
- adapter_map.macAddress = mac if !mac.nil? && (mac != 'auto')
752
+ adapter_map.macAddress = mac if !mac.nil? && (mac != AUTO_MAC)
752
753
  adapter_map.adapter = settings
753
754
  adapter_map
754
755
  end
@@ -789,6 +790,7 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
789
790
  ui.error('Unsupported Bootstrapping Protocol. Supports : winrm, ssh')
790
791
  exit 1
791
792
  end
793
+ bootstrap.config[:msi_url] = get_config(:bootstrap_msi_url)
792
794
  bootstrap_common_params(bootstrap)
793
795
  end
794
796
 
@@ -802,6 +804,7 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
802
804
  bootstrap.config[:ssh_port] = get_config(:ssh_port)
803
805
  bootstrap.config[:identity_file] = get_config(:identity_file)
804
806
  bootstrap.config[:use_sudo] = true unless get_config(:ssh_user) == 'root'
807
+ bootstrap.config[:use_sudo_password] = true unless get_config(:ssh_user) == 'root'
805
808
  bootstrap.config[:log_level] = get_config(:log_level)
806
809
  bootstrap_common_params(bootstrap)
807
810
  end
@@ -8,10 +8,6 @@ require 'chef/knife/base_vsphere_command'
8
8
  require 'rbvmomi'
9
9
  require 'netaddr'
10
10
 
11
- PsOn = 'poweredOn'
12
- PsOff = 'poweredOff'
13
- PsSuspended = 'suspended'
14
-
15
11
  # find vms belonging to pool that match criteria, display specified fields
16
12
  class Chef::Knife::VsphereVmFind < Chef::Knife::BaseVsphereCommand
17
13
  banner 'knife vsphere vm find'
@@ -95,22 +91,20 @@ class Chef::Knife::VsphereVmFind < Chef::Knife::BaseVsphereCommand
95
91
  long: '--full-path',
96
92
  description: 'Show full path'
97
93
 
98
- $stdout.sync = true # smoother output from print
94
+ $stdout.sync = true # smoother output from print
99
95
 
100
96
  def traverse_folders_for_pool_clustercompute(folder, poolname)
101
- # children = folder.children.find_all
102
97
  children = find_all_in_folder(folder, RbVmomi::VIM::ManagedObject)
103
98
  children.each do |child|
104
- if child.class == RbVmomi::VIM::ClusterComputeResource || child.class == RbVmomi::VIM::ComputeResource || child.class == RbVmomi::VIM::ResourcePool
105
- if child.name == poolname then return child
106
- else if child.class == RbVmomi::VIM::Folder || child.class == RbVmomi::VIM::ComputeResource || child.class == RbVmomi::VIM::ClusterComputeResource || child.class == RbVmomi::VIM::ResourcePool
107
- pool = traverse_folders_for_pool_clustercompute(child, poolname)
108
- end
109
- end
110
- if pool then return pool end
99
+ next unless child.class == RbVmomi::VIM::ClusterComputeResource || child.class == RbVmomi::VIM::ComputeResource || child.class == RbVmomi::VIM::ResourcePool
100
+ if child.name == poolname
101
+ return child
102
+ elsif child.class == RbVmomi::VIM::Folder || child.class == RbVmomi::VIM::ComputeResource || child.class == RbVmomi::VIM::ClusterComputeResource || child.class == RbVmomi::VIM::ResourcePool
103
+ pool = traverse_folders_for_pool_clustercompute(child, poolname)
111
104
  end
105
+ return pool if pool
112
106
  end
113
- return false
107
+ false
114
108
  end
115
109
 
116
110
  def run
@@ -120,125 +114,124 @@ class Chef::Knife::VsphereVmFind < Chef::Knife::BaseVsphereCommand
120
114
  fatal_exit('You must specify a resource pool or cluster name (see knife vsphere pool list)')
121
115
  end
122
116
 
123
- vim = vim_connection
117
+ vim_connection
124
118
  dc = datacenter
125
119
  folder = dc.hostFolder
126
120
 
127
- pool = traverse_folders_for_pool_clustercompute(folder, poolname) or abort "Pool #{poolname} not found"
121
+ pool = traverse_folders_for_pool_clustercompute(folder, poolname) || abort("Pool #{poolname} not found")
128
122
 
129
- if pool.class == RbVmomi::VIM::ResourcePool
130
- vm = pool.vm
131
- else
132
- vm = pool.resourcePool.vm
133
- end
134
-
135
- unless vm.nil?
136
- vm.each do |vmc|
137
- state = case vmc.runtime.powerState
138
- when PsOn
139
- ui.color('on', :green)
140
- when PsOff
141
- ui.color('off', :red)
142
- when PsSuspended
143
- ui.color('suspended', :yellow)
144
- end
145
-
146
- if get_config(:matchname)
147
- next unless vmc.name.include? config[:matchname]
148
- end
149
-
150
- if get_config(:matchtools)
151
- next unless vmc.guest.toolsStatus == config[:matchtools]
152
- end
153
-
154
- next if get_config(:soff) && (vmc.runtime.powerState == PsOn)
155
-
156
- next if get_config(:son) && (vmc.runtime.powerState == PsOff)
157
-
158
- if get_config(:matchip)
159
- if (!vmc.guest.ipAddress.nil? && vmc.guest.ipAddress != '')
160
- next unless vmc.guest.ipAddress.include? config[:matchip]
161
- else
162
- next
123
+ vm = if pool.class == RbVmomi::VIM::ResourcePool
124
+ pool.vm
125
+ else
126
+ pool.resourcePool.vm
163
127
  end
164
- end
165
128
 
166
- unless vmc.guest.guestFullName.nil?
167
- if get_config(:matchos)
168
- next unless vmc.guest.guestFullName.include? config[:matchos]
169
- end
170
- end
171
-
172
- print "#{ui.color("VM Name:", :cyan)} #{vmc.name}\t"
173
- if get_config(:hostname)
174
- print "#{ui.color("Hostname:", :cyan)} #{vmc.guest.hostName}\t"
175
- end
176
-
177
- if get_config(:full_path)
178
- actualname = ''
179
- vmcp = vmc
180
- while vmcp.parent != nil && vmcp.parent.name != 'vm'
181
- actualname.concat("#{vmcp.parent.name}/")
182
- vmcp = vmcp.parent
183
- end
184
- print "#{ui.color("Folder:", :cyan)}"
185
- print "\""
186
- print actualname.split('/').reverse().join('/')
187
- print "\"\t"
188
-
189
- else
190
- print "#{ui.color("Folder", :cyan)}: #{vmc.parent.name}\t"
191
- end
192
-
193
- if get_config(:ip)
194
- print "#{ui.color("IP:", :cyan)} #{vmc.guest.ipAddress}\t"
195
- end
196
- if get_config(:ips)
197
- ipregex = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/
198
- networks = vmc.guest.net.map { |net| "#{net.network}:" + net.ipConfig.ipAddress.select { |i| i.ipAddress[ipregex] }[0].ipAddress }
199
- print "#{ui.color("IPS:", :cyan)} #{networks.join(",")}\t"
200
- end
201
- if get_config(:os)
202
- print "#{ui.color("OS:", :cyan)} #{vmc.guest.guestFullName}\t"
203
- end
204
- if get_config(:ram)
205
- print "#{ui.color("RAM:", :cyan)} #{vmc.summary.config.memorySizeMB}\t"
206
- end
207
- if get_config(:cpu)
208
- print "#{ui.color("CPU:", :cyan)} #{vmc.summary.config.numCpu}\t"
209
- end
210
- if get_config(:alarms)
211
- print "#{ui.color("Alarms:", :cyan)} #{vmc.summary.overallStatus}\t"
212
- end
213
- print "#{ui.color("State:", :cyan)} #{state}\t"
214
- if get_config(:tools)
215
- print "#{ui.color("Tools:", :cyan)} #{vmc.guest.toolsStatus}\t"
216
- end
217
-
218
- if get_config(:os_disk)
219
- print "#{ui.color("OS Disks:", :cyan)}"
220
- vmc.guest.disk.each do |disc|
221
- print "#{disc.diskPath} #{disc.capacity / 1024 / 1024}MB Free:#{disc.freeSpace / 1024 / 1024}MB |"
222
- end
223
- end
129
+ return if vm.nil?
130
+ vm.each do |vmc|
131
+ state = case vmc.runtime.powerState
132
+ when PS_ON
133
+ ui.color('on', :green)
134
+ when PS_OFF
135
+ ui.color('off', :red)
136
+ when PS_SUSPENDED
137
+ ui.color('suspended', :yellow)
138
+ end
224
139
 
225
- if get_config(:esx_disk)
226
- print "#{ui.color("ESX Disks:", :cyan)}"
227
- vmc.layout.disk.each do |dsc|
228
- print "#{dsc.diskFile} | "
229
- end
230
- end
231
-
232
- if get_config(:snapshots)
233
- unless vmc.snapshot.nil?
234
- print "#{ui.color("Snapshots:", :cyan)}"
235
- vmc.snapshot.rootSnapshotList.each do |snap|
236
- print " #{snap.name}"
237
- end
238
- end
239
- end
240
- puts
140
+ if get_config(:matchname)
141
+ next unless vmc.name.include? config[:matchname]
142
+ end
143
+
144
+ if get_config(:matchtools)
145
+ next unless vmc.guest.toolsStatus == config[:matchtools]
146
+ end
147
+
148
+ next if get_config(:soff) && (vmc.runtime.powerState == PS_ON)
149
+
150
+ next if get_config(:son) && (vmc.runtime.powerState == PS_OFF)
151
+
152
+ if get_config(:matchip)
153
+ if !vmc.guest.ipAddress.nil? && vmc.guest.ipAddress != ''
154
+ next unless vmc.guest.ipAddress.include? config[:matchip]
155
+ else
156
+ next
157
+ end
158
+ end
159
+
160
+ unless vmc.guest.guestFullName.nil?
161
+ if get_config(:matchos)
162
+ next unless vmc.guest.guestFullName.include? config[:matchos]
163
+ end
164
+ end
165
+
166
+ print "#{ui.color('VM Name:', :cyan)} #{vmc.name}\t"
167
+ if get_config(:hostname)
168
+ print "#{ui.color('Hostname:', :cyan)} #{vmc.guest.hostName}\t"
169
+ end
170
+
171
+ if get_config(:full_path)
172
+ actualname = ''
173
+ vmcp = vmc
174
+ while !vmcp.parent.nil? && vmcp.parent.name != 'vm'
175
+ actualname.concat("#{vmcp.parent.name}/")
176
+ vmcp = vmcp.parent
177
+ end
178
+ print ui.color('Folder:', :cyan)
179
+ print '"'
180
+ print actualname.split('/').reverse.join('/')
181
+ print "\"\t"
182
+
183
+ else
184
+ print "#{ui.color('Folder', :cyan)}: #{vmc.parent.name}\t"
185
+ end
186
+
187
+ if get_config(:ip)
188
+ print "#{ui.color('IP:', :cyan)} #{vmc.guest.ipAddress}\t"
189
+ end
190
+ if get_config(:ips)
191
+ ipregex = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/
192
+ networks = vmc.guest.net.map { |net| "#{net.network}:" + net.ipConfig.ipAddress.select { |i| i.ipAddress[ipregex] }[0].ipAddress }
193
+ print "#{ui.color('IPS:', :cyan)} #{networks.join(',')}\t"
194
+ end
195
+ if get_config(:os)
196
+ print "#{ui.color('OS:', :cyan)} #{vmc.guest.guestFullName}\t"
197
+ end
198
+ if get_config(:ram)
199
+ print "#{ui.color('RAM:', :cyan)} #{vmc.summary.config.memorySizeMB}\t"
200
+ end
201
+ if get_config(:cpu)
202
+ print "#{ui.color('CPU:', :cyan)} #{vmc.summary.config.numCpu}\t"
203
+ end
204
+ if get_config(:alarms)
205
+ print "#{ui.color('Alarms:', :cyan)} #{vmc.summary.overallStatus}\t"
206
+ end
207
+ print "#{ui.color('State:', :cyan)} #{state}\t"
208
+ if get_config(:tools)
209
+ print "#{ui.color('Tools:', :cyan)} #{vmc.guest.toolsStatus}\t"
210
+ end
211
+
212
+ if get_config(:os_disk)
213
+ print ui.color('OS Disks:', :cyan)
214
+ vmc.guest.disk.each do |disc|
215
+ print "#{disc.diskPath} #{disc.capacity / 1024 / 1024}MB Free:#{disc.freeSpace / 1024 / 1024}MB |"
216
+ end
217
+ end
218
+
219
+ if get_config(:esx_disk)
220
+ print ui.color('ESX Disks:', :cyan)
221
+ vmc.layout.disk.each do |dsc|
222
+ print "#{dsc.diskFile} | "
223
+ end
224
+ end
225
+
226
+ if get_config(:snapshots)
227
+ unless vmc.snapshot.nil?
228
+ print ui.color('Snapshots:', :cyan)
229
+ vmc.snapshot.rootSnapshotList.each do |snap|
230
+ print " #{snap.name}"
231
+ end
232
+ end
241
233
  end
234
+ puts
242
235
  end
243
236
  end
244
237
  end
@@ -8,18 +8,14 @@ require 'chef/knife/base_vsphere_command'
8
8
  require 'rbvmomi'
9
9
  require 'netaddr'
10
10
 
11
- PS_ON = 'poweredOn'
12
- PS_OFF = 'poweredOff'
13
- PS_SUSPENDED = 'suspended'
14
-
15
- POWER_STATES = {
16
- PS_ON => 'powered on',
17
- PS_OFF => 'powered off',
18
- PS_SUSPENDED => 'suspended'
19
- }
20
-
21
11
  # Manage power state of a virtual machine
22
12
  class Chef::Knife::VsphereVmState < Chef::Knife::BaseVsphereCommand
13
+ POWER_STATES = {
14
+ PS_ON => 'powered on',
15
+ PS_OFF => 'powered off',
16
+ PS_SUSPENDED => 'suspended'
17
+ }
18
+
23
19
  banner 'knife vsphere vm state VMNAME (options)'
24
20
 
25
21
  common_options
@@ -1,3 +1,3 @@
1
1
  module KnifeVsphere
2
- VERSION = '1.2.14'
2
+ VERSION = '1.2.16'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-vsphere
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.14
4
+ version: 1.2.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ezra Pagel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-30 00:00:00.000000000 Z
11
+ date: 2016-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: filesize
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: byebug
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: VMware vSphere Support for Chef's Knife Command
112
126
  email: ezra@cpan.org
113
127
  executables: []