class Chef::Knife::Cloud::SshBootstrapProtocol
Public Class Methods
new(config)
click to toggle source
Calls superclass method
Chef::Knife::Cloud::BootstrapProtocol::new
# File lib/chef/knife/cloud/chefbootstrap/ssh_bootstrap_protocol.rb, line 29 def initialize(config) @bootstrap = Chef::Knife::Bootstrap.new super end
Public Instance Methods
configure_ssh_gateway(ssh_gateway)
click to toggle source
# File lib/chef/knife/cloud/chefbootstrap/ssh_bootstrap_protocol.rb, line 145 def configure_ssh_gateway(ssh_gateway) gw_host, gw_user = ssh_gateway.split("@").reverse gw_host, gw_port = gw_host.split(":") gateway_options = { port: gw_port || 22 } # Load the SSH config for the SSH gateway host. # Set the gateway user if it was not part of the # SSH gateway string, and use any configured # SSH keys. ssh_gateway_config = Net::SSH::Config.for(gw_host) gw_user ||= ssh_gateway_config[:user] # Always use the gateway keys from the SSH Config gateway_keys = ssh_gateway_config[:keys] # Use the keys specificed on the command line if available (overrides SSH Config) if config[:ssh_gateway_identity] gateway_keys = Array(config[:ssh_gateway_identity]) end unless gateway_keys.nil? gateway_options[:keys] = gateway_keys end Net::SSH::Gateway.new(gw_host, gw_user, gateway_options) end
get_ssh_gateway_for(hostname)
click to toggle source
# File lib/chef/knife/cloud/chefbootstrap/ssh_bootstrap_protocol.rb, line 68 def get_ssh_gateway_for(hostname) if config[:ssh_gateway] # The ssh_gateway specified in the knife config (if any) takes # precedence over anything in the SSH configuration Chef::Log.debug("Using ssh gateway #{config[:ssh_gateway]} from knife config") config[:ssh_gateway] else # Next, check if the SSH configuration has a ProxyCommand # directive for this host. If there is one, parse out the # host from the proxy command ssh_proxy = Net::SSH::Config.for(hostname)[:proxy] if ssh_proxy.respond_to?(:command_line_template) # ssh gateway_hostname nc %h %p proxy_pattern = /ssh\s+(\S+)\s+nc/ matchdata = proxy_pattern.match(ssh_proxy.command_line_template) if matchdata.nil? Chef::Log.debug("Unable to determine ssh gateway for '#{hostname}' from ssh config template: #{ssh_proxy.command_line_template}") nil else # Return hostname extracted from command line template Chef::Log.debug("Using ssh gateway #{matchdata[1]} from ssh config") matchdata[1] end else # Return nil if we cannot find an ssh_gateway Chef::Log.debug("No ssh gateway found, making a direct connection") nil end end end
init_bootstrap_options()
click to toggle source
Calls superclass method
Chef::Knife::Cloud::BootstrapProtocol#init_bootstrap_options
# File lib/chef/knife/cloud/chefbootstrap/ssh_bootstrap_protocol.rb, line 34 def init_bootstrap_options bootstrap.config[:connection_user] = config[:connection_user] bootstrap.config[:connection_password] = config[:connection_password] bootstrap.config[:connection_port] = config[:connection_port] bootstrap.config[:ssh_identity_file] = config[:ssh_identity_file] bootstrap.config[:ssh_verify_host_key] = config[:ssh_verify_host_key] bootstrap.config[:use_sudo] = true unless config[:connection_user] == "root" bootstrap.config[:ssh_gateway] = config[:ssh_gateway] bootstrap.config[:forward_agent] = config[:forward_agent] bootstrap.config[:use_sudo_password] = config[:use_sudo_password] super end
tcp_test_ssh(hostname, ssh_port) { || ... }
click to toggle source
# File lib/chef/knife/cloud/chefbootstrap/ssh_bootstrap_protocol.rb, line 99 def tcp_test_ssh(hostname, ssh_port) tcp_socket = TCPSocket.new(hostname, ssh_port) readable = IO.select([tcp_socket], nil, nil, 5) if readable ssh_banner = tcp_socket.gets if ssh_banner.nil? || ssh_banner.empty? false else Chef::Log.debug("ssh accepting connections on #{hostname}, banner is #{tcp_socket.gets}") yield true end else false end rescue Errno::EPERM, Errno::ETIMEDOUT Chef::Log.debug("ssh timed out: #{hostname}") false rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError Chef::Log.debug("ssh failed to connect: #{hostname}") sleep 2 false # This happens on some mobile phone networks rescue Errno::ECONNRESET Chef::Log.debug("ssh reset its connection: #{hostname}") sleep 2 false ensure tcp_socket && tcp_socket.close end
tunnel_test_ssh(ssh_gateway, hostname, &block)
click to toggle source
# File lib/chef/knife/cloud/chefbootstrap/ssh_bootstrap_protocol.rb, line 130 def tunnel_test_ssh(ssh_gateway, hostname, &block) status = false gateway = configure_ssh_gateway(ssh_gateway) remote_ssh_port = config[:connection_port] || config[:ssh_port] || 22 gateway.open(hostname, remote_ssh_port) do |local_tunnel_port| status = tcp_test_ssh("localhost", local_tunnel_port, &block) end status rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError sleep 2 false rescue Errno::EPERM, Errno::ETIMEDOUT false end
wait_for_server_ready()
click to toggle source
# File lib/chef/knife/cloud/chefbootstrap/ssh_bootstrap_protocol.rb, line 47 def wait_for_server_ready print "\n#{ui.color("Waiting for sshd to host (#{config[:bootstrap_ip_address]})", :magenta)}" ssh_gateway = get_ssh_gateway_for(config[:bootstrap_ip_address]) # The ssh_gateway & subnet_id are currently supported only in EC2. if ssh_gateway print(".") until tunnel_test_ssh(ssh_gateway, config[:bootstrap_ip_address]) do @initial_sleep_delay = !!config[:subnet_id] ? 40 : 10 sleep @initial_sleep_delay puts("done") end else print(".") until tcp_test_ssh(config[:bootstrap_ip_address], config[:connection_port] || config[:ssh_port] ) do @initial_sleep_delay = !!config[:subnet_id] ? 40 : 10 sleep @initial_sleep_delay puts("done") end end end