hybrid_platforms_conductor 32.5.0 → 32.6.0
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 +69 -23
- 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 +41 -2
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/global_helpers_spec.rb +50 -6
- 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 +10 -10
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/{config_spec.rb → config_dsl_spec.rb} +4 -4
- data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +7 -5
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6b6259b1f05bb082b4f2c6820f74b6c90dad15f5868a311337429b80d233500
|
4
|
+
data.tar.gz: c5f58e3ba104ba2365addea64ab08c43a4fe9797430c950bf01258eb7bfcdc1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b079e89a17630ed994614bc24e76ba2154ae52fcaf3712feaaef9e823487d933d6b33b87b3aa253e8d11270d5765d061349c4a37f467e81d729d994ed1f7b72e
|
7
|
+
data.tar.gz: 4a89e197bed2c87dbc10d66d8a3f6240c68deb7c2799962be282634c3c109b653c2a66725baa5ca44e38fd0bf1ec992148720047668c1c7786bd494a8e3836e7
|
@@ -16,11 +16,40 @@ module HybridPlatformsConductor
|
|
16
16
|
|
17
17
|
module PlatformsDslSsh
|
18
18
|
|
19
|
+
# List of SSH connection transformations:
|
20
|
+
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by this rule
|
21
|
+
# * *transform* (Proc): Code called to transform SSH connection info:
|
22
|
+
# Parameters::
|
23
|
+
# * *node* (String): Node for which we transform the SSH connection
|
24
|
+
# * *connection* (String or nil): The connection host or IP, or nil if none
|
25
|
+
# * *connection_user* (String): The connection user
|
26
|
+
# * *gateway* (String or nil): The gateway name, or nil if none
|
27
|
+
# * *gateway_user* (String or nil): The gateway user, or nil if none
|
28
|
+
# Result::
|
29
|
+
# * String: The transformed connection host or IP, or nil if none
|
30
|
+
# * String: The transformed connection user
|
31
|
+
# * String or nil: The transformed gateway name, or nil if none
|
32
|
+
# * String or nil: The transformed gateway user, or nil if none
|
33
|
+
# Array< Hash<Symbol, Object> >
|
34
|
+
attr_reader :ssh_connection_transforms
|
35
|
+
|
19
36
|
# Initialize the DSL
|
20
37
|
def init_ssh
|
21
38
|
# List of gateway configurations, per gateway config name
|
22
39
|
# Hash<Symbol, String>
|
23
40
|
@gateways = {}
|
41
|
+
@ssh_connection_transforms = []
|
42
|
+
end
|
43
|
+
|
44
|
+
# Define a transformation of SSH connection.
|
45
|
+
#
|
46
|
+
# Parameters::
|
47
|
+
# * *transform* (Proc): Code to be called to transform an SSH connection (see ssh_connection_transforms signature for details)
|
48
|
+
def transform_ssh_connection(&transform)
|
49
|
+
@ssh_connection_transforms << {
|
50
|
+
nodes_selectors_stack: current_nodes_selectors_stack,
|
51
|
+
transform: transform
|
52
|
+
}
|
24
53
|
end
|
25
54
|
|
26
55
|
# Register a new gateway configuration
|
@@ -295,7 +324,7 @@ module HybridPlatformsConductor
|
|
295
324
|
# Result::
|
296
325
|
# * String: The ssh URL connecting to the current node
|
297
326
|
def ssh_url
|
298
|
-
"
|
327
|
+
"hpc.#{@node}"
|
299
328
|
end
|
300
329
|
|
301
330
|
# Get an SSH configuration content giving access to nodes of the platforms with the current configuration
|
@@ -318,14 +347,6 @@ module HybridPlatformsConductor
|
|
318
347
|
# ENDPOINTS #
|
319
348
|
#############
|
320
349
|
|
321
|
-
Host *
|
322
|
-
User #{@ssh_user}
|
323
|
-
# Default control socket path to be used when multiplexing SSH connections
|
324
|
-
ControlPath #{control_master_file('%h', '%p', '%r')}
|
325
|
-
#{open_ssh_major_version >= 7 ? 'PubkeyAcceptedKeyTypes +ssh-dss' : ''}
|
326
|
-
#{known_hosts_file.nil? ? '' : "UserKnownHostsFile #{known_hosts_file}"}
|
327
|
-
#{@ssh_strict_host_key_checking ? '' : 'StrictHostKeyChecking no'}
|
328
|
-
|
329
350
|
EOS
|
330
351
|
|
331
352
|
# Add each node
|
@@ -333,21 +354,37 @@ module HybridPlatformsConductor
|
|
333
354
|
@nodes_handler.prefetch_metadata_of nodes, %i[private_ips hostname host_ip description]
|
334
355
|
nodes.sort.each do |node|
|
335
356
|
# Generate the conf for the node
|
336
|
-
|
337
|
-
|
357
|
+
connection, connection_user, gateway, gateway_user = connection_info_for(node, no_exception: true)
|
358
|
+
if connection.nil?
|
359
|
+
config_content << "# #{node} - Not connectable using SSH - #{@nodes_handler.get_description_of(node) || ''}\n"
|
360
|
+
else
|
338
361
|
config_content << "# #{node} - #{connection} - #{@nodes_handler.get_description_of(node) || ''}\n"
|
339
362
|
config_content << "Host #{ssh_aliases_for(node).join(' ')}\n"
|
340
363
|
config_content << " Hostname #{connection}\n"
|
364
|
+
config_content << " User \"#{connection_user}\"\n" if connection_user != @ssh_user
|
341
365
|
config_content << " ProxyCommand #{ssh_exec} -q -W %h:%p #{gateway_user}@#{gateway}\n" unless gateway.nil?
|
342
366
|
if @passwords.key?(node)
|
343
367
|
config_content << " PreferredAuthentications password\n"
|
344
368
|
config_content << " PubkeyAuthentication no\n"
|
345
369
|
end
|
346
|
-
rescue NotConnectableError
|
347
|
-
config_content << "# #{node} - Not connectable using SSH - #{@nodes_handler.get_description_of(node) || ''}\n"
|
348
370
|
end
|
349
371
|
config_content << "\n"
|
350
372
|
end
|
373
|
+
# Add global definitions at the end of the SSH config, as they might be overriden by previous ones, and first match wins.
|
374
|
+
config_content << <<~EOS
|
375
|
+
###########
|
376
|
+
# GLOBALS #
|
377
|
+
###########
|
378
|
+
|
379
|
+
Host *
|
380
|
+
User #{@ssh_user}
|
381
|
+
# Default control socket path to be used when multiplexing SSH connections
|
382
|
+
ControlPath #{control_master_file('%h', '%p', '%r')}
|
383
|
+
#{open_ssh_major_version >= 7 ? 'PubkeyAcceptedKeyTypes +ssh-dss' : ''}
|
384
|
+
#{known_hosts_file.nil? ? '' : "UserKnownHostsFile #{known_hosts_file}"}
|
385
|
+
#{@ssh_strict_host_key_checking ? '' : 'StrictHostKeyChecking no'}
|
386
|
+
|
387
|
+
EOS
|
351
388
|
config_content
|
352
389
|
end
|
353
390
|
|
@@ -450,7 +487,7 @@ module HybridPlatformsConductor
|
|
450
487
|
with_lock_on_control_master_for(node) do |current_users, user_id|
|
451
488
|
working_master = false
|
452
489
|
ssh_exec = ssh_exec_for(node)
|
453
|
-
ssh_url = "
|
490
|
+
ssh_url = "hpc.#{node}"
|
454
491
|
if current_users.empty?
|
455
492
|
log_debug "[ ControlMaster - #{ssh_url} ] - Creating SSH ControlMaster..."
|
456
493
|
# Create the control master
|
@@ -518,7 +555,7 @@ module HybridPlatformsConductor
|
|
518
555
|
user_locks_mutex.synchronize do
|
519
556
|
user_locks.each do |node, user_id|
|
520
557
|
with_lock_on_control_master_for(node, user_id: user_id) do |current_users, user_id|
|
521
|
-
ssh_url = "
|
558
|
+
ssh_url = "hpc.#{node}"
|
522
559
|
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)
|
523
560
|
remaining_users = current_users - [user_id]
|
524
561
|
if remaining_users.empty?
|
@@ -562,8 +599,9 @@ module HybridPlatformsConductor
|
|
562
599
|
# TODO: Add test case when control file is missing ad when it is stale
|
563
600
|
# Get the list of existing process/thread ids using this control master
|
564
601
|
existing_users = File.exist?(control_master_users_file) ? File.read(control_master_users_file).split("\n") : []
|
565
|
-
ssh_url = "
|
566
|
-
|
602
|
+
ssh_url = "hpc.#{node}"
|
603
|
+
connection, connection_user, _gateway, _gateway_user = connection_info_for(node)
|
604
|
+
control_path_file = control_master_file(connection, '22', connection_user)
|
567
605
|
if existing_users.empty?
|
568
606
|
# Make sure there is no stale one.
|
569
607
|
if File.exist?(control_path_file)
|
@@ -595,7 +633,7 @@ module HybridPlatformsConductor
|
|
595
633
|
# * *port* (String): The port. Can be a string as ssh config uses wildchars.
|
596
634
|
# * *user* (String): The user
|
597
635
|
def control_master_file(host, port, user)
|
598
|
-
"#{@tmp_dir}/
|
636
|
+
"#{@tmp_dir}/hpc_ssh_mux_#{host}_#{port}_#{user}"
|
599
637
|
end
|
600
638
|
|
601
639
|
# Provide a bootstrapped ssh executable that includes an SSH config allowing access to nodes.
|
@@ -627,7 +665,7 @@ module HybridPlatformsConductor
|
|
627
665
|
nodes.sort.each do |node|
|
628
666
|
host_keys = @nodes_handler.get_host_keys_of(node)
|
629
667
|
if host_keys && !host_keys.empty?
|
630
|
-
connection, _gateway, _gateway_user = connection_info_for(node)
|
668
|
+
connection, _connection_user, _gateway, _gateway_user = connection_info_for(node)
|
631
669
|
host_keys.each do |host_key|
|
632
670
|
file.puts "#{connection} #{host_key}"
|
633
671
|
end
|
@@ -660,11 +698,13 @@ module HybridPlatformsConductor
|
|
660
698
|
#
|
661
699
|
# Parameters::
|
662
700
|
# * *node* (String): The node to access
|
701
|
+
# * *no_exception* (Boolean): Should we skip exceptions in case of no connection possible? [default: false]
|
663
702
|
# Result::
|
664
|
-
# * String: The real hostname or IP to be used to connect
|
703
|
+
# * String: The real hostname or IP to be used to connect, or nil if none and no_exception is true
|
704
|
+
# * String: The real user to be used to connect, or nil if none and no_exception is true
|
665
705
|
# * String or nil: The gateway name to be used (should be defined by the gateways configurations), or nil if no gateway to be used.
|
666
706
|
# * String or nil: The gateway user to be used, or nil if none.
|
667
|
-
def connection_info_for(node)
|
707
|
+
def connection_info_for(node, no_exception: false)
|
668
708
|
connection =
|
669
709
|
if @nodes_handler.get_host_ip_of(node)
|
670
710
|
@nodes_handler.get_host_ip_of(node)
|
@@ -673,12 +713,18 @@ module HybridPlatformsConductor
|
|
673
713
|
elsif @nodes_handler.get_hostname_of(node)
|
674
714
|
@nodes_handler.get_hostname_of(node)
|
675
715
|
else
|
676
|
-
|
716
|
+
nil
|
677
717
|
end
|
718
|
+
connection_user = @ssh_user
|
678
719
|
gateway = @nodes_handler.get_gateway_of node
|
679
720
|
gateway_user = @nodes_handler.get_gateway_user_of node
|
680
721
|
gateway_user = @ssh_gateway_user if !gateway.nil? && gateway_user.nil?
|
681
|
-
|
722
|
+
# In case we want to transform the connection info, do it here.
|
723
|
+
@nodes_handler.select_confs_for_node(node, @config.ssh_connection_transforms).each do |transform_info|
|
724
|
+
connection, connection_user, gateway, gateway_user = transform_info[:transform].call(node, connection, connection_user, gateway, gateway_user)
|
725
|
+
end
|
726
|
+
raise NotConnectableError, "No connection possible to #{node}" if connection.nil? && !no_exception
|
727
|
+
[connection, connection_user, gateway, gateway_user]
|
682
728
|
end
|
683
729
|
|
684
730
|
# Get the possible SSH aliases for a given node.
|
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
@@ -52,6 +52,45 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
it 'creates SSH master to several nodes with ssh connections transformed' do
|
56
|
+
with_test_platform(
|
57
|
+
{ nodes: {
|
58
|
+
'node1' => { meta: { host_ip: '192.168.42.1' } },
|
59
|
+
'node2' => { meta: { host_ip: '192.168.42.2' } },
|
60
|
+
'node3' => { meta: { host_ip: '192.168.42.3' } }
|
61
|
+
} },
|
62
|
+
false,
|
63
|
+
'
|
64
|
+
for_nodes(%w[node1 node3]) do
|
65
|
+
transform_ssh_connection do |node, connection, connection_user, gateway, gateway_user|
|
66
|
+
["#{connection}_#{node}_13", "#{connection_user}_#{node}_13", "#{gateway}_#{node}_13", "#{gateway_user}_#{node}_13"]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
for_nodes(\'node1\') do
|
70
|
+
transform_ssh_connection do |node, connection, connection_user, gateway, gateway_user|
|
71
|
+
["#{connection}_#{node}_1", "#{connection_user}_#{node}_1", "#{gateway}_#{node}_1", "#{gateway_user}_#{node}_1"]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
'
|
75
|
+
) do
|
76
|
+
with_cmd_runner_mocked(
|
77
|
+
[
|
78
|
+
['which env', proc { [0, "/usr/bin/env\n", ''] }],
|
79
|
+
['ssh -V 2>&1', proc { [0, "OpenSSH_7.4p1 Debian-10+deb9u7, OpenSSL 1.0.2u 20 Dec 2019\n", ''] }]
|
80
|
+
] + ssh_expected_commands_for(
|
81
|
+
'node1' => { ip: '192.168.42.1', connection: '192.168.42.1_node1_13_node1_1', user: 'test_user_node1_13_node1_1' },
|
82
|
+
'node2' => { ip: '192.168.42.2', connection: '192.168.42.2', user: 'test_user' },
|
83
|
+
'node3' => { ip: '192.168.42.3', connection: '192.168.42.3_node3_13', user: 'test_user_node3_13' }
|
84
|
+
)
|
85
|
+
) do
|
86
|
+
test_connector.ssh_user = 'test_user'
|
87
|
+
test_connector.with_connection_to(%w[node1 node2 node3]) do |connected_nodes|
|
88
|
+
expect(connected_nodes.sort).to eq %w[node1 node2 node3].sort
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
55
94
|
it 'fails when an SSH master can\'t be created' do
|
56
95
|
with_test_platform(nodes: {
|
57
96
|
'node1' => { meta: { host_ip: '192.168.42.1' } },
|
@@ -73,7 +112,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
73
112
|
)
|
74
113
|
) do
|
75
114
|
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
|
115
|
+
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
116
|
end
|
78
117
|
end
|
79
118
|
end
|
@@ -416,7 +455,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
416
455
|
['ssh -V 2>&1', proc { [0, "OpenSSH_7.4p1 Debian-10+deb9u7, OpenSSL 1.0.2u 20 Dec 2019\n", ''] }],
|
417
456
|
] +
|
418
457
|
[[
|
419
|
-
/^.+\/ssh -o BatchMode=yes -o ControlMaster=yes -o ControlPersist=yes
|
458
|
+
/^.+\/ssh -o BatchMode=yes -o ControlMaster=yes -o ControlPersist=yes hpc\.node true$/,
|
420
459
|
proc do
|
421
460
|
nbr_boot_messages += 1
|
422
461
|
[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
|
@@ -274,6 +277,47 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
274
277
|
end
|
275
278
|
end
|
276
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
|
+
|
277
321
|
it 'generates a config compatible for passwords authentication' do
|
278
322
|
with_test_platform(nodes: { 'node' => { meta: { host_ip: '192.168.42.42' } } }) do
|
279
323
|
test_connector.passwords['node'] = 'PaSsWoRd'
|
data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/node_helpers_spec.rb
CHANGED
@@ -13,7 +13,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
13
13
|
|
14
14
|
it 'provides an SSH URL that can be used by other processes to connect to this node' do
|
15
15
|
with_test_platform_for_remote_testing do
|
16
|
-
expect(test_connector.ssh_url).to eq '
|
16
|
+
expect(test_connector.ssh_url).to eq 'hpc.node'
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/remote_actions_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
6
6
|
|
7
7
|
it 'executes bash commands remotely' do
|
8
8
|
with_test_platform_for_remote_testing(
|
9
|
-
expected_cmds: [[/.+\/ssh
|
9
|
+
expected_cmds: [[/.+\/ssh hpc\.node \/bin\/bash <<'EOF'\nbash_cmd.bash\nEOF/, proc { [0, 'Bash commands executed on node', ''] }]],
|
10
10
|
expected_stdout: 'Bash commands executed on node'
|
11
11
|
) do
|
12
12
|
test_connector.remote_bash('bash_cmd.bash')
|
@@ -17,7 +17,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
17
17
|
with_test_platform_for_remote_testing(
|
18
18
|
expected_cmds: [
|
19
19
|
[
|
20
|
-
/.+\/ssh
|
20
|
+
/.+\/ssh hpc\.node \/bin\/bash <<'EOF'\nbash_cmd.bash\nEOF/,
|
21
21
|
proc 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
22
|
expect(timeout).to eq 5
|
23
23
|
[0, '', '']
|
@@ -33,7 +33,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
33
33
|
it 'executes interactive commands remotely' do
|
34
34
|
with_test_platform_for_remote_testing do
|
35
35
|
expect(test_connector).to receive(:system) do |cmd|
|
36
|
-
expect(cmd).to match /^.+\/ssh
|
36
|
+
expect(cmd).to match /^.+\/ssh hpc\.node$/
|
37
37
|
end
|
38
38
|
test_connector.remote_interactive
|
39
39
|
end
|
@@ -43,7 +43,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
43
43
|
with_test_platform_for_remote_testing(
|
44
44
|
expected_cmds: [
|
45
45
|
[
|
46
|
-
/cd \/path\/to && tar\s+--create\s+--gzip\s+--file -\s+src.file \| \/.+\/ssh\s+
|
46
|
+
/cd \/path\/to && tar\s+--create\s+--gzip\s+--file -\s+src.file \| \/.+\/ssh\s+hpc\.node\s+"tar\s+--extract\s+--gunzip\s+--file -\s+--directory \/remote_path\/to\/dst.dir\s+--owner root\s+"/,
|
47
47
|
proc { [0, '', ''] }
|
48
48
|
]
|
49
49
|
]
|
@@ -56,7 +56,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
56
56
|
with_test_platform_for_remote_testing(
|
57
57
|
expected_cmds: [
|
58
58
|
[
|
59
|
-
/cd \/path\/to && tar\s+--create\s+--gzip\s+--file -\s+src.file \| \/.+\/ssh\s+
|
59
|
+
/cd \/path\/to && tar\s+--create\s+--gzip\s+--file -\s+src.file \| \/.+\/ssh\s+hpc\.node\s+"tar\s+--extract\s+--gunzip\s+--file -\s+--directory \/remote_path\/to\/dst.dir\s+--owner root\s+"/,
|
60
60
|
proc 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|
|
61
61
|
expect(timeout).to eq 5
|
62
62
|
[0, '', '']
|
@@ -76,7 +76,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
76
76
|
[
|
77
77
|
/.+\/hpc_temp_cmds_.+\.sh$/,
|
78
78
|
proc do |received_cmd|
|
79
|
-
expect(File.read(received_cmd)).to match /.+\/ssh
|
79
|
+
expect(File.read(received_cmd)).to match /.+\/ssh hpc\.node \/bin\/bash <<'EOF'\n#{Regexp.escape(cmd)}\nEOF/
|
80
80
|
[0, 'Bash commands executed on node', '']
|
81
81
|
end
|
82
82
|
]
|
@@ -92,7 +92,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
92
92
|
with_test_platform_for_remote_testing(
|
93
93
|
expected_cmds: [
|
94
94
|
[
|
95
|
-
/cd \/path\/to && tar\s+--create\s+--gzip\s+--file -\s+src.file \| \/.+\/ssh\s+
|
95
|
+
/cd \/path\/to && tar\s+--create\s+--gzip\s+--file -\s+src.file \| \/.+\/ssh\s+hpc\.node\s+"sudo -u root tar\s+--extract\s+--gunzip\s+--file -\s+--directory \/remote_path\/to\/dst.dir\s+--owner root\s+"/,
|
96
96
|
proc { [0, '', ''] }
|
97
97
|
]
|
98
98
|
]
|
@@ -105,7 +105,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
105
105
|
with_test_platform_for_remote_testing(
|
106
106
|
expected_cmds: [
|
107
107
|
[
|
108
|
-
/cd \/path\/to && tar\s+--create\s+--gzip\s+--file -\s+src.file \| \/.+\/ssh\s+
|
108
|
+
/cd \/path\/to && tar\s+--create\s+--gzip\s+--file -\s+src.file \| \/.+\/ssh\s+hpc\.node\s+"other_sudo --user root tar\s+--extract\s+--gunzip\s+--file -\s+--directory \/remote_path\/to\/dst.dir\s+--owner root\s+"/,
|
109
109
|
proc { [0, '', ''] }
|
110
110
|
]
|
111
111
|
],
|
@@ -119,7 +119,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
119
119
|
with_test_platform_for_remote_testing(
|
120
120
|
expected_cmds: [
|
121
121
|
[
|
122
|
-
/cd \/path\/to && tar\s+--create\s+--gzip\s+--file -\s+--owner remote_user\s+src.file \| \/.+\/ssh\s+
|
122
|
+
/cd \/path\/to && tar\s+--create\s+--gzip\s+--file -\s+--owner remote_user\s+src.file \| \/.+\/ssh\s+hpc\.node\s+"tar\s+--extract\s+--gunzip\s+--file -\s+--directory \/remote_path\/to\/dst.dir\s+--owner root\s+"/,
|
123
123
|
proc { [0, '', ''] }
|
124
124
|
]
|
125
125
|
]
|
@@ -132,7 +132,7 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
132
132
|
with_test_platform_for_remote_testing(
|
133
133
|
expected_cmds: [
|
134
134
|
[
|
135
|
-
/cd \/path\/to && tar\s+--create\s+--gzip\s+--file -\s+--group remote_group\s+src.file \| \/.+\/ssh\s+
|
135
|
+
/cd \/path\/to && tar\s+--create\s+--gzip\s+--file -\s+--group remote_group\s+src.file \| \/.+\/ssh\s+hpc\.node\s+"tar\s+--extract\s+--gunzip\s+--file -\s+--directory \/remote_path\/to\/dst.dir\s+--owner root\s+"/,
|
136
136
|
proc { [0, '', ''] }
|
137
137
|
]
|
138
138
|
]
|
data/spec/hybrid_platforms_conductor_test/api/nodes_handler/{config_spec.rb → config_dsl_spec.rb}
RENAMED
@@ -59,10 +59,10 @@ describe HybridPlatformsConductor::NodesHandler do
|
|
59
59
|
'
|
60
60
|
) do
|
61
61
|
expect(test_config.sudo_procs.size).to eq 2
|
62
|
-
expect(test_config.sudo_procs[0][:nodes_selectors_stack]).
|
63
|
-
expect(test_config.sudo_procs[0][:sudo_proc].call('test_user')).
|
64
|
-
expect(test_config.sudo_procs[1][:nodes_selectors_stack]).
|
65
|
-
expect(test_config.sudo_procs[1][:sudo_proc].call('test_user')).
|
62
|
+
expect(test_config.sudo_procs[0][:nodes_selectors_stack]).to eq []
|
63
|
+
expect(test_config.sudo_procs[0][:sudo_proc].call('test_user')).to eq 'alt_sudo1 -p test_user'
|
64
|
+
expect(test_config.sudo_procs[1][:nodes_selectors_stack]).to eq ['node2']
|
65
|
+
expect(test_config.sudo_procs[1][:sudo_proc].call('test_user')).to eq 'alt_sudo2 -q test_user'
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
@@ -10,6 +10,7 @@ module HybridPlatformsConductorTest
|
|
10
10
|
# Parameters::
|
11
11
|
# * *nodes_connections* (Hash<String, Hash<Symbol,Object> >): Nodes' connections info, per node name:
|
12
12
|
# * *connection* (String): Connection string (fqdn, IP...) used by SSH
|
13
|
+
# * *ip* (String): IP used by SSH (can be different from connection in case of transformed SSH) [default: connection]
|
13
14
|
# * *user* (String): User used by SSH
|
14
15
|
# * *times* (Integer): Number of times this connection should be used [default: 1]
|
15
16
|
# * *control_master_create_error* (String or nil): Error to simulate during the SSH ControlMaster creation, or nil for none [default: nil]
|
@@ -33,16 +34,17 @@ module HybridPlatformsConductorTest
|
|
33
34
|
ssh_commands_once = []
|
34
35
|
ssh_commands_per_connection = []
|
35
36
|
if with_strict_host_key_checking
|
37
|
+
ip = node_connection_info[:ip] || node_connection_info[:connection]
|
36
38
|
ssh_commands_once.concat([
|
37
39
|
[
|
38
|
-
"ssh-keyscan #{
|
39
|
-
proc { [0, "#{
|
40
|
+
"ssh-keyscan #{ip}",
|
41
|
+
proc { [0, "#{ip} ssh-rsa fake_host_key_for_#{ip}", ''] }
|
40
42
|
]
|
41
43
|
])
|
42
44
|
end
|
43
45
|
if with_control_master_create
|
44
46
|
ssh_commands_per_connection << [
|
45
|
-
/^.+\/ssh #{with_batch_mode ? '-o BatchMode=yes ' : ''}-o ControlMaster=yes -o ControlPersist=yes
|
47
|
+
/^.+\/ssh #{with_batch_mode ? '-o BatchMode=yes ' : ''}-o ControlMaster=yes -o ControlPersist=yes hpc\.#{Regexp.escape(node)} true$/,
|
46
48
|
proc do
|
47
49
|
control_file = test_actions_executor.connector(:ssh).send(:control_master_file, node_connection_info[:connection], '22', node_connection_info[:user])
|
48
50
|
# Fail if the ControlMaster file already exists, as would SSH do if the file is stalled
|
@@ -60,13 +62,13 @@ module HybridPlatformsConductorTest
|
|
60
62
|
end
|
61
63
|
if with_control_master_check
|
62
64
|
ssh_commands_per_connection << [
|
63
|
-
/^.+\/ssh -O check
|
65
|
+
/^.+\/ssh -O check hpc\.#{Regexp.escape(node)}$/,
|
64
66
|
proc { [0, '', ''] }
|
65
67
|
]
|
66
68
|
end
|
67
69
|
if with_control_master_destroy
|
68
70
|
ssh_commands_per_connection << [
|
69
|
-
/^.+\/ssh -O exit
|
71
|
+
/^.+\/ssh -O exit hpc\.#{Regexp.escape(node)} 2>&1 \| grep -v 'Exit request sent\.'$/,
|
70
72
|
proc do
|
71
73
|
# Really mock the control file deletion
|
72
74
|
File.unlink(test_actions_executor.connector(:ssh).send(:control_master_file, node_connection_info[:connection], '22', node_connection_info[:user]))
|
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.
|
4
|
+
version: 32.6.0
|
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-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: range_operators
|
@@ -463,7 +463,7 @@ files:
|
|
463
463
|
- spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/platform_handlers_spec.rb
|
464
464
|
- spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs_plugins_api_spec.rb
|
465
465
|
- spec/hybrid_platforms_conductor_test/api/nodes_handler/common_spec.rb
|
466
|
-
- spec/hybrid_platforms_conductor_test/api/nodes_handler/
|
466
|
+
- spec/hybrid_platforms_conductor_test/api/nodes_handler/config_dsl_spec.rb
|
467
467
|
- spec/hybrid_platforms_conductor_test/api/nodes_handler/git_diff_impacts_spec.rb
|
468
468
|
- spec/hybrid_platforms_conductor_test/api/nodes_handler/nodes_selectors_spec.rb
|
469
469
|
- spec/hybrid_platforms_conductor_test/api/nodes_handler/platform_handlers_plugins_api_spec.rb
|