bcome 1.3.6 → 1.4.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 (165) hide show
  1. checksums.yaml +4 -4
  2. data/bin/bcome +13 -8
  3. data/lib/bcome.rb +7 -11
  4. data/lib/objects/bcome/version.rb +19 -1
  5. data/lib/objects/bootup.rb +13 -5
  6. data/lib/objects/command/local.rb +2 -0
  7. data/lib/objects/config_factory.rb +3 -0
  8. data/lib/objects/driver/base.rb +36 -4
  9. data/lib/objects/driver/bucket.rb +6 -4
  10. data/lib/objects/driver/ec2.rb +35 -4
  11. data/lib/objects/driver/gcp.rb +124 -0
  12. data/lib/objects/driver/gcp/authentication/api_key.rb +6 -0
  13. data/lib/objects/driver/gcp/authentication/oauth.rb +101 -0
  14. data/lib/objects/driver/gcp/authentication/service_account.rb +7 -0
  15. data/lib/objects/driver/static.rb +2 -0
  16. data/lib/objects/encryptor.rb +26 -24
  17. data/lib/objects/exception/argument_error_invoking_method_from_command_line.rb +8 -4
  18. data/lib/objects/exception/base.rb +14 -10
  19. data/lib/objects/exception/can_only_subselect_on_inventory.rb +8 -4
  20. data/lib/objects/exception/cannot_authenticate_to_gcp.rb +11 -0
  21. data/lib/objects/exception/cannot_find_internal_registry_klass.rb +8 -4
  22. data/lib/objects/exception/cannot_find_inventory.rb +11 -0
  23. data/lib/objects/exception/cannot_find_subselection_parent.rb +8 -4
  24. data/lib/objects/exception/cant_find_key_in_cloud_tags.rb +8 -4
  25. data/lib/objects/exception/cant_find_key_in_metadata.rb +8 -4
  26. data/lib/objects/exception/cant_find_proxy_host_by_identifier.rb +8 -4
  27. data/lib/objects/exception/cant_find_proxy_host_by_namespace.rb +8 -4
  28. data/lib/objects/exception/could_not_initiate_ssh_connection.rb +8 -4
  29. data/lib/objects/exception/could_not_initiate_ssh_connection_through_backend_proxy.rb +8 -4
  30. data/lib/objects/exception/could_not_retrieve_terraform_output.rb +11 -0
  31. data/lib/objects/exception/deprecation_warning.rb +9 -7
  32. data/lib/objects/exception/duplicate_command_line_argument_key.rb +8 -4
  33. data/lib/objects/exception/ec2_driver_missing_provisioning_region.rb +8 -4
  34. data/lib/objects/exception/failed_to_run_local_command.rb +8 -4
  35. data/lib/objects/exception/generic.rb +11 -0
  36. data/lib/objects/exception/interactive_session_halt.rb +6 -2
  37. data/lib/objects/exception/invalid_bcome_breadcrumb.rb +8 -4
  38. data/lib/objects/exception/invalid_breadcrumb.rb +8 -4
  39. data/lib/objects/exception/invalid_context_command.rb +8 -4
  40. data/lib/objects/exception/invalid_gcp_authentication_scheme.rb +11 -0
  41. data/lib/objects/exception/invalid_identifier.rb +8 -4
  42. data/lib/objects/exception/invalid_machines_cache_config.rb +8 -4
  43. data/lib/objects/exception/invalid_matcher_query.rb +8 -4
  44. data/lib/objects/exception/invalid_meta_data_config.rb +8 -4
  45. data/lib/objects/exception/invalid_metadata_encryption_key.rb +8 -4
  46. data/lib/objects/exception/invalid_network_config.rb +8 -4
  47. data/lib/objects/exception/invalid_network_driver_type.rb +8 -4
  48. data/lib/objects/exception/invalid_port_forward_request.rb +11 -0
  49. data/lib/objects/exception/invalid_proxy_config.rb +8 -4
  50. data/lib/objects/exception/invalid_regexp_matcher_in_registry.rb +8 -4
  51. data/lib/objects/exception/invalid_registry_arguments_type.rb +8 -4
  52. data/lib/objects/exception/invalid_registry_command_name_length.rb +8 -4
  53. data/lib/objects/exception/invalid_registry_data_config.rb +8 -4
  54. data/lib/objects/exception/invalid_restriction_key_in_registry.rb +8 -4
  55. data/lib/objects/exception/invalid_ssh_config.rb +8 -4
  56. data/lib/objects/exception/inventories_cannot_have_subviews.rb +8 -4
  57. data/lib/objects/exception/malformed_command_line_arguments.rb +8 -4
  58. data/lib/objects/exception/method_invocation_requires_parameter.rb +8 -4
  59. data/lib/objects/exception/method_name_conflict_in_registry.rb +8 -4
  60. data/lib/objects/exception/missing_argument_for_registry_command.rb +8 -4
  61. data/lib/objects/exception/missing_description_on_view.rb +8 -4
  62. data/lib/objects/exception/missing_execute_on_registry_object.rb +8 -4
  63. data/lib/objects/exception/missing_gcp_authentication_scheme.rb +11 -0
  64. data/lib/objects/exception/missing_gcp_service_scopes.rb +11 -0
  65. data/lib/objects/exception/missing_identifier_on_view.rb +8 -4
  66. data/lib/objects/exception/missing_inventory_contributors.rb +11 -0
  67. data/lib/objects/exception/missing_ip_address_on_server.rb +8 -4
  68. data/lib/objects/exception/missing_network_config.rb +8 -4
  69. data/lib/objects/exception/missing_or_invalid_client_secrets.rb +11 -0
  70. data/lib/objects/exception/missing_params_for_rsync.rb +8 -4
  71. data/lib/objects/exception/missing_params_for_scp.rb +8 -4
  72. data/lib/objects/exception/missing_subselection_key.rb +8 -4
  73. data/lib/objects/exception/missing_type_on_view.rb +8 -4
  74. data/lib/objects/exception/no_node_found_for_breadcrumb.rb +8 -4
  75. data/lib/objects/exception/no_node_named_by_identifier.rb +8 -4
  76. data/lib/objects/exception/node_identifiers_must_be_unique.rb +8 -4
  77. data/lib/objects/exception/orchestration_script_does_not_exist.rb +8 -4
  78. data/lib/objects/exception/proxy_host_node_does_not_have_public_ip_address.rb +8 -4
  79. data/lib/objects/exception/unknown_dynamic_server_type.rb +11 -0
  80. data/lib/objects/exception/unknown_method_for_namespace.rb +8 -4
  81. data/lib/objects/interactive/session.rb +4 -1
  82. data/lib/objects/interactive/session_item/base.rb +2 -0
  83. data/lib/objects/interactive/session_item/capture_input.rb +2 -0
  84. data/lib/objects/interactive/session_item/transparent_ssh.rb +29 -23
  85. data/lib/objects/loading_bar/handler.rb +80 -0
  86. data/lib/objects/loading_bar/indicator/base.rb +64 -0
  87. data/lib/objects/loading_bar/indicator/basic.rb +34 -0
  88. data/lib/objects/loading_bar/indicator/progress.rb +26 -0
  89. data/lib/objects/loading_bar/pid_bucket.rb +27 -0
  90. data/lib/objects/modules/context.rb +13 -9
  91. data/lib/objects/modules/registry_management.rb +16 -10
  92. data/lib/objects/modules/ui_output.rb +10 -6
  93. data/lib/objects/modules/workspace_commands.rb +159 -155
  94. data/lib/objects/modules/workspace_menu.rb +129 -130
  95. data/lib/objects/node/attributes.rb +13 -21
  96. data/lib/objects/node/base.rb +113 -71
  97. data/lib/objects/node/cache_handler.rb +2 -0
  98. data/lib/objects/node/collection.rb +10 -9
  99. data/lib/objects/node/factory.rb +35 -28
  100. data/lib/objects/node/inventory/base.rb +100 -100
  101. data/lib/objects/node/inventory/defined.rb +110 -89
  102. data/lib/objects/node/inventory/merge.rb +43 -0
  103. data/lib/objects/node/inventory/subselect.rb +64 -46
  104. data/lib/objects/node/kube/base.rb +51 -0
  105. data/lib/objects/node/kube/container.rb +9 -0
  106. data/lib/objects/node/kube/estate.rb +19 -0
  107. data/lib/objects/node/kube/namespace.rb +24 -0
  108. data/lib/objects/node/kube/pod.rb +24 -0
  109. data/lib/objects/node/kube_wrap.rb +26 -0
  110. data/lib/objects/node/meta/base.rb +8 -1
  111. data/lib/objects/node/meta/cloud.rb +2 -0
  112. data/lib/objects/node/meta/local.rb +2 -0
  113. data/lib/objects/node/meta_data_factory.rb +3 -1
  114. data/lib/objects/node/meta_data_loader.rb +27 -28
  115. data/lib/objects/node/resources/base.rb +5 -1
  116. data/lib/objects/node/resources/inventory.rb +7 -5
  117. data/lib/objects/node/resources/merged.rb +38 -0
  118. data/lib/objects/node/resources/sub_inventory.rb +7 -4
  119. data/lib/objects/node/server/base.rb +88 -66
  120. data/lib/objects/node/server/dynamic/base.rb +23 -0
  121. data/lib/objects/node/server/{dynamic.rb → dynamic/ec2.rb} +14 -13
  122. data/lib/objects/node/server/dynamic/gcp.rb +47 -0
  123. data/lib/objects/node/server/static.rb +13 -2
  124. data/lib/objects/orchestration/base.rb +10 -0
  125. data/lib/objects/orchestration/interactive_terraform.rb +62 -27
  126. data/lib/objects/orchestrator.rb +22 -0
  127. data/lib/objects/parser/bread_crumb.rb +3 -1
  128. data/lib/objects/registry/arguments/base.rb +3 -1
  129. data/lib/objects/registry/arguments/command_line.rb +6 -1
  130. data/lib/objects/registry/arguments/console.rb +4 -1
  131. data/lib/objects/registry/command/base.rb +3 -0
  132. data/lib/objects/registry/command/external.rb +4 -2
  133. data/lib/objects/registry/command/group.rb +6 -3
  134. data/lib/objects/registry/command/internal.rb +3 -1
  135. data/lib/objects/registry/command/shortcut.rb +17 -9
  136. data/lib/objects/registry/command_list.rb +2 -0
  137. data/lib/objects/registry/loader.rb +10 -10
  138. data/lib/objects/ssh/bootstrap.rb +3 -1
  139. data/lib/objects/ssh/command.rb +10 -5
  140. data/lib/objects/ssh/command_exec.rb +13 -9
  141. data/lib/objects/ssh/connection_wrangler.rb +105 -0
  142. data/lib/objects/ssh/connector.rb +100 -0
  143. data/lib/objects/ssh/driver.rb +27 -230
  144. data/lib/objects/ssh/driver_concerns/command_strings.rb +17 -0
  145. data/lib/objects/ssh/driver_concerns/connection.rb +78 -0
  146. data/lib/objects/ssh/driver_concerns/functions.rb +89 -0
  147. data/lib/objects/ssh/driver_concerns/user.rb +32 -0
  148. data/lib/objects/ssh/{proxy_data.rb → proxy_hop.rb} +52 -7
  149. data/lib/objects/ssh/script_exec.rb +4 -1
  150. data/lib/objects/ssh/tunnel/local_port_forward.rb +5 -6
  151. data/lib/objects/ssh/tunnel_keeper.rb +21 -0
  152. data/lib/objects/ssh/window.rb +31 -0
  153. data/lib/objects/startup.rb +52 -0
  154. data/lib/objects/system/local.rb +3 -0
  155. data/lib/objects/terraform/output.rb +41 -0
  156. data/lib/objects/workspace.rb +3 -14
  157. data/patches/irb.rb +27 -3
  158. data/patches/string-encrypt.rb +20 -23
  159. data/patches/string.rb +5 -1
  160. data/patches/string_stylesheet.rb +2 -0
  161. metadata +95 -18
  162. data/lib/objects/progress_bar.rb +0 -30
  163. data/lib/objects/ssh/connection_handler.rb +0 -101
  164. data/lib/objects/terraform/parser.rb +0 -23
  165. data/lib/objects/terraform/state.rb +0 -40
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d87216a1088316fa96d518641a96b0e91bf8e329b3dab8909844370e901bc7a
4
- data.tar.gz: 6278ffabc92b6adc0a45a08ba2c440f80c89478fa99874a4c4430d5f434646a0
3
+ metadata.gz: 7ace465761e84db321e1de7eea860a3ade94ecda5d5e091e8784740b1cb07ea4
4
+ data.tar.gz: 996329541843570edfef238c8a1dd46830402fd04586530b66810478b303b59c
5
5
  SHA512:
6
- metadata.gz: fc285a553d0f46f873a0b82652cef41246996c17b680532ca64696923fb8af934eefb99e2706739f09be6eefaa3ed6e034a280619570dffb9514ba7ac7384c22
7
- data.tar.gz: 5f7a554733686efa6b219fdce445b0a68f5e23641058d531b807d5b646ebe65fdee8137cb94d88f2effa3af93ef168691cb862b939b7ce08a7e28ed8d0fa8abb
6
+ metadata.gz: db096f8fdde0c83e57519c5d09089d3d8e2bf26a4e4f07c675cf18aafb42a279ca7788114378dd7737e84f4279bbc09e141a1612669de6bea792370bd419fffd
7
+ data.tar.gz: 4ed639e3378da6b8cefef9727c640d8462ff3fe01f35f63d30b28ef4cd3c50c8975cf7226f4b74f789068223238e860dd7f8300cc4861b18f25b6dec4149b9a7
data/bin/bcome CHANGED
@@ -1,15 +1,20 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'bcome'
4
5
 
5
- begin
6
- spawn_into_console = true
7
- arguments = ARGV - [ARGV[0]]
8
- ::Bcome::Bootup.set_and_do({ breadcrumbs: ARGV[0], arguments: arguments }, spawn_into_console)
6
+ breadcrumbs = ARGV[0]
7
+ arguments = ARGV - [ARGV[0]]
8
+ handler = ::Bcome::Startup.new(breadcrumbs, arguments)
9
9
 
10
- # close any trailing connections
11
- Bcome::Bootup.instance.estate.close_ssh_connections
10
+ trap('SIGINT') do
11
+ handler.stop_loading_bars
12
+ end
12
13
 
13
- rescue ::Bcome::Exception::Base
14
- puts "bcome terminated unexpectedly".warning
14
+ trap('INT') do
15
+ handler.stop_loading_bars
15
16
  end
17
+
18
+ Thread.report_on_exception = false
19
+
20
+ handler.do
@@ -1,17 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'irb'
2
- require 'irb/completion'
3
- require 'rainbow'
4
- require 'net/scp'
5
- require 'net/ssh/proxy/command'
6
- require 'fog/aws'
7
- require 'require_all'
8
- require 'pmap'
9
- require 'singleton'
10
4
  require 'active_support'
11
5
  require 'active_support/core_ext'
12
- require 'pp'
13
- require 'awesome_print'
14
- require 'io/console'
6
+ require 'pmap'
7
+ require 'singleton'
8
+ require 'require_all'
9
+ require 'tty-cursor'
10
+ require 'pry'
15
11
 
16
12
  require_all "#{File.dirname(__FILE__)}/../patches"
17
13
  require_all "#{File.dirname(__FILE__)}/../lib/objects"
@@ -1,3 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bcome
2
- VERSION = '1.3.6'.freeze
4
+ module Version
5
+ def self.name
6
+ 'bcome'
7
+ end
8
+
9
+ def self.release
10
+ '1.4.0'
11
+ end
12
+
13
+ def self.release_name
14
+ 'multicloud'
15
+ end
16
+
17
+ def self.display
18
+ "#{name} #{release} #{release_name}"
19
+ end
20
+ end
3
21
  end
@@ -1,12 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bcome
2
4
  class Bootup
3
5
  def self.set_and_do(params, spawn_into_console = true)
4
6
  instance.set(params, spawn_into_console)
5
7
  instance.do
6
- rescue Bcome::Exception::Base => e
7
- puts e.pretty_display
8
- rescue Excon::Error::Socket => e
9
- puts "\nNo network access - please check your connection and try again\n".red
10
8
  end
11
9
 
12
10
  def self.traverse(breadcrumbs = nil, _spawn_into_console = false)
@@ -31,6 +29,7 @@ module Bcome
31
29
 
32
30
  def init_context(context)
33
31
  if @spawn_into_console
32
+ puts "\n\n"
34
33
  ::Bcome::Workspace.instance.set(context: context)
35
34
  else
36
35
  context
@@ -55,7 +54,6 @@ module Bcome
55
54
  end
56
55
  starting_context = next_context
57
56
  end
58
-
59
57
  # Set our workspace to our last context - we're not invoking a method call and so we're entering a console session
60
58
  init_context(starting_context)
61
59
  end
@@ -64,6 +62,16 @@ module Bcome
64
62
  @estate ||= ::Bcome::Node::Factory.instance.init_tree
65
63
  end
66
64
 
65
+ def estate_loaded?
66
+ !@estate.nil?
67
+ end
68
+
69
+ def close_ssh_connections
70
+ return unless estate_loaded?
71
+
72
+ estate.close_ssh_connections
73
+ end
74
+
67
75
  def parser
68
76
  ::Bcome::Parser::BreadCrumb.new(@breadcrumbs)
69
77
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'open3'
2
4
 
3
5
  module Bcome::Command
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Bcome::ConfigFactory
2
4
  attr_reader :tree
3
5
 
@@ -31,6 +33,7 @@ class Bcome::ConfigFactory
31
33
 
32
34
  def hash_for_identifier_from_view(identifier, views)
33
35
  raise Bcome::Exception::InventoriesCannotHaveSubViews, 'Inventories cannot hold other inventories - invalid network config' unless views.key?(:views)
36
+
34
37
  views[:views].select { |v| v[:identifier].to_s == identifier.to_s }.first
35
38
  end
36
39
  end
@@ -1,26 +1,58 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bcome::Driver
2
4
  class Base
3
5
  class << self
4
- def create_from_config(config)
6
+ def create_from_config(config, node)
5
7
  raise Bcome::Exception::InvalidNetworkDriverType, 'Your network configurtion is invalid' unless config.is_a?(Hash)
6
8
  raise Bcome::Exception::InvalidNetworkDriverType, "Missing config parameter 'type'" unless config[:type]
9
+
7
10
  config_klass_key = config[:type].to_sym
8
11
  driver_klass = klass_for_type[config_klass_key]
9
12
  raise Bcome::Exception::InvalidNetworkDriverType, config unless driver_klass
10
- driver = driver_klass.new(config)
13
+
14
+ driver = driver_klass.new(config, node)
11
15
  driver
12
16
  end
13
17
 
14
18
  def klass_for_type
15
19
  {
16
20
  static: ::Bcome::Driver::Static,
17
- ec2: ::Bcome::Driver::Ec2
21
+ ec2: ::Bcome::Driver::Ec2,
22
+ gcp: ::Bcome::Driver::Gcp
18
23
  }
19
24
  end
20
25
  end
21
26
 
22
- def initialize(params)
27
+ include ::Bcome::LoadingBar::Handler
28
+
29
+ def initialize(params, node)
23
30
  @params = params
31
+ @node = node
32
+ end
33
+
34
+ def has_network_credentials?
35
+ false
36
+ end
37
+
38
+ def loader_title
39
+ 'Loading' + "\s#{pretty_provider_name.bc_blue.bold}\s#{pretty_resource_location.underline}".bc_green
40
+ end
41
+
42
+ def loader_completed_title
43
+ 'done'
44
+ end
45
+
46
+ def pretty_provider_name
47
+ raise 'Should be overriden'
48
+ end
49
+
50
+ def pretty_resource_location
51
+ raise 'Should be overidden'
52
+ end
53
+
54
+ def network_credentials
55
+ raise 'Should be overidden'
24
56
  end
25
57
 
26
58
  def config
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bcome::Driver
2
4
  class Bucket
3
5
  include Singleton
@@ -6,13 +8,13 @@ module Bcome::Driver
6
8
  @drivers = []
7
9
  end
8
10
 
9
- def driver_for_network_data(network_data)
11
+ def driver_for_network_data(network_data, node)
10
12
  found_driver = @drivers.select { |driver| driver.config == network_data }.first
11
- found_driver ? found_driver : create_network_driver(network_data)
13
+ found_driver || create_network_driver(network_data, node)
12
14
  end
13
15
 
14
- def create_network_driver(network_data)
15
- driver = ::Bcome::Driver::Base.create_from_config(network_data)
16
+ def create_network_driver(network_data, node)
17
+ driver = ::Bcome::Driver::Base.create_from_config(network_data, node)
16
18
  @drivers << driver
17
19
  driver
18
20
  end
@@ -1,20 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fog/aws'
4
+
1
5
  module Bcome::Driver
2
6
  class Ec2 < Bcome::Driver::Base
3
-
4
- PATH_TO_FOG_CREDENTIALS = "#{ENV['HOME']}/.fog".freeze
7
+ PATH_TO_FOG_CREDENTIALS = "#{ENV['HOME']}/.fog"
5
8
 
6
9
  def initialize(*params)
7
10
  super
8
11
  raise Bcome::Exception::Ec2DriverMissingProvisioningRegion, params.inspect unless provisioning_region
9
12
  end
10
13
 
14
+ def pretty_provider_name
15
+ 'EC2'
16
+ end
17
+
18
+ def pretty_resource_location
19
+ @node.network_data[:provisioning_region]
20
+ end
21
+
11
22
  def fog_client
12
23
  @fog_client ||= get_fog_client
13
24
  end
14
25
 
15
26
  def fetch_server_list(filters)
16
- servers = unfiltered_server_list.all(filters)
17
- servers
27
+ wrap_indicator type: :basic, title: loader_title, completed_title: loader_completed_title do
28
+ begin
29
+ @servers = unfiltered_server_list.all(filters)
30
+ signal_success
31
+ rescue Exception => e
32
+ signal_failure
33
+ raise e
34
+ end
35
+ end
36
+
37
+ @servers
18
38
  end
19
39
 
20
40
  def unfiltered_server_list
@@ -25,6 +45,17 @@ module Bcome::Driver
25
45
  fog_client.servers.all({})
26
46
  end
27
47
 
48
+ def has_network_credentials?
49
+ true
50
+ end
51
+
52
+ def network_credentials
53
+ {
54
+ access_key: raw_fog_credentials['aws_access_key_id'],
55
+ secret_key: raw_fog_credentials['aws_secret_access_key']
56
+ }
57
+ end
58
+
28
59
  def raw_fog_credentials
29
60
  @raw_fog_credentials ||= YAML.load_file(PATH_TO_FOG_CREDENTIALS)[credentials_key]
30
61
  end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'google/apis/compute_beta'
4
+
5
+ module Bcome::Driver
6
+ class Gcp < Bcome::Driver::Base
7
+ APPLICATION_NAME = 'Bcome console'
8
+
9
+ def initialize(*params)
10
+ super
11
+ validate_service_scopes
12
+ validate_authentication_scheme
13
+ end
14
+
15
+ def pretty_provider_name
16
+ 'GCP'
17
+ end
18
+
19
+ def pretty_resource_location
20
+ "#{@params[:project]}/#{@params[:zone]}"
21
+ end
22
+
23
+ def fetch_server_list(_filters)
24
+ unless authentication_scheme.authorized?
25
+ get_authenticated_gcp_service
26
+ raise ::Bcome::Exception::Generic, 'GCP authentication process failed' unless authentication_scheme.authorized?
27
+ end
28
+
29
+ wrap_indicator type: :basic, title: loader_title, completed_title: loader_completed_title do
30
+ begin
31
+ @instances = do_fetch_server_list(_filters)
32
+ signal_success
33
+ rescue Exception => e
34
+ signal_failure
35
+ raise e
36
+ end
37
+ end
38
+ @instances.items
39
+ end
40
+
41
+ def do_fetch_server_list(_filters)
42
+ gcp_service.list_instances(@params[:project], @params[:zone])
43
+ rescue Google::Apis::AuthorizationError
44
+ raise ::Bcome::Exception::CannotAuthenticateToGcp
45
+ rescue Google::Apis::ClientError => e
46
+ raise ::Bcome::Exception::Generic, "Namespace #{@node.namespace} / #{e.message}"
47
+ rescue Google::Apis::TransmissionError => e
48
+ raise ::Bcome::Exception::Generic, 'Cannot reach GCP - do you have an internet connection?'
49
+ end
50
+
51
+ def has_network_credentials?
52
+ true
53
+ end
54
+
55
+ def network_credentials
56
+ {
57
+ access_token: access_token,
58
+ project_name: @params[:project]
59
+ }
60
+ end
61
+
62
+ protected
63
+
64
+ def validate_authentication_scheme
65
+ raise ::Bcome::Exception::MissingGcpAuthenticationScheme, "node #{@node.namespace}" if @params[:authentication_scheme].nil? || @params[:authentication_scheme].empty?
66
+ raise ::Bcome::Exception::InvalidGcpAuthenticationScheme, "Invalid GCP authentication scheme '#{@params[:authentication_scheme]}' for node #{@node.namespace}" unless auth_scheme
67
+ end
68
+
69
+ def invalid_auth_scheme?
70
+ !auth_schemes.keys.include?(@params[:authentication_scheme].to_sym)
71
+ end
72
+
73
+ def auth_scheme
74
+ auth_schemes[@params[:authentication_scheme].to_sym]
75
+ end
76
+
77
+ def auth_schemes
78
+ {
79
+ oauth: ::Bcome::Driver::Gcp::Authentication::Oauth,
80
+ serviceaccount: ::Bcome::Driver::Gcp::Authentication::ServiceAccount,
81
+ api_key: ::Bcome::Driver::Gcp::Authentication::ApiKey
82
+ }
83
+ end
84
+
85
+ def compute_service
86
+ @compute_service ||= ::Google::Apis::ComputeBeta::ComputeService.new
87
+ end
88
+
89
+ def get_authenticated_gcp_service
90
+ authentication_scheme.do!
91
+ compute_service
92
+ end
93
+
94
+ def authentication_scheme
95
+ # Service scopes are specified directly from the network config
96
+ # A minumum scope of https://www.googleapis.com/auth/compute.readonly is required in order to list resources.
97
+ @authentication_scheme ||= auth_scheme.new(self, compute_service, service_scopes, @node, @params[:secrets_path])
98
+ end
99
+
100
+ def gcp_service
101
+ @gcp_service ||= get_authenticated_gcp_service
102
+ end
103
+
104
+ def access_token
105
+ gcp_service.authorization.access_token
106
+ end
107
+
108
+ def authorization
109
+ gcp_service.authorization
110
+ end
111
+
112
+ def service_scopes
113
+ @params[:service_scopes]
114
+ end
115
+
116
+ def validate_service_scopes
117
+ raise ::Bcome::Exception::MissingGcpServiceScopes, 'Please define as minimum https://www.googleapis.com/auth/compute.readonly' unless has_service_scopes_defined?
118
+ end
119
+
120
+ def has_service_scopes_defined?
121
+ service_scopes&.any?
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bcome::Driver::Gcp::Authentication
4
+ class ApiKey
5
+ end
6
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'google/api_client/auth/storage'
4
+ require 'google/api_client/auth/storages/file_store'
5
+ require 'google/api_client/client_secrets'
6
+
7
+ module Bcome::Driver::Gcp::Authentication
8
+ class Oauth
9
+ credential_directory = '.gauth'
10
+ credential_file_suffix = 'oauth2.json'
11
+
12
+ include ::Bcome::LoadingBar::Handler
13
+
14
+ def initialize(driver, service, scopes, node, path_to_secrets)
15
+ @service = service
16
+ @scopes = scopes
17
+ @node = node
18
+ @driver = driver
19
+
20
+ @path_to_secrets = "#{credential_directory}/#{path_to_secrets}"
21
+ # All credentials are held in .gauth
22
+ ensure_credential_directory
23
+ end
24
+
25
+ def authorized?
26
+ storage && !@storage.authorization.nil?
27
+ end
28
+
29
+ def storage
30
+ @storage ||= ::Google::APIClient::Storage.new(Google::APIClient::FileStore.new(full_path_to_credential_file))
31
+ end
32
+
33
+ def credential_directory
34
+ '.gauth'
35
+ end
36
+
37
+ def credential_file_suffix
38
+ 'oauth2.json'
39
+ end
40
+
41
+ def full_path_to_credential_file
42
+ "#{credential_directory}/#{credential_file}"
43
+ end
44
+
45
+ def credential_file
46
+ "#{@node.keyed_namespace}:#{credential_file_suffix}"
47
+ end
48
+
49
+ def authorize!
50
+ @service.authorization = storage.authorize
51
+ end
52
+
53
+ def client_secrets
54
+ @client_secrets ||= load_client_secrets
55
+ end
56
+
57
+ def load_client_secrets
58
+ ::Google::APIClient::ClientSecrets.load(@path_to_secrets)
59
+ rescue Exception => e
60
+ raise ::Bcome::Exception::MissingOrInvalidClientSecrets, "#{@path_to_secrets}. Gcp exception: #{e.class} #{e.message}"
61
+ end
62
+
63
+ def loader_title
64
+ 'Authenticating' + "\s#{@driver.pretty_provider_name.bc_blue.bold}\s#{@driver.pretty_resource_location.underline}".bc_green
65
+ end
66
+
67
+ def do!
68
+ authorize!
69
+ if @storage.authorization.nil?
70
+ # Total bloat from google here. Thanks google... requiring at last possible moment.
71
+ require 'google/api_client/auth/installed_app'
72
+
73
+ wrap_indicator type: :basic, title: loader_title, completed_title: '' do
74
+ flow = Google::APIClient::InstalledAppFlow.new(
75
+ client_id: client_secrets.client_id,
76
+ client_secret: client_secrets.client_secret,
77
+ scope: @scopes
78
+ )
79
+
80
+ begin
81
+ @service.authorization = flow.authorize(storage)
82
+ signal_success
83
+ rescue ArgumentError => e
84
+ signal_failure
85
+ raise ::Bcome::Exception::MissingOrInvalidClientSecrets, "#{@path_to_secrets}. Gcp exception: #{e.class} #{e.message}"
86
+ end
87
+ end
88
+ end
89
+
90
+ @service
91
+ end
92
+
93
+ def notify_success
94
+ print "[\s" + "Credentials file written to\s" + full_path_to_credential_file + "\s]" + "\n"
95
+ end
96
+
97
+ def ensure_credential_directory
98
+ `mkdir -p #{credential_directory}`
99
+ end
100
+ end
101
+ end