chef-metal-ssh 0.0.4 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -20,20 +20,70 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
+ * valid machine options: one of the two is required, ip address is boss if both given
24
+
25
+ :ip_address,
26
+ :fqdn - this can be a shortname too as long as it resolves
27
+
28
+
29
+ * valid ssh options
30
+
31
+ :auth_methods,
32
+ :bind_address,
33
+ :compression,
34
+ :compression_level,
35
+ :config,
36
+ :encryption,
37
+ :forward_agent,
38
+ :hmac,
39
+ :host_key,
40
+ :keepalive,
41
+ :keepalive_interval,
42
+ :kex,
43
+ :keys,
44
+ :key_data,
45
+ :languages,
46
+ :logger,
47
+ :paranoid,
48
+ :password,
49
+ :port,
50
+ :proxy,
51
+ :rekey_blocks_limit,
52
+ :rekey_limit,
53
+ :rekey_packet_limit,
54
+ :timeout,
55
+ :verbose,
56
+ :global_known_hosts_file,
57
+ :user_known_hosts_file,
58
+ :host_key_alias,
59
+ :host_name,
60
+ :user,
61
+ :properties,
62
+ :passphrase,
63
+ :keys_only,
64
+ :max_pkt_size,
65
+ :max_win_size, :send_env,
66
+ :use_agent
67
+
68
+ * machine resource example:
69
+
70
+ require 'chef_metal_ssh'
71
+
72
+ with_ssh_cluster("~/metal_ssh")
73
+
23
74
  machine "one" do
24
- action :create
25
- converge true
26
- provisioner ChefMetalSsh::SshProvisioner.new
27
- provisioner_options 'target_ip' => '192.168.33.21',
28
- 'ssh_user' => 'vagrant',
29
- 'ssh_options' => {
30
- 'password' => 'vagrant'
31
- }
75
+ action [:ready, :converge]
76
+ machine_options 'ip_address' => '192.168.33.21',
77
+ 'ssh_options' => {
78
+ 'user' => 'vagrant',
79
+ 'password' => 'vagrant'
80
+ }
32
81
  recipe 'ssh_test::remote1'
33
82
  notifies :create, 'machine[two]'
34
83
  notifies :run, 'execute[run_touch1]'
35
84
  end
36
85
 
86
+
37
87
  To test it out, clone the repo:
38
88
 
39
89
  `git clone https://github.com/double-z/chef-metal-ssh.git`
@@ -0,0 +1,31 @@
1
+ require 'chef/provider/lwrp_base'
2
+ require 'cheffish'
3
+
4
+ class Chef::Provider::SshCluster < Chef::Provider::LWRPBase
5
+
6
+ use_inline_resources
7
+
8
+ def whyrun_supported?
9
+ true
10
+ end
11
+
12
+ action :create do
13
+ the_base_path = new_resource.path
14
+ Cheffish.inline_resource(self, :create) do
15
+ directory the_base_path
16
+ end
17
+ end
18
+
19
+ action :delete do
20
+ the_base_path = new_resource.path
21
+ Cheffish.inline_resource(self, :delete) do
22
+ directory the_base_path do
23
+ action :delete
24
+ end
25
+ end
26
+ end
27
+
28
+ def load_current_resource
29
+ end
30
+
31
+ end
@@ -0,0 +1,78 @@
1
+ # require 'json'
2
+ # require 'chef/provider/lwrp_base'
3
+ # require 'chef_metal/provider_action_handler'
4
+
5
+ # class Chef::Provider::SshTarget < Chef::Provider::LWRPBase
6
+
7
+ # include ChefMetal::ProviderActionHandler
8
+
9
+ # use_inline_resources
10
+
11
+ # def whyrun_supported?
12
+ # true
13
+ # end
14
+
15
+ # action :register do
16
+
17
+ # ip_address = new_resource.name
18
+ # target_registration_file_json = target_registration_file_to_json(new_resource)
19
+ # base_ssh_cluster_path = new_resource.ssh_cluster_path
20
+ # puts
21
+ # puts '::File.join(Chef::Resource::SshCluster.path, "#{ip_address}.json")'
22
+ # puts ::File.join(Chef::Resource::SshCluster.path, "#{ip_address}.json")
23
+
24
+ # unless ::File.exists?(::File.join(Chef::Resource::SshCluster.path, "#{ip_address}.json"))
25
+ # ChefMetal.inline_resource(self) do
26
+ # file ::File.join(Chef::Resource::SshCluster.path, "#{ip_address}.json") do
27
+ # Chef::Log.info(::File.join(Chef::Resource::SshCluster.path, "#{ip_address}.json"))
28
+ # content target_registration_file_json
29
+ # not_if { ::File.exists?(::File.join(Chef::Resource::SshCluster.path, "#{ip_address}.json")) }
30
+ # end
31
+ # end
32
+ # end
33
+
34
+ # end
35
+
36
+ # action :update do
37
+
38
+ # ip_address = new_resource.name
39
+ # target_registration_file_json = target_registration_file_to_json(new_resource)
40
+ # base_ssh_cluster_path = new_resource.ssh_cluster_path
41
+
42
+ # ChefMetal.inline_resource(self) do
43
+ # file ::File.join(Chef::Resource::SshCluster.path, "#{ip_address}.json") do
44
+ # content target_registration_file_json
45
+ # not_if { ::File.exists?(::File.join(Chef::Resource::SshCluster.path, "#{ip_address}.json")) }
46
+ # end
47
+ # end
48
+ # end
49
+
50
+ # def load_current_resource
51
+ # end
52
+
53
+ # end
54
+
55
+ # def target_registration_file_to_json(new_resource)
56
+
57
+ # # Determine contents of registration file
58
+ # target_registration_file_content = {}
59
+ # target_registration_file_content = target_registration_file_content.merge!({ 'available' => new_resource.available })
60
+ # target_registration_file_content = target_registration_file_content.merge!({ 'ip_address' => new_resource.name })
61
+ # target_registration_file_content = target_registration_file_content.merge!({ 'machine_types' => new_resource.machine_types })
62
+ # target_registration_file_content = target_registration_file_content.merge!({ 'mac_address' => new_resource.mac_address }) #if new_resource.mac_address
63
+ # target_registration_file_content = target_registration_file_content.merge!({ 'hostname' => new_resource.hostname }) #if new_resource.hostname
64
+ # target_registration_file_content = target_registration_file_content.merge!({ 'password' => new_resource.password }) #if new_resource.hostname
65
+ # target_registration_file_content = target_registration_file_content.merge!({ 'key' => new_resource.key }) #if new_resource.hostname
66
+ # target_registration_file_content = target_registration_file_content.merge!({ 'subnet' => new_resource.subnet }) #if new_resource.subnet
67
+ # target_registration_file_content = target_registration_file_content.merge!({ 'domain' => new_resource.domain }) #if new_resource.domain
68
+ # target_registration_file_content = target_registration_file_content.merge!({ 'fqdn' => new_resource.fqdn }) #if new_resource.fqdn
69
+ # target_registration_file_content = target_registration_file_content.merge!({ 'memory' => new_resource.memory }) #if new_resource.memory
70
+ # target_registration_file_content = target_registration_file_content.merge!({ 'cpu_count' => new_resource.cpu_count }) #if new_resource.cpu_count
71
+ # target_registration_file_content = target_registration_file_content.merge!({ 'cpu_type' => new_resource.cpu_type }) #if new_resource.cpu_type
72
+ # target_registration_file_content = target_registration_file_content.merge!({ 'arch' => new_resource.arch }) #if new_resource.arch
73
+
74
+ # target_registration_file_json = JSON.parse(target_registration_file_content.to_json)
75
+ # target_registration_file_json_content = JSON.pretty_generate(target_registration_file_json)
76
+ # target_registration_file_json_content
77
+
78
+ # end
@@ -0,0 +1,21 @@
1
+ require 'chef/resource/lwrp_base'
2
+ require 'chef_metal_ssh'
3
+
4
+ class Chef::Resource::SshCluster < Chef::Resource::LWRPBase
5
+ self.resource_name = 'ssh_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
+ run_context.chef_metal.with_driver "ssh:#{path}"
15
+ end
16
+
17
+ # We are not interested in Chef's cloning behavior here.
18
+ def load_prior_resource
19
+ Chef::Log.debug("Overloading #{resource_name}.load_prior_resource with NOOP")
20
+ end
21
+ end
@@ -0,0 +1,71 @@
1
+ # require 'chef/resource/lwrp_base'
2
+
3
+ # class Chef::Resource::SshTarget < Chef::Resource::LWRPBase
4
+
5
+ # self.resource_name = 'ssh_target'
6
+
7
+ # actions :register, :update
8
+
9
+ # default_action :register
10
+
11
+ # attribute :ip_address,
12
+ # :kind_of => [String],
13
+ # :name => true
14
+
15
+ # # TODO, get path from cluster resource
16
+ # attribute :ssh_cluster_path,
17
+ # :kind_of => [String]
18
+
19
+ # attribute :mac_address,
20
+ # :kind_of => [String],
21
+ # :default => ""
22
+
23
+ # attribute :hostname,
24
+ # :kind_of => [String],
25
+ # :default => ""
26
+
27
+ # attribute :password,
28
+ # :kind_of => [String],
29
+ # :default => ""
30
+
31
+ # attribute :key,
32
+ # :kind_of => [String],
33
+ # :default => ""
34
+
35
+ # attribute :subnet,
36
+ # :kind_of => [String],
37
+ # :default => ""
38
+
39
+ # attribute :domain,
40
+ # :kind_of => [String],
41
+ # :default => ""
42
+
43
+ # attribute :fqdn,
44
+ # :kind_of => [String],
45
+ # :default => ""
46
+
47
+ # attribute :available,
48
+ # :kind_of => [String],
49
+ # :default => "true"
50
+
51
+ # attribute :machine_types,
52
+ # :kind_of => [Array],
53
+ # :default => Array.new
54
+
55
+ # attribute :memory,
56
+ # :kind_of => [String],
57
+ # :default => ""
58
+
59
+ # attribute :cpu_count,
60
+ # :kind_of => [String],
61
+ # :default => ""
62
+
63
+ # attribute :cpu_type,
64
+ # :kind_of => [String],
65
+ # :default => ""
66
+
67
+ # attribute :arch,
68
+ # :kind_of => [String],
69
+ # :default => ""
70
+
71
+ # end
@@ -0,0 +1,3 @@
1
+ require 'chef_metal_ssh/ssh_driver'
2
+
3
+ ChefMetal.register_driver_class('ssh', ChefMetalSsh::SshDriver)
@@ -1,2 +1,17 @@
1
1
  require 'chef_metal'
2
- require 'chef_metal_ssh/ssh_provisioner'
2
+ require 'chef/resource/ssh_cluster'
3
+ require 'chef/provider/ssh_cluster'
4
+ require 'chef/resource/ssh_target'
5
+ require 'chef/provider/ssh_target'
6
+ # require 'chef_metal_ssh/machine_registry'
7
+ require 'chef_metal_ssh/ssh_driver'
8
+
9
+ class Chef
10
+ module DSL
11
+ module Recipe
12
+ def with_ssh_cluster(cluster_path, &block)
13
+ with_driver("ssh:#{cluster_path}", &block)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,230 @@
1
+ # require 'chef_metal_ssh'
2
+
3
+ module ChefMetalSsh
4
+ module MachineRegistry
5
+
6
+ def validate_machine_options(node)
7
+
8
+ allowed_new_machine_keys = %w{
9
+ ssh_cluster_path
10
+ machine_types
11
+ mac_address
12
+ ip_address
13
+ subnet
14
+ hostname
15
+ domain
16
+ fqdn
17
+ memory
18
+ cpu_count
19
+ cpu_type
20
+ arch
21
+ }
22
+
23
+ # Validate Machine Options
24
+ new_machine.each { |k,v| raise 'Invalid Machine Option' unless allowed_new_machine_keys.include?(k) }
25
+
26
+ if new_machine['cpu_type'] && ! new_machine['cpu_type'].empty?
27
+ raise "Bad Cpu Type" unless ( new_machine['cpu_type'] == 'intel' || new_machine['cpu_type'] == 'amd' )
28
+ end
29
+
30
+ if new_machine['arch']
31
+ raise "No Such Arch. Either i386 or x86_64" unless ( new_machine['arch'] == 'i386' || new_machine['arch'] == 'x86_64' )
32
+ end
33
+
34
+ end
35
+
36
+ def registered_machine_is_available?(v)
37
+ case v
38
+ when "true"
39
+ true
40
+ when "false"
41
+ false
42
+ when nil
43
+ true
44
+ else
45
+ raise "Available Key is not true or false string"
46
+ end
47
+ end
48
+
49
+ def delete_provider_registration_file(action_handler, registry_file)
50
+ ChefMetal.inline_resource(action_handler) do
51
+ file registry_file do
52
+ action :delete
53
+ end
54
+ end
55
+ end
56
+
57
+ def create_registration_file(action_handler, node, machine_options, new_machine_registry_match = false)
58
+
59
+ # if machine_options.has_key?("available") && machine_options["available"] == "false"
60
+ # raise ""
61
+
62
+ node['normal']['provisioner_options']['machine_options']['available'] = machine_options["available"]
63
+
64
+ machine_registration_file = ::File.join(Chef::Resource::SshCluster.path, "#{machine_options['ip_address']}.json")
65
+
66
+ if new_machine_registry_match
67
+ # delete_registry_file = ::File.join(Chef::Resource::SshCluster.path, "#{machine_options_json['ipaddress']}.json")
68
+ delete_provider_registration_file(action_handler, machine_registration_file)
69
+ end
70
+
71
+ machine_options_json = JSON.pretty_generate(machine_options)
72
+
73
+ ChefMetal.inline_resource(action_handler) do
74
+ file machine_registration_file do
75
+ content machine_options_json
76
+ end
77
+ end
78
+
79
+ end
80
+
81
+ def match_machine_options_to_registered(ssh_cluster_path, machine_options)
82
+
83
+ ssh_cluster_machines = File.join(ssh_cluster_path, "*.json")
84
+
85
+ Dir.glob(ssh_cluster_machines).sort.each do |registered_machine_file|
86
+
87
+ # Not Available By Default.
88
+ # available_registered_machine = false
89
+ matched_machine_json = false unless matched_machine_json
90
+
91
+ ip_address_match = false unless ip_address_match
92
+ mac_address_match = false unless mac_address_match
93
+ fqdn_match = false unless fqdn_match
94
+ hostname_match = false unless hostname_match
95
+ node_name_match = false unless node_name_match
96
+
97
+
98
+ # Fail By Default.
99
+ will_work = false
100
+ not_gonna_work = false
101
+ # But Assume is Available till told its not
102
+ available_registered_machine = true unless (available_registered_machine == false)
103
+
104
+ registered_machine_json = JSON.parse(File.read(registered_machine_file))
105
+
106
+ ip_address_match = (registered_machine_json['ip_address'] == machine_options['ip_address']) # rescue false
107
+ mac_address_match = (registered_machine_json['mac_address'] == machine_options['mac_address']) # rescue false
108
+ fqdn_match = (registered_machine_json['fqdn'] == machine_options['fqdn']) # rescue false
109
+ hostname_match = (registered_machine_json['hostname'] == machine_options['hostname']) # rescue false
110
+
111
+
112
+ registered_machine_json.each_pair do |k,v|
113
+
114
+ # Check if key name is 'available' and if key value is true or false
115
+ if k == "available"
116
+
117
+ available_registered_machine =
118
+ registered_machine_is_available?(v) if available_registered_machine
119
+
120
+ elsif k == "node_name"
121
+ if v == machine_options[k] && (!v.nil? || !v.empty?)
122
+ node_name_match = true
123
+ end
124
+ else
125
+ if machine_options.has_key?(k)
126
+ case v
127
+ when String
128
+ # see if registered_machine value equals value in machine_options
129
+ if v == machine_options[k] && !v.empty?
130
+ will_work = true
131
+ else
132
+ not_gonna_work = true unless (v.empty? ||
133
+ machine_options[k].empty? ||
134
+ k == "password" )
135
+ end
136
+ when Array
137
+ Array(machine_options[k]).each do |sv|
138
+ if v.include?(sv)
139
+ will_work = true
140
+ else
141
+ not_gonna_work = true
142
+ end
143
+ end
144
+ when Hash
145
+ else
146
+ Chef::Log.debug "NOTHING?"
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ # end
153
+ # else
154
+ # puts "already registered"
155
+ # end
156
+
157
+ #
158
+ # So we looped through a registered machine and:
159
+ #
160
+ # - we matched
161
+ #
162
+ # - we fatally matched
163
+ #
164
+ # - or we got nothin and move on to the next loop
165
+ #
166
+
167
+ if (will_work == true) && (not_gonna_work == false) && (available_registered_machine == true)
168
+ matched_machine_json = true
169
+ # break
170
+ end
171
+
172
+ error_out = false unless error_out
173
+ error_message = 'We Matched' unless error_message
174
+ if ip_address_match
175
+ error_out = true unless available_registered_machine
176
+ error_message << ' IP,'
177
+ end
178
+
179
+ if fqdn_match
180
+ error_out = true unless available_registered_machine
181
+ error_message << ' FQDN,'
182
+ end
183
+
184
+ if mac_address_match
185
+ error_out = true unless available_registered_machine
186
+ error_message << ' MAC ADDRESS,'
187
+ end
188
+
189
+ if hostname_match
190
+ error_out = true unless available_registered_machine
191
+ error_message << ' HOSTNAME,'
192
+ end
193
+
194
+ if node_name_match
195
+ error_out = true unless available_registered_machine
196
+ error_message << ' NODE NAME,'
197
+ end
198
+
199
+ if error_out && !available_registered_machine
200
+ error_message << ' but they already exist.'
201
+ error_message << ' Aborting to avoid inconsistencies.'
202
+ raise error_message
203
+ end
204
+
205
+ ##
206
+ # did we decide it will work?
207
+ if matched_machine_json
208
+ # Strip out any erroneous empty hash keys
209
+ # so we don't overwrite non-empty registered values
210
+ # with empty passed values
211
+ stripped_machine_json = JSON.parse(machine_options.to_json).delete_if {
212
+ |k, v| v.empty? unless k == 'machine_types' }
213
+
214
+ new_registration_json = registered_machine_json.merge!(stripped_machine_json)
215
+
216
+ # We're off the market
217
+ set_available_to_false = { "available" => "false" }
218
+ @matched_machine_json = new_registration_json.merge!(JSON.parse(set_available_to_false.to_json))
219
+
220
+ return @matched_machine_json
221
+ break
222
+ else
223
+ # wah wah wah
224
+ @matched_machine_json = false
225
+ end
226
+ end
227
+ return @matched_machine_json
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,388 @@
1
+ require 'json'
2
+ require 'resolv'
3
+ require 'chef_metal/driver'
4
+ require 'chef_metal/version'
5
+ require 'chef_metal/machine/basic_machine'
6
+ require 'chef_metal/machine/unix_machine'
7
+ require 'chef_metal/convergence_strategy/install_cached'
8
+ require 'chef_metal/transport/ssh'
9
+ require 'chef_metal_ssh/machine_registry'
10
+ require 'chef_metal_ssh/version'
11
+ require 'chef/resource/ssh_cluster'
12
+ require 'chef/provider/ssh_cluster'
13
+ module ChefMetalSsh
14
+ # Provisions machines with ssh.
15
+ class SshDriver < ChefMetal::Driver
16
+
17
+ include ChefMetalSsh::MachineRegistry
18
+
19
+ # ## Parameters
20
+ # cluster_path - path to the directory containing the vagrant files, which
21
+ # should have been created with the vagrant_cluster resource.
22
+
23
+ # Create a new ssh driver.
24
+ #
25
+ # ## Parameters
26
+ # cluster_path - path to the directory containing the vagrant files, which
27
+ # should have been created with the vagrant_cluster resource.
28
+ def initialize(driver_url, config)
29
+ super
30
+ scheme, cluster_path = driver_url.split(':', 2)
31
+ @cluster_path = cluster_path
32
+ end
33
+
34
+ attr_reader :cluster_path
35
+
36
+ def self.from_url(driver_url, config)
37
+ SshDriver.new(driver_url, config)
38
+ end
39
+
40
+ def self.canonicalize_url(driver_url, config)
41
+ scheme, cluster_path = driver_url.split(':', 2)
42
+ cluster_path = File.expand_path(cluster_path || File.join(Chef::Config.config_dir, 'metal_ssh'))
43
+ "ssh:#{cluster_path}"
44
+ end
45
+ # Acquire a machine, generally by provisioning it. Returns a Machine
46
+ # object pointing at the machine, allowing useful actions like setup,
47
+ # converge, execute, file and directory. The Machine object will have a
48
+ # "node" property which must be saved to the server (if it is any
49
+ # different from the original node object).
50
+ #
51
+ # ## Parameters
52
+ # action_handler - the action_handler object that provides context.
53
+ # node - node object (deserialized json) representing this machine. If
54
+ # the node has a provisioner_options hash in it, these will be used
55
+ # instead of options provided by the provisioner. TODO compare and
56
+ # fail if different?
57
+ # node will have node['normal']['provisioner_options'] in it with any options.
58
+ # It is a hash with this format:
59
+ #
60
+ # -- provisioner_url: ssh:<@target_host>
61
+ # -- target_ip: the IP address of the target machine - IP or FQDN is required
62
+ # -- target_fqdn: The Resolvable name of the target machine - IP or FQDN is required
63
+ # -- ssh_user: the user to ssh as
64
+ # -- ssh_options: options to pass the ssh command. available options are here - https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh.rb#L61
65
+ #
66
+ # node['normal']['provisioner_output'] will be populated with information
67
+ # about the created machine. For ssh, it is a hash with this
68
+ # format:
69
+ #
70
+ # -- provisioner_url: ssh:<@target_host>
71
+ # -- name: container name
72
+ #
73
+ def allocate_machine(action_handler, machine_spec, machine_options)
74
+ # TODO verify that the existing provisioner_url in the node is the same as ours
75
+ ensure_ssh_cluster(action_handler)
76
+ target_name = machine_spec.name
77
+ target_file_path = File.join(cluster_path, "#{machine_spec.name}.json")
78
+
79
+
80
+ # Chef::Log.debug("======================================>")
81
+ # Chef::Log.debug("acquire_machine - provisioner_options.inspect: #{provisioner_options.inspect}")
82
+ # Chef::Log.debug("======================================>")
83
+
84
+ @target_host = get_target_connection_method(machine_options)
85
+
86
+ # Chef::Log.debug("======================================>")
87
+ # Chef::Log.debug("acquire_machine - target_host: #{@target_host}")
88
+ # Chef::Log.debug("======================================>")
89
+
90
+ # Set up Provisioner Output
91
+ # TODO - make url the chef server url path? maybe disk path if zero?
92
+ machine_spec.location = {
93
+ 'driver_url' => driver_url,
94
+ 'driver_version' => ChefMetalSsh::VERSION,
95
+ 'target_name' => target_name,
96
+ 'target_file_path' => target_file_path,
97
+ 'allocated_at' => Time.now.utc.to_s
98
+ }
99
+
100
+ # Chef::Log.debug("======================================>")
101
+ # Chef::Log.debug("acquire_machine - machine_spec.inspect: #{machine_spec.inspect}")
102
+ # Chef::Log.debug("======================================>")
103
+
104
+
105
+ end
106
+
107
+ def ready_machine(action_handler, machine_spec, machine_options)
108
+ machine_for(machine_spec, machine_options)
109
+ end
110
+
111
+ def connect_to_machine(machine_spec, machine_options)
112
+ machine_for(machine_spec, machine_options)
113
+ end
114
+ # # Connect to machine without acquiring it
115
+ # def connect_to_machine(node)
116
+
117
+ # # Get Password If Needs To Be Got
118
+ # provisioner_url = node['normal']['provisioner_output']['provisioner_url']
119
+ # provisioner_path = provisioner_url.split(':', 2)[1].sub(/^\/\//, "")
120
+ # existing_machine_options = JSON.parse(File.read(provisioner_path)) # rescue nil
121
+ # node_machine_options = node['normal']['provisioner_options']['machine_options']
122
+ # unless node_machine_options['password']
123
+ # Chef::Log.debug "Password Not in Provisioner Machine Options"
124
+ # node_machine_options['password'] = existing_machine_options['password'] ?
125
+ # existing_machine_options['password'] : nil
126
+ # end
127
+
128
+ # # Get Some
129
+ # machine_for(machine_spec, machine_options)
130
+ # end
131
+
132
+ # def delete_machine(action_handler, node)
133
+ # convergence_strategy_for(node).delete_chef_objects(action_handler, node)
134
+ # end
135
+
136
+ # def stop_machine(action_handler, node)
137
+ # #
138
+ # # What to do What to do.
139
+ # #
140
+ # # On one level there's really only one thing to do here,
141
+ # # shellout and halt, or shutdown -h now,
142
+ # # maybe provide abitily to pass some shutdown options
143
+ # #
144
+ # # But be vewwy vewwy careful:
145
+ # #
146
+ # # you better have console...
147
+ # # or be close to your datacenter
148
+ # #
149
+ # end
150
+
151
+ # def restart_machine(action_handler, node)
152
+ # # Full Restart, POST BIOS and all
153
+ # end
154
+
155
+ # def reload_machine(action_handler, node)
156
+ # # Use `kexec` here to skip POST and BIOS and all that noise.
157
+ # end
158
+
159
+ def driver_url
160
+ "ssh:#{cluster_path}"
161
+ end
162
+
163
+
164
+ protected
165
+
166
+ def ensure_ssh_cluster(action_handler)
167
+ _cluster_path = cluster_path
168
+ ChefMetal.inline_resource(action_handler) do
169
+ ssh_cluster _cluster_path
170
+ end
171
+ end
172
+
173
+ def get_target_connection_method(given_machine_options)
174
+
175
+ machine_options = symbolize_keys(given_machine_options)
176
+
177
+ target_ip = machine_options[:ip_address] || false
178
+ target_fqdn = machine_options[:fqdn] || false
179
+
180
+ raise "no @target_host, target_ip or target_fqdn given" unless
181
+ ( @target_host || target_ip || target_fqdn )
182
+
183
+ remote_host = ''
184
+ if @target_host
185
+ remote_host = @target_host
186
+ elsif target_ip
187
+ raise 'Invalid IP' unless ( target_ip =~ Resolv::IPv4::Regex ||
188
+ target_ip =~ Resolv::IPv6::Regex )
189
+ remote_host = target_ip
190
+ elsif target_fqdn
191
+ rh = Resolv::Hosts.new
192
+ rd = Resolv.new
193
+
194
+ begin
195
+ rh.getaddress(target_fqdn)
196
+ in_hosts_file = true
197
+ rescue
198
+ in_hosts_file = false
199
+ end
200
+
201
+ begin
202
+ rd.getaddress(target_fqdn)
203
+ in_dns = true
204
+ rescue
205
+ in_dns = false
206
+ end
207
+
208
+ raise 'Unresolvable Hostname' unless ( in_hosts_file || in_dns )
209
+ remote_host = target_fqdn
210
+ else
211
+ raise "aint got no target yo, that dog dont hunt"
212
+ end
213
+
214
+ Chef::Log.debug("======================================>")
215
+ Chef::Log.debug("get_target_connection_method - remote_host: #{remote_host}")
216
+ Chef::Log.debug("======================================>")
217
+
218
+ remote_host
219
+ end
220
+
221
+ def machine_for(machine_spec, machine_options)
222
+ # ChefMetal::Machine::UnixMachine.new(node, transport_for(node), convergence_strategy_for(node))
223
+ ChefMetal::Machine::UnixMachine.new(machine_spec,
224
+ create_ssh_transport(machine_options),
225
+ convergence_strategy_for(machine_spec, machine_options))
226
+ end
227
+
228
+ def transport_for(machine_options)
229
+ create_ssh_transport(machine_options)
230
+ end
231
+
232
+ def convergence_strategy_for(machine_spec, machine_options)
233
+ @unix_convergence_strategy ||= begin
234
+ ChefMetal::ConvergenceStrategy::InstallCached.new(machine_options[:convergence_options],
235
+ config)
236
+ end
237
+ end
238
+
239
+ def symbolize_keys(hash)
240
+ hash.inject({}){|result, (key, value)|
241
+
242
+ new_key = case key
243
+ when String
244
+ key.to_sym
245
+ else
246
+ key
247
+ end
248
+
249
+ new_value = case value
250
+ when Hash
251
+ symbolize_keys(value)
252
+ else
253
+ value
254
+ end
255
+
256
+ result[new_key] = new_value
257
+ result
258
+
259
+ }
260
+ end
261
+
262
+ # Setup Ssh
263
+ def create_ssh_transport(machine_options)
264
+ machine_ssh_options = machine_options['ssh_options']
265
+
266
+ ##
267
+ # Ssh Username
268
+ username = machine_ssh_options['user'] || 'root'
269
+
270
+ Chef::Log.debug("======================================>")
271
+ Chef::Log.debug("create_ssh_transport - username: #{username}")
272
+ Chef::Log.debug("======================================>")
273
+
274
+ ##
275
+ # Ssh Password
276
+ ssh_pass = machine_ssh_options['password'] || false
277
+ if ssh_pass
278
+ ssh_pass_hash = Hash.new
279
+ ssh_pass_hash = { 'password' => ssh_pass }
280
+ else
281
+ Chef::Log.info("NO PASSWORD")
282
+ end
283
+
284
+ ##
285
+ # Ssh Key
286
+ ssh_keys = []
287
+ if machine_ssh_options['keys']
288
+ if machine_ssh_options['keys'].kind_of?(Array)
289
+ machine_ssh_options['keys'].each do |key|
290
+ ssh_keys << key
291
+ end
292
+ elsif machine_ssh_options['keys'].kind_of?(String)
293
+ ssh_keys << machine_ssh_options['keys']
294
+ else
295
+ ssh_keys = false
296
+ end
297
+ end
298
+
299
+ if ssh_keys
300
+ ssh_key_hash = Hash.new
301
+ ssh_key_hash = { 'keys' => ssh_keys }
302
+ end
303
+
304
+ Chef::Log.info("======================================>")
305
+ if ssh_pass
306
+ Chef::Log.info("create_ssh_transport - ssh_pass: #{ssh_pass_hash.inspect}")
307
+ elsif ssh_keys
308
+ Chef::Log.info("create_ssh_transport - ssh_key: #{ssh_keys.inpsect}")
309
+ else
310
+ Chef::Log.info("create_ssh_transport - no ssh_pass or ssh_key given")
311
+ end
312
+ Chef::Log.info("======================================>")
313
+
314
+ raise "no ssh_pass or ssh_key given" unless ( ssh_pass || ssh_keys )
315
+
316
+ machine_ssh_options = machine_ssh_options.merge!(ssh_pass_hash)
317
+ machine_ssh_options = machine_ssh_options.merge!(ssh_key_hash)
318
+
319
+ ##
320
+ # Valid Ssh Options
321
+ valid_ssh_options = [
322
+ :auth_methods, :bind_address, :compression, :compression_level, :config,
323
+ :encryption, :forward_agent, :hmac, :host_key,
324
+ :keepalive, :keepalive_interval, :kex, :keys, :key_data,
325
+ :languages, :logger, :paranoid, :password, :port, :proxy,
326
+ :rekey_blocks_limit,:rekey_limit, :rekey_packet_limit, :timeout, :verbose,
327
+ :global_known_hosts_file, :user_known_hosts_file, :host_key_alias,
328
+ :host_name, :user, :properties, :passphrase, :keys_only, :max_pkt_size,
329
+ :max_win_size, :send_env, :use_agent
330
+ ]
331
+
332
+ ##
333
+ # Ssh Options
334
+ ssh_options = symbolize_keys(machine_ssh_options)
335
+
336
+ # Validate Ssh Options
337
+ ssh_options.each { |k,v| raise 'Invalid Shh Option' unless valid_ssh_options.include?(k) }
338
+
339
+ Chef::Log.debug "======================================>"
340
+ Chef::Log.debug "create_ssh_transport - ssh_options: #{ssh_options.inspect}"
341
+ Chef::Log.debug "======================================>"
342
+
343
+ # Now That We Validated Options, Lets Get Our Target
344
+ @target_host = get_target_connection_method(machine_ssh_options)
345
+
346
+ # Make Sure We Can Connect
347
+ begin
348
+ ssh = Net::SSH.start(@target_host, username, ssh_options)
349
+ ssh.close
350
+ Chef::Log.debug("======================================>")
351
+ Chef::Log.debug("ABLE to Connect to #{@target_host} using #{username} and #{ssh_options.inspect}")
352
+ Chef::Log.debug("======================================>")
353
+ rescue
354
+ Chef::Log.debug("======================================>")
355
+ Chef::Log.debug("UNABLE to Connect to #{@target_host} using #{username} and #{ssh_options.inspect}")
356
+ Chef::Log.debug("======================================>")
357
+ raise "UNABLE to Connect to #{@target_host} using #{username} and #{ssh_options.inspect}"
358
+ end
359
+
360
+ ##
361
+ # Ssh Additional Options
362
+ options = {}
363
+
364
+ #Enable pty by default
365
+ options[:ssh_pty_enable] = true
366
+
367
+ # If we not root use sudo
368
+ if username != 'root'
369
+ options[:prefix] = 'sudo '
370
+ end
371
+
372
+ Chef::Log.debug("======================================>")
373
+ Chef::Log.debug("create_ssh_transport - options: #{options.inspect}")
374
+ Chef::Log.debug("======================================>")
375
+
376
+ ChefMetal::Transport::SSH.new(@target_host, username, ssh_options, options, config)
377
+
378
+ # We Duped It So Now We Can Zero the Node Attr. So Not Saved On Server
379
+ # provisioner_options['machine_options']['password'] =
380
+ # nil if provisioner_options['machine_options']['password']
381
+
382
+ # provisioner_options['ssh_options']['password'] =
383
+ # nil if provisioner_options['ssh_options']['password']
384
+
385
+ end
386
+
387
+ end
388
+ end
@@ -1,3 +1,3 @@
1
1
  module ChefMetalSsh
2
- VERSION = "0.0.4"
2
+ VERSION = "0.1.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-metal-ssh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-04-08 00:00:00.000000000 Z
12
+ date: 2014-10-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: chef
16
- requirement: &13107560 !ruby/object:Gem::Requirement
16
+ requirement: &22050800 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,21 +21,21 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *13107560
24
+ version_requirements: *22050800
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: chef-metal
27
- requirement: &13163400 !ruby/object:Gem::Requirement
27
+ requirement: &22049540 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
31
31
  - !ruby/object:Gem::Version
32
- version: '0.6'
32
+ version: '0.12'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *13163400
35
+ version_requirements: *22049540
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: bundler
38
- requirement: &13161940 !ruby/object:Gem::Requirement
38
+ requirement: &22068960 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '1.5'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *13161940
46
+ version_requirements: *22068960
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &13160480 !ruby/object:Gem::Requirement
49
+ requirement: &22068460 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *13160480
57
+ version_requirements: *22068460
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rake
60
- requirement: &13158020 !ruby/object:Gem::Requirement
60
+ requirement: &22067540 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *13158020
68
+ version_requirements: *22067540
69
69
  description: Provisioner for managing servers using ssh in Chef Metal.
70
70
  email: zackzondlo@gmail.com
71
71
  executables: []
@@ -77,10 +77,15 @@ files:
77
77
  - Rakefile
78
78
  - LICENSE.txt
79
79
  - README.md
80
- - lib/chef_metal/provisioner_init/ssh_init.rb
80
+ - lib/chef/provider/ssh_cluster.rb
81
+ - lib/chef/provider/ssh_target.rb
82
+ - lib/chef/resource/ssh_cluster.rb
83
+ - lib/chef/resource/ssh_target.rb
84
+ - lib/chef_metal/driver_init/ssh.rb
81
85
  - lib/chef_metal_ssh.rb
82
- - lib/chef_metal_ssh/ssh_provisioner.rb
83
86
  - lib/chef_metal_ssh/version.rb
87
+ - lib/chef_metal_ssh/ssh_driver.rb
88
+ - lib/chef_metal_ssh/machine_registry.rb
84
89
  homepage: https://github.com/double-z/chef-metal-ssh
85
90
  licenses: []
86
91
  post_install_message:
@@ -1,4 +0,0 @@
1
- require 'chef_metal_ssh/ssh_provisioner'
2
-
3
- ChefMetal.add_registered_provisioner_class("ssh",
4
- ChefMetalSsh::SshProvisioner)
@@ -1,300 +0,0 @@
1
- require 'resolv'
2
- require 'chef_metal/provisioner'
3
- require 'chef_metal/version'
4
- require 'chef_metal/machine/basic_machine'
5
- require 'chef_metal/machine/unix_machine'
6
- require 'chef_metal/convergence_strategy/install_cached'
7
- require 'chef_metal/transport/ssh'
8
-
9
- module ChefMetalSsh
10
- # Provisions machines with ssh.
11
- class SshProvisioner < ChefMetal::Provisioner
12
-
13
- def initialize()
14
- end
15
-
16
- # Acquire a machine, generally by provisioning it. Returns a Machine
17
- # object pointing at the machine, allowing useful actions like setup,
18
- # converge, execute, file and directory. The Machine object will have a
19
- # "node" property which must be saved to the server (if it is any
20
- # different from the original node object).
21
- #
22
- # ## Parameters
23
- # action_handler - the action_handler object that provides context.
24
- # node - node object (deserialized json) representing this machine. If
25
- # the node has a provisioner_options hash in it, these will be used
26
- # instead of options provided by the provisioner. TODO compare and
27
- # fail if different?
28
- # node will have node['normal']['provisioner_options'] in it with any options.
29
- # It is a hash with this format:
30
- #
31
- # -- provisioner_url: ssh:<@target_host>
32
- # -- target_ip: the IP address of the target machine - IP or FQDN is required
33
- # -- target_fqdn: The Resolvable name of the target machine - IP or FQDN is required
34
- # -- ssh_user: the user to ssh as
35
- # -- ssh_options: options to pass the ssh command. available options are here - https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh.rb#L61
36
- #
37
- # node['normal']['provisioner_output'] will be populated with information
38
- # about the created machine. For ssh, it is a hash with this
39
- # format:
40
- #
41
- # -- provisioner_url: ssh:<@target_host>
42
- # -- name: container name
43
- #
44
- def acquire_machine(action_handler, node)
45
- # TODO verify that the existing provisioner_url in the node is the same as ours
46
-
47
- # Set up the modified node data
48
- provisioner_options = node['normal']['provisioner_options']
49
-
50
- Chef::Log.debug("======================================>")
51
- Chef::Log.debug("acquire_machine - provisioner_options.inspect: #{provisioner_options.inspect}")
52
- Chef::Log.debug("======================================>")
53
-
54
- @target_host = get_target_connection_method(node)
55
-
56
- Chef::Log.debug("======================================>")
57
- Chef::Log.debug("acquire_machine - target_host: #{@target_host}")
58
- Chef::Log.debug("======================================>")
59
-
60
- # Set up Provisioner Output
61
- # TODO - make url the chef server url path? maybe disk path if zero?
62
- provisioner_output = node['normal']['provisioner_output'] || {
63
- 'provisioner_url' => "ssh:#{@target_host}",
64
- 'name' => node['name']
65
- }
66
-
67
- Chef::Log.debug("======================================>")
68
- Chef::Log.debug("acquire_machine - provisioner_output.inspect: #{provisioner_output.inspect}")
69
- Chef::Log.debug("======================================>")
70
-
71
- node['normal']['provisioner_output'] = provisioner_output
72
-
73
- # Create machine object for callers to use
74
- machine_for(node)
75
- end
76
-
77
- # Connect to machine without acquiring it
78
- def connect_to_machine(node)
79
- @target_host = get_target_connection_method(node)
80
-
81
- Chef::Log.debug("======================================>")
82
- Chef::Log.debug("connect_to_machine - target_host: #{@target_host}")
83
- Chef::Log.debug("======================================>")
84
-
85
- machine_for(node)
86
- end
87
-
88
- def delete_machine(action_handler, node)
89
- convergence_strategy_for(node).delete_chef_objects(action_handler, node)
90
- end
91
-
92
- def stop_machine(action_handler, node)
93
- # What to do What to do.
94
- # On one level there's really only one thing to do here,
95
- # shellout and halt, or shutdown -h now,
96
- # maybe provide abitily to pass some shutdown options
97
- # But be vewwy vewwy careful, you better have console,
98
- # or be close to your datacenter
99
- true
100
- end
101
-
102
- def restart_machine(action_handler, node)
103
- # Full Restart, POST BIOS and all
104
- end
105
-
106
- def reload_machine(action_handler, node)
107
- # Use `kexec` here to skip POST and BIOS and all that noise.
108
- end
109
-
110
- # Not meant to be part of public interface
111
- def transport_for(node)
112
- create_ssh_transport(node)
113
- end
114
-
115
- protected
116
-
117
- def get_target_connection_method(node)
118
-
119
- provisioner_options = node['normal']['provisioner_options']
120
-
121
- target_ip = ''
122
- target_ip = provisioner_options['target_ip'] || nil
123
-
124
- target_fqdn = ''
125
- target_fqdn = provisioner_options['target_fqdn'] || nil
126
-
127
- remote_host = ''
128
- if @target_host
129
- remote_host = @target_host
130
- elsif target_ip
131
- raise 'Invalid IP' unless ( target_ip =~ Resolv::IPv4::Regex ||
132
- target_ip =~ Resolv::IPv6::Regex )
133
- remote_host = target_ip
134
- elsif target_fqdn
135
- rh = Resolv::Hosts.new
136
- rd = Resolv.new
137
-
138
- begin
139
- rh.getaddress(target_fqdn)
140
- in_hosts_file = true
141
- rescue
142
- in_hosts_file = false
143
- end
144
-
145
- begin
146
- rd.getaddress(target_fqdn)
147
- in_dns = true
148
- rescue
149
- in_dns = false
150
- end
151
-
152
- raise 'Unresolvable Hostname' unless ( in_hosts_file || in_dns )
153
- remote_host = target_fqdn
154
- else
155
- raise "aint got no target yo, that dog dont hunt"
156
- end
157
-
158
- Chef::Log.debug("======================================>")
159
- Chef::Log.debug("get_target_connection_method - remote_host: #{remote_host}")
160
- Chef::Log.debug("======================================>")
161
-
162
- remote_host
163
- end
164
-
165
- def machine_for(node)
166
- ChefMetal::Machine::UnixMachine.new(node, transport_for(node), convergence_strategy_for(node))
167
- end
168
-
169
- def convergence_strategy_for(node)
170
- @convergence_strategy ||= begin
171
- ChefMetal::ConvergenceStrategy::InstallCached.new
172
- end
173
- end
174
-
175
- def symbolize_keys(hash)
176
- hash.inject({}){|result, (key, value)|
177
- new_key = case key
178
- when String then key.to_sym
179
- else key
180
- end
181
- new_value = case value
182
- when Hash then symbolize_keys(value)
183
- else value
184
- end
185
- result[new_key] = new_value
186
- result
187
- }
188
- end
189
-
190
- # Setup Ssh
191
- def create_ssh_transport(node)
192
-
193
- provisioner_options = node['normal']['provisioner_options']
194
- provisioner_ssh_options = provisioner_options['ssh_options']
195
-
196
- Chef::Log.debug("======================================>")
197
- Chef::Log.debug("create_ssh_transport - target_host: #{@target_host}")
198
- Chef::Log.debug("======================================>")
199
-
200
- ##
201
- # Ssh Username
202
- username = ''
203
- username = provisioner_options['ssh_user'] || 'vagrant'
204
-
205
- Chef::Log.debug("======================================>")
206
- Chef::Log.debug("create_ssh_transport - username: #{username}")
207
- Chef::Log.debug("======================================>")
208
-
209
- ##
210
- # Ssh Password
211
- ssh_pass = false
212
- ssh_pass = provisioner_ssh_options['password'] if provisioner_ssh_options['password']
213
- # ssh_pass = ssh_options[:password] if ssh_options[:password]
214
-
215
- ##
216
- # Ssh Key
217
- ssh_key = false
218
- ssh_key = provisioner_ssh_options['host_key'] if provisioner_ssh_options['host_key']
219
-
220
- Chef::Log.debug("======================================>")
221
- if ssh_pass
222
- Chef::Log.debug("create_ssh_transport - ssh_pass: #{ssh_pass}")
223
- elsif ssh_key
224
- Chef::Log.debug("create_ssh_transport - ssh_key: #{ssh_key}")
225
- else
226
- Chef::Log.debug("create_ssh_transport - no ssh_pass or ssh_key given")
227
- end
228
- Chef::Log.debug("======================================>")
229
-
230
- raise "no ssh_pass or ssh_key given" unless ( ssh_pass || ssh_key )
231
- ##
232
- # Ssh Main Options
233
- valid_ssh_options = [
234
- :auth_methods, :bind_address, :compression, :compression_level, :config,
235
- :encryption, :forward_agent, :hmac, :host_key,
236
- :keepalive, :keepalive_interval, :kex, :keys, :key_data,
237
- :languages, :logger, :paranoid, :password, :port, :proxy,
238
- :rekey_blocks_limit,:rekey_limit, :rekey_packet_limit, :timeout, :verbose,
239
- :global_known_hosts_file, :user_known_hosts_file, :host_key_alias,
240
- :host_name, :user, :properties, :passphrase, :keys_only, :max_pkt_size,
241
- :max_win_size, :send_env, :use_agent
242
- ]
243
-
244
- ##
245
- # Ssh Main Options
246
- ssh_options = symbolize_keys(provisioner_ssh_options)
247
-
248
- # Validate Ssh Options
249
- ssh_options.each { |k,v| raise 'Invalid Shh Option' unless valid_ssh_options.include?(k) }
250
-
251
- ##
252
- # Ssh Main Options
253
- # ssh_options = symbolize_keys(provisioner_ssh_options)
254
- # ssh_options = {
255
- # # TODO create a user known hosts file
256
- # # :user_known_hosts_file => provisioner_options['ssh_connect_options']['UserKnownHostsFile'],
257
- # # :paranoid => true,
258
- # # :auth_methods => [ 'publickey' ],
259
- # :keys_only => false,
260
- # :host_key => ssh_key,
261
- # :password => ssh_pass
262
- # }
263
-
264
- Chef::Log.debug("======================================>")
265
- Chef::Log.debug("create_ssh_transport - ssh_options: #{ssh_options.inspect}")
266
- Chef::Log.debug("======================================>")
267
-
268
- # Make Sure We Can Connect
269
- begin
270
- ssh = Net::SSH.start(@target_host, username, ssh_options)
271
- ssh.close
272
- Chef::Log.debug("======================================>")
273
- Chef::Log.debug("ABLE to Connect to #{@target_host} using #{username} and #{ssh_options.inspect}")
274
- Chef::Log.debug("======================================>")
275
- rescue
276
- Chef::Log.debug("======================================>")
277
- Chef::Log.debug("UNABLE to Connect to #{@target_host} using #{username} and #{ssh_options.inspect}")
278
- Chef::Log.debug("======================================>")
279
- raise "UNABLE to Connect to #{@target_host} using #{username} and #{ssh_options.inspect}"
280
- end
281
-
282
- ##
283
- # Ssh Additional Options
284
- options = {}
285
- #Enable pty by default
286
- options[:ssh_pty_enable] = true
287
-
288
- if username != 'root'
289
- options[:prefix] = 'sudo '
290
- end
291
-
292
- Chef::Log.debug("======================================>")
293
- Chef::Log.debug("create_ssh_transport - options: #{options.inspect}")
294
- Chef::Log.debug("======================================>")
295
-
296
- ChefMetal::Transport::SSH.new(@target_host, username, ssh_options, options)
297
- end
298
-
299
- end
300
- end