bcome 0.7.0 → 1.0.0
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.
- checksums.yaml +4 -4
- data/bin/bcome +8 -39
- data/lib/bcome.rb +12 -3
- data/lib/objects/bcome/version.rb +3 -0
- data/lib/objects/bootup.rb +81 -0
- data/lib/objects/command/local.rb +40 -0
- data/lib/objects/config_factory.rb +36 -0
- data/lib/objects/driver/base.rb +30 -0
- data/lib/objects/driver/bucket.rb +20 -0
- data/lib/objects/driver/ec2.rb +44 -0
- data/lib/objects/driver/static.rb +4 -0
- data/lib/objects/exception/argument_error_invoking_method_from_command_line.rb +7 -0
- data/lib/objects/exception/base.rb +15 -0
- data/lib/objects/exception/can_only_subselect_on_inventory.rb +7 -0
- data/lib/objects/exception/cannot_find_internal_registry_klass.rb +7 -0
- data/lib/objects/exception/cannot_find_subselection_parent.rb +7 -0
- data/lib/objects/exception/cant_find_key_in_cloud_tags.rb +7 -0
- data/lib/objects/exception/cant_find_key_in_metadata.rb +7 -0
- data/lib/objects/exception/cant_find_proxy_host_by_identifier.rb +7 -0
- data/lib/objects/exception/cant_find_proxy_host_by_namespace.rb +7 -0
- data/lib/objects/exception/could_not_initiate_ssh_connection.rb +7 -0
- data/lib/objects/exception/could_not_initiate_ssh_connection_through_backend_proxy.rb +7 -0
- data/lib/objects/exception/deprecation_warning.rb +11 -0
- data/lib/objects/exception/duplicate_command_line_argument_key.rb +7 -0
- data/lib/objects/exception/ec2_driver_missing_provisioning_region.rb +7 -0
- data/lib/objects/exception/failed_to_run_local_command.rb +7 -0
- data/lib/objects/exception/interactive_session_halt.rb +4 -0
- data/lib/objects/exception/invalid_bcome_breadcrumb.rb +7 -0
- data/lib/objects/exception/invalid_breadcrumb.rb +7 -0
- data/lib/objects/exception/invalid_context_command.rb +7 -0
- data/lib/objects/exception/invalid_identifier.rb +7 -0
- data/lib/objects/exception/invalid_machines_cache_config.rb +7 -0
- data/lib/objects/exception/invalid_matcher_query.rb +7 -0
- data/lib/objects/exception/invalid_meta_data_config.rb +7 -0
- data/lib/objects/exception/invalid_network_config.rb +7 -0
- data/lib/objects/exception/invalid_network_driver_type.rb +7 -0
- data/lib/objects/exception/invalid_proxy_config.rb +7 -0
- data/lib/objects/exception/invalid_regexp_matcher_in_registry.rb +7 -0
- data/lib/objects/exception/invalid_registry_arguments_type.rb +7 -0
- data/lib/objects/exception/invalid_registry_data_config.rb +7 -0
- data/lib/objects/exception/invalid_restriction_key_in_registry.rb +7 -0
- data/lib/objects/exception/invalid_ssh_config.rb +7 -0
- data/lib/objects/exception/inventories_cannot_have_subviews.rb +7 -0
- data/lib/objects/exception/malformed_command_line_arguments.rb +7 -0
- data/lib/objects/exception/method_invocation_requires_parameter.rb +7 -0
- data/lib/objects/exception/method_name_conflict_in_registry.rb +7 -0
- data/lib/objects/exception/missing_argument_for_registry_command.rb +7 -0
- data/lib/objects/exception/missing_description_on_view.rb +7 -0
- data/lib/objects/exception/missing_execute_on_registry_object.rb +7 -0
- data/lib/objects/exception/missing_identifier_on_view.rb +7 -0
- data/lib/objects/exception/missing_ip_address_on_server.rb +7 -0
- data/lib/objects/exception/missing_network_config.rb +7 -0
- data/lib/objects/exception/missing_params_for_rsync.rb +7 -0
- data/lib/objects/exception/missing_params_for_scp.rb +7 -0
- data/lib/objects/exception/missing_subselection_key.rb +7 -0
- data/lib/objects/exception/missing_type_on_view.rb +7 -0
- data/lib/objects/exception/no_node_found_for_breadcrumb.rb +7 -0
- data/lib/objects/exception/no_node_named_by_identifier.rb +7 -0
- data/lib/objects/exception/node_identifiers_must_be_unique.rb +7 -0
- data/lib/objects/exception/orchestration_script_does_not_exist.rb +7 -0
- data/lib/objects/exception/proxy_host_node_does_not_have_public_ip_address.rb +7 -0
- data/lib/objects/exception/unknown_method_for_namespace.rb +7 -0
- data/lib/objects/interactive/session.rb +45 -0
- data/lib/objects/interactive/session_item/base.rb +36 -0
- data/lib/objects/interactive/session_item/capture_input.rb +20 -0
- data/lib/objects/interactive/session_item/transparent_ssh.rb +111 -0
- data/lib/objects/modules/context.rb +13 -0
- data/lib/objects/modules/registry_management.rb +14 -0
- data/lib/objects/modules/ui_output.rb +9 -0
- data/lib/objects/modules/workspace_commands.rb +198 -0
- data/lib/objects/modules/workspace_menu.rb +128 -0
- data/lib/objects/node/attributes.rb +47 -0
- data/lib/objects/node/base.rb +248 -0
- data/lib/objects/node/cache_handler.rb +24 -0
- data/lib/objects/node/collection.rb +51 -0
- data/lib/objects/node/factory.rb +108 -0
- data/lib/objects/node/inventory/base.rb +88 -0
- data/lib/objects/node/inventory/defined.rb +112 -0
- data/lib/objects/node/inventory/subselect.rb +54 -0
- data/lib/objects/node/meta/base.rb +36 -0
- data/lib/objects/node/meta/cloud.rb +4 -0
- data/lib/objects/node/meta/local.rb +4 -0
- data/lib/objects/node/meta_data_factory.rb +23 -0
- data/lib/objects/node/meta_data_loader.rb +32 -0
- data/lib/objects/node/resources/base.rb +98 -0
- data/lib/objects/node/resources/inventory.rb +25 -0
- data/lib/objects/node/resources/sub_inventory.rb +56 -0
- data/lib/objects/node/server/base.rb +218 -0
- data/lib/objects/node/server/dynamic.rb +39 -0
- data/lib/objects/node/server/static.rb +31 -0
- data/lib/objects/orchestration/base.rb +13 -0
- data/lib/objects/orchestrator.rb +24 -0
- data/lib/objects/parser/bread_crumb.rb +31 -0
- data/lib/objects/progress_bar.rb +30 -0
- data/lib/objects/registry/arguments/base.rb +36 -0
- data/lib/objects/registry/arguments/command_line.rb +35 -0
- data/lib/objects/registry/arguments/console.rb +15 -0
- data/lib/objects/registry/command/base.rb +66 -0
- data/lib/objects/registry/command/external.rb +55 -0
- data/lib/objects/registry/command/group.rb +76 -0
- data/lib/objects/registry/command/internal.rb +34 -0
- data/lib/objects/registry/command_list.rb +33 -0
- data/lib/objects/registry/loader.rb +70 -0
- data/lib/objects/ssh/bootstrap.rb +19 -0
- data/lib/objects/ssh/command.rb +46 -0
- data/lib/objects/ssh/command_exec.rb +65 -0
- data/lib/objects/ssh/connection_handler.rb +101 -0
- data/lib/objects/ssh/driver.rb +204 -0
- data/lib/objects/ssh/proxy_data.rb +56 -0
- data/lib/objects/ssh/script_exec.rb +43 -0
- data/lib/objects/system/local.rb +30 -0
- data/lib/objects/workspace.rb +75 -0
- data/patches/irb.rb +20 -7
- data/patches/string.rb +75 -0
- data/patches/string_stylesheet.rb +61 -0
- metadata +175 -93
- data/bin/bcome-bash-setup +0 -18
- data/bin/bcome-setup +0 -43
- data/bin/boot.rb +0 -148
- data/bin/boot_no_shell.rb +0 -3
- data/filters/ec2_filter.rb +0 -12
- data/lib/bcome/version.rb +0 -3
- data/lib/become_object.rb +0 -111
- data/lib/boot.rb +0 -13
- data/lib/command.rb +0 -56
- data/lib/context_functions.rb +0 -65
- data/lib/filters/base.rb +0 -10
- data/lib/filters/ec2_filter.rb +0 -4
- data/lib/functions.rb +0 -70
- data/lib/helpers/command_helper.rb +0 -13
- data/lib/helpers/environment_ssh.rb +0 -122
- data/lib/helpers/fog_helper.rb +0 -108
- data/lib/helpers/instance_command.rb +0 -71
- data/lib/helpers/instance_ssh.rb +0 -83
- data/lib/helpers/selections.rb +0 -117
- data/lib/interactive/interactive_session_halt.rb +0 -4
- data/lib/interactive/session.rb +0 -44
- data/lib/interactive/session_item/base.rb +0 -30
- data/lib/interactive/session_item/transparent_ssh.rb +0 -133
- data/lib/nodes/base.rb +0 -60
- data/lib/nodes/environment.rb +0 -30
- data/lib/nodes/estate.rb +0 -44
- data/lib/nodes/instance.rb +0 -94
- data/lib/nodes/platform.rb +0 -17
- data/lib/nodes/view.rb +0 -31
- data/lib/object.rb +0 -21
- data/lib/orchestrator/command_group/base.rb +0 -56
- data/lib/orchestrator/command_group/custom.rb +0 -13
- data/lib/orchestrator/command_group/direct.rb +0 -53
- data/lib/orchestrator/direct_command/group.rb +0 -21
- data/lib/orchestrator/direct_command/instance.rb +0 -19
- data/lib/orchestrator/factory.rb +0 -38
- data/lib/orchestrator/loader.rb +0 -47
- data/lib/orchestrator/node_target/all.rb +0 -14
- data/lib/orchestrator/node_target/all_excluding_roles.rb +0 -14
- data/lib/orchestrator/node_target/all_with_roles.rb +0 -14
- data/lib/orchestrator/node_target/base.rb +0 -43
- data/lib/orchestrator/node_target/single.rb +0 -12
- data/lib/orchestrator/recipe.rb +0 -60
- data/lib/orchestrator/registry.rb +0 -37
- data/lib/orchestrator/validate_and_set.rb +0 -10
- data/lib/patches/string.rb +0 -86
- data/lib/progress_bar.rb +0 -31
- data/lib/render_irb.rb +0 -53
- data/lib/scp.rb +0 -40
- data/lib/ssh.rb +0 -51
- data/lib/stack/base.rb +0 -148
- data/lib/stack/environment.rb +0 -222
- data/lib/stack/estate.rb +0 -50
- data/lib/stack/instance.rb +0 -130
- data/lib/stack/platform.rb +0 -74
- data/lib/stack/view.rb +0 -56
- data/lib/workspace_context.rb +0 -40
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Bcome::Ssh
|
|
2
|
+
class Bootstrap
|
|
3
|
+
def initialize(config)
|
|
4
|
+
@config = config
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def ssh_key_path
|
|
8
|
+
@config[:ssh_key_path]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def user
|
|
12
|
+
@config[:user]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def bastion_host_user
|
|
16
|
+
@config[:bastion_host_user]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module ::Bcome::Ssh
|
|
2
|
+
class Command
|
|
3
|
+
attr_reader :raw, :stdout, :stderr, :exit_code, :node, :bootstrap
|
|
4
|
+
|
|
5
|
+
def initialize(params)
|
|
6
|
+
@raw = params[:raw]
|
|
7
|
+
@node = params[:node]
|
|
8
|
+
@exit_code = nil
|
|
9
|
+
@exit_signal = nil
|
|
10
|
+
@stdin = ''; @stdout = ''; @stderr = ''
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def unset_node
|
|
14
|
+
@node = nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def pretty_result
|
|
18
|
+
is_success? ? 'success'.success : 'failure'.error
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
attr_writer :bootstrap
|
|
22
|
+
|
|
23
|
+
def output
|
|
24
|
+
command_output = is_success? ? @stdout : "Exit code: #{@exit_code}\n\nSTDERR: #{@stderr}"
|
|
25
|
+
"\n#{command_output}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def is_success?
|
|
29
|
+
exit_code.to_i == 0
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def success_codes
|
|
33
|
+
['0']
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
attr_writer :stdout
|
|
37
|
+
|
|
38
|
+
attr_writer :stderr
|
|
39
|
+
|
|
40
|
+
attr_writer :exit_code
|
|
41
|
+
|
|
42
|
+
def exit_signal(data)
|
|
43
|
+
@exit_signal = data
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module ::Bcome::Ssh
|
|
2
|
+
class CommandExec
|
|
3
|
+
attr_reader :commands
|
|
4
|
+
|
|
5
|
+
def initialize(commands)
|
|
6
|
+
@commands = commands
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def output_append(output_string)
|
|
10
|
+
@output_string = "#{@output_string}#{output_string}"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def print_output
|
|
14
|
+
print "#{@output_string}\n\n"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def execute!
|
|
18
|
+
# TODO: - catch IOError: closed stream here and re-connect gracefully
|
|
19
|
+
# to reproduce: open connections, and let them timeout then re-enter command (interactive mode)
|
|
20
|
+
|
|
21
|
+
@commands.each do |command|
|
|
22
|
+
node = command.node
|
|
23
|
+
ssh = node.ssh_driver.ssh_connection
|
|
24
|
+
|
|
25
|
+
begin
|
|
26
|
+
ssh_exec!(ssh, command)
|
|
27
|
+
rescue IOError # Typically occurs after a timeout if the session has been left idle
|
|
28
|
+
node.open_ssh_connection
|
|
29
|
+
ssh_exec!(ssh, command) # retry, once
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
output_append("\n(#{node.namespace})$".terminal_prompt + ">\s#{command.raw} (#{command.pretty_result})\n")
|
|
33
|
+
output_append(command.output.to_s)
|
|
34
|
+
end
|
|
35
|
+
print_output unless ::Bcome::Orchestrator.instance.command_output_silenced?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def ssh_exec!(ssh, command) # NON PTY (i.e no pseudo-terminal)
|
|
39
|
+
ssh.open_channel do |channel|
|
|
40
|
+
channel.exec(command.raw) do |_cha, success|
|
|
41
|
+
unless success
|
|
42
|
+
abort "FAILED: couldn't execute command (ssh.channel.exec)"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
channel.on_data do |_ch, data|
|
|
46
|
+
command.stdout += data
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
channel.on_extended_data do |_ch, _type, data|
|
|
50
|
+
command.stderr += data
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
channel.on_request('exit-status') do |_ch, data|
|
|
54
|
+
command.exit_code = data.read_long
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
channel.on_request('exit-signal') do |_ch, data|
|
|
58
|
+
command.exit_signal = data.read_long
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
ssh.loop
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
module Bcome::Ssh
|
|
2
|
+
class ConnectionHandler
|
|
3
|
+
MAX_CONNECTION_ATTEMPTS = 3
|
|
4
|
+
|
|
5
|
+
class << self
|
|
6
|
+
def connect(node, config = {})
|
|
7
|
+
handler = new(node, config)
|
|
8
|
+
handler.connect
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initialize(node, config = {})
|
|
13
|
+
@node = node
|
|
14
|
+
@config = config
|
|
15
|
+
@servers_to_connect = machines.dup
|
|
16
|
+
@connection_exceptions = {}
|
|
17
|
+
reset_progress if show_progress?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def machines
|
|
21
|
+
@node.server? ? [@node] : @node.machines
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def show_progress?
|
|
25
|
+
@config[:show_progress] ? true : false
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def ping?
|
|
29
|
+
@config[:is_ping] ? true : false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def reset_progress
|
|
33
|
+
::Bcome::ProgressBar.instance.reset!
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def ping
|
|
37
|
+
connect
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def connect
|
|
41
|
+
connection_attempt = 0
|
|
42
|
+
::Bcome::ProgressBar.instance.indicate(progress_bar_config, true) if show_progress?
|
|
43
|
+
|
|
44
|
+
# So here we have a bit of a hack: If you're connecting to a network via a bastion host, it may not be able to handle over a certain amount of consecutive/parallelized ssh connection attempts
|
|
45
|
+
# from bcome, so, we'll sweep up failures and re-try to connect up to MAX_CONNECTION_ATTEMPTS. Once connected, we're generally good - and any subsequent connection failures
|
|
46
|
+
# within a specific session will be handled ad-hoc and re-connection is automatic.
|
|
47
|
+
while @servers_to_connect.any? && connection_attempt <= MAX_CONNECTION_ATTEMPTS
|
|
48
|
+
puts connection_attempt == 0 ? 'Initiating connections'.informational : 'Retrying failed connections'.warning
|
|
49
|
+
do_connect
|
|
50
|
+
connection_attempt += 1
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if show_progress?
|
|
54
|
+
::Bcome::ProgressBar.instance.indicate(progress_bar_config, false)
|
|
55
|
+
reset_progress
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if ping?
|
|
59
|
+
# If any machines remain, then we couldn't connect to them
|
|
60
|
+
@servers_to_connect.each do |server|
|
|
61
|
+
ping_result = {
|
|
62
|
+
success: false,
|
|
63
|
+
error: last_connection_exception_for(server)
|
|
64
|
+
}
|
|
65
|
+
puts server.print_ping_result(ping_result)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
if @servers_to_connect.any?
|
|
70
|
+
puts "Failed to connect to #{@servers_to_connect.size} nodes".error
|
|
71
|
+
else
|
|
72
|
+
puts 'All nodes reachable'.success
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def last_connection_exception_for(server)
|
|
77
|
+
@connection_exceptions[server]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def do_connect
|
|
81
|
+
@servers_to_connect.pmap do |server|
|
|
82
|
+
begin
|
|
83
|
+
server.open_ssh_connection unless server.has_ssh_connection?
|
|
84
|
+
Bcome::ProgressBar.instance.indicate_and_increment!(progress_bar_config, true) if show_progress?
|
|
85
|
+
@servers_to_connect -= [server]
|
|
86
|
+
puts server.print_ping_result if ping?
|
|
87
|
+
rescue Exception => e
|
|
88
|
+
@connection_exceptions[server] = e
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def progress_bar_config
|
|
94
|
+
{
|
|
95
|
+
prefix: "\sOpening SSH connections\s",
|
|
96
|
+
indice: '...',
|
|
97
|
+
indice_descriptor: "of #{machines.size}"
|
|
98
|
+
}
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
module Bcome::Ssh
|
|
2
|
+
class Driver
|
|
3
|
+
attr_reader :config, :bootstrap_settings
|
|
4
|
+
|
|
5
|
+
DEFAULT_TIMEOUT_IN_SECONDS = 5
|
|
6
|
+
PROXY_CONNECT_PREFIX = '-o StrictHostKeyChecking=no -W %h:%p'.freeze
|
|
7
|
+
PROXY_SSH_PREFIX = '-o UserKnownHostsFile=/dev/null -o "ProxyCommand ssh -W %h:%p'.freeze
|
|
8
|
+
|
|
9
|
+
def initialize(config, context_node)
|
|
10
|
+
@config = config
|
|
11
|
+
@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
|
+
end
|
|
15
|
+
|
|
16
|
+
def bootstrap?
|
|
17
|
+
@context_node.bootstrap? && has_bootstrap_settings?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def has_bootstrap_settings?
|
|
21
|
+
!@bootstrap_settings.nil?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def pretty_config_details
|
|
25
|
+
config = {
|
|
26
|
+
user: user,
|
|
27
|
+
ssh_keys: ssh_keys,
|
|
28
|
+
timeout: timeout_in_seconds
|
|
29
|
+
}
|
|
30
|
+
if has_proxy?
|
|
31
|
+
config[:host_or_ip] = @context_node.internal_ip_address
|
|
32
|
+
config[:proxy] = {
|
|
33
|
+
bastion_host: @proxy_data.host,
|
|
34
|
+
bastion_host_user: bastion_host_user
|
|
35
|
+
}
|
|
36
|
+
else
|
|
37
|
+
config[:host_or_ip] = @context_node.public_ip_address
|
|
38
|
+
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
|
+
|
|
46
|
+
def proxy
|
|
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
|
+
!@config[:proxy].nil?
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def proxy_connection_string
|
|
57
|
+
"ssh #{PROXY_CONNECT_PREFIX} #{bastion_host_user}@#{@proxy_data.host}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def bootstrap_proxy_connection_string
|
|
61
|
+
"ssh -i #{@bootstrap_settings.ssh_key_path} -o StrictHostKeyChecking=no -W %h:%p #{@bootstrap_settings.bastion_host_user}@#{@proxy_data.host}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def do_ssh
|
|
65
|
+
cmd = ssh_command
|
|
66
|
+
@context_node.execute_local(cmd)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def bastion_host_user
|
|
70
|
+
bootstrap? && @bootstrap_settings.bastion_host_user ? @bootstrap_settings.bastion_host_user : @proxy_data.bastion_host_user ? @proxy_data.bastion_host_user : user
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def ssh_command
|
|
74
|
+
return bootstrap_ssh_command if bootstrap? && @bootstrap_settings.ssh_key_path
|
|
75
|
+
if has_proxy?
|
|
76
|
+
"ssh #{PROXY_SSH_PREFIX} #{bastion_host_user}@#{@proxy_data.host}\" #{user}@#{@context_node.internal_ip_address}"
|
|
77
|
+
else
|
|
78
|
+
"ssh #{user}@#{@context_node.public_ip_address}"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def bootstrap_ssh_command
|
|
83
|
+
if has_proxy?
|
|
84
|
+
"ssh -i #{@bootstrap_settings.ssh_key_path} -t #{bastion_host_user}@#{@proxy_data.host} ssh -t #{user}@#{@context_node.internal_ip_address}"
|
|
85
|
+
else
|
|
86
|
+
"ssh -i #{@bootstrap_settings.ssh_key_path} #{user}@#{@context_node.public_ip_address}"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def user
|
|
91
|
+
bootstrap? && @bootstrap_settings.user ? @bootstrap_settings.user : @config[:user] ? @config[:user] : fallback_local_user
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def fallback_local_user
|
|
95
|
+
@fallback_local_user ||= ::Bcome::System::Local.instance.local_user
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def node_host_or_ip
|
|
99
|
+
has_proxy? ? @context_node.internal_ip_address : @context_node.public_ip_address
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def net_ssh_params(verbose = false)
|
|
103
|
+
raise Bcome::Exception::InvalidSshConfig, "Missing ssh keys for #{@context_node.namespace}" unless ssh_keys
|
|
104
|
+
params = { keys: ssh_keys, paranoid: false }
|
|
105
|
+
params[:proxy] = proxy if has_proxy?
|
|
106
|
+
params[:timeout] = timeout_in_seconds
|
|
107
|
+
params[:verbose] = :debug if verbose
|
|
108
|
+
params
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def ssh_keys
|
|
112
|
+
if bootstrap?
|
|
113
|
+
[@bootstrap_settings.ssh_key_path]
|
|
114
|
+
else
|
|
115
|
+
@config[:ssh_keys]
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def rsync(local_path, remote_path)
|
|
120
|
+
raise Bcome::Exception::MissingParamsForRsync, "'rsync' requires a local_path and a remote_path" if local_path.to_s.empty? || remote_path.to_s.empty?
|
|
121
|
+
command = rsync_command(local_path, remote_path)
|
|
122
|
+
@context_node.execute_local(command)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def rsync_command(local_path, remote_path)
|
|
126
|
+
return bootstrap_rsync_command(local_path, remote_path) if bootstrap? && @bootstrap_settings.ssh_key_path
|
|
127
|
+
if has_proxy?
|
|
128
|
+
"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}"
|
|
129
|
+
else
|
|
130
|
+
"rsync -av #{local_path} #{user}@#{@context_node.public_ip_address}:#{remote_path}"
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def bootstrap_rsync_command(local_path, remote_path)
|
|
135
|
+
if has_proxy?
|
|
136
|
+
"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}"
|
|
137
|
+
else
|
|
138
|
+
"rsync -i #{@bootstrap_settings.ssh_key_path} -av #{local_path} #{user}@#{@context_node.public_ip_address}:#{remote_path}"
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def ssh_connect!(_verbose = false)
|
|
143
|
+
@connection = nil
|
|
144
|
+
begin
|
|
145
|
+
@connection = ::Net::SSH.start(node_host_or_ip, user, net_ssh_params)
|
|
146
|
+
rescue Net::SSH::Proxy::ConnectError, Net::SSH::ConnectionTimeout, Errno::EPIPE => e
|
|
147
|
+
raise Bcome::Exception::CouldNotInitiateSshConnection, @context_node.namespace + "\s-\s#{e.message}"
|
|
148
|
+
end
|
|
149
|
+
@connection
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def ping
|
|
153
|
+
ssh_connect!
|
|
154
|
+
return { success: true }
|
|
155
|
+
rescue Exception => e
|
|
156
|
+
return { success: false, error: e }
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def scp
|
|
160
|
+
ssh_connection.scp
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def put(local_path, remote_path)
|
|
164
|
+
raise Bcome::Exception::MissingParamsForScp, "'put' requires a local_path and a remote_path" if local_path.to_s.empty? || remote_path.to_s.empty?
|
|
165
|
+
puts "\n(#{@context_node.namespace})\s".namespace + "Uploading #{local_path} to #{remote_path}\n".informational
|
|
166
|
+
|
|
167
|
+
begin
|
|
168
|
+
scp.upload!(local_path, remote_path, recursive: true) do |_ch, name, sent, total|
|
|
169
|
+
puts "#{name}: #{sent}/#{total}".progress
|
|
170
|
+
end
|
|
171
|
+
rescue Exception => e # scp just throws generic exceptions :-/
|
|
172
|
+
puts e.message.error
|
|
173
|
+
end
|
|
174
|
+
nil
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def get(remote_path, local_path)
|
|
178
|
+
raise Bcome::Exception::MissingParamsForScp, "'get' requires a local_path and a remote_path" if local_path.to_s.empty? || remote_path.to_s.empty?
|
|
179
|
+
puts "\n(#{@context_node.namespace})\s".namespace + "Downloading #{remote_path} to #{local_path}\n".informational
|
|
180
|
+
|
|
181
|
+
begin
|
|
182
|
+
scp.download!(remote_path, local_path, recursive: true) do |_ch, name, sent, total|
|
|
183
|
+
puts "#{name}: #{sent}/#{total}".progress
|
|
184
|
+
end
|
|
185
|
+
rescue Exception => e # scp just throws generic exceptions :-/
|
|
186
|
+
puts e.message.error
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def close_ssh_connection
|
|
191
|
+
return unless @connection
|
|
192
|
+
@connection.close unless @connection.closed?
|
|
193
|
+
@connection = nil
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def ssh_connection(_bootstrap = false)
|
|
197
|
+
has_open_ssh_con? ? @connection : ssh_connect!
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def has_open_ssh_con?
|
|
201
|
+
!@connection.nil? && !@connection.closed?
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module Bcome::Ssh
|
|
2
|
+
class ProxyData
|
|
3
|
+
def initialize(config, context_node)
|
|
4
|
+
@config = config
|
|
5
|
+
@context_node = context_node
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def host
|
|
9
|
+
@host ||= get_host
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def bastion_host_user
|
|
13
|
+
@bastion_host_user ||= get_bastion_host_user
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def valid_host_lookups
|
|
19
|
+
{
|
|
20
|
+
by_inventory_node: :get_host_by_inventory_node,
|
|
21
|
+
by_host_or_ip: :get_host_or_ip_from_config,
|
|
22
|
+
by_bcome_namespace: :get_host_by_namespace
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def get_bastion_host_user
|
|
27
|
+
@config[:bastion_host_user]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def get_host
|
|
31
|
+
raise Bcome::Exception::InvalidProxyConfig, 'Missing host id or namespace' unless @config[:host_id] || @config[:namespace]
|
|
32
|
+
raise Bcome::Exception::InvalidProxyConfig, 'Missing host lookup method' unless @config[:host_lookup]
|
|
33
|
+
host_lookup_method = valid_host_lookups[@config[:host_lookup].to_sym]
|
|
34
|
+
raise Bcome::Exception::InvalidProxyConfig, "#{@config[:host_lookup]} is not a valid host lookup method" unless host_lookup_method
|
|
35
|
+
send(host_lookup_method)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def get_host_or_ip_from_config
|
|
39
|
+
@config[:host_id]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def get_host_by_inventory_node
|
|
43
|
+
identifier = @config[:host_id]
|
|
44
|
+
resource = @context_node.recurse_resource_for_identifier(identifier)
|
|
45
|
+
raise Bcome::Exception::CantFindProxyHostByIdentifier, identifier unless resource
|
|
46
|
+
raise Bcome::Exception::ProxyHostNodeDoesNotHavePublicIp, identifier unless resource.public_ip_address
|
|
47
|
+
resource.public_ip_address
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def get_host_by_namespace
|
|
51
|
+
node = ::Bcome::Orchestrator.instance.get(@config[:namespace])
|
|
52
|
+
raise Bcome::Exception::CantFindProxyHostByNamespace, @config[:namespace] unless node
|
|
53
|
+
node.public_ip_address
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|