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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 34ae09b6107332c4f51418677736cabed358f01c3e5c47ff2f5752f6c597a809
4
- data.tar.gz: 99358ffeb3d2f70819c5408c18b5b8d8e5531331da0c96073e5577f02cebcb72
3
+ metadata.gz: 04d2e323c123bfaa35c0fb61f95dcc7a9ade67b19f184eff75c61419e249ac8e
4
+ data.tar.gz: 25afb265a466103db73b891c62ec9a9ee32e5529bf8d9f0df71df379bab5ec7a
5
5
  SHA512:
6
- metadata.gz: 873851a3e54538b2915df041e9dca3decde7cbfe4f7e8b82ea7102bbe5e75668ef5d7adb828979f4eab8493245f982b3e5da0bb492c116688b9151d10bc979a2
7
- data.tar.gz: 72418b66806746d05589f08f773eb065b0811d760e35908410405f1cbd9a6fadc94aa2ec85a83ac7f314f53d6a7ebc6396460894c4f595aee9c9b0ffd65625c0
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
- user_locks_mutex.synchronize do
581
- user_locks.each do |node, user_id|
582
- with_lock_on_control_master_for(node, user_id: user_id) do |current_users, user_id|
583
- ssh_url = "hpc.#{node}"
584
- 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)
585
- remaining_users = current_users - [user_id]
586
- if remaining_users.empty?
587
- # Stop the ControlMaster
588
- log_debug "[ ControlMaster - #{ssh_url} ] - Stopping ControlMaster..."
589
- # Dumb verbose ssh! Tricky trick to just silence what is useless.
590
- # 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.
591
- @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
592
- log_debug "[ ControlMaster - #{ssh_url} ] - ControlMaster stopped"
593
- # Uncomment if you want to test that the connection has been closed
594
- # @cmd_runner.run_cmd "#{ssh_exec_for(node)} -O check #{ssh_url}", log_to_stdout: log_debug?, expected_code: 255, timeout: timeout
595
- else
596
- log_debug "[ ControlMaster - #{ssh_url} ] - Leaving ControlMaster started as #{remaining_users.size} processes/threads are still using it."
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
@@ -1,5 +1,5 @@
1
1
  module HybridPlatformsConductor
2
2
 
3
- VERSION = '32.7.0'
3
+ VERSION = '32.7.1'
4
4
 
5
5
  end
@@ -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
- 'node1' => { connection: '192.168.42.1', user: 'test_user' },
122
- 'node3' => { connection: '192.168.42.3', user: 'test_user' }
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
- expect(stderr).to eq ''
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< [String or Regexp, Proc] >): Expected commands that should be called on CmdRunner: the command name or regexp and the corresponding mocked code
12
- # * Parameters::
13
- # * Same parameters as CmdRunner@run_cmd
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.clone
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(remaining_expected_commands).to eq([]), "Expected CmdRunner commands were not run:\n#{remaining_expected_commands.map(&:first).join("\n")}"
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< [String or Regexp, Proc] >: The expected commands that should be used, and their corresponding mocked code
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 MAster will be created in another thread and the main thread waits for user input.
53
- expect($stdin).to receive(:gets) { "\n" }
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.0
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 00:00:00.000000000 Z
11
+ date: 2021-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: range_operators