hybrid_platforms_conductor 32.5.0 → 32.6.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/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
|