bcome 1.3.6 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
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