hybrid_platforms_conductor 33.4.0 → 33.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -0
- data/README.md +5 -5
- data/docs/config_dsl.md +7 -5
- data/docs/plugins/cmdb/host_keys.md +3 -1
- data/docs/plugins/connector/ssh.md +1 -0
- data/lib/hybrid_platforms_conductor/actions_executor.rb +29 -1
- data/lib/hybrid_platforms_conductor/bitbucket.rb +2 -2
- data/lib/hybrid_platforms_conductor/cmd_runner.rb +4 -4
- data/lib/hybrid_platforms_conductor/config.rb +2 -0
- data/lib/hybrid_platforms_conductor/confluence.rb +2 -2
- data/lib/hybrid_platforms_conductor/connector.rb +5 -2
- data/lib/hybrid_platforms_conductor/credentials.rb +20 -12
- data/lib/hybrid_platforms_conductor/deployer.rb +5 -7
- data/lib/hybrid_platforms_conductor/github.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/bash.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/remote_bash.rb +27 -17
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/host_keys.rb +13 -12
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/local.rb +6 -4
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/my_connector.rb.sample +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +37 -25
- data/lib/hybrid_platforms_conductor/hpc_plugins/log/remote_fs.rb +5 -6
- data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb +23 -14
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/docker.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +3 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/keepass.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_deploy_and_idempotence.rb +17 -3
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_removes_root_access.rb +30 -10
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/hostname.rb +1 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/idempotence.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/ip.rb +1 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_conf.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_masters_ok.rb +2 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/local_users.rb +1 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/mounts.rb +1 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/orphan_files.rb +1 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +1 -2
- data/lib/hybrid_platforms_conductor/logger_helpers.rb +17 -0
- data/lib/hybrid_platforms_conductor/test.rb +21 -7
- data/lib/hybrid_platforms_conductor/tests_runner.rb +7 -6
- data/lib/hybrid_platforms_conductor/thycotic.rb +2 -2
- data/lib/hybrid_platforms_conductor/version.rb +1 -1
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/bash_spec.rb +15 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/remote_bash_spec.rb +32 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/local/remote_actions_spec.rb +87 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb +30 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/global_helpers_spec.rb +10 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/remote_actions_spec.rb +38 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/helpers_spec.rb +195 -0
- data/spec/hybrid_platforms_conductor_test/api/cmd_runner_spec.rb +14 -0
- data/spec/hybrid_platforms_conductor_test/api/config_spec.rb +11 -0
- data/spec/hybrid_platforms_conductor_test/api/credentials_spec.rb +8 -4
- data/spec/hybrid_platforms_conductor_test/api/deployer/log_plugins/remote_fs_spec.rb +215 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/host_keys_spec.rb +49 -10
- data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/services_deployment_spec.rb +64 -16
- data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +5 -3
- data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/chef_versions.yml +3 -0
- data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/nodes/node.json +15 -0
- data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/policyfiles/test_policy.rb +3 -0
- data/spec/hybrid_platforms_conductor_test/shared_examples/deployer.rb +134 -0
- data/spec/hybrid_platforms_conductor_test/test_connector.rb +2 -2
- 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 |
|
56
|
-
hostnames[
|
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
|
-
|
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 "#{@
|
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
|
-
|
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
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
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
|
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("#{@
|
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
|
-
\"#{
|
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,
|
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
|
-
|
34
|
-
|
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 =>
|
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.
|
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
|
-
|
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}
|
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 =
|
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
|
-
|
286
|
-
|
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
|
-
|
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 "
|
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.
|
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(
|
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
|
-
|
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(
|
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(
|
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
|
-
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
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
|