hybrid_platforms_conductor 32.5.0 → 32.7.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 834a3af157221b88e6a150738b146f90fdf832c43fe5e8471619879c47a22d5b
4
- data.tar.gz: c4f54b879fbfba923fda2a8aee1b299cb846ed9478ca9bd81535f220ec622f69
3
+ metadata.gz: 83352b7821e41bc5b0282c693c47f0cac0f5a9915a45dfa37affd3d1fcaadd8c
4
+ data.tar.gz: fba8bf35c2569716b2b8f934a46684c8b29843e50fe49b8133d3eeae580938d1
5
5
  SHA512:
6
- metadata.gz: 42ae65da627c812b096c0e9f9b4bb8c9ac4dde3185e1f6cf8d1405acbab960d5c5c88050c25e3d45906acb6054c73fd7ec29b2e5751b1ec38734f83a33f34bef
7
- data.tar.gz: 41e641381b34d9d0841770974c4401612bfc3a4d11a5ec2fe85969f40ab1bfce0952cb4bbf5b7d2fce5420d9090a4962e278b9fb84d4251e0f13ee84db405e6c
6
+ metadata.gz: 69c667f1f6c626372ecef7c21c9afdb2865a38e418ad6add2ec4d04d9a0eeda6892fed168d546d89d8805d843c31945eb885d53b0cf5208a65a7eb89ba75ea74
7
+ data.tar.gz: b9478d38660f80b7c9f62411d72d0e890e74ec509973ceb3d417721d21f5f9923ffc5dfbc96b857af6301d7bd708630638d393dc3bbf2abcd4cf7d12e22a7af6
@@ -311,13 +311,24 @@ module HybridPlatformsConductor
311
311
  environment: environment,
312
312
  logger: @logger,
313
313
  logger_stderr: @logger_stderr,
314
- config: @config,
314
+ config: sub_executable.config,
315
315
  cmd_runner: @cmd_runner,
316
316
  # Here we use the NodesHandler that will be bound to the sub-Deployer only, as the node's metadata might be modified by the Provisioner.
317
317
  nodes_handler: sub_executable.nodes_handler,
318
318
  actions_executor: @actions_executor
319
319
  )
320
320
  instance.with_running_instance(stop_on_exit: true, destroy_on_exit: !reuse_instance, port: 22) do
321
+ # Test-provisioned nodes have SSH Session Exec capabilities
322
+ sub_executable.nodes_handler.override_metadata_of node, :ssh_session_exec, 'true'
323
+ # Test-provisioned nodes use default sudo
324
+ sub_executable.config.sudo_procs.replace(sub_executable.config.sudo_procs.map do |sudo_proc_info|
325
+ {
326
+ nodes_selectors_stack: sudo_proc_info[:nodes_selectors_stack].map do |nodes_selector|
327
+ @nodes_handler.select_nodes(nodes_selector).select { |selected_node| selected_node != node }
328
+ end,
329
+ sudo_proc: sudo_proc_info[:sudo_proc]
330
+ }
331
+ end)
321
332
  actions_executor = sub_executable.actions_executor
322
333
  deployer = sub_executable.deployer
323
334
  # Setup test environment for this container
@@ -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
@@ -204,7 +233,13 @@ module HybridPlatformsConductor
204
233
  # Parameters::
205
234
  # * *bash_cmds* (String): Bash commands to execute
206
235
  def remote_bash(bash_cmds)
207
- ssh_cmd = "#{ssh_exec} #{ssh_url} /bin/bash <<'EOF'\n#{bash_cmds}\nEOF"
236
+ ssh_cmd =
237
+ if @nodes_handler.get_ssh_session_exec_of(@node) == 'false'
238
+ # When ExecSession is disabled we need to use stdin directly
239
+ "{ cat | #{ssh_exec} #{ssh_url} -T; } <<'EOF'\n#{bash_cmds}\nEOF"
240
+ else
241
+ "#{ssh_exec} #{ssh_url} /bin/bash <<'EOF'\n#{bash_cmds}\nEOF"
242
+ end
208
243
  # Due to a limitation of Process.spawn, each individual argument is limited to 128KB of size.
209
244
  # Therefore we need to make sure that if bash_cmds exceeds MAX_CMD_ARG_LENGTH bytes (considering EOF chars) then we use an intermediary shell script to store the commands.
210
245
  if bash_cmds.size > MAX_CMD_ARG_LENGTH
@@ -261,25 +296,30 @@ module HybridPlatformsConductor
261
296
  # * *owner* (String or nil): Owner to be used when copying the files, or nil for current one [default: nil]
262
297
  # * *group* (String or nil): Group to be used when copying the files, or nil for current one [default: nil]
263
298
  def remote_copy(from, to, sudo: false, owner: nil, group: nil)
264
- run_cmd <<~EOS
265
- cd #{File.dirname(from)} && \
266
- tar \
267
- --create \
268
- --gzip \
269
- --file - \
270
- #{owner.nil? ? '' : "--owner #{owner}"} \
271
- #{group.nil? ? '' : "--group #{group}"} \
272
- #{File.basename(from)} | \
273
- #{ssh_exec} \
274
- #{ssh_url} \
275
- \"#{sudo ? "#{@nodes_handler.sudo_on(@node)} " : ''}tar \
276
- --extract \
277
- --gunzip \
299
+ if @nodes_handler.get_ssh_session_exec_of(@node) == 'false'
300
+ # We don't have ExecSession, so don't use ssh, but scp instead.
301
+ run_cmd "scp -S #{ssh_exec} #{from} #{ssh_url}:#{to}"
302
+ else
303
+ run_cmd <<~EOS
304
+ cd #{File.dirname(from)} && \
305
+ tar \
306
+ --create \
307
+ --gzip \
278
308
  --file - \
279
- --directory #{to} \
280
- --owner root \
281
- \"
282
- EOS
309
+ #{owner.nil? ? '' : "--owner #{owner}"} \
310
+ #{group.nil? ? '' : "--group #{group}"} \
311
+ #{File.basename(from)} | \
312
+ #{ssh_exec} \
313
+ #{ssh_url} \
314
+ \"#{sudo ? "#{@nodes_handler.sudo_on(@node)} " : ''}tar \
315
+ --extract \
316
+ --gunzip \
317
+ --file - \
318
+ --directory #{to} \
319
+ --owner root \
320
+ \"
321
+ EOS
322
+ end
283
323
  end
284
324
 
285
325
  # Get the ssh executable to be used when connecting to the current node
@@ -295,7 +335,7 @@ module HybridPlatformsConductor
295
335
  # Result::
296
336
  # * String: The ssh URL connecting to the current node
297
337
  def ssh_url
298
- "#{@ssh_user}@hpc.#{@node}"
338
+ "hpc.#{@node}"
299
339
  end
300
340
 
301
341
  # Get an SSH configuration content giving access to nodes of the platforms with the current configuration
@@ -318,14 +358,6 @@ module HybridPlatformsConductor
318
358
  # ENDPOINTS #
319
359
  #############
320
360
 
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
361
  EOS
330
362
 
331
363
  # Add each node
@@ -333,21 +365,37 @@ module HybridPlatformsConductor
333
365
  @nodes_handler.prefetch_metadata_of nodes, %i[private_ips hostname host_ip description]
334
366
  nodes.sort.each do |node|
335
367
  # Generate the conf for the node
336
- begin
337
- connection, gateway, gateway_user = connection_info_for(node)
368
+ connection, connection_user, gateway, gateway_user = connection_info_for(node, no_exception: true)
369
+ if connection.nil?
370
+ config_content << "# #{node} - Not connectable using SSH - #{@nodes_handler.get_description_of(node) || ''}\n"
371
+ else
338
372
  config_content << "# #{node} - #{connection} - #{@nodes_handler.get_description_of(node) || ''}\n"
339
373
  config_content << "Host #{ssh_aliases_for(node).join(' ')}\n"
340
374
  config_content << " Hostname #{connection}\n"
375
+ config_content << " User \"#{connection_user}\"\n" if connection_user != @ssh_user
341
376
  config_content << " ProxyCommand #{ssh_exec} -q -W %h:%p #{gateway_user}@#{gateway}\n" unless gateway.nil?
342
377
  if @passwords.key?(node)
343
378
  config_content << " PreferredAuthentications password\n"
344
379
  config_content << " PubkeyAuthentication no\n"
345
380
  end
346
- rescue NotConnectableError
347
- config_content << "# #{node} - Not connectable using SSH - #{@nodes_handler.get_description_of(node) || ''}\n"
348
381
  end
349
382
  config_content << "\n"
350
383
  end
384
+ # Add global definitions at the end of the SSH config, as they might be overriden by previous ones, and first match wins.
385
+ config_content << <<~EOS
386
+ ###########
387
+ # GLOBALS #
388
+ ###########
389
+
390
+ Host *
391
+ User #{@ssh_user}
392
+ # Default control socket path to be used when multiplexing SSH connections
393
+ ControlPath #{control_master_file('%h', '%p', '%r')}
394
+ #{open_ssh_major_version >= 7 ? 'PubkeyAcceptedKeyTypes +ssh-dss' : ''}
395
+ #{known_hosts_file.nil? ? '' : "UserKnownHostsFile #{known_hosts_file}"}
396
+ #{@ssh_strict_host_key_checking ? '' : 'StrictHostKeyChecking no'}
397
+
398
+ EOS
351
399
  config_content
352
400
  end
353
401
 
@@ -450,34 +498,48 @@ module HybridPlatformsConductor
450
498
  with_lock_on_control_master_for(node) do |current_users, user_id|
451
499
  working_master = false
452
500
  ssh_exec = ssh_exec_for(node)
453
- ssh_url = "#{@ssh_user}@hpc.#{node}"
501
+ ssh_url = "hpc.#{node}"
454
502
  if current_users.empty?
455
503
  log_debug "[ ControlMaster - #{ssh_url} ] - Creating SSH ControlMaster..."
456
- # Create the control master
457
- ssh_control_master_start_cmd = "#{ssh_exec}#{@passwords.key?(node) || @auth_password ? '' : ' -o BatchMode=yes'} -o ControlMaster=yes -o ControlPersist=yes #{ssh_url} true"
458
504
  exit_status = nil
459
- idx_try = 0
460
- loop do
461
- stderr = nil
462
- exit_status, _stdout, stderr = @cmd_runner.run_cmd ssh_control_master_start_cmd, log_to_stdout: log_debug?, no_exception: true, timeout: timeout
463
- if exit_status == 0
464
- break
465
- elsif stderr =~ /System is booting up/
466
- if idx_try == MAX_RETRIES_FOR_BOOT
467
- if no_exception
468
- break
469
- else
470
- raise ActionsExecutor::ConnectionError, "Tried #{idx_try} times to create SSH Control Master with #{ssh_control_master_start_cmd} but system says it's booting up."
505
+ if @nodes_handler.get_ssh_session_exec_of(node) == 'false'
506
+ # Here we have to create a ControlMaster using an interactive session, as the SSH server prohibits ExecSession, and so command executions.
507
+ # We'll do that using another terminal spawned in the background.
508
+ Thread.new do
509
+ log_debug "[ ControlMaster - #{ssh_url} ] - Spawn interactive ControlMaster in separate terminal"
510
+ @cmd_runner.run_cmd "xterm -e '#{ssh_exec} -o ControlMaster=yes -o ControlPersist=yes #{ssh_url}'", log_to_stdout: log_debug?
511
+ log_debug "[ ControlMaster - #{ssh_url} ] - Separate interactive ControlMaster closed"
512
+ end
513
+ out 'External ControlMaster has been spawned.'
514
+ out 'Please login into it, keep its session opened and press enter here when done...'
515
+ $stdin.gets
516
+ exit_status = 0
517
+ else
518
+ # Create the control master
519
+ ssh_control_master_start_cmd = "#{ssh_exec}#{@passwords.key?(node) || @auth_password ? '' : ' -o BatchMode=yes'} -o ControlMaster=yes -o ControlPersist=yes #{ssh_url} true"
520
+ idx_try = 0
521
+ loop do
522
+ stderr = nil
523
+ exit_status, _stdout, stderr = @cmd_runner.run_cmd ssh_control_master_start_cmd, log_to_stdout: log_debug?, no_exception: true, timeout: timeout
524
+ if exit_status == 0
525
+ break
526
+ elsif stderr =~ /System is booting up/
527
+ if idx_try == MAX_RETRIES_FOR_BOOT
528
+ if no_exception
529
+ break
530
+ else
531
+ raise ActionsExecutor::ConnectionError, "Tried #{idx_try} times to create SSH Control Master with #{ssh_control_master_start_cmd} but system says it's booting up."
532
+ end
471
533
  end
534
+ # Wait a bit and try again
535
+ idx_try += 1
536
+ log_debug "[ ControlMaster - #{ssh_url} ] - System is booting up (try ##{idx_try}). Wait #{WAIT_TIME_FOR_BOOT} seconds before trying ControlMaster's creation again."
537
+ sleep WAIT_TIME_FOR_BOOT
538
+ elsif no_exception
539
+ break
540
+ else
541
+ raise ActionsExecutor::ConnectionError, "Error while starting SSH Control Master with #{ssh_control_master_start_cmd}: #{stderr.strip}"
472
542
  end
473
- # Wait a bit and try again
474
- idx_try += 1
475
- log_debug "[ ControlMaster - #{ssh_url} ] - System is booting up (try ##{idx_try}). Wait #{WAIT_TIME_FOR_BOOT} seconds before trying ControlMaster's creation again."
476
- sleep WAIT_TIME_FOR_BOOT
477
- elsif no_exception
478
- break
479
- else
480
- raise ActionsExecutor::ConnectionError, "Error while starting SSH Control Master with #{ssh_control_master_start_cmd}: #{stderr.strip}"
481
543
  end
482
544
  end
483
545
  if exit_status == 0
@@ -512,28 +574,33 @@ module HybridPlatformsConductor
512
574
  end
513
575
  end
514
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]} ]
515
580
  end
516
581
  yield user_locks.keys
517
582
  ensure
518
- user_locks_mutex.synchronize do
519
- user_locks.each do |node, user_id|
520
- with_lock_on_control_master_for(node, user_id: user_id) do |current_users, user_id|
521
- ssh_url = "#{@ssh_user}@hpc.#{node}"
522
- 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
- remaining_users = current_users - [user_id]
524
- if remaining_users.empty?
525
- # Stop the ControlMaster
526
- log_debug "[ ControlMaster - #{ssh_url} ] - Stopping ControlMaster..."
527
- # Dumb verbose ssh! Tricky trick to just silence what is useless.
528
- # 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.
529
- @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
530
- log_debug "[ ControlMaster - #{ssh_url} ] - ControlMaster stopped"
531
- # Uncomment if you want to test that the connection has been closed
532
- # @cmd_runner.run_cmd "#{ssh_exec_for(node)} -O check #{ssh_url}", log_to_stdout: log_debug?, expected_code: 255, timeout: timeout
533
- else
534
- 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
535
603
  end
536
- false
537
604
  end
538
605
  end
539
606
  end
@@ -562,8 +629,9 @@ module HybridPlatformsConductor
562
629
  # TODO: Add test case when control file is missing ad when it is stale
563
630
  # Get the list of existing process/thread ids using this control master
564
631
  existing_users = File.exist?(control_master_users_file) ? File.read(control_master_users_file).split("\n") : []
565
- ssh_url = "#{@ssh_user}@hpc.#{node}"
566
- control_path_file = control_master_file(connection_info_for(node).first, '22', @ssh_user)
632
+ ssh_url = "hpc.#{node}"
633
+ connection, connection_user, _gateway, _gateway_user = connection_info_for(node)
634
+ control_path_file = control_master_file(connection, '22', connection_user)
567
635
  if existing_users.empty?
568
636
  # Make sure there is no stale one.
569
637
  if File.exist?(control_path_file)
@@ -595,7 +663,7 @@ module HybridPlatformsConductor
595
663
  # * *port* (String): The port. Can be a string as ssh config uses wildchars.
596
664
  # * *user* (String): The user
597
665
  def control_master_file(host, port, user)
598
- "#{@tmp_dir}/hpc_actions_executor_mux_#{host}_#{port}_#{user}"
666
+ "#{@tmp_dir}/hpc_ssh_mux_#{host}_#{port}_#{user}"
599
667
  end
600
668
 
601
669
  # Provide a bootstrapped ssh executable that includes an SSH config allowing access to nodes.
@@ -627,7 +695,7 @@ module HybridPlatformsConductor
627
695
  nodes.sort.each do |node|
628
696
  host_keys = @nodes_handler.get_host_keys_of(node)
629
697
  if host_keys && !host_keys.empty?
630
- connection, _gateway, _gateway_user = connection_info_for(node)
698
+ connection, _connection_user, _gateway, _gateway_user = connection_info_for(node)
631
699
  host_keys.each do |host_key|
632
700
  file.puts "#{connection} #{host_key}"
633
701
  end
@@ -660,11 +728,13 @@ module HybridPlatformsConductor
660
728
  #
661
729
  # Parameters::
662
730
  # * *node* (String): The node to access
731
+ # * *no_exception* (Boolean): Should we skip exceptions in case of no connection possible? [default: false]
663
732
  # Result::
664
- # * String: The real hostname or IP to be used to connect
733
+ # * String: The real hostname or IP to be used to connect, or nil if none and no_exception is true
734
+ # * String: The real user to be used to connect, or nil if none and no_exception is true
665
735
  # * 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
736
  # * String or nil: The gateway user to be used, or nil if none.
667
- def connection_info_for(node)
737
+ def connection_info_for(node, no_exception: false)
668
738
  connection =
669
739
  if @nodes_handler.get_host_ip_of(node)
670
740
  @nodes_handler.get_host_ip_of(node)
@@ -673,12 +743,18 @@ module HybridPlatformsConductor
673
743
  elsif @nodes_handler.get_hostname_of(node)
674
744
  @nodes_handler.get_hostname_of(node)
675
745
  else
676
- raise NotConnectableError, "No connection possible to #{node}"
746
+ nil
677
747
  end
748
+ connection_user = @ssh_user
678
749
  gateway = @nodes_handler.get_gateway_of node
679
750
  gateway_user = @nodes_handler.get_gateway_user_of node
680
751
  gateway_user = @ssh_gateway_user if !gateway.nil? && gateway_user.nil?
681
- [connection, gateway, gateway_user]
752
+ # In case we want to transform the connection info, do it here.
753
+ @nodes_handler.select_confs_for_node(node, @config.ssh_connection_transforms).each do |transform_info|
754
+ connection, connection_user, gateway, gateway_user = transform_info[:transform].call(node, connection, connection_user, gateway, gateway_user)
755
+ end
756
+ raise NotConnectableError, "No connection possible to #{node}" if connection.nil? && !no_exception
757
+ [connection, connection_user, gateway, gateway_user]
682
758
  end
683
759
 
684
760
  # Get the possible SSH aliases for a given node.
@@ -54,17 +54,19 @@ module HybridPlatformsConductor
54
54
  instance.stop
55
55
  instance.with_running_instance(port: 22) do
56
56
 
57
- # ===== Deploy removes root access
58
- # Check that we can't connect with root
59
- ssh_ok = false
60
- begin
61
- Net::SSH.start(instance.ip, 'root', password: 'root_pwd', auth_methods: ['password'], verify_host_key: :never) do |ssh|
62
- ssh_ok = ssh.exec!('echo Works').strip == 'Works'
57
+ unless @nodes_handler.get_root_access_allowed_of(@node) == 'true'
58
+ # ===== Deploy removes root access
59
+ # Check that we can't connect with root
60
+ ssh_ok = false
61
+ begin
62
+ Net::SSH.start(instance.ip, 'root', password: 'root_pwd', auth_methods: ['password'], verify_host_key: :never) do |ssh|
63
+ ssh_ok = ssh.exec!('echo Works').strip == 'Works'
64
+ end
65
+ rescue
63
66
  end
64
- rescue
67
+ assert_equal ssh_ok, false, 'Root can still connect on the image after deployment'
68
+ # Even if we can connect using root, run the idempotence test
65
69
  end
66
- assert_equal ssh_ok, false, 'Root can still connect on the image after deployment'
67
- # Even if we can connect using root, run the idempotence test
68
70
 
69
71
  # ===== Idempotence
70
72
  unless ssh_ok
@@ -76,6 +76,15 @@ module HybridPlatformsConductor
76
76
  # Make sure we update it.
77
77
  @nodes_handler.override_metadata_of @node, :host_ip, instance_ip
78
78
  @nodes_handler.invalidate_metadata_of @node, :host_keys
79
+ # Make sure the SSH transformations don't apply to this node
80
+ @config.ssh_connection_transforms.replace(@config.ssh_connection_transforms.map do |ssh_transform_info|
81
+ {
82
+ nodes_selectors_stack: ssh_transform_info[:nodes_selectors_stack].map do |nodes_selector|
83
+ @nodes_handler.select_nodes(nodes_selector).select { |selected_node| selected_node != @node }
84
+ end,
85
+ transform: ssh_transform_info[:transform]
86
+ }
87
+ end)
79
88
  end
80
89
  wait_for_port!(port) if port
81
90
  yield
@@ -1,5 +1,5 @@
1
1
  module HybridPlatformsConductor
2
2
 
3
- VERSION = '32.5.0'
3
+ VERSION = '32.7.3'
4
4
 
5
5
  end