knife-vsphere 1.0.0.pre.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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