chef-metal 0.5 → 0.6

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.
@@ -1,18 +0,0 @@
1
- require 'chef/resource/lwrp_base'
2
- require 'chef_metal/provisioner/vagrant_provisioner'
3
-
4
- class Chef::Resource::VagrantBox < Chef::Resource::LWRPBase
5
- self.resource_name = 'vagrant_box'
6
-
7
- actions :create, :delete, :nothing
8
- default_action :create
9
-
10
- attribute :name, :kind_of => String, :name_attribute => true
11
- attribute :url, :kind_of => String
12
- attribute :provisioner_options, :kind_of => Hash
13
-
14
- def after_created
15
- super
16
- ChefMetal.with_vagrant_box self
17
- end
18
- end
@@ -1,16 +0,0 @@
1
- require 'chef/resource/lwrp_base'
2
- require 'chef_metal'
3
-
4
- class Chef::Resource::VagrantCluster < Chef::Resource::LWRPBase
5
- self.resource_name = 'vagrant_cluster'
6
-
7
- actions :create, :delete, :nothing
8
- default_action :create
9
-
10
- attribute :path, :kind_of => String, :name_attribute => true
11
-
12
- def after_created
13
- super
14
- ChefMetal.with_vagrant_cluster path
15
- end
16
- end
@@ -1,20 +0,0 @@
1
- require 'chef_metal'
2
- require 'chef/resource/fog_key_pair'
3
- require 'chef/provider/fog_key_pair'
4
- require 'chef_metal/provisioner/fog_provisioner'
5
-
6
- class Chef
7
- class Recipe
8
- def with_fog_provisioner(options = {}, &block)
9
- ChefMetal.with_provisioner(ChefMetal::Provisioner::FogProvisioner.new(options), &block)
10
- end
11
-
12
- def with_fog_ec2_provisioner(options = {}, &block)
13
- with_fog_provisioner({ :provider => 'AWS' }.merge(options), &block)
14
- end
15
-
16
- def with_fog_openstack_provisioner(options = {}, &block)
17
- with_fog_provisioner({ :provider => 'OpenStack' }.merge(options), &block)
18
- end
19
- end
20
- end
@@ -1,550 +0,0 @@
1
- require 'chef_metal/provisioner'
2
- require 'chef_metal/aws_credentials'
3
- require 'chef_metal/openstack_credentials'
4
- require 'chef_metal/version'
5
- require 'fog/compute'
6
- require 'fog'
7
-
8
- module ChefMetal
9
- class Provisioner
10
-
11
- # Provisions machines in vagrant.
12
- class FogProvisioner < Provisioner
13
-
14
- include Chef::Mixin::ShellOut
15
-
16
- DEFAULT_OPTIONS = {
17
- :create_timeout => 600,
18
- :start_timeout => 600,
19
- :ssh_timeout => 20
20
- }
21
-
22
- def self.inflate(node)
23
- url = node['normal']['provisioner_output']['provisioner_url']
24
- scheme, provider, id = url.split(':', 3)
25
- FogProvisioner.new({ :provider => provider }, id)
26
- end
27
-
28
- # Create a new fog provisioner.
29
- #
30
- # ## Parameters
31
- # compute_options - hash of options to be passed to Fog::Compute.new
32
- # Special options:
33
- # - :base_bootstrap_options is merged with bootstrap_options in acquire_machine
34
- # to present the full set of bootstrap options. Write down any bootstrap_options
35
- # you intend to apply universally here.
36
- # - :aws_credentials is an AWS CSV file (created with Download Credentials)
37
- # containing your aws key information. If you do not specify aws_access_key_id
38
- # and aws_secret_access_key explicitly, the first line from this file
39
- # will be used. You may pass a Cheffish::AWSCredentials object.
40
- # - :create_timeout - the time to wait for the instance to boot to ssh (defaults to 600)
41
- # - :start_timeout - the time to wait for the instance to start (defaults to 600)
42
- # - :ssh_timeout - the time to wait for ssh to be available if the instance is detected as up (defaults to 20)
43
- # id - the ID in the provisioner_url (fog:PROVIDER:ID)
44
- def initialize(compute_options, id=nil)
45
- @compute_options = compute_options
46
- @base_bootstrap_options = compute_options.delete(:base_bootstrap_options) || {}
47
-
48
- case compute_options[:provider]
49
- when 'AWS'
50
- aws_credentials = compute_options.delete(:aws_credentials)
51
- if aws_credentials
52
- @aws_credentials = aws_credentials
53
- else
54
- @aws_credentials = ChefMetal::AWSCredentials.new
55
- @aws_credentials.load_default
56
- end
57
- compute_options[:aws_access_key_id] ||= @aws_credentials.default[:access_key_id]
58
- compute_options[:aws_secret_access_key] ||= @aws_credentials.default[:secret_access_key]
59
- # TODO actually find a key with the proper id
60
- # TODO let the user specify credentials and provider profiles that we can use
61
- if id && aws_login_info[0] != id
62
- raise "Default AWS credentials point at AWS account #{aws_login_info[0]}, but inflating from URL #{id}"
63
- end
64
- when 'OpenStack'
65
- openstack_credentials = compute_options.delete(:openstack_credentials)
66
- if openstack_credentials
67
- @openstack_credentials = openstack_credentials
68
- else
69
- @openstack_credentials = ChefMetal::OpenstackCredentials.new
70
- @openstack_credentials.load_default
71
- end
72
-
73
- compute_options[:openstack_username] ||= @openstack_credentials.default[:openstack_username]
74
- compute_options[:openstack_api_key] ||= @openstack_credentials.default[:openstack_api_key]
75
- compute_options[:openstack_auth_url] ||= @openstack_credentials.default[:openstack_auth_url]
76
- compute_options[:openstack_tenant] ||= @openstack_credentials.default[:openstack_tenant]
77
- end
78
- @key_pairs = {}
79
- @base_bootstrap_options_for = {}
80
- end
81
-
82
- attr_reader :compute_options
83
- attr_reader :aws_credentials
84
- attr_reader :openstack_credentials
85
- attr_reader :key_pairs
86
-
87
- def current_base_bootstrap_options
88
- result = @base_bootstrap_options.dup
89
- if key_pairs.size > 0
90
- last_pair_name = key_pairs.keys.last
91
- last_pair = key_pairs[last_pair_name]
92
- result[:key_name] ||= last_pair_name
93
- result[:private_key_path] ||= last_pair.private_key_path
94
- result[:public_key_path] ||= last_pair.public_key_path
95
- end
96
- result
97
- end
98
-
99
- # Inflate a provisioner from node information; we don't want to force the
100
- # driver to figure out what the provisioner really needs, since it varies
101
- # from provisioner to provisioner.
102
- #
103
- # ## Parameters
104
- # node - node to inflate the provisioner for
105
- #
106
- # returns a FogProvisioner
107
- # TODO: def self.inflate(node)
108
- # right now, not implemented, will raise error from base class until overridden
109
-
110
- # Acquire a machine, generally by provisioning it. Returns a Machine
111
- # object pointing at the machine, allowing useful actions like setup,
112
- # converge, execute, file and directory. The Machine object will have a
113
- # "node" property which must be saved to the server (if it is any
114
- # different from the original node object).
115
- #
116
- # ## Parameters
117
- # action_handler - the action_handler object that is calling this method; this
118
- # is generally a action_handler, but could be anything that can support the
119
- # ChefMetal::ActionHandler interface (i.e., in the case of the test
120
- # kitchen metal driver for acquiring and destroying VMs; see the base
121
- # class for what needs providing).
122
- # node - node object (deserialized json) representing this machine. If
123
- # the node has a provisioner_options hash in it, these will be used
124
- # instead of options provided by the provisioner. TODO compare and
125
- # fail if different?
126
- # node will have node['normal']['provisioner_options'] in it with any options.
127
- # It is a hash with this format:
128
- #
129
- # -- provisioner_url: fog:<relevant_fog_options>
130
- # -- bootstrap_options: hash of options to pass to compute.servers.create
131
- # -- is_windows: true if windows. TODO detect this from ami?
132
- # -- create_timeout - the time to wait for the instance to boot to ssh (defaults to 600)
133
- # -- start_timeout - the time to wait for the instance to start (defaults to 600)
134
- # -- ssh_timeout - the time to wait for ssh to be available if the instance is detected as up (defaults to 20)
135
- #
136
- # Example bootstrap_options for ec2:
137
- # :image_id =>'ami-311f2b45',
138
- # :flavor_id =>'t1.micro',
139
- # :key_name => 'key-pair-name'
140
- #
141
- # node['normal']['provisioner_output'] will be populated with information
142
- # about the created machine. For vagrant, it is a hash with this
143
- # format:
144
- #
145
- # -- provisioner_url: fog:<relevant_fog_options>
146
- # -- server_id: the ID of the server so it can be found again
147
- #
148
- def acquire_machine(action_handler, node)
149
- # Set up the modified node data
150
- provisioner_output = node['normal']['provisioner_output'] || {
151
- 'provisioner_url' => provisioner_url,
152
- 'provisioner_version' => ChefMetal::VERSION,
153
- 'creator' => aws_login_info[1]
154
- }
155
-
156
- if provisioner_output['provisioner_url'] != provisioner_url
157
- if (provisioner_output['provisioner_version'].to_f <= 0.3) && provisioner_output['provisioner_url'].start_with?('fog:AWS:') && compute_options[:provider] == 'AWS'
158
- Chef::Log.warn "The upgrade from chef-metal 0.3 to 0.4 changed the provisioner URL format! Metal will assume you are in fact using the same AWS account, and modify the provisioner URL to match."
159
- provisioner_output['provisioner_url'] = provisioner_url
160
- provisioner_output['provisioner_version'] ||= ChefMetal::VERSION
161
- provisioner_output['creator'] ||= aws_login_info[1]
162
- else
163
- raise "Switching providers for a machine is not currently supported! Use machine :destroy and then re-create the machine on the new action_handler."
164
- end
165
- end
166
-
167
- node['normal']['provisioner_output'] = provisioner_output
168
-
169
- if provisioner_output['server_id']
170
-
171
- # If the server already exists, make sure it is up
172
-
173
- # TODO verify that the server info matches the specification (ami, etc.)\
174
- server = server_for(node)
175
- if !server
176
- Chef::Log.warn "Machine #{node['name']} (#{provisioner_output['server_id']} on #{provisioner_url}) is not associated with the ec2 account. Recreating ..."
177
- need_to_create = true
178
- elsif %w(terminated archive).include?(server.state) # Can't come back from that
179
- Chef::Log.warn "Machine #{node['name']} (#{server.id} on #{provisioner_url}) is terminated. Recreating ..."
180
- need_to_create = true
181
- else
182
- need_to_create = false
183
- if !server.ready?
184
- action_handler.perform_action "start machine #{node['name']} (#{server.id} on #{provisioner_url})" do
185
- server.start
186
- end
187
- action_handler.perform_action "wait for machine #{node['name']} (#{server.id} on #{provisioner_url}) to be ready" do
188
- wait_until_ready(server, option_for(node, :start_timeout))
189
- end
190
- else
191
- wait_until_ready(server, option_for(node, :ssh_timeout))
192
- end
193
- end
194
- else
195
- need_to_create = true
196
- end
197
-
198
- if need_to_create
199
- # If the server does not exist, create it
200
- bootstrap_options = bootstrap_options_for(action_handler.new_resource, node)
201
- bootstrap_options.merge(:name => action_handler.new_resource.name)
202
-
203
- start_time = Time.now
204
- timeout = option_for(node, :create_timeout)
205
-
206
- description = [ "create machine #{node['name']} on #{provisioner_url}" ]
207
- bootstrap_options.each_pair { |key,value| description << " #{key}: #{value.inspect}" }
208
- server = nil
209
- action_handler.perform_action description do
210
- server = compute.servers.create(bootstrap_options)
211
- provisioner_output['server_id'] = server.id
212
- # Save quickly in case something goes wrong
213
- save_node(action_handler, node, action_handler.new_resource.chef_server)
214
- end
215
-
216
- if server
217
- @@ip_pool_lock = Mutex.new
218
- # Re-retrieve the server in a more malleable form and wait for it to be ready
219
- server = compute.servers.get(server.id)
220
- if bootstrap_options[:floating_ip_pool]
221
- Chef::Log.info 'Attaching IP from pool'
222
- server.wait_for { ready? }
223
- action_handler.perform_action "attach floating IP from #{bootstrap_options[:floating_ip_pool]} pool" do
224
- attach_ip_from_pool(server, bootstrap_options[:floating_ip_pool])
225
- end
226
- elsif bootstrap_options[:floating_ip]
227
- Chef::Log.info 'Attaching given IP'
228
- server.wait_for { ready? }
229
- action_handler.perform_action "attach floating IP #{bootstrap_options[:floating_ip]}" do
230
- attach_ip(server, bootstrap_options[:floating_ip])
231
- end
232
- end
233
- action_handler.perform_action "machine #{node['name']} created as #{server.id} on #{provisioner_url}" do
234
- end
235
- # Wait for the machine to come up and for ssh to start listening
236
- transport = nil
237
- _self = self
238
- action_handler.perform_action "wait for machine #{node['name']} to boot" do
239
- server.wait_for(timeout - (Time.now - start_time)) do
240
- if ready?
241
- transport ||= _self.transport_for(server)
242
- begin
243
- transport.execute('pwd')
244
- true
245
- rescue Errno::ECONNREFUSED, Net::SSH::Disconnect
246
- false
247
- rescue
248
- true
249
- end
250
- else
251
- false
252
- end
253
- end
254
- end
255
-
256
- # If there is some other error, we just wait patiently for SSH
257
- begin
258
- server.wait_for(option_for(node, :ssh_timeout)) { transport.available? }
259
- rescue Fog::Errors::TimeoutError
260
- # Sometimes (on EC2) the machine comes up but gets stuck or has
261
- # some other problem. If this is the case, we restart the server
262
- # to unstick it. Reboot covers a multitude of sins.
263
- Chef::Log.warn "Machine #{node['name']} (#{server.id} on #{provisioner_url}) was started but SSH did not come up. Rebooting machine in an attempt to unstick it ..."
264
- action_handler.perform_action "reboot machine #{node['name']} to try to unstick it" do
265
- server.reboot
266
- end
267
- action_handler.perform_action "wait for machine #{node['name']} to be ready after reboot" do
268
- wait_until_ready(server, option_for(node, :start_timeout))
269
- end
270
- end
271
- end
272
- end
273
-
274
- # Create machine object for callers to use
275
- machine_for(node, server)
276
- end
277
-
278
- # Attach IP to machine from IP pool
279
- # Code taken from kitchen-openstack driver
280
- # https://github.com/test-kitchen/kitchen-openstack/blob/master/lib/kitchen/driver/openstack.rb#L196-L207
281
- def attach_ip_from_pool(server, pool)
282
- @@ip_pool_lock.synchronize do
283
- Chef::Log.info "Attaching floating IP from <#{pool}> pool"
284
- free_addrs = compute.addresses.collect do |i|
285
- i.ip if i.fixed_ip.nil? and i.instance_id.nil? and i.pool == pool
286
- end.compact
287
- if free_addrs.empty?
288
- raise ActionFailed, "No available IPs in pool <#{pool}>"
289
- end
290
- attach_ip(server, free_addrs[0])
291
- end
292
- end
293
-
294
- # Attach given IP to machine
295
- # Code taken from kitchen-openstack driver
296
- # https://github.com/test-kitchen/kitchen-openstack/blob/master/lib/kitchen/driver/openstack.rb#L209-L213
297
- def attach_ip(server, ip)
298
- Chef::Log.info "Attaching floating IP <#{ip}>"
299
- server.associate_address ip
300
- (server.addresses['public'] ||= []) << { 'version' => 4, 'addr' => ip }
301
- end
302
-
303
- # Connect to machine without acquiring it
304
- def connect_to_machine(node)
305
- machine_for(node)
306
- end
307
-
308
- def delete_machine(action_handler, node)
309
- if node['normal']['provisioner_output'] && node['normal']['provisioner_output']['server_id']
310
- server = compute.servers.get(node['normal']['provisioner_output']['server_id'])
311
- action_handler.perform_action "destroy machine #{node['name']} (#{node['normal']['provisioner_output']['server_id']} at #{provisioner_url})" do
312
- server.destroy
313
- end
314
- convergence_strategy_for(node).cleanup_convergence(action_handler, node)
315
- end
316
- end
317
-
318
- def stop_machine(action_handler, node)
319
- # If the machine doesn't exist, we silently do nothing
320
- if node['normal']['provisioner_output'] && node['normal']['provisioner_output']['server_id']
321
- server = compute.servers.get(node['normal']['provisioner_output']['server_id'])
322
- action_handler.perform_action "stop machine #{node['name']} (#{server.id} at #{provisioner_url})" do
323
- server.stop
324
- end
325
- end
326
- end
327
-
328
- def resource_created(machine)
329
- @base_bootstrap_options_for[machine] = current_base_bootstrap_options
330
- end
331
-
332
-
333
- def compute
334
- @compute ||= Fog::Compute.new(compute_options)
335
- end
336
-
337
- def provisioner_url
338
- provider_identifier = case compute_options[:provider]
339
- when 'AWS'
340
- aws_login_info[0]
341
- when 'DigitalOcean'
342
- compute_options[:digitalocean_client_id]
343
- when 'OpenStack'
344
- compute_options[:openstack_auth_url]
345
- else
346
- '???'
347
- end
348
- "fog:#{compute_options[:provider]}:#{provider_identifier}"
349
- end
350
-
351
- # Not meant to be part of public interface
352
- def transport_for(server)
353
- # TODO winrm
354
- create_ssh_transport(server)
355
- end
356
-
357
- protected
358
-
359
- def option_for(node, key)
360
- if node['normal']['provisioner_options'] && node['normal']['provisioner_options'][key.to_s]
361
- node['normal']['provisioner_options'][key.to_s]
362
- elsif compute_options[key]
363
- compute_options[key]
364
- else
365
- DEFAULT_OPTIONS[key]
366
- end
367
- end
368
-
369
- # Returns [ Account ID, User ]
370
- # Account ID is the 12 digit identifier on your Manage Account page in AWS Console. It is used as part of all ARNs identifying resources.
371
- # User is an identifier like "root" or "user/username" or "federated-user/username"
372
- def aws_login_info
373
- @aws_login_info ||= begin
374
- iam = Fog::AWS::IAM.new(:aws_access_key_id => compute_options[:aws_access_key_id], :aws_secret_access_key => compute_options[:aws_secret_access_key])
375
- arn = begin
376
- # TODO it would be nice if Fog let you do this normally ...
377
- iam.send(:request, {
378
- 'Action' => 'GetUser',
379
- :parser => Fog::Parsers::AWS::IAM::GetUser.new
380
- }).body['User']['Arn']
381
- rescue Fog::AWS::IAM::Error
382
- # TODO Someone tell me there is a better way to find out your current
383
- # user ID than this! This is what happens when you use an IAM user
384
- # with default privileges.
385
- if $!.message =~ /AccessDenied.+(arn:aws:iam::\d+:\S+)/
386
- arn = $1
387
- else
388
- raise
389
- end
390
- end
391
- arn.split(':')[4..5]
392
- end
393
- end
394
-
395
- def symbolize_keys(options)
396
- options.inject({}) { |result,(key,value)| result[key.to_sym] = value; result }
397
- end
398
-
399
- def server_for(node)
400
- if node['normal']['provisioner_output'] && node['normal']['provisioner_output']['server_id']
401
- compute.servers.get(node['normal']['provisioner_output']['server_id'])
402
- else
403
- nil
404
- end
405
- end
406
-
407
- def bootstrap_options_for(machine, node)
408
- provisioner_options = node['normal']['provisioner_options'] || {}
409
- bootstrap_options = @base_bootstrap_options_for[machine] || current_base_bootstrap_options
410
- bootstrap_options = bootstrap_options.merge(symbolize_keys(provisioner_options['bootstrap_options'] || {}))
411
- require 'socket'
412
- require 'etc'
413
- tags = {
414
- 'Name' => node['name'],
415
- 'BootstrapChefServer' => machine.chef_server[:chef_server_url],
416
- 'BootstrapHost' => Socket.gethostname,
417
- 'BootstrapUser' => Etc.getlogin,
418
- 'BootstrapNodeName' => node['name']
419
- }
420
- if machine.chef_server[:options] && machine.chef_server[:options][:data_store]
421
- tags['ChefLocalRepository'] = machine.chef_server[:options][:data_store].chef_fs.fs_description
422
- end
423
- # User-defined tags override the ones we set
424
- tags.merge!(bootstrap_options[:tags]) if bootstrap_options[:tags]
425
- bootstrap_options.merge!({ :tags => tags })
426
-
427
- # Provide reasonable defaults for DigitalOcean
428
- if compute_options[:provider] == 'DigitalOcean'
429
- if !bootstrap_options[:image_id]
430
- bootstrap_options[:image_name] ||= 'CentOS 6.4 x32'
431
- bootstrap_options[:image_id] = compute.images.select { |image| image.name == bootstrap_options[:image_name] }.first.id
432
- end
433
- if !bootstrap_options[:flavor_id]
434
- bootstrap_options[:flavor_name] ||= '512MB'
435
- bootstrap_options[:flavor_id] = compute.flavors.select { |flavor| flavor.name == bootstrap_options[:flavor_name] }.first.id
436
- end
437
- if !bootstrap_options[:region_id]
438
- bootstrap_options[:region_name] ||= 'San Francisco 1'
439
- bootstrap_options[:region_id] = compute.regions.select { |region| region.name == bootstrap_options[:region_name] }.first.id
440
- end
441
- bootstrap_options[:ssh_key_ids] ||= [ compute.ssh_keys.select { |k| k.name == bootstrap_options[:key_name] }.first.id ]
442
-
443
- # You don't get to specify name yourself
444
- bootstrap_options[:name] = node['name']
445
- end
446
-
447
- bootstrap_options
448
- end
449
-
450
- def machine_for(node, server = nil)
451
- server ||= server_for(node)
452
- if !server
453
- raise "Server for node #{node['name']} has not been created!"
454
- end
455
-
456
- if node['normal']['provisioner_options'] && node['normal']['provisioner_options']['is_windows']
457
- require 'chef_metal/machine/windows_machine'
458
- ChefMetal::Machine::WindowsMachine.new(node, transport_for(server), convergence_strategy_for(node))
459
- else
460
- require 'chef_metal/machine/unix_machine'
461
- ChefMetal::Machine::UnixMachine.new(node, transport_for(server), convergence_strategy_for(node))
462
- end
463
- end
464
-
465
- def convergence_strategy_for(node)
466
- if node['normal']['provisioner_options'] && node['normal']['provisioner_options']['is_windows']
467
- @windows_convergence_strategy ||= begin
468
- require 'chef_metal/convergence_strategy/install_msi'
469
- ChefMetal::ConvergenceStrategy::InstallMsi.new
470
- end
471
- else
472
- @unix_convergence_strategy ||= begin
473
- require 'chef_metal/convergence_strategy/install_cached'
474
- ChefMetal::ConvergenceStrategy::InstallCached.new
475
- end
476
- end
477
- end
478
-
479
- def ssh_options_for(server)
480
- result = {
481
- # TODO create a user known hosts file
482
- # :user_known_hosts_file => vagrant_ssh_config['UserKnownHostsFile'],
483
- # :paranoid => true,
484
- :auth_methods => [ 'publickey' ],
485
- :keys_only => true,
486
- :host_key_alias => "#{server.id}.#{compute_options[:provider]}"
487
- }
488
- if server.respond_to?(:private_key) && server.private_key
489
- result[:keys] = [ server.private_key ]
490
- elsif server.respond_to?(:key_name) && key_pairs[server.key_name]
491
- # TODO generalize for others?
492
- result[:keys] ||= [ key_pairs[server.key_name].private_key_path ]
493
- else
494
- # TODO need a way to know which key if there were multiple
495
- result[:keys] = [ key_pairs.first[1].private_key_path ]
496
- end
497
- result
498
- end
499
-
500
- def create_ssh_transport(server)
501
- require 'chef_metal/transport/ssh'
502
-
503
- ssh_options = ssh_options_for(server)
504
- # If we're on AWS, the default is to use ubuntu, not root
505
- if compute_options[:provider] == 'AWS'
506
- username = compute_options[:ssh_username] || 'ubuntu'
507
- else
508
- username = compute_options[:ssh_username] || 'root'
509
- end
510
- options = {}
511
- if compute_options[:sudo] || (!compute_options.has_key?(:sudo) && username != 'root')
512
- options[:prefix] = 'sudo '
513
- end
514
-
515
- remote_host = nil
516
- if compute_options[:use_private_ip_for_ssh]
517
- remote_host = server.private_ip_address
518
- elsif !server.public_ip_address
519
- Chef::Log.warn("Server has no public ip address. Using private ip '#{server.private_ip_address}'. Set provisioner option 'use_private_ip_for_ssh' => true if this will always be the case ...")
520
- remote_host = server.private_ip_address
521
- elsif server.public_ip_address
522
- remote_host = server.public_ip_address
523
- else
524
- raise "Server #{server.id} has no private or public IP address!"
525
- end
526
-
527
- #Enable pty by default
528
- options[:ssh_pty_enable] = true
529
-
530
- ChefMetal::Transport::SSH.new(remote_host, username, ssh_options, options)
531
- end
532
-
533
- def wait_until_ready(server, timeout)
534
- transport = nil
535
- _self = self
536
- server.wait_for(timeout) do
537
- if transport
538
- transport.available?
539
- elsif ready?
540
- # Don't create the transport until the machine is ready (we won't have the host till then)
541
- transport = _self.transport_for(server)
542
- transport.available?
543
- else
544
- false
545
- end
546
- end
547
- end
548
- end
549
- end
550
- end