hybrid_platforms_conductor 32.4.0 → 32.7.0
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.
- 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'
|