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
@@ -24,7 +24,7 @@ module HybridPlatformsConductor
24
24
  # * Hash<Symbol, Symbol or Array<Symbol> >: The list of necessary properties (or single one) that should be set, per property name (:others can also be used here)
25
25
  def property_dependencies
26
26
  {
27
- host_keys: %i[hostname host_ip]
27
+ host_keys: %i[hostname host_ip ssh_port]
28
28
  }
29
29
  end
30
30
 
@@ -41,19 +41,20 @@ module HybridPlatformsConductor
41
41
  # Nodes for which the property can't be fetched can be ommitted.
42
42
  def get_host_keys(_nodes, metadata)
43
43
  updated_metadata = {}
44
- # Get the list of nodes, per hostname (just in case several nodes share the same hostname)
45
- # Hash<String, Array<String> >
44
+ # Get the list of nodes, per [hostname, port] (just in case several nodes share the same hostname and port)
45
+ # Hash<[String, Integer], Array<String> >
46
46
  hostnames = Hash.new { |hash, key| hash[key] = [] }
47
47
  metadata.each do |node, node_metadata|
48
+ ssh_port = node_metadata[:ssh_port] || 22
48
49
  if node_metadata[:host_ip]
49
- hostnames[node_metadata[:host_ip]] << node
50
+ hostnames[[node_metadata[:host_ip], ssh_port]] << node
50
51
  elsif node_metadata[:hostname]
51
- hostnames[node_metadata[:hostname]] << node
52
+ hostnames[[node_metadata[:hostname], ssh_port]] << node
52
53
  end
53
54
  end
54
55
  unless hostnames.empty?
55
- host_keys_for(*hostnames.keys).each do |hostname, ip|
56
- hostnames[hostname].each do |node|
56
+ host_keys_for(*hostnames.keys).each do |host_id, ip|
57
+ hostnames[host_id].each do |node|
57
58
  updated_metadata[node] = ip
58
59
  end
59
60
  end
@@ -71,7 +72,7 @@ module HybridPlatformsConductor
71
72
  # Discover the host keys associated to a list of hosts.
72
73
  #
73
74
  # Parameters::
74
- # * *hosts* (Array<String>): The hosts to check for
75
+ # * *hosts* (Array<[String, Integer]>): The hosts to check for ([hostname, port])
75
76
  # Result::
76
77
  # * Hash<String, Array<String> >: The corresponding host keys, per host name
77
78
  def host_keys_for(*hosts)
@@ -82,9 +83,9 @@ module HybridPlatformsConductor
82
83
  parallel: true,
83
84
  nbr_threads_max: MAX_THREADS_SSH_KEY_SCAN,
84
85
  progress: log_debug? ? 'Gather host keys' : nil
85
- ) do |host|
86
+ ) do |(host, ssh_port)|
86
87
  exit_status, stdout, _stderr = @cmd_runner.run_cmd(
87
- "ssh-keyscan #{host}",
88
+ "ssh-keyscan -p #{ssh_port} #{host}",
88
89
  timeout: TIMEOUT_SSH_KEYSCAN,
89
90
  log_to_stdout: log_debug?,
90
91
  no_exception: true
@@ -97,9 +98,9 @@ module HybridPlatformsConductor
97
98
  found_keys << "#{type} #{key}"
98
99
  end
99
100
  end
100
- results[host] = found_keys.sort unless found_keys.empty?
101
+ results[[host, ssh_port]] = found_keys.sort unless found_keys.empty?
101
102
  else
102
- log_warn "Unable to get host key for #{host}. Ignoring it. Accessing #{host} might require manual acceptance of its host key."
103
+ log_warn "Unable to get host key for #{host} (port #{ssh_port}). Ignoring it. Accessing #{host} might require manual acceptance of its host key."
103
104
  end
104
105
  end
105
106
  results
@@ -35,9 +35,11 @@ module HybridPlatformsConductor
35
35
  # [API] - @stderr_io can be used to send stderr output
36
36
  #
37
37
  # Parameters::
38
- # * *bash_cmds* (String): Bash commands to execute
38
+ # * *bash_cmds* (String or SecretString): Bash commands to execute. Use #to_unprotected to access the real content (otherwise secrets are obfuscated).
39
39
  def remote_bash(bash_cmds)
40
- run_cmd "cd #{workspace_for(@node)} ; #{bash_cmds}", force_bash: true
40
+ SecretString.protect("cd #{workspace_for(@node)} ; #{bash_cmds.to_unprotected}", silenced_str: "cd #{workspace_for(@node)} ; #{bash_cmds}") do |cmd|
41
+ run_cmd cmd, force_bash: true
42
+ end
41
43
  end
42
44
 
43
45
  # Execute an interactive shell on the remote node
@@ -75,8 +77,8 @@ module HybridPlatformsConductor
75
77
  def remote_copy(from, to, sudo: false, owner: nil, group: nil)
76
78
  # If the destination is a relative path, prepend the workspace dir to it.
77
79
  to = "#{workspace_for(@node)}/#{to}" unless to.start_with?('/')
78
- if sudo
79
- 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}\""
80
82
  else
81
83
  FileUtils.cp_r from, to unless @cmd_runner.dry_run
82
84
  end
@@ -104,7 +104,7 @@ module HybridPlatformsConductor
104
104
  # [API] - @stderr_io can be used to send stderr output
105
105
  #
106
106
  # Parameters::
107
- # * *bash_cmds* (String): Bash commands to execute
107
+ # * *bash_cmds* (String or SecretString): Bash commands to execute. Use #to_unprotected to access the real content (otherwise secrets are obfuscated).
108
108
  def remote_bash(bash_cmds)
109
109
  MyConnectLib.connect_to(@nodes_handler.get_host_ip_of(@node)).run_bash(bash_cmds)
110
110
  end
@@ -236,31 +236,40 @@ module HybridPlatformsConductor
236
236
  # [API] - @stderr_io can be used to send stderr output
237
237
  #
238
238
  # Parameters::
239
- # * *bash_cmds* (String): Bash commands to execute
239
+ # * *bash_cmds* (String or SecretString): Bash commands to execute. Use #to_unprotected to access the real content (otherwise secrets are obfuscated).
240
240
  def remote_bash(bash_cmds)
241
- ssh_cmd =
241
+ SecretString.protect(
242
242
  if @nodes_handler.get_ssh_session_exec_of(@node) == false
243
243
  # When ExecSession is disabled we need to use stdin directly
244
- "{ cat | #{ssh_exec} #{ssh_url} -T; } <<'HPC_EOF'\n#{bash_cmds}\nHPC_EOF"
244
+ "{ cat | #{ssh_exec} #{ssh_url} -T; } <<'HPC_EOF'\n#{bash_cmds.to_unprotected}\nHPC_EOF"
245
245
  else
246
- "#{ssh_exec} #{ssh_url} /bin/bash <<'HPC_EOF'\n#{bash_cmds}\nHPC_EOF"
247
- end
248
- # Due to a limitation of Process.spawn, each individual argument is limited to 128KB of size.
249
- # Therefore we need to make sure that if bash_cmds exceeds MAX_CMD_ARG_LENGTH bytes (considering EOF chars) then we use an intermediary shell script to store the commands.
250
- if bash_cmds.size > MAX_CMD_ARG_LENGTH
251
- # Write the commands in a file
252
- temp_file = "#{Dir.tmpdir}/hpc_temp_cmds_#{Digest::MD5.hexdigest(bash_cmds)}.sh"
253
- File.open(temp_file, 'w+') do |file|
254
- file.write ssh_cmd
255
- file.chmod 0o700
256
- end
257
- begin
258
- run_cmd(temp_file)
259
- ensure
260
- File.unlink(temp_file)
246
+ "#{ssh_exec} #{ssh_url} /bin/bash <<'HPC_EOF'\n#{bash_cmds.to_unprotected}\nHPC_EOF"
247
+ end,
248
+ silenced_str:
249
+ if @nodes_handler.get_ssh_session_exec_of(@node) == false
250
+ # When ExecSession is disabled we need to use stdin directly
251
+ "{ cat | #{ssh_exec} #{ssh_url} -T; } <<'HPC_EOF'\n#{bash_cmds}\nHPC_EOF"
252
+ else
253
+ "#{ssh_exec} #{ssh_url} /bin/bash <<'HPC_EOF'\n#{bash_cmds}\nHPC_EOF"
254
+ end
255
+ ) do |ssh_cmd|
256
+ # Due to a limitation of Process.spawn, each individual argument is limited to 128KB of size.
257
+ # Therefore we need to make sure that if bash_cmds exceeds MAX_CMD_ARG_LENGTH bytes (considering EOF chars) then we use an intermediary shell script to store the commands.
258
+ if bash_cmds.to_unprotected.size > MAX_CMD_ARG_LENGTH
259
+ # Write the commands in a file
260
+ temp_file = "#{Dir.tmpdir}/hpc_temp_cmds_#{Digest::MD5.hexdigest(bash_cmds.to_unprotected)}.sh"
261
+ File.open(temp_file, 'w+') do |file|
262
+ file.write ssh_cmd.to_unprotected
263
+ file.chmod 0o700
264
+ end
265
+ begin
266
+ run_cmd(temp_file)
267
+ ensure
268
+ File.unlink(temp_file)
269
+ end
270
+ else
271
+ run_cmd ssh_cmd
261
272
  end
262
- else
263
- run_cmd ssh_cmd
264
273
  end
265
274
  end
266
275
 
@@ -301,13 +310,14 @@ module HybridPlatformsConductor
301
310
  # * *owner* (String or nil): Owner to be used when copying the files, or nil for current one [default: nil]
302
311
  # * *group* (String or nil): Group to be used when copying the files, or nil for current one [default: nil]
303
312
  def remote_copy(from, to, sudo: false, owner: nil, group: nil)
313
+ need_sudo = sudo && !@actions_executor.privileged_access?(@node)
304
314
  if @nodes_handler.get_ssh_session_exec_of(@node) == false
305
315
  # We don't have ExecSession, so don't use ssh, but scp instead.
306
- if sudo
316
+ if need_sudo
307
317
  # We need to first copy the file in an accessible directory, and then sudo mv
308
318
  remote_bash('mkdir -p hpc_tmp_scp')
309
319
  run_cmd "scp -S #{ssh_exec} #{from} #{ssh_url}:./hpc_tmp_scp"
310
- 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}")
311
321
  else
312
322
  run_cmd "scp -S #{ssh_exec} #{from} #{ssh_url}:#{to}"
313
323
  end
@@ -323,7 +333,7 @@ module HybridPlatformsConductor
323
333
  #{File.basename(from)} | \
324
334
  #{ssh_exec} \
325
335
  #{ssh_url} \
326
- \"#{sudo ? "#{@nodes_handler.sudo_on(@node)} " : ''}tar \
336
+ \"#{need_sudo ? @actions_executor.sudo_prefix(@node) : ''}tar \
327
337
  --extract \
328
338
  --gunzip \
329
339
  --file - \
@@ -374,16 +384,18 @@ module HybridPlatformsConductor
374
384
 
375
385
  # Add each node
376
386
  # Query for the metadata of all nodes at once
377
- @nodes_handler.prefetch_metadata_of nodes, %i[private_ips hostname host_ip description]
387
+ @nodes_handler.prefetch_metadata_of nodes, %i[private_ips hostname host_ip description ssh_port]
378
388
  nodes.sort.each do |node|
379
389
  # Generate the conf for the node
380
390
  connection, connection_user, gateway, gateway_user = connection_info_for(node, no_exception: true)
381
391
  if connection.nil?
382
392
  config_content << "# #{node} - Not connectable using SSH - #{@nodes_handler.get_description_of(node) || ''}\n"
383
393
  else
394
+ ssh_port = @nodes_handler.get_ssh_port_of(node)
384
395
  config_content << "# #{node} - #{connection} - #{@nodes_handler.get_description_of(node) || ''}\n"
385
396
  config_content << "Host #{ssh_aliases_for(node).join(' ')}\n"
386
397
  config_content << " Hostname #{connection}\n"
398
+ config_content << " Port #{ssh_port}\n" unless ssh_port.nil?
387
399
  config_content << " User \"#{connection_user}\"\n" if connection_user != @ssh_user
388
400
  config_content << " ProxyCommand #{ssh_exec} -q -W %h:%p #{gateway_user}@#{gateway}\n" unless gateway.nil?
389
401
  if @passwords.key?(node)
@@ -648,7 +660,7 @@ module HybridPlatformsConductor
648
660
  existing_users = File.exist?(control_master_users_file) ? File.read(control_master_users_file).split("\n") : []
649
661
  ssh_url = "hpc.#{node}"
650
662
  connection, connection_user, _gateway, _gateway_user = connection_info_for(node)
651
- control_path_file = control_master_file(connection, '22', connection_user)
663
+ control_path_file = control_master_file(connection, @nodes_handler.get_ssh_port_of(node) || 22, connection_user)
652
664
  if existing_users.empty?
653
665
  # Make sure there is no stale one.
654
666
  if File.exist?(control_path_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
  ]
@@ -241,18 +241,24 @@ module HybridPlatformsConductor
241
241
  '--json-attributes', "nodes/#{node}.json"
242
242
  ]
243
243
  client_options << '--why-run' if use_why_run
244
+ # Force setting of TERM variable and usage of unbuffer to get colored output from chef-client even if executed through a non-interactive SSH session.
245
+ client_env = {
246
+ 'SSL_CERT_DIR' => '/etc/ssl/certs',
247
+ 'TERM' => 'xterm-256color'
248
+ }
244
249
  if @nodes_handler.get_use_local_chef_of(node)
245
250
  # Just run the chef-client directly from the packaged repository
246
- sudo_prefix = @cmd_runner.root? ? '' : 'sudo '
251
+ sudo_prefix = @cmd_runner.root? ? '' : 'sudo -E '
247
252
  [
248
253
  {
249
254
  bash: [
250
255
  'set -e',
251
256
  "cd #{package_dir}"
252
257
  ] +
253
- gems_to_install.map { |(gem_name, gem_version)| "#{sudo_prefix}SSL_CERT_DIR=/etc/ssl/certs /opt/chef-workstation/bin/chef gem install #{gem_name} --version \"#{gem_version}\"" } +
258
+ client_env.map { |var_name, value| "export #{var_name}=#{value}" } +
259
+ gems_to_install.map { |(gem_name, gem_version)| "#{sudo_prefix}/opt/chef-workstation/bin/chef gem install #{gem_name} --version \"#{gem_version}\"" } +
254
260
  [
255
- "#{sudo_prefix}SSL_CERT_DIR=/etc/ssl/certs /opt/chef-workstation/bin/chef-client #{client_options.join(' ')}"
261
+ "#{sudo_prefix}/opt/chef-workstation/bin/chef-client #{client_options.join(' ')}"
256
262
  ]
257
263
  }
258
264
  ]
@@ -263,14 +269,14 @@ module HybridPlatformsConductor
263
269
  raise "Missing file #{chef_versions_file} specifying the Chef Infra Client version to be deployed" unless File.exist?(chef_versions_file)
264
270
 
265
271
  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 ")
272
+ sudo = @actions_executor.sudo_prefix(node, forward_env: true)
267
273
  [
268
274
  {
269
275
  # Install dependencies
270
276
  remote_bash: [
271
277
  'set -e',
272
278
  'set -o pipefail',
273
- "if [ -n \"$(command -v apt)\" ]; then #{sudo}apt update && #{sudo}apt install -y curl build-essential ; else #{sudo}yum groupinstall 'Development Tools' && #{sudo}yum install -y curl ; fi",
279
+ "if [ -n \"$(command -v apt)\" ]; then #{sudo}apt update && #{sudo}apt install -y curl build-essential expect ; else #{sudo}yum groupinstall 'Development Tools' && #{sudo}yum install -y curl expect ; fi",
274
280
  'mkdir -p ./hpc_deploy',
275
281
  'rm -rf ./hpc_deploy/tmp',
276
282
  'mkdir -p ./hpc_deploy/tmp',
@@ -281,16 +287,19 @@ module HybridPlatformsConductor
281
287
  },
282
288
  {
283
289
  scp: { package_dir => './hpc_deploy' },
284
- remote_bash: [
285
- 'set -e',
286
- "cd ./hpc_deploy/#{package_name}"
287
- ] +
288
- gems_to_install.map { |(gem_name, gem_version)| "#{sudo}SSL_CERT_DIR=/etc/ssl/certs /opt/chef/embedded/bin/gem install #{gem_name} --version \"#{gem_version}\"" } +
289
- [
290
- "#{sudo}SSL_CERT_DIR=/etc/ssl/certs /opt/chef/bin/chef-client #{client_options.join(' ')}",
291
- 'cd ..'
290
+ remote_bash: {
291
+ commands: [
292
+ 'set -e',
293
+ "cd ./hpc_deploy/#{package_name}"
292
294
  ] +
293
- (log_debug? ? [] : ["#{sudo}rm -rf ./hpc_deploy/#{package_name}"])
295
+ gems_to_install.map { |(gem_name, gem_version)| "#{sudo}/opt/chef/embedded/bin/gem install #{gem_name} --version \"#{gem_version}\"" } +
296
+ [
297
+ "#{sudo}unbuffer /opt/chef/bin/chef-client #{client_options.join(' ')}",
298
+ 'cd ..'
299
+ ] +
300
+ (log_debug? ? [] : ["#{sudo}rm -rf ./hpc_deploy/#{package_name}"]),
301
+ env: client_env
302
+ }
294
303
  }
295
304
  ]
296
305
  end
@@ -21,7 +21,7 @@ module HybridPlatformsConductor
21
21
  ::Docker.validate_version!
22
22
  docker_ok = true
23
23
  rescue
24
- log_error "[ #{@node}/#{@environment} ] - Docker is not installed correctly. Please install it. Error: #{$ERROR_INFO}"
24
+ log_error "Docker is not installed correctly. Please install it. Error: #{$ERROR_INFO}"
25
25
  end
26
26
  docker_ok
27
27
  end
@@ -2,6 +2,7 @@ require 'json'
2
2
  require 'proxmox'
3
3
  require 'digest'
4
4
  require 'hybrid_platforms_conductor/actions_executor'
5
+ require 'hybrid_platforms_conductor/credentials'
5
6
  require 'hybrid_platforms_conductor/provisioner'
6
7
 
7
8
  module HybridPlatformsConductor
@@ -284,7 +285,7 @@ module HybridPlatformsConductor
284
285
  # cf https://pve.proxmox.com/wiki/Renaming_a_PVE_node
285
286
  URI.parse(url).host.downcase.split('.').first,
286
287
  user,
287
- password,
288
+ password&.to_unprotected,
288
289
  ENV['hpc_realm_for_proxmox'] || 'pam',
289
290
  {
290
291
  verify_ssl: false,
@@ -436,7 +437,7 @@ module HybridPlatformsConductor
436
437
  {
437
438
  proxmox_test_info[:sync_node] => {
438
439
  remote_bash: {
439
- commands: "#{@actions_executor.connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(proxmox_test_info[:sync_node])} -E "}./proxmox/#{cmd}",
440
+ commands: "#{@actions_executor.sudo_prefix(proxmox_test_info[:sync_node], forward_env: true)}./proxmox/#{cmd}",
440
441
  env: {
441
442
  'hpc_user_for_proxmox' => user,
442
443
  'hpc_password_for_proxmox' => password,
@@ -90,7 +90,7 @@ module HybridPlatformsConductor
90
90
  key_file = ENV['hpc_key_file_for_keepass']
91
91
  password_enc = ENV['hpc_password_enc_for_keepass']
92
92
  keepass_credentials = {}
93
- keepass_credentials[:password] = password if password
93
+ keepass_credentials[:password] = password.to_unprotected if password
94
94
  keepass_credentials[:password_enc] = password_enc if password_enc
95
95
  keepass_credentials[:key_file] = key_file if key_file
96
96
  KeepassKpscript.
@@ -26,7 +26,13 @@ module HybridPlatformsConductor
26
26
  # Check that we can connect with root
27
27
  ssh_ok = false
28
28
  begin
29
- Net::SSH.start(instance.ip, 'root', password: 'root_pwd', auth_methods: ['password'], verify_host_key: :never) do |ssh|
29
+ Net::SSH.start(
30
+ instance.ip,
31
+ 'root',
32
+ password: 'root_pwd',
33
+ auth_methods: ['password'],
34
+ verify_host_key: :never
35
+ ) do |ssh|
30
36
  ssh_ok = ssh.exec!('echo Works').strip == 'Works'
31
37
  end
32
38
  rescue
@@ -53,14 +59,22 @@ module HybridPlatformsConductor
53
59
  # System is booting up. See pam_nologin(8)
54
60
  # Authentication failed.
55
61
  instance.stop
56
- instance.with_running_instance(port: 22) do
62
+ ssh_port = @nodes_handler.get_ssh_port_of(@node) || 22
63
+ instance.with_running_instance(port: ssh_port) do
57
64
 
58
65
  unless @nodes_handler.get_root_access_allowed_of(@node)
59
66
  # ===== Deploy removes root access
60
67
  # Check that we can't connect with root
61
68
  ssh_ok = false
62
69
  begin
63
- Net::SSH.start(instance.ip, 'root', password: 'root_pwd', auth_methods: ['password'], verify_host_key: :never) do |ssh|
70
+ Net::SSH.start(
71
+ instance.ip,
72
+ 'root',
73
+ password: 'root_pwd',
74
+ auth_methods: ['password'],
75
+ verify_host_key: :never,
76
+ port: ssh_port
77
+ ) do |ssh|
64
78
  ssh_ok = ssh.exec!('echo Works').strip == 'Works'
65
79
  end
66
80
  rescue
@@ -18,7 +18,13 @@ module HybridPlatformsConductor
18
18
  # Check that we can connect with root
19
19
  ssh_ok = false
20
20
  begin
21
- Net::SSH.start(instance.ip, 'root', password: 'root_pwd', auth_methods: ['password'], verify_host_key: :never) do |ssh|
21
+ Net::SSH.start(
22
+ instance.ip,
23
+ 'root',
24
+ password: 'root_pwd',
25
+ auth_methods: ['password'],
26
+ verify_host_key: :never
27
+ ) do |ssh|
22
28
  ssh_ok = ssh.exec!('echo Works').strip == 'Works'
23
29
  end
24
30
  rescue
@@ -29,17 +35,31 @@ module HybridPlatformsConductor
29
35
  deployer.nbr_retries_on_error = 3
30
36
  deployer.deploy_on @node
31
37
  # As sshd is certainly being restarted, start and stop the container to reload it.
32
- deployer.restart @node
33
- # Check that we can't connect with root
34
- ssh_ok = false
35
- begin
36
- Net::SSH.start(instance.ip, 'root', password: 'root_pwd', auth_methods: ['password'], verify_host_key: :never) do |ssh|
37
- ssh_ok = ssh.exec!('echo Works').strip == 'Works'
38
+ # As it's possible sshd has to be restarted because of a change in its conf, restart the container.
39
+ # Otherwise you'll get the following error upon reconnection:
40
+ # System is booting up. See pam_nologin(8)
41
+ # Authentication failed.
42
+ instance.stop
43
+ ssh_port = @nodes_handler.get_ssh_port_of(@node) || 22
44
+ instance.with_running_instance(port: ssh_port) do
45
+ # Check that we can't connect with root
46
+ ssh_ok = false
47
+ begin
48
+ Net::SSH.start(
49
+ instance.ip,
50
+ 'root',
51
+ password: 'root_pwd',
52
+ auth_methods: ['password'],
53
+ verify_host_key: :never,
54
+ port: ssh_port
55
+ ) do |ssh|
56
+ ssh_ok = ssh.exec!('echo Works').strip == 'Works'
57
+ end
58
+ rescue
59
+ nil
38
60
  end
39
- rescue
40
- nil
61
+ assert_equal ssh_ok, false, 'Root can still connect on the image after deployment'
41
62
  end
42
- assert_equal ssh_ok, false, 'Root can still connect on the image after deployment'
43
63
  end
44
64
  end
45
65
  end