bcome 1.3.4 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. checksums.yaml +5 -5
  2. data/bin/bcome +13 -8
  3. data/lib/bcome.rb +14 -11
  4. data/lib/objects/bcome/version.rb +19 -1
  5. data/lib/objects/bootup.rb +16 -7
  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 +52 -6
  9. data/lib/objects/driver/bucket.rb +6 -4
  10. data/lib/objects/driver/ec2.rb +45 -5
  11. data/lib/objects/driver/gcp.rb +168 -0
  12. data/lib/objects/driver/gcp/authentication/api_key.rb +6 -0
  13. data/lib/objects/driver/gcp/authentication/base.rb +36 -0
  14. data/lib/objects/driver/gcp/authentication/oauth.rb +96 -0
  15. data/lib/objects/driver/gcp/authentication/oauth_client_config.rb +22 -0
  16. data/lib/objects/driver/gcp/authentication/oauth_session_store.rb +22 -0
  17. data/lib/objects/driver/gcp/authentication/service_account.rb +62 -0
  18. data/lib/objects/driver/gcp/authentication/signet/service_account.rb +27 -0
  19. data/lib/objects/driver/gcp/authentication/utilities.rb +42 -0
  20. data/lib/objects/encryptor.rb +109 -24
  21. data/lib/objects/exception/argument_error_invoking_method_from_command_line.rb +8 -4
  22. data/lib/objects/exception/base.rb +21 -10
  23. data/lib/objects/exception/can_only_subselect_on_inventory.rb +8 -4
  24. data/lib/objects/exception/cannot_authenticate_to_gcp.rb +11 -0
  25. data/lib/objects/exception/cannot_find_internal_registry_klass.rb +8 -4
  26. data/lib/objects/exception/cannot_find_inventory.rb +11 -0
  27. data/lib/objects/exception/cannot_find_subselection_parent.rb +8 -4
  28. data/lib/objects/exception/cant_find_key_in_cloud_tags.rb +8 -4
  29. data/lib/objects/exception/cant_find_key_in_metadata.rb +8 -4
  30. data/lib/objects/exception/cant_find_proxy_host_by_identifier.rb +8 -4
  31. data/lib/objects/exception/cant_find_proxy_host_by_namespace.rb +8 -4
  32. data/lib/objects/exception/could_not_initiate_ssh_connection.rb +8 -4
  33. data/lib/objects/exception/could_not_initiate_ssh_connection_through_backend_proxy.rb +8 -4
  34. data/lib/objects/exception/could_not_retrieve_terraform_output.rb +11 -0
  35. data/lib/objects/exception/deprecation_warning.rb +9 -7
  36. data/lib/objects/exception/duplicate_command_line_argument_key.rb +8 -4
  37. data/lib/objects/exception/ec2_driver_missing_authorization_keys.rb +11 -0
  38. data/lib/objects/exception/ec2_driver_missing_provisioning_region.rb +8 -4
  39. data/lib/objects/exception/empty_namespace_tree.rb +11 -0
  40. data/lib/objects/exception/failed_to_run_local_command.rb +8 -4
  41. data/lib/objects/exception/gcp_auth_service_account_missing_credentials.rb +11 -0
  42. data/lib/objects/exception/generic.rb +11 -0
  43. data/lib/objects/exception/interactive_session_halt.rb +6 -2
  44. data/lib/objects/exception/invalid_bcome_breadcrumb.rb +8 -4
  45. data/lib/objects/exception/invalid_breadcrumb.rb +8 -4
  46. data/lib/objects/exception/invalid_context_command.rb +8 -4
  47. data/lib/objects/exception/invalid_gcp_authentication_scheme.rb +11 -0
  48. data/lib/objects/exception/invalid_identifier.rb +8 -4
  49. data/lib/objects/exception/invalid_machines_cache_config.rb +8 -4
  50. data/lib/objects/exception/invalid_matcher_query.rb +8 -4
  51. data/lib/objects/exception/invalid_meta_data_config.rb +8 -4
  52. data/lib/objects/exception/invalid_metadata_encryption_key.rb +8 -4
  53. data/lib/objects/exception/invalid_network_config.rb +8 -4
  54. data/lib/objects/exception/invalid_network_driver_type.rb +8 -4
  55. data/lib/objects/exception/invalid_port_forward_request.rb +11 -0
  56. data/lib/objects/exception/invalid_proxy_config.rb +8 -4
  57. data/lib/objects/exception/invalid_regexp_matcher_in_registry.rb +8 -4
  58. data/lib/objects/exception/invalid_registry_arguments_type.rb +8 -4
  59. data/lib/objects/exception/invalid_registry_command_name_length.rb +8 -4
  60. data/lib/objects/exception/invalid_registry_data_config.rb +8 -4
  61. data/lib/objects/exception/invalid_restriction_key_in_registry.rb +8 -4
  62. data/lib/objects/exception/invalid_ssh_config.rb +8 -4
  63. data/lib/objects/exception/inventories_cannot_have_subviews.rb +8 -4
  64. data/lib/objects/exception/malformed_command_line_arguments.rb +8 -4
  65. data/lib/objects/exception/method_invocation_requires_parameter.rb +8 -4
  66. data/lib/objects/exception/method_name_conflict_in_registry.rb +8 -4
  67. data/lib/objects/exception/missing_argument_for_registry_command.rb +8 -4
  68. data/lib/objects/exception/missing_description_on_view.rb +8 -4
  69. data/lib/objects/exception/missing_execute_on_registry_object.rb +8 -4
  70. data/lib/objects/exception/missing_gcp_authentication_scheme.rb +11 -0
  71. data/lib/objects/exception/missing_gcp_service_account_credentials_filename.rb +11 -0
  72. data/lib/objects/exception/missing_gcp_service_scopes.rb +11 -0
  73. data/lib/objects/exception/missing_identifier_on_view.rb +8 -4
  74. data/lib/objects/exception/missing_inventory_contributors.rb +11 -0
  75. data/lib/objects/exception/missing_ip_address_on_server.rb +8 -4
  76. data/lib/objects/exception/missing_network_config.rb +8 -4
  77. data/lib/objects/exception/missing_or_invalid_client_secrets.rb +11 -0
  78. data/lib/objects/exception/missing_params_for_rsync.rb +8 -4
  79. data/lib/objects/exception/missing_params_for_scp.rb +8 -4
  80. data/lib/objects/exception/missing_subselection_key.rb +8 -4
  81. data/lib/objects/exception/missing_type_on_view.rb +8 -4
  82. data/lib/objects/exception/no_node_found_for_breadcrumb.rb +8 -4
  83. data/lib/objects/exception/no_node_named_by_identifier.rb +8 -4
  84. data/lib/objects/exception/node_identifiers_must_be_unique.rb +8 -4
  85. data/lib/objects/exception/orchestration_script_does_not_exist.rb +8 -4
  86. data/lib/objects/exception/proxy_host_node_does_not_have_public_ip_address.rb +8 -4
  87. data/lib/objects/exception/unknown_dynamic_server_type.rb +11 -0
  88. data/lib/objects/exception/unknown_method_for_namespace.rb +8 -4
  89. data/lib/objects/exception/user_orchestration_error.rb +11 -0
  90. data/lib/objects/initialization/factory.rb +36 -0
  91. data/lib/objects/initialization/structure.rb +18 -0
  92. data/lib/objects/initialization/utils.rb +20 -0
  93. data/lib/objects/interactive/session.rb +4 -1
  94. data/lib/objects/interactive/session_item/base.rb +2 -0
  95. data/lib/objects/interactive/session_item/capture_input.rb +2 -0
  96. data/lib/objects/interactive/session_item/transparent_ssh.rb +29 -23
  97. data/lib/objects/loading_bar/handler.rb +80 -0
  98. data/lib/objects/loading_bar/indicator/base.rb +65 -0
  99. data/lib/objects/loading_bar/indicator/basic.rb +34 -0
  100. data/lib/objects/loading_bar/indicator/progress.rb +26 -0
  101. data/lib/objects/loading_bar/pid_bucket.rb +27 -0
  102. data/lib/objects/modules/context.rb +13 -9
  103. data/lib/objects/modules/draw.rb +49 -0
  104. data/lib/objects/modules/registry_management.rb +16 -10
  105. data/lib/objects/modules/tree.rb +157 -0
  106. data/lib/objects/modules/ui_output.rb +10 -6
  107. data/lib/objects/modules/workspace_commands.rb +131 -157
  108. data/lib/objects/modules/workspace_menu.rb +193 -129
  109. data/lib/objects/node/attributes.rb +17 -19
  110. data/lib/objects/node/base.rb +136 -74
  111. data/lib/objects/node/cache_handler.rb +3 -1
  112. data/lib/objects/node/collection.rb +10 -9
  113. data/lib/objects/node/factory.rb +47 -36
  114. data/lib/objects/node/inventory/base.rb +106 -100
  115. data/lib/objects/node/inventory/defined.rb +113 -89
  116. data/lib/objects/node/inventory/merge.rb +51 -0
  117. data/lib/objects/node/inventory/subselect.rb +66 -46
  118. data/lib/objects/node/kube/base.rb +51 -0
  119. data/lib/objects/node/kube/container.rb +9 -0
  120. data/lib/objects/node/kube/estate.rb +19 -0
  121. data/lib/objects/node/kube/namespace.rb +24 -0
  122. data/lib/objects/node/kube/pod.rb +24 -0
  123. data/lib/objects/node/kube_wrap.rb +26 -0
  124. data/lib/objects/node/meta/base.rb +8 -1
  125. data/lib/objects/node/meta/cloud.rb +2 -0
  126. data/lib/objects/node/meta/local.rb +2 -0
  127. data/lib/objects/node/meta_data_factory.rb +4 -2
  128. data/lib/objects/node/meta_data_loader.rb +28 -29
  129. data/lib/objects/node/resources/base.rb +5 -1
  130. data/lib/objects/node/resources/inventory.rb +26 -5
  131. data/lib/objects/node/resources/merged.rb +47 -0
  132. data/lib/objects/node/resources/sub_inventory.rb +12 -8
  133. data/lib/objects/node/server/base.rb +105 -70
  134. data/lib/objects/node/server/dynamic/base.rb +23 -0
  135. data/lib/objects/node/server/{dynamic.rb → dynamic/ec2.rb} +13 -13
  136. data/lib/objects/node/server/dynamic/gcp.rb +46 -0
  137. data/lib/objects/node/server/static.rb +34 -10
  138. data/lib/objects/orchestration/base.rb +17 -1
  139. data/lib/objects/orchestration/interactive_terraform.rb +59 -30
  140. data/lib/objects/orchestrator.rb +22 -0
  141. data/lib/objects/parser/bread_crumb.rb +3 -1
  142. data/lib/objects/registry/arguments/base.rb +3 -1
  143. data/lib/objects/registry/arguments/command_line.rb +6 -1
  144. data/lib/objects/registry/arguments/console.rb +4 -1
  145. data/lib/objects/registry/command/base.rb +3 -0
  146. data/lib/objects/registry/command/external.rb +9 -3
  147. data/lib/objects/registry/command/group.rb +11 -4
  148. data/lib/objects/registry/command/internal.rb +3 -1
  149. data/lib/objects/registry/command/shortcut.rb +17 -9
  150. data/lib/objects/registry/command_list.rb +2 -0
  151. data/lib/objects/registry/loader.rb +13 -10
  152. data/lib/objects/ssh/bootstrap.rb +3 -1
  153. data/lib/objects/ssh/command.rb +9 -8
  154. data/lib/objects/ssh/command_exec.rb +16 -10
  155. data/lib/objects/ssh/connection_wrangler.rb +124 -0
  156. data/lib/objects/ssh/connector.rb +108 -0
  157. data/lib/objects/ssh/driver.rb +28 -242
  158. data/lib/objects/ssh/driver_concerns/command_strings.rb +17 -0
  159. data/lib/objects/ssh/driver_concerns/connection.rb +75 -0
  160. data/lib/objects/ssh/driver_concerns/functions.rb +89 -0
  161. data/lib/objects/ssh/driver_concerns/user.rb +32 -0
  162. data/lib/objects/ssh/proxy_chain.rb +19 -0
  163. data/lib/objects/ssh/proxy_chain_link.rb +26 -0
  164. data/lib/objects/ssh/proxy_hop.rb +130 -0
  165. data/lib/objects/ssh/script_exec.rb +12 -11
  166. data/lib/objects/ssh/tunnel/local_port_forward.rb +5 -6
  167. data/lib/objects/ssh/tunnel_keeper.rb +21 -0
  168. data/lib/objects/ssh/window.rb +31 -0
  169. data/lib/objects/startup.rb +58 -0
  170. data/lib/objects/system/local.rb +3 -0
  171. data/lib/objects/terraform/output.rb +45 -0
  172. data/lib/objects/workspace.rb +13 -14
  173. data/patches/irb.rb +63 -6
  174. data/patches/string-encrypt.rb +20 -23
  175. data/patches/string.rb +18 -1
  176. data/patches/string_stylesheet.rb +2 -0
  177. metadata +157 -33
  178. data/lib/objects/driver/static.rb +0 -4
  179. data/lib/objects/progress_bar.rb +0 -30
  180. data/lib/objects/ssh/connection_handler.rb +0 -101
  181. data/lib/objects/ssh/proxy_data.rb +0 -56
  182. data/lib/objects/terraform/parser.rb +0 -23
  183. data/lib/objects/terraform/state.rb +0 -40
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4e26f496e3b1756df2ee8a288a02c8ca9746f975
4
- data.tar.gz: f241fbbcc02373d2071b846a1082a97eb5375a78
2
+ SHA256:
3
+ metadata.gz: c27e993a1ebc7cb838f3f13927f85ef715aecf18ccebd03c54fb9d6ccb782728
4
+ data.tar.gz: cfc4d0618d32554c00b0d1c6bd20932cb56bd762fce87504386519db81072bf9
5
5
  SHA512:
6
- metadata.gz: 0e1d58cf79db6fa814f733963ac851c4e16bce7f0f22ee6dc10139ee1164b99d84f0eae7253a01cdc8912866fd9b032f3e34fddd0d3ebf493f6d55b2c0446220
7
- data.tar.gz: 6da1f5d5bda08ba8a17099a5e3f1848fd01934ed27f21bad1d7dbeed993368766ee7fd659b21ec4927993d89d975c29ee75dfdeb587b63ababef2328bb342559
6
+ metadata.gz: a36e1a6d0b76cb4b1a4dbfac6ce34da68eb07217a190495cea4fd5904ac1b0d6f7f30c5c7ea4b02fcbb68958d4f6472b33fb3e35f6ce5d873484e6afbcfd6434
7
+ data.tar.gz: b37ee3c185cf7914efb462bbb4279e92255bd711e2283a48ff4a9d40c646d9a7365afd1cdfc5b665f04127087bf7d6fd72d46e610ebad228cc3fd0e996590134
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,14 @@
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 'strings-ansi'
11
+ require 'pry'
15
12
 
16
13
  require_all "#{File.dirname(__FILE__)}/../patches"
17
14
  require_all "#{File.dirname(__FILE__)}/../lib/objects"
@@ -19,3 +16,9 @@ require_all "#{File.dirname(__FILE__)}/../lib/objects"
19
16
  # Load in any user defined orchestration
20
17
  path_to_bcome_orchestration_configs = "#{Dir.getwd}/bcome/orchestration"
21
18
  require_all path_to_bcome_orchestration_configs if File.directory?(path_to_bcome_orchestration_configs)
19
+
20
+ # Load in any patches
21
+ # Note: previously patches could have (and were placed) anywhere in the orchestration directory above. This just makes it more explicit, and keeps
22
+ # things tidier.
23
+ path_to_user_monkey_patches = "#{Dir.getwd}/bcome/patches"
24
+ require_all path_to_user_monkey_patches if File.directory?(path_to_user_monkey_patches)
@@ -1,3 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bcome
2
- VERSION = '1.3.4'.freeze
4
+ module Version
5
+ def self.name
6
+ 'bcome'
7
+ end
8
+
9
+ def self.release
10
+ '2.0.1'
11
+ end
12
+
13
+ def self.release_name
14
+ 'Multicloud & Hybrid'
15
+ end
16
+
17
+ def self.display
18
+ "#{name} v#{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,7 +29,7 @@ module Bcome
31
29
 
32
30
  def init_context(context)
33
31
  if @spawn_into_console
34
- ::Bcome::Workspace.instance.set(context: context)
32
+ ::Bcome::Workspace.instance.set(context: context, show_welcome: true)
35
33
  else
36
34
  context
37
35
  end
@@ -45,17 +43,18 @@ module Bcome
45
43
  starting_context.load_nodes if starting_context.inventory? && !starting_context.nodes_loaded?
46
44
 
47
45
  # Attempt to load our next context resource
48
- next_context = starting_context.resource_for_identifier(crumb)
46
+ next_context = starting_context.resources.active.first if crumb == 'first'
47
+ next_context ||= starting_context.resource_for_identifier(crumb)
49
48
 
50
49
  # Our current breadcrumb is not a node, and so we'll attempt to invoke a method call on the previous
51
50
  # e.g. given resource:foo, then invoke 'foo' on 'resource'
52
51
  unless next_context
52
+ puts "\n" # clean any trailing loading bars
53
53
  starting_context.invoke(crumb, @arguments)
54
54
  return
55
55
  end
56
56
  starting_context = next_context
57
57
  end
58
-
59
58
  # Set our workspace to our last context - we're not invoking a method call and so we're entering a console session
60
59
  init_context(starting_context)
61
60
  end
@@ -64,6 +63,16 @@ module Bcome
64
63
  @estate ||= ::Bcome::Node::Factory.instance.init_tree
65
64
  end
66
65
 
66
+ def estate_loaded?
67
+ !@estate.nil?
68
+ end
69
+
70
+ def close_ssh_connections
71
+ return unless estate_loaded?
72
+
73
+ estate.close_ssh_connections
74
+ end
75
+
67
76
  def parser
68
77
  ::Bcome::Parser::BreadCrumb.new(@breadcrumbs)
69
78
  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,30 +1,76 @@
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
- raise Bcome::Exception::InvalidNetworkDriverType, "Missing config parameter 'type'" unless config[:type]
8
+ raise Bcome::Exception::InvalidNetworkDriverType, "Missing config parameter 'type' for namespace '#{config.inspect}'" 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
- static: ::Bcome::Driver::Static,
17
- ec2: ::Bcome::Driver::Ec2
20
+ ec2: ::Bcome::Driver::Ec2,
21
+ gcp: ::Bcome::Driver::Gcp
18
22
  }
19
23
  end
20
24
  end
21
25
 
22
- def initialize(params)
26
+ include ::Bcome::LoadingBar::Handler
27
+
28
+ def initialize(params, node)
23
29
  @params = params
30
+ @node = node
31
+ end
32
+
33
+ def has_network_credentials?
34
+ false
35
+ end
36
+
37
+ def loader_title
38
+ 'Loading' + "\s#{pretty_provider_name.bc_blue.bold}\s#{pretty_resource_location.underline}".bc_green
39
+ end
40
+
41
+ def loader_completed_title
42
+ 'done'
43
+ end
44
+
45
+ def pretty_provider_name
46
+ raise 'Should be overriden'
47
+ end
48
+
49
+ def pretty_resource_location
50
+ raise 'Should be overidden'
51
+ end
52
+
53
+ def network_credentials
54
+ raise 'Should be overidden'
24
55
  end
25
56
 
26
57
  def config
27
58
  @params
28
59
  end
60
+
61
+ ## Spoof-fetch. Used with the network-socket linkup POC.
62
+ def spoof_fetch_server_list(monkey_patched_inventory)
63
+ if @node.nodes_loaded?
64
+ monkey_patched_inventory.set_static_servers
65
+ else
66
+ wrap_indicator type: :basic, title: loader_title, completed_title: loader_completed_title do
67
+ fake_delay_milliseconds = rand(1..400).to_f / 1000
68
+ sleep fake_delay_milliseconds
69
+ monkey_patched_inventory.set_static_servers
70
+ signal_success
71
+ end
72
+ @node.nodes_loaded!
73
+ end
74
+ end
29
75
  end
30
76
  end
@@ -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,48 @@
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 = '.aws/keys'
5
8
 
6
9
  def initialize(*params)
7
10
  super
8
11
  raise Bcome::Exception::Ec2DriverMissingProvisioningRegion, params.inspect unless provisioning_region
12
+ raise ::Bcome::Exception::Ec2DriverMissingAuthorizationKeys, PATH_TO_FOG_CREDENTIALS unless File.exist?(PATH_TO_FOG_CREDENTIALS)
13
+
14
+ ENV['FOG_RC'] = PATH_TO_FOG_CREDENTIALS
15
+ end
16
+
17
+ def pretty_provider_name
18
+ 'EC2'
19
+ end
20
+
21
+ def pretty_resource_location
22
+ @node.network_data[:provisioning_region]
9
23
  end
10
24
 
11
25
  def fog_client
12
26
  @fog_client ||= get_fog_client
13
27
  end
14
28
 
15
- def fetch_server_list(filters)
16
- servers = unfiltered_server_list.all(filters)
17
- servers
29
+ def fetch_server_list(legacy_ec2_filters)
30
+ # Filters should be defined within a namespace's :network element. Pre 2.0 the expection for AWS was
31
+ # to define filters at the root level of the namespace. Here we move :filters into :network, yet retain
32
+ # ec2_filters at the root level for backwards compaibility with pre 2.0 versions.
33
+ filters = config.key?(:filters) ? config[:filters] : legacy_ec2_filters
34
+
35
+ wrap_indicator type: :basic, title: loader_title, completed_title: loader_completed_title do
36
+ begin
37
+ @servers = unfiltered_server_list.all(filters)
38
+ signal_success
39
+ rescue Exception => e
40
+ signal_failure
41
+ raise e
42
+ end
43
+ end
44
+
45
+ @servers
18
46
  end
19
47
 
20
48
  def unfiltered_server_list
@@ -25,6 +53,17 @@ module Bcome::Driver
25
53
  fog_client.servers.all({})
26
54
  end
27
55
 
56
+ def has_network_credentials?
57
+ true
58
+ end
59
+
60
+ def network_credentials
61
+ {
62
+ access_key: raw_fog_credentials['aws_access_key_id'],
63
+ secret_key: raw_fog_credentials['aws_secret_access_key']
64
+ }
65
+ end
66
+
28
67
  def raw_fog_credentials
29
68
  @raw_fog_credentials ||= YAML.load_file(PATH_TO_FOG_CREDENTIALS)[credentials_key]
30
69
  end
@@ -41,6 +80,7 @@ module Bcome::Driver
41
80
 
42
81
  def get_fog_client
43
82
  ::Fog.credential = credentials_key
83
+
44
84
  client = ::Fog::Compute.new(
45
85
  provider: 'AWS',
46
86
  region: provisioning_region
@@ -0,0 +1,168 @@
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
+ # Network filter key now called :filter. retained :list_filter for backwards compatibility.
43
+ # Fallback is ""
44
+ filters = (
45
+ @params[:filters] || (
46
+ @params[:list_filter] || ''
47
+ )
48
+ )
49
+
50
+ gcp_service.list_instances(@params[:project], @params[:zone], filter: filters)
51
+ rescue Google::Apis::AuthorizationError => e
52
+ raise ::Bcome::Exception::CannotAuthenticateToGcp
53
+ rescue Google::Apis::ClientError => e
54
+ raise ::Bcome::Exception::Generic, "Namespace #{@node.namespace} / #{e.message}"
55
+ rescue Google::Apis::TransmissionError => e
56
+ raise ::Bcome::Exception::Generic, 'Cannot reach GCP - do you have an internet connection?'
57
+ end
58
+
59
+ def has_network_credentials?
60
+ true
61
+ end
62
+
63
+ def network_credentials
64
+ {
65
+ access_token: access_token,
66
+ project_name: @params[:project]
67
+ }
68
+ end
69
+
70
+ protected
71
+
72
+ def validate_authentication_scheme
73
+ raise ::Bcome::Exception::MissingGcpAuthenticationScheme, "node #{@node.namespace}" if @params[:authentication_scheme].nil? || @params[:authentication_scheme].empty?
74
+ raise ::Bcome::Exception::InvalidGcpAuthenticationScheme, "Invalid GCP authentication scheme '#{@params[:authentication_scheme]}' for node #{@node.namespace}" unless auth_scheme
75
+ end
76
+
77
+ def invalid_auth_scheme?
78
+ !auth_schemes.keys.include?(@params[:authentication_scheme].to_sym)
79
+ end
80
+
81
+ def auth_scheme
82
+ auth_schemes[@params[:authentication_scheme].to_sym]
83
+ end
84
+
85
+ def auth_schemes
86
+ {
87
+ oauth: ::Bcome::Driver::Gcp::Authentication::Oauth,
88
+ service_account: ::Bcome::Driver::Gcp::Authentication::ServiceAccount
89
+ # api_key: ::Bcome::Driver::Gcp::Authentication::ApiKey
90
+ }
91
+ end
92
+
93
+ def compute_service
94
+ @compute_service ||= ::Google::Apis::ComputeBeta::ComputeService.new
95
+ end
96
+
97
+ def get_authenticated_gcp_service
98
+ authentication_scheme.do!
99
+ compute_service
100
+ end
101
+
102
+ def authentication_scheme
103
+ # Service scopes are specified directly from the network config
104
+ # A minumum scope of https://www.googleapis.com/auth/compute.readonly is required in order to list resources.
105
+
106
+ auth_scheme_key = @params[:authentication_scheme].to_sym
107
+ auth_scheme = auth_schemes[auth_scheme_key]
108
+ raise ::Bcome::Exception::InvalidGcpAuthenticationScheme, "Invalid GCP authentication scheme '#{auth_scheme_key}' for node #{@node.namespace}" unless auth_scheme
109
+
110
+ case auth_scheme_key
111
+ when :oauth
112
+
113
+ client_config = ::Bcome::Driver::Gcp::Authentication::OauthClientConfig.new(service_scopes, oauth_filename)
114
+
115
+ # Prevent second oauth flow during same session with same credentials, different inventory.
116
+ # If we already have an outh authentication scheme for the same scopes & oauth credentials, then we'll return that one
117
+
118
+ # If the scheme is set, return it
119
+ return @authentication_scheme if @authentication_scheme
120
+
121
+ # Look to see if we have an existing oauth scheme setup for the same scopes & credentials file
122
+ if @authentication_scheme = ::Bcome::Driver::Gcp::Authentication::OauthSessionStore.instance.in_memory_session_for(client_config)
123
+ @compute_service = @authentication_scheme.service
124
+
125
+ return @authentication_scheme
126
+ end
127
+
128
+ # Otherwise, we'll create a new outh scheme and register it with the session store
129
+ @authentication_scheme = auth_scheme.new(self, compute_service, client_config, @node)
130
+ ::Bcome::Driver::Gcp::Authentication::OauthSessionStore.instance << @authentication_scheme
131
+ @authentication_scheme
132
+
133
+ when :service_account
134
+ @authentication_scheme ||= auth_scheme.new(compute_service, service_scopes, @node, @params[:service_account_credentials], self)
135
+ else
136
+ raise ::Bcome::Exception::InvalidGcpAuthenticationScheme, "Invalid GCP authentication scheme '#{auth_scheme_key}' for node #{@node.namespace}"
137
+ end
138
+ end
139
+
140
+ def oauth_filename
141
+ @params[:secrets_path] || @params[:secrets_filename]
142
+ end
143
+
144
+ def gcp_service
145
+ @gcp_service ||= get_authenticated_gcp_service
146
+ end
147
+
148
+ def access_token
149
+ gcp_service.authorization.access_token
150
+ end
151
+
152
+ def authorization
153
+ gcp_service.authorization
154
+ end
155
+
156
+ def service_scopes
157
+ @params[:service_scopes]
158
+ end
159
+
160
+ def validate_service_scopes
161
+ raise ::Bcome::Exception::MissingGcpServiceScopes, 'Please define as minimum https://www.googleapis.com/auth/compute.readonly' unless has_service_scopes_defined?
162
+ end
163
+
164
+ def has_service_scopes_defined?
165
+ service_scopes&.any?
166
+ end
167
+ end
168
+ end