bcome 1.3.4 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/bin/bcome +13 -8
- data/lib/bcome.rb +14 -11
- data/lib/objects/bcome/version.rb +19 -1
- data/lib/objects/bootup.rb +16 -7
- data/lib/objects/command/local.rb +2 -0
- data/lib/objects/config_factory.rb +3 -0
- data/lib/objects/driver/base.rb +52 -6
- data/lib/objects/driver/bucket.rb +6 -4
- data/lib/objects/driver/ec2.rb +45 -5
- data/lib/objects/driver/gcp.rb +168 -0
- data/lib/objects/driver/gcp/authentication/api_key.rb +6 -0
- data/lib/objects/driver/gcp/authentication/base.rb +36 -0
- data/lib/objects/driver/gcp/authentication/oauth.rb +96 -0
- data/lib/objects/driver/gcp/authentication/oauth_client_config.rb +22 -0
- data/lib/objects/driver/gcp/authentication/oauth_session_store.rb +22 -0
- data/lib/objects/driver/gcp/authentication/service_account.rb +62 -0
- data/lib/objects/driver/gcp/authentication/signet/service_account.rb +27 -0
- data/lib/objects/driver/gcp/authentication/utilities.rb +42 -0
- data/lib/objects/encryptor.rb +109 -24
- data/lib/objects/exception/argument_error_invoking_method_from_command_line.rb +8 -4
- data/lib/objects/exception/base.rb +21 -10
- data/lib/objects/exception/can_only_subselect_on_inventory.rb +8 -4
- data/lib/objects/exception/cannot_authenticate_to_gcp.rb +11 -0
- data/lib/objects/exception/cannot_find_internal_registry_klass.rb +8 -4
- data/lib/objects/exception/cannot_find_inventory.rb +11 -0
- data/lib/objects/exception/cannot_find_subselection_parent.rb +8 -4
- data/lib/objects/exception/cant_find_key_in_cloud_tags.rb +8 -4
- data/lib/objects/exception/cant_find_key_in_metadata.rb +8 -4
- data/lib/objects/exception/cant_find_proxy_host_by_identifier.rb +8 -4
- data/lib/objects/exception/cant_find_proxy_host_by_namespace.rb +8 -4
- data/lib/objects/exception/could_not_initiate_ssh_connection.rb +8 -4
- data/lib/objects/exception/could_not_initiate_ssh_connection_through_backend_proxy.rb +8 -4
- data/lib/objects/exception/could_not_retrieve_terraform_output.rb +11 -0
- data/lib/objects/exception/deprecation_warning.rb +9 -7
- data/lib/objects/exception/duplicate_command_line_argument_key.rb +8 -4
- data/lib/objects/exception/ec2_driver_missing_authorization_keys.rb +11 -0
- data/lib/objects/exception/ec2_driver_missing_provisioning_region.rb +8 -4
- data/lib/objects/exception/empty_namespace_tree.rb +11 -0
- data/lib/objects/exception/failed_to_run_local_command.rb +8 -4
- data/lib/objects/exception/gcp_auth_service_account_missing_credentials.rb +11 -0
- data/lib/objects/exception/generic.rb +11 -0
- data/lib/objects/exception/interactive_session_halt.rb +6 -2
- data/lib/objects/exception/invalid_bcome_breadcrumb.rb +8 -4
- data/lib/objects/exception/invalid_breadcrumb.rb +8 -4
- data/lib/objects/exception/invalid_context_command.rb +8 -4
- data/lib/objects/exception/invalid_gcp_authentication_scheme.rb +11 -0
- data/lib/objects/exception/invalid_identifier.rb +8 -4
- data/lib/objects/exception/invalid_machines_cache_config.rb +8 -4
- data/lib/objects/exception/invalid_matcher_query.rb +8 -4
- data/lib/objects/exception/invalid_meta_data_config.rb +8 -4
- data/lib/objects/exception/invalid_metadata_encryption_key.rb +8 -4
- data/lib/objects/exception/invalid_network_config.rb +8 -4
- data/lib/objects/exception/invalid_network_driver_type.rb +8 -4
- data/lib/objects/exception/invalid_port_forward_request.rb +11 -0
- data/lib/objects/exception/invalid_proxy_config.rb +8 -4
- data/lib/objects/exception/invalid_regexp_matcher_in_registry.rb +8 -4
- data/lib/objects/exception/invalid_registry_arguments_type.rb +8 -4
- data/lib/objects/exception/invalid_registry_command_name_length.rb +8 -4
- data/lib/objects/exception/invalid_registry_data_config.rb +8 -4
- data/lib/objects/exception/invalid_restriction_key_in_registry.rb +8 -4
- data/lib/objects/exception/invalid_ssh_config.rb +8 -4
- data/lib/objects/exception/inventories_cannot_have_subviews.rb +8 -4
- data/lib/objects/exception/malformed_command_line_arguments.rb +8 -4
- data/lib/objects/exception/method_invocation_requires_parameter.rb +8 -4
- data/lib/objects/exception/method_name_conflict_in_registry.rb +8 -4
- data/lib/objects/exception/missing_argument_for_registry_command.rb +8 -4
- data/lib/objects/exception/missing_description_on_view.rb +8 -4
- data/lib/objects/exception/missing_execute_on_registry_object.rb +8 -4
- data/lib/objects/exception/missing_gcp_authentication_scheme.rb +11 -0
- data/lib/objects/exception/missing_gcp_service_account_credentials_filename.rb +11 -0
- data/lib/objects/exception/missing_gcp_service_scopes.rb +11 -0
- data/lib/objects/exception/missing_identifier_on_view.rb +8 -4
- data/lib/objects/exception/missing_inventory_contributors.rb +11 -0
- data/lib/objects/exception/missing_ip_address_on_server.rb +8 -4
- data/lib/objects/exception/missing_network_config.rb +8 -4
- data/lib/objects/exception/missing_or_invalid_client_secrets.rb +11 -0
- data/lib/objects/exception/missing_params_for_rsync.rb +8 -4
- data/lib/objects/exception/missing_params_for_scp.rb +8 -4
- data/lib/objects/exception/missing_subselection_key.rb +8 -4
- data/lib/objects/exception/missing_type_on_view.rb +8 -4
- data/lib/objects/exception/no_node_found_for_breadcrumb.rb +8 -4
- data/lib/objects/exception/no_node_named_by_identifier.rb +8 -4
- data/lib/objects/exception/node_identifiers_must_be_unique.rb +8 -4
- data/lib/objects/exception/orchestration_script_does_not_exist.rb +8 -4
- data/lib/objects/exception/proxy_host_node_does_not_have_public_ip_address.rb +8 -4
- data/lib/objects/exception/unknown_dynamic_server_type.rb +11 -0
- data/lib/objects/exception/unknown_method_for_namespace.rb +8 -4
- data/lib/objects/exception/user_orchestration_error.rb +11 -0
- data/lib/objects/initialization/factory.rb +36 -0
- data/lib/objects/initialization/structure.rb +18 -0
- data/lib/objects/initialization/utils.rb +20 -0
- data/lib/objects/interactive/session.rb +4 -1
- data/lib/objects/interactive/session_item/base.rb +2 -0
- data/lib/objects/interactive/session_item/capture_input.rb +2 -0
- data/lib/objects/interactive/session_item/transparent_ssh.rb +29 -23
- data/lib/objects/loading_bar/handler.rb +80 -0
- data/lib/objects/loading_bar/indicator/base.rb +65 -0
- data/lib/objects/loading_bar/indicator/basic.rb +34 -0
- data/lib/objects/loading_bar/indicator/progress.rb +26 -0
- data/lib/objects/loading_bar/pid_bucket.rb +27 -0
- data/lib/objects/modules/context.rb +13 -9
- data/lib/objects/modules/draw.rb +49 -0
- data/lib/objects/modules/registry_management.rb +16 -10
- data/lib/objects/modules/tree.rb +157 -0
- data/lib/objects/modules/ui_output.rb +10 -6
- data/lib/objects/modules/workspace_commands.rb +131 -157
- data/lib/objects/modules/workspace_menu.rb +193 -129
- data/lib/objects/node/attributes.rb +17 -19
- data/lib/objects/node/base.rb +136 -74
- data/lib/objects/node/cache_handler.rb +3 -1
- data/lib/objects/node/collection.rb +10 -9
- data/lib/objects/node/factory.rb +47 -36
- data/lib/objects/node/inventory/base.rb +106 -100
- data/lib/objects/node/inventory/defined.rb +113 -89
- data/lib/objects/node/inventory/merge.rb +51 -0
- data/lib/objects/node/inventory/subselect.rb +66 -46
- data/lib/objects/node/kube/base.rb +51 -0
- data/lib/objects/node/kube/container.rb +9 -0
- data/lib/objects/node/kube/estate.rb +19 -0
- data/lib/objects/node/kube/namespace.rb +24 -0
- data/lib/objects/node/kube/pod.rb +24 -0
- data/lib/objects/node/kube_wrap.rb +26 -0
- data/lib/objects/node/meta/base.rb +8 -1
- data/lib/objects/node/meta/cloud.rb +2 -0
- data/lib/objects/node/meta/local.rb +2 -0
- data/lib/objects/node/meta_data_factory.rb +4 -2
- data/lib/objects/node/meta_data_loader.rb +28 -29
- data/lib/objects/node/resources/base.rb +5 -1
- data/lib/objects/node/resources/inventory.rb +26 -5
- data/lib/objects/node/resources/merged.rb +47 -0
- data/lib/objects/node/resources/sub_inventory.rb +12 -8
- data/lib/objects/node/server/base.rb +105 -70
- data/lib/objects/node/server/dynamic/base.rb +23 -0
- data/lib/objects/node/server/{dynamic.rb → dynamic/ec2.rb} +13 -13
- data/lib/objects/node/server/dynamic/gcp.rb +46 -0
- data/lib/objects/node/server/static.rb +34 -10
- data/lib/objects/orchestration/base.rb +17 -1
- data/lib/objects/orchestration/interactive_terraform.rb +59 -30
- data/lib/objects/orchestrator.rb +22 -0
- data/lib/objects/parser/bread_crumb.rb +3 -1
- data/lib/objects/registry/arguments/base.rb +3 -1
- data/lib/objects/registry/arguments/command_line.rb +6 -1
- data/lib/objects/registry/arguments/console.rb +4 -1
- data/lib/objects/registry/command/base.rb +3 -0
- data/lib/objects/registry/command/external.rb +9 -3
- data/lib/objects/registry/command/group.rb +11 -4
- data/lib/objects/registry/command/internal.rb +3 -1
- data/lib/objects/registry/command/shortcut.rb +17 -9
- data/lib/objects/registry/command_list.rb +2 -0
- data/lib/objects/registry/loader.rb +13 -10
- data/lib/objects/ssh/bootstrap.rb +3 -1
- data/lib/objects/ssh/command.rb +9 -8
- data/lib/objects/ssh/command_exec.rb +16 -10
- data/lib/objects/ssh/connection_wrangler.rb +124 -0
- data/lib/objects/ssh/connector.rb +108 -0
- data/lib/objects/ssh/driver.rb +28 -242
- data/lib/objects/ssh/driver_concerns/command_strings.rb +17 -0
- data/lib/objects/ssh/driver_concerns/connection.rb +75 -0
- data/lib/objects/ssh/driver_concerns/functions.rb +89 -0
- data/lib/objects/ssh/driver_concerns/user.rb +32 -0
- data/lib/objects/ssh/proxy_chain.rb +19 -0
- data/lib/objects/ssh/proxy_chain_link.rb +26 -0
- data/lib/objects/ssh/proxy_hop.rb +130 -0
- data/lib/objects/ssh/script_exec.rb +12 -11
- data/lib/objects/ssh/tunnel/local_port_forward.rb +5 -6
- data/lib/objects/ssh/tunnel_keeper.rb +21 -0
- data/lib/objects/ssh/window.rb +31 -0
- data/lib/objects/startup.rb +58 -0
- data/lib/objects/system/local.rb +3 -0
- data/lib/objects/terraform/output.rb +45 -0
- data/lib/objects/workspace.rb +13 -14
- data/patches/irb.rb +63 -6
- data/patches/string-encrypt.rb +20 -23
- data/patches/string.rb +18 -1
- data/patches/string_stylesheet.rb +2 -0
- metadata +157 -33
- data/lib/objects/driver/static.rb +0 -4
- data/lib/objects/progress_bar.rb +0 -30
- data/lib/objects/ssh/connection_handler.rb +0 -101
- data/lib/objects/ssh/proxy_data.rb +0 -56
- data/lib/objects/terraform/parser.rb +0 -23
- data/lib/objects/terraform/state.rb +0 -40
data/lib/objects/ssh/driver.rb
CHANGED
@@ -1,276 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/scp'
|
4
|
+
|
1
5
|
module Bcome::Ssh
|
2
6
|
class Driver
|
3
|
-
attr_reader :config, :
|
7
|
+
attr_reader :config, :context_node
|
4
8
|
|
5
|
-
|
6
|
-
|
7
|
-
|
9
|
+
include Bcome::Ssh::DriverConnection
|
10
|
+
include Bcome::Ssh::DriverFunctions
|
11
|
+
include Bcome::Ssh::DriverUser
|
12
|
+
include Bcome::Ssh::DriverCommandStrings
|
8
13
|
|
9
14
|
def initialize(config, context_node)
|
10
15
|
@config = config
|
11
16
|
@context_node = context_node
|
12
|
-
@proxy_data = @config[:proxy] ? ::Bcome::Ssh::ProxyData.new(@config[:proxy], @context_node) : nil
|
13
|
-
@bootstrap_settings = @config[:bootstrap_settings] ? ::Bcome::Ssh::Bootstrap.new(@config[:bootstrap_settings]) : nil
|
14
17
|
end
|
15
18
|
|
16
|
-
def
|
17
|
-
@
|
19
|
+
def connection_wrangler
|
20
|
+
@connection_wrangler ||= set_connection_wrangler
|
21
|
+
end
|
22
|
+
|
23
|
+
def proxy_chain
|
24
|
+
@proxy_chain ||= ::Bcome::Ssh::ProxyChain.new(connection_wrangler)
|
18
25
|
end
|
19
26
|
|
20
|
-
def
|
21
|
-
|
27
|
+
def set_connection_wrangler
|
28
|
+
@connection_wrangler = ::Bcome::Ssh::ConnectionWrangler.new(self)
|
22
29
|
end
|
23
30
|
|
24
|
-
def
|
31
|
+
def pretty_ssh_config
|
25
32
|
config = {
|
26
33
|
user: user,
|
27
|
-
ssh_keys: ssh_keys,
|
28
34
|
timeout: timeout_in_seconds
|
29
35
|
}
|
36
|
+
|
30
37
|
if has_proxy?
|
31
|
-
config[:
|
32
|
-
config[:proxy] = {
|
33
|
-
bastion_host: @proxy_data.host,
|
34
|
-
bastion_host_user: bastion_host_user
|
35
|
-
}
|
38
|
+
config[:proxy] = connection_wrangler.proxy_details
|
36
39
|
else
|
37
|
-
config[:host_or_ip] =
|
40
|
+
config[:host_or_ip] = node_host_or_ip
|
38
41
|
end
|
39
|
-
config
|
40
|
-
end
|
41
|
-
|
42
|
-
def timeout_in_seconds
|
43
|
-
@config[:timeout_in_seconds] ||= Bcome::Ssh::Driver::DEFAULT_TIMEOUT_IN_SECONDS
|
44
|
-
end
|
45
42
|
|
46
|
-
|
47
|
-
return nil unless has_proxy?
|
48
|
-
connection_string = bootstrap? ? bootstrap_proxy_connection_string : proxy_connection_string
|
49
|
-
::Net::SSH::Proxy::Command.new(connection_string)
|
50
|
-
end
|
51
|
-
|
52
|
-
def has_proxy?
|
53
|
-
return false if proxy_config_value && proxy_config_value == -1
|
54
|
-
!@config[:proxy].nil?
|
43
|
+
config
|
55
44
|
end
|
56
45
|
|
57
46
|
def proxy_config_value
|
58
47
|
@config[:proxy]
|
59
48
|
end
|
60
49
|
|
61
|
-
def
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
def bootstrap_proxy_connection_string
|
66
|
-
"ssh -i #{@bootstrap_settings.ssh_key_path} -o StrictHostKeyChecking=no -W %h:%p #{@bootstrap_settings.bastion_host_user}@#{@proxy_data.host}"
|
67
|
-
end
|
68
|
-
|
69
|
-
def do_ssh
|
70
|
-
cmd = ssh_command
|
71
|
-
@context_node.execute_local(cmd)
|
72
|
-
end
|
73
|
-
|
74
|
-
def bastion_host_user
|
75
|
-
bootstrap? && @bootstrap_settings.bastion_host_user ? @bootstrap_settings.bastion_host_user : @proxy_data.bastion_host_user ? @proxy_data.bastion_host_user : user
|
76
|
-
end
|
77
|
-
|
78
|
-
def ssh_command(as_pseudo_tty = false)
|
79
|
-
return bootstrap_ssh_command if bootstrap? && @bootstrap_settings.ssh_key_path
|
80
|
-
|
81
|
-
if has_proxy?
|
82
|
-
"#{as_pseudo_tty ? "ssh -t" : "ssh"} #{PROXY_SSH_PREFIX} #{bastion_host_user}@#{@proxy_data.host}\" #{node_level_ssh_key_connection_string}#{user}@#{@context_node.internal_ip_address}"
|
83
|
-
else
|
84
|
-
"#{as_pseudo_tty ? "ssh -t" : "ssh"} #{node_level_ssh_key_connection_string}#{user}@#{@context_node.public_ip_address}"
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def node_level_ssh_key_connection_string
|
89
|
-
key_specified_at_node_level? ? "-i #{node_level_ssh_key}\s" : ""
|
90
|
-
end
|
91
|
-
|
92
|
-
def key_specified_at_node_level?
|
93
|
-
!node_level_ssh_key.nil?
|
94
|
-
end
|
95
|
-
|
96
|
-
def node_level_ssh_key
|
97
|
-
return (@config[:ssh_keys]) ? @config[:ssh_keys].first : nil
|
98
|
-
end
|
99
|
-
|
100
|
-
def local_port_forward(start_port, end_port)
|
101
|
-
if has_proxy?
|
102
|
-
|
103
|
-
if bootstrap?
|
104
|
-
tunnel_command = "ssh -N -L #{start_port}:#{@context_node.internal_ip_address}:#{end_port} -i #{@bootstrap_settings.ssh_key_path} #{bastion_host_user}@#{@proxy_data.host}"
|
105
|
-
else
|
106
|
-
tunnel_command = "ssh -N -L #{start_port}:#{@context_node.internal_ip_address}:#{end_port} #{bastion_host_user}@#{@proxy_data.host}"
|
107
|
-
end
|
108
|
-
else
|
109
|
-
if bootstrap?
|
110
|
-
tunnel_command = "ssh -i #{@bootstrap_settings.ssh_key_path} -N -L #{start_port}:#{@context_node.public_ip_address}:#{end_port}"
|
111
|
-
else
|
112
|
-
tunnel_command = "ssh -N -L #{start_port}:#{@context_node.public_ip_address}:#{end_port}"
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
tunnel = ::Bcome::Ssh::Tunnel::LocalPortForward.new(tunnel_command)
|
117
|
-
tunnel.open!
|
118
|
-
return tunnel
|
119
|
-
end
|
120
|
-
|
121
|
-
def bootstrap_ssh_command
|
122
|
-
if has_proxy?
|
123
|
-
"ssh -i #{@bootstrap_settings.ssh_key_path} -t #{bastion_host_user}@#{@proxy_data.host} ssh -t #{user}@#{@context_node.internal_ip_address}"
|
124
|
-
else
|
125
|
-
"ssh -i #{@bootstrap_settings.ssh_key_path} #{user}@#{@context_node.public_ip_address}"
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
def user
|
130
|
-
# If we're in bootstrapping mode and have a bootstrap user set, return it
|
131
|
-
return @bootstrap_settings.user if (bootstrap? && @bootstrap_settings.user)
|
132
|
-
|
133
|
-
# If we have a user explcitly set in the config, then return it
|
134
|
-
return @config[:user] if @config[:user]
|
135
|
-
|
136
|
-
# If the local user has explicitly overriden their user, return that
|
137
|
-
return overriden_local_user if overriden_local_user
|
138
|
-
|
139
|
-
# Else fall back to whichever local user is using bcome
|
140
|
-
fallback_local_user
|
141
|
-
end
|
142
|
-
|
143
|
-
def overriden_local_user
|
144
|
-
@overriden_local_user ||= get_overriden_local_user
|
50
|
+
def multi_hop_proxy_config
|
51
|
+
@config[:multi_hop_proxy]
|
145
52
|
end
|
146
53
|
|
147
|
-
def
|
148
|
-
|
54
|
+
def has_multi_hop_proxy?
|
55
|
+
!multi_hop_proxy_config.nil?
|
149
56
|
end
|
150
57
|
|
151
|
-
def
|
152
|
-
|
153
|
-
end
|
154
|
-
|
155
|
-
def node_host_or_ip
|
156
|
-
has_proxy? ? @context_node.internal_ip_address : @context_node.public_ip_address
|
157
|
-
end
|
158
|
-
|
159
|
-
def net_ssh_params(verbose = false)
|
160
|
-
raise Bcome::Exception::InvalidSshConfig, "Missing ssh keys for #{@context_node.namespace}" unless ssh_keys
|
161
|
-
params = { keys: ssh_keys, paranoid: false }
|
162
|
-
params[:proxy] = proxy if has_proxy?
|
163
|
-
params[:timeout] = timeout_in_seconds
|
164
|
-
params[:verbose] = :debug if verbose
|
165
|
-
params
|
166
|
-
end
|
167
|
-
|
168
|
-
def ssh_keys
|
169
|
-
if bootstrap?
|
170
|
-
[@bootstrap_settings.ssh_key_path]
|
171
|
-
else
|
172
|
-
@config[:ssh_keys]
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def rsync(local_path, remote_path)
|
177
|
-
raise Bcome::Exception::MissingParamsForRsync, "'rsync' requires a local_path and a remote_path" if local_path.to_s.empty? || remote_path.to_s.empty?
|
178
|
-
command = rsync_command(local_path, remote_path)
|
179
|
-
@context_node.execute_local(command)
|
180
|
-
end
|
181
|
-
|
182
|
-
def rsync_command(local_path, remote_path)
|
183
|
-
return bootstrap_rsync_command(local_path, remote_path) if bootstrap? && @bootstrap_settings.ssh_key_path
|
184
|
-
if has_proxy?
|
185
|
-
"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}"
|
186
|
-
else
|
187
|
-
"rsync -av #{local_path} #{user}@#{@context_node.public_ip_address}:#{remote_path}"
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def bootstrap_rsync_command(local_path, remote_path)
|
192
|
-
if has_proxy?
|
193
|
-
"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}"
|
194
|
-
else
|
195
|
-
"rsync -i #{@bootstrap_settings.ssh_key_path} -av #{local_path} #{user}@#{@context_node.public_ip_address}:#{remote_path}"
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
def ssh_connect!(_verbose = false)
|
200
|
-
@connection = nil
|
201
|
-
begin
|
202
|
-
@connection = ::Net::SSH.start(node_host_or_ip, user, net_ssh_params)
|
203
|
-
rescue Net::SSH::Proxy::ConnectError, Net::SSH::ConnectionTimeout, Errno::EPIPE => e
|
204
|
-
raise Bcome::Exception::CouldNotInitiateSshConnection, @context_node.namespace + "\s-\s#{e.message}"
|
205
|
-
end
|
206
|
-
@connection
|
207
|
-
end
|
208
|
-
|
209
|
-
def ping
|
210
|
-
ssh_connect!
|
211
|
-
return { success: true }
|
212
|
-
rescue Exception => e
|
213
|
-
return { success: false, error: e }
|
214
|
-
end
|
215
|
-
|
216
|
-
def scp
|
217
|
-
ssh_connection.scp
|
218
|
-
end
|
219
|
-
|
220
|
-
def put(local_path, remote_path)
|
221
|
-
raise Bcome::Exception::MissingParamsForScp, "'put' requires a local_path and a remote_path" if local_path.to_s.empty? || remote_path.to_s.empty?
|
222
|
-
puts "\n(#{@context_node.namespace})\s".namespace + "Uploading #{local_path} to #{remote_path}\n".informational
|
223
|
-
|
224
|
-
begin
|
225
|
-
scp.upload!(local_path, remote_path, recursive: true) do |_ch, name, sent, total|
|
226
|
-
puts "#{name}: #{sent}/#{total}".progress
|
227
|
-
end
|
228
|
-
rescue Exception => e # scp just throws generic exceptions :-/
|
229
|
-
puts e.message.error
|
230
|
-
end
|
231
|
-
nil
|
232
|
-
end
|
233
|
-
|
234
|
-
def put_str(string, remote_path)
|
235
|
-
raise Bcome::Exception::MissingParamsForScp, "'put' requires a string and a remote_path" if string.to_s.empty? || remote_path.to_s.empty?
|
236
|
-
puts "\n(#{@context_node.namespace})\s".namespace + "Uploading from string to #{remote_path}\n".informational
|
237
|
-
|
238
|
-
begin
|
239
|
-
scp.upload!(StringIO.new(string), remote_path) do |_ch, name, sent, total|
|
240
|
-
puts "#{name}: #{sent}/#{total}".progress
|
241
|
-
end
|
242
|
-
rescue Exception => e # scp just throws generic exceptions :-/
|
243
|
-
puts e.message.error
|
244
|
-
end
|
245
|
-
nil
|
246
|
-
end
|
247
|
-
|
248
|
-
|
249
|
-
def get(remote_path, local_path)
|
250
|
-
raise Bcome::Exception::MissingParamsForScp, "'get' requires a local_path and a remote_path" if local_path.to_s.empty? || remote_path.to_s.empty?
|
251
|
-
puts "\n(#{@context_node.namespace})\s".namespace + "Downloading #{remote_path} to #{local_path}\n".informational
|
252
|
-
|
253
|
-
begin
|
254
|
-
scp.download!(remote_path, local_path, recursive: true) do |_ch, name, sent, total|
|
255
|
-
puts "#{name}: #{sent}/#{total}".progress
|
256
|
-
end
|
257
|
-
rescue Exception => e # scp just throws generic exceptions :-/
|
258
|
-
puts e.message.error
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
def close_ssh_connection
|
263
|
-
return unless @connection
|
264
|
-
@connection.close unless @connection.closed?
|
265
|
-
@connection = nil
|
266
|
-
end
|
267
|
-
|
268
|
-
def ssh_connection(_bootstrap = false)
|
269
|
-
has_open_ssh_con? ? @connection : ssh_connect!
|
270
|
-
end
|
271
|
-
|
272
|
-
def has_open_ssh_con?
|
273
|
-
!@connection.nil? && !@connection.closed?
|
58
|
+
def has_proxy?
|
59
|
+
return connection_wrangler.has_hop?
|
274
60
|
end
|
275
61
|
end
|
276
62
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ::Bcome::Ssh
|
4
|
+
module DriverCommandStrings
|
5
|
+
def ssh_command(as_pseudo_tty = false)
|
6
|
+
connection_wrangler.get_ssh_command(as_pseudo_tty: as_pseudo_tty)
|
7
|
+
end
|
8
|
+
|
9
|
+
def rsync_command(local_path, remote_path)
|
10
|
+
connection_wrangler.get_rsync_command(local_path, remote_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def local_port_forward_command(start_port, end_port)
|
14
|
+
connection_wrangler.get_local_port_forward_command(start_port, end_port)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ::Bcome::Ssh
|
4
|
+
module DriverConnection
|
5
|
+
DEFAULT_TIMEOUT_IN_SECONDS = 1
|
6
|
+
|
7
|
+
attr_reader :connection
|
8
|
+
|
9
|
+
## CONNECTION --
|
10
|
+
|
11
|
+
def ssh_connect!
|
12
|
+
@connection = nil
|
13
|
+
begin
|
14
|
+
raise ::Bcome::Exception::InvalidProxyConfig, "missing target ip address for #{@context_node.identifier}. Perhaps you meant to configure a proxy?" unless node_host_or_ip
|
15
|
+
@connection = ::Net::SSH.start(node_host_or_ip, user, net_ssh_params)
|
16
|
+
rescue Net::SSH::AuthenticationFailed, Net::SSH::Proxy::ConnectError, Net::SSH::ConnectionTimeout => e
|
17
|
+
raise Bcome::Exception::CouldNotInitiateSshConnection, @context_node.namespace + "\s-\s#{e.message}"
|
18
|
+
end
|
19
|
+
@connection
|
20
|
+
end
|
21
|
+
|
22
|
+
def close_ssh_connection
|
23
|
+
return unless @connection
|
24
|
+
|
25
|
+
begin
|
26
|
+
@connection.close unless @connection.closed?
|
27
|
+
@connection = nil
|
28
|
+
rescue Net::SCP::Error
|
29
|
+
@connection = nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def ssh_connection(ping = false)
|
34
|
+
if ping
|
35
|
+
# We do not cache ping results
|
36
|
+
ssh_connect!
|
37
|
+
else
|
38
|
+
has_open_ssh_con? ? @connection : ssh_connect!
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def has_open_ssh_con?
|
43
|
+
!@connection.nil? && !@connection.closed?
|
44
|
+
end
|
45
|
+
|
46
|
+
def node_host_or_ip
|
47
|
+
return @context_node.internal_ip_address if @context_node.local_network?
|
48
|
+
|
49
|
+
if has_proxy? || !@context_node.public_ip_address
|
50
|
+
@context_node.internal_ip_address
|
51
|
+
else
|
52
|
+
@context_node.public_ip_address
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def net_ssh_params
|
57
|
+
params = { paranoid: false }
|
58
|
+
params[:proxy] = proxy if has_proxy?
|
59
|
+
params[:timeout] = timeout_in_seconds
|
60
|
+
params[:verbose] = :fatal # All but silent
|
61
|
+
|
62
|
+
params
|
63
|
+
end
|
64
|
+
|
65
|
+
def timeout_in_seconds
|
66
|
+
@config[:timeout_in_seconds] ||= DEFAULT_TIMEOUT_IN_SECONDS
|
67
|
+
end
|
68
|
+
|
69
|
+
## PROXYING --
|
70
|
+
|
71
|
+
def proxy
|
72
|
+
connection_wrangler.proxy
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ::Bcome::Ssh
|
4
|
+
module DriverFunctions
|
5
|
+
def do_ssh
|
6
|
+
cmd = ssh_command
|
7
|
+
@context_node.execute_local(cmd)
|
8
|
+
end
|
9
|
+
|
10
|
+
def rsync(local_path, remote_path)
|
11
|
+
raise Bcome::Exception::MissingParamsForRsync, "'rsync' requires a local_path and a remote_path" if local_path.to_s.empty? || remote_path.to_s.empty?
|
12
|
+
|
13
|
+
command = rsync_command(local_path, remote_path)
|
14
|
+
@context_node.execute_local(command)
|
15
|
+
end
|
16
|
+
|
17
|
+
def local_port_forward(start_port, end_port)
|
18
|
+
tunnel_command = local_port_forward_command(start_port, end_port)
|
19
|
+
|
20
|
+
if ::Bcome::Workspace.instance.console_set?
|
21
|
+
puts "\sOpening ssh tunnel:\s".informational + tunnel_command.to_s.terminal_prompt
|
22
|
+
tunnel = ::Bcome::Ssh::Tunnel::LocalPortForward.new(tunnel_command)
|
23
|
+
::Bcome::Ssh::TunnelKeeper.instance << tunnel
|
24
|
+
tunnel.open!
|
25
|
+
tunnel
|
26
|
+
else
|
27
|
+
puts "\n\nOpening ssh tunnel".informational + "\slocalhost:#{start_port} ~> #{@context_node.namespace}:#{end_port}"
|
28
|
+
puts "\nTo use, navigate to another terminal window or application."
|
29
|
+
puts "\nctrl+c to close."
|
30
|
+
::Bcome::Command::Local.run(tunnel_command)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def ping
|
35
|
+
ssh_connect!
|
36
|
+
{ success: true }
|
37
|
+
rescue Exception => e
|
38
|
+
{ success: false, error: e, backtrace: e.backtrace }
|
39
|
+
end
|
40
|
+
|
41
|
+
def scp
|
42
|
+
ssh_connection.scp
|
43
|
+
end
|
44
|
+
|
45
|
+
def put(local_path, remote_path)
|
46
|
+
raise Bcome::Exception::MissingParamsForScp, "'put' requires a local_path and a remote_path" if local_path.to_s.empty? || remote_path.to_s.empty?
|
47
|
+
|
48
|
+
puts "\n(#{@context_node.namespace})\s".namespace + "Uploading #{local_path} to #{remote_path}\n".informational
|
49
|
+
|
50
|
+
begin
|
51
|
+
scp.upload!(local_path, remote_path, recursive: true) do |_ch, name, sent, total|
|
52
|
+
puts "#{name}: #{sent}/#{total}".progress
|
53
|
+
end
|
54
|
+
rescue Exception => e # scp just throws generic exceptions :-/
|
55
|
+
puts e.message.error
|
56
|
+
end
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def put_str(string, remote_path, silence_progress = false)
|
61
|
+
raise Bcome::Exception::MissingParamsForScp, "'put' requires a string and a remote_path" if string.nil? || remote_path.to_s.empty?
|
62
|
+
|
63
|
+
puts "\n(#{@context_node.namespace})\s".namespace + "Uploading from string to #{remote_path}\n".informational unless silence_progress
|
64
|
+
|
65
|
+
begin
|
66
|
+
scp.upload!(StringIO.new(string), remote_path) do |_ch, name, sent, total|
|
67
|
+
puts "#{name}: #{sent}/#{total}".progress unless silence_progress
|
68
|
+
end
|
69
|
+
rescue StandardError => e
|
70
|
+
raise ::Bcome::Exception::Generic, e.message
|
71
|
+
end
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
|
75
|
+
def get(remote_path, local_path)
|
76
|
+
raise Bcome::Exception::MissingParamsForScp, "'get' requires a local_path and a remote_path" if local_path.to_s.empty? || remote_path.to_s.empty?
|
77
|
+
|
78
|
+
puts "\n(#{@context_node.namespace})\s".namespace + "Downloading #{remote_path} to #{local_path}\n".informational
|
79
|
+
|
80
|
+
begin
|
81
|
+
scp.download!(remote_path, local_path, recursive: true) do |_ch, name, sent, total|
|
82
|
+
puts "#{name}: #{sent}/#{total}".progress
|
83
|
+
end
|
84
|
+
rescue Exception => e
|
85
|
+
puts e.message.error
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|