hybrid_platforms_conductor 32.7.0 → 32.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +23 -18
- data/lib/hybrid_platforms_conductor/version.rb +1 -1
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb +8 -3
- data/spec/hybrid_platforms_conductor_test/executables/options/common_spec.rb +2 -1
- data/spec/hybrid_platforms_conductor_test/helpers/cmd_runner_helpers.rb +24 -6
- data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +15 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04d2e323c123bfaa35c0fb61f95dcc7a9ade67b19f184eff75c61419e249ac8e
|
4
|
+
data.tar.gz: 25afb265a466103db73b891c62ec9a9ee32e5529bf8d9f0df71df379bab5ec7a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d8112983393928123c7f8f35395506c4ec5e401e84577e3ab1e24380ab0cd92affd90b6be0cb75645314d06cc8350cd8c478e1d1b9e3c600143296bdec73af47
|
7
|
+
data.tar.gz: 6177c45b5489b077ee2d3e6d7535d6c07e94715c755c282ea8dc424e54d35ac1603c4be9d2e2d9b4cbfc4f450463c792a3e449f6dbbc5eb6bba4a0161c695c65
|
@@ -574,28 +574,33 @@ module HybridPlatformsConductor
|
|
574
574
|
end
|
575
575
|
end
|
576
576
|
end
|
577
|
+
else
|
578
|
+
# We have not created any ControlMaster, but still consider the nodes to be ready to connect
|
579
|
+
user_locks = Hash[nodes.map { |node| [node, nil]} ]
|
577
580
|
end
|
578
581
|
yield user_locks.keys
|
579
582
|
ensure
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
583
|
+
if @ssh_use_control_master
|
584
|
+
user_locks_mutex.synchronize do
|
585
|
+
user_locks.each do |node, user_id|
|
586
|
+
with_lock_on_control_master_for(node, user_id: user_id) do |current_users, user_id|
|
587
|
+
ssh_url = "hpc.#{node}"
|
588
|
+
log_warn "[ ControlMaster - #{ssh_url} ] - Current process/thread was not part of the ControlMaster users anymore whereas it should have been" unless current_users.include?(user_id)
|
589
|
+
remaining_users = current_users - [user_id]
|
590
|
+
if remaining_users.empty?
|
591
|
+
# Stop the ControlMaster
|
592
|
+
log_debug "[ ControlMaster - #{ssh_url} ] - Stopping ControlMaster..."
|
593
|
+
# Dumb verbose ssh! Tricky trick to just silence what is useless.
|
594
|
+
# Don't fail if the connection close fails (but still log the error), as it can be seen as only a warning: it means the connection was closed anyway.
|
595
|
+
@cmd_runner.run_cmd "#{ssh_exec_for(node)} -O exit #{ssh_url} 2>&1 | grep -v 'Exit request sent.'", log_to_stdout: log_debug?, expected_code: 1, timeout: timeout, no_exception: true
|
596
|
+
log_debug "[ ControlMaster - #{ssh_url} ] - ControlMaster stopped"
|
597
|
+
# Uncomment if you want to test that the connection has been closed
|
598
|
+
# @cmd_runner.run_cmd "#{ssh_exec_for(node)} -O check #{ssh_url}", log_to_stdout: log_debug?, expected_code: 255, timeout: timeout
|
599
|
+
else
|
600
|
+
log_debug "[ ControlMaster - #{ssh_url} ] - Leaving ControlMaster started as #{remaining_users.size} processes/threads are still using it."
|
601
|
+
end
|
602
|
+
false
|
597
603
|
end
|
598
|
-
false
|
599
604
|
end
|
600
605
|
end
|
601
606
|
end
|
data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb
CHANGED
@@ -118,8 +118,12 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
118
118
|
['which env', proc { [0, "/usr/bin/env\n", ''] }],
|
119
119
|
['ssh -V 2>&1', proc { [0, "OpenSSH_7.4p1 Debian-10+deb9u7, OpenSSL 1.0.2u 20 Dec 2019\n", ''] }]
|
120
120
|
] + ssh_expected_commands_for(
|
121
|
-
|
122
|
-
|
121
|
+
{
|
122
|
+
'node1' => { connection: '192.168.42.1', user: 'test_user' },
|
123
|
+
'node3' => { connection: '192.168.42.3', user: 'test_user' }
|
124
|
+
},
|
125
|
+
# Here the threads for node1's and node3's ControlMasters might not trigger before the one for node2, so they will not destroy it.
|
126
|
+
with_control_master_destroy_optional: true
|
123
127
|
) + ssh_expected_commands_for(
|
124
128
|
{
|
125
129
|
'node2' => { connection: '192.168.42.2', user: 'test_user', control_master_create_error: 'Can\'t connect to 192.168.42.2' }
|
@@ -294,7 +298,8 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
294
298
|
) do
|
295
299
|
test_connector.ssh_use_control_master = false
|
296
300
|
test_connector.ssh_user = 'test_user'
|
297
|
-
test_connector.with_connection_to(['node']) do
|
301
|
+
test_connector.with_connection_to(['node']) do |connected_nodes|
|
302
|
+
expect(connected_nodes).to eq %w[node]
|
298
303
|
end
|
299
304
|
end
|
300
305
|
end
|
@@ -50,7 +50,8 @@ describe 'executables\' common options' do
|
|
50
50
|
with_test_platform_for_common_options do
|
51
51
|
exit_code, stdout, stderr = run executable, *(['--debug'] + default_options)
|
52
52
|
expect(exit_code).to eq 0
|
53
|
-
|
53
|
+
# Make sure to ignore the deployment markers from stderr.
|
54
|
+
expect(stderr.gsub("===== [ node1 / node1_service ] - HPC Service Check ===== Begin\n===== [ node1 / node1_service ] - HPC Service Check ===== End\n", '')).to eq ''
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
@@ -8,13 +8,27 @@ module HybridPlatformsConductorTest
|
|
8
8
|
# Run expectations on the expected commands to be called.
|
9
9
|
#
|
10
10
|
# Parameters::
|
11
|
-
# * *commands* (Array<
|
12
|
-
# *
|
13
|
-
#
|
11
|
+
# * *commands* (Array<Array>): List of expected commands that should be called on CmdRunner. Each specification is a list containing those items:
|
12
|
+
# * *0* (String or Regexp): The command name or regexp matching the command name
|
13
|
+
# * *1* (Proc): The mocking code to be called in place of the real command:
|
14
|
+
# * Parameters::
|
15
|
+
# * Same parameters as CmdRunner@run_cmd
|
16
|
+
# * Result::
|
17
|
+
# * Same results as CmdRunner@run_cmd
|
18
|
+
# * *2* (Hash): Optional hash of options. Can be ommited. [default = {}]
|
19
|
+
# * *optional* (Boolean): If true then don't fail if the command to be mocked has not been called [default: false]
|
14
20
|
# * *cmd_runner* (CmdRunner): The CmdRunner to mock [default: test_cmd_runner]
|
15
21
|
# * Proc: Code called with the command runner mocked
|
16
22
|
def with_cmd_runner_mocked(commands, cmd_runner: test_cmd_runner)
|
17
|
-
remaining_expected_commands = commands.
|
23
|
+
remaining_expected_commands = commands.map do |(expected_command, command_code, options)|
|
24
|
+
[
|
25
|
+
expected_command,
|
26
|
+
command_code,
|
27
|
+
{
|
28
|
+
optional: false
|
29
|
+
}.merge(options || {})
|
30
|
+
]
|
31
|
+
end
|
18
32
|
# We need to protect the access to this array as the mocked commands can be called by competing threads
|
19
33
|
remaining_expected_commands_mutex = Mutex.new
|
20
34
|
allow(cmd_runner).to receive(:run_cmd) do |cmd, log_to_file: nil, log_to_stdout: true, log_stdout_to_io: nil, log_stderr_to_io: nil, expected_code: 0, timeout: nil, no_exception: false|
|
@@ -22,7 +36,7 @@ module HybridPlatformsConductorTest
|
|
22
36
|
found_command = nil
|
23
37
|
found_command_code = nil
|
24
38
|
remaining_expected_commands_mutex.synchronize do
|
25
|
-
remaining_expected_commands.delete_if do |(expected_command, command_code)|
|
39
|
+
remaining_expected_commands.delete_if do |(expected_command, command_code, _options)|
|
26
40
|
break unless found_command.nil?
|
27
41
|
if (expected_command.is_a?(String) && expected_command == cmd) || (expected_command.is_a?(Regexp) && cmd =~ expected_command)
|
28
42
|
found_command = expected_command
|
@@ -67,7 +81,11 @@ module HybridPlatformsConductorTest
|
|
67
81
|
end
|
68
82
|
end
|
69
83
|
yield
|
70
|
-
expect(
|
84
|
+
expect(
|
85
|
+
remaining_expected_commands.select do |(_expected_command, _command_code, options)|
|
86
|
+
!options[:optional]
|
87
|
+
end
|
88
|
+
).to eq([]), "Expected CmdRunner commands were not run:\n#{remaining_expected_commands.map(&:first).join("\n")}"
|
71
89
|
# Un-mock the command runner
|
72
90
|
allow(cmd_runner).to receive(:run_cmd).and_call_original
|
73
91
|
end
|
@@ -17,16 +17,18 @@ module HybridPlatformsConductorTest
|
|
17
17
|
# * *with_control_master_create* (Boolean): Do we create the control master? [default: true]
|
18
18
|
# * *with_control_master_check* (Boolean): Do we check the control master? [default: false]
|
19
19
|
# * *with_control_master_destroy* (Boolean): Do we destroy the control master? [default: true]
|
20
|
+
# * *with_control_master_destroy_optional* (Boolean): If true, then consider the ControlMaster destruction to be optional [default: false]
|
20
21
|
# * *with_strict_host_key_checking* (Boolean): Do we use strict host key checking? [default: true]
|
21
22
|
# * *with_batch_mode* (Boolean): Do we use BatchMode when creating the control master? [default: true]
|
22
23
|
# * *with_session_exec* (Boolean): Do we use Sessien Exec capabilities when creating the control master? [default: true]
|
23
24
|
# Result::
|
24
|
-
# * Array<
|
25
|
+
# * Array<Array>: The expected commands that should be used, and their corresponding mocked code and options
|
25
26
|
def ssh_expected_commands_for(
|
26
27
|
nodes_connections,
|
27
28
|
with_control_master_create: true,
|
28
29
|
with_control_master_check: false,
|
29
30
|
with_control_master_destroy: true,
|
31
|
+
with_control_master_destroy_optional: false,
|
30
32
|
with_strict_host_key_checking: true,
|
31
33
|
with_batch_mode: true,
|
32
34
|
with_session_exec: true
|
@@ -45,12 +47,19 @@ module HybridPlatformsConductorTest
|
|
45
47
|
])
|
46
48
|
end
|
47
49
|
if with_control_master_create
|
50
|
+
control_master_created = false
|
48
51
|
ssh_commands_per_connection << [
|
49
52
|
if with_session_exec
|
50
53
|
/^.+\/ssh #{with_batch_mode ? '-o BatchMode=yes ' : ''}-o ControlMaster=yes -o ControlPersist=yes hpc\.#{Regexp.escape(node)} true$/
|
51
54
|
else
|
52
|
-
# Mock the user hitting enter as the Control
|
53
|
-
expect($stdin).to receive(:gets)
|
55
|
+
# Mock the user hitting enter as the Control Master will be created in another thread and the main thread waits for user input.
|
56
|
+
expect($stdin).to receive(:gets) do
|
57
|
+
# We have to wait for the Control Master creation thread to actually create the Control Master before hitting Enter.
|
58
|
+
while !control_master_created do
|
59
|
+
sleep 0.1
|
60
|
+
end
|
61
|
+
"\n"
|
62
|
+
end
|
54
63
|
/^xterm -e '.+\/ssh -o ControlMaster=yes -o ControlPersist=yes hpc\.#{Regexp.escape(node)}'$/
|
55
64
|
end,
|
56
65
|
proc do
|
@@ -61,6 +70,7 @@ module HybridPlatformsConductorTest
|
|
61
70
|
elsif node_connection_info[:control_master_create_error].nil?
|
62
71
|
# Really touch a fake control file, as ssh connector checks for its existence
|
63
72
|
File.write(control_file, '')
|
73
|
+
control_master_created = true
|
64
74
|
# If there is no Session Exec, this is done in a separate thread.
|
65
75
|
# So keep it alive until the user wants to stop it (which is done using an ssh -O exit command).
|
66
76
|
loop { sleep 0.1 } unless with_session_exec
|
@@ -84,7 +94,8 @@ module HybridPlatformsConductorTest
|
|
84
94
|
# Really mock the control file deletion
|
85
95
|
File.unlink(test_actions_executor.connector(:ssh).send(:control_master_file, node_connection_info[:connection], '22', node_connection_info[:user]))
|
86
96
|
[1, '', '']
|
87
|
-
end
|
97
|
+
end,
|
98
|
+
{ optional: with_control_master_destroy_optional }
|
88
99
|
]
|
89
100
|
end
|
90
101
|
ssh_commands_once + ssh_commands_per_connection * node_connection_info[:times]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hybrid_platforms_conductor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 32.7.
|
4
|
+
version: 32.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Muriel Salvan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-03-
|
11
|
+
date: 2021-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: range_operators
|