Class: Bcome::Ssh::Driver

Inherits:
Object
  • Object
show all
Defined in:
lib/objects/ssh/driver.rb

Constant Summary collapse

DEFAULT_TIMEOUT_IN_SECONDS =
5
PROXY_CONNECT_PREFIX =
'-o StrictHostKeyChecking=no -W %h:%p'.freeze
PROXY_SSH_PREFIX =
'-o UserKnownHostsFile=/dev/null -o "ProxyCommand ssh -W %h:%p'.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config, context_node) ⇒ Driver

Returns a new instance of Driver.



9
10
11
12
13
14
# File 'lib/objects/ssh/driver.rb', line 9

def initialize(config, context_node)
  @config = config
  @context_node = context_node
  @proxy_data = @config[:proxy] ? ::Bcome::Ssh::ProxyData.new(@config[:proxy], @context_node) : nil
  @bootstrap_settings = @config[:bootstrap_settings] ? ::Bcome::Ssh::Bootstrap.new(@config[:bootstrap_settings]) : nil
end

Instance Attribute Details

#bootstrap_settingsObject (readonly)

Returns the value of attribute bootstrap_settings.



3
4
5
# File 'lib/objects/ssh/driver.rb', line 3

def bootstrap_settings
  @bootstrap_settings
end

#configObject (readonly)

Returns the value of attribute config.



3
4
5
# File 'lib/objects/ssh/driver.rb', line 3

def config
  @config
end

Instance Method Details

#bastion_host_userObject



69
70
71
# File 'lib/objects/ssh/driver.rb', line 69

def bastion_host_user
  bootstrap? && @bootstrap_settings.bastion_host_user ? @bootstrap_settings.bastion_host_user : @proxy_data.bastion_host_user ? @proxy_data.bastion_host_user : user
end

#bootstrap?Boolean

Returns:

  • (Boolean)


16
17
18
# File 'lib/objects/ssh/driver.rb', line 16

def bootstrap?
  @context_node.bootstrap? && has_bootstrap_settings?
end

#bootstrap_proxy_connection_stringObject



60
61
62
# File 'lib/objects/ssh/driver.rb', line 60

def bootstrap_proxy_connection_string
  "ssh -i #{@bootstrap_settings.ssh_key_path} -o StrictHostKeyChecking=no -W %h:%p #{@bootstrap_settings.bastion_host_user}@#{@proxy_data.host}"
end

#bootstrap_rsync_command(local_path, remote_path) ⇒ Object



134
135
136
137
138
139
140
# File 'lib/objects/ssh/driver.rb', line 134

def bootstrap_rsync_command(local_path, remote_path)
  if has_proxy?
    "rsync -av -e \"ssh -i #{@bootstrap_settings.ssh_key_path} -A #{bastion_host_user}@#{@proxy_data.host} ssh -o StrictHostKeyChecking=no\" #{local_path} #{user}@#{@context_node.internal_ip_address}:#{remote_path}"
  else
    "rsync -i #{@bootstrap_settings.ssh_key_path} -av #{local_path} #{user}@#{@context_node.public_ip_address}:#{remote_path}"
  end
end

#bootstrap_ssh_commandObject



82
83
84
85
86
87
88
# File 'lib/objects/ssh/driver.rb', line 82

def bootstrap_ssh_command
  if has_proxy?
    "ssh -i #{@bootstrap_settings.ssh_key_path} -t #{bastion_host_user}@#{@proxy_data.host} ssh -t #{user}@#{@context_node.internal_ip_address}"
  else
    "ssh -i #{@bootstrap_settings.ssh_key_path} #{user}@#{@context_node.public_ip_address}"
  end
end

#close_ssh_connectionObject



190
191
192
193
194
# File 'lib/objects/ssh/driver.rb', line 190

def close_ssh_connection
  return unless @connection
  @connection.close unless @connection.closed?
  @connection = nil
end

#do_sshObject



64
65
66
67
# File 'lib/objects/ssh/driver.rb', line 64

def do_ssh
  cmd = ssh_command
  @context_node.execute_local(cmd)
end

#fallback_local_userObject



94
95
96
# File 'lib/objects/ssh/driver.rb', line 94

def fallback_local_user
  @fallback_local_user ||= ::Bcome::System::Local.instance.local_user
end

#get(remote_path, local_path) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/objects/ssh/driver.rb', line 177

def get(remote_path, local_path)
  raise Bcome::Exception::MissingParamsForScp, "'get' requires a local_path and a remote_path" if local_path.to_s.empty? || remote_path.to_s.empty?
  puts "\n(#{@context_node.namespace})\s".namespace + "Downloading #{remote_path} to #{local_path}\n".informational

  begin
    scp.download!(remote_path, local_path, recursive: true) do |_ch, name, sent, total|
      puts "#{name}: #{sent}/#{total}".progress
    end
  rescue Exception => e # scp just throws generic exceptions :-/
    puts e.message.error
  end
end

#has_bootstrap_settings?Boolean

Returns:

  • (Boolean)


20
21
22
# File 'lib/objects/ssh/driver.rb', line 20

def has_bootstrap_settings?
  !@bootstrap_settings.nil?
end

#has_open_ssh_con?Boolean

Returns:

  • (Boolean)


200
201
202
# File 'lib/objects/ssh/driver.rb', line 200

def has_open_ssh_con?
  !@connection.nil? && !@connection.closed?
end

#has_proxy?Boolean

Returns:

  • (Boolean)


52
53
54
# File 'lib/objects/ssh/driver.rb', line 52

def has_proxy?
  !@config[:proxy].nil?
end

#net_ssh_params(verbose = false) ⇒ Object



102
103
104
105
106
107
108
109
# File 'lib/objects/ssh/driver.rb', line 102

def net_ssh_params(verbose = false)
  raise Bcome::Exception::InvalidSshConfig, "Missing ssh keys for #{@context_node.namespace}" unless ssh_keys
  params = { keys: ssh_keys, paranoid: false }
  params[:proxy] = proxy if has_proxy?
  params[:timeout] = timeout_in_seconds
  params[:verbose] = :debug if verbose
  params
end

#node_host_or_ipObject



98
99
100
# File 'lib/objects/ssh/driver.rb', line 98

def node_host_or_ip
  has_proxy? ? @context_node.internal_ip_address : @context_node.public_ip_address
end

#pingObject



152
153
154
155
156
157
# File 'lib/objects/ssh/driver.rb', line 152

def ping
  ssh_connect!
  return { success: true }
rescue Exception => e
  return { success: false, error: e }
end

#pretty_config_detailsObject



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/objects/ssh/driver.rb', line 24

def pretty_config_details
  config = {
    user: user,
    ssh_keys: ssh_keys,
    timeout: timeout_in_seconds
  }
  if has_proxy?
    config[:host_or_ip] = @context_node.internal_ip_address
    config[:proxy] = {
      bastion_host:  @proxy_data.host,
      bastion_host_user: bastion_host_user
    }
  else
    config[:host_or_ip] = @context_node.public_ip_address
  end
  config
end

#proxyObject



46
47
48
49
50
# File 'lib/objects/ssh/driver.rb', line 46

def proxy
  return nil unless has_proxy?
  connection_string = bootstrap? ? bootstrap_proxy_connection_string : proxy_connection_string
  ::Net::SSH::Proxy::Command.new(connection_string)
end

#proxy_connection_stringObject



56
57
58
# File 'lib/objects/ssh/driver.rb', line 56

def proxy_connection_string
  "ssh #{PROXY_CONNECT_PREFIX} #{bastion_host_user}@#{@proxy_data.host}"
end

#put(local_path, remote_path) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/objects/ssh/driver.rb', line 163

def put(local_path, remote_path)
  raise Bcome::Exception::MissingParamsForScp, "'put' requires a local_path and a remote_path" if local_path.to_s.empty? || remote_path.to_s.empty?
  puts "\n(#{@context_node.namespace})\s".namespace + "Uploading #{local_path} to #{remote_path}\n".informational

  begin
    scp.upload!(local_path, remote_path, recursive: true) do |_ch, name, sent, total|
      puts "#{name}: #{sent}/#{total}".progress
    end
  rescue Exception => e # scp just throws generic exceptions :-/
    puts e.message.error
  end
  nil
end

#rsync(local_path, remote_path) ⇒ Object



119
120
121
122
123
# File 'lib/objects/ssh/driver.rb', line 119

def rsync(local_path, remote_path)
  raise Bcome::Exception::MissingParamsForRsync, "'rsync' requires a local_path and a remote_path" if local_path.to_s.empty? || remote_path.to_s.empty?
  command = rsync_command(local_path, remote_path)
  @context_node.execute_local(command)
end

#rsync_command(local_path, remote_path) ⇒ Object



125
126
127
128
129
130
131
132
# File 'lib/objects/ssh/driver.rb', line 125

def rsync_command(local_path, remote_path)
  return bootstrap_rsync_command(local_path, remote_path) if bootstrap? && @bootstrap_settings.ssh_key_path
  if has_proxy?
    "rsync -av -e \"ssh -A #{bastion_host_user}@#{@proxy_data.host} ssh -o StrictHostKeyChecking=no\" #{local_path} #{user}@#{@context_node.internal_ip_address}:#{remote_path}"
  else
    "rsync -av #{local_path} #{user}@#{@context_node.public_ip_address}:#{remote_path}"
  end
end

#scpObject



159
160
161
# File 'lib/objects/ssh/driver.rb', line 159

def scp
  ssh_connection.scp
end

#ssh_commandObject



73
74
75
76
77
78
79
80
# File 'lib/objects/ssh/driver.rb', line 73

def ssh_command
  return bootstrap_ssh_command if bootstrap? && @bootstrap_settings.ssh_key_path
  if has_proxy?
    "ssh #{PROXY_SSH_PREFIX} #{bastion_host_user}@#{@proxy_data.host}\" #{user}@#{@context_node.internal_ip_address}"
  else
    "ssh #{user}@#{@context_node.public_ip_address}"
  end
end

#ssh_connect!(_verbose = false) ⇒ Object



142
143
144
145
146
147
148
149
150
# File 'lib/objects/ssh/driver.rb', line 142

def ssh_connect!(_verbose = false)
  @connection = nil
  begin
    @connection = ::Net::SSH.start(node_host_or_ip, user, net_ssh_params)
  rescue Net::SSH::Proxy::ConnectError, Net::SSH::ConnectionTimeout, Errno::EPIPE => e
    raise Bcome::Exception::CouldNotInitiateSshConnection, @context_node.namespace + "\s-\s#{e.message}"
  end
  @connection
end

#ssh_connection(_bootstrap = false) ⇒ Object



196
197
198
# File 'lib/objects/ssh/driver.rb', line 196

def ssh_connection(_bootstrap = false)
  has_open_ssh_con? ? @connection : ssh_connect!
end

#ssh_keysObject



111
112
113
114
115
116
117
# File 'lib/objects/ssh/driver.rb', line 111

def ssh_keys
  if bootstrap?
    [@bootstrap_settings.ssh_key_path]
  else
    @config[:ssh_keys]
  end
end

#timeout_in_secondsObject



42
43
44
# File 'lib/objects/ssh/driver.rb', line 42

def timeout_in_seconds
  @config[:timeout_in_seconds] ||= Bcome::Ssh::Driver::DEFAULT_TIMEOUT_IN_SECONDS
end

#userObject



90
91
92
# File 'lib/objects/ssh/driver.rb', line 90

def user
  bootstrap? && @bootstrap_settings.user ? @bootstrap_settings.user : @config[:user] ? @config[:user] : fallback_local_user
end