chef-provisioning-vsphere 0.8.3.dev.2 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -2
- data/Gemfile +5 -5
- data/LICENSE +19 -19
- data/LICENSE-Rally +20 -20
- data/README.md +269 -269
- data/Rakefile +22 -22
- data/chef-provisioning-vsphere.gemspec +28 -28
- data/contribution-notice +7 -7
- data/lib/chef/provisioning/driver_init/vsphere.rb +2 -2
- data/lib/chef/provisioning/vsphere_driver.rb +14 -14
- data/lib/chef/provisioning/vsphere_driver/clone_spec_builder.rb +205 -205
- data/lib/chef/provisioning/vsphere_driver/driver.rb +679 -679
- data/lib/chef/provisioning/vsphere_driver/version.rb +3 -3
- data/lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb +341 -341
- data/lib/chef/provisioning/vsphere_driver/vsphere_url.rb +45 -45
- data/lib/kitchen/driver/vsphere.rb +104 -104
- data/spec/integration_tests/.gitignore +1 -1
- data/spec/integration_tests/vsphere_driver_spec.rb +158 -158
- data/spec/unit_tests/VsphereDriver_spec.rb +132 -132
- data/spec/unit_tests/VsphereUrl_spec.rb +65 -65
- data/spec/unit_tests/clone_spec_builder_spec.rb +161 -161
- data/spec/unit_tests/support/fake_action_handler.rb +7 -7
- data/spec/unit_tests/support/vsphere_helper_stub.rb +52 -52
- metadata +4 -4
data/Rakefile
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
require 'bundler/gem_tasks'
|
2
|
-
require 'chef/provisioning/vsphere_driver/version'
|
3
|
-
require 'rspec/core/rake_task'
|
4
|
-
require "rubocop/rake_task"
|
5
|
-
|
6
|
-
$:.unshift(File.dirname(__FILE__) + '/lib')
|
7
|
-
|
8
|
-
RuboCop::RakeTask.new(:style) do |task|
|
9
|
-
task.options << "--display-cop-names"
|
10
|
-
end
|
11
|
-
|
12
|
-
RSpec::Core::RakeTask.new(:unit) do |task|
|
13
|
-
task.pattern = 'spec/unit_tests/*_spec.rb'
|
14
|
-
task.rspec_opts = ['--color', '-f documentation']
|
15
|
-
end
|
16
|
-
|
17
|
-
RSpec::Core::RakeTask.new(:integration) do |task|
|
18
|
-
task.pattern = 'spec/integration_tests/*_spec.rb'
|
19
|
-
task.rspec_opts = ['--color', '-f documentation']
|
20
|
-
end
|
21
|
-
|
22
|
-
task :default => [:unit]
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'chef/provisioning/vsphere_driver/version'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
require "rubocop/rake_task"
|
5
|
+
|
6
|
+
$:.unshift(File.dirname(__FILE__) + '/lib')
|
7
|
+
|
8
|
+
RuboCop::RakeTask.new(:style) do |task|
|
9
|
+
task.options << "--display-cop-names"
|
10
|
+
end
|
11
|
+
|
12
|
+
RSpec::Core::RakeTask.new(:unit) do |task|
|
13
|
+
task.pattern = 'spec/unit_tests/*_spec.rb'
|
14
|
+
task.rspec_opts = ['--color', '-f documentation']
|
15
|
+
end
|
16
|
+
|
17
|
+
RSpec::Core::RakeTask.new(:integration) do |task|
|
18
|
+
task.pattern = 'spec/integration_tests/*_spec.rb'
|
19
|
+
task.rspec_opts = ['--color', '-f documentation']
|
20
|
+
end
|
21
|
+
|
22
|
+
task :default => [:unit]
|
@@ -1,29 +1,29 @@
|
|
1
|
-
$:.unshift(File.dirname(__FILE__) + '/lib')
|
2
|
-
require 'chef/provisioning/vsphere_driver/version'
|
3
|
-
|
4
|
-
Gem::Specification.new do |s|
|
5
|
-
s.name = 'chef-provisioning-vsphere'
|
6
|
-
s.version = ChefProvisioningVsphere::VERSION
|
7
|
-
s.platform = Gem::Platform::RUBY
|
8
|
-
s.extra_rdoc_files = ['README.md']
|
9
|
-
s.summary = 'Provisioner for creating vSphere VM instances in Chef Provisioning.'
|
10
|
-
s.description = s.summary
|
11
|
-
s.authors = ['CenturyLink Cloud']
|
12
|
-
s.email = 'matt.wrock@CenturyLinkCloud.com'
|
13
|
-
s.homepage = 'https://github.com/tier3/chef-provisioning-vsphere'
|
14
|
-
s.license = 'MIT'
|
15
|
-
|
16
|
-
s.bindir = 'bin'
|
17
|
-
s.executables = %w( )
|
18
|
-
|
19
|
-
s.require_path = 'lib'
|
20
|
-
s.files = `git ls-files -z`.split("\x0")
|
21
|
-
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
22
|
-
|
23
|
-
s.add_dependency 'rbvmomi', '~> 1.8.0', '>= 1.8.2'
|
24
|
-
s.add_dependency 'chef-provisioning', '~>1.1'
|
25
|
-
|
26
|
-
s.add_development_dependency 'rspec'
|
27
|
-
s.add_development_dependency 'rake'
|
28
|
-
s.add_development_dependency 'rubocop', '~> 0.29'
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/lib')
|
2
|
+
require 'chef/provisioning/vsphere_driver/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'chef-provisioning-vsphere'
|
6
|
+
s.version = ChefProvisioningVsphere::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.extra_rdoc_files = ['README.md']
|
9
|
+
s.summary = 'Provisioner for creating vSphere VM instances in Chef Provisioning.'
|
10
|
+
s.description = s.summary
|
11
|
+
s.authors = ['CenturyLink Cloud']
|
12
|
+
s.email = 'matt.wrock@CenturyLinkCloud.com'
|
13
|
+
s.homepage = 'https://github.com/tier3/chef-provisioning-vsphere'
|
14
|
+
s.license = 'MIT'
|
15
|
+
|
16
|
+
s.bindir = 'bin'
|
17
|
+
s.executables = %w( )
|
18
|
+
|
19
|
+
s.require_path = 'lib'
|
20
|
+
s.files = `git ls-files -z`.split("\x0")
|
21
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
22
|
+
|
23
|
+
s.add_dependency 'rbvmomi', '~> 1.8.0', '>= 1.8.2'
|
24
|
+
s.add_dependency 'chef-provisioning', '~>1.1'
|
25
|
+
|
26
|
+
s.add_development_dependency 'rspec'
|
27
|
+
s.add_development_dependency 'rake'
|
28
|
+
s.add_development_dependency 'rubocop', '~> 0.29'
|
29
29
|
end
|
data/contribution-notice
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
Contribution Notice
|
2
|
-
|
3
|
-
By contributing to this Project, You grant to CenturyLink and to recipients of software distributed by CenturyLink, a perpetual worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute your contributions to this Project (“Your Contributions”), including derivative works thereof.
|
4
|
-
|
5
|
-
You grant to CenturyLink and to recipients of software distributed by CenturyLink a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section), patent license to make, have made, use, offer to sell, sell, import and otherwise transfer Your Contributions, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contributions(s) alone or by combination of Your Contribution(s) with this Project. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that Your Contribution, or this Project, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this agreement for Your Contribution or this Project shall terminate as of the date such litigation is filed.
|
6
|
-
|
7
|
-
You represent that each of Your Contributions is Your original creation and represent that You are legally entitled to grant the above license and that no other third party permission is required. If your employer(s) has rights to intellectual property that is included in Your Contributions, You represent that You have received permission to make such contributions on behalf of that employer.
|
1
|
+
Contribution Notice
|
2
|
+
|
3
|
+
By contributing to this Project, You grant to CenturyLink and to recipients of software distributed by CenturyLink, a perpetual worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute your contributions to this Project (“Your Contributions”), including derivative works thereof.
|
4
|
+
|
5
|
+
You grant to CenturyLink and to recipients of software distributed by CenturyLink a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section), patent license to make, have made, use, offer to sell, sell, import and otherwise transfer Your Contributions, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contributions(s) alone or by combination of Your Contribution(s) with this Project. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that Your Contribution, or this Project, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this agreement for Your Contribution or this Project shall terminate as of the date such litigation is filed.
|
6
|
+
|
7
|
+
You represent that each of Your Contributions is Your original creation and represent that You are legally entitled to grant the above license and that no other third party permission is required. If your employer(s) has rights to intellectual property that is included in Your Contributions, You represent that You have received permission to make such contributions on behalf of that employer.
|
@@ -1,3 +1,3 @@
|
|
1
|
-
require 'chef/provisioning/vsphere_driver'
|
2
|
-
|
1
|
+
require 'chef/provisioning/vsphere_driver'
|
2
|
+
|
3
3
|
Chef::Provisioning.register_driver_class('vsphere', ChefProvisioningVsphere::VsphereDriver)
|
@@ -1,14 +1,14 @@
|
|
1
|
-
require 'chef/provisioning'
|
2
|
-
require 'chef/provisioning/vsphere_driver/driver'
|
3
|
-
|
4
|
-
class Chef
|
5
|
-
module DSL
|
6
|
-
module Recipe
|
7
|
-
def with_vsphere_driver(driver_options, &block)
|
8
|
-
url = ChefProvisioningVsphere::VsphereDriver.canonicalize_url(
|
9
|
-
nil, driver_options)[0]
|
10
|
-
with_driver url, driver_options, &block
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
1
|
+
require 'chef/provisioning'
|
2
|
+
require 'chef/provisioning/vsphere_driver/driver'
|
3
|
+
|
4
|
+
class Chef
|
5
|
+
module DSL
|
6
|
+
module Recipe
|
7
|
+
def with_vsphere_driver(driver_options, &block)
|
8
|
+
url = ChefProvisioningVsphere::VsphereDriver.canonicalize_url(
|
9
|
+
nil, driver_options)[0]
|
10
|
+
with_driver url, driver_options, &block
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,205 +1,205 @@
|
|
1
|
-
module ChefProvisioningVsphere
|
2
|
-
class CloneSpecBuilder
|
3
|
-
def initialize(vsphere_helper, action_handler)
|
4
|
-
@vsphere_helper = vsphere_helper
|
5
|
-
@action_handler = action_handler
|
6
|
-
end
|
7
|
-
|
8
|
-
attr_reader :vsphere_helper
|
9
|
-
attr_reader :action_handler
|
10
|
-
|
11
|
-
def build(vm_template, vm_name, options)
|
12
|
-
clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(
|
13
|
-
location: relocate_spec_for(vm_template, options),
|
14
|
-
powerOn: false,
|
15
|
-
template: false,
|
16
|
-
config: RbVmomi::VIM.VirtualMachineConfigSpec(
|
17
|
-
:cpuHotAddEnabled => true,
|
18
|
-
:memoryHotAddEnabled => true,
|
19
|
-
:cpuHotRemoveEnabled => true,
|
20
|
-
:deviceChange => Array.new)
|
21
|
-
)
|
22
|
-
|
23
|
-
unless options[:annotation].to_s.nil?
|
24
|
-
clone_spec.config.annotation = options[:annotation]
|
25
|
-
end
|
26
|
-
|
27
|
-
unless options[:num_cpus].to_s.nil?
|
28
|
-
clone_spec.config.numCPUs = options[:num_cpus]
|
29
|
-
end
|
30
|
-
|
31
|
-
unless options[:memory_mb].to_s.nil?
|
32
|
-
clone_spec.config.memoryMB = options[:memory_mb]
|
33
|
-
end
|
34
|
-
|
35
|
-
unless options[:network_name].nil?
|
36
|
-
deviceAdditions, changes = vsphere_helper.network_device_changes(
|
37
|
-
action_handler,
|
38
|
-
vm_template,
|
39
|
-
options
|
40
|
-
)
|
41
|
-
clone_spec.config.deviceChange = changes
|
42
|
-
end
|
43
|
-
|
44
|
-
clone_spec.customization = customization_options_from(
|
45
|
-
vm_template,
|
46
|
-
vm_name,
|
47
|
-
options
|
48
|
-
)
|
49
|
-
|
50
|
-
clone_spec
|
51
|
-
end
|
52
|
-
|
53
|
-
def relocate_spec_for(vm_template, options)
|
54
|
-
rspec = RbVmomi::VIM.VirtualMachineRelocateSpec
|
55
|
-
host = nil
|
56
|
-
|
57
|
-
if options.has_key?(:host)
|
58
|
-
host = vsphere_helper.find_host(options[:host])
|
59
|
-
rspec.host = host
|
60
|
-
end
|
61
|
-
|
62
|
-
if options[:resource_pool]
|
63
|
-
rspec.pool = vsphere_helper.find_pool(options[:resource_pool])
|
64
|
-
elsif vm_template.config.template && !host.nil?
|
65
|
-
rspec.pool = host.parent.resourcePool # assign to the "invisible" pool root
|
66
|
-
elsif vm_template.config.template
|
67
|
-
raise 'either :host or :resource_pool must be specified when cloning from a VM Template'
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
if options[:use_linked_clone]
|
72
|
-
if vm_template.config.template
|
73
|
-
Chef::Log.warn("Using a VM Template, ignoring use_linked_clone.")
|
74
|
-
else
|
75
|
-
vsphere_helper.create_delta_disk(vm_template)
|
76
|
-
rspec.diskMoveType = :moveChildMostDiskBacking
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
unless options[:datastore].to_s.empty?
|
81
|
-
rspec.datastore = vsphere_helper.find_datastore(options[:datastore])
|
82
|
-
end
|
83
|
-
|
84
|
-
rspec
|
85
|
-
end
|
86
|
-
|
87
|
-
def customization_options_from(vm_template, vm_name, options)
|
88
|
-
if options.has_key?(:customization_spec)
|
89
|
-
if options[:customization_spec].is_a?(Hash) ||
|
90
|
-
options[:customization_spec].is_a?(Cheffish::MergedConfig)
|
91
|
-
cust_options = options[:customization_spec]
|
92
|
-
ip_settings = cust_options[:ipsettings]
|
93
|
-
cust_domain = cust_options[:domain]
|
94
|
-
|
95
|
-
raise ArgumentError, 'domain is required' unless cust_domain
|
96
|
-
cust_ip_settings = nil
|
97
|
-
if ip_settings && ip_settings.key?(:ip)
|
98
|
-
unless cust_options[:ipsettings].key?(:subnetMask)
|
99
|
-
raise ArgumentError, 'subnetMask is required for static ip'
|
100
|
-
end
|
101
|
-
cust_ip_settings = RbVmomi::VIM::CustomizationIPSettings.new(
|
102
|
-
ip_settings)
|
103
|
-
action_handler.report_progress "customizing #{vm_name} \
|
104
|
-
with static IP #{ip_settings[:ip]}"
|
105
|
-
cust_ip_settings.ip = RbVmomi::VIM::CustomizationFixedIp(
|
106
|
-
:ipAddress => ip_settings[:ip])
|
107
|
-
end
|
108
|
-
if cust_ip_settings.nil?
|
109
|
-
cust_ip_settings= RbVmomi::VIM::CustomizationIPSettings.new(
|
110
|
-
:ip => RbVmomi::VIM::CustomizationDhcpIpGenerator.new())
|
111
|
-
end
|
112
|
-
|
113
|
-
if ip_settings && ip_settings.key?(:dnsServerList)
|
114
|
-
cust_ip_settings.dnsServerList = ip_settings[:dnsServerList]
|
115
|
-
action_handler.report_progress "customizing #{vm_name} with /
|
116
|
-
dynamic IP and DNS: #{ip_settings[:dnsServerList]}"
|
117
|
-
end
|
118
|
-
|
119
|
-
cust_ip_settings.dnsDomain = cust_domain
|
120
|
-
global_ip_settings = RbVmomi::VIM::CustomizationGlobalIPSettings.new
|
121
|
-
global_ip_settings.dnsServerList = cust_ip_settings.dnsServerList
|
122
|
-
global_ip_settings.dnsSuffixList = [cust_domain]
|
123
|
-
cust_hostname = hostname_from(cust_options, vm_name)
|
124
|
-
cust_hwclockutc = cust_options[:hw_clock_utc]
|
125
|
-
cust_timezone = cust_options[:time_zone]
|
126
|
-
|
127
|
-
if vm_template.config.guestId.start_with?('win')
|
128
|
-
cust_prep = windows_prep_for(options, vm_name)
|
129
|
-
else
|
130
|
-
cust_prep = RbVmomi::VIM::CustomizationLinuxPrep.new(
|
131
|
-
:domain => cust_domain,
|
132
|
-
:hostName => cust_hostname,
|
133
|
-
:hwClockUTC => cust_hwclockutc,
|
134
|
-
:timeZone => cust_timezone
|
135
|
-
)
|
136
|
-
end
|
137
|
-
cust_adapter_mapping = [
|
138
|
-
RbVmomi::VIM::CustomizationAdapterMapping.new(
|
139
|
-
:adapter => cust_ip_settings)
|
140
|
-
]
|
141
|
-
RbVmomi::VIM::CustomizationSpec.new(
|
142
|
-
:identity => cust_prep,
|
143
|
-
:globalIPSettings => global_ip_settings,
|
144
|
-
:nicSettingMap => cust_adapter_mapping
|
145
|
-
)
|
146
|
-
else
|
147
|
-
vsphere_helper.find_customization_spec(cust_options)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def hostname_from(options, vm_name)
|
153
|
-
hostname = options[:hostname] || vm_name
|
154
|
-
test = /^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])$/
|
155
|
-
if !(hostname =~ test)
|
156
|
-
raise 'Only letters, numbers or hyphens in hostnames allowed'
|
157
|
-
end
|
158
|
-
RbVmomi::VIM::CustomizationFixedName.new(:name => hostname)
|
159
|
-
end
|
160
|
-
|
161
|
-
def windows_prep_for(options, vm_name)
|
162
|
-
cust_options = options[:customization_spec]
|
163
|
-
cust_runonce = RbVmomi::VIM::CustomizationGuiRunOnce.new(
|
164
|
-
:commandList => [
|
165
|
-
'winrm set winrm/config/client/auth @{Basic="true"}',
|
166
|
-
'winrm set winrm/config/service/auth @{Basic="true"}',
|
167
|
-
'winrm set winrm/config/service @{AllowUnencrypted="true"}',
|
168
|
-
'shutdown -l'])
|
169
|
-
|
170
|
-
cust_login_password = RbVmomi::VIM::CustomizationPassword(
|
171
|
-
:plainText => true,
|
172
|
-
:value => options[:ssh][:password])
|
173
|
-
if cust_options.has_key?(:domain) and cust_options[:domain] != 'local'
|
174
|
-
cust_domain_password = RbVmomi::VIM::CustomizationPassword(
|
175
|
-
:plainText => true,
|
176
|
-
:value => ENV['domainAdminPassword'] || cust_options[:domainAdminPassword])
|
177
|
-
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
178
|
-
:joinDomain => cust_options[:domain],
|
179
|
-
:domainAdmin => cust_options[:domainAdmin],
|
180
|
-
:domainAdminPassword => cust_domain_password)
|
181
|
-
#puts "my env passwd is: #{ENV['domainAdminPassword']}"
|
182
|
-
action_handler.report_progress "joining domain #{cust_options[:domain]} /
|
183
|
-
with user: #{cust_options[:domainAdmin]}"
|
184
|
-
else
|
185
|
-
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
186
|
-
:joinWorkgroup => 'WORKGROUP')
|
187
|
-
end
|
188
|
-
cust_gui_unattended = RbVmomi::VIM::CustomizationGuiUnattended.new(
|
189
|
-
:autoLogon => true,
|
190
|
-
:autoLogonCount => 1,
|
191
|
-
:password => cust_login_password,
|
192
|
-
:timeZone => cust_options[:win_time_zone])
|
193
|
-
cust_userdata = RbVmomi::VIM::CustomizationUserData.new(
|
194
|
-
:computerName => hostname_from(cust_options, vm_name),
|
195
|
-
:fullName => cust_options[:org_name],
|
196
|
-
:orgName => cust_options[:org_name],
|
197
|
-
:productId => cust_options[:product_id])
|
198
|
-
RbVmomi::VIM::CustomizationSysprep.new(
|
199
|
-
:guiRunOnce => cust_runonce,
|
200
|
-
:identification => cust_id,
|
201
|
-
:guiUnattended => cust_gui_unattended,
|
202
|
-
:userData => cust_userdata)
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
1
|
+
module ChefProvisioningVsphere
|
2
|
+
class CloneSpecBuilder
|
3
|
+
def initialize(vsphere_helper, action_handler)
|
4
|
+
@vsphere_helper = vsphere_helper
|
5
|
+
@action_handler = action_handler
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :vsphere_helper
|
9
|
+
attr_reader :action_handler
|
10
|
+
|
11
|
+
def build(vm_template, vm_name, options)
|
12
|
+
clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(
|
13
|
+
location: relocate_spec_for(vm_template, options),
|
14
|
+
powerOn: false,
|
15
|
+
template: false,
|
16
|
+
config: RbVmomi::VIM.VirtualMachineConfigSpec(
|
17
|
+
:cpuHotAddEnabled => true,
|
18
|
+
:memoryHotAddEnabled => true,
|
19
|
+
:cpuHotRemoveEnabled => true,
|
20
|
+
:deviceChange => Array.new)
|
21
|
+
)
|
22
|
+
|
23
|
+
unless options[:annotation].to_s.nil?
|
24
|
+
clone_spec.config.annotation = options[:annotation]
|
25
|
+
end
|
26
|
+
|
27
|
+
unless options[:num_cpus].to_s.nil?
|
28
|
+
clone_spec.config.numCPUs = options[:num_cpus]
|
29
|
+
end
|
30
|
+
|
31
|
+
unless options[:memory_mb].to_s.nil?
|
32
|
+
clone_spec.config.memoryMB = options[:memory_mb]
|
33
|
+
end
|
34
|
+
|
35
|
+
unless options[:network_name].nil?
|
36
|
+
deviceAdditions, changes = vsphere_helper.network_device_changes(
|
37
|
+
action_handler,
|
38
|
+
vm_template,
|
39
|
+
options
|
40
|
+
)
|
41
|
+
clone_spec.config.deviceChange = changes
|
42
|
+
end
|
43
|
+
|
44
|
+
clone_spec.customization = customization_options_from(
|
45
|
+
vm_template,
|
46
|
+
vm_name,
|
47
|
+
options
|
48
|
+
)
|
49
|
+
|
50
|
+
clone_spec
|
51
|
+
end
|
52
|
+
|
53
|
+
def relocate_spec_for(vm_template, options)
|
54
|
+
rspec = RbVmomi::VIM.VirtualMachineRelocateSpec
|
55
|
+
host = nil
|
56
|
+
|
57
|
+
if options.has_key?(:host)
|
58
|
+
host = vsphere_helper.find_host(options[:host])
|
59
|
+
rspec.host = host
|
60
|
+
end
|
61
|
+
|
62
|
+
if options[:resource_pool]
|
63
|
+
rspec.pool = vsphere_helper.find_pool(options[:resource_pool])
|
64
|
+
elsif vm_template.config.template && !host.nil?
|
65
|
+
rspec.pool = host.parent.resourcePool # assign to the "invisible" pool root
|
66
|
+
elsif vm_template.config.template
|
67
|
+
raise 'either :host or :resource_pool must be specified when cloning from a VM Template'
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
if options[:use_linked_clone]
|
72
|
+
if vm_template.config.template
|
73
|
+
Chef::Log.warn("Using a VM Template, ignoring use_linked_clone.")
|
74
|
+
else
|
75
|
+
vsphere_helper.create_delta_disk(vm_template)
|
76
|
+
rspec.diskMoveType = :moveChildMostDiskBacking
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
unless options[:datastore].to_s.empty?
|
81
|
+
rspec.datastore = vsphere_helper.find_datastore(options[:datastore])
|
82
|
+
end
|
83
|
+
|
84
|
+
rspec
|
85
|
+
end
|
86
|
+
|
87
|
+
def customization_options_from(vm_template, vm_name, options)
|
88
|
+
if options.has_key?(:customization_spec)
|
89
|
+
if options[:customization_spec].is_a?(Hash) ||
|
90
|
+
options[:customization_spec].is_a?(Cheffish::MergedConfig)
|
91
|
+
cust_options = options[:customization_spec]
|
92
|
+
ip_settings = cust_options[:ipsettings]
|
93
|
+
cust_domain = cust_options[:domain]
|
94
|
+
|
95
|
+
raise ArgumentError, 'domain is required' unless cust_domain
|
96
|
+
cust_ip_settings = nil
|
97
|
+
if ip_settings && ip_settings.key?(:ip)
|
98
|
+
unless cust_options[:ipsettings].key?(:subnetMask)
|
99
|
+
raise ArgumentError, 'subnetMask is required for static ip'
|
100
|
+
end
|
101
|
+
cust_ip_settings = RbVmomi::VIM::CustomizationIPSettings.new(
|
102
|
+
ip_settings)
|
103
|
+
action_handler.report_progress "customizing #{vm_name} \
|
104
|
+
with static IP #{ip_settings[:ip]}"
|
105
|
+
cust_ip_settings.ip = RbVmomi::VIM::CustomizationFixedIp(
|
106
|
+
:ipAddress => ip_settings[:ip])
|
107
|
+
end
|
108
|
+
if cust_ip_settings.nil?
|
109
|
+
cust_ip_settings= RbVmomi::VIM::CustomizationIPSettings.new(
|
110
|
+
:ip => RbVmomi::VIM::CustomizationDhcpIpGenerator.new())
|
111
|
+
end
|
112
|
+
|
113
|
+
if ip_settings && ip_settings.key?(:dnsServerList)
|
114
|
+
cust_ip_settings.dnsServerList = ip_settings[:dnsServerList]
|
115
|
+
action_handler.report_progress "customizing #{vm_name} with /
|
116
|
+
dynamic IP and DNS: #{ip_settings[:dnsServerList]}"
|
117
|
+
end
|
118
|
+
|
119
|
+
cust_ip_settings.dnsDomain = cust_domain
|
120
|
+
global_ip_settings = RbVmomi::VIM::CustomizationGlobalIPSettings.new
|
121
|
+
global_ip_settings.dnsServerList = cust_ip_settings.dnsServerList
|
122
|
+
global_ip_settings.dnsSuffixList = [cust_domain]
|
123
|
+
cust_hostname = hostname_from(cust_options, vm_name)
|
124
|
+
cust_hwclockutc = cust_options[:hw_clock_utc]
|
125
|
+
cust_timezone = cust_options[:time_zone]
|
126
|
+
|
127
|
+
if vm_template.config.guestId.start_with?('win')
|
128
|
+
cust_prep = windows_prep_for(options, vm_name)
|
129
|
+
else
|
130
|
+
cust_prep = RbVmomi::VIM::CustomizationLinuxPrep.new(
|
131
|
+
:domain => cust_domain,
|
132
|
+
:hostName => cust_hostname,
|
133
|
+
:hwClockUTC => cust_hwclockutc,
|
134
|
+
:timeZone => cust_timezone
|
135
|
+
)
|
136
|
+
end
|
137
|
+
cust_adapter_mapping = [
|
138
|
+
RbVmomi::VIM::CustomizationAdapterMapping.new(
|
139
|
+
:adapter => cust_ip_settings)
|
140
|
+
]
|
141
|
+
RbVmomi::VIM::CustomizationSpec.new(
|
142
|
+
:identity => cust_prep,
|
143
|
+
:globalIPSettings => global_ip_settings,
|
144
|
+
:nicSettingMap => cust_adapter_mapping
|
145
|
+
)
|
146
|
+
else
|
147
|
+
vsphere_helper.find_customization_spec(cust_options)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def hostname_from(options, vm_name)
|
153
|
+
hostname = options[:hostname] || vm_name
|
154
|
+
test = /^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])$/
|
155
|
+
if !(hostname =~ test)
|
156
|
+
raise 'Only letters, numbers or hyphens in hostnames allowed'
|
157
|
+
end
|
158
|
+
RbVmomi::VIM::CustomizationFixedName.new(:name => hostname)
|
159
|
+
end
|
160
|
+
|
161
|
+
def windows_prep_for(options, vm_name)
|
162
|
+
cust_options = options[:customization_spec]
|
163
|
+
cust_runonce = RbVmomi::VIM::CustomizationGuiRunOnce.new(
|
164
|
+
:commandList => [
|
165
|
+
'winrm set winrm/config/client/auth @{Basic="true"}',
|
166
|
+
'winrm set winrm/config/service/auth @{Basic="true"}',
|
167
|
+
'winrm set winrm/config/service @{AllowUnencrypted="true"}',
|
168
|
+
'shutdown -l'])
|
169
|
+
|
170
|
+
cust_login_password = RbVmomi::VIM::CustomizationPassword(
|
171
|
+
:plainText => true,
|
172
|
+
:value => options[:ssh][:password])
|
173
|
+
if cust_options.has_key?(:domain) and cust_options[:domain] != 'local'
|
174
|
+
cust_domain_password = RbVmomi::VIM::CustomizationPassword(
|
175
|
+
:plainText => true,
|
176
|
+
:value => ENV['domainAdminPassword'] || cust_options[:domainAdminPassword])
|
177
|
+
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
178
|
+
:joinDomain => cust_options[:domain],
|
179
|
+
:domainAdmin => cust_options[:domainAdmin],
|
180
|
+
:domainAdminPassword => cust_domain_password)
|
181
|
+
#puts "my env passwd is: #{ENV['domainAdminPassword']}"
|
182
|
+
action_handler.report_progress "joining domain #{cust_options[:domain]} /
|
183
|
+
with user: #{cust_options[:domainAdmin]}"
|
184
|
+
else
|
185
|
+
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
186
|
+
:joinWorkgroup => 'WORKGROUP')
|
187
|
+
end
|
188
|
+
cust_gui_unattended = RbVmomi::VIM::CustomizationGuiUnattended.new(
|
189
|
+
:autoLogon => true,
|
190
|
+
:autoLogonCount => 1,
|
191
|
+
:password => cust_login_password,
|
192
|
+
:timeZone => cust_options[:win_time_zone])
|
193
|
+
cust_userdata = RbVmomi::VIM::CustomizationUserData.new(
|
194
|
+
:computerName => hostname_from(cust_options, vm_name),
|
195
|
+
:fullName => cust_options[:org_name],
|
196
|
+
:orgName => cust_options[:org_name],
|
197
|
+
:productId => cust_options[:product_id])
|
198
|
+
RbVmomi::VIM::CustomizationSysprep.new(
|
199
|
+
:guiRunOnce => cust_runonce,
|
200
|
+
:identification => cust_id,
|
201
|
+
:guiUnattended => cust_gui_unattended,
|
202
|
+
:userData => cust_userdata)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|