chef-metal 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,16 +9,16 @@ module ChefMetal
9
9
  # Sets up everything necessary for convergence to happen on the machine.
10
10
  # The node MUST be saved as part of this procedure. Other than that,
11
11
  # nothing is guaranteed except that converge() will work when this is done.
12
- def setup_convergence(provider)
12
+ def setup_convergence(action_handler)
13
13
  raise "setup_convergence not overridden on #{self.class}"
14
14
  end
15
15
 
16
- def converge(provider)
16
+ def converge(action_handler)
17
17
  raise "converge not overridden on #{self.class}"
18
18
  end
19
19
 
20
20
 
21
- def execute(provider, command)
21
+ def execute(action_handler, command)
22
22
  raise "execute not overridden on #{self.class}"
23
23
  end
24
24
 
@@ -26,24 +26,24 @@ module ChefMetal
26
26
  raise "read_file not overridden on #{self.class}"
27
27
  end
28
28
 
29
- def download_file(provider, path, local_path)
29
+ def download_file(action_handler, path, local_path)
30
30
  raise "read_file not overridden on #{self.class}"
31
31
  end
32
32
 
33
- def write_file(provider, path, content)
33
+ def write_file(action_handler, path, content)
34
34
  raise "write_file not overridden on #{self.class}"
35
35
  end
36
36
 
37
- def upload_file(provider, local_path, path)
37
+ def upload_file(action_handler, local_path, path)
38
38
  raise "write_file not overridden on #{self.class}"
39
39
  end
40
40
 
41
- def create_dir(provider, path)
41
+ def create_dir(action_handler, path)
42
42
  raise "create_dir not overridden on #{self.class}"
43
43
  end
44
44
 
45
45
  # Delete file
46
- def delete_file(provider, path)
46
+ def delete_file(action_handler, path)
47
47
  raise "delete_file not overridden on #{self.class}"
48
48
  end
49
49
 
@@ -58,7 +58,7 @@ module ChefMetal
58
58
  end
59
59
 
60
60
  # Set file attributes { mode, :owner, :group }
61
- def set_attributes(provider, path, attributes)
61
+ def set_attributes(action_handler, path, attributes)
62
62
  raise "set_attributes not overridden on #{self.class}"
63
63
  end
64
64
 
@@ -76,13 +76,13 @@ module ChefMetal
76
76
  raise "disconnect not overridden on #{self.class}"
77
77
  end
78
78
 
79
- # TODO get rid of the provider attribute, that is ridiculous
79
+ # TODO get rid of the action_handler attribute, that is ridiculous
80
80
  # Detect the OS on the machine (assumes the machine is up)
81
81
  # Returns a triplet:
82
- # platform, platform_version, machine_architecture = machine.detect_os(provider)
82
+ # platform, platform_version, machine_architecture = machine.detect_os(action_handler)
83
83
  # This triplet is suitable for passing to the Chef metadata API:
84
84
  # https://www.opscode.com/chef/metadata?p=#{platform}&pv=#{platform_version}&m=#{machine_architecture}
85
- def detect_os(provider)
85
+ def detect_os(action_handler)
86
86
  raise "detect_os not overridden on #{self.class}"
87
87
  end
88
88
  end
@@ -15,16 +15,16 @@ module ChefMetal
15
15
  # Sets up everything necessary for convergence to happen on the machine.
16
16
  # The node MUST be saved as part of this procedure. Other than that,
17
17
  # nothing is guaranteed except that converge() will work when this is done.
18
- def setup_convergence(provider, machine_resource)
19
- convergence_strategy.setup_convergence(provider, self, machine_resource)
18
+ def setup_convergence(action_handler, machine_resource)
19
+ convergence_strategy.setup_convergence(action_handler, self, machine_resource)
20
20
  end
21
21
 
22
- def converge(provider)
23
- convergence_strategy.converge(provider, self)
22
+ def converge(action_handler)
23
+ convergence_strategy.converge(action_handler, self)
24
24
  end
25
25
 
26
- def execute(provider, command)
27
- provider.converge_by "run '#{command}' on #{node['name']}" do
26
+ def execute(action_handler, command)
27
+ action_handler.converge_by "run '#{command}' on #{node['name']}" do
28
28
  transport.execute(command).error!
29
29
  end
30
30
  end
@@ -37,31 +37,31 @@ module ChefMetal
37
37
  transport.read_file(path)
38
38
  end
39
39
 
40
- def download_file(provider, path, local_path)
40
+ def download_file(action_handler, path, local_path)
41
41
  if files_different?(path, local_path)
42
- provider.converge_by "download file #{path} on #{node['name']} to #{local_path}" do
42
+ action_handler.converge_by "download file #{path} on #{node['name']} to #{local_path}" do
43
43
  transport.download_file(path, local_path)
44
44
  end
45
45
  end
46
46
  end
47
47
 
48
- def write_file(provider, path, content, options = {})
48
+ def write_file(action_handler, path, content, options = {})
49
49
  if files_different?(path, nil, content)
50
50
  if options[:ensure_dir]
51
- create_dir(provider, dirname_on_machine(path))
51
+ create_dir(action_handler, dirname_on_machine(path))
52
52
  end
53
- provider.converge_by "write file #{path} on #{node['name']}" do
53
+ action_handler.converge_by "write file #{path} on #{node['name']}" do
54
54
  transport.write_file(path, content)
55
55
  end
56
56
  end
57
57
  end
58
58
 
59
- def upload_file(provider, local_path, path, options = {})
59
+ def upload_file(action_handler, local_path, path, options = {})
60
60
  if files_different?(path, local_path)
61
61
  if options[:ensure_dir]
62
- create_dir(provider, dirname_on_machine(path))
62
+ create_dir(action_handler, dirname_on_machine(path))
63
63
  end
64
- provider.converge_by "upload file #{local_path} to #{path} on #{node['name']}" do
64
+ action_handler.converge_by "upload file #{local_path} to #{path} on #{node['name']}" do
65
65
  transport.upload_file(local_path, path)
66
66
  end
67
67
  end
@@ -16,9 +16,9 @@ module ChefMetal
16
16
  attr_reader :options
17
17
 
18
18
  # Delete file
19
- def delete_file(provider, path)
19
+ def delete_file(action_handler, path)
20
20
  if file_exists?(path)
21
- provider.converge_by "delete file #{path} on #{node['name']}" do
21
+ action_handler.converge_by "delete file #{path} on #{node['name']}" do
22
22
  transport.execute("rm -f #{path}").error!
23
23
  end
24
24
  end
@@ -53,30 +53,30 @@ module ChefMetal
53
53
  remote_sum != digest.hexdigest
54
54
  end
55
55
 
56
- def create_dir(provider, path)
56
+ def create_dir(action_handler, path)
57
57
  if !file_exists?(path)
58
- provider.converge_by "create directory #{path} on #{node['name']}" do
58
+ action_handler.converge_by "create directory #{path} on #{node['name']}" do
59
59
  transport.execute("mkdir #{path}").error!
60
60
  end
61
61
  end
62
62
  end
63
63
 
64
64
  # Set file attributes { mode, :owner, :group }
65
- def set_attributes(provider, path, attributes)
65
+ def set_attributes(action_handler, path, attributes)
66
66
  if attributes[:mode] || attributes[:owner] || attributes[:group]
67
- current_attributes = get_file_attributes(path)
68
- if attributes[:mode] && current_attributes[:mode] != attributes[:mode]
69
- provider.converge_by "change mode of #{path} on #{node['name']} from #{current_attributes[:mode].to_i(8)} to #{attributes[:mode].to_i(8)}" do
70
- transport.execute("chmod #{attributes[:mode].to_i(8)} #{path}").error!
67
+ current_attributes = get_attributes(path)
68
+ if attributes[:mode] && current_attributes[:mode].to_i != attributes[:mode].to_i
69
+ action_handler.converge_by "change mode of #{path} on #{node['name']} from #{current_attributes[:mode].to_i} to #{attributes[:mode].to_i}" do
70
+ transport.execute("chmod #{attributes[:mode].to_i} #{path}").error!
71
71
  end
72
72
  end
73
73
  if attributes[:owner] && current_attributes[:owner] != attributes[:owner]
74
- provider.converge_by "change group of #{path} on #{node['name']} from #{current_attributes[:owner]} to #{attributes[:owner]}" do
74
+ action_handler.converge_by "change group of #{path} on #{node['name']} from #{current_attributes[:owner]} to #{attributes[:owner]}" do
75
75
  transport.execute("chown #{attributes[:owner]} #{path}").error!
76
76
  end
77
77
  end
78
78
  if attributes[:group] && current_attributes[:group] != attributes[:group]
79
- provider.converge_by "change group of #{path} on #{node['name']} from #{current_attributes[:group]} to #{attributes[:group]}" do
79
+ action_handler.converge_by "change group of #{path} on #{node['name']} from #{current_attributes[:group]} to #{attributes[:group]}" do
80
80
  transport.execute("chgrp #{attributes[:group]} #{path}").error!
81
81
  end
82
82
  end
@@ -85,21 +85,15 @@ module ChefMetal
85
85
 
86
86
  # Get file attributes { :mode, :owner, :group }
87
87
  def get_attributes(path)
88
- file_info = transport.execute("ls -ld #{path}").stdout.split(/\s+/)
88
+ file_info = transport.execute("stat -c '%a %U %G %n' #{path}").stdout.split(/\s+/)
89
89
  if file_info.size <= 1
90
90
  raise "#{path} does not exist in set_attributes()"
91
91
  end
92
92
  result = {
93
- :mode => 0,
94
- :owner => file_info[2],
95
- :group => file_info[3]
93
+ :mode => file_info[0],
94
+ :owner => file_info[1],
95
+ :group => file_info[2]
96
96
  }
97
- attribute_string = file_info[0]
98
- 0.upto(attribute_string.length-1).each do |i|
99
- result[:mode] <<= 1
100
- result[:mode] += (attribute_string[i] == '-' ? 0 : 1)
101
- end
102
- result
103
97
  end
104
98
 
105
99
  def dirname_on_machine(path)
@@ -107,12 +101,12 @@ module ChefMetal
107
101
  end
108
102
  end
109
103
 
110
- def detect_os(provider)
104
+ def detect_os(action_handler)
111
105
  #
112
106
  # Use detect.sh to detect the operating system of the remote machine
113
107
  #
114
108
  # TODO do this in terms of commands rather than writing a shell script
115
- self.write_file(provider, "#{@tmp_dir}/detect.sh", detect_sh)
109
+ self.write_file(action_handler, "#{@tmp_dir}/detect.sh", detect_sh)
116
110
  detected = self.execute_always("sh #{@tmp_dir}/detect.sh")
117
111
  if detected.exitstatus != 0
118
112
  raise "detect.sh exited with nonzero exit status: #{detected.exitstatus}"
@@ -13,9 +13,9 @@ module ChefMetal
13
13
  attr_reader :options
14
14
 
15
15
  # Delete file
16
- def delete_file(provider, path)
16
+ def delete_file(action_handler, path)
17
17
  if file_exists?(path)
18
- provider.converge_by "delete file #{escape(path)} on #{node['name']}" do
18
+ action_handler.converge_by "delete file #{escape(path)} on #{node['name']}" do
19
19
  transport.execute("Remove-Item #{escape(path)}").error!
20
20
  end
21
21
  end
@@ -58,16 +58,16 @@ EOM
58
58
  remote_sum != digest.hexdigest
59
59
  end
60
60
 
61
- def create_dir(provider, path)
61
+ def create_dir(action_handler, path)
62
62
  if !file_exists?(path)
63
- provider.converge_by "create directory #{path} on #{node['name']}" do
63
+ action_handler.converge_by "create directory #{path} on #{node['name']}" do
64
64
  transport.execute("New-Item #{escape(path)} -Type directory")
65
65
  end
66
66
  end
67
67
  end
68
68
 
69
69
  # Set file attributes { :owner, :group, :rights }
70
- # def set_attributes(provider, path, attributes)
70
+ # def set_attributes(action_handler, path, attributes)
71
71
  # end
72
72
 
73
73
  # Get file attributes { :owner, :group, :rights }
@@ -91,4 +91,4 @@ EOM
91
91
  end
92
92
  end
93
93
  end
94
- end
94
+ end
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Douglas Triggs (<doug@getchef.com>)
4
+ #
5
+ # Copyright (C) 2014, Chef, Inc.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ # This is included in the metal provisioners to proxy from generic requests needed
20
+ # to specific provider actions
21
+ module ChefMetal
22
+ module ProviderActionHandler
23
+ # Implementation of ActionHandler interface
24
+
25
+ def recipe_context
26
+ self.run_context
27
+ end
28
+
29
+ def updated!
30
+ self.new_resource.updated_by_last_action(true)
31
+ end
32
+
33
+ def perform_action(description, &block)
34
+ self.converge_by(description, &block)
35
+ end
36
+
37
+ def debug_name
38
+ self.cookbook_name
39
+ end
40
+ end
41
+ end
@@ -1,5 +1,17 @@
1
1
  module ChefMetal
2
2
  class Provisioner
3
+ # Inflate a provisioner from node information; we don't want to force the
4
+ # driver to figure out what the provisioner really needs, since it varies
5
+ # from provisioner to provisioner.
6
+ #
7
+ # ## Parameters
8
+ # node - node to inflate the provisioner for
9
+ #
10
+ # returns a should return a Privisoner from the information provided
11
+ def self.inflate(node)
12
+ raise "#{self.class} does not override self.inflate"
13
+ end
14
+
3
15
  # Acquire a machine, generally by provisioning it. Returns a Machine
4
16
  # object pointing at the machine, allowing useful actions like setup,
5
17
  # converge, execute, file and directory. The Machine object will have a
@@ -7,7 +19,10 @@ module ChefMetal
7
19
  # different from the original node object).
8
20
  #
9
21
  # ## Parameters
10
- # provider - the provider object that is calling this method.
22
+ # action_handler - the action_handler object that is calling this method; this
23
+ # is generally a provider, but could be anything that can support the
24
+ # interface (i.e., in the case of the test kitchen metal driver for
25
+ # acquiring and destroying VMs).
11
26
  # node - node object (deserialized json) representing this machine. If
12
27
  # the node has a provisioner_options hash in it, these will be used
13
28
  # instead of options provided by the provisioner. TODO compare and
@@ -23,7 +38,7 @@ module ChefMetal
23
38
  #
24
39
  # -- provisioner_url: <provisioner url>
25
40
  #
26
- def acquire_machine(provider, node)
41
+ def acquire_machine(action_handler, node)
27
42
  raise "#{self.class} does not override acquire_machine"
28
43
  end
29
44
 
@@ -42,12 +57,12 @@ module ChefMetal
42
57
 
43
58
  # Delete the given machine (idempotent). Should destroy the machine,
44
59
  # returning things to the state before acquire_machine was called.
45
- def delete_machine(provider, node)
60
+ def delete_machine(action_handler, node)
46
61
  raise "#{self.class} does not override delete_machine"
47
62
  end
48
63
 
49
64
  # Stop the given machine.
50
- def stop_machine(provider, node)
65
+ def stop_machine(action_handler, node)
51
66
  raise "#{self.class} does not override stop_machine"
52
67
  end
53
68
 
@@ -2,6 +2,8 @@ require 'chef_metal/provisioner'
2
2
  require 'chef_metal/aws_credentials'
3
3
  require 'chef_metal/openstack_credentials'
4
4
  require 'chef_metal/version'
5
+ require 'fog/compute'
6
+ require 'fog'
5
7
 
6
8
  module ChefMetal
7
9
  class Provisioner
@@ -17,7 +19,13 @@ module ChefMetal
17
19
  :ssh_timeout => 20
18
20
  }
19
21
 
20
- # Create a new vagrant provisioner.
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.
21
29
  #
22
30
  # ## Parameters
23
31
  # compute_options - hash of options to be passed to Fog::Compute.new
@@ -32,7 +40,9 @@ module ChefMetal
32
40
  # - :create_timeout - the time to wait for the instance to boot to ssh (defaults to 600)
33
41
  # - :start_timeout - the time to wait for the instance to start (defaults to 600)
34
42
  # - :ssh_timeout - the time to wait for ssh to be available if the instance is detected as up (defaults to 20)
35
- def initialize(compute_options)
43
+ # id - the ID in the provisioner_url (fog:PROVIDER:ID)
44
+ def initialize(compute_options, id=nil)
45
+ @compute_options = compute_options
36
46
  @base_bootstrap_options = compute_options.delete(:base_bootstrap_options) || {}
37
47
 
38
48
  case compute_options[:provider]
@@ -46,6 +56,11 @@ module ChefMetal
46
56
  end
47
57
  compute_options[:aws_access_key_id] ||= @aws_credentials.default[:access_key_id]
48
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
49
64
  when 'OpenStack'
50
65
  openstack_credentials = compute_options.delete(:openstack_credentials)
51
66
  if openstack_credentials
@@ -61,7 +76,6 @@ module ChefMetal
61
76
  compute_options[:openstack_tenant] ||= @openstack_credentials.default[:openstack_tenant]
62
77
  end
63
78
  @key_pairs = {}
64
- @compute_options = compute_options
65
79
  @base_bootstrap_options_for = {}
66
80
  end
67
81
 
@@ -82,6 +96,17 @@ module ChefMetal
82
96
  result
83
97
  end
84
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
+
85
110
  # Acquire a machine, generally by provisioning it. Returns a Machine
86
111
  # object pointing at the machine, allowing useful actions like setup,
87
112
  # converge, execute, file and directory. The Machine object will have a
@@ -89,7 +114,11 @@ module ChefMetal
89
114
  # different from the original node object).
90
115
  #
91
116
  # ## Parameters
92
- # provider - the provider object that is calling this method.
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).
93
122
  # node - node object (deserialized json) representing this machine. If
94
123
  # the node has a provisioner_options hash in it, these will be used
95
124
  # instead of options provided by the provisioner. TODO compare and
@@ -116,7 +145,7 @@ module ChefMetal
116
145
  # -- provisioner_url: fog:<relevant_fog_options>
117
146
  # -- server_id: the ID of the server so it can be found again
118
147
  #
119
- def acquire_machine(provider, node)
148
+ def acquire_machine(action_handler, node)
120
149
  # Set up the modified node data
121
150
  provisioner_output = node['normal']['provisioner_output'] || {
122
151
  'provisioner_url' => provisioner_url,
@@ -131,7 +160,7 @@ module ChefMetal
131
160
  provisioner_output['provisioner_version'] ||= ChefMetal::VERSION
132
161
  provisioner_output['creator'] ||= aws_login_info[1]
133
162
  else
134
- raise "Switching providers for a machine is not currently supported! Use machine :destroy and then re-create the machine on the new provider."
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."
135
164
  end
136
165
  end
137
166
 
@@ -152,10 +181,10 @@ module ChefMetal
152
181
  else
153
182
  need_to_create = false
154
183
  if !server.ready?
155
- provider.converge_by "start machine #{node['name']} (#{server.id} on #{provisioner_url})" do
184
+ action_handler.perform_action "start machine #{node['name']} (#{server.id} on #{provisioner_url})" do
156
185
  server.start
157
186
  end
158
- provider.converge_by "wait for machine #{node['name']} (#{server.id} on #{provisioner_url}) to be ready" do
187
+ action_handler.perform_action "wait for machine #{node['name']} (#{server.id} on #{provisioner_url}) to be ready" do
159
188
  wait_until_ready(server, option_for(node, :start_timeout))
160
189
  end
161
190
  else
@@ -168,8 +197,8 @@ module ChefMetal
168
197
 
169
198
  if need_to_create
170
199
  # If the server does not exist, create it
171
- bootstrap_options = bootstrap_options_for(provider.new_resource, node)
172
- bootstrap_options.merge(:name => provider.new_resource.name)
200
+ bootstrap_options = bootstrap_options_for(action_handler.new_resource, node)
201
+ bootstrap_options.merge(:name => action_handler.new_resource.name)
173
202
 
174
203
  start_time = Time.now
175
204
  timeout = option_for(node, :create_timeout)
@@ -177,11 +206,11 @@ module ChefMetal
177
206
  description = [ "create machine #{node['name']} on #{provisioner_url}" ]
178
207
  bootstrap_options.each_pair { |key,value| description << " #{key}: #{value.inspect}" }
179
208
  server = nil
180
- provider.converge_by description do
209
+ action_handler.perform_action description do
181
210
  server = compute.servers.create(bootstrap_options)
182
211
  provisioner_output['server_id'] = server.id
183
212
  # Save quickly in case something goes wrong
184
- save_node(provider, node, provider.new_resource.chef_server)
213
+ save_node(action_handler, node, action_handler.new_resource.chef_server)
185
214
  end
186
215
 
187
216
  if server
@@ -191,22 +220,22 @@ module ChefMetal
191
220
  if bootstrap_options[:floating_ip_pool]
192
221
  Chef::Log.info 'Attaching IP from pool'
193
222
  server.wait_for { ready? }
194
- provider.converge_by "attach floating IP from #{bootstrap_options[:floating_ip_pool]} pool" do
223
+ action_handler.perform_action "attach floating IP from #{bootstrap_options[:floating_ip_pool]} pool" do
195
224
  attach_ip_from_pool(server, bootstrap_options[:floating_ip_pool])
196
225
  end
197
226
  elsif bootstrap_options[:floating_ip]
198
227
  Chef::Log.info 'Attaching given IP'
199
228
  server.wait_for { ready? }
200
- provider.converge_by "attach floating IP #{bootstrap_options[:floating_ip]}" do
229
+ action_handler.perform_action "attach floating IP #{bootstrap_options[:floating_ip]}" do
201
230
  attach_ip(server, bootstrap_options[:floating_ip])
202
231
  end
203
232
  end
204
- provider.converge_by "machine #{node['name']} created as #{server.id} on #{provisioner_url}" do
233
+ action_handler.perform_action "machine #{node['name']} created as #{server.id} on #{provisioner_url}" do
205
234
  end
206
235
  # Wait for the machine to come up and for ssh to start listening
207
236
  transport = nil
208
237
  _self = self
209
- provider.converge_by "wait for machine #{node['name']} to boot" do
238
+ action_handler.perform_action "wait for machine #{node['name']} to boot" do
210
239
  server.wait_for(timeout - (Time.now - start_time)) do
211
240
  if ready?
212
241
  transport ||= _self.transport_for(server)
@@ -232,10 +261,10 @@ module ChefMetal
232
261
  # some other problem. If this is the case, we restart the server
233
262
  # to unstick it. Reboot covers a multitude of sins.
234
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 ..."
235
- provider.converge_by "reboot machine #{node['name']} to try to unstick it" do
264
+ action_handler.perform_action "reboot machine #{node['name']} to try to unstick it" do
236
265
  server.reboot
237
266
  end
238
- provider.converge_by "wait for machine #{node['name']} to be ready after reboot" do
267
+ action_handler.perform_action "wait for machine #{node['name']} to be ready after reboot" do
239
268
  wait_until_ready(server, option_for(node, :start_timeout))
240
269
  end
241
270
  end
@@ -276,21 +305,21 @@ module ChefMetal
276
305
  machine_for(node)
277
306
  end
278
307
 
279
- def delete_machine(provider, node)
308
+ def delete_machine(action_handler, node)
280
309
  if node['normal']['provisioner_output'] && node['normal']['provisioner_output']['server_id']
281
310
  server = compute.servers.get(node['normal']['provisioner_output']['server_id'])
282
- provider.converge_by "destroy machine #{node['name']} (#{node['normal']['provisioner_output']['server_id']} at #{provisioner_url})" do
311
+ action_handler.perform_action "destroy machine #{node['name']} (#{node['normal']['provisioner_output']['server_id']} at #{provisioner_url})" do
283
312
  server.destroy
284
313
  end
285
- convergence_strategy_for(node).delete_chef_objects(provider, node)
314
+ convergence_strategy_for(node).cleanup_convergence(action_handler, node)
286
315
  end
287
316
  end
288
317
 
289
- def stop_machine(provider, node)
318
+ def stop_machine(action_handler, node)
290
319
  # If the machine doesn't exist, we silently do nothing
291
320
  if node['normal']['provisioner_output'] && node['normal']['provisioner_output']['server_id']
292
321
  server = compute.servers.get(node['normal']['provisioner_output']['server_id'])
293
- provider.converge_by "stop machine #{node['name']} (#{server.id} at #{provisioner_url})" do
322
+ action_handler.perform_action "stop machine #{node['name']} (#{server.id} at #{provisioner_url})" do
294
323
  server.stop
295
324
  end
296
325
  end
@@ -302,11 +331,7 @@ module ChefMetal
302
331
 
303
332
 
304
333
  def compute
305
- @compute ||= begin
306
- require 'fog/compute'
307
- require 'fog'
308
- Fog::Compute.new(compute_options)
309
- end
334
+ @compute ||= Fog::Compute.new(compute_options)
310
335
  end
311
336
 
312
337
  def provisioner_url
@@ -499,6 +524,9 @@ module ChefMetal
499
524
  raise "Server #{server.id} has no private or public IP address!"
500
525
  end
501
526
 
527
+ #Enable pty by default
528
+ options[:ssh_pty_enable] = true
529
+
502
530
  ChefMetal::Transport::SSH.new(remote_host, username, ssh_options, options)
503
531
  end
504
532