hybrid_platforms_conductor 33.5.0 → 33.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/lib/hybrid_platforms_conductor/actions_executor.rb +29 -1
  4. data/lib/hybrid_platforms_conductor/connector.rb +4 -1
  5. data/lib/hybrid_platforms_conductor/deployer.rb +5 -7
  6. data/lib/hybrid_platforms_conductor/hpc_plugins/connector/local.rb +2 -2
  7. data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +4 -3
  8. data/lib/hybrid_platforms_conductor/hpc_plugins/log/remote_fs.rb +5 -6
  9. data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb +1 -1
  10. data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +1 -1
  11. data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system.rb +1 -1
  12. data/lib/hybrid_platforms_conductor/hpc_plugins/test/hostname.rb +1 -2
  13. data/lib/hybrid_platforms_conductor/hpc_plugins/test/ip.rb +1 -2
  14. data/lib/hybrid_platforms_conductor/hpc_plugins/test/local_users.rb +1 -2
  15. data/lib/hybrid_platforms_conductor/hpc_plugins/test/mounts.rb +1 -2
  16. data/lib/hybrid_platforms_conductor/hpc_plugins/test/orphan_files.rb +1 -2
  17. data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre.rb +1 -1
  18. data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +1 -2
  19. data/lib/hybrid_platforms_conductor/test.rb +21 -7
  20. data/lib/hybrid_platforms_conductor/tests_runner.rb +7 -6
  21. data/lib/hybrid_platforms_conductor/version.rb +1 -1
  22. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/local/remote_actions_spec.rb +78 -0
  23. data/spec/hybrid_platforms_conductor_test/api/actions_executor/helpers_spec.rb +195 -0
  24. data/spec/hybrid_platforms_conductor_test/api/deployer/log_plugins/remote_fs_spec.rb +215 -0
  25. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/services_deployment_spec.rb +38 -0
  26. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/chef_versions.yml +3 -0
  27. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/nodes/node.json +15 -0
  28. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/policyfiles/test_policy.rb +3 -0
  29. data/spec/hybrid_platforms_conductor_test/shared_examples/deployer.rb +134 -0
  30. metadata +5 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: daf46892dd3b5a79ff0e54f16d6881b80519e8fe926e9952ad7faafd1706c31e
4
- data.tar.gz: 84f9ee06afb8141f140a8754d0961217ceb14b3f8d2d1d2577792be420d42aa2
3
+ metadata.gz: a1e882e48d05f919ad5818c9251e045f941d78a9eacc16824f3fd49e787d91b5
4
+ data.tar.gz: b685a6a1ca1f6f40714da2443ad7de95d78e90489f15a4b8499e153f4d84945a
5
5
  SHA512:
6
- metadata.gz: 7b1355694d9c7dbc5b2d2f9f6555972c25033d11bd07b14dfc728c94b2965ac1a852c91cb6ed4f20a26bc41cceb12f437a8b599177331cbf544e38ebc387cd4a
7
- data.tar.gz: 8636507ef5724bd9f0b3ffbb1f08c3efd1a48d39fe7161a4421350b4a03a9afff279b5522175418742ba87f7daca4dcdb4382e10f3283c39f9816eceba04bdc3
6
+ metadata.gz: f9386d953b2e652fd453656a21a935470099ba3f935a82229829d5777408e93149833883d7acd277da6cf2f08ba5ca49c8c62d43d3207b34113c347299335e5f
7
+ data.tar.gz: 9066d78f77fed46560b1884bade1074055da61547bd196c2a6479cf9412ba30f9d7518f91e05244307b703ebd241a620985e59f93a7911cd353543af26ae3699
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # [v33.5.1](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.5.0...v33.5.1) (2021-07-07 12:01:32)
2
+
3
+ ### Patches
4
+
5
+ * [[Bugfix] [#87] Make sure local nodes and root accounts are taken into account when getting sudo prefixes](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/cb626f1c99a6f1a95c9c884c03bf3fd71045259c)
6
+
1
7
  # [v33.5.0](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.4.0...v33.5.0) (2021-07-07 11:03:01)
2
8
 
3
9
  ### Features
@@ -53,7 +53,8 @@ module HybridPlatformsConductor
53
53
  logger_stderr: @logger_stderr,
54
54
  config: @config,
55
55
  cmd_runner: @cmd_runner,
56
- nodes_handler: @nodes_handler
56
+ nodes_handler: @nodes_handler,
57
+ actions_executor: self
57
58
  )
58
59
  end
59
60
  )
@@ -246,6 +247,33 @@ module HybridPlatformsConductor
246
247
  @connector_plugins[connector_name]
247
248
  end
248
249
 
250
+ # Is the access to a given node privileged?
251
+ # Take into account if remote actions are executed on a local node, and configurable sudos.
252
+ #
253
+ # Parameters::
254
+ # * *node* (String): Node on which we want privileged access
255
+ # Result::
256
+ # * Boolean: Is the access privileged?
257
+ def privileged_access?(node)
258
+ (@nodes_handler.get_local_node_of(node) ? @cmd_runner.whoami : connector(:ssh).ssh_user) == 'root'
259
+ end
260
+
261
+ # Get the sudo prefix to get privileged access.
262
+ # Take into account if remote actions are executed on a local node, and configurable sudos.
263
+ #
264
+ # Parameters::
265
+ # * *node* (String): Node on which we want privileged access
266
+ # * *forward_env* (Boolean): Do we need to forward environment in case of sudo? [default: false]
267
+ # Result::
268
+ # * String: Sudo prefix to be used (can be empty if root is being used)
269
+ def sudo_prefix(node, forward_env: false)
270
+ if privileged_access?(node)
271
+ ''
272
+ else
273
+ "#{@nodes_handler.sudo_on(node)} #{forward_env ? '-E ' : ''}"
274
+ end
275
+ end
276
+
249
277
  private
250
278
 
251
279
  # Execute a list of actions for a node, and return exit codes, stdout and stderr of those actions.
@@ -14,16 +14,19 @@ module HybridPlatformsConductor
14
14
  # * *config* (Config): Config to be used. [default: Config.new]
15
15
  # * *cmd_runner* (CmdRunner): Command executor to be used. [default: CmdRunner.new]
16
16
  # * *nodes_handler* (NodesHandler): NodesHandler to be used. [default: NodesHandler.new]
17
+ # * *actions_executor* (ActionsExecutor): ActionsExecutor to be used. [default: ActionsExecutor.new]
17
18
  def initialize(
18
19
  logger: Logger.new($stdout),
19
20
  logger_stderr: Logger.new($stderr),
20
21
  config: Config.new,
21
22
  cmd_runner: CmdRunner.new,
22
- nodes_handler: NodesHandler.new
23
+ nodes_handler: NodesHandler.new,
24
+ actions_executor: ActionsExecutor.new
23
25
  )
24
26
  super(logger: logger, logger_stderr: logger_stderr, config: config)
25
27
  @cmd_runner = cmd_runner
26
28
  @nodes_handler = nodes_handler
29
+ @actions_executor = actions_executor
27
30
  # If the connector has an initializer, use it
28
31
  init if respond_to?(:init)
29
32
  end
@@ -544,15 +544,13 @@ module HybridPlatformsConductor
544
544
  # Result::
545
545
  # * Hash<String, [Integer or Symbol, String, String]>: Exit status code (or Symbol in case of error or dry run), standard output and error for each node.
546
546
  def deploy(services)
547
- # Get the ssh user directly from the connector
548
- ssh_user = @actions_executor.connector(:ssh).ssh_user
549
-
550
547
  # Deploy for real
551
548
  @nodes_handler.prefetch_metadata_of services.keys, :image
552
549
  outputs = @actions_executor.execute_actions(
553
550
  services.map do |node, node_services|
554
551
  image_id = @nodes_handler.get_image_of(node)
555
- sudo = (ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(node)} ")
552
+ need_sudo = !@actions_executor.privileged_access?(node)
553
+ sudo = @actions_executor.sudo_prefix(node)
556
554
  # Install corporate certificates if present
557
555
  certificate_actions =
558
556
  if @local_environment && ENV['hpc_certificates']
@@ -568,7 +566,7 @@ module HybridPlatformsConductor
568
566
  {
569
567
  scp: {
570
568
  ENV['hpc_certificates'] => '/usr/local/share/ca-certificates',
571
- :sudo => ssh_user != 'root'
569
+ :sudo => need_sudo
572
570
  },
573
571
  remote_bash: "#{sudo}update-ca-certificates"
574
572
  }
@@ -584,7 +582,7 @@ module HybridPlatformsConductor
584
582
  cert_file,
585
583
  '/etc/pki/ca-trust/source/anchors'
586
584
  ]
587
- end.to_h.merge(sudo: ssh_user != 'root'),
585
+ end.to_h.merge(sudo: need_sudo),
588
586
  remote_bash: [
589
587
  "#{sudo}update-ca-trust enable",
590
588
  "#{sudo}update-ca-trust extract"
@@ -619,7 +617,7 @@ module HybridPlatformsConductor
619
617
  services.keys.map do |node|
620
618
  [
621
619
  node,
622
- { remote_bash: "#{ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(node)} "}./mutex_dir unlock /tmp/hybrid_platforms_conductor_deploy_lock" }
620
+ { remote_bash: "#{@actions_executor.sudo_prefix(node)}./mutex_dir unlock /tmp/hybrid_platforms_conductor_deploy_lock" }
623
621
  ]
624
622
  end.to_h,
625
623
  timeout: 10,
@@ -77,8 +77,8 @@ module HybridPlatformsConductor
77
77
  def remote_copy(from, to, sudo: false, owner: nil, group: nil)
78
78
  # If the destination is a relative path, prepend the workspace dir to it.
79
79
  to = "#{workspace_for(@node)}/#{to}" unless to.start_with?('/')
80
- if sudo
81
- run_cmd "#{@nodes_handler.sudo_on(@node)} cp -r \"#{from}\" \"#{to}\""
80
+ if sudo && !@actions_executor.privileged_access?(@node)
81
+ run_cmd "#{@actions_executor.sudo_prefix(@node)}cp -r \"#{from}\" \"#{to}\""
82
82
  else
83
83
  FileUtils.cp_r from, to unless @cmd_runner.dry_run
84
84
  end
@@ -310,13 +310,14 @@ module HybridPlatformsConductor
310
310
  # * *owner* (String or nil): Owner to be used when copying the files, or nil for current one [default: nil]
311
311
  # * *group* (String or nil): Group to be used when copying the files, or nil for current one [default: nil]
312
312
  def remote_copy(from, to, sudo: false, owner: nil, group: nil)
313
+ need_sudo = sudo && !@actions_executor.privileged_access?(@node)
313
314
  if @nodes_handler.get_ssh_session_exec_of(@node) == false
314
315
  # We don't have ExecSession, so don't use ssh, but scp instead.
315
- if sudo
316
+ if need_sudo
316
317
  # We need to first copy the file in an accessible directory, and then sudo mv
317
318
  remote_bash('mkdir -p hpc_tmp_scp')
318
319
  run_cmd "scp -S #{ssh_exec} #{from} #{ssh_url}:./hpc_tmp_scp"
319
- remote_bash("#{@nodes_handler.sudo_on(@node)} mv ./hpc_tmp_scp/#{File.basename(from)} #{to}")
320
+ remote_bash("#{@actions_executor.sudo_prefix(@node)}mv ./hpc_tmp_scp/#{File.basename(from)} #{to}")
320
321
  else
321
322
  run_cmd "scp -S #{ssh_exec} #{from} #{ssh_url}:#{to}"
322
323
  end
@@ -332,7 +333,7 @@ module HybridPlatformsConductor
332
333
  #{File.basename(from)} | \
333
334
  #{ssh_exec} \
334
335
  #{ssh_url} \
335
- \"#{sudo ? "#{@nodes_handler.sudo_on(@node)} " : ''}tar \
336
+ \"#{need_sudo ? @actions_executor.sudo_prefix(@node) : ''}tar \
336
337
  --extract \
337
338
  --gunzip \
338
339
  --file - \
@@ -29,10 +29,9 @@ module HybridPlatformsConductor
29
29
  # Result::
30
30
  # * Array< Hash<Symbol,Object> >: List of actions to be done
31
31
  def actions_to_save_logs(node, services, deployment_info, exit_status, stdout, stderr)
32
- # Create a log file to be scp with all relevant info
33
- ssh_user = @actions_executor.connector(:ssh).ssh_user
34
- sudo_prefix = ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(node)} "
35
- log_file = "#{Dir.tmpdir}/hpc_deploy_logs/#{node}_#{Time.now.utc.strftime('%F_%H%M%S')}_#{ssh_user}"
32
+ # Create a log file to be scp-ed with all relevant info
33
+ sudo_prefix = @actions_executor.sudo_prefix(node)
34
+ log_file = "#{Dir.tmpdir}/hpc_deploy_logs/#{node}_#{Time.now.utc.strftime('%F_%H%M%S')}_#{@actions_executor.connector(:ssh).ssh_user}"
36
35
  [
37
36
  {
38
37
  ruby: proc do
@@ -56,7 +55,7 @@ module HybridPlatformsConductor
56
55
  {
57
56
  scp: {
58
57
  log_file => '/var/log/deployments',
59
- :sudo => ssh_user != 'root',
58
+ :sudo => !@actions_executor.privileged_access?(node),
60
59
  :owner => 'root',
61
60
  :group => 'root'
62
61
  }
@@ -85,7 +84,7 @@ module HybridPlatformsConductor
85
84
  # Result::
86
85
  # * Array< Hash<Symbol,Object> >: List of actions to be done
87
86
  def actions_to_read_logs(node)
88
- sudo_prefix = @actions_executor.connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(node)} "
87
+ sudo_prefix = @actions_executor.sudo_prefix(node)
89
88
  [
90
89
  { remote_bash: "#{sudo_prefix}cat /var/log/deployments/`#{sudo_prefix}ls -t /var/log/deployments/ | head -1`" }
91
90
  ]
@@ -263,7 +263,7 @@ module HybridPlatformsConductor
263
263
  raise "Missing file #{chef_versions_file} specifying the Chef Infra Client version to be deployed" unless File.exist?(chef_versions_file)
264
264
 
265
265
  required_chef_client_version = YAML.load_file(chef_versions_file)['client']
266
- sudo = (@actions_executor.connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(node)} -E ")
266
+ sudo = @actions_executor.sudo_prefix(node, forward_env: true)
267
267
  [
268
268
  {
269
269
  # Install dependencies
@@ -436,7 +436,7 @@ module HybridPlatformsConductor
436
436
  {
437
437
  proxmox_test_info[:sync_node] => {
438
438
  remote_bash: {
439
- commands: "#{@actions_executor.connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(proxmox_test_info[:sync_node])} -E "}./proxmox/#{cmd}",
439
+ commands: "#{@actions_executor.sudo_prefix(proxmox_test_info[:sync_node], forward_env: true)}./proxmox/#{cmd}",
440
440
  env: {
441
441
  'hpc_user_for_proxmox' => user,
442
442
  'hpc_password_for_proxmox' => password,
@@ -17,7 +17,7 @@ module HybridPlatformsConductor
17
17
  # Flatten the paths rules so that we can spot inconsistencies in configuration
18
18
  @config.aggregate_files_rules(@nodes_handler, @node).map do |path, rule_info|
19
19
  [
20
- "if #{@nodes_handler.sudo_on(@node)} /bin/bash -c '[[ -d \"#{path}\" ]]' ; then echo 1 ; else echo 0 ; fi",
20
+ "if #{@actions_executor.sudo_prefix(@node)}/bin/bash -c '[[ -d \"#{path}\" ]]' ; then echo 1 ; else echo 0 ; fi",
21
21
  {
22
22
  validator: proc do |stdout, stderr|
23
23
  case stdout.last
@@ -12,8 +12,7 @@ module HybridPlatformsConductor
12
12
  # Check my_test_plugin.rb.sample documentation for signature details.
13
13
  def test_on_node
14
14
  {
15
- # TODO: Access the user correctly when the user notion will be moved out of the ssh connector
16
- "#{@deployer.instance_variable_get(:@actions_executor).connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(@node)} "}hostname -s" => proc do |stdout|
15
+ "#{@actions_executor.sudo_prefix(@node)}hostname -s" => proc do |stdout|
17
16
  assert_equal stdout.first, @node, "Expected hostname to be #{@node}, but got #{stdout.first} instead."
18
17
  end
19
18
  }
@@ -12,8 +12,7 @@ module HybridPlatformsConductor
12
12
  # Check my_test_plugin.rb.sample documentation for signature details.
13
13
  def test_on_node
14
14
  {
15
- # TODO: Access the user correctly when the user notion will be moved out of the ssh connector
16
- "#{@deployer.instance_variable_get(:@actions_executor).connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(@node)} "}hostname -I" => proc do |stdout|
15
+ "#{@actions_executor.sudo_prefix(@node)}hostname -I" => proc do |stdout|
17
16
  if stdout.first.nil?
18
17
  error 'No IP returned by "hostname -I"'
19
18
  else
@@ -59,8 +59,7 @@ module HybridPlatformsConductor
59
59
  # Check my_test_plugin.rb.sample documentation for signature details.
60
60
  def test_on_node
61
61
  {
62
- # TODO: Access the user correctly when the user notion will be moved out of the ssh connector
63
- "#{@deployer.instance_variable_get(:@actions_executor).connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(@node)} "}cat /etc/passwd" => proc do |stdout|
62
+ "#{@actions_executor.sudo_prefix(@node)}cat /etc/passwd" => proc do |stdout|
64
63
  passwd_users = stdout.map { |passwd_line| passwd_line.split(':').first }
65
64
  missing_users = @nodes_handler.
66
65
  select_confs_for_node(@node, @config.users_that_should_be_present).
@@ -63,8 +63,7 @@ module HybridPlatformsConductor
63
63
  # Check my_test_plugin.rb.sample documentation for signature details.
64
64
  def test_on_node
65
65
  {
66
- # TODO: Access the user correctly when the user notion will be moved out of the ssh connector
67
- "#{@deployer.instance_variable_get(:@actions_executor).connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(@node)} "}mount" => proc do |stdout|
66
+ "#{@actions_executor.sudo_prefix(@node)}mount" => proc do |stdout|
68
67
  mounts_info = stdout.map do |line|
69
68
  fields = line.split
70
69
  {
@@ -52,8 +52,7 @@ module HybridPlatformsConductor
52
52
  # Check my_test_plugin.rb.sample documentation for signature details.
53
53
  def test_on_node
54
54
  {
55
- # TODO: Access the user correctly when the user notion will be moved out of the ssh connector
56
- "#{@deployer.instance_variable_get(:@actions_executor).connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(@node)} "}/usr/bin/find / \\( #{
55
+ "#{@actions_executor.sudo_prefix(@node)}/usr/bin/find / \\( #{
57
56
  @nodes_handler.
58
57
  select_confs_for_node(@node, @config.ignored_orphan_files_paths).
59
58
  inject(DIRECTORIES_TO_ALWAYS_IGNORE) { |merged_paths, paths_to_ignore_info| merged_paths + paths_to_ignore_info[:ignored_paths] }.
@@ -18,7 +18,7 @@ module HybridPlatformsConductor
18
18
  # Check my_test_plugin.rb.sample documentation for signature details.
19
19
  def test_on_node
20
20
  spectre_cmd = <<~EO_BASH
21
- #{@deployer.instance_variable_get(:@actions_executor).connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(@node)} "}/bin/bash <<'EOAction'
21
+ #{@actions_executor.sudo_prefix(@node)}/bin/bash <<'EOAction'
22
22
  #{File.read("#{__dir__}/spectre-meltdown-checker.sh")}
23
23
  EOAction
24
24
  EO_BASH
@@ -56,8 +56,7 @@ module HybridPlatformsConductor
56
56
  current_url
57
57
  end
58
58
  )
59
- # TODO: Access the user correctly when the user notion will be moved out of the ssh connector
60
- sudo = @deployer.instance_variable_get(:@actions_executor).connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(@node)} "
59
+ sudo = @actions_executor.sudo_prefix(@node)
61
60
  urls.map do |url|
62
61
  # 1. Get the OVAL file on the node to be tested (uncompress it if needed)
63
62
  # 2. Make sure oscap is installed
@@ -36,20 +36,34 @@ module HybridPlatformsConductor
36
36
  # Constructor
37
37
  #
38
38
  # Parameters::
39
- # * *logger* (Logger): Logger to be used
40
- # * *logger_stderr* (Logger): Logger to be used for stderr
41
- # * *config* (Config): Config to be used.
42
- # * *cmd_runner* (CmdRunner): CmdRunner that can be used by tests
43
- # * *nodes_handler* (NodesHandler): Nodes handler that can be used by tests
44
- # * *deployer* (Deployer): Deployer that can be used by tests
39
+ # * *logger* (Logger): Logger to be used [default: Logger.new($stdout)]
40
+ # * *logger_stderr* (Logger): Logger to be used for stderr [default: Logger.new($stderr)]
41
+ # * *config* (Config): Config to be used. [default: Config.new]
42
+ # * *cmd_runner* (CmdRunner): Command executor to be used. [default: CmdRunner.new]
43
+ # * *nodes_handler* (NodesHandler): Nodes handler to be used. [default: NodesHandler.new]
44
+ # * *actions_executor* (ActionsExecutor): Actions Executor to be used. [default: ActionsExecutor.new]
45
+ # * *deployer* (Deployer): Deployer that can be used by tests [default: Deployer.new]
45
46
  # * *name* (String): Name of the test being instantiated [default: 'unknown_test']
46
47
  # * *platform* (PlatformHandler): Platform handler for which the test is instantiated, or nil if global or node specific [default: nil]
47
48
  # * *node* (String): Node name for which the test is instantiated, or nil if global or platform specific [default: nil]
48
49
  # * *expected_failure* (String or nil): Expected failure, or nil if not expected to fail [default: nil]
49
- def initialize(logger, logger_stderr, config, cmd_runner, nodes_handler, deployer, name: 'unknown_test', platform: nil, node: nil, expected_failure: nil)
50
+ def initialize(
51
+ logger: Logger.new($stdout),
52
+ logger_stderr: Logger.new($stderr),
53
+ config: Config.new,
54
+ cmd_runner: CmdRunner.new,
55
+ nodes_handler: NodesHandler.new,
56
+ actions_executor: ActionsExecutor.new,
57
+ deployer: Deployer.new,
58
+ name: 'unknown_test',
59
+ platform: nil,
60
+ node: nil,
61
+ expected_failure: nil
62
+ )
50
63
  super(logger: logger, logger_stderr: logger_stderr, config: config)
51
64
  @cmd_runner = cmd_runner
52
65
  @nodes_handler = nodes_handler
66
+ @actions_executor = actions_executor
53
67
  @deployer = deployer
54
68
  @name = name
55
69
  @platform = platform
@@ -274,12 +274,13 @@ module HybridPlatformsConductor
274
274
  # * Test: Corresponding test
275
275
  def new_test(test_name, platform: nil, node: nil, ignore_expected_failure: false)
276
276
  (test_name.nil? ? Test : @tests_plugins[test_name]).new(
277
- @logger,
278
- @logger_stderr,
279
- @config,
280
- @cmd_runner,
281
- @nodes_handler,
282
- @deployer,
277
+ logger: @logger,
278
+ logger_stderr: @logger_stderr,
279
+ config: @config,
280
+ cmd_runner: @cmd_runner,
281
+ nodes_handler: @nodes_handler,
282
+ actions_executor: @actions_executor,
283
+ deployer: @deployer,
283
284
  name: test_name.nil? ? :global : test_name,
284
285
  platform: platform,
285
286
  node: node,
@@ -1,5 +1,5 @@
1
1
  module HybridPlatformsConductor
2
2
 
3
- VERSION = '33.5.0'
3
+ VERSION = '33.5.1'
4
4
 
5
5
  end
@@ -107,6 +107,10 @@ describe HybridPlatformsConductor::ActionsExecutor do
107
107
  it 'copies files remotely with sudo' do
108
108
  with_test_platform_for_remote_testing(
109
109
  expected_cmds: [
110
+ [
111
+ 'whoami',
112
+ proc { [0, 'test_user', ''] }
113
+ ],
110
114
  [
111
115
  'sudo -u root cp -r "/path/to/src.file" "/remote_path/to/dst.dir"',
112
116
  proc { [0, '', ''] }
@@ -117,9 +121,27 @@ describe HybridPlatformsConductor::ActionsExecutor do
117
121
  end
118
122
  end
119
123
 
124
+ it 'copies files remotely with sudo when being root' do
125
+ with_test_platform_for_remote_testing(
126
+ expected_cmds: [
127
+ [
128
+ 'whoami',
129
+ proc { [0, 'root', ''] }
130
+ ]
131
+ ]
132
+ ) do
133
+ expect(FileUtils).to receive(:cp_r).with('/path/to/src.file', '/remote_path/to/dst.dir')
134
+ test_connector.remote_copy('/path/to/src.file', '/remote_path/to/dst.dir', sudo: true)
135
+ end
136
+ end
137
+
120
138
  it 'copies files remotely with a different sudo' do
121
139
  with_test_platform_for_remote_testing(
122
140
  expected_cmds: [
141
+ [
142
+ 'whoami',
143
+ proc { [0, 'test_user', ''] }
144
+ ],
123
145
  [
124
146
  'other_sudo --user root cp -r "/path/to/src.file" "/remote_path/to/dst.dir"',
125
147
  proc { [0, '', ''] }
@@ -133,6 +155,23 @@ describe HybridPlatformsConductor::ActionsExecutor do
133
155
  end
134
156
  end
135
157
 
158
+ it 'copies files remotely with a different sudo when being root' do
159
+ with_test_platform_for_remote_testing(
160
+ expected_cmds: [
161
+ [
162
+ 'whoami',
163
+ proc { [0, 'root', ''] }
164
+ ]
165
+ ],
166
+ additional_config: <<~'EO_CONFIG'
167
+ sudo_for { |user| "other_sudo --user #{user}" }
168
+ EO_CONFIG
169
+ ) do
170
+ expect(FileUtils).to receive(:cp_r).with('/path/to/src.file', '/remote_path/to/dst.dir')
171
+ test_connector.remote_copy('/path/to/src.file', '/remote_path/to/dst.dir', sudo: true)
172
+ end
173
+ end
174
+
136
175
  it 'copies files remotely with timeout' do
137
176
  with_test_platform_for_remote_testing(
138
177
  timeout: 5
@@ -152,6 +191,10 @@ describe HybridPlatformsConductor::ActionsExecutor do
152
191
  it 'copies relative files remotely with sudo' do
153
192
  with_test_platform_for_remote_testing(
154
193
  expected_cmds: [
194
+ [
195
+ 'whoami',
196
+ proc { [0, 'test_user', ''] }
197
+ ],
155
198
  [
156
199
  'sudo -u root cp -r "/path/to/src.file" "/tmp/hpc_local_workspaces/node/to/dst.dir"',
157
200
  proc { [0, '', ''] }
@@ -162,9 +205,27 @@ describe HybridPlatformsConductor::ActionsExecutor do
162
205
  end
163
206
  end
164
207
 
208
+ it 'copies relative files remotely with sudo when being root' do
209
+ with_test_platform_for_remote_testing(
210
+ expected_cmds: [
211
+ [
212
+ 'whoami',
213
+ proc { [0, 'root', ''] }
214
+ ]
215
+ ]
216
+ ) do
217
+ expect(FileUtils).to receive(:cp_r).with('/path/to/src.file', '/tmp/hpc_local_workspaces/node/to/dst.dir')
218
+ test_connector.remote_copy('/path/to/src.file', 'to/dst.dir', sudo: true)
219
+ end
220
+ end
221
+
165
222
  it 'copies relative files remotely with a different sudo' do
166
223
  with_test_platform_for_remote_testing(
167
224
  expected_cmds: [
225
+ [
226
+ 'whoami',
227
+ proc { [0, 'test_user', ''] }
228
+ ],
168
229
  [
169
230
  'other_sudo --user root cp -r "/path/to/src.file" "/tmp/hpc_local_workspaces/node/to/dst.dir"',
170
231
  proc { [0, '', ''] }
@@ -178,6 +239,23 @@ describe HybridPlatformsConductor::ActionsExecutor do
178
239
  end
179
240
  end
180
241
 
242
+ it 'copies relative files remotely with a different sudo when being root' do
243
+ with_test_platform_for_remote_testing(
244
+ expected_cmds: [
245
+ [
246
+ 'whoami',
247
+ proc { [0, 'root', ''] }
248
+ ]
249
+ ],
250
+ additional_config: <<~'EO_CONFIG'
251
+ sudo_for { |user| "other_sudo --user #{user}" }
252
+ EO_CONFIG
253
+ ) do
254
+ expect(FileUtils).to receive(:cp_r).with('/path/to/src.file', '/tmp/hpc_local_workspaces/node/to/dst.dir')
255
+ test_connector.remote_copy('/path/to/src.file', 'to/dst.dir', sudo: true)
256
+ end
257
+ end
258
+
181
259
  end
182
260
 
183
261
  end
@@ -0,0 +1,195 @@
1
+ describe HybridPlatformsConductor::ActionsExecutor do
2
+
3
+ context 'when checking helpers' do
4
+
5
+ it 'gives access to connectors' do
6
+ with_test_platform({}) do
7
+ expect(test_actions_executor.connector(:ssh)).not_to be_nil
8
+ end
9
+ end
10
+
11
+ it 'returns if a user has privileged access on a node' do
12
+ with_test_platform({ nodes: { 'node' => {} } }) do
13
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
14
+ expect(test_actions_executor.privileged_access?('node')).to eq false
15
+ end
16
+ end
17
+
18
+ it 'returns if a user has privileged access on a node when connecting with root' do
19
+ with_test_platform({ nodes: { 'node' => {} } }) do
20
+ test_actions_executor.connector(:ssh).ssh_user = 'root'
21
+ expect(test_actions_executor.privileged_access?('node')).to eq true
22
+ end
23
+ end
24
+
25
+ it 'returns if a user has privileged access on a local node' do
26
+ with_test_platform({ nodes: { 'node' => { meta: { local_node: true } } } }) do
27
+ with_cmd_runner_mocked [
28
+ ['whoami', proc { [0, 'test_user', ''] }]
29
+ ] do
30
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
31
+ expect(test_actions_executor.privileged_access?('node')).to eq false
32
+ end
33
+ end
34
+ end
35
+
36
+ it 'returns if a user has privileged access on a local node when local user is root' do
37
+ with_test_platform({ nodes: { 'node' => { meta: { local_node: true } } } }) do
38
+ with_cmd_runner_mocked [
39
+ ['whoami', proc { [0, 'root', ''] }]
40
+ ] do
41
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
42
+ expect(test_actions_executor.privileged_access?('node')).to eq true
43
+ end
44
+ end
45
+ end
46
+
47
+ context 'with connection on a remote node' do
48
+
49
+ it 'returns the correct sudo prefix' do
50
+ with_test_platform({ nodes: { 'node' => {} } }) do
51
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
52
+ expect(test_actions_executor.sudo_prefix('node')).to eq 'sudo -u root '
53
+ end
54
+ end
55
+
56
+ it 'returns the correct sudo prefix with env forwarding' do
57
+ with_test_platform({ nodes: { 'node' => {} } }) do
58
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
59
+ expect(test_actions_executor.sudo_prefix('node', forward_env: true)).to eq 'sudo -u root -E '
60
+ end
61
+ end
62
+
63
+ it 'returns the correct sudo prefix when connecting as root' do
64
+ with_test_platform({ nodes: { 'node' => {} } }) do
65
+ test_actions_executor.connector(:ssh).ssh_user = 'root'
66
+ expect(test_actions_executor.sudo_prefix('node')).to eq ''
67
+ end
68
+ end
69
+
70
+ it 'returns the correct sudo prefix with a different sudo' do
71
+ with_test_platform(
72
+ { nodes: { 'node' => {} } },
73
+ additional_config: <<~'EO_CONFIG'
74
+ sudo_for { |user| "other_sudo --user #{user}" }
75
+ EO_CONFIG
76
+ ) do
77
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
78
+ expect(test_actions_executor.sudo_prefix('node')).to eq 'other_sudo --user root '
79
+ end
80
+ end
81
+
82
+ it 'returns the correct sudo prefix with a different sudo and env forwarding' do
83
+ with_test_platform(
84
+ { nodes: { 'node' => {} } },
85
+ additional_config: <<~'EO_CONFIG'
86
+ sudo_for { |user| "other_sudo --user #{user}" }
87
+ EO_CONFIG
88
+ ) do
89
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
90
+ expect(test_actions_executor.sudo_prefix('node', forward_env: true)).to eq 'other_sudo --user root -E '
91
+ end
92
+ end
93
+
94
+ it 'returns the correct sudo prefix with a different sudo when connecting as root' do
95
+ with_test_platform(
96
+ { nodes: { 'node' => {} } },
97
+ additional_config: <<~'EO_CONFIG'
98
+ sudo_for { |user| "other_sudo --user #{user}" }
99
+ EO_CONFIG
100
+ ) do
101
+ test_actions_executor.connector(:ssh).ssh_user = 'root'
102
+ expect(test_actions_executor.sudo_prefix('node')).to eq ''
103
+ end
104
+ end
105
+
106
+ end
107
+
108
+ context 'with connection on a local node' do
109
+
110
+ it 'returns the correct sudo prefix' do
111
+ with_test_platform({ nodes: { 'node' => { meta: { local_node: true } } } }) do
112
+ with_cmd_runner_mocked [
113
+ ['whoami', proc { [0, 'test_user', ''] }]
114
+ ] do
115
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
116
+ expect(test_actions_executor.sudo_prefix('node')).to eq 'sudo -u root '
117
+ end
118
+ end
119
+ end
120
+
121
+ it 'returns the correct sudo prefix with env forwarding' do
122
+ with_test_platform({ nodes: { 'node' => { meta: { local_node: true } } } }) do
123
+ with_cmd_runner_mocked [
124
+ ['whoami', proc { [0, 'test_user', ''] }]
125
+ ] do
126
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
127
+ expect(test_actions_executor.sudo_prefix('node', forward_env: true)).to eq 'sudo -u root -E '
128
+ end
129
+ end
130
+ end
131
+
132
+ it 'returns the correct sudo prefix when connecting as root' do
133
+ with_test_platform({ nodes: { 'node' => { meta: { local_node: true } } } }) do
134
+ with_cmd_runner_mocked [
135
+ ['whoami', proc { [0, 'root', ''] }]
136
+ ] do
137
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
138
+ expect(test_actions_executor.sudo_prefix('node')).to eq ''
139
+ end
140
+ end
141
+ end
142
+
143
+ it 'returns the correct sudo prefix with a different sudo' do
144
+ with_test_platform(
145
+ { nodes: { 'node' => { meta: { local_node: true } } } },
146
+ additional_config: <<~'EO_CONFIG'
147
+ sudo_for { |user| "other_sudo --user #{user}" }
148
+ EO_CONFIG
149
+ ) do
150
+ with_cmd_runner_mocked [
151
+ ['whoami', proc { [0, 'test_user', ''] }]
152
+ ] do
153
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
154
+ expect(test_actions_executor.sudo_prefix('node')).to eq 'other_sudo --user root '
155
+ end
156
+ end
157
+ end
158
+
159
+ it 'returns the correct sudo prefix with a different sudo and env forwarding' do
160
+ with_test_platform(
161
+ { nodes: { 'node' => { meta: { local_node: true } } } },
162
+ additional_config: <<~'EO_CONFIG'
163
+ sudo_for { |user| "other_sudo --user #{user}" }
164
+ EO_CONFIG
165
+ ) do
166
+ with_cmd_runner_mocked [
167
+ ['whoami', proc { [0, 'test_user', ''] }]
168
+ ] do
169
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
170
+ expect(test_actions_executor.sudo_prefix('node', forward_env: true)).to eq 'other_sudo --user root -E '
171
+ end
172
+ end
173
+ end
174
+
175
+ it 'returns the correct sudo prefix with a different sudo when connecting as root' do
176
+ with_test_platform(
177
+ { nodes: { 'node' => { meta: { local_node: true } } } },
178
+ additional_config: <<~'EO_CONFIG'
179
+ sudo_for { |user| "other_sudo --user #{user}" }
180
+ EO_CONFIG
181
+ ) do
182
+ with_cmd_runner_mocked [
183
+ ['whoami', proc { [0, 'root', ''] }]
184
+ ] do
185
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
186
+ expect(test_actions_executor.sudo_prefix('node')).to eq ''
187
+ end
188
+ end
189
+ end
190
+
191
+ end
192
+
193
+ end
194
+
195
+ end
@@ -129,6 +129,127 @@ describe HybridPlatformsConductor::Deployer do
129
129
  end
130
130
  end
131
131
 
132
+ it 'returns actions to save logs on a local node' do
133
+ with_test_platform({ nodes: { 'node' => { meta: { local_node: true }, services: %w[service1 service2] } } }, additional_config: 'send_logs_to :remote_fs') do
134
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
135
+ expect_services_handler_to_deploy('node' => %w[service1 service2])
136
+ expect_actions_executor_runs [
137
+ # First run, we expect the mutex to be setup, and the deployment actions to be run
138
+ proc do |actions_per_nodes|
139
+ expect_actions_to_deploy_on(
140
+ actions_per_nodes,
141
+ 'node',
142
+ mocked_result: { 'node' => [0, 'Deploy successful stdout', 'Deploy successful stderr'] }
143
+ )
144
+ end,
145
+ # Second run, we expect the mutex to be released
146
+ proc { |actions_per_nodes| expect_actions_to_unlock(actions_per_nodes, 'node') },
147
+ # Third run, we expect logs to be uploaded on the node
148
+ proc do |actions_per_nodes|
149
+ expect(actions_per_nodes['node'].size).to eq 3
150
+ expect(actions_per_nodes['node'][0].keys.sort).to eq %i[ruby remote_bash].sort
151
+ expect(actions_per_nodes['node'][0][:remote_bash]).to eq 'sudo -u root mkdir -p /var/log/deployments && sudo -u root chmod 600 /var/log/deployments'
152
+ expect(actions_per_nodes['node'][1].keys.sort).to eq %i[scp].sort
153
+ expect(actions_per_nodes['node'][1][:scp].delete(:sudo)).to eq true
154
+ expect(actions_per_nodes['node'][1][:scp].delete(:owner)).to eq 'root'
155
+ expect(actions_per_nodes['node'][1][:scp].delete(:group)).to eq 'root'
156
+ expect(actions_per_nodes['node'][1][:scp].size).to eq 1
157
+ tmp_log_file = actions_per_nodes['node'][1][:scp].first[0]
158
+ expect(actions_per_nodes['node'][1][:scp].first[1]).to eq '/var/log/deployments'
159
+ expect(actions_per_nodes['node'][2].keys.sort).to eq %i[ruby remote_bash].sort
160
+ expect(actions_per_nodes['node'][2][:remote_bash]).to eq "sudo -u root chmod 600 /var/log/deployments/#{File.basename(tmp_log_file)}"
161
+ # Call the Ruby codes to be tested
162
+ actions_per_nodes['node'][0][:ruby].call
163
+ expect(File.exist?(tmp_log_file)).to eq true
164
+ file_content_regexp = Regexp.new <<~EOREGEXP
165
+ repo_name_0: platform
166
+ commit_id_0: 123456
167
+ commit_message_0: Test commit for node: service1, service2
168
+ date: \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}
169
+ user: test_user
170
+ debug: No
171
+ services: service1, service2
172
+ exit_status: 0
173
+ ===== STDOUT =====
174
+ Deploy successful stdout
175
+ ===== STDERR =====
176
+ Deploy successful stderr
177
+ EOREGEXP
178
+ expect(File.read(tmp_log_file)).to match file_content_regexp
179
+ actions_per_nodes['node'][2][:ruby].call
180
+ # Check temporary log file gets deleted for security reasons
181
+ expect(File.exist?(tmp_log_file)).to eq false
182
+ end
183
+ ]
184
+ with_cmd_runner_mocked [
185
+ ['whoami', proc { [0, 'test_user', ''] }]
186
+ ] do
187
+ expect(test_deployer.deploy_on('node')).to eq('node' => [0, 'Deploy successful stdout', 'Deploy successful stderr'])
188
+ end
189
+ end
190
+ end
191
+
192
+ it 'returns actions to save logs on a local node as root' do
193
+ with_test_platform({ nodes: { 'node' => { meta: { local_node: true }, services: %w[service1 service2] } } }, additional_config: 'send_logs_to :remote_fs') do
194
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
195
+ expect_services_handler_to_deploy('node' => %w[service1 service2])
196
+ expect_actions_executor_runs [
197
+ # First run, we expect the mutex to be setup, and the deployment actions to be run
198
+ proc do |actions_per_nodes|
199
+ expect_actions_to_deploy_on(
200
+ actions_per_nodes,
201
+ 'node',
202
+ sudo: nil,
203
+ mocked_result: { 'node' => [0, 'Deploy successful stdout', 'Deploy successful stderr'] }
204
+ )
205
+ end,
206
+ # Second run, we expect the mutex to be released
207
+ proc { |actions_per_nodes| expect_actions_to_unlock(actions_per_nodes, 'node', sudo: nil) },
208
+ # Third run, we expect logs to be uploaded on the node
209
+ proc do |actions_per_nodes|
210
+ expect(actions_per_nodes['node'].size).to eq 3
211
+ expect(actions_per_nodes['node'][0].keys.sort).to eq %i[ruby remote_bash].sort
212
+ expect(actions_per_nodes['node'][0][:remote_bash]).to eq 'mkdir -p /var/log/deployments && chmod 600 /var/log/deployments'
213
+ expect(actions_per_nodes['node'][1].keys.sort).to eq %i[scp].sort
214
+ expect(actions_per_nodes['node'][1][:scp].delete(:sudo)).to eq false
215
+ expect(actions_per_nodes['node'][1][:scp].delete(:owner)).to eq 'root'
216
+ expect(actions_per_nodes['node'][1][:scp].delete(:group)).to eq 'root'
217
+ expect(actions_per_nodes['node'][1][:scp].size).to eq 1
218
+ tmp_log_file = actions_per_nodes['node'][1][:scp].first[0]
219
+ expect(actions_per_nodes['node'][1][:scp].first[1]).to eq '/var/log/deployments'
220
+ expect(actions_per_nodes['node'][2].keys.sort).to eq %i[ruby remote_bash].sort
221
+ expect(actions_per_nodes['node'][2][:remote_bash]).to eq "chmod 600 /var/log/deployments/#{File.basename(tmp_log_file)}"
222
+ # Call the Ruby codes to be tested
223
+ actions_per_nodes['node'][0][:ruby].call
224
+ expect(File.exist?(tmp_log_file)).to eq true
225
+ file_content_regexp = Regexp.new <<~EOREGEXP
226
+ repo_name_0: platform
227
+ commit_id_0: 123456
228
+ commit_message_0: Test commit for node: service1, service2
229
+ date: \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}
230
+ user: test_user
231
+ debug: No
232
+ services: service1, service2
233
+ exit_status: 0
234
+ ===== STDOUT =====
235
+ Deploy successful stdout
236
+ ===== STDERR =====
237
+ Deploy successful stderr
238
+ EOREGEXP
239
+ expect(File.read(tmp_log_file)).to match file_content_regexp
240
+ actions_per_nodes['node'][2][:ruby].call
241
+ # Check temporary log file gets deleted for security reasons
242
+ expect(File.exist?(tmp_log_file)).to eq false
243
+ end
244
+ ]
245
+ with_cmd_runner_mocked [
246
+ ['whoami', proc { [0, 'root', ''] }]
247
+ ] do
248
+ expect(test_deployer.deploy_on('node')).to eq('node' => [0, 'Deploy successful stdout', 'Deploy successful stderr'])
249
+ end
250
+ end
251
+ end
252
+
132
253
  it 'reads logs' do
133
254
  with_test_platform_for_remote_fs do
134
255
  expect_actions_executor_runs [
@@ -216,6 +337,100 @@ describe HybridPlatformsConductor::Deployer do
216
337
  end
217
338
  end
218
339
 
340
+ it 'reads logs on a local node' do
341
+ with_test_platform({ nodes: { 'node' => { meta: { local_node: true }, services: %w[service1 service2] } } }, additional_config: 'send_logs_to :remote_fs') do
342
+ expect_actions_executor_runs [
343
+ # Expect the actions to get log files
344
+ proc do |actions_per_nodes|
345
+ expect(actions_per_nodes).to eq('node' => [{ remote_bash: 'sudo -u root cat /var/log/deployments/`sudo -u root ls -t /var/log/deployments/ | head -1`' }])
346
+ { 'node' => [0, <<~EO_STDOUT, ''] }
347
+ repo_name_0: platform
348
+ commit_id_0: 123456
349
+ commit_message_0: Test commit for node: service1, service2
350
+ diff_files_0: file1, file2, file3
351
+ date: 2017-11-23 18:43:01
352
+ user: test_user
353
+ debug: Yes
354
+ services: service1, service2, service3
355
+ exit_status: 0
356
+ ===== STDOUT =====
357
+ Deploy successful stdout
358
+ ===== STDERR =====
359
+ Deploy successful stderr
360
+ EO_STDOUT
361
+ end
362
+ ]
363
+ with_cmd_runner_mocked [
364
+ ['whoami', proc { [0, 'test_user', ''] }]
365
+ ] do
366
+ expect(test_deployer.deployment_info_from('node')).to eq(
367
+ 'node' => {
368
+ deployment_info: {
369
+ repo_name_0: 'platform',
370
+ commit_id_0: '123456',
371
+ commit_message_0: 'Test commit for node: service1, service2',
372
+ diff_files_0: %w[file1 file2 file3],
373
+ date: Time.parse('2017-11-23 18:43:01 UTC'),
374
+ debug: true,
375
+ user: 'test_user'
376
+ },
377
+ exit_status: 0,
378
+ services: %w[service1 service2 service3],
379
+ stderr: 'Deploy successful stderr',
380
+ stdout: 'Deploy successful stdout'
381
+ }
382
+ )
383
+ end
384
+ end
385
+ end
386
+
387
+ it 'reads logs on a local node as root' do
388
+ with_test_platform({ nodes: { 'node' => { meta: { local_node: true }, services: %w[service1 service2] } } }, additional_config: 'send_logs_to :remote_fs') do
389
+ expect_actions_executor_runs [
390
+ # Expect the actions to get log files
391
+ proc do |actions_per_nodes|
392
+ expect(actions_per_nodes).to eq('node' => [{ remote_bash: 'cat /var/log/deployments/`ls -t /var/log/deployments/ | head -1`' }])
393
+ { 'node' => [0, <<~EO_STDOUT, ''] }
394
+ repo_name_0: platform
395
+ commit_id_0: 123456
396
+ commit_message_0: Test commit for node: service1, service2
397
+ diff_files_0: file1, file2, file3
398
+ date: 2017-11-23 18:43:01
399
+ user: test_user
400
+ debug: Yes
401
+ services: service1, service2, service3
402
+ exit_status: 0
403
+ ===== STDOUT =====
404
+ Deploy successful stdout
405
+ ===== STDERR =====
406
+ Deploy successful stderr
407
+ EO_STDOUT
408
+ end
409
+ ]
410
+ with_cmd_runner_mocked [
411
+ ['whoami', proc { [0, 'root', ''] }]
412
+ ] do
413
+ expect(test_deployer.deployment_info_from('node')).to eq(
414
+ 'node' => {
415
+ deployment_info: {
416
+ repo_name_0: 'platform',
417
+ commit_id_0: '123456',
418
+ commit_message_0: 'Test commit for node: service1, service2',
419
+ diff_files_0: %w[file1 file2 file3],
420
+ date: Time.parse('2017-11-23 18:43:01 UTC'),
421
+ debug: true,
422
+ user: 'test_user'
423
+ },
424
+ exit_status: 0,
425
+ services: %w[service1 service2 service3],
426
+ stderr: 'Deploy successful stderr',
427
+ stdout: 'Deploy successful stdout'
428
+ }
429
+ )
430
+ end
431
+ end
432
+ end
433
+
219
434
  end
220
435
 
221
436
  end
@@ -256,6 +256,44 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
256
256
 
257
257
  end
258
258
 
259
+ context 'with a platform having 1 local node' do
260
+
261
+ it 'returns actions to deploy on this node' do
262
+ with_serverless_chef_platforms('1_local_node') do |platform, repository|
263
+ mock_package(repository)
264
+ platform.prepare_for_deploy(
265
+ services: { 'node' => %w[test_policy] },
266
+ secrets: {},
267
+ local_environment: false,
268
+ why_run: false
269
+ )
270
+ with_cmd_runner_mocked [
271
+ ['whoami', proc { [0, 'test_user', ''] }]
272
+ ] do
273
+ expect(platform.actions_to_deploy_on('node', 'test_policy', use_why_run: false)).to eq expected_actions_to_deploy_chef(repository)
274
+ end
275
+ end
276
+ end
277
+
278
+ it 'returns actions to deploy on this node as root' do
279
+ with_serverless_chef_platforms('1_local_node') do |platform, repository|
280
+ mock_package(repository)
281
+ platform.prepare_for_deploy(
282
+ services: { 'node' => %w[test_policy] },
283
+ secrets: {},
284
+ local_environment: false,
285
+ why_run: false
286
+ )
287
+ with_cmd_runner_mocked [
288
+ ['whoami', proc { [0, 'root', ''] }]
289
+ ] do
290
+ expect(platform.actions_to_deploy_on('node', 'test_policy', use_why_run: false)).to eq expected_actions_to_deploy_chef(repository, sudo: '')
291
+ end
292
+ end
293
+ end
294
+
295
+ end
296
+
259
297
  context 'with a platform having several nodes' do
260
298
 
261
299
  it 'deploys services declared on 1 node on another node if asked' do
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "node",
3
+ "normal": {
4
+ "description": "Single test node",
5
+ "image": "debian_9",
6
+ "private_ips": ["172.16.0.1"],
7
+ "local_node": true,
8
+ "property_1": {
9
+ "property_11": "value11"
10
+ },
11
+ "property_2": "value2"
12
+ },
13
+ "policy_name": "test_policy",
14
+ "policy_group": "test_group"
15
+ }
@@ -0,0 +1,3 @@
1
+ name File.basename(__FILE__, '.rb')
2
+ default_source :supermarket
3
+ run_list 'recipe[test_cookbook]'
@@ -46,6 +46,30 @@ shared_examples 'a deployer' do
46
46
  end
47
47
  end
48
48
 
49
+ it 'deploys on 1 local node' do
50
+ with_platform_to_deploy(nodes_info: { nodes: { 'node' => { meta: { local_node: true }, services: %w[service] } } }) do
51
+ # Make sure the ssh_user is ignored in this case
52
+ test_actions_executor.connector(:ssh).ssh_user = 'root'
53
+ with_cmd_runner_mocked [
54
+ ['whoami', proc { [0, 'test_user', ''] }]
55
+ ] do
56
+ expect(test_deployer.deploy_on('node')).to eq('node' => expected_deploy_result)
57
+ end
58
+ end
59
+ end
60
+
61
+ it 'deploys on 1 local node as root' do
62
+ with_platform_to_deploy(nodes_info: { nodes: { 'node' => { meta: { local_node: true }, services: %w[service] } } }, expect_sudo: nil) do
63
+ # Make sure the ssh_user is ignored in this case
64
+ test_actions_executor.connector(:ssh).ssh_user = 'test_user'
65
+ with_cmd_runner_mocked [
66
+ ['whoami', proc { [0, 'root', ''] }]
67
+ ] do
68
+ expect(test_deployer.deploy_on('node')).to eq('node' => expected_deploy_result)
69
+ end
70
+ end
71
+ end
72
+
49
73
  it 'deploys on 1 node using 1 secret' do
50
74
  with_platform_to_deploy(expect_secrets: { 'secret1' => 'password1' }) do
51
75
  test_deployer.override_secrets('secret1' => 'password1')
@@ -137,6 +161,61 @@ shared_examples 'a deployer' do
137
161
  end
138
162
  end
139
163
 
164
+ it 'deploys on 1 local node in local environment with certificates to install using hpc_certificates on Debian' do
165
+ with_certs_dir do |certs_dir|
166
+ with_platform_to_deploy(
167
+ nodes_info: { nodes: { 'node' => { meta: { local_node: true, image: 'debian_9' }, services: %w[service] } } },
168
+ expect_local_environment: true,
169
+ expect_additional_actions: [
170
+ { remote_bash: 'sudo -u root apt update && sudo -u root apt install -y ca-certificates' },
171
+ {
172
+ remote_bash: 'sudo -u root update-ca-certificates',
173
+ scp: {
174
+ certs_dir => '/usr/local/share/ca-certificates',
175
+ :sudo => true
176
+ }
177
+ }
178
+ ]
179
+ ) do
180
+ ENV['hpc_certificates'] = certs_dir
181
+ test_deployer.local_environment = true
182
+ with_cmd_runner_mocked [
183
+ ['whoami', proc { [0, 'test_user', ''] }]
184
+ ] do
185
+ expect(test_deployer.deploy_on('node')).to eq('node' => expected_deploy_result)
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+ it 'deploys on 1 local node in local environment with certificates to install using hpc_certificates on Debian as root' do
192
+ with_certs_dir do |certs_dir|
193
+ with_platform_to_deploy(
194
+ nodes_info: { nodes: { 'node' => { meta: { local_node: true, image: 'debian_9' }, services: %w[service] } } },
195
+ expect_sudo: nil,
196
+ expect_local_environment: true,
197
+ expect_additional_actions: [
198
+ { remote_bash: 'apt update && apt install -y ca-certificates' },
199
+ {
200
+ remote_bash: 'update-ca-certificates',
201
+ scp: {
202
+ certs_dir => '/usr/local/share/ca-certificates',
203
+ :sudo => false
204
+ }
205
+ }
206
+ ]
207
+ ) do
208
+ ENV['hpc_certificates'] = certs_dir
209
+ test_deployer.local_environment = true
210
+ with_cmd_runner_mocked [
211
+ ['whoami', proc { [0, 'root', ''] }]
212
+ ] do
213
+ expect(test_deployer.deploy_on('node')).to eq('node' => expected_deploy_result)
214
+ end
215
+ end
216
+ end
217
+ end
218
+
140
219
  it 'deploys on 1 node with certificates to install using hpc_certificates on CentOS' do
141
220
  with_certs_dir do |certs_dir|
142
221
  with_platform_to_deploy(
@@ -212,6 +291,61 @@ shared_examples 'a deployer' do
212
291
  end
213
292
  end
214
293
 
294
+ it 'deploys on 1 local node with certificates to install using hpc_certificates on CentOS' do
295
+ with_certs_dir do |certs_dir|
296
+ with_platform_to_deploy(
297
+ nodes_info: { nodes: { 'node' => { meta: { local_node: true, image: 'centos_7' }, services: %w[service] } } },
298
+ expect_local_environment: true,
299
+ expect_additional_actions: [
300
+ { remote_bash: 'sudo -u root yum install -y ca-certificates' },
301
+ {
302
+ remote_bash: ['sudo -u root update-ca-trust enable', 'sudo -u root update-ca-trust extract'],
303
+ scp: {
304
+ "#{certs_dir}/test_cert.crt" => '/etc/pki/ca-trust/source/anchors',
305
+ :sudo => true
306
+ }
307
+ }
308
+ ]
309
+ ) do
310
+ ENV['hpc_certificates'] = certs_dir
311
+ test_deployer.local_environment = true
312
+ with_cmd_runner_mocked [
313
+ ['whoami', proc { [0, 'test_user', ''] }]
314
+ ] do
315
+ expect(test_deployer.deploy_on('node')).to eq('node' => expected_deploy_result)
316
+ end
317
+ end
318
+ end
319
+ end
320
+
321
+ it 'deploys on 1 local node with certificates to install using hpc_certificates on CentOS as root' do
322
+ with_certs_dir do |certs_dir|
323
+ with_platform_to_deploy(
324
+ nodes_info: { nodes: { 'node' => { meta: { local_node: true, image: 'centos_7' }, services: %w[service] } } },
325
+ expect_sudo: nil,
326
+ expect_local_environment: true,
327
+ expect_additional_actions: [
328
+ { remote_bash: 'yum install -y ca-certificates' },
329
+ {
330
+ remote_bash: ['update-ca-trust enable', 'update-ca-trust extract'],
331
+ scp: {
332
+ "#{certs_dir}/test_cert.crt" => '/etc/pki/ca-trust/source/anchors',
333
+ :sudo => false
334
+ }
335
+ }
336
+ ]
337
+ ) do
338
+ ENV['hpc_certificates'] = certs_dir
339
+ test_deployer.local_environment = true
340
+ with_cmd_runner_mocked [
341
+ ['whoami', proc { [0, 'root', ''] }]
342
+ ] do
343
+ expect(test_deployer.deploy_on('node')).to eq('node' => expected_deploy_result)
344
+ end
345
+ end
346
+ end
347
+ end
348
+
215
349
  it 'deploys on several nodes' do
216
350
  with_platform_to_deploy(
217
351
  nodes_info: {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hybrid_platforms_conductor
3
3
  version: !ruby/object:Gem::Version
4
- version: 33.5.0
4
+ version: 33.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Muriel Salvan
@@ -866,6 +866,7 @@ files:
866
866
  - spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/global_helpers_spec.rb
867
867
  - spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/node_helpers_spec.rb
868
868
  - spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/remote_actions_spec.rb
869
+ - spec/hybrid_platforms_conductor_test/api/actions_executor/helpers_spec.rb
869
870
  - spec/hybrid_platforms_conductor_test/api/actions_executor/logging_spec.rb
870
871
  - spec/hybrid_platforms_conductor_test/api/actions_executor/parallel_spec.rb
871
872
  - spec/hybrid_platforms_conductor_test/api/actions_executor/timeout_spec.rb
@@ -982,6 +983,9 @@ files:
982
983
  - spec/hybrid_platforms_conductor_test/platform_handler_plugins/test_2.rb
983
984
  - spec/hybrid_platforms_conductor_test/report_plugin.rb
984
985
  - spec/hybrid_platforms_conductor_test/rubocop_spec.rb
986
+ - spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/chef_versions.yml
987
+ - spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/nodes/node.json
988
+ - spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/policyfiles/test_policy.rb
985
989
  - spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_node/chef_versions.yml
986
990
  - spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_node/nodes/node.json
987
991
  - spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_node/policyfiles/test_policy.rb