chef-metal-ssh 0.0.4 → 0.1.2

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.
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