hybrid_platforms_conductor 32.7.0 → 32.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|