hybrid_platforms_conductor 32.4.0 → 32.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/nodes_to_deploy +11 -5
- data/lib/hybrid_platforms_conductor/deployer.rb +9 -8
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +147 -68
- data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/platform_handler_plugin.rb.sample +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_freshness.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/hostname.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/ip.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/local_users.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/mounts.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/orphan_files.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre.rb +6 -7
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +7 -6
- data/lib/hybrid_platforms_conductor/nodes_handler.rb +45 -1
- data/lib/hybrid_platforms_conductor/services_handler.rb +9 -13
- data/lib/hybrid_platforms_conductor/version.rb +1 -1
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/config_dsl_spec.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb +57 -2
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/global_helpers_spec.rb +68 -12
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/node_helpers_spec.rb +1 -1
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/remote_actions_spec.rb +47 -9
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/common_spec.rb +28 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/config_dsl_spec.rb +71 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/git_diff_impacts_spec.rb +10 -0
- data/spec/hybrid_platforms_conductor_test/executables/nodes_to_deploy_spec.rb +25 -0
- data/spec/hybrid_platforms_conductor_test/helpers/cmd_runner_helpers.rb +1 -5
- data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +37 -9
- data/spec/hybrid_platforms_conductor_test/helpers/deployer_helpers.rb +14 -14
- data/spec/hybrid_platforms_conductor_test/helpers/deployer_test_helpers.rb +70 -11
- data/spec/hybrid_platforms_conductor_test/helpers/platforms_handler_helpers.rb +1 -1
- data/spec/hybrid_platforms_conductor_test/helpers/provisioner_proxmox_helpers.rb +2 -2
- metadata +12 -11
@@ -17,7 +17,7 @@ module HybridPlatformsConductor
|
|
17
17
|
Hash[
|
18
18
|
@config.aggregate_files_rules(@nodes_handler, @node).map do |path, rule_info|
|
19
19
|
[
|
20
|
-
"if
|
20
|
+
"if #{@nodes_handler.sudo_on(@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
|
@@ -10,7 +10,7 @@ module HybridPlatformsConductor
|
|
10
10
|
# Check my_test_plugin.rb.sample documentation for signature details.
|
11
11
|
def test_on_node
|
12
12
|
{
|
13
|
-
|
13
|
+
"#{@nodes_handler.sudo_on(@node)} hostname -s" => proc do |stdout|
|
14
14
|
assert_equal stdout.first, @node, "Expected hostname to be #{@node}, but got #{stdout.first} instead."
|
15
15
|
end
|
16
16
|
}
|
@@ -10,7 +10,7 @@ module HybridPlatformsConductor
|
|
10
10
|
# Check my_test_plugin.rb.sample documentation for signature details.
|
11
11
|
def test_on_node
|
12
12
|
{
|
13
|
-
|
13
|
+
"#{@nodes_handler.sudo_on(@node)} hostname -I" => proc do |stdout|
|
14
14
|
if stdout.first.nil?
|
15
15
|
error 'No IP returned by "hostname -I"'
|
16
16
|
else
|
@@ -57,7 +57,7 @@ module HybridPlatformsConductor
|
|
57
57
|
# Check my_test_plugin.rb.sample documentation for signature details.
|
58
58
|
def test_on_node
|
59
59
|
{
|
60
|
-
"
|
60
|
+
"#{@nodes_handler.sudo_on(@node)} cat /etc/passwd" => proc do |stdout|
|
61
61
|
passwd_users = stdout.map { |passwd_line| passwd_line.split(':').first }
|
62
62
|
missing_users = @nodes_handler.
|
63
63
|
select_confs_for_node(@node, @config.users_that_should_be_present).
|
@@ -61,7 +61,7 @@ module HybridPlatformsConductor
|
|
61
61
|
# Check my_test_plugin.rb.sample documentation for signature details.
|
62
62
|
def test_on_node
|
63
63
|
{
|
64
|
-
|
64
|
+
"#{@nodes_handler.sudo_on(@node)} mount" => proc do |stdout|
|
65
65
|
mounts_info = stdout.map do |line|
|
66
66
|
fields = line.split
|
67
67
|
{
|
@@ -50,7 +50,7 @@ module HybridPlatformsConductor
|
|
50
50
|
# Check my_test_plugin.rb.sample documentation for signature details.
|
51
51
|
def test_on_node
|
52
52
|
{
|
53
|
-
"
|
53
|
+
"#{@nodes_handler.sudo_on(@node)} /usr/bin/find / \\( #{@nodes_handler.
|
54
54
|
select_confs_for_node(@node, @config.ignored_orphan_files_paths).
|
55
55
|
inject(DIRECTORIES_TO_ALWAYS_IGNORE) { |merged_paths, paths_to_ignore_info| merged_paths + paths_to_ignore_info[:ignored_paths] }.
|
56
56
|
uniq.
|
@@ -13,16 +13,15 @@ module HybridPlatformsConductor
|
|
13
13
|
'CVE-2017-5754' => 'Meltdown'
|
14
14
|
}
|
15
15
|
|
16
|
-
SPECTRE_CMD = <<~EOS
|
17
|
-
sudo /bin/bash <<'EOAction'
|
18
|
-
#{File.read("#{__dir__}/spectre-meltdown-checker.sh")}
|
19
|
-
EOAction
|
20
|
-
EOS
|
21
|
-
|
22
16
|
# Check my_test_plugin.rb.sample documentation for signature details.
|
23
17
|
def test_on_node
|
18
|
+
spectre_cmd = <<~EOS
|
19
|
+
#{@nodes_handler.sudo_on(@node)} /bin/bash <<'EOAction'
|
20
|
+
#{File.read("#{__dir__}/spectre-meltdown-checker.sh")}
|
21
|
+
EOAction
|
22
|
+
EOS
|
24
23
|
{
|
25
|
-
|
24
|
+
spectre_cmd => {
|
26
25
|
validator: proc do |stdout|
|
27
26
|
VULNERABILITIES_TO_CHECK.each do |id, name|
|
28
27
|
id_regexp = /#{Regexp.escape(id)}/
|
@@ -54,6 +54,7 @@ module HybridPlatformsConductor
|
|
54
54
|
current_url
|
55
55
|
end
|
56
56
|
)
|
57
|
+
sudo = @nodes_handler.sudo_on(@node)
|
57
58
|
Hash[urls.map do |url|
|
58
59
|
# 1. Get the OVAL file on the node to be tested (uncompress it if needed)
|
59
60
|
# 2. Make sure oscap is installed
|
@@ -74,9 +75,9 @@ module HybridPlatformsConductor
|
|
74
75
|
#{
|
75
76
|
case image
|
76
77
|
when :centos_7
|
77
|
-
"sudo yum install -y wget openscap-scanner #{packages_to_install.join(' ')}"
|
78
|
+
"#{sudo} yum install -y wget openscap-scanner #{packages_to_install.join(' ')}"
|
78
79
|
when :debian_9
|
79
|
-
"sudo apt install -y wget libopenscap8 #{packages_to_install.join(' ')}"
|
80
|
+
"#{sudo} apt install -y wget libopenscap8 #{packages_to_install.join(' ')}"
|
80
81
|
when :debian_10
|
81
82
|
# On Debian 10 we have to compile it from sources, as the packaged official version has core dumps.
|
82
83
|
# cf https://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg1688223.html
|
@@ -86,13 +87,13 @@ module HybridPlatformsConductor
|
|
86
87
|
rm -rf openscap
|
87
88
|
git clone --recurse-submodules https://github.com/OpenSCAP/openscap.git
|
88
89
|
cd openscap
|
89
|
-
sudo apt install -y cmake libdbus-1-dev libdbus-glib-1-dev libcurl4-openssl-dev libgcrypt20-dev libselinux1-dev libxslt1-dev libgconf2-dev libacl1-dev libblkid-dev libcap-dev libxml2-dev libldap2-dev libpcre3-dev python-dev swig libxml-parser-perl libxml-xpath-perl libperl-dev libbz2-dev librpm-dev g++ libapt-pkg-dev libyaml-dev
|
90
|
+
#{sudo} apt install -y cmake libdbus-1-dev libdbus-glib-1-dev libcurl4-openssl-dev libgcrypt20-dev libselinux1-dev libxslt1-dev libgconf2-dev libacl1-dev libblkid-dev libcap-dev libxml2-dev libldap2-dev libpcre3-dev python-dev swig libxml-parser-perl libxml-xpath-perl libperl-dev libbz2-dev librpm-dev g++ libapt-pkg-dev libyaml-dev
|
90
91
|
cd build
|
91
92
|
cmake ../
|
92
93
|
make
|
93
|
-
sudo make install
|
94
|
+
#{sudo} make install
|
94
95
|
fi
|
95
|
-
sudo apt install -y wget #{packages_to_install.join(' ')}
|
96
|
+
#{sudo} apt install -y wget #{packages_to_install.join(' ')}
|
96
97
|
EOS2
|
97
98
|
else
|
98
99
|
raise "Non supported image: #{image}. Please adapt this test's code."
|
@@ -103,7 +104,7 @@ module HybridPlatformsConductor
|
|
103
104
|
cd hpc_vulnerabilities_test
|
104
105
|
wget -N #{url}
|
105
106
|
#{uncompress_cmds.join("\n")}
|
106
|
-
sudo oscap oval eval --skip-valid --results "#{local_oval_file}.results.xml" "#{local_oval_file}"
|
107
|
+
#{sudo} oscap oval eval --skip-valid --results "#{local_oval_file}.results.xml" "#{local_oval_file}"
|
107
108
|
echo "===== RESULTS ====="
|
108
109
|
cat "#{local_oval_file}.results.xml"
|
109
110
|
cd ..
|
@@ -18,9 +18,20 @@ module HybridPlatformsConductor
|
|
18
18
|
# Array< Hash<Symbol, Object> >
|
19
19
|
attr_reader :cmdb_masters
|
20
20
|
|
21
|
+
# List of sudo methods. Each info has the following properties:
|
22
|
+
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by this rule.
|
23
|
+
# * *sudo_proc* (Proc): Code giving the sudo line for a given user
|
24
|
+
# Parameters::
|
25
|
+
# * *user* (String): User for which we want sudo
|
26
|
+
# Result::
|
27
|
+
# * String: Corresponding sudo string
|
28
|
+
# Array< Hash<Symbol, Object> >
|
29
|
+
attr_reader :sudo_procs
|
30
|
+
|
21
31
|
# Mixin initializer
|
22
32
|
def init_nodes_handler_config
|
23
33
|
@cmdb_masters = []
|
34
|
+
@sudo_procs = []
|
24
35
|
end
|
25
36
|
|
26
37
|
# Set CMDB masters
|
@@ -34,12 +45,26 @@ module HybridPlatformsConductor
|
|
34
45
|
}
|
35
46
|
end
|
36
47
|
|
48
|
+
# Set a sudo proc
|
49
|
+
#
|
50
|
+
# Parameters::
|
51
|
+
# * *sudo_proc* (Proc): The sudo proc (see #sudo_procs doc to know the signature)
|
52
|
+
def sudo_for(&sudo_proc)
|
53
|
+
@sudo_procs << {
|
54
|
+
nodes_selectors_stack: current_nodes_selectors_stack,
|
55
|
+
sudo_proc: sudo_proc
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
37
59
|
end
|
38
60
|
|
39
61
|
Config.extend_config_dsl_with ConfigDSLExtension, :init_nodes_handler_config
|
40
62
|
|
41
63
|
include LoggerHelpers, ParallelThreads
|
42
64
|
|
65
|
+
class GitError < RuntimeError
|
66
|
+
end
|
67
|
+
|
43
68
|
# Constructor
|
44
69
|
#
|
45
70
|
# Parameters::
|
@@ -484,7 +509,11 @@ module HybridPlatformsConductor
|
|
484
509
|
def impacted_nodes_from_git_diff(platform_name, from_commit: 'master', to_commit: nil, smallest_set: false)
|
485
510
|
platform = @platforms_handler.platform(platform_name)
|
486
511
|
raise "Unkown platform #{platform_name}. Possible platforms are #{@platforms_handler.known_platforms.map(&:name).sort.join(', ')}" if platform.nil?
|
487
|
-
|
512
|
+
begin
|
513
|
+
_exit_status, stdout, _stderr = @cmd_runner.run_cmd "cd #{platform.repository_path} && git --no-pager diff --no-color #{from_commit} #{to_commit.nil? ? '' : to_commit}", log_to_stdout: log_debug?
|
514
|
+
rescue CmdRunner::UnexpectedExitCodeError
|
515
|
+
raise GitError, $!.to_s
|
516
|
+
end
|
488
517
|
# Parse the git diff output to create a structured diff
|
489
518
|
# Hash< String, Hash< Symbol, Object > >: List of diffs info, per file name having a diff. Diffs info have the following properties:
|
490
519
|
# * *moved_to* (String): The new file path, in case it has been moved [optional]
|
@@ -561,6 +590,21 @@ module HybridPlatformsConductor
|
|
561
590
|
nodes_selector_stack.inject(known_nodes) { |selected_nodes, nodes_selector| selected_nodes & select_nodes(nodes_selector) }
|
562
591
|
end
|
563
592
|
|
593
|
+
# Get the sudo command for a given user on a given node
|
594
|
+
#
|
595
|
+
# Parameters::
|
596
|
+
# * *node* (String): Node on which we need sudo
|
597
|
+
# * *user* (String): User for which we need sudo [default = 'root']
|
598
|
+
# Result::
|
599
|
+
# * String: The corresponding sudo string
|
600
|
+
def sudo_on(node, user = 'root')
|
601
|
+
sudo = nil
|
602
|
+
select_confs_for_node(node, @config.sudo_procs).each do |sudo_proc_info|
|
603
|
+
sudo = sudo_proc_info[:sudo_proc].call(user)
|
604
|
+
end
|
605
|
+
sudo.nil? ? "sudo -u #{user}" : sudo
|
606
|
+
end
|
607
|
+
|
564
608
|
private
|
565
609
|
|
566
610
|
# Get the CMDB master for a given property.
|
@@ -12,14 +12,9 @@ module HybridPlatformsConductor
|
|
12
12
|
|
13
13
|
class << self
|
14
14
|
|
15
|
-
# List of
|
16
|
-
# Each deployment has the following info:
|
17
|
-
# * *platform_name* (String): The platform name
|
18
|
-
# * *services* (Hash< String, Array<String> >): Services to be deployed, per node
|
19
|
-
# * *secrets* (Hash): Secrets for which this has been packaged
|
20
|
-
# * *local_environment* (Boolean): Has it been packaged for local environment?
|
15
|
+
# List of package IDs that have been packaged.
|
21
16
|
# Make this at class level as several Deployer instances can be used in a multi-thread environmnent.
|
22
|
-
# Array<
|
17
|
+
# Array<Object>
|
23
18
|
attr_reader :packaged_deployments
|
24
19
|
|
25
20
|
end
|
@@ -114,21 +109,22 @@ module HybridPlatformsConductor
|
|
114
109
|
)
|
115
110
|
platforms_for(services).each do |platform, platform_services|
|
116
111
|
platform_name = platform.name
|
117
|
-
|
112
|
+
# Compute the package ID that is unique to this packaging, so that we don't mix it with others if needed.
|
113
|
+
package_id = {
|
118
114
|
platform_name: platform_name,
|
119
|
-
services: platform_services,
|
120
|
-
secrets: secrets,
|
115
|
+
services: Hash[platform_services.map { |node, node_services| [node, node_services.sort] }].sort,
|
116
|
+
secrets: secrets.sort,
|
121
117
|
local_environment: local_environment
|
122
118
|
}
|
123
|
-
if ServicesHandler.packaged_deployments.include?(
|
124
|
-
log_debug "Platform #{platform_name} has already been packaged for this deployment. Won't package it another time."
|
119
|
+
if ServicesHandler.packaged_deployments.include?(package_id)
|
120
|
+
log_debug "Platform #{platform_name} has already been packaged for this deployment (package ID #{package_id}). Won't package it another time."
|
125
121
|
else
|
126
122
|
platform.package(
|
127
123
|
services: platform_services,
|
128
124
|
secrets: secrets,
|
129
125
|
local_environment: local_environment
|
130
126
|
)
|
131
|
-
ServicesHandler.packaged_deployments <<
|
127
|
+
ServicesHandler.packaged_deployments << package_id
|
132
128
|
end
|
133
129
|
end
|
134
130
|
end
|
data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/config_dsl_spec.rb
CHANGED
@@ -43,6 +43,41 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
it 'returns ssh transformation procs' do
|
47
|
+
with_test_platform(
|
48
|
+
{
|
49
|
+
nodes: {
|
50
|
+
'node1' => {},
|
51
|
+
'node2' => {},
|
52
|
+
'node3' => {}
|
53
|
+
},
|
54
|
+
},
|
55
|
+
false,
|
56
|
+
'
|
57
|
+
for_nodes(%w[node1 node3]) do
|
58
|
+
transform_ssh_connection do |node, connection, connection_user, gateway, gateway_user|
|
59
|
+
["#{connection}_#{node}_13", "#{connection_user}_#{node}_13", "#{gateway}_#{node}_13", "#{gateway_user}_#{node}_13"]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
for_nodes(\'node1\') do
|
63
|
+
transform_ssh_connection do |node, connection, connection_user, gateway, gateway_user|
|
64
|
+
["#{connection}_#{node}_1", "#{connection_user}_#{node}_1", "#{gateway}_#{node}_1", "#{gateway_user}_#{node}_1"]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
'
|
68
|
+
) do
|
69
|
+
expect(test_config.ssh_connection_transforms.size).to eq 2
|
70
|
+
expect(test_config.ssh_connection_transforms[0][:nodes_selectors_stack]).to eq [%w[node1 node3]]
|
71
|
+
expect(test_config.ssh_connection_transforms[0][:transform].call('node1', 'test_host', 'test_user', 'test_gateway', 'test_gateway_user')).to eq [
|
72
|
+
'test_host_node1_13', 'test_user_node1_13', 'test_gateway_node1_13', 'test_gateway_user_node1_13'
|
73
|
+
]
|
74
|
+
expect(test_config.ssh_connection_transforms[1][:nodes_selectors_stack]).to eq ['node1']
|
75
|
+
expect(test_config.ssh_connection_transforms[1][:transform].call('node1', 'test_host', 'test_user', 'test_gateway', 'test_gateway_user')).to eq [
|
76
|
+
'test_host_node1_1', 'test_user_node1_1', 'test_gateway_node1_1', 'test_gateway_user_node1_1'
|
77
|
+
]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
46
81
|
end
|
47
82
|
|
48
83
|
end
|
data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb
CHANGED
@@ -28,6 +28,22 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
it 'creates an SSH master to 1 node not having Session Exec capabilities' do
|
32
|
+
with_test_platform(nodes: { 'node' => { meta: { host_ip: '192.168.42.42', ssh_session_exec: 'false' } } }) do
|
33
|
+
with_cmd_runner_mocked(
|
34
|
+
[
|
35
|
+
['which env', proc { [0, "/usr/bin/env\n", ''] }],
|
36
|
+
['ssh -V 2>&1', proc { [0, "OpenSSH_7.4p1 Debian-10+deb9u7, OpenSSL 1.0.2u 20 Dec 2019\n", ''] }]
|
37
|
+
] + ssh_expected_commands_for({ 'node' => { connection: '192.168.42.42', user: 'test_user' } }, with_session_exec: false)
|
38
|
+
) do
|
39
|
+
test_connector.ssh_user = 'test_user'
|
40
|
+
test_connector.with_connection_to(['node']) do |connected_nodes|
|
41
|
+
expect(connected_nodes).to eq ['node']
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
31
47
|
it 'creates SSH master to several nodes' do
|
32
48
|
with_test_platform(nodes: {
|
33
49
|
'node1' => { meta: { host_ip: '192.168.42.1' } },
|
@@ -52,6 +68,45 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
52
68
|
end
|
53
69
|
end
|
54
70
|
|
71
|
+
it 'creates SSH master to several nodes with ssh connections transformed' do
|
72
|
+
with_test_platform(
|
73
|
+
{ nodes: {
|
74
|
+
'node1' => { meta: { host_ip: '192.168.42.1' } },
|
75
|
+
'node2' => { meta: { host_ip: '192.168.42.2' } },
|
76
|
+
'node3' => { meta: { host_ip: '192.168.42.3' } }
|
77
|
+
} },
|
78
|
+
false,
|
79
|
+
'
|
80
|
+
for_nodes(%w[node1 node3]) do
|
81
|
+
transform_ssh_connection do |node, connection, connection_user, gateway, gateway_user|
|
82
|
+
["#{connection}_#{node}_13", "#{connection_user}_#{node}_13", "#{gateway}_#{node}_13", "#{gateway_user}_#{node}_13"]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
for_nodes(\'node1\') do
|
86
|
+
transform_ssh_connection do |node, connection, connection_user, gateway, gateway_user|
|
87
|
+
["#{connection}_#{node}_1", "#{connection_user}_#{node}_1", "#{gateway}_#{node}_1", "#{gateway_user}_#{node}_1"]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
'
|
91
|
+
) do
|
92
|
+
with_cmd_runner_mocked(
|
93
|
+
[
|
94
|
+
['which env', proc { [0, "/usr/bin/env\n", ''] }],
|
95
|
+
['ssh -V 2>&1', proc { [0, "OpenSSH_7.4p1 Debian-10+deb9u7, OpenSSL 1.0.2u 20 Dec 2019\n", ''] }]
|
96
|
+
] + ssh_expected_commands_for(
|
97
|
+
'node1' => { ip: '192.168.42.1', connection: '192.168.42.1_node1_13_node1_1', user: 'test_user_node1_13_node1_1' },
|
98
|
+
'node2' => { ip: '192.168.42.2', connection: '192.168.42.2', user: 'test_user' },
|
99
|
+
'node3' => { ip: '192.168.42.3', connection: '192.168.42.3_node3_13', user: 'test_user_node3_13' }
|
100
|
+
)
|
101
|
+
) do
|
102
|
+
test_connector.ssh_user = 'test_user'
|
103
|
+
test_connector.with_connection_to(%w[node1 node2 node3]) do |connected_nodes|
|
104
|
+
expect(connected_nodes.sort).to eq %w[node1 node2 node3].sort
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
55
110
|
it 'fails when an SSH master can\'t be created' do
|
56
111
|
with_test_platform(nodes: {
|
57
112
|
'node1' => { meta: { host_ip: '192.168.42.1' } },
|
@@ -73,7 +128,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
73
128
|
)
|
74
129
|
) do
|
75
130
|
test_connector.ssh_user = 'test_user'
|
76
|
-
expect { test_connector.with_connection_to(%w[node1 node2 node3]) }.to raise_error(/^Error while starting SSH Control Master with .+\/ssh -o BatchMode=yes -o ControlMaster=yes -o ControlPersist=yes
|
131
|
+
expect { test_connector.with_connection_to(%w[node1 node2 node3]) }.to raise_error(/^Error while starting SSH Control Master with .+\/ssh -o BatchMode=yes -o ControlMaster=yes -o ControlPersist=yes hpc.node2 true: Can't connect to 192.168.42.2$/)
|
77
132
|
end
|
78
133
|
end
|
79
134
|
end
|
@@ -416,7 +471,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
416
471
|
['ssh -V 2>&1', proc { [0, "OpenSSH_7.4p1 Debian-10+deb9u7, OpenSSL 1.0.2u 20 Dec 2019\n", ''] }],
|
417
472
|
] +
|
418
473
|
[[
|
419
|
-
/^.+\/ssh -o BatchMode=yes -o ControlMaster=yes -o ControlPersist=yes
|
474
|
+
/^.+\/ssh -o BatchMode=yes -o ControlMaster=yes -o ControlPersist=yes hpc\.node true$/,
|
420
475
|
proc do
|
421
476
|
nbr_boot_messages += 1
|
422
477
|
[255, '', "System is booting up. See pam_nologin(8)\nAuthentication failed.\n"]
|
data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/global_helpers_spec.rb
CHANGED
@@ -35,8 +35,11 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
35
35
|
begin_marker = node.nil? ? /^Host \*$/ : /^# #{Regexp.escape(node)} - .+$/
|
36
36
|
start_idx = ssh_config_lines.index { |line| line =~ begin_marker }
|
37
37
|
return nil if start_idx.nil?
|
38
|
-
|
39
|
-
|
38
|
+
end_markers = [
|
39
|
+
/^\# \w+ - .+$/,
|
40
|
+
/^\#+$/
|
41
|
+
]
|
42
|
+
end_idx = ssh_config_lines[start_idx + 1..-1].index { |line| end_markers.any? { |end_marker| line =~ end_marker } }
|
40
43
|
end_idx = end_idx.nil? ? -1 : start_idx + end_idx
|
41
44
|
ssh_config_lines[start_idx..end_idx].select do |line|
|
42
45
|
stripped_line = line.strip
|
@@ -50,7 +53,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
50
53
|
expect(ssh_config_for(nil)).to eq <<~EOS
|
51
54
|
Host *
|
52
55
|
User test_user
|
53
|
-
ControlPath #{Dir.tmpdir}/hpc_ssh/
|
56
|
+
ControlPath #{Dir.tmpdir}/hpc_ssh/hpc_ssh_mux_%h_%p_%r
|
54
57
|
PubkeyAcceptedKeyTypes +ssh-dss
|
55
58
|
EOS
|
56
59
|
end
|
@@ -62,7 +65,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
62
65
|
expect(ssh_config_for(nil)).to eq <<~EOS
|
63
66
|
Host *
|
64
67
|
User test_user
|
65
|
-
ControlPath #{Dir.tmpdir}/hpc_ssh/
|
68
|
+
ControlPath #{Dir.tmpdir}/hpc_ssh/hpc_ssh_mux_%h_%p_%r
|
66
69
|
PubkeyAcceptedKeyTypes +ssh-dss
|
67
70
|
EOS
|
68
71
|
end
|
@@ -74,7 +77,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
74
77
|
expect(ssh_config_for(nil, known_hosts_file: '/path/to/known_hosts')).to eq <<~EOS
|
75
78
|
Host *
|
76
79
|
User test_user
|
77
|
-
ControlPath #{Dir.tmpdir}/hpc_ssh/
|
80
|
+
ControlPath #{Dir.tmpdir}/hpc_ssh/hpc_ssh_mux_%h_%p_%r
|
78
81
|
PubkeyAcceptedKeyTypes +ssh-dss
|
79
82
|
UserKnownHostsFile /path/to/known_hosts
|
80
83
|
EOS
|
@@ -88,7 +91,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
88
91
|
expect(ssh_config_for(nil)).to eq <<~EOS
|
89
92
|
Host *
|
90
93
|
User test_user
|
91
|
-
ControlPath #{Dir.tmpdir}/hpc_ssh/
|
94
|
+
ControlPath #{Dir.tmpdir}/hpc_ssh/hpc_ssh_mux_%h_%p_%r
|
92
95
|
PubkeyAcceptedKeyTypes +ssh-dss
|
93
96
|
StrictHostKeyChecking no
|
94
97
|
EOS
|
@@ -153,6 +156,24 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
153
156
|
end
|
154
157
|
end
|
155
158
|
|
159
|
+
it 'generates a simple config for several nodes even when some of them can\'t be connected' do
|
160
|
+
with_test_platform(nodes: {
|
161
|
+
'node1' => { meta: { host_ip: '192.168.42.1' } },
|
162
|
+
'node2' => { meta: {} },
|
163
|
+
'node3' => { meta: { host_ip: '192.168.42.3' } }
|
164
|
+
}) do
|
165
|
+
expect(ssh_config_for('node1')).to eq <<~EOS
|
166
|
+
Host hpc.node1
|
167
|
+
Hostname 192.168.42.1
|
168
|
+
EOS
|
169
|
+
expect(ssh_config_for('node2')).to eq "\n"
|
170
|
+
expect(ssh_config_for('node3')).to eq <<~EOS
|
171
|
+
Host hpc.node3
|
172
|
+
Hostname 192.168.42.3
|
173
|
+
EOS
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
156
177
|
it 'selects nodes when generating the config' do
|
157
178
|
with_test_platform(nodes: {
|
158
179
|
'node1' => { meta: { host_ip: '192.168.42.1' } },
|
@@ -167,12 +188,6 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
167
188
|
end
|
168
189
|
end
|
169
190
|
|
170
|
-
it 'fails if a node can\'t be connected to' do
|
171
|
-
with_test_platform(nodes: { 'node' => {} }) do
|
172
|
-
expect { ssh_config_for('node') }.to raise_error(/No connection possible to node/)
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
191
|
it 'generates an alias if the node has a hostname' do
|
177
192
|
with_test_platform(nodes: { 'node' => { meta: { host_ip: '192.168.42.42', hostname: 'my_hostname.my_domain' } } }) do
|
178
193
|
expect(ssh_config_for('node')).to eq <<~EOS
|
@@ -262,6 +277,47 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
262
277
|
end
|
263
278
|
end
|
264
279
|
|
280
|
+
it 'uses node transformed SSH connection' do
|
281
|
+
with_test_platform(
|
282
|
+
{ nodes: {
|
283
|
+
'node1' => { meta: { host_ip: '192.168.42.1', gateway: 'test_gateway1', gateway_user: 'test_gateway1_user' } },
|
284
|
+
'node2' => { meta: { host_ip: '192.168.42.2', gateway: 'test_gateway2', gateway_user: 'test_gateway2_user' } },
|
285
|
+
'node3' => { meta: { host_ip: '192.168.42.3', gateway: 'test_gateway3', gateway_user: 'test_gateway3_user' } }
|
286
|
+
} },
|
287
|
+
false,
|
288
|
+
'
|
289
|
+
for_nodes(%w[node1 node3]) do
|
290
|
+
transform_ssh_connection do |node, connection, connection_user, gateway, gateway_user|
|
291
|
+
["#{connection}_#{node}_13", "#{connection_user}_#{node}_13", "#{gateway}_#{node}_13", "#{gateway_user}_#{node}_13"]
|
292
|
+
end
|
293
|
+
end
|
294
|
+
for_nodes(\'node1\') do
|
295
|
+
transform_ssh_connection do |node, connection, connection_user, gateway, gateway_user|
|
296
|
+
["#{connection}_#{node}_1", "#{connection_user}_#{node}_1", "#{gateway}_#{node}_1", "#{gateway_user}_#{node}_1"]
|
297
|
+
end
|
298
|
+
end
|
299
|
+
') do
|
300
|
+
test_connector.ssh_user = 'test_user'
|
301
|
+
expect(ssh_config_for('node1')).to eq <<~EOS
|
302
|
+
Host hpc.node1
|
303
|
+
Hostname 192.168.42.1_node1_13_node1_1
|
304
|
+
User "test_user_node1_13_node1_1"
|
305
|
+
ProxyCommand ssh -q -W %h:%p test_gateway1_user_node1_13_node1_1@test_gateway1_node1_13_node1_1
|
306
|
+
EOS
|
307
|
+
expect(ssh_config_for('node2')).to eq <<~EOS
|
308
|
+
Host hpc.node2
|
309
|
+
Hostname 192.168.42.2
|
310
|
+
ProxyCommand ssh -q -W %h:%p test_gateway2_user@test_gateway2
|
311
|
+
EOS
|
312
|
+
expect(ssh_config_for('node3')).to eq <<~EOS
|
313
|
+
Host hpc.node3
|
314
|
+
Hostname 192.168.42.3_node3_13
|
315
|
+
User "test_user_node3_13"
|
316
|
+
ProxyCommand ssh -q -W %h:%p test_gateway3_user_node3_13@test_gateway3_node3_13
|
317
|
+
EOS
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
265
321
|
it 'generates a config compatible for passwords authentication' do
|
266
322
|
with_test_platform(nodes: { 'node' => { meta: { host_ip: '192.168.42.42' } } }) do
|
267
323
|
test_connector.passwords['node'] = 'PaSsWoRd'
|