knife-vsphere 1.0.0.pre.3 → 1.0.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.
@@ -146,7 +146,7 @@ class Chef
146
146
  end
147
147
 
148
148
  def traverse_folders_for_vms(folder, vmname)
149
- retval = []
149
+ retval = []
150
150
  children = folder.children.find_all
151
151
  children.each do |child|
152
152
  if child.class == RbVmomi::VIM::VirtualMachine && child.name == vmname
@@ -204,7 +204,7 @@ class Chef
204
204
  if baseEntity.is_a? RbVmomi::VIM::Folder
205
205
  baseEntity = baseEntity.childEntity.find { |f| f.name == entityArrItem } or
206
206
  abort "no such pool #{poolName} while looking for #{entityArrItem}"
207
- elsif baseEntity.is_a? RbVmomi::VIM::ClusterComputeResource or baseEntity.is_a? RbVmomi::VIM::ComputeResource
207
+ elsif baseEntity.is_a? RbVmomi::VIM::ClusterComputeResource or baseEntity.is_a? RbVmomi::VIM::ComputeResource
208
208
  baseEntity = baseEntity.resourcePool.resourcePool.find { |f| f.name == entityArrItem } or
209
209
  abort "no such pool #{poolName} while looking for #{entityArrItem}"
210
210
  elsif baseEntity.is_a? RbVmomi::VIM::ResourcePool
@@ -272,10 +272,20 @@ class Chef
272
272
  baseEntity.find { |f| f.info.name == dsName } or abort "no such datastore #{dsName}"
273
273
  end
274
274
 
275
- def find_datastorecluster(dsName)
276
- dc = get_datacenter
277
- baseEntity = dc.datastoreFolder.childEntity
278
- baseEntity.find { |f| f.name == dsName and f.instance_of?(RbVmomi::VIM::StoragePod) } or abort "no such datastorecluster #{dsName}"
275
+ def find_datastorecluster(dsName, folder = nil)
276
+ if ! folder
277
+ dc = get_datacenter
278
+ folder = dc.datastoreFolder
279
+ end
280
+ folder.childEntity.each do |child|
281
+ if child.class.to_s == 'Folder'
282
+ ds = find_datastorecluster(dsName, child)
283
+ if ds then return ds end
284
+ elsif child.class.to_s == 'StoragePod' && child.name == dsName
285
+ return child
286
+ end
287
+ end
288
+ return nil
279
289
  end
280
290
 
281
291
  def find_device(vm, deviceName)
@@ -304,8 +314,8 @@ class Chef
304
314
  if object.parent.is_a?(RbVmomi::VIM:: ManagedEntity)
305
315
  return get_path_to_object(object.parent) + "/" + object.parent.name
306
316
  else
307
- return ""
308
- end
317
+ return ""
318
+ end
309
319
  else
310
320
  puts "Unknown type #{object.class}, not enumerating"
311
321
  nil
@@ -21,6 +21,50 @@ class Chef::Knife::VsphereVmMove < Chef::Knife::BaseVsphereCommand
21
21
  :long => "--dest-folder FOLDER",
22
22
  :description => "The destination folder into which the VM or template should be moved"
23
23
 
24
+ option :datastore,
25
+ :long => "--datastore STORE",
26
+ :description => "The datastore into which to put the cloned VM"
27
+
28
+ option :thin_provision,
29
+ :long => "--thin-provision",
30
+ :description => "Indicates whether disk should be thin provisioned.",
31
+ :boolean => true
32
+
33
+ option :thick_provision,
34
+ :long => "--thick-provision",
35
+ :description => "Indicates whether disk should be thick provisioned.",
36
+ :boolean => true
37
+
38
+ # Convert VM
39
+ def convert_vm(vm)
40
+ rspec = nil
41
+ dc = get_datacenter
42
+ hosts = find_all_in_folder(dc.hostFolder, RbVmomi::VIM::ComputeResource)
43
+ rp = hosts.first.resourcePool
44
+ rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(:pool => rp)
45
+
46
+ if get_config(:thin_provision)
47
+ puts "Thin provsisioning #{vm.name}"
48
+ rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(:datastore => find_datastore(get_config(:datastore)), :transform => :sparse)
49
+ end
50
+
51
+ if get_config(:thick_provision)
52
+ puts "Thick provsisioning #{vm.name}"
53
+ rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(:datastore => find_datastore(get_config(:datastore)), :transform => :flat)
54
+ end
55
+
56
+ task = vm.RelocateVM_Task(:spec => rspec)
57
+ task.wait_for_completion
58
+ end
59
+
60
+ # Move VM
61
+ def move_vm(vm)
62
+ dest_name = config[:dest_name] || vmname
63
+ dest_folder = config[:dest_folder].nil? ? (vm.parent) : (find_folder(get_config(:dest_folder)))
64
+
65
+ vm.Rename_Task(:newName => dest_name).wait_for_completion unless vmname == dest_name
66
+ dest_folder.MoveIntoFolder_Task(:list => [vm]).wait_for_completion unless folder == dest_folder
67
+ end
24
68
 
25
69
  def run
26
70
  $stdout.sync = true
@@ -38,10 +82,11 @@ class Chef::Knife::VsphereVmMove < Chef::Knife::BaseVsphereCommand
38
82
  vm = find_in_folder(folder, RbVmomi::VIM::VirtualMachine, vmname) or
39
83
  abort "VM #{vmname} not found"
40
84
 
41
- dest_name = config[:dest_name] || vmname
42
- dest_folder = config[:dest_folder].nil? ? (vm.parent) : (find_folder(get_config(:dest_folder)))
43
-
44
- vm.Rename_Task(:newName => dest_name).wait_for_completion unless vmname == dest_name
45
- dest_folder.MoveIntoFolder_Task(:list => [vm]).wait_for_completion unless folder == dest_folder
85
+ if get_config(:thin_provision) || get_config(:thick_provision)
86
+ convert_vm(vm)
87
+ else
88
+ move_vm(vm)
89
+ end
46
90
  end
47
91
  end
92
+
@@ -0,0 +1,45 @@
1
+ require 'chef/knife'
2
+ require 'chef/knife/base_vsphere_command'
3
+
4
+ class Chef::Knife::VsphereCpuRatio < Chef::Knife::BaseVsphereCommand
5
+ banner 'knife vsphere cpu ratio [CLUSTER] [HOST]'
6
+
7
+ get_common_options
8
+
9
+ def run
10
+ $stdout.sync = true
11
+
12
+ cluster_name = @name_args[0]
13
+ host_name = @name_args[1]
14
+
15
+ get_vim_connection
16
+
17
+ dc = get_datacenter
18
+ hf = dc.hostFolder
19
+
20
+ cluster = cluster_name.nil? ? hf.childEntity : hf.childEntity.select { |c| c.name == cluster_name }
21
+
22
+ if cluster.empty?
23
+ fatal_exit("Cluster #{cluster_name} not found.")
24
+ end
25
+
26
+ cluster.each { |c|
27
+ host = host_name.nil? ? c.host : c.host.select { |h| h.name == host_name }
28
+ if host.empty?
29
+ fatal_exit("Host not found in cluster #{c.name}.")
30
+ end
31
+
32
+ puts "### Cluster #{c.name} ###"
33
+
34
+ host.each { |h|
35
+ v_cpu = h.vm.inject(0) { |sum, vm| sum + vm.config.hardware.numCPU }
36
+ p_cpu = h.summary.hardware.numCpuThreads
37
+
38
+ ratio = 1.0 * v_cpu/p_cpu
39
+
40
+ puts "#{h.name}: #{ratio}"
41
+ }
42
+ puts ''
43
+ }
44
+ end
45
+ end
@@ -43,6 +43,12 @@ class Chef::Knife::VsphereDatastoreList < Chef::Knife::BaseVsphereCommand
43
43
 
44
44
  get_common_options
45
45
 
46
+ option :list,
47
+ :long => "--list",
48
+ :short => "-L",
49
+ :description => "Indicates whether to list VM's in datastore",
50
+ :boolean => true
51
+
46
52
  def run
47
53
  $stdout.sync = true
48
54
 
@@ -52,6 +58,14 @@ class Chef::Knife::VsphereDatastoreList < Chef::Knife::BaseVsphereCommand
52
58
  avail = number_to_human_size(store.summary[:freeSpace])
53
59
  cap = number_to_human_size(store.summary[:capacity])
54
60
  puts "#{ui.color("Datastore", :cyan)}: #{store.name} (#{avail} / #{cap})"
61
+ if get_config(:list)
62
+ store.vm.each do |vms|
63
+ hostName = vms.guest[:hostName]
64
+ guestFullName = vms.guest[:guestFullName]
65
+ guestState = vms.guest[:guestState]
66
+ puts "#{ui.color("VM Name:", :green)} #{hostName} #{ui.color("OS:", :magenta)} #{guestFullName} #{ui.color("State:", :cyan)} #{guestState}"
67
+ end
68
+ end
55
69
  end
56
70
  end
57
71
  end
@@ -35,6 +35,24 @@ def number_to_human_size(number)
35
35
  return sprintf("%0.2f %s", number, unit)
36
36
  end
37
37
 
38
+ def traverse_folders_for_dsclusters(folder)
39
+ print_dsclusters_in_folder(folder)
40
+ folder.childEntity.each do |child|
41
+ if child.class.to_s == 'Folder'
42
+ traverse_folders_for_dsclusters(child)
43
+ end
44
+ end
45
+ end
46
+
47
+ def print_dsclusters_in_folder (folder)
48
+ folder.childEntity.each do |child|
49
+ if child.class.to_s == "StoragePod"
50
+ avail = number_to_human_size(child.summary[:freeSpace])
51
+ cap = number_to_human_size(child.summary[:capacity])
52
+ puts "#{ui.color("DatastoreCluster", :cyan)}: #{child.name} (#{avail} / #{cap})"
53
+ end
54
+ end
55
+ end
38
56
 
39
57
  # Lists all known data store cluster in datacenter with sizes
40
58
  class Chef::Knife::VsphereDatastoreclusterList < Chef::Knife::BaseVsphereCommand
@@ -45,16 +63,9 @@ class Chef::Knife::VsphereDatastoreclusterList < Chef::Knife::BaseVsphereCommand
45
63
 
46
64
  def run
47
65
  $stdout.sync = true
48
-
49
66
  vim = get_vim_connection
50
67
  dc = get_datacenter
51
- dc.datastoreFolder.childEntity.each do |store|
52
- if store.class.to_s == "StoragePod"
53
- avail = number_to_human_size(store.summary[:freeSpace])
54
- cap = number_to_human_size(store.summary[:capacity])
55
- puts "#{ui.color("DatastoreCluster", :cyan)}: #{store.name} (#{avail} / #{cap})"
56
- end
57
- end
68
+ traverse_folders_for_dsclusters(dc.datastoreFolder)
58
69
  end
59
70
  end
60
71
 
@@ -18,6 +18,36 @@
18
18
  require 'chef/knife'
19
19
  require 'chef/knife/base_vsphere_command'
20
20
 
21
+ def is_max_dscluster(dscluster, max_dscluster)
22
+ if ! max_dscluster
23
+ return true
24
+ end
25
+
26
+ if dscluster.summary[:freeSpace] > max_dscluster.summary[:freeSpace]
27
+ return true
28
+ end
29
+
30
+ return false
31
+ end
32
+
33
+ def find_max_dscluster(folder, max_dscluster, regex)
34
+ folder.childEntity.each do |child|
35
+ if child.class.to_s == 'Folder'
36
+ sub_max = find_max_dscluster(child, max_dscluster, regex)
37
+ if is_max_dscluster(sub_max, max_dscluster)
38
+ max_dscluster = sub_max
39
+ end
40
+ elsif child.class.to_s == 'StoragePod'
41
+
42
+ if is_max_dscluster(child, max_dscluster) && regex.match(child.name)
43
+ max_dscluster = child
44
+ end
45
+ end
46
+ end
47
+
48
+ return max_dscluster
49
+ end
50
+
21
51
  # Gets the data store cluster with the most free space in datacenter
22
52
  class Chef::Knife::VsphereDatastoreclusterMaxfree < Chef::Knife::BaseVsphereCommand
23
53
 
@@ -35,14 +65,20 @@ class Chef::Knife::VsphereDatastoreclusterMaxfree < Chef::Knife::BaseVsphereComm
35
65
 
36
66
  vim = get_vim_connection
37
67
  dcname = get_config(:vsphere_dc)
38
- regex = /#{Regexp.escape( get_config(:regex))}/
39
- dc = config[:vim].serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
40
- max = nil
41
- dc.datastoreFolder.childEntity.each do |store|
42
- if regex.match(store.name) and (store.class.to_s == "StoragePod") and (max == nil or max.summary[:freeSpace] < store.summary[:freeSpace])
43
- max = store
44
- end
68
+ regex = /#{Regexp.escape( get_config(:regex))}/
69
+ max_dscluster = nil
70
+
71
+ vim = get_vim_connection
72
+ dc = get_datacenter
73
+
74
+ max_dscluster = find_max_dscluster(dc.datastoreFolder, max_dscluster, regex)
75
+
76
+ if max_dscluster
77
+ puts max_dscluster.name
78
+ else
79
+ puts "No datastore clusters found"
80
+ exit 1
45
81
  end
46
- puts max ? max.name : ""
82
+
47
83
  end
48
84
  end
@@ -0,0 +1,30 @@
1
+ #
2
+ # Author:: Ezra Pagel (<ezra@cpan.org>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ require 'chef/knife'
6
+ require 'chef/knife/base_vsphere_command'
7
+
8
+ # Lists all vm folders
9
+ class Chef::Knife::VsphereFolderList < Chef::Knife::BaseVsphereCommand
10
+
11
+ banner "knife vsphere folder list"
12
+
13
+ get_common_options
14
+
15
+ def traverse_folders(folder, indent_level)
16
+
17
+ puts "#{" " * indent_level} #{ui.color("Folder", :cyan)}: " + folder.name
18
+
19
+ folders = find_all_in_folder(folder, RbVmomi::VIM::Folder)
20
+ folders.each do |child|
21
+ traverse_folders(child, indent_level + 1)
22
+ end
23
+ end
24
+
25
+ def run
26
+ vim = get_vim_connection
27
+ baseFolder = find_folder(get_config(:folder));
28
+ traverse_folders(baseFolder, 0)
29
+ end
30
+ end
@@ -2,6 +2,7 @@ require 'chef/knife'
2
2
  require 'chef/knife/base_vsphere_command'
3
3
  require 'rbvmomi'
4
4
  require 'netaddr'
5
+
5
6
  #list hosts belonging to pool
6
7
  class Chef::Knife::VsphereHostsList < Chef::Knife::BaseVsphereCommand
7
8
  banner "knife vsphere hosts list"
@@ -12,38 +13,30 @@ class Chef::Knife::VsphereHostsList < Chef::Knife::BaseVsphereCommand
12
13
  :short => "-h",
13
14
  :description => "Target pool"
14
15
 
15
- def traverse_folders_for_pool(folder, poolname)
16
- children = folder.children.find_all
17
- children.each do |child|
18
- if child.class == RbVmomi::VIM::ClusterComputeResource || child.class == RbVmomi::VIM::ComputeResource || child.class == RbVmomi::VIM::ResourcePool
19
- if child.name == poolname then return child end
20
- elsif child.class == RbVmomi::VIM::Folder
21
- pool = traverse_folders_for_pool(child, poolname)
22
- if pool then return pool end
23
- end
24
- end
25
- return false
16
+ def find_pools(folder, poolname = nil)
17
+ pools = folder.children.find_all.select {|p| p.is_a?(RbVmomi::VIM::ComputeResource) || p.is_a?(RbVmomi::VIM::ResourcePool) }
18
+ poolname.nil? ? pools : pools.select {|p| p.name == poolname }
26
19
  end
27
20
 
28
21
  def run
29
- poolname = config[:pool]
30
- if poolname.nil?
31
- show_usage
32
- fatal_exit("You must specify a resource pool or cluster name (see knife vsphere pool list)")
33
- end
34
-
35
-
36
22
  vim = get_vim_connection
37
23
  dc = get_datacenter
38
24
  folder = dc.hostFolder
39
25
 
40
- pool = traverse_folders_for_pool(folder, poolname) or abort "Pool #{poolname} not found"
26
+ target_pool = config[:pool]
41
27
 
42
- hosts=pool.host
43
- unless hosts.nil?
28
+ pools = find_pools(folder, target_pool)
29
+ if target_pool && pools.empty?
30
+ puts "Pool #{target_pool} not found"
31
+ return
32
+ end
33
+
34
+ pools.each do |pool|
35
+ puts "#{ui.color("Pool", :cyan)}: #{pool.name}"
36
+ hosts = pool.host || []
44
37
  hosts.each do |hostc|
45
- puts "#{ui.color("Host", :cyan)}: #{hostc.name}"
46
- end
47
- end
48
- end
38
+ puts " #{ui.color("Host", :cyan)}: #{hostc.name}"
39
+ end
40
+ end
41
+ end
49
42
  end
@@ -13,13 +13,16 @@ class Chef::Knife::VspherePoolList < Chef::Knife::BaseVsphereCommand
13
13
  get_common_options
14
14
 
15
15
  def traverse_folders(folder)
16
- puts "#{ui.color("#{folder.class}", :cyan)}: "+(folder.path[3..-1].map { |x| x[1] }.* '/')
17
- folders = find_all_in_folder(folder, RbVmomi::VIM::ManagedObject)
18
- unless folders.nil?
19
- folders.each do |child|
20
- traverse_folders(child)
21
- end
16
+ return if folder.is_a? RbVmomi::VIM::VirtualApp
17
+
18
+ puts "#{ui.color("Pool", :cyan)}: "+(folder.path[3..-1].map { |x| x[1] }.* '/') if
19
+ folder.is_a? RbVmomi::VIM::ResourcePool
20
+
21
+ folders = find_all_in_folder(folder, RbVmomi::VIM::ManagedObject) || []
22
+ folders.each do |child|
23
+ traverse_folders(child)
22
24
  end
25
+
23
26
  end
24
27
 
25
28
  def find_pool_folder(folderName)
@@ -36,7 +39,6 @@ class Chef::Knife::VspherePoolList < Chef::Knife::BaseVsphereCommand
36
39
  end
37
40
 
38
41
  def run
39
- $stdout.sync = true
40
42
  vim = get_vim_connection
41
43
  baseFolder = find_pool_folder(get_config(:folder));
42
44
  traverse_folders(baseFolder)
@@ -47,6 +47,16 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
47
47
  :description => "Indicates whether to use linked clones.",
48
48
  :boolean => false
49
49
 
50
+ option :linked_clone,
51
+ :long => "--linked-clone",
52
+ :description => "Indicates whether to use linked clones.",
53
+ :boolean => false
54
+
55
+ option :thin_provision,
56
+ :long => "--thin-provision",
57
+ :description => "Indicates whether disk should be thin provisioned.",
58
+ :boolean => true
59
+
50
60
  option :annotation,
51
61
  :long => "--annotation TEXT",
52
62
  :description => "Add TEXT in Notes field from annotation"
@@ -113,6 +123,10 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
113
123
  :description => "Indicates whether to bootstrap the VM",
114
124
  :boolean => false
115
125
 
126
+ option :environment,
127
+ :long => "--environment ENVIRONMENT",
128
+ :description => "Environment to add the node to for bootstrapping"
129
+
116
130
  option :fqdn,
117
131
  :long => "--fqdn SERVER_FQDN",
118
132
  :description => "Fully qualified hostname for bootstrapping"
@@ -233,6 +247,7 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
233
247
  end
234
248
 
235
249
  vim = get_vim_connection
250
+ vdm = vim.serviceContent.virtualDiskManager
236
251
 
237
252
  dc = get_datacenter
238
253
 
@@ -310,7 +325,6 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
310
325
 
311
326
  # Builds a CloneSpec
312
327
  def generate_clone_spec (src_config)
313
-
314
328
  rspec = nil
315
329
  if get_config(:resource_pool)
316
330
  rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(:pool => find_pool(get_config(:resource_pool)))
@@ -343,15 +357,13 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
343
357
  end
344
358
  end
345
359
 
346
- if get_config(:mark_as_template)
347
- clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(:location => rspec,
348
- :powerOn => false,
349
- :template => true)
350
- else
351
- clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(:location => rspec,
352
- :powerOn => false,
353
- :template => false)
360
+ if get_config(:thin_provision)
361
+ rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(:transform => :sparse, :pool => find_pool(get_config(:resource_pool)))
354
362
  end
363
+
364
+ is_template = !get_config(:mark_as_template).nil?
365
+ clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(:location => rspec, :powerOn => false,:template => is_template)
366
+
355
367
  clone_spec.config = RbVmomi::VIM.VirtualMachineConfigSpec(:deviceChange => Array.new)
356
368
 
357
369
  if get_config(:annotation)
@@ -375,7 +387,7 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
375
387
  card.backing.port = switch_port
376
388
  rescue
377
389
  # not connected to a distibuted switch?
378
- card.backing.deviceName = network.name
390
+ card.backing = RbVmomi::VIM::VirtualEthernetCardNetworkBackingInfo(:network => network, :deviceName => network.name)
379
391
  end
380
392
  dev_spec = RbVmomi::VIM.VirtualDeviceConfigSpec(:device => card, :operation => "edit")
381
393
  clone_spec.config.deviceChange.push dev_spec
@@ -417,24 +429,21 @@ class Chef::Knife::VsphereVmClone < Chef::Knife::BaseVsphereCommand
417
429
  config[:vmname]
418
430
  end
419
431
 
420
- if src_config.guestId.downcase.include?("linux")
432
+ if src_config.guestId.downcase.include?("windows")
433
+ if cust_spec.identity.nil?
434
+ fatal_exit("Please provide Windows Guest Customization")
435
+ else
436
+ cust_spec.identity.userData.computerName = RbVmomi::VIM.CustomizationFixedName(:name => hostname)
437
+ end
438
+ else
421
439
  ident = RbVmomi::VIM.CustomizationLinuxPrep
422
-
423
440
  ident.hostName = RbVmomi::VIM.CustomizationFixedName(:name => hostname)
424
-
425
441
  if get_config(:customization_domain)
426
442
  ident.domain = get_config(:customization_domain)
427
443
  else
428
444
  ident.domain = ''
429
445
  end
430
-
431
446
  cust_spec.identity = ident
432
- elsif src_config.guestId.downcase.include?("windows")
433
- if cust_spec.identity.nil?
434
- fatal_exit("Please provide Windows Guest Customization")
435
- else
436
- cust_spec.identity.userData.computerName = RbVmomi::VIM.CustomizationFixedName(:name => hostname)
437
- end
438
447
  end
439
448
  end
440
449
 
@@ -1,66 +1,66 @@
1
- #
2
- # Author:: Ezra Pagel (<ezra@cpan.org>)
3
- # License:: Apache License, Version 2.0
4
- #
5
-
6
- require 'chef/knife'
7
- require 'chef/knife/base_vsphere_command'
8
- require 'rbvmomi'
9
-
10
- # These two are needed for the '--purge' deletion case
11
- require 'chef/node'
12
- require 'chef/api_client'
13
-
14
- # Delete a virtual machine from vCenter
15
- class Chef::Knife::VsphereVmDelete < Chef::Knife::BaseVsphereCommand
16
-
17
- banner "knife vsphere vm delete VMNAME"
18
-
19
- option :purge,
20
- :short => "-P",
21
- :long => "--purge",
22
- :boolean => true,
23
- :description => "Destroy corresponding node and client on the Chef Server, in addition to destroying the VM itself."
24
-
25
- get_common_options
26
-
27
- # Extracted from Chef::Knife.delete_object, because it has a
28
- # confirmation step built in... By specifying the '--purge'
29
- # flag (and also explicitly confirming the server destruction!)
30
- # the user is already making their intent known. It is not
31
- # necessary to make them confirm two more times.
32
- def destroy_item(itemClass, name, type_name)
33
- object = itemClass.load(name)
34
- object.destroy
35
- puts "Deleted #{type_name} #{name}"
36
- end
37
-
38
- def run
39
- $stdout.sync = true
40
-
41
- vmname = @name_args[0]
42
-
43
- if vmname.nil?
44
- show_usage
45
- fatal_exit("You must specify a virtual machine name")
46
- end
47
-
48
- vim = get_vim_connection
49
-
50
- baseFolder = find_folder(get_config(:folder));
51
-
52
- vm = find_in_folder(baseFolder, RbVmomi::VIM::VirtualMachine, vmname) or
53
- fatal_exit("VM #{vmname} not found")
54
-
55
- vm.PowerOffVM_Task.wait_for_completion unless vm.runtime.powerState == "poweredOff"
56
- vm.Destroy_Task
57
- puts "Deleted virtual machine #{vmname}"
58
-
59
- if config[:purge]
60
- destroy_item(Chef::Node, vmname, "node")
61
- destroy_item(Chef::ApiClient, vmname, "client")
62
- else
63
- puts "Corresponding node and client for the #{vmname} server were not deleted and remain registered with the Chef Server"
64
- end
65
- end
66
- end
1
+ #
2
+ # Author:: Ezra Pagel (<ezra@cpan.org>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+
6
+ require 'chef/knife'
7
+ require 'chef/knife/base_vsphere_command'
8
+ require 'rbvmomi'
9
+
10
+ # These two are needed for the '--purge' deletion case
11
+ require 'chef/node'
12
+ require 'chef/api_client'
13
+
14
+ # Delete a virtual machine from vCenter
15
+ class Chef::Knife::VsphereVmDelete < Chef::Knife::BaseVsphereCommand
16
+
17
+ banner "knife vsphere vm delete VMNAME"
18
+
19
+ option :purge,
20
+ :short => "-P",
21
+ :long => "--purge",
22
+ :boolean => true,
23
+ :description => "Destroy corresponding node and client on the Chef Server, in addition to destroying the VM itself."
24
+
25
+ get_common_options
26
+
27
+ # Extracted from Chef::Knife.delete_object, because it has a
28
+ # confirmation step built in... By specifying the '--purge'
29
+ # flag (and also explicitly confirming the server destruction!)
30
+ # the user is already making their intent known. It is not
31
+ # necessary to make them confirm two more times.
32
+ def destroy_item(itemClass, name, type_name)
33
+ object = itemClass.load(name)
34
+ object.destroy
35
+ puts "Deleted #{type_name} #{name}"
36
+ end
37
+
38
+ def run
39
+ $stdout.sync = true
40
+
41
+ vmname = @name_args[0]
42
+
43
+ if vmname.nil?
44
+ show_usage
45
+ fatal_exit("You must specify a virtual machine name")
46
+ end
47
+
48
+ vim = get_vim_connection
49
+
50
+ baseFolder = find_folder(get_config(:folder));
51
+
52
+ vm = traverse_folders_for_vm(baseFolder, vmname) or
53
+ fatal_exit("VM #{vmname} not found")
54
+
55
+ vm.PowerOffVM_Task.wait_for_completion unless vm.runtime.powerState == "poweredOff"
56
+ vm.Destroy_Task
57
+ puts "Deleted virtual machine #{vmname}"
58
+
59
+ if config[:purge]
60
+ destroy_item(Chef::Node, vmname, "node")
61
+ destroy_item(Chef::ApiClient, vmname, "client")
62
+ else
63
+ puts "Corresponding node and client for the #{vmname} server were not deleted and remain registered with the Chef Server"
64
+ end
65
+ end
66
+ end
@@ -15,52 +15,47 @@ class Chef::Knife::VsphereVmList < Chef::Knife::BaseVsphereCommand
15
15
  option :recursive,
16
16
  :long => "--recursive",
17
17
  :short => "-r",
18
- :description => "Recurse down through sub-folders"
18
+ :description => "Recurse into sub-folders"
19
19
 
20
- option :only_folders,
21
- :long => "--only-folders",
22
- :description => "Print only sub-folders"
20
+ def traverse_folders(folder, is_top = false, recurse = false)
23
21
 
24
- def traverse_folders(folder)
25
- puts "#{ui.color("Folder", :cyan)}: "+(folder.path[3..-1].map { |x| x[1] }.* '/')
26
- print_vms_in_folder(folder) unless get_config(:only_folders)
27
- folders = find_all_in_folder(folder, RbVmomi::VIM::Folder)
28
- folders.each do |child|
29
- traverse_folders(child)
22
+ vms = find_all_in_folder(folder, RbVmomi::VIM::VirtualMachine).select {|v| v.config && !v.config.template }
23
+ if vms.any?
24
+ puts "#{ui.color("Folder", :cyan)}: "+(folder.path[3..-1].map { |x| x[1] }.* '/')
25
+ vms.each { |v| print_vm(v) }
26
+ elsif is_top
27
+ puts "#{ui.color("No VMs", :cyan)}"
30
28
  end
31
- end
32
29
 
33
- def print_vms_in_folder(folder)
34
- vms = find_all_in_folder(folder, RbVmomi::VIM::VirtualMachine)
35
- vms.each do |vm|
36
- state = case vm.runtime.powerState
37
- when PsOn
38
- ui.color("on", :green)
39
- when PsOff
40
- ui.color("off", :red)
41
- when PsSuspended
42
- ui.color("suspended", :yellow)
43
- end
44
- puts "#{ui.color("VM Name:", :cyan)} #{vm.name}\t#{ui.color("IP:", :magenta)} #{vm.guest.ipAddress}\t#{ui.color("RAM:", :magenta)} #{vm.summary.config.memorySizeMB}\t#{ui.color("State:", :cyan)} #{state}"
30
+ if (recurse)
31
+ folders = find_all_in_folder(folder, RbVmomi::VIM::Folder)
32
+ folders.each do |child|
33
+ traverse_folders(child, false, recurse)
34
+ end
45
35
  end
36
+
46
37
  end
47
38
 
48
- def print_subfolders(folder)
49
- folders = find_all_in_folder(folder, RbVmomi::VIM::Folder)
50
- folders.each do |subfolder|
51
- puts "#{ui.color("Folder Name", :cyan)}: #{subfolder.name}"
52
- end
39
+ def print_vm(vm)
40
+ state = case vm.runtime.powerState
41
+ when PsOn
42
+ ui.color("on", :green)
43
+ when PsOff
44
+ ui.color("off", :red)
45
+ when PsSuspended
46
+ ui.color("suspended", :yellow)
47
+ end
48
+ puts "\t#{ui.color("VM Name:", :cyan)} #{vm.name}"
49
+ "\t\t#{ui.color("IP:", :magenta)} #{vm.guest.ipAddress}"
50
+ "\t\t#{ui.color("RAM:", :magenta)} #{vm.summary.config.memorySizeMB}"
51
+ "\t\t#{ui.color("State:", :cyan)} #{state}"
53
52
  end
54
53
 
55
54
  def run
56
- $stdout.sync = true
57
55
  vim = get_vim_connection
58
56
  baseFolder = find_folder(get_config(:folder));
59
- if get_config(:recursive)
60
- traverse_folders(baseFolder)
61
- else
62
- print_subfolders(baseFolder)
63
- print_vms_in_folder(baseFolder)
64
- end
57
+ recurse = get_config(:recursive)
58
+ is_top = true
59
+ traverse_folders(baseFolder, is_top, recurse)
65
60
  end
66
61
  end
@@ -106,6 +106,7 @@ class Chef::Knife::VsphereVmSnapshot < Chef::Knife::BaseVsphereCommand
106
106
  tree.each do |node|
107
107
  if node.name == name
108
108
  snapshot = node.snapshot
109
+ break
109
110
  elsif !node.childSnapshotList.empty?
110
111
  snapshot = find_node(node.childSnapshotList, name)
111
112
  end
@@ -0,0 +1,52 @@
1
+ # Author:: Malte Heidenreich
2
+ # License:: Apache License, Version 2.0
3
+
4
+ require 'chef/knife'
5
+ require 'chef/knife/base_vsphere_command'
6
+ require 'rbvmomi'
7
+ require 'netaddr'
8
+
9
+ class Chef::Knife::VsphereVmToolsconfig < Chef::Knife::BaseVsphereCommand
10
+ banner "knife vsphere vm toolsconfig PROPERTY VALUE. See \"https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.vm.ToolsConfigInfo.html\" for available properties and types."
11
+
12
+ option :empty,
13
+ :short => "-e",
14
+ :long => "--empty",
15
+ :description => "Allow empty string"
16
+ get_common_options
17
+
18
+ def run
19
+ $stdout.sync = true
20
+ vmname = @name_args[0]
21
+ if vmname.nil?
22
+ show_usage
23
+ fatal_exit("You must specify a virtual machine name")
24
+ end
25
+
26
+ property = @name_args[1]
27
+ if property.nil?
28
+ show_usage
29
+ fatal_exit("You must specify a property to modify")
30
+ end
31
+
32
+ value = @name_args[2]
33
+ if value.nil? && !get_config(:empty)
34
+ show_usage
35
+ fatal_exit("You must specify a value")
36
+ end
37
+
38
+ value = "" if get_config(:empty)
39
+
40
+ vim = get_vim_connection
41
+
42
+ dc = get_datacenter
43
+ folder = find_folder(get_config(:folder)) || dc.vmFolder
44
+
45
+ vm = traverse_folders_for_vm(folder, vmname) or abort "VM #{vmname} not found"
46
+
47
+ vmConfigSpec = RbVmomi::VIM.VirtualMachineConfigSpec(:tools => RbVmomi::VIM.ToolsConfigInfo(property => value))
48
+ vm.ReconfigVM_Task(:spec => vmConfigSpec)
49
+
50
+ puts "property #{property} updated successfully"
51
+ end
52
+ end
@@ -1,4 +1,4 @@
1
1
  module KnifeVsphere
2
- VERSION = "1.0.0.pre.3"
2
+ VERSION = "1.0.0"
3
3
  end
4
4
 
metadata CHANGED
@@ -1,53 +1,60 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-vsphere
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.3
4
+ version: 1.0.0
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Ezra Pagel
8
- autorequire:
9
+ autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-07-18 00:00:00.000000000 Z
12
+ date: 2014-12-30 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
15
+ name: netaddr
14
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
15
18
  requirements:
16
19
  - - ~>
17
20
  - !ruby/object:Gem::Version
18
21
  version: 1.5.0
19
- name: netaddr
20
- prerelease: false
21
22
  type: :runtime
23
+ prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
27
  - - ~>
25
28
  - !ruby/object:Gem::Version
26
29
  version: 1.5.0
27
30
  - !ruby/object:Gem::Dependency
31
+ name: chef
28
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
29
34
  requirements:
30
- - - '>='
35
+ - - ! '>='
31
36
  - !ruby/object:Gem::Version
32
37
  version: 0.10.0
33
- name: chef
34
- prerelease: false
35
38
  type: :runtime
39
+ prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
- - - '>='
43
+ - - ! '>='
39
44
  - !ruby/object:Gem::Version
40
45
  version: 0.10.0
41
46
  - !ruby/object:Gem::Dependency
47
+ name: rbvmomi
42
48
  requirement: !ruby/object:Gem::Requirement
49
+ none: false
43
50
  requirements:
44
51
  - - ~>
45
52
  - !ruby/object:Gem::Version
46
53
  version: 1.5.1
47
- name: rbvmomi
48
- prerelease: false
49
54
  type: :runtime
55
+ prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
51
58
  requirements:
52
59
  - - ~>
53
60
  - !ruby/object:Gem::Version
@@ -58,55 +65,59 @@ executables: []
58
65
  extensions: []
59
66
  extra_rdoc_files: []
60
67
  files:
61
- - lib/chef/knife/base_vsphere_command.rb
62
- - lib/chef/knife/vshpere_vm_migrate.rb
63
- - lib/chef/knife/vshpere_vm_move.rb
64
- - lib/chef/knife/vshpere_vm_net.rb
65
- - lib/chef/knife/vsphere_customization_list.rb
68
+ - lib/chef/knife/vsphere_vm_query.rb
69
+ - lib/chef/knife/vsphere_cpu_ratio.rb
66
70
  - lib/chef/knife/vsphere_datastorecluster_list.rb
67
71
  - lib/chef/knife/vsphere_datastorecluster_maxfree.rb
68
- - lib/chef/knife/vsphere_datastore_list.rb
69
- - lib/chef/knife/vsphere_datastore_maxfree.rb
72
+ - lib/chef/knife/vshpere_vm_migrate.rb
73
+ - lib/chef/knife/vsphere_vm_property_get.rb
74
+ - lib/chef/knife/vsphere_vm_state.rb
75
+ - lib/chef/knife/vshpere_vm_net.rb
76
+ - lib/chef/knife/vsphere_vm_execute.rb
70
77
  - lib/chef/knife/vsphere_hosts_list.rb
71
- - lib/chef/knife/vsphere_pool_list.rb
72
- - lib/chef/knife/vsphere_pool_query.rb
73
- - lib/chef/knife/vsphere_template_list.rb
74
- - lib/chef/knife/vsphere_vlan_list.rb
78
+ - lib/chef/knife/vsphere_vm_snapshot.rb
79
+ - lib/chef/knife/vsphere_vm_toolsconfig.rb
80
+ - lib/chef/knife/vsphere_vm_markastemplate.rb
75
81
  - lib/chef/knife/vsphere_vm_clone.rb
76
- - lib/chef/knife/vsphere_vm_config.rb
82
+ - lib/chef/knife/base_vsphere_command.rb
83
+ - lib/chef/knife/vsphere_vm_vmdk_add.rb
84
+ - lib/chef/knife/vsphere_customization_list.rb
85
+ - lib/chef/knife/vsphere_template_list.rb
77
86
  - lib/chef/knife/vsphere_vm_delete.rb
78
- - lib/chef/knife/vsphere_vm_execute.rb
87
+ - lib/chef/knife/vsphere_datastore_list.rb
88
+ - lib/chef/knife/vsphere_vm_config.rb
89
+ - lib/chef/knife/vsphere_vlan_list.rb
90
+ - lib/chef/knife/vsphere_datastore_maxfree.rb
79
91
  - lib/chef/knife/vsphere_vm_list.rb
80
- - lib/chef/knife/vsphere_vm_markastemplate.rb
81
- - lib/chef/knife/vsphere_vm_property_get.rb
92
+ - lib/chef/knife/vsphere_pool_query.rb
93
+ - lib/chef/knife/vshpere_vm_move.rb
94
+ - lib/chef/knife/vsphere_pool_list.rb
95
+ - lib/chef/knife/vsphere_folder_list.rb
82
96
  - lib/chef/knife/vsphere_vm_property_set.rb
83
- - lib/chef/knife/vsphere_vm_query.rb
84
- - lib/chef/knife/vsphere_vm_snapshot.rb
85
- - lib/chef/knife/vsphere_vm_state.rb
86
- - lib/chef/knife/vsphere_vm_vmdk_add.rb
87
97
  - lib/knife-vsphere/version.rb
88
98
  homepage: http://github.com/ezrapagel/knife-vsphere
89
99
  licenses:
90
100
  - Apache
91
- metadata: {}
92
- post_install_message:
101
+ post_install_message:
93
102
  rdoc_options: []
94
103
  require_paths:
95
104
  - lib
96
105
  required_ruby_version: !ruby/object:Gem::Requirement
106
+ none: false
97
107
  requirements:
98
- - - '>='
108
+ - - ! '>='
99
109
  - !ruby/object:Gem::Version
100
110
  version: '0'
101
111
  required_rubygems_version: !ruby/object:Gem::Requirement
112
+ none: false
102
113
  requirements:
103
- - - '>='
114
+ - - ! '>='
104
115
  - !ruby/object:Gem::Version
105
116
  version: '0'
106
117
  requirements: []
107
- rubyforge_project:
108
- rubygems_version: 2.1.9
109
- signing_key:
110
- specification_version: 4
118
+ rubyforge_project:
119
+ rubygems_version: 1.8.23
120
+ signing_key:
121
+ specification_version: 3
111
122
  summary: vSphere Support for Knife
112
123
  test_files: []
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: ca44c31e612974c4085c95cebd7ce9290782a76d
4
- data.tar.gz: 03d2eae019a9a4d898e5a9bc94391aa640d28de2
5
- SHA512:
6
- metadata.gz: f6d164cc5012c7eee2e351f7c241bc1fbd24f47b468fedb6f84e84ce9a7135c30481179eb46c9d2877a8c39dc4a667bc246ec9f8d2bc781677d61c3fa091a287
7
- data.tar.gz: 03eeac904d852e5394f1a6d573fae6f664a202e72805a8a87a883d71f112d2677fc6f568b898237f1c2ab07bad3ee46f7a497521b9efd7519078a825633a6de2