hybrid_platforms_conductor 33.4.0 → 33.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/README.md +5 -5
  4. data/docs/config_dsl.md +7 -5
  5. data/docs/plugins/cmdb/host_keys.md +3 -1
  6. data/docs/plugins/connector/ssh.md +1 -0
  7. data/lib/hybrid_platforms_conductor/actions_executor.rb +29 -1
  8. data/lib/hybrid_platforms_conductor/bitbucket.rb +2 -2
  9. data/lib/hybrid_platforms_conductor/cmd_runner.rb +4 -4
  10. data/lib/hybrid_platforms_conductor/config.rb +2 -0
  11. data/lib/hybrid_platforms_conductor/confluence.rb +2 -2
  12. data/lib/hybrid_platforms_conductor/connector.rb +5 -2
  13. data/lib/hybrid_platforms_conductor/credentials.rb +20 -12
  14. data/lib/hybrid_platforms_conductor/deployer.rb +5 -7
  15. data/lib/hybrid_platforms_conductor/github.rb +1 -1
  16. data/lib/hybrid_platforms_conductor/hpc_plugins/action/bash.rb +1 -1
  17. data/lib/hybrid_platforms_conductor/hpc_plugins/action/remote_bash.rb +27 -17
  18. data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/host_keys.rb +13 -12
  19. data/lib/hybrid_platforms_conductor/hpc_plugins/connector/local.rb +6 -4
  20. data/lib/hybrid_platforms_conductor/hpc_plugins/connector/my_connector.rb.sample +1 -1
  21. data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +37 -25
  22. data/lib/hybrid_platforms_conductor/hpc_plugins/log/remote_fs.rb +5 -6
  23. data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb +23 -14
  24. data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/docker.rb +1 -1
  25. data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +3 -2
  26. data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/keepass.rb +1 -1
  27. data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_deploy_and_idempotence.rb +17 -3
  28. data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_removes_root_access.rb +30 -10
  29. data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system.rb +1 -1
  30. data/lib/hybrid_platforms_conductor/hpc_plugins/test/hostname.rb +1 -2
  31. data/lib/hybrid_platforms_conductor/hpc_plugins/test/idempotence.rb +1 -1
  32. data/lib/hybrid_platforms_conductor/hpc_plugins/test/ip.rb +1 -2
  33. data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_conf.rb +1 -1
  34. data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_masters_ok.rb +2 -2
  35. data/lib/hybrid_platforms_conductor/hpc_plugins/test/local_users.rb +1 -2
  36. data/lib/hybrid_platforms_conductor/hpc_plugins/test/mounts.rb +1 -2
  37. data/lib/hybrid_platforms_conductor/hpc_plugins/test/orphan_files.rb +1 -2
  38. data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre.rb +1 -1
  39. data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +1 -2
  40. data/lib/hybrid_platforms_conductor/logger_helpers.rb +17 -0
  41. data/lib/hybrid_platforms_conductor/test.rb +21 -7
  42. data/lib/hybrid_platforms_conductor/tests_runner.rb +7 -6
  43. data/lib/hybrid_platforms_conductor/thycotic.rb +2 -2
  44. data/lib/hybrid_platforms_conductor/version.rb +1 -1
  45. data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/bash_spec.rb +15 -0
  46. data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/remote_bash_spec.rb +32 -0
  47. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/local/remote_actions_spec.rb +87 -0
  48. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb +30 -0
  49. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/global_helpers_spec.rb +10 -0
  50. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/remote_actions_spec.rb +38 -0
  51. data/spec/hybrid_platforms_conductor_test/api/actions_executor/helpers_spec.rb +195 -0
  52. data/spec/hybrid_platforms_conductor_test/api/cmd_runner_spec.rb +14 -0
  53. data/spec/hybrid_platforms_conductor_test/api/config_spec.rb +11 -0
  54. data/spec/hybrid_platforms_conductor_test/api/credentials_spec.rb +8 -4
  55. data/spec/hybrid_platforms_conductor_test/api/deployer/log_plugins/remote_fs_spec.rb +215 -0
  56. data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/host_keys_spec.rb +49 -10
  57. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/services_deployment_spec.rb +64 -16
  58. data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +5 -3
  59. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/chef_versions.yml +3 -0
  60. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/nodes/node.json +15 -0
  61. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/policyfiles/test_policy.rb +3 -0
  62. data/spec/hybrid_platforms_conductor_test/shared_examples/deployer.rb +134 -0
  63. data/spec/hybrid_platforms_conductor_test/test_connector.rb +2 -2
  64. metadata +20 -2
@@ -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
  }
@@ -27,7 +27,7 @@ module HybridPlatformsConductor
27
27
  # System is booting up. See pam_nologin(8)
28
28
  # Authentication failed.
29
29
  instance.stop
30
- instance.with_running_instance(port: 22) do
30
+ instance.with_running_instance(port: @nodes_handler.get_ssh_port_of(@node) || 22) do
31
31
  # Now that the node has been deployed, use the a_testadmin user for the check-node (as root has no more access)
32
32
  deployer.instance_variable_get(:@actions_executor).connector(:ssh).ssh_user = 'a_testadmin'
33
33
  deployer.instance_variable_get(:@actions_executor).connector(:ssh).passwords.delete(@node)
@@ -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
@@ -26,7 +26,7 @@ module HybridPlatformsConductor
26
26
  else
27
27
  with_credentials_for(:jenkins_ci, resource: repo_info[:jenkins_ci_url]) do |jenkins_user, jenkins_password|
28
28
  # Get its config
29
- doc = Nokogiri::XML(URI.parse("#{repo_info[:jenkins_ci_url]}/config.xml").open(http_basic_authentication: [jenkins_user, jenkins_password]).read)
29
+ doc = Nokogiri::XML(URI.parse("#{repo_info[:jenkins_ci_url]}/config.xml").open(http_basic_authentication: [jenkins_user, jenkins_password&.to_unprotected]).read)
30
30
  # Check that this job builds the correct Bitbucket repository
31
31
  assert_equal(
32
32
  doc.xpath('/org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject/sources/data/jenkins.branch.BranchSource/source/serverUrl').text,
@@ -34,10 +34,10 @@ module HybridPlatformsConductor
34
34
  master_info_url = "#{repo_info[:jenkins_ci_url]}/job/master/api/json"
35
35
  with_credentials_for(:jenkins_ci, resource: master_info_url) do |jenkins_user, jenkins_password|
36
36
  # Get the master branch info from the API
37
- master_info = JSON.parse(URI.parse(master_info_url).open(http_basic_authentication: [jenkins_user, jenkins_password]).read)
37
+ master_info = JSON.parse(URI.parse(master_info_url).open(http_basic_authentication: [jenkins_user, jenkins_password&.to_unprotected]).read)
38
38
  # Get the last build's URL
39
39
  last_build_info_url = "#{master_info['lastBuild']['url']}/api/json"
40
- last_build_info = JSON.parse(URI.parse(last_build_info_url).open(http_basic_authentication: [jenkins_user, jenkins_password]).read)
40
+ last_build_info = JSON.parse(URI.parse(last_build_info_url).open(http_basic_authentication: [jenkins_user, jenkins_password&.to_unprotected]).read)
41
41
  log_debug "Build info for #{master_info_url}:\n#{JSON.pretty_generate(last_build_info)}"
42
42
  error "Last build for job #{repo_info[:project]}/#{repo_info[:name]} is in status #{last_build_info['result']}: #{master_info['lastBuild']['url']}" unless SUCCESS_STATUSES.include?(last_build_info['result'])
43
43
  rescue
@@ -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
@@ -1,6 +1,23 @@
1
1
  require 'colorize'
2
2
  require 'logger'
3
3
  require 'ruby-progressbar'
4
+ require 'secret_string'
5
+
6
+ # Add colorization methods to SecretString, but always directed to the silenced string as we NEVER want to modiy/clone a secret
7
+ class SecretString
8
+
9
+ extend Colorize::ClassMethods
10
+
11
+ def_delegators :@silenced_str, *%i[
12
+ colorize
13
+ uncolorize
14
+ colorized?
15
+ ]
16
+
17
+ color_methods
18
+ modes_methods
19
+
20
+ end
4
21
 
5
22
  module HybridPlatformsConductor
6
23
 
@@ -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,
@@ -33,7 +33,7 @@ module HybridPlatformsConductor
33
33
  # Parameters::
34
34
  # * *url* (String): URL of the Thycotic Secret Server
35
35
  # * *user* (String): User name to be used to connect to Thycotic
36
- # * *password* (String): Password to be used to connect to Thycotic
36
+ # * *password* (SecretString): Password to be used to connect to Thycotic
37
37
  # * *domain* (String): Domain to use for authentication to Thycotic [default: ENV['hpc_domain_for_thycotic']]
38
38
  # * *logger* (Logger): Logger to be used [default: Logger.new(STDOUT)]
39
39
  # * *logger_stderr* (Logger): Logger to be used for stderr [default: Logger.new(STDERR)]
@@ -57,7 +57,7 @@ module HybridPlatformsConductor
57
57
  :authenticate,
58
58
  message: {
59
59
  username: user,
60
- password: password,
60
+ password: password&.to_unprotected,
61
61
  domain: domain
62
62
  }
63
63
  ).to_hash.dig(:authenticate_response, :authenticate_result, :token)
@@ -1,5 +1,5 @@
1
1
  module HybridPlatformsConductor
2
2
 
3
- VERSION = '33.4.0'
3
+ VERSION = '33.7.1'
4
4
 
5
5
  end
@@ -17,6 +17,21 @@ describe HybridPlatformsConductor::ActionsExecutor do
17
17
  end
18
18
  end
19
19
 
20
+ it 'executes local Bash code from a SecretString' do
21
+ with_test_platform_for_action_plugins do |repository|
22
+ expect(
23
+ test_actions_executor.execute_actions(
24
+ {
25
+ 'node' => {
26
+ bash: SecretString.new("echo TestContent >#{repository}/test_file ; echo TestStdout ; echo TestStderr 1>&2", silenced_str: '__INVALID_BASH__')
27
+ }
28
+ }
29
+ )['node']
30
+ ).to eq [0, "TestStdout\n", "TestStderr\n"]
31
+ expect(File.read("#{repository}/test_file")).to eq "TestContent\n"
32
+ end
33
+ end
34
+
20
35
  it 'executes local Bash code with timeout' do
21
36
  with_test_platform_for_action_plugins do
22
37
  expect(test_actions_executor.execute_actions(
@@ -13,6 +13,17 @@ describe HybridPlatformsConductor::ActionsExecutor do
13
13
  end
14
14
  end
15
15
 
16
+ it 'executes remote Bash code from a SecretString' do
17
+ with_test_platform_for_action_plugins do
18
+ test_actions_executor.execute_actions({ 'node' => { remote_bash: SecretString.new('remote_bash_cmd.bash', silenced_str: '__INVALID_BASH__') } })
19
+ expect(test_actions_executor.connector(:test_connector).calls).to eq [
20
+ [:connectable_nodes_from, ['node']],
21
+ [:with_connection_to, ['node'], { no_exception: true }],
22
+ [:remote_bash, 'remote_bash_cmd.bash']
23
+ ]
24
+ end
25
+ end
26
+
16
27
  it 'executes remote Bash code with timeout' do
17
28
  with_test_platform_for_action_plugins do
18
29
  test_actions_executor.connector(:test_connector).remote_bash_code = proc do |_stdout, _stderr, connector|
@@ -124,6 +135,27 @@ describe HybridPlatformsConductor::ActionsExecutor do
124
135
  end
125
136
  end
126
137
 
138
+ it 'executes remote Bash code with environment variables set using SecretStrings' do
139
+ with_test_platform_for_action_plugins do
140
+ test_actions_executor.execute_actions(
141
+ {
142
+ 'node' => { remote_bash: {
143
+ commands: 'bash_cmd.bash',
144
+ env: {
145
+ 'var1' => SecretString.new('value1', silenced_str: 'SILENCED_VALUE'),
146
+ 'var2' => 'value2'
147
+ }
148
+ } }
149
+ }
150
+ )
151
+ expect(test_actions_executor.connector(:test_connector).calls).to eq [
152
+ [:connectable_nodes_from, ['node']],
153
+ [:with_connection_to, ['node'], { no_exception: true }],
154
+ [:remote_bash, "export var1='value1'\nexport var2='value2'\nbash_cmd.bash"]
155
+ ]
156
+ end
157
+ end
158
+
127
159
  end
128
160
 
129
161
  end
@@ -54,6 +54,15 @@ describe HybridPlatformsConductor::ActionsExecutor do
54
54
  end
55
55
  end
56
56
 
57
+ it 'executes bash commands remotely from a SecretString' do
58
+ with_test_platform_for_remote_testing(
59
+ expected_cmds: [['cd /tmp/hpc_local_workspaces/node ; bash_cmd.bash', proc { [0, 'Bash commands executed on node', ''] }]],
60
+ expected_stdout: 'Bash commands executed on node'
61
+ ) do
62
+ test_connector.remote_bash(SecretString.new('bash_cmd.bash', silenced_str: '__INVALID_BASH__'))
63
+ end
64
+ end
65
+
57
66
  it 'executes bash commands remotely with timeout' do
58
67
  with_test_platform_for_remote_testing(
59
68
  expected_cmds: [
@@ -98,6 +107,10 @@ describe HybridPlatformsConductor::ActionsExecutor do
98
107
  it 'copies files remotely with sudo' do
99
108
  with_test_platform_for_remote_testing(
100
109
  expected_cmds: [
110
+ [
111
+ 'whoami',
112
+ proc { [0, 'test_user', ''] }
113
+ ],
101
114
  [
102
115
  'sudo -u root cp -r "/path/to/src.file" "/remote_path/to/dst.dir"',
103
116
  proc { [0, '', ''] }
@@ -108,9 +121,27 @@ describe HybridPlatformsConductor::ActionsExecutor do
108
121
  end
109
122
  end
110
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
+
111
138
  it 'copies files remotely with a different sudo' do
112
139
  with_test_platform_for_remote_testing(
113
140
  expected_cmds: [
141
+ [
142
+ 'whoami',
143
+ proc { [0, 'test_user', ''] }
144
+ ],
114
145
  [
115
146
  'other_sudo --user root cp -r "/path/to/src.file" "/remote_path/to/dst.dir"',
116
147
  proc { [0, '', ''] }
@@ -124,6 +155,23 @@ describe HybridPlatformsConductor::ActionsExecutor do
124
155
  end
125
156
  end
126
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
+
127
175
  it 'copies files remotely with timeout' do
128
176
  with_test_platform_for_remote_testing(
129
177
  timeout: 5
@@ -143,6 +191,10 @@ describe HybridPlatformsConductor::ActionsExecutor do
143
191
  it 'copies relative files remotely with sudo' do
144
192
  with_test_platform_for_remote_testing(
145
193
  expected_cmds: [
194
+ [
195
+ 'whoami',
196
+ proc { [0, 'test_user', ''] }
197
+ ],
146
198
  [
147
199
  'sudo -u root cp -r "/path/to/src.file" "/tmp/hpc_local_workspaces/node/to/dst.dir"',
148
200
  proc { [0, '', ''] }
@@ -153,9 +205,27 @@ describe HybridPlatformsConductor::ActionsExecutor do
153
205
  end
154
206
  end
155
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
+
156
222
  it 'copies relative files remotely with a different sudo' do
157
223
  with_test_platform_for_remote_testing(
158
224
  expected_cmds: [
225
+ [
226
+ 'whoami',
227
+ proc { [0, 'test_user', ''] }
228
+ ],
159
229
  [
160
230
  'other_sudo --user root cp -r "/path/to/src.file" "/tmp/hpc_local_workspaces/node/to/dst.dir"',
161
231
  proc { [0, '', ''] }
@@ -169,6 +239,23 @@ describe HybridPlatformsConductor::ActionsExecutor do
169
239
  end
170
240
  end
171
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
+
172
259
  end
173
260
 
174
261
  end
@@ -132,6 +132,36 @@ describe HybridPlatformsConductor::ActionsExecutor do
132
132
  end
133
133
  end
134
134
 
135
+ it 'creates SSH master to several nodes differing only by the SSH port' do
136
+ with_test_platform(
137
+ {
138
+ nodes: {
139
+ 'node1' => { meta: { host_ip: '192.168.42.1', ssh_port: 6661 } },
140
+ 'node2' => { meta: { host_ip: '192.168.42.1', ssh_port: 6662 } },
141
+ 'node3' => { meta: { host_ip: '192.168.42.1', ssh_port: 6663 } }
142
+ }
143
+ }
144
+ ) do
145
+ with_cmd_runner_mocked(
146
+ [
147
+ ['which env', proc { [0, "/usr/bin/env\n", ''] }],
148
+ ['ssh -V 2>&1', proc { [0, "OpenSSH_7.4p1 Debian-10+deb9u7, OpenSSL 1.0.2u 20 Dec 2019\n", ''] }]
149
+ ] + ssh_expected_commands_for(
150
+ {
151
+ 'node1' => { connection: '192.168.42.1', user: 'test_user', port: 6661 },
152
+ 'node2' => { connection: '192.168.42.1', user: 'test_user', port: 6662 },
153
+ 'node3' => { connection: '192.168.42.1', user: 'test_user', port: 6663 }
154
+ }
155
+ )
156
+ ) do
157
+ test_connector.ssh_user = 'test_user'
158
+ test_connector.with_connection_to(%w[node1 node2 node3]) do |connected_nodes|
159
+ expect(connected_nodes.sort).to eq %w[node1 node2 node3].sort
160
+ end
161
+ end
162
+ end
163
+ end
164
+
135
165
  it 'creates SSH master to several nodes with ssh connections transformed' do
136
166
  with_test_platform(
137
167
  { nodes: {