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.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/bin/bcome +8 -39
  3. data/lib/bcome.rb +12 -3
  4. data/lib/objects/bcome/version.rb +3 -0
  5. data/lib/objects/bootup.rb +81 -0
  6. data/lib/objects/command/local.rb +40 -0
  7. data/lib/objects/config_factory.rb +36 -0
  8. data/lib/objects/driver/base.rb +30 -0
  9. data/lib/objects/driver/bucket.rb +20 -0
  10. data/lib/objects/driver/ec2.rb +44 -0
  11. data/lib/objects/driver/static.rb +4 -0
  12. data/lib/objects/exception/argument_error_invoking_method_from_command_line.rb +7 -0
  13. data/lib/objects/exception/base.rb +15 -0
  14. data/lib/objects/exception/can_only_subselect_on_inventory.rb +7 -0
  15. data/lib/objects/exception/cannot_find_internal_registry_klass.rb +7 -0
  16. data/lib/objects/exception/cannot_find_subselection_parent.rb +7 -0
  17. data/lib/objects/exception/cant_find_key_in_cloud_tags.rb +7 -0
  18. data/lib/objects/exception/cant_find_key_in_metadata.rb +7 -0
  19. data/lib/objects/exception/cant_find_proxy_host_by_identifier.rb +7 -0
  20. data/lib/objects/exception/cant_find_proxy_host_by_namespace.rb +7 -0
  21. data/lib/objects/exception/could_not_initiate_ssh_connection.rb +7 -0
  22. data/lib/objects/exception/could_not_initiate_ssh_connection_through_backend_proxy.rb +7 -0
  23. data/lib/objects/exception/deprecation_warning.rb +11 -0
  24. data/lib/objects/exception/duplicate_command_line_argument_key.rb +7 -0
  25. data/lib/objects/exception/ec2_driver_missing_provisioning_region.rb +7 -0
  26. data/lib/objects/exception/failed_to_run_local_command.rb +7 -0
  27. data/lib/objects/exception/interactive_session_halt.rb +4 -0
  28. data/lib/objects/exception/invalid_bcome_breadcrumb.rb +7 -0
  29. data/lib/objects/exception/invalid_breadcrumb.rb +7 -0
  30. data/lib/objects/exception/invalid_context_command.rb +7 -0
  31. data/lib/objects/exception/invalid_identifier.rb +7 -0
  32. data/lib/objects/exception/invalid_machines_cache_config.rb +7 -0
  33. data/lib/objects/exception/invalid_matcher_query.rb +7 -0
  34. data/lib/objects/exception/invalid_meta_data_config.rb +7 -0
  35. data/lib/objects/exception/invalid_network_config.rb +7 -0
  36. data/lib/objects/exception/invalid_network_driver_type.rb +7 -0
  37. data/lib/objects/exception/invalid_proxy_config.rb +7 -0
  38. data/lib/objects/exception/invalid_regexp_matcher_in_registry.rb +7 -0
  39. data/lib/objects/exception/invalid_registry_arguments_type.rb +7 -0
  40. data/lib/objects/exception/invalid_registry_data_config.rb +7 -0
  41. data/lib/objects/exception/invalid_restriction_key_in_registry.rb +7 -0
  42. data/lib/objects/exception/invalid_ssh_config.rb +7 -0
  43. data/lib/objects/exception/inventories_cannot_have_subviews.rb +7 -0
  44. data/lib/objects/exception/malformed_command_line_arguments.rb +7 -0
  45. data/lib/objects/exception/method_invocation_requires_parameter.rb +7 -0
  46. data/lib/objects/exception/method_name_conflict_in_registry.rb +7 -0
  47. data/lib/objects/exception/missing_argument_for_registry_command.rb +7 -0
  48. data/lib/objects/exception/missing_description_on_view.rb +7 -0
  49. data/lib/objects/exception/missing_execute_on_registry_object.rb +7 -0
  50. data/lib/objects/exception/missing_identifier_on_view.rb +7 -0
  51. data/lib/objects/exception/missing_ip_address_on_server.rb +7 -0
  52. data/lib/objects/exception/missing_network_config.rb +7 -0
  53. data/lib/objects/exception/missing_params_for_rsync.rb +7 -0
  54. data/lib/objects/exception/missing_params_for_scp.rb +7 -0
  55. data/lib/objects/exception/missing_subselection_key.rb +7 -0
  56. data/lib/objects/exception/missing_type_on_view.rb +7 -0
  57. data/lib/objects/exception/no_node_found_for_breadcrumb.rb +7 -0
  58. data/lib/objects/exception/no_node_named_by_identifier.rb +7 -0
  59. data/lib/objects/exception/node_identifiers_must_be_unique.rb +7 -0
  60. data/lib/objects/exception/orchestration_script_does_not_exist.rb +7 -0
  61. data/lib/objects/exception/proxy_host_node_does_not_have_public_ip_address.rb +7 -0
  62. data/lib/objects/exception/unknown_method_for_namespace.rb +7 -0
  63. data/lib/objects/interactive/session.rb +45 -0
  64. data/lib/objects/interactive/session_item/base.rb +36 -0
  65. data/lib/objects/interactive/session_item/capture_input.rb +20 -0
  66. data/lib/objects/interactive/session_item/transparent_ssh.rb +111 -0
  67. data/lib/objects/modules/context.rb +13 -0
  68. data/lib/objects/modules/registry_management.rb +14 -0
  69. data/lib/objects/modules/ui_output.rb +9 -0
  70. data/lib/objects/modules/workspace_commands.rb +198 -0
  71. data/lib/objects/modules/workspace_menu.rb +128 -0
  72. data/lib/objects/node/attributes.rb +47 -0
  73. data/lib/objects/node/base.rb +248 -0
  74. data/lib/objects/node/cache_handler.rb +24 -0
  75. data/lib/objects/node/collection.rb +51 -0
  76. data/lib/objects/node/factory.rb +108 -0
  77. data/lib/objects/node/inventory/base.rb +88 -0
  78. data/lib/objects/node/inventory/defined.rb +112 -0
  79. data/lib/objects/node/inventory/subselect.rb +54 -0
  80. data/lib/objects/node/meta/base.rb +36 -0
  81. data/lib/objects/node/meta/cloud.rb +4 -0
  82. data/lib/objects/node/meta/local.rb +4 -0
  83. data/lib/objects/node/meta_data_factory.rb +23 -0
  84. data/lib/objects/node/meta_data_loader.rb +32 -0
  85. data/lib/objects/node/resources/base.rb +98 -0
  86. data/lib/objects/node/resources/inventory.rb +25 -0
  87. data/lib/objects/node/resources/sub_inventory.rb +56 -0
  88. data/lib/objects/node/server/base.rb +218 -0
  89. data/lib/objects/node/server/dynamic.rb +39 -0
  90. data/lib/objects/node/server/static.rb +31 -0
  91. data/lib/objects/orchestration/base.rb +13 -0
  92. data/lib/objects/orchestrator.rb +24 -0
  93. data/lib/objects/parser/bread_crumb.rb +31 -0
  94. data/lib/objects/progress_bar.rb +30 -0
  95. data/lib/objects/registry/arguments/base.rb +36 -0
  96. data/lib/objects/registry/arguments/command_line.rb +35 -0
  97. data/lib/objects/registry/arguments/console.rb +15 -0
  98. data/lib/objects/registry/command/base.rb +66 -0
  99. data/lib/objects/registry/command/external.rb +55 -0
  100. data/lib/objects/registry/command/group.rb +76 -0
  101. data/lib/objects/registry/command/internal.rb +34 -0
  102. data/lib/objects/registry/command_list.rb +33 -0
  103. data/lib/objects/registry/loader.rb +70 -0
  104. data/lib/objects/ssh/bootstrap.rb +19 -0
  105. data/lib/objects/ssh/command.rb +46 -0
  106. data/lib/objects/ssh/command_exec.rb +65 -0
  107. data/lib/objects/ssh/connection_handler.rb +101 -0
  108. data/lib/objects/ssh/driver.rb +204 -0
  109. data/lib/objects/ssh/proxy_data.rb +56 -0
  110. data/lib/objects/ssh/script_exec.rb +43 -0
  111. data/lib/objects/system/local.rb +30 -0
  112. data/lib/objects/workspace.rb +75 -0
  113. data/patches/irb.rb +20 -7
  114. data/patches/string.rb +75 -0
  115. data/patches/string_stylesheet.rb +61 -0
  116. metadata +175 -93
  117. data/bin/bcome-bash-setup +0 -18
  118. data/bin/bcome-setup +0 -43
  119. data/bin/boot.rb +0 -148
  120. data/bin/boot_no_shell.rb +0 -3
  121. data/filters/ec2_filter.rb +0 -12
  122. data/lib/bcome/version.rb +0 -3
  123. data/lib/become_object.rb +0 -111
  124. data/lib/boot.rb +0 -13
  125. data/lib/command.rb +0 -56
  126. data/lib/context_functions.rb +0 -65
  127. data/lib/filters/base.rb +0 -10
  128. data/lib/filters/ec2_filter.rb +0 -4
  129. data/lib/functions.rb +0 -70
  130. data/lib/helpers/command_helper.rb +0 -13
  131. data/lib/helpers/environment_ssh.rb +0 -122
  132. data/lib/helpers/fog_helper.rb +0 -108
  133. data/lib/helpers/instance_command.rb +0 -71
  134. data/lib/helpers/instance_ssh.rb +0 -83
  135. data/lib/helpers/selections.rb +0 -117
  136. data/lib/interactive/interactive_session_halt.rb +0 -4
  137. data/lib/interactive/session.rb +0 -44
  138. data/lib/interactive/session_item/base.rb +0 -30
  139. data/lib/interactive/session_item/transparent_ssh.rb +0 -133
  140. data/lib/nodes/base.rb +0 -60
  141. data/lib/nodes/environment.rb +0 -30
  142. data/lib/nodes/estate.rb +0 -44
  143. data/lib/nodes/instance.rb +0 -94
  144. data/lib/nodes/platform.rb +0 -17
  145. data/lib/nodes/view.rb +0 -31
  146. data/lib/object.rb +0 -21
  147. data/lib/orchestrator/command_group/base.rb +0 -56
  148. data/lib/orchestrator/command_group/custom.rb +0 -13
  149. data/lib/orchestrator/command_group/direct.rb +0 -53
  150. data/lib/orchestrator/direct_command/group.rb +0 -21
  151. data/lib/orchestrator/direct_command/instance.rb +0 -19
  152. data/lib/orchestrator/factory.rb +0 -38
  153. data/lib/orchestrator/loader.rb +0 -47
  154. data/lib/orchestrator/node_target/all.rb +0 -14
  155. data/lib/orchestrator/node_target/all_excluding_roles.rb +0 -14
  156. data/lib/orchestrator/node_target/all_with_roles.rb +0 -14
  157. data/lib/orchestrator/node_target/base.rb +0 -43
  158. data/lib/orchestrator/node_target/single.rb +0 -12
  159. data/lib/orchestrator/recipe.rb +0 -60
  160. data/lib/orchestrator/registry.rb +0 -37
  161. data/lib/orchestrator/validate_and_set.rb +0 -10
  162. data/lib/patches/string.rb +0 -86
  163. data/lib/progress_bar.rb +0 -31
  164. data/lib/render_irb.rb +0 -53
  165. data/lib/scp.rb +0 -40
  166. data/lib/ssh.rb +0 -51
  167. data/lib/stack/base.rb +0 -148
  168. data/lib/stack/environment.rb +0 -222
  169. data/lib/stack/estate.rb +0 -50
  170. data/lib/stack/instance.rb +0 -130
  171. data/lib/stack/platform.rb +0 -74
  172. data/lib/stack/view.rb +0 -56
  173. 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