knife-ovh-cloud 1.0.0.pre.1
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.
- checksums.yaml +7 -0
- data/lib/chef/knife/base_ovh_cloud_command.rb +358 -0
- data/lib/chef/knife/ovh_cloud_customization_list.rb +29 -0
- data/lib/chef/knife/ovh_cloud_datastore_list.rb +58 -0
- data/lib/chef/knife/ovh_cloud_datastore_maxfree.rb +49 -0
- data/lib/chef/knife/ovh_cloud_datastorecluster_list.rb +60 -0
- data/lib/chef/knife/ovh_cloud_datastorecluster_maxfree.rb +48 -0
- data/lib/chef/knife/ovh_cloud_hosts_list.rb +49 -0
- data/lib/chef/knife/ovh_cloud_pool_list.rb +44 -0
- data/lib/chef/knife/ovh_cloud_pool_query.rb +58 -0
- data/lib/chef/knife/ovh_cloud_template_list.rb +32 -0
- data/lib/chef/knife/ovh_cloud_vlan_list.rb +37 -0
- data/lib/chef/knife/ovh_cloud_vm_clone.rb +567 -0
- data/lib/chef/knife/ovh_cloud_vm_config.rb +46 -0
- data/lib/chef/knife/ovh_cloud_vm_delete.rb +66 -0
- data/lib/chef/knife/ovh_cloud_vm_execute.rb +66 -0
- data/lib/chef/knife/ovh_cloud_vm_list.rb +66 -0
- data/lib/chef/knife/ovh_cloud_vm_markastemplate.rb +54 -0
- data/lib/chef/knife/ovh_cloud_vm_migrate.rb +80 -0
- data/lib/chef/knife/ovh_cloud_vm_move.rb +47 -0
- data/lib/chef/knife/ovh_cloud_vm_net.rb +57 -0
- data/lib/chef/knife/ovh_cloud_vm_property_get.rb +46 -0
- data/lib/chef/knife/ovh_cloud_vm_property_set.rb +84 -0
- data/lib/chef/knife/ovh_cloud_vm_query.rb +48 -0
- data/lib/chef/knife/ovh_cloud_vm_snapshot.rb +129 -0
- data/lib/chef/knife/ovh_cloud_vm_state.rb +127 -0
- data/lib/chef/knife/ovh_cloud_vm_vmdk_add.rb +241 -0
- data/lib/knife-ovh-cloud/version.rb +4 -0
- metadata +112 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
# Author:: Brian Dupras (<bdupras@rallydev.com>)
|
2
|
+
# License:: Apache License, Version 2.0
|
3
|
+
|
4
|
+
require 'chef/knife'
|
5
|
+
require 'chef/knife/base_ovh_cloud_command'
|
6
|
+
require 'rbvmomi'
|
7
|
+
require 'netaddr'
|
8
|
+
|
9
|
+
class Chef::Knife::OvhCloudVmPropertyGet < Chef::Knife::BaseOvhCloudCommand
|
10
|
+
banner "knife ovh cloud vm property get VMNAME PROPERTY. Gets a vApp Property on VMNAME."
|
11
|
+
|
12
|
+
get_common_options
|
13
|
+
|
14
|
+
def run
|
15
|
+
$stdout.sync = true
|
16
|
+
vmname = @name_args[0]
|
17
|
+
if vmname.nil?
|
18
|
+
show_usage
|
19
|
+
fatal_exit("You must specify a virtual machine name")
|
20
|
+
end
|
21
|
+
|
22
|
+
property_name = @name_args[1]
|
23
|
+
if property_name.nil?
|
24
|
+
show_usage
|
25
|
+
fatal_exit("You must specify a PROPERTY name (e.g. annotation)")
|
26
|
+
end
|
27
|
+
property_name = property_name.to_sym
|
28
|
+
|
29
|
+
vim = get_vim_connection
|
30
|
+
|
31
|
+
dc = get_datacenter
|
32
|
+
folder = find_folder(get_config(:folder)) || dc.vmFolder
|
33
|
+
|
34
|
+
vm = find_in_folder(folder, RbVmomi::VIM::VirtualMachine, vmname) or
|
35
|
+
abort "VM #{vmname} not found"
|
36
|
+
|
37
|
+
existing_property = vm.config.vAppConfig.property.find { |p| p.props[:id] == property_name.to_s }
|
38
|
+
|
39
|
+
if existing_property
|
40
|
+
puts existing_property.props[:value]
|
41
|
+
else
|
42
|
+
fatal_exit("PROPERTY [#{property_name.to_s}] not found")
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# Author:: Brian Dupras (<bdupras@rallydev.com>)
|
2
|
+
# License:: Apache License, Version 2.0
|
3
|
+
|
4
|
+
require 'chef/knife'
|
5
|
+
require 'chef/knife/base_ovh_cloud_command'
|
6
|
+
require 'rbvmomi'
|
7
|
+
require 'netaddr'
|
8
|
+
|
9
|
+
class Chef::Knife::OvhCloudVmPropertySet < Chef::Knife::BaseOvhCloudCommand
|
10
|
+
banner "knife ovh cloud vm property set VMNAME PROPERTY VALUE. Sets a vApp Property on VMNAME."
|
11
|
+
|
12
|
+
get_common_options
|
13
|
+
|
14
|
+
option :ovf_environment_transport,
|
15
|
+
:long => "--ovf-environment-transport STRING",
|
16
|
+
:description => "Comma delimited string. Configures the transports to use for properties. Supported values are: iso and com.vmware.guestInfo."
|
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 = @name_args[1]
|
27
|
+
if property_name.nil?
|
28
|
+
show_usage
|
29
|
+
fatal_exit("You must specify a PROPERTY name (e.g. annotation)")
|
30
|
+
end
|
31
|
+
property_name = property_name.to_sym
|
32
|
+
|
33
|
+
property_value = @name_args[2]
|
34
|
+
if property_value.nil?
|
35
|
+
show_usage
|
36
|
+
fatal_exit("You must specify a PROPERTY value")
|
37
|
+
end
|
38
|
+
|
39
|
+
vim = get_vim_connection
|
40
|
+
|
41
|
+
dc = get_datacenter
|
42
|
+
folder = find_folder(get_config(:folder)) || dc.vmFolder
|
43
|
+
|
44
|
+
vm = find_in_folder(folder, RbVmomi::VIM::VirtualMachine, vmname) or
|
45
|
+
abort "VM #{vmname} not found"
|
46
|
+
|
47
|
+
if vm.config.vAppConfig && vm.config.vAppConfig.property
|
48
|
+
existing_property = vm.config.vAppConfig.property.find { |p| p.props[:id] == property_name.to_s }
|
49
|
+
end
|
50
|
+
|
51
|
+
if existing_property
|
52
|
+
operation = 'edit'
|
53
|
+
property_key = existing_property.props[:key]
|
54
|
+
else
|
55
|
+
operation = 'add'
|
56
|
+
property_key = property_name.object_id
|
57
|
+
end
|
58
|
+
|
59
|
+
vm_config_spec = RbVmomi::VIM.VirtualMachineConfigSpec(
|
60
|
+
:vAppConfig => RbVmomi::VIM.VmConfigSpec(
|
61
|
+
:property => [
|
62
|
+
RbVmomi::VIM.VAppPropertySpec(
|
63
|
+
:operation => operation,
|
64
|
+
:info => {
|
65
|
+
:key => property_key,
|
66
|
+
:id => property_name.to_s,
|
67
|
+
:type => 'string',
|
68
|
+
:userConfigurable => true,
|
69
|
+
:value => property_value
|
70
|
+
}
|
71
|
+
)
|
72
|
+
]
|
73
|
+
)
|
74
|
+
)
|
75
|
+
|
76
|
+
unless config[:ovf_environment_transport].nil?
|
77
|
+
transport = config[:ovf_environment_transport].split(",")
|
78
|
+
transport = [""] if transport == [] ## because "".split returns [] and vmware wants [""]
|
79
|
+
vm_config_spec[:vAppConfig][:ovfEnvironmentTransport] = transport
|
80
|
+
end
|
81
|
+
|
82
|
+
vm.ReconfigVM_Task( :spec => vm_config_spec ).wait_for_completion
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Author:: Brian Dupras (<bdupras@rallydev.com>)
|
2
|
+
# License:: Apache License, Version 2.0
|
3
|
+
|
4
|
+
require 'chef/knife'
|
5
|
+
require 'chef/knife/base_ovh_cloud_command'
|
6
|
+
require 'rbvmomi'
|
7
|
+
require 'netaddr'
|
8
|
+
|
9
|
+
class Chef::Knife::OvhCloudVmQuery < Chef::Knife::BaseOvhCloudCommand
|
10
|
+
banner "knife ovh cloud query VMNAME QUERY. See \"http://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.VirtualMachine.html\" for allowed QUERY values."
|
11
|
+
|
12
|
+
get_common_options
|
13
|
+
|
14
|
+
def run
|
15
|
+
$stdout.sync = true
|
16
|
+
vmname = @name_args[0]
|
17
|
+
if vmname.nil?
|
18
|
+
show_usage
|
19
|
+
fatal_exit("You must specify a virtual machine name")
|
20
|
+
end
|
21
|
+
|
22
|
+
query_string = @name_args[1]
|
23
|
+
if query_string.nil?
|
24
|
+
show_usage
|
25
|
+
fatal_exit("You must specify a QUERY value (e.g. guest.ipAddress or network[0].name)")
|
26
|
+
end
|
27
|
+
|
28
|
+
vim = get_vim_connection
|
29
|
+
|
30
|
+
dc = get_datacenter
|
31
|
+
folder = find_folder(get_config(:folder)) || dc.vmFolder
|
32
|
+
|
33
|
+
vm = traverse_folders_for_vm(folder, vmname) or abort "VM #{vmname} not found"
|
34
|
+
|
35
|
+
# split QUERY by dots, and walk the object model
|
36
|
+
query = query_string.split '.'
|
37
|
+
result = vm
|
38
|
+
query.each do |part|
|
39
|
+
message, index = part.split(/[\[\]]/)
|
40
|
+
unless result.respond_to? message.to_sym
|
41
|
+
fatal_exit("\"#{query_string}\" not recognized.")
|
42
|
+
end
|
43
|
+
|
44
|
+
result = index ? result.send(message)[index.to_i] : result.send(message)
|
45
|
+
end
|
46
|
+
puts result
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
#
|
2
|
+
# License:: Apache License, Version 2.0
|
3
|
+
#
|
4
|
+
|
5
|
+
require 'chef/knife'
|
6
|
+
require 'chef/knife/base_ovh_cloud_command'
|
7
|
+
require 'rbvmomi'
|
8
|
+
require 'netaddr'
|
9
|
+
|
10
|
+
|
11
|
+
# Manage snapshots of a virtual machine
|
12
|
+
class Chef::Knife::OvhCloudVmSnapshot < Chef::Knife::BaseOvhCloudCommand
|
13
|
+
|
14
|
+
banner "knife ovh cloud vm snapshot VMNAME (options)"
|
15
|
+
|
16
|
+
get_common_options
|
17
|
+
|
18
|
+
option :list,
|
19
|
+
:long => "--list",
|
20
|
+
:description => "The current tree of snapshots"
|
21
|
+
|
22
|
+
option :create_new_snapshot,
|
23
|
+
:long => "--create SNAPSHOT",
|
24
|
+
:description => "Create a new snapshot off of the current snapshot."
|
25
|
+
|
26
|
+
option :remove_named_snapshot,
|
27
|
+
:long => "--remove SNAPSHOT",
|
28
|
+
:description => "Remove a named snapshot."
|
29
|
+
|
30
|
+
option :revert_snapshot,
|
31
|
+
:long => "--revert SNAPSHOT",
|
32
|
+
:description => "Revert to a named snapshot."
|
33
|
+
|
34
|
+
option :revert_current_snapshot,
|
35
|
+
:long => "--revert-current",
|
36
|
+
:description => "Revert to current snapshot.",
|
37
|
+
:boolean => false
|
38
|
+
|
39
|
+
option :power,
|
40
|
+
:long => "--start",
|
41
|
+
:description => "Indicates whether to start the VM after a successful revert",
|
42
|
+
:boolean => false
|
43
|
+
|
44
|
+
def run
|
45
|
+
|
46
|
+
$stdout.sync = true
|
47
|
+
|
48
|
+
vmname = @name_args[0]
|
49
|
+
if vmname.nil?
|
50
|
+
show_usage
|
51
|
+
ui.fatal("You must specify a virtual machine name")
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
|
55
|
+
vim = get_vim_connection
|
56
|
+
|
57
|
+
baseFolder = find_folder(get_config(:folder));
|
58
|
+
|
59
|
+
vm = find_in_folder(baseFolder, RbVmomi::VIM::VirtualMachine, vmname) or
|
60
|
+
abort "VM #{vmname} not found"
|
61
|
+
|
62
|
+
if vm.snapshot
|
63
|
+
snapshot_list = vm.snapshot.rootSnapshotList
|
64
|
+
current_snapshot = vm.snapshot.currentSnapshot
|
65
|
+
end
|
66
|
+
|
67
|
+
if config[:list] && vm.snapshot
|
68
|
+
puts "Current snapshot tree: "
|
69
|
+
puts "#{vmname}"
|
70
|
+
snapshot_list.each { |i| puts display_node(i, current_snapshot) }
|
71
|
+
end
|
72
|
+
|
73
|
+
if config[:create_new_snapshot]
|
74
|
+
vm.CreateSnapshot_Task(:name => config[:create_new_snapshot], :description => "", :memory => false, :quiesce => false)
|
75
|
+
end
|
76
|
+
|
77
|
+
if config[:remove_named_snapshot]
|
78
|
+
ss_name = config[:remove_named_snapshot]
|
79
|
+
snapshot = find_node(snapshot_list, ss_name)
|
80
|
+
puts "Found snapshot #{ss_name} removing."
|
81
|
+
snapshot.RemoveSnapshot_Task(:removeChildren => false)
|
82
|
+
end
|
83
|
+
|
84
|
+
if config[:revert_current_snapshot]
|
85
|
+
puts "Reverting to Current Snapshot"
|
86
|
+
vm.RevertToCurrentSnapshot_Task(:suppressPowerOn => false).wait_for_completion
|
87
|
+
if get_config(:power)
|
88
|
+
vm.PowerOnVM_Task.wait_for_completion
|
89
|
+
puts "Powered on virtual machine #{vmname}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
if config[:revert_snapshot]
|
94
|
+
ss_name = config[:revert_snapshot]
|
95
|
+
snapshot = find_node(snapshot_list, ss_name)
|
96
|
+
snapshot.RevertToSnapshot_Task(:suppressPowerOn => false).wait_for_completion
|
97
|
+
if get_config(:power)
|
98
|
+
vm.PowerOnVM_Task.wait_for_completion
|
99
|
+
puts "Powered on virtual machine #{vmname}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def find_node(tree, name)
|
105
|
+
snapshot = nil
|
106
|
+
tree.each do |node|
|
107
|
+
if node.name == name
|
108
|
+
snapshot = node.snapshot
|
109
|
+
elsif !node.childSnapshotList.empty?
|
110
|
+
snapshot = find_node(node.childSnapshotList, name)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
return snapshot
|
114
|
+
end
|
115
|
+
|
116
|
+
def display_node(node, current, shift=1)
|
117
|
+
out = ""
|
118
|
+
out << "+--"*shift
|
119
|
+
if node.snapshot == current
|
120
|
+
out << "#{ui.color(node.name, :cyan)}" << "\n"
|
121
|
+
else
|
122
|
+
out << "#{node.name}" << "\n"
|
123
|
+
end
|
124
|
+
if !node.childSnapshotList.empty?
|
125
|
+
node.childSnapshotList.each { |item| out << display_node(item, current, shift+1) }
|
126
|
+
end
|
127
|
+
out
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,127 @@
|
|
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_ovh_cloud_command'
|
8
|
+
require 'rbvmomi'
|
9
|
+
require 'netaddr'
|
10
|
+
|
11
|
+
PsOn = 'poweredOn'
|
12
|
+
PsOff = 'poweredOff'
|
13
|
+
PsSuspended = 'suspended'
|
14
|
+
|
15
|
+
PowerStates = {
|
16
|
+
PsOn => 'powered on',
|
17
|
+
PsOff => 'powered off',
|
18
|
+
PsSuspended => 'suspended'
|
19
|
+
}
|
20
|
+
|
21
|
+
# Manage power state of a virtual machine
|
22
|
+
class Chef::Knife::OvhCloudVmState < Chef::Knife::BaseOvhCloudCommand
|
23
|
+
|
24
|
+
banner "knife ovh cloud vm state VMNAME (options)"
|
25
|
+
|
26
|
+
get_common_options
|
27
|
+
|
28
|
+
option :state,
|
29
|
+
:short => "-s STATE",
|
30
|
+
:long => "--state STATE",
|
31
|
+
:description => "The power state to transition the VM into; one of on|off|suspended"
|
32
|
+
|
33
|
+
option :wait_port,
|
34
|
+
:short => "-w PORT",
|
35
|
+
:long => "--wait-port PORT",
|
36
|
+
:description => "Wait for VM to be accessible on a port"
|
37
|
+
|
38
|
+
option :shutdown,
|
39
|
+
:short => "-g",
|
40
|
+
:long => "--shutdown",
|
41
|
+
:description => "Guest OS shutdown"
|
42
|
+
|
43
|
+
option :recursive,
|
44
|
+
:short => "-r",
|
45
|
+
:long => "--recursive",
|
46
|
+
:description => "Search all folders"
|
47
|
+
|
48
|
+
def run
|
49
|
+
|
50
|
+
$stdout.sync = true
|
51
|
+
|
52
|
+
vmname = @name_args[0]
|
53
|
+
if vmname.nil?
|
54
|
+
show_usage
|
55
|
+
ui.fatal("You must specify a virtual machine name")
|
56
|
+
exit 1
|
57
|
+
end
|
58
|
+
|
59
|
+
vim = get_vim_connection
|
60
|
+
|
61
|
+
if get_config(:recursive)
|
62
|
+
vms = get_vms(vmname)
|
63
|
+
if vms.length > 1
|
64
|
+
abort "More than one VM with name #{vmname} found:\n" + vms.map{ |vm| get_path_to_object(vm) }.join("\n")
|
65
|
+
end
|
66
|
+
if vms.length == 0
|
67
|
+
abort "VM #{vmname} not found"
|
68
|
+
end
|
69
|
+
vm = vms[0]
|
70
|
+
else
|
71
|
+
baseFolder = find_folder(get_config(:folder));
|
72
|
+
|
73
|
+
vm = find_in_folder(baseFolder, RbVmomi::VIM::VirtualMachine, vmname) or
|
74
|
+
abort "VM #{vmname} not found"
|
75
|
+
end
|
76
|
+
|
77
|
+
state = vm.runtime.powerState
|
78
|
+
|
79
|
+
if config[:state].nil?
|
80
|
+
puts "VM #{vmname} is currently " + PowerStates[vm.runtime.powerState]
|
81
|
+
else
|
82
|
+
|
83
|
+
case config[:state]
|
84
|
+
when 'on'
|
85
|
+
if state == PsOn
|
86
|
+
puts "Virtual machine #{vmname} was already powered on"
|
87
|
+
else
|
88
|
+
vm.PowerOnVM_Task.wait_for_completion
|
89
|
+
puts "Powered on virtual machine #{vmname}"
|
90
|
+
end
|
91
|
+
when 'off'
|
92
|
+
if state == PsOff
|
93
|
+
puts "Virtual machine #{vmname} was already powered off"
|
94
|
+
else
|
95
|
+
if get_config(:shutdown)
|
96
|
+
vm.ShutdownGuest
|
97
|
+
print "Waiting for virtual machine #{vmname} to shut down..."
|
98
|
+
until vm.runtime.powerState == PsOff do
|
99
|
+
sleep 2
|
100
|
+
print "."
|
101
|
+
end
|
102
|
+
puts "done"
|
103
|
+
else
|
104
|
+
vm.PowerOffVM_Task.wait_for_completion
|
105
|
+
puts "Powered off virtual machine #{vmname}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
when 'suspend'
|
109
|
+
if state == PowerStates['suspended']
|
110
|
+
puts "Virtual machine #{vmname} was already suspended"
|
111
|
+
else
|
112
|
+
vm.SuspendVM_Task.wait_for_completion
|
113
|
+
puts "Suspended virtual machine #{vmname}"
|
114
|
+
end
|
115
|
+
when 'reset'
|
116
|
+
vm.ResetVM_Task.wait_for_completion
|
117
|
+
puts "Reset virtual machine #{vmname}"
|
118
|
+
end
|
119
|
+
|
120
|
+
if get_config(:wait_port)
|
121
|
+
print "Waiting for port #{get_config(:wait_port)}..."
|
122
|
+
print "." until tcp_test_port_vm(vm, get_config(:wait_port))
|
123
|
+
puts "done"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,241 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Brian Flad (<bflad417@gmail.com>)
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
require 'chef/knife'
|
6
|
+
require 'chef/knife/base_ovh_cloud_command'
|
7
|
+
|
8
|
+
# Lists all known virtual machines in the configured datacenter
|
9
|
+
class Chef::Knife::OvhCloudVmVmdkAdd < Chef::Knife::BaseOvhCloudCommand
|
10
|
+
|
11
|
+
banner "knife ovh cloud vm vmdk add"
|
12
|
+
|
13
|
+
get_common_options
|
14
|
+
|
15
|
+
option :vmdk_type,
|
16
|
+
:long => "--vmdk-type TYPE",
|
17
|
+
:description => "Type of VMDK"
|
18
|
+
# this is a bad idea as it will let you overcommit SAN by 400% or more. thick is a more "sane" default
|
19
|
+
$default[:vmdk_type] = "thin"
|
20
|
+
|
21
|
+
option :target_lun,
|
22
|
+
:long => "--target-lun NAME",
|
23
|
+
:description => "name of target LUN"
|
24
|
+
|
25
|
+
def run
|
26
|
+
$stdout.sync = true
|
27
|
+
|
28
|
+
vmname = @name_args[0]
|
29
|
+
if vmname.nil?
|
30
|
+
show_usage
|
31
|
+
ui.fatal("You must specify a virtual machine name")
|
32
|
+
exit 1
|
33
|
+
end
|
34
|
+
|
35
|
+
size = @name_args[1]
|
36
|
+
if size.nil?
|
37
|
+
ui.fatal "You need a VMDK size!"
|
38
|
+
show_usage
|
39
|
+
exit 1
|
40
|
+
end
|
41
|
+
|
42
|
+
vim = get_vim_connection
|
43
|
+
vdm = vim.serviceContent.virtualDiskManager
|
44
|
+
vm = get_vm(vmname)
|
45
|
+
if vm.nil?
|
46
|
+
puts "Could not find #{vmname}"
|
47
|
+
return
|
48
|
+
end
|
49
|
+
|
50
|
+
target_lun = get_config(:target_lun) unless get_config(:target_lun).nil?
|
51
|
+
vmdk_size_kb = size.to_i * 1024 * 1024
|
52
|
+
|
53
|
+
if target_lun.nil?
|
54
|
+
vmdk_datastore = choose_datastore(vm.datastore, size)
|
55
|
+
exit -1 if vmdk_datastore.nil?
|
56
|
+
else
|
57
|
+
vmdk_datastores = find_datastores_regex(target_lun)
|
58
|
+
vmdk_datastore = choose_datastore(vmdk_datastores, size)
|
59
|
+
exit -1 if vmdk_datastore.nil?
|
60
|
+
vmdk_dir = "[#{vmdk_datastore.name}] #{vmname}"
|
61
|
+
# create the vm folder on the LUN or subsequent operations will fail.
|
62
|
+
if not vmdk_datastore.exists? vmname
|
63
|
+
dc = get_datacenter
|
64
|
+
dc._connection.serviceContent.fileManager.MakeDirectory :name => vmdk_dir, :datacenter => dc, :createParentDirectories => false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
puts "Choosing: #{vmdk_datastore.name}"
|
69
|
+
|
70
|
+
# now we need to inspect the files in this datastore to get our next file name
|
71
|
+
next_vmdk = 1
|
72
|
+
pc = vmdk_datastore._connection.serviceContent.propertyCollector
|
73
|
+
vms = vmdk_datastore.vm
|
74
|
+
vmFiles = pc.collectMultiple vms, 'layoutEx.file'
|
75
|
+
vmFiles.keys.each do |vm|
|
76
|
+
vmFiles[vm]["layoutEx.file"].each do |layout|
|
77
|
+
if layout.name.match(/^\[#{vmdk_datastore.name}\] #{vmname}\/#{vmname}_([0-9]+).vmdk/)
|
78
|
+
num = $1
|
79
|
+
if next_vmdk <= num.to_i
|
80
|
+
next_vmdk = num.to_i + 1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
vmdk_fileName = "#{vmname}/#{vmname}_#{next_vmdk}.vmdk"
|
86
|
+
vmdk_name = "[#{vmdk_datastore.name}] #{vmdk_fileName}"
|
87
|
+
vmdk_type = get_config(:vmdk_type)
|
88
|
+
vmdk_type = "preallocated" if vmdk_type == "thick"
|
89
|
+
puts "Next vmdk name is => #{vmdk_name}"
|
90
|
+
|
91
|
+
# create the disk
|
92
|
+
if not vmdk_datastore.exists? vmdk_fileName
|
93
|
+
vmdk_spec = RbVmomi::VIM::FileBackedVirtualDiskSpec(
|
94
|
+
:adapterType => "lsiLogic",
|
95
|
+
:capacityKb => vmdk_size_kb,
|
96
|
+
:diskType => vmdk_type
|
97
|
+
)
|
98
|
+
ui.info "Creating VMDK"
|
99
|
+
ui.info "#{ui.color "Capacity:", :cyan} #{size} GB"
|
100
|
+
ui.info "#{ui.color "Disk:", :cyan} #{vmdk_name}"
|
101
|
+
|
102
|
+
if get_config(:noop)
|
103
|
+
ui.info "#{ui.color "Skipping disk creation process because --noop specified.", :red}"
|
104
|
+
else
|
105
|
+
vdm.CreateVirtualDisk_Task(
|
106
|
+
:datacenter => get_datacenter,
|
107
|
+
:name => vmdk_name,
|
108
|
+
:spec => vmdk_spec
|
109
|
+
).wait_for_completion
|
110
|
+
end
|
111
|
+
end
|
112
|
+
ui.info "Attaching VMDK to #{vmname}"
|
113
|
+
|
114
|
+
# now we run through the SCSI controllers to see if there's an available one
|
115
|
+
available_controllers = Array.new()
|
116
|
+
use_controller = nil
|
117
|
+
scsi_tree = Hash.new()
|
118
|
+
vm.config.hardware.device.each do |device|
|
119
|
+
if device.is_a? RbVmomi::VIM::VirtualSCSIController
|
120
|
+
if scsi_tree[device.controllerKey].nil?
|
121
|
+
scsi_tree[device.key]=Hash.new()
|
122
|
+
scsi_tree[device.key]['children'] = Array.new();
|
123
|
+
end
|
124
|
+
scsi_tree[device.key]['device'] = device;
|
125
|
+
end
|
126
|
+
if device.class == RbVmomi::VIM::VirtualDisk
|
127
|
+
if scsi_tree[device.controllerKey].nil?
|
128
|
+
scsi_tree[device.controllerKey]=Hash.new()
|
129
|
+
scsi_tree[device.controllerKey]['children'] = Array.new();
|
130
|
+
end
|
131
|
+
scsi_tree[device.controllerKey]['children'].push(device)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
scsi_tree.keys.sort.each do |controller|
|
135
|
+
if scsi_tree[controller]['children'].length < 15
|
136
|
+
available_controllers.push(scsi_tree[controller]['device'].deviceInfo.label)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
if available_controllers.length > 0
|
141
|
+
use_controller = available_controllers[0]
|
142
|
+
puts "using #{use_controller}"
|
143
|
+
else
|
144
|
+
|
145
|
+
if scsi_tree.keys.length < 4
|
146
|
+
|
147
|
+
# Add a controller if none are available
|
148
|
+
puts "no controllers available. Will attempt to create"
|
149
|
+
new_scsi_key = scsi_tree.keys.sort[scsi_tree.length - 1] + 1
|
150
|
+
new_scsi_busNumber = scsi_tree[scsi_tree.keys.sort[scsi_tree.length - 1]]['device'].busNumber + 1
|
151
|
+
|
152
|
+
controller_device = RbVmomi::VIM::VirtualLsiLogicController(
|
153
|
+
:key => new_scsi_key,
|
154
|
+
:busNumber => new_scsi_busNumber,
|
155
|
+
:sharedBus => :noSharing
|
156
|
+
)
|
157
|
+
|
158
|
+
device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec(
|
159
|
+
:device => controller_device,
|
160
|
+
:operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation("add")
|
161
|
+
)
|
162
|
+
|
163
|
+
vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec(
|
164
|
+
:deviceChange => [device_config_spec]
|
165
|
+
)
|
166
|
+
|
167
|
+
if get_config(:noop)
|
168
|
+
ui.info "#{ui.color "Skipping controller creation process because --noop specified.", :red}"
|
169
|
+
else
|
170
|
+
vm.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion
|
171
|
+
end
|
172
|
+
else
|
173
|
+
ui.info "Controllers maxed out at 4."
|
174
|
+
exit -1
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# now go back and get the new device's name
|
179
|
+
vm.config.hardware.device.each do |device|
|
180
|
+
if device.class == RbVmomi::VIM::VirtualLsiLogicController
|
181
|
+
if device.key == new_scsi_key
|
182
|
+
use_controller = device.deviceInfo.label
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# add the disk
|
188
|
+
controller = find_device(vm, use_controller)
|
189
|
+
|
190
|
+
used_unitNumbers = Array.new()
|
191
|
+
scsi_tree.keys.sort.each do |c|
|
192
|
+
if controller.key == scsi_tree[c]['device'].key
|
193
|
+
used_unitNumbers.push(scsi_tree[c]['device'].scsiCtlrUnitNumber)
|
194
|
+
scsi_tree[c]['children'].each do |disk|
|
195
|
+
used_unitNumbers.push(disk.unitNumber)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
available_unitNumbers = Array.new
|
201
|
+
(0 .. 15).each do |scsi_id|
|
202
|
+
if used_unitNumbers.grep(scsi_id).length > 0
|
203
|
+
else
|
204
|
+
available_unitNumbers.push(scsi_id)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# ensure we don't try to add the controllers SCSI ID
|
209
|
+
new_unitNumber = available_unitNumbers.sort[0]
|
210
|
+
puts "using SCSI ID #{new_unitNumber}"
|
211
|
+
|
212
|
+
vmdk_backing = RbVmomi::VIM::VirtualDiskFlatVer2BackingInfo(
|
213
|
+
:datastore => vmdk_datastore,
|
214
|
+
:diskMode => "persistent",
|
215
|
+
:fileName => vmdk_name
|
216
|
+
)
|
217
|
+
|
218
|
+
device = RbVmomi::VIM::VirtualDisk(
|
219
|
+
:backing => vmdk_backing,
|
220
|
+
:capacityInKB => vmdk_size_kb,
|
221
|
+
:controllerKey => controller.key,
|
222
|
+
:key => -1,
|
223
|
+
:unitNumber => new_unitNumber
|
224
|
+
)
|
225
|
+
|
226
|
+
device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec(
|
227
|
+
:device => device,
|
228
|
+
:operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation("add")
|
229
|
+
)
|
230
|
+
|
231
|
+
vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec(
|
232
|
+
:deviceChange => [device_config_spec]
|
233
|
+
)
|
234
|
+
|
235
|
+
if get_config(:noop)
|
236
|
+
ui.info "#{ui.color "Skipping disk attaching process because --noop specified.", :red}"
|
237
|
+
else
|
238
|
+
vm.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|