bcome 1.4.0 → 2.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/lib/bcome.rb +7 -0
- data/lib/objects/bcome/version.rb +3 -3
- data/lib/objects/bootup.rb +4 -3
- data/lib/objects/driver/base.rb +16 -2
- data/lib/objects/driver/ec2.rb +11 -2
- data/lib/objects/driver/gcp.rb +49 -5
- data/lib/objects/driver/gcp/authentication/base.rb +36 -0
- data/lib/objects/driver/gcp/authentication/oauth.rb +24 -29
- 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 +57 -2
- 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 +83 -0
- data/lib/objects/exception/base.rb +10 -3
- data/lib/objects/exception/ec2_driver_missing_authorization_keys.rb +11 -0
- data/lib/objects/exception/empty_namespace_tree.rb +11 -0
- data/lib/objects/exception/gcp_auth_service_account_missing_credentials.rb +11 -0
- data/lib/objects/exception/invalid_metadata_encryption_key.rb +1 -1
- data/lib/objects/exception/missing_gcp_service_account_credentials_filename.rb +11 -0
- 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/loading_bar/handler.rb +1 -1
- data/lib/objects/loading_bar/indicator/base.rb +1 -0
- data/lib/objects/modules/draw.rb +49 -0
- data/lib/objects/modules/tree.rb +157 -0
- data/lib/objects/modules/workspace_commands.rb +2 -32
- data/lib/objects/modules/workspace_menu.rb +113 -48
- data/lib/objects/node/attributes.rb +6 -0
- data/lib/objects/node/base.rb +27 -7
- data/lib/objects/node/cache_handler.rb +1 -1
- data/lib/objects/node/factory.rb +15 -11
- data/lib/objects/node/inventory/base.rb +9 -3
- data/lib/objects/node/inventory/defined.rb +18 -15
- data/lib/objects/node/inventory/merge.rb +9 -1
- data/lib/objects/node/inventory/subselect.rb +6 -4
- data/lib/objects/node/meta_data_factory.rb +1 -1
- data/lib/objects/node/meta_data_loader.rb +2 -2
- data/lib/objects/node/resources/inventory.rb +19 -0
- data/lib/objects/node/resources/merged.rb +23 -14
- data/lib/objects/node/resources/sub_inventory.rb +6 -5
- data/lib/objects/node/server/base.rb +35 -22
- data/lib/objects/node/server/dynamic/ec2.rb +0 -1
- data/lib/objects/node/server/dynamic/gcp.rb +0 -1
- data/lib/objects/node/server/static.rb +22 -9
- data/lib/objects/orchestration/base.rb +7 -1
- data/lib/objects/orchestration/interactive_terraform.rb +10 -16
- data/lib/objects/registry/command/external.rb +6 -2
- data/lib/objects/registry/command/group.rb +5 -1
- data/lib/objects/registry/loader.rb +3 -0
- data/lib/objects/ssh/command.rb +4 -8
- data/lib/objects/ssh/command_exec.rb +3 -1
- data/lib/objects/ssh/connection_wrangler.rb +34 -17
- data/lib/objects/ssh/connector.rb +17 -9
- data/lib/objects/ssh/driver.rb +7 -18
- data/lib/objects/ssh/driver_concerns/connection.rb +3 -11
- data/lib/objects/ssh/driver_concerns/functions.rb +7 -7
- 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 +47 -18
- data/lib/objects/ssh/script_exec.rb +9 -11
- data/lib/objects/startup.rb +7 -1
- data/lib/objects/terraform/output.rb +5 -1
- data/lib/objects/workspace.rb +10 -0
- data/patches/irb.rb +35 -1
- data/patches/string.rb +13 -0
- metadata +71 -25
- data/lib/objects/driver/static.rb +0 -6
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bcome::Driver::Gcp::Authentication
|
4
|
+
class SignetServiceAccountClient < Signet::OAuth2::Client
|
5
|
+
def initialize(scopes, service_account_json_path)
|
6
|
+
@scopes = scopes
|
7
|
+
@service_account_json_path = service_account_json_path
|
8
|
+
raise ::Bcome::Exception::GcpAuthServiceAccountMissingCredentials, @service_account_json_path unless File.exist?(@service_account_json_path)
|
9
|
+
end
|
10
|
+
|
11
|
+
def fetch_access_token(_options = {})
|
12
|
+
token = authorizer.fetch_access_token!
|
13
|
+
token
|
14
|
+
end
|
15
|
+
|
16
|
+
def authorize
|
17
|
+
@token ||= fetch_access_token
|
18
|
+
end
|
19
|
+
|
20
|
+
def authorizer
|
21
|
+
authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
|
22
|
+
json_key_io: File.open(@service_account_json_path),
|
23
|
+
scope: @scopes
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Bcome::Driver::Gcp::Authentication::Utilities
|
2
|
+
|
3
|
+
def oauth_redirect_html
|
4
|
+
## [GR] Style rules: Explicitly no assets to be pulled from bcome remote (no tracking). Inline styles only.
|
5
|
+
## Made an exception for the google font, as the user is already oauthing against google in any case.
|
6
|
+
<<-HTML
|
7
|
+
<html>
|
8
|
+
<head>
|
9
|
+
<script>
|
10
|
+
function closeWindow() {
|
11
|
+
window.open('', '_self', '');
|
12
|
+
window.close();
|
13
|
+
}
|
14
|
+
setTimeout(closeWindow, 10);
|
15
|
+
</script>
|
16
|
+
</head>
|
17
|
+
<style>
|
18
|
+
@import url("https://fonts.googleapis.com/css2?family=Catamaran:wght@200;500&display=swap");
|
19
|
+
|
20
|
+
body {
|
21
|
+
font-family: 'Catamaran', sans-serif;
|
22
|
+
font-weight: 200;
|
23
|
+
color: #3E4E60;
|
24
|
+
}
|
25
|
+
</style>
|
26
|
+
<body>#{oauth_redirect_body}</body>
|
27
|
+
</html>
|
28
|
+
HTML
|
29
|
+
end
|
30
|
+
|
31
|
+
def oauth_redirect_body
|
32
|
+
<<-HTML
|
33
|
+
<p>
|
34
|
+
OAuth redirection for namespace <strong>#{@node.keyed_namespace}</strong> complete.
|
35
|
+
</p>
|
36
|
+
<p>
|
37
|
+
You may close this window and return to the Bcome Console.
|
38
|
+
</p>
|
39
|
+
HTML
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/objects/encryptor.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'diffy'
|
4
|
+
|
3
5
|
module Bcome
|
4
6
|
class Encryptor
|
5
7
|
UNENC_SIGNIFIER = ''
|
6
8
|
ENC_SIGNIFIER = 'enc'
|
9
|
+
AFFIRMATIVE = 'yes'
|
7
10
|
|
8
11
|
include Singleton
|
9
12
|
|
@@ -27,7 +30,16 @@ module Bcome
|
|
27
30
|
puts "\n"
|
28
31
|
print 'Please enter an encryption key (and if your data is already encrypted, you must provide the same key): '.informational
|
29
32
|
@key = STDIN.noecho(&:gets).chomp
|
33
|
+
# puts "\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
def prompt_to_overwrite
|
37
|
+
valid_answers = [AFFIRMATIVE, 'no']
|
30
38
|
puts "\n"
|
39
|
+
print "Do you want to continue with unpacking this file? Your local changes would be overwritten [#{valid_answers.join(',')}]\s"
|
40
|
+
answer = STDIN.gets.chomp
|
41
|
+
prompt_to_overwrite unless valid_answers.include?(answer)
|
42
|
+
answer
|
31
43
|
end
|
32
44
|
|
33
45
|
def has_encrypted_files?
|
@@ -52,6 +64,64 @@ module Bcome
|
|
52
64
|
nil
|
53
65
|
end
|
54
66
|
|
67
|
+
def decrypt_file_data(filename)
|
68
|
+
raw_contents = File.read(filename)
|
69
|
+
raw_contents.send(:decrypt, @key)
|
70
|
+
end
|
71
|
+
|
72
|
+
def enc_file_diff(filename)
|
73
|
+
# Get decrypted file data
|
74
|
+
decrypted_data_for_filename = decrypt_file_data(filename)
|
75
|
+
|
76
|
+
# Get unpacked file data
|
77
|
+
opposing_filename = opposing_file_for_filename(filename)
|
78
|
+
return nil unless File.exist?(opposing_filename)
|
79
|
+
|
80
|
+
unpacked_file_data = File.read(opposing_filename)
|
81
|
+
|
82
|
+
# there are no differences
|
83
|
+
return nil if decrypted_data_for_filename.eql?(unpacked_file_data)
|
84
|
+
|
85
|
+
get_diffs(unpacked_file_data, decrypted_data_for_filename)
|
86
|
+
end
|
87
|
+
|
88
|
+
def opposing_file_for_filename(filename)
|
89
|
+
filename =~ %r{#{path_to_metadata}/(.+)\.enc}
|
90
|
+
"#{path_to_metadata}/#{Regexp.last_match(1)}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_diffs(file_one, file_two)
|
94
|
+
diffy = ::Diffy::SplitDiff.new(file_one, file_two)
|
95
|
+
left_diffs = diffy.left.split("\n").each_with_index.collect { |l, index| "#{index + 1}:\s#{l}" }
|
96
|
+
right_diffs = diffy.right.split("\n").each_with_index.collect { |l, index| "#{index + 1}:\s#{l}" }
|
97
|
+
|
98
|
+
diffed_lines = (left_diffs + right_diffs).select { |line| line =~ /^[0-9]+:\s[+-](.+)$/ }
|
99
|
+
return nil if diffed_lines.empty?
|
100
|
+
|
101
|
+
diffed_lines.collect do |line|
|
102
|
+
line =~ /^[0-9]+:\s\+(.+)$/ ? line.bc_green : line.bc_red
|
103
|
+
end.join("\n")
|
104
|
+
end
|
105
|
+
|
106
|
+
def diff
|
107
|
+
prompt_for_key
|
108
|
+
puts "\n"
|
109
|
+
all_encrypted_filenames.each do |filename|
|
110
|
+
opposing_file = opposing_file_for_filename(filename)
|
111
|
+
if File.exist?(opposing_file)
|
112
|
+
if diffs = enc_file_diff(filename)
|
113
|
+
puts "\n[+/-]\s".warning + filename + "\sis different to your local unpacked version\n\n"
|
114
|
+
puts diffs + "\n\n"
|
115
|
+
else
|
116
|
+
puts filename.to_s.informational + "\s- no differences".bc_green
|
117
|
+
end
|
118
|
+
else
|
119
|
+
puts filename.to_s.informational + "\s- new file".warning
|
120
|
+
end
|
121
|
+
end
|
122
|
+
puts "\n"
|
123
|
+
end
|
124
|
+
|
55
125
|
def toggle_packed_files(filenames, packer_method)
|
56
126
|
raise 'Missing encryption key. Please set an encryption key' unless @key
|
57
127
|
|
@@ -63,6 +133,18 @@ module Bcome
|
|
63
133
|
filename =~ %r{#{path_to_metadata}/(.+)\.enc}
|
64
134
|
opposing_filename = Regexp.last_match(1)
|
65
135
|
action = 'Unpacking'
|
136
|
+
|
137
|
+
# Skip unpacking a file if there are local modifications that the user does not want to lose.
|
138
|
+
if diffs = enc_file_diff(filename)
|
139
|
+
puts "\n[+/-]\s".warning + filename + "\sis different to your local unpacked version\n\n"
|
140
|
+
puts diffs
|
141
|
+
|
142
|
+
if prompt_to_overwrite != AFFIRMATIVE
|
143
|
+
puts "\n\nskipping\s".warning + filename + "\n"
|
144
|
+
next
|
145
|
+
end
|
146
|
+
puts "\n"
|
147
|
+
end
|
66
148
|
else
|
67
149
|
filename =~ %r{#{path_to_metadata}/(.*)}
|
68
150
|
opposing_filename = "#{Regexp.last_match(1)}.enc"
|
@@ -71,6 +153,7 @@ module Bcome
|
|
71
153
|
|
72
154
|
# Write encrypted/decryption action
|
73
155
|
enc_decrypt_result = raw_contents.send(packer_method, @key)
|
156
|
+
print "\n\n"
|
74
157
|
puts "#{action}\s".informational + filename + "\sto\s".informational + "#{path_to_metadata}/" + opposing_filename
|
75
158
|
write_file(opposing_filename, enc_decrypt_result)
|
76
159
|
end
|
@@ -8,12 +8,19 @@ module Bcome
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def message
|
11
|
-
"#{message_prefix}#{
|
11
|
+
"#{message_prefix}#{if @message_suffix
|
12
|
+
+ (!message_prefix.empty? ? ':' : '').to_s + " #{@message_suffix}"
|
13
|
+
else
|
14
|
+
''
|
15
|
+
end}"
|
12
16
|
end
|
13
17
|
|
14
|
-
def pretty_display
|
15
|
-
puts "\n
|
18
|
+
def pretty_display(show_backtrace = false)
|
19
|
+
puts "\n" + message.error
|
20
|
+
print backtrace.join("\n") if show_backtrace
|
21
|
+
print "\n"
|
16
22
|
end
|
23
|
+
|
17
24
|
end
|
18
25
|
end
|
19
26
|
end
|
@@ -4,7 +4,7 @@ module Bcome
|
|
4
4
|
module Exception
|
5
5
|
class InvalidMetaDataEncryptionKey < ::Bcome::Exception::Base
|
6
6
|
def message_prefix
|
7
|
-
'Your metadata encryption key is invalid
|
7
|
+
'Your metadata encryption key is invalid.'
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bcome
|
4
|
+
module Exception
|
5
|
+
class MissingGcpServiceAccountCredentialsFilename < ::Bcome::Exception::Base
|
6
|
+
def message_prefix
|
7
|
+
"Cannot authenticate with GCP - missing service account credentials file name in networks.yml. Define this with a 'service_account_credentials' key"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Bcome::Initialization
|
4
|
+
class Factory
|
5
|
+
include ::Bcome::Initialization::Utils
|
6
|
+
include ::Bcome::Initialization::Structure
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def do
|
10
|
+
new.do
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@created = []
|
16
|
+
@exists = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def do
|
20
|
+
puts "\nInitialising Bcome".title.bold
|
21
|
+
initialization_paths.each do |conf|
|
22
|
+
create_file_utils(conf[:method], conf[:paths])
|
23
|
+
end
|
24
|
+
summarize(@created, "\nThe following paths were created")
|
25
|
+
summarize(@exists, "\nThe following paths exist already, and were untouched")
|
26
|
+
puts "\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
def summarize(paths, caption)
|
30
|
+
return unless paths.any?
|
31
|
+
|
32
|
+
puts "#{caption}:".informational
|
33
|
+
paths.each { |path| puts path.resource_key }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Bcome::Initialization::Structure
|
2
|
+
def initialization_paths
|
3
|
+
[
|
4
|
+
{ # Configuration directories
|
5
|
+
paths: ['bcome', 'bcome/metadata', 'bcome/orchestration'],
|
6
|
+
method: :create_as_directory
|
7
|
+
},
|
8
|
+
{ # Configuration files
|
9
|
+
paths: ['bcome/networks.yml', 'bcome/registry.yml'],
|
10
|
+
method: :initialize_empty_yaml_config
|
11
|
+
},
|
12
|
+
{ # Cloud provider authorisation directories
|
13
|
+
paths: ['.gauth', '.aws'],
|
14
|
+
method: :create_as_directory
|
15
|
+
}
|
16
|
+
]
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Bcome::Initialization::Utils
|
2
|
+
def initialize_empty_yaml_config(path)
|
3
|
+
File.write(path, {}.to_yaml)
|
4
|
+
end
|
5
|
+
|
6
|
+
def create_as_directory(path)
|
7
|
+
::FileUtils.mkdir_p(path)
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_file_utils(method, paths)
|
11
|
+
paths.each do |path|
|
12
|
+
if path.is_file_or_directory?
|
13
|
+
@exists << path
|
14
|
+
else
|
15
|
+
send(method, path)
|
16
|
+
@created << path
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bcome
|
4
|
+
module Draw
|
5
|
+
# see: https://en.wikipedia.org/wiki/Box-drawing_character
|
6
|
+
|
7
|
+
## Tree shapes
|
8
|
+
BOTTOM_ANCHOR = '└───╸'
|
9
|
+
MID_SHIPS = '├───╸'
|
10
|
+
BRANCH = '│'
|
11
|
+
LEFT_PADDING = "\s" * 6
|
12
|
+
INGRESS = '│'
|
13
|
+
BLIP = '▐▆'
|
14
|
+
|
15
|
+
# # Box shapes
|
16
|
+
BOX_SIDE = '│'
|
17
|
+
BOX_TOP_LEFT = '┌'
|
18
|
+
BOX_TOP_RIGHT = '┐'
|
19
|
+
BOX_BOTTOM_LEFT = '└'
|
20
|
+
BOX_BOTTOM_RIGHT = '┘'
|
21
|
+
BOX_HORIZONTAL_LINE = '─'
|
22
|
+
|
23
|
+
# Takes an array of strings, each representing a line
|
24
|
+
# Draws a box around the lines, and returns a new array
|
25
|
+
# padding may be provided
|
26
|
+
def box_it(array_of_lines, padding = 1, _box_colour = :bc_cyan)
|
27
|
+
max_length = max_box_line_length(array_of_lines)
|
28
|
+
pad_string = "\s" * padding
|
29
|
+
|
30
|
+
box_lines = [
|
31
|
+
# Set the top box line
|
32
|
+
"#{BOX_TOP_LEFT}#{BOX_HORIZONTAL_LINE * (max_length + (padding + 1))}#{BOX_TOP_RIGHT}"
|
33
|
+
]
|
34
|
+
|
35
|
+
array_of_lines.each do |line|
|
36
|
+
line_length = line.sanitize.length
|
37
|
+
box_lines << "#{BOX_SIDE}#{pad_string}" + line.to_s + "#{"\s" * (max_length - line_length)}#{pad_string}#{BOX_SIDE}"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Set the bottom box line
|
41
|
+
box_lines << "#{BOX_BOTTOM_LEFT}#{BOX_HORIZONTAL_LINE * (max_length + (padding + 1))}#{BOX_BOTTOM_RIGHT}"
|
42
|
+
box_lines
|
43
|
+
end
|
44
|
+
|
45
|
+
def max_box_line_length(array_of_lines)
|
46
|
+
array_of_lines.max_by { |string| string.sanitize.length }.sanitize.length
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bcome
|
4
|
+
module Tree
|
5
|
+
include Bcome::Draw
|
6
|
+
|
7
|
+
def tree
|
8
|
+
title_prefix = 'Namespace tree'
|
9
|
+
build_tree(:network_namespace_tree_data, title_prefix)
|
10
|
+
end
|
11
|
+
|
12
|
+
def routes
|
13
|
+
if machines.empty?
|
14
|
+
puts "\nNo routes are found below this namespace (empty server list)\n".warning
|
15
|
+
else
|
16
|
+
title_prefix = 'Ssh connection routes'
|
17
|
+
build_tree(:routing_tree_data, title_prefix)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def routing_tree_data
|
22
|
+
@tree = {}
|
23
|
+
|
24
|
+
# For each namespace, we have many proxy chains
|
25
|
+
proxy_chain_link.link.each do |proxy_chain, machines|
|
26
|
+
is_direct = proxy_chain.hops.any? ? false : true
|
27
|
+
|
28
|
+
if inventory?
|
29
|
+
load_nodes unless nodes_loaded?
|
30
|
+
end
|
31
|
+
|
32
|
+
## Machine data
|
33
|
+
machine_data = {}
|
34
|
+
machines.each do |machine|
|
35
|
+
key = machine.routing_tree_line(is_direct)
|
36
|
+
machine_data[key] = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
## Construct Hop data
|
40
|
+
hops = proxy_chain.hops
|
41
|
+
hop_lines = hops.compact.enum_for(:each_with_index).collect { |hop, index| hop.pretty_proxy_details(index + 1) }
|
42
|
+
|
43
|
+
@tree.merge!(to_nested_hash(hop_lines, machine_data))
|
44
|
+
end
|
45
|
+
|
46
|
+
@tree
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_nested_hash(array, data)
|
50
|
+
nested = array.reverse.inject(data) { |a, n| { n => a } }
|
51
|
+
nested.is_a?(String) ? { "#{nested}": nil } : nested
|
52
|
+
end
|
53
|
+
|
54
|
+
def network_namespace_tree_data
|
55
|
+
@tree = {}
|
56
|
+
|
57
|
+
resources.sort_by(&:identifier).each do |resource|
|
58
|
+
next if resource.hide?
|
59
|
+
|
60
|
+
if resource.inventory?
|
61
|
+
resource.load_nodes unless resource.nodes_loaded?
|
62
|
+
end
|
63
|
+
|
64
|
+
unless resource.is_a?(Bcome::Node::Inventory::Merge)
|
65
|
+
next if resource.parent && !resource.parent.resources.is_active_resource?(resource)
|
66
|
+
end
|
67
|
+
@tree[resource.namespace_tree_line] = resource.resources.any? ? resource.network_namespace_tree_data : nil
|
68
|
+
end
|
69
|
+
|
70
|
+
@tree
|
71
|
+
end
|
72
|
+
|
73
|
+
def namespace_tree_line
|
74
|
+
return "#{type.bc_green} #{identifier} (empty set)" if !server? && !resources.has_active_nodes?
|
75
|
+
|
76
|
+
"#{type.bc_green} #{identifier}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def routing_tree_line(is_direct = true)
|
80
|
+
address = if is_direct && public_ip_address
|
81
|
+
public_ip_address
|
82
|
+
else
|
83
|
+
internal_ip_address
|
84
|
+
end
|
85
|
+
|
86
|
+
[
|
87
|
+
type.to_s.bc_cyan,
|
88
|
+
"namespace:\s".bc_green + keyed_namespace,
|
89
|
+
"ip address\s".bc_green + address.to_s,
|
90
|
+
"user\s".bc_green + ssh_driver.user
|
91
|
+
]
|
92
|
+
end
|
93
|
+
|
94
|
+
def build_tree(data_build_method, title_prefix)
|
95
|
+
data = send(data_build_method)
|
96
|
+
|
97
|
+
@lines = []
|
98
|
+
title = "#{title_prefix.informational}\s#{namespace}"
|
99
|
+
@lines << "\n"
|
100
|
+
@lines << "#{BLIP}\s\s\s#{title}"
|
101
|
+
@lines << INGRESS.to_s
|
102
|
+
|
103
|
+
if data.nil?
|
104
|
+
parent.build_tree(data_build_method)
|
105
|
+
return
|
106
|
+
end
|
107
|
+
|
108
|
+
recurse_tree_lines(data)
|
109
|
+
|
110
|
+
@lines.each do |line|
|
111
|
+
print "#{LEFT_PADDING}#{line}\n"
|
112
|
+
end
|
113
|
+
|
114
|
+
print "\n\n"
|
115
|
+
p
|
116
|
+
end
|
117
|
+
|
118
|
+
def recurse_tree_lines(data, padding = '')
|
119
|
+
# @lines << padding + BRANCH
|
120
|
+
|
121
|
+
data.each_with_index do |config, index|
|
122
|
+
key = config[0]
|
123
|
+
values = config[1]
|
124
|
+
|
125
|
+
anchor, branch = deduce_tree_structure(index, data.size)
|
126
|
+
|
127
|
+
labels = key.is_a?(Array) ? key : [key]
|
128
|
+
|
129
|
+
labels.each_with_index do |label, index|
|
130
|
+
key_string = if index == 0 # First line
|
131
|
+
"#{anchor}\s#{label}"
|
132
|
+
else # Any subsequent line
|
133
|
+
"#{branch}#{"\s" * 4}\s#{label}"
|
134
|
+
end
|
135
|
+
|
136
|
+
entry_string = "#{padding}#{key_string}"
|
137
|
+
@lines << entry_string
|
138
|
+
end # End labels group
|
139
|
+
|
140
|
+
@lines << "#{padding}#{branch}" if labels.size > 1
|
141
|
+
|
142
|
+
next unless values&.is_a?(Hash)
|
143
|
+
|
144
|
+
tab_padding = padding + branch + ("\s" * (anchor.length + 4))
|
145
|
+
recurse_tree_lines(values, tab_padding)
|
146
|
+
@lines << padding + branch
|
147
|
+
end
|
148
|
+
nil
|
149
|
+
end
|
150
|
+
|
151
|
+
def deduce_tree_structure(index, number_lines)
|
152
|
+
return BOTTOM_ANCHOR, "\s" if (index + 1) == number_lines
|
153
|
+
|
154
|
+
[MID_SHIPS, BRANCH]
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|