chef-provisioning-vsphere 0.10.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +7 -3
- data/.rubocop.yml +8 -0
- data/.rubocop_todo.yml +143 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +111 -0
- data/Gemfile +2 -3
- data/LICENSE +19 -19
- data/LICENSE-Rally +20 -20
- data/README.md +29 -19
- data/Rakefile +34 -22
- data/chef-provisioning-vsphere.gemspec +9 -7
- data/contribution-notice +7 -7
- data/lib/chef/provisioning/driver_init/vsphere.rb +4 -3
- data/lib/chef/provisioning/vsphere_driver.rb +16 -14
- data/lib/chef/provisioning/vsphere_driver/clone_spec_builder.rb +68 -53
- data/lib/chef/provisioning/vsphere_driver/driver.rb +96 -70
- data/lib/chef/provisioning/vsphere_driver/version.rb +2 -1
- data/lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb +98 -99
- data/lib/chef/provisioning/vsphere_driver/vsphere_url.rb +46 -45
- data/lib/kitchen/driver/vsphere.rb +27 -27
- data/spec/integration_tests/.gitignore +1 -1
- data/spec/integration_tests/vsphere_driver_spec.rb +50 -51
- data/spec/unit_tests/VsphereDriver_spec.rb +133 -132
- data/spec/unit_tests/VsphereUrl_spec.rb +67 -66
- data/spec/unit_tests/clone_spec_builder_spec.rb +162 -161
- data/spec/unit_tests/support/fake_action_handler.rb +6 -7
- data/spec/unit_tests/support/vsphere_helper_stub.rb +51 -52
- metadata +29 -10
data/Rakefile
CHANGED
@@ -1,22 +1,34 @@
|
|
1
|
-
|
2
|
-
require '
|
3
|
-
require '
|
4
|
-
require
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
task.
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
task.
|
20
|
-
|
21
|
-
|
22
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'chef/provisioning/vsphere_driver/version'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/lib')
|
8
|
+
|
9
|
+
RuboCop::RakeTask.new(:style) do |task|
|
10
|
+
task.options << '--display-cop-names'
|
11
|
+
end
|
12
|
+
|
13
|
+
RSpec::Core::RakeTask.new(:unit) do |task|
|
14
|
+
task.pattern = 'spec/unit_tests/*_spec.rb'
|
15
|
+
task.rspec_opts = ['--color', '-f documentation']
|
16
|
+
end
|
17
|
+
|
18
|
+
RSpec::Core::RakeTask.new(:integration) do |task|
|
19
|
+
task.pattern = 'spec/integration_tests/*_spec.rb'
|
20
|
+
task.rspec_opts = ['--color', '-f documentation']
|
21
|
+
end
|
22
|
+
|
23
|
+
begin
|
24
|
+
require 'github_changelog_generator/task'
|
25
|
+
|
26
|
+
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
27
|
+
config.future_release = ChefProvisioningVsphere::VERSION
|
28
|
+
config.issues = true
|
29
|
+
end
|
30
|
+
rescue LoadError
|
31
|
+
puts 'github_changelog_generator is not available. gem install github_changelog_generator to generate changelogs'
|
32
|
+
end
|
33
|
+
|
34
|
+
task default: [:unit]
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/lib')
|
2
3
|
require 'chef/provisioning/vsphere_driver/version'
|
3
4
|
|
4
5
|
Gem::Specification.new do |s|
|
@@ -8,13 +9,13 @@ Gem::Specification.new do |s|
|
|
8
9
|
s.extra_rdoc_files = ['README.md']
|
9
10
|
s.summary = 'Provisioner for creating vSphere VM instances in Chef Provisioning.'
|
10
11
|
s.description = s.summary
|
11
|
-
s.authors = ['CenturyLink Cloud']
|
12
|
-
s.email = '
|
13
|
-
s.homepage = 'https://github.com/
|
12
|
+
s.authors = ['CenturyLink Cloud', 'JJ Asghar']
|
13
|
+
s.email = 'jj@chef.io'
|
14
|
+
s.homepage = 'https://github.com/chef-partners/chef-provisioning-vsphere'
|
14
15
|
s.license = 'MIT'
|
15
16
|
|
16
17
|
s.bindir = 'bin'
|
17
|
-
s.executables = %w(
|
18
|
+
s.executables = %w()
|
18
19
|
|
19
20
|
s.require_path = 'lib'
|
20
21
|
s.files = `git ls-files -z`.split("\x0")
|
@@ -22,8 +23,9 @@ Gem::Specification.new do |s|
|
|
22
23
|
|
23
24
|
s.add_dependency 'rbvmomi', '~> 1.8.0', '>= 1.8.2'
|
24
25
|
s.add_dependency 'chef-provisioning', '~>2.0', '>= 2.0.1'
|
26
|
+
s.add_dependency 'github_changelog_generator'
|
25
27
|
|
26
28
|
s.add_development_dependency 'rspec'
|
27
29
|
s.add_development_dependency 'rake'
|
28
|
-
s.add_development_dependency '
|
29
|
-
end
|
30
|
+
s.add_development_dependency 'chefstyle'
|
31
|
+
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,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'chef/provisioning/vsphere_driver'
|
3
|
+
|
4
|
+
Chef::Provisioning.register_driver_class('vsphere', ChefProvisioningVsphere::VsphereDriver)
|
@@ -1,14 +1,16 @@
|
|
1
|
-
|
2
|
-
require 'chef/provisioning
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'chef/provisioning'
|
3
|
+
require 'chef/provisioning/vsphere_driver/driver'
|
4
|
+
|
5
|
+
class Chef
|
6
|
+
module DSL
|
7
|
+
module Recipe
|
8
|
+
def with_vsphere_driver(driver_options, &block)
|
9
|
+
url = ChefProvisioningVsphere::VsphereDriver.canonicalize_url(
|
10
|
+
nil, driver_options
|
11
|
+
)[0]
|
12
|
+
with_driver url, driver_options, &block
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ChefProvisioningVsphere
|
2
3
|
class CloneSpecBuilder
|
3
4
|
def initialize(vsphere_helper, action_handler)
|
@@ -14,10 +15,11 @@ module ChefProvisioningVsphere
|
|
14
15
|
powerOn: false,
|
15
16
|
template: false,
|
16
17
|
config: RbVmomi::VIM.VirtualMachineConfigSpec(
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
20
|
-
:
|
18
|
+
cpuHotAddEnabled: true,
|
19
|
+
memoryHotAddEnabled: true,
|
20
|
+
cpuHotRemoveEnabled: true,
|
21
|
+
deviceChange: []
|
22
|
+
)
|
21
23
|
)
|
22
24
|
|
23
25
|
unless options[:annotation].to_s.nil?
|
@@ -54,7 +56,7 @@ module ChefProvisioningVsphere
|
|
54
56
|
rspec = RbVmomi::VIM.VirtualMachineRelocateSpec
|
55
57
|
host = nil
|
56
58
|
|
57
|
-
if options.
|
59
|
+
if options.key?(:host)
|
58
60
|
host = vsphere_helper.find_host(options[:host])
|
59
61
|
rspec.host = host
|
60
62
|
end
|
@@ -67,10 +69,9 @@ module ChefProvisioningVsphere
|
|
67
69
|
raise 'either :host or :resource_pool must be specified when cloning from a VM Template'
|
68
70
|
end
|
69
71
|
|
70
|
-
|
71
72
|
if options[:use_linked_clone]
|
72
73
|
if vm_template.config.template
|
73
|
-
Chef::Log.warn(
|
74
|
+
Chef::Log.warn('Using a VM Template, ignoring use_linked_clone.')
|
74
75
|
else
|
75
76
|
vsphere_helper.create_delta_disk(vm_template)
|
76
77
|
rspec.diskMoveType = :moveChildMostDiskBacking
|
@@ -85,9 +86,9 @@ module ChefProvisioningVsphere
|
|
85
86
|
end
|
86
87
|
|
87
88
|
def customization_options_from(vm_template, vm_name, options)
|
88
|
-
if options.
|
89
|
+
if options.key?(:customization_spec)
|
89
90
|
if options[:customization_spec].is_a?(Hash) ||
|
90
|
-
|
91
|
+
options[:customization_spec].is_a?(Cheffish::MergedConfig)
|
91
92
|
cust_options = options[:customization_spec]
|
92
93
|
ip_settings = cust_options[:ipsettings]
|
93
94
|
cust_domain = cust_options[:domain]
|
@@ -99,15 +100,18 @@ module ChefProvisioningVsphere
|
|
99
100
|
raise ArgumentError, 'subnetMask is required for static ip'
|
100
101
|
end
|
101
102
|
cust_ip_settings = RbVmomi::VIM::CustomizationIPSettings.new(
|
102
|
-
ip_settings
|
103
|
+
ip_settings
|
104
|
+
)
|
103
105
|
action_handler.report_progress "customizing #{vm_name} \
|
104
106
|
with static IP #{ip_settings[:ip]}"
|
105
107
|
cust_ip_settings.ip = RbVmomi::VIM::CustomizationFixedIp(
|
106
|
-
:
|
108
|
+
ipAddress: ip_settings[:ip]
|
109
|
+
)
|
107
110
|
end
|
108
111
|
if cust_ip_settings.nil?
|
109
|
-
cust_ip_settings= RbVmomi::VIM::CustomizationIPSettings.new(
|
110
|
-
:
|
112
|
+
cust_ip_settings = RbVmomi::VIM::CustomizationIPSettings.new(
|
113
|
+
ip: RbVmomi::VIM::CustomizationDhcpIpGenerator.new
|
114
|
+
)
|
111
115
|
end
|
112
116
|
|
113
117
|
if ip_settings && ip_settings.key?(:dnsServerList)
|
@@ -124,24 +128,25 @@ module ChefProvisioningVsphere
|
|
124
128
|
cust_hwclockutc = cust_options[:hw_clock_utc]
|
125
129
|
cust_timezone = cust_options[:time_zone]
|
126
130
|
|
127
|
-
if vm_template.config.guestId.start_with?('win')
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
131
|
+
cust_prep = if vm_template.config.guestId.start_with?('win')
|
132
|
+
windows_prep_for(options, vm_name)
|
133
|
+
else
|
134
|
+
RbVmomi::VIM::CustomizationLinuxPrep.new(
|
135
|
+
domain: cust_domain,
|
136
|
+
hostName: cust_hostname,
|
137
|
+
hwClockUTC: cust_hwclockutc,
|
138
|
+
timeZone: cust_timezone
|
139
|
+
)
|
140
|
+
end
|
137
141
|
cust_adapter_mapping = [
|
138
142
|
RbVmomi::VIM::CustomizationAdapterMapping.new(
|
139
|
-
:
|
143
|
+
adapter: cust_ip_settings
|
144
|
+
)
|
140
145
|
]
|
141
146
|
RbVmomi::VIM::CustomizationSpec.new(
|
142
|
-
:
|
143
|
-
:
|
144
|
-
:
|
147
|
+
identity: cust_prep,
|
148
|
+
globalIPSettings: global_ip_settings,
|
149
|
+
nicSettingMap: cust_adapter_mapping
|
145
150
|
)
|
146
151
|
else
|
147
152
|
vsphere_helper.find_customization_spec(options[:customization_spec])
|
@@ -152,50 +157,60 @@ module ChefProvisioningVsphere
|
|
152
157
|
def hostname_from(options, vm_name)
|
153
158
|
hostname = options[:hostname] || vm_name
|
154
159
|
test = /^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])$/
|
155
|
-
|
160
|
+
unless hostname =~ test
|
156
161
|
raise 'Only letters, numbers or hyphens in hostnames allowed'
|
157
162
|
end
|
158
|
-
RbVmomi::VIM::CustomizationFixedName.new(:
|
163
|
+
RbVmomi::VIM::CustomizationFixedName.new(name: hostname)
|
159
164
|
end
|
160
165
|
|
161
166
|
def windows_prep_for(options, vm_name)
|
162
167
|
cust_options = options[:customization_spec]
|
163
|
-
|
164
|
-
|
168
|
+
unless cust_options[:run_once].nil?
|
169
|
+
cust_runonce = RbVmomi::VIM::CustomizationGuiRunOnce.new(
|
170
|
+
commandList: cust_options[:run_once]
|
171
|
+
)
|
172
|
+
end
|
165
173
|
|
166
174
|
cust_login_password = RbVmomi::VIM::CustomizationPassword(
|
167
|
-
:
|
168
|
-
:
|
169
|
-
|
175
|
+
plainText: true,
|
176
|
+
value: options[:ssh][:password]
|
177
|
+
)
|
178
|
+
if cust_options.key?(:domain) && (cust_options[:domain] != 'local')
|
170
179
|
cust_domain_password = RbVmomi::VIM::CustomizationPassword(
|
171
|
-
:
|
172
|
-
:
|
180
|
+
plainText: true,
|
181
|
+
value: ENV['domainAdminPassword'] || cust_options[:domainAdminPassword]
|
182
|
+
)
|
173
183
|
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
174
|
-
:
|
175
|
-
:
|
176
|
-
:
|
177
|
-
|
184
|
+
joinDomain: cust_options[:domain],
|
185
|
+
domainAdmin: cust_options[:domainAdmin],
|
186
|
+
domainAdminPassword: cust_domain_password
|
187
|
+
)
|
188
|
+
# puts "my env passwd is: #{ENV['domainAdminPassword']}"
|
178
189
|
action_handler.report_progress "joining domain #{cust_options[:domain]} /
|
179
190
|
with user: #{cust_options[:domainAdmin]}"
|
180
191
|
else
|
181
192
|
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
182
|
-
:
|
193
|
+
joinWorkgroup: 'WORKGROUP'
|
194
|
+
)
|
183
195
|
end
|
184
196
|
cust_gui_unattended = RbVmomi::VIM::CustomizationGuiUnattended.new(
|
185
|
-
:
|
186
|
-
:
|
187
|
-
:
|
188
|
-
:
|
197
|
+
autoLogon: true,
|
198
|
+
autoLogonCount: 1,
|
199
|
+
password: cust_login_password,
|
200
|
+
timeZone: cust_options[:win_time_zone]
|
201
|
+
)
|
189
202
|
cust_userdata = RbVmomi::VIM::CustomizationUserData.new(
|
190
|
-
:
|
191
|
-
:
|
192
|
-
:
|
193
|
-
:
|
203
|
+
computerName: hostname_from(cust_options, vm_name),
|
204
|
+
fullName: cust_options[:org_name],
|
205
|
+
orgName: cust_options[:org_name],
|
206
|
+
productId: cust_options[:product_id]
|
207
|
+
)
|
194
208
|
RbVmomi::VIM::CustomizationSysprep.new(
|
195
|
-
:
|
196
|
-
:
|
197
|
-
:
|
198
|
-
:
|
209
|
+
guiRunOnce: cust_runonce,
|
210
|
+
identification: cust_id,
|
211
|
+
guiUnattended: cust_gui_unattended,
|
212
|
+
userData: cust_userdata
|
213
|
+
)
|
199
214
|
end
|
200
215
|
end
|
201
216
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'chef'
|
2
3
|
require 'cheffish/merged_config'
|
3
4
|
require 'chef/provisioning/driver'
|
@@ -30,7 +31,7 @@ module ChefProvisioningVsphere
|
|
30
31
|
# :password - required - password to use in connection to vSphere API server
|
31
32
|
def self.canonicalize_url(driver_url, config)
|
32
33
|
config = symbolize_keys(config)
|
33
|
-
[
|
34
|
+
[driver_url || URI::VsphereUrl.from_config(config).to_s, config]
|
34
35
|
end
|
35
36
|
|
36
37
|
def self.symbolize_keys(h)
|
@@ -42,6 +43,16 @@ module ChefProvisioningVsphere
|
|
42
43
|
] : h
|
43
44
|
end
|
44
45
|
|
46
|
+
def deep_symbolize(hash_like)
|
47
|
+
return {} if hash_like.nil? || hash_like.empty?
|
48
|
+
r = {}
|
49
|
+
hash_like.each do |key, value|
|
50
|
+
value = deep_symbolize(value) if value.respond_to?(:values)
|
51
|
+
r[key.to_sym] = value
|
52
|
+
end
|
53
|
+
r
|
54
|
+
end
|
55
|
+
|
45
56
|
def initialize(driver_url, config)
|
46
57
|
super(driver_url, config)
|
47
58
|
|
@@ -110,11 +121,13 @@ module ChefProvisioningVsphere
|
|
110
121
|
# -- vm_folder: name of the vSphere folder containing the VM
|
111
122
|
#
|
112
123
|
def allocate_machine(action_handler, machine_spec, machine_options)
|
124
|
+
machine_options = deep_symbolize(machine_options)
|
113
125
|
merge_options! machine_options
|
114
126
|
|
115
127
|
if machine_spec.location
|
116
128
|
Chef::Log.warn(
|
117
|
-
"Checking to see if #{machine_spec.location} has been created..."
|
129
|
+
"Checking to see if #{machine_spec.location} has been created..."
|
130
|
+
)
|
118
131
|
vm = vm_for(machine_spec)
|
119
132
|
if vm
|
120
133
|
Chef::Log.warn 'returning existing machine'
|
@@ -130,16 +143,17 @@ module ChefProvisioningVsphere
|
|
130
143
|
bootstrap_options = machine_options[:bootstrap_options]
|
131
144
|
|
132
145
|
action_handler.report_progress full_description(
|
133
|
-
machine_spec, bootstrap_options
|
146
|
+
machine_spec, bootstrap_options
|
147
|
+
)
|
134
148
|
|
135
149
|
vm = find_or_create_vm(bootstrap_options, machine_spec, action_handler)
|
136
150
|
|
137
151
|
add_machine_spec_location(vm, machine_spec)
|
138
152
|
|
139
153
|
action_handler.performed_action(machine_msg(
|
140
|
-
|
141
|
-
|
142
|
-
|
154
|
+
machine_spec.name,
|
155
|
+
vm.config.instanceUuid,
|
156
|
+
'created'
|
143
157
|
))
|
144
158
|
vm
|
145
159
|
end
|
@@ -149,6 +163,7 @@ module ChefProvisioningVsphere
|
|
149
163
|
{ machine_options: machine_options },
|
150
164
|
@config
|
151
165
|
)
|
166
|
+
@config = deep_symbolize(@config.to_h)
|
152
167
|
end
|
153
168
|
|
154
169
|
def add_machine_spec_location(vm, machine_spec)
|
@@ -183,25 +198,26 @@ module ChefProvisioningVsphere
|
|
183
198
|
vm
|
184
199
|
end
|
185
200
|
|
186
|
-
|
187
|
-
description = [
|
188
|
-
bootstrap_options.to_hash.each_pair do |key,value|
|
189
|
-
if value.is_a?(Hash)
|
201
|
+
def full_description(machine_spec, bootstrap_options)
|
202
|
+
description = ["creating machine #{machine_spec.name} on #{driver_url}"]
|
203
|
+
bootstrap_options.to_hash.each_pair do |key, value|
|
204
|
+
if value.is_a?(Hash)
|
190
205
|
temp_value = value.clone
|
191
|
-
temp_value[:password] =
|
206
|
+
temp_value[:password] = '*********' if value.key?(:password)
|
192
207
|
else
|
193
208
|
temp_value = value
|
194
209
|
end
|
195
210
|
description << " #{key}: #{temp_value.inspect}"
|
196
211
|
end
|
197
212
|
description
|
198
|
-
|
213
|
+
end
|
199
214
|
|
200
215
|
def machine_msg(name, id, action)
|
201
216
|
"Machine - #{action} - #{name} (#{id} on #{driver_url})"
|
202
217
|
end
|
203
218
|
|
204
219
|
def ready_machine(action_handler, machine_spec, machine_options)
|
220
|
+
machine_options = deep_symbolize(machine_options)
|
205
221
|
merge_options! machine_options
|
206
222
|
|
207
223
|
vm = start_machine(action_handler, machine_spec, machine_options)
|
@@ -219,7 +235,7 @@ module ChefProvisioningVsphere
|
|
219
235
|
machine_spec
|
220
236
|
)
|
221
237
|
|
222
|
-
machine = machine_for(machine_spec,machine_options)
|
238
|
+
machine = machine_for(machine_spec, machine_options)
|
223
239
|
|
224
240
|
setup_extra_nics(action_handler, bootstrap_options, vm, machine)
|
225
241
|
|
@@ -231,10 +247,8 @@ module ChefProvisioningVsphere
|
|
231
247
|
end
|
232
248
|
|
233
249
|
def setup_extra_nics(action_handler, bootstrap_options, vm, machine)
|
234
|
-
networks=bootstrap_options[:network_name]
|
235
|
-
if networks.
|
236
|
-
networks=[networks]
|
237
|
-
end
|
250
|
+
networks = bootstrap_options[:network_name]
|
251
|
+
networks = [networks] if networks.is_a?(String)
|
238
252
|
return if networks.nil? || networks.count < 2
|
239
253
|
|
240
254
|
new_nics = vsphere_helper.add_extra_nic(
|
@@ -247,7 +261,8 @@ module ChefProvisioningVsphere
|
|
247
261
|
new_nics.each do |nic|
|
248
262
|
nic_label = nic.device.deviceInfo.label
|
249
263
|
machine.execute_always(
|
250
|
-
"Disable-Netadapter -Name '#{nic_label}' -Confirm:$false"
|
264
|
+
"Disable-Netadapter -Name '#{nic_label}' -Confirm:$false"
|
265
|
+
)
|
251
266
|
end
|
252
267
|
end
|
253
268
|
end
|
@@ -281,7 +296,8 @@ module ChefProvisioningVsphere
|
|
281
296
|
end
|
282
297
|
machine_spec.location['ipaddress'] = vm.guest.ipAddress
|
283
298
|
action_handler.report_progress(
|
284
|
-
"IP address obtained: #{machine_spec.location['ipaddress']}"
|
299
|
+
"IP address obtained: #{machine_spec.location['ipaddress']}"
|
300
|
+
)
|
285
301
|
end
|
286
302
|
|
287
303
|
wait_for_domain(bootstrap_options, vm, machine_spec, action_handler)
|
@@ -292,13 +308,13 @@ module ChefProvisioningVsphere
|
|
292
308
|
# Only ever reboot once, and only if it's been less than 10 minutes
|
293
309
|
# since we stopped waiting
|
294
310
|
if machine_spec.location['started_at'] ||
|
295
|
-
|
311
|
+
remaining_wait_time(machine_spec, machine_options) < -(10 * 60)
|
296
312
|
raise
|
297
313
|
else
|
298
314
|
Chef::Log.warn(machine_msg(
|
299
|
-
|
300
|
-
|
301
|
-
|
315
|
+
machine_spec.name,
|
316
|
+
vm.config.instanceUuid,
|
317
|
+
'started but SSH did not come up. Rebooting...'
|
302
318
|
))
|
303
319
|
restart_server(action_handler, machine_spec, machine_options)
|
304
320
|
wait_until_ready(action_handler, machine_spec, machine_options, vm)
|
@@ -313,8 +329,8 @@ module ChefProvisioningVsphere
|
|
313
329
|
wait_for_ip(vm, machine_options, machine_spec, action_handler)
|
314
330
|
|
315
331
|
unless has_ip?(vm_ip, vm)
|
316
|
-
action_handler.report_progress
|
317
|
-
if vm.guest.toolsRunningStatus !=
|
332
|
+
action_handler.report_progress 'rebooting...'
|
333
|
+
if vm.guest.toolsRunningStatus != 'guestToolsRunning'
|
318
334
|
msg = 'tools have stopped. current power state is '
|
319
335
|
msg << vm.runtime.powerState
|
320
336
|
msg << ' and tools state is '
|
@@ -333,25 +349,26 @@ module ChefProvisioningVsphere
|
|
333
349
|
return unless bootstrap_options[:customization_spec]
|
334
350
|
|
335
351
|
domain = if bootstrap_options[:customization_spec].is_a?(String) && is_windows?(vm)
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
352
|
+
spec = vsphere_helper.find_customization_spec(bootstrap_options[:customization_spec])
|
353
|
+
spec.identity.identification.joinDomain
|
354
|
+
elsif bootstrap_options[:customization_spec].is_a?(String) && !is_windows?(vm)
|
355
|
+
spec = vsphere_helper.find_customization_spec(bootstrap_options[:customization_spec])
|
356
|
+
spec.identity.domain
|
357
|
+
else
|
358
|
+
bootstrap_options[:customization_spec][:domain]
|
343
359
|
end
|
344
360
|
|
345
361
|
return unless domain
|
346
362
|
|
347
363
|
if is_windows?(vm) && domain != 'local'
|
348
364
|
start = Time.now.utc
|
349
|
-
trimmed_name = machine_spec.name.byteslice(0,15)
|
350
|
-
expected_name="#{trimmed_name}.#{domain}"
|
365
|
+
trimmed_name = machine_spec.name.byteslice(0, 15)
|
366
|
+
expected_name = "#{trimmed_name}.#{domain}"
|
351
367
|
action_handler.report_progress(
|
352
|
-
"waiting to domain join and be named #{expected_name}"
|
368
|
+
"waiting to domain join and be named #{expected_name}"
|
369
|
+
)
|
353
370
|
until (Time.now.utc - start) > 30 ||
|
354
|
-
|
371
|
+
(vm.guest.hostName == expected_name)
|
355
372
|
print '.'
|
356
373
|
sleep 5
|
357
374
|
end
|
@@ -363,14 +380,15 @@ module ChefProvisioningVsphere
|
|
363
380
|
vm_ip = ip_to_bootstrap(bootstrap_options, vm)
|
364
381
|
ready_timeout = machine_options[:ready_timeout] || 300
|
365
382
|
msg = "waiting up to #{ready_timeout} seconds for customization"
|
366
|
-
msg << " and find #{vm_ip}" unless vm_ip ==
|
383
|
+
msg << " and find #{vm_ip}" unless vm_ip == vm.guest.ipAddress
|
367
384
|
action_handler.report_progress msg
|
368
385
|
|
369
386
|
start = Time.now.utc
|
370
387
|
connectable = false
|
371
|
-
until (Time.now.utc - start) > ready_timeout || connectable
|
388
|
+
until (Time.now.utc - start) > ready_timeout || connectable
|
372
389
|
action_handler.report_progress(
|
373
|
-
"IP addresses found: #{all_ips_for(vm)}"
|
390
|
+
"IP addresses found: #{all_ips_for(vm)}"
|
391
|
+
)
|
374
392
|
vm_ip ||= ip_to_bootstrap(bootstrap_options, vm)
|
375
393
|
if has_ip?(vm_ip, vm)
|
376
394
|
connectable = transport_for(
|
@@ -384,7 +402,7 @@ module ChefProvisioningVsphere
|
|
384
402
|
end
|
385
403
|
|
386
404
|
def all_ips_for(vm)
|
387
|
-
vm.guest.net.map
|
405
|
+
vm.guest.net.map(&:ipAddress).flatten
|
388
406
|
end
|
389
407
|
|
390
408
|
def has_ip?(ip, vm)
|
@@ -393,11 +411,13 @@ module ChefProvisioningVsphere
|
|
393
411
|
|
394
412
|
# Connect to machine without acquiring it
|
395
413
|
def connect_to_machine(machine_spec, machine_options)
|
414
|
+
machine_options = deep_symbolize(machine_options)
|
396
415
|
merge_options! machine_options
|
397
416
|
machine_for(machine_spec, machine_options)
|
398
417
|
end
|
399
418
|
|
400
419
|
def destroy_machine(action_handler, machine_spec, machine_options)
|
420
|
+
machine_options = deep_symbolize(machine_options)
|
401
421
|
merge_options! machine_options
|
402
422
|
vm = vm_for(machine_spec)
|
403
423
|
if vm
|
@@ -406,7 +426,7 @@ module ChefProvisioningVsphere
|
|
406
426
|
vsphere_helper.stop_vm(vm, machine_options[:stop_timeout])
|
407
427
|
vm.Destroy_Task.wait_for_completion
|
408
428
|
rescue RbVmomi::Fault => fault
|
409
|
-
raise fault unless fault.fault.class.wsdl_name ==
|
429
|
+
raise fault unless fault.fault.class.wsdl_name == 'ManagedObjectNotFound'
|
410
430
|
ensure
|
411
431
|
machine_spec.location = nil
|
412
432
|
end
|
@@ -417,6 +437,7 @@ module ChefProvisioningVsphere
|
|
417
437
|
end
|
418
438
|
|
419
439
|
def stop_machine(action_handler, machine_spec, machine_options)
|
440
|
+
machine_options = deep_symbolize(machine_options)
|
420
441
|
merge_options! machine_options
|
421
442
|
vm = vm_for(machine_spec)
|
422
443
|
if vm
|
@@ -427,6 +448,7 @@ module ChefProvisioningVsphere
|
|
427
448
|
end
|
428
449
|
|
429
450
|
def start_machine(action_handler, machine_spec, machine_options)
|
451
|
+
machine_options = deep_symbolize(machine_options)
|
430
452
|
merge_options! machine_options
|
431
453
|
vm = vm_for(machine_spec)
|
432
454
|
if vm
|
@@ -447,20 +469,20 @@ module ChefProvisioningVsphere
|
|
447
469
|
|
448
470
|
protected
|
449
471
|
|
450
|
-
def setup_ubuntu_dns(machine, bootstrap_options,
|
472
|
+
def setup_ubuntu_dns(machine, bootstrap_options, _machine_spec)
|
451
473
|
host_lookup = machine.execute_always('host google.com')
|
452
474
|
if host_lookup.exitstatus != 0
|
453
|
-
if host_lookup.stdout.include?(
|
475
|
+
if host_lookup.stdout.include?('setlocale: LC_ALL')
|
454
476
|
machine.execute_always('locale-gen en_US && update-locale LANG=en_US')
|
455
477
|
end
|
456
478
|
distro = machine.execute_always("lsb_release -i | sed -e 's/Distributor ID://g'").stdout.strip
|
457
479
|
Chef::Log.info "Found distro:#{distro}"
|
458
480
|
if distro == 'Ubuntu'
|
459
|
-
distro_version =
|
481
|
+
distro_version = machine.execute_always('lsb_release -r | sed -e s/[^0-9.]//g').stdout.strip.to_f
|
460
482
|
Chef::Log.info "Found distro version:#{distro_version}"
|
461
|
-
if distro_version>= 12.04
|
462
|
-
Chef::Log.info
|
463
|
-
interfaces_file =
|
483
|
+
if distro_version >= 12.04
|
484
|
+
Chef::Log.info 'Ubuntu version 12.04 or greater. Need to patch DNS.'
|
485
|
+
interfaces_file = '/etc/network/interfaces'
|
464
486
|
nameservers = bootstrap_options[:customization_spec][:ipsettings][:dnsServerList].join(' ')
|
465
487
|
machine.execute_always("if ! cat #{interfaces_file} | grep -q dns-search ; then echo 'dns-search #{bootstrap_options[:customization_spec][:domain]}' >> #{interfaces_file} ; fi")
|
466
488
|
machine.execute_always("if ! cat #{interfaces_file} | grep -q dns-nameservers ; then echo 'dns-nameservers #{nameservers}' >> #{interfaces_file} ; fi")
|
@@ -472,15 +494,15 @@ module ChefProvisioningVsphere
|
|
472
494
|
end
|
473
495
|
|
474
496
|
def has_static_ip(bootstrap_options)
|
475
|
-
if bootstrap_options.
|
497
|
+
if bootstrap_options.key?(:customization_spec)
|
476
498
|
bootstrap_options = bootstrap_options[:customization_spec]
|
477
499
|
|
478
500
|
if bootstrap_options.is_a?(String)
|
479
501
|
spec = vsphere_helper.find_customization_spec(bootstrap_options)
|
480
502
|
return spec.nicSettingMap[0].adapter.ip.is_a?(RbVmomi::VIM::CustomizationFixedIp)
|
481
|
-
elsif bootstrap_options.
|
503
|
+
elsif bootstrap_options.key?(:ipsettings)
|
482
504
|
bootstrap_options = bootstrap_options[:ipsettings]
|
483
|
-
return bootstrap_options.
|
505
|
+
return bootstrap_options.key?(:ip)
|
484
506
|
end
|
485
507
|
end
|
486
508
|
false
|
@@ -492,17 +514,17 @@ module ChefProvisioningVsphere
|
|
492
514
|
(Time.now.utc - Time.parse(machine_spec.location['started_at']))
|
493
515
|
else
|
494
516
|
(machine_options[:create_timeout] || 600) -
|
495
|
-
|
517
|
+
(Time.now.utc - Time.parse(machine_spec.location['allocated_at']))
|
496
518
|
end
|
497
519
|
end
|
498
520
|
|
499
521
|
def wait_until_ready(action_handler, machine_spec, machine_options, vm)
|
500
|
-
if vm.guest.toolsRunningStatus !=
|
522
|
+
if vm.guest.toolsRunningStatus != 'guestToolsRunning'
|
501
523
|
if action_handler.should_perform_actions
|
502
524
|
action_handler.report_progress "waiting for #{machine_spec.name} (#{vm.config.instanceUuid} on #{driver_url}) to be ready ..."
|
503
525
|
until remaining_wait_time(machine_spec, machine_options) < 0 ||
|
504
|
-
|
505
|
-
print
|
526
|
+
(vm.guest.toolsRunningStatus == 'guestToolsRunning' && vm.guest.ipAddress && !vm.guest.ipAddress.empty?)
|
527
|
+
print '.'
|
506
528
|
sleep 5
|
507
529
|
end
|
508
530
|
action_handler.report_progress "#{machine_spec.name} is now ready"
|
@@ -513,8 +535,6 @@ module ChefProvisioningVsphere
|
|
513
535
|
def vm_for(machine_spec)
|
514
536
|
if machine_spec.location
|
515
537
|
vsphere_helper.find_vm_by_id(machine_spec.location['server_id'])
|
516
|
-
else
|
517
|
-
nil
|
518
538
|
end
|
519
539
|
end
|
520
540
|
|
@@ -535,7 +555,7 @@ module ChefProvisioningVsphere
|
|
535
555
|
vm = vsphere_helper.find_vm(vm_folder, machine_name)
|
536
556
|
|
537
557
|
additional_disk_size_gb = bootstrap_options[:additional_disk_size_gb]
|
538
|
-
|
558
|
+
unless additional_disk_size_gb.is_a?(Array)
|
539
559
|
additional_disk_size_gb = [additional_disk_size_gb]
|
540
560
|
end
|
541
561
|
|
@@ -589,10 +609,12 @@ module ChefProvisioningVsphere
|
|
589
609
|
|
590
610
|
if machine_spec.location['is_windows']
|
591
611
|
Chef::Provisioning::Machine::WindowsMachine.new(
|
592
|
-
machine_spec, transport, strategy
|
612
|
+
machine_spec, transport, strategy
|
613
|
+
)
|
593
614
|
else
|
594
615
|
Chef::Provisioning::Machine::UnixMachine.new(
|
595
|
-
machine_spec, transport, strategy
|
616
|
+
machine_spec, transport, strategy
|
617
|
+
)
|
596
618
|
end
|
597
619
|
end
|
598
620
|
|
@@ -612,17 +634,20 @@ module ChefProvisioningVsphere
|
|
612
634
|
mopts[:chef_server][:options] = mopts[:chef_server][:options].to_hash.dup if mopts[:chef_server][:options]
|
613
635
|
end
|
614
636
|
|
615
|
-
|
637
|
+
unless machine_spec.location
|
616
638
|
return Chef::Provisioning::ConvergenceStrategy::NoConverge.new(
|
617
|
-
mopts, config
|
639
|
+
mopts, config
|
640
|
+
)
|
618
641
|
end
|
619
642
|
|
620
643
|
if machine_spec.location['is_windows']
|
621
644
|
Chef::Provisioning::ConvergenceStrategy::InstallMsi.new(
|
622
|
-
mopts, config
|
645
|
+
mopts, config
|
646
|
+
)
|
623
647
|
else
|
624
648
|
Chef::Provisioning::ConvergenceStrategy::InstallCached.new(
|
625
|
-
mopts, config
|
649
|
+
mopts, config
|
650
|
+
)
|
626
651
|
end
|
627
652
|
end
|
628
653
|
|
@@ -631,12 +656,12 @@ module ChefProvisioningVsphere
|
|
631
656
|
machine_spec,
|
632
657
|
machine_options[:bootstrap_options][:ssh]
|
633
658
|
)
|
634
|
-
|
659
|
+
unless transport.available?
|
635
660
|
if action_handler.should_perform_actions
|
636
661
|
action_handler.report_progress "waiting for #{machine_spec.name} (#{vm.config.instanceUuid} on #{driver_url}) to be connectable (transport up and running) ..."
|
637
662
|
|
638
|
-
until remaining_wait_time(machine_spec, machine_options) < 0 || transport.available?
|
639
|
-
print
|
663
|
+
until remaining_wait_time(machine_spec, machine_options) < 0 || transport.available?
|
664
|
+
print '.'
|
640
665
|
sleep 5
|
641
666
|
end
|
642
667
|
|
@@ -663,12 +688,12 @@ module ChefProvisioningVsphere
|
|
663
688
|
options[:winrm_transport].nil? ? :negotiate : options[:winrm_transport].to_sym
|
664
689
|
port = options[:port] || winrm_transport == :ssl ? '5986' : '5985'
|
665
690
|
winrm_options = {
|
666
|
-
user:
|
691
|
+
user: (options[:user]).to_s,
|
667
692
|
pass: options[:password]
|
668
693
|
}
|
669
694
|
if options[:winrm_opts].nil?
|
670
|
-
opt = options[:user].include?(
|
671
|
-
winrm_options
|
695
|
+
opt = options[:user].include?('\\') ? :disable_sspi : :basic_auth_only
|
696
|
+
winrm_options[opt] = true
|
672
697
|
else
|
673
698
|
winrm_options.merge!(options[:winrm_opts])
|
674
699
|
end
|
@@ -686,11 +711,12 @@ module ChefProvisioningVsphere
|
|
686
711
|
def create_ssh_transport(host, options)
|
687
712
|
require 'chef/provisioning/transport/ssh'
|
688
713
|
ssh_user = options[:user]
|
714
|
+
options = options.each_with_object({}) { |(k, v), memo| memo[k.to_sym] = v; }
|
689
715
|
Chef::Provisioning::Transport::SSH.new(
|
690
716
|
host,
|
691
717
|
ssh_user,
|
692
718
|
options.to_hash,
|
693
|
-
@config[:machine_options][:sudo] ? {:
|
719
|
+
@config[:machine_options][:sudo] ? { prefix: 'sudo ' } : {},
|
694
720
|
config
|
695
721
|
)
|
696
722
|
end
|