hybrid_platforms_conductor 33.5.1 → 33.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -0
- data/README.md +2 -0
- data/docs/plugins/cmdb/host_keys.md +3 -1
- data/docs/plugins/connector/ssh.md +1 -0
- data/lib/hybrid_platforms_conductor/config.rb +2 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/host_keys.rb +13 -12
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +4 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb +23 -13
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/docker.rb +2 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +1 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_deploy_and_idempotence.rb +17 -3
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_removes_root_access.rb +30 -10
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/idempotence.rb +1 -1
- data/lib/hybrid_platforms_conductor/version.rb +1 -1
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb +30 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/global_helpers_spec.rb +10 -0
- data/spec/hybrid_platforms_conductor_test/api/config_spec.rb +11 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/host_keys_spec.rb +49 -10
- data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/services_deployment_spec.rb +26 -16
- data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +5 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 143014298b9351f34fdfa3d4e69e0c91a918c3f6c6ed8faa9348cc36380e43e2
|
4
|
+
data.tar.gz: aa78731557e9650d06780a4b1505b28c206476b111d9f42171e4cab4cc46b829
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b13deb407182b0ef9bbb3ea5cb513938acf57b9773aa28c4c43088d972b1b668f1ded6c46067bfe8c9544c67bb2ce596750c7f211389bd1ffc32039aef1e5511
|
7
|
+
data.tar.gz: f5f11ed1bc6d675478778c6fb66af5a90e7e06e0a61f73b6683782f960492339002f93f3e6ce9e37ad4bc2f690a31e2529044fda6a8787a8db15e81611323518
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,50 @@
|
|
1
|
+
# [v33.7.2](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.7.1...v33.7.2) (2021-07-15 14:37:59)
|
2
|
+
|
3
|
+
## Global changes
|
4
|
+
### Patches
|
5
|
+
|
6
|
+
* [[Hotfix(provisioner_docker)] Increase Futex timeout to cope with image building time](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/52a03adbfc176f49800793acb3ab28026eb56289)
|
7
|
+
|
8
|
+
## Changes for provisioner_docker
|
9
|
+
### Patches
|
10
|
+
|
11
|
+
* [[Hotfix(provisioner_docker)] Increase Futex timeout to cope with image building time](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/52a03adbfc176f49800793acb3ab28026eb56289)
|
12
|
+
|
13
|
+
# [v33.7.1](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.7.0...v33.7.1) (2021-07-09 17:17:18)
|
14
|
+
|
15
|
+
## Global changes
|
16
|
+
### Patches
|
17
|
+
|
18
|
+
* [[Bugfix(platform_handler_serverless_chef)] [#93] Make sure chef runs use colors in their output](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/14352425115cf46b92e4c747b2e34e3734314288)
|
19
|
+
|
20
|
+
## Changes for platform_handler_serverless_chef
|
21
|
+
### Patches
|
22
|
+
|
23
|
+
* [[Bugfix(platform_handler_serverless_chef)] [#93] Make sure chef runs use colors in their output](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/14352425115cf46b92e4c747b2e34e3734314288)
|
24
|
+
|
25
|
+
# [v33.7.0](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.6.0...v33.7.0) (2021-07-09 16:32:25)
|
26
|
+
|
27
|
+
### Features
|
28
|
+
|
29
|
+
* [[Feature] [#91] Expose log_debug? method to the config DSL to adapt configuration in case we are in debug mode](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/87f6f51df2d20c7861f9ddd59a8d7f68c27cdd74)
|
30
|
+
|
31
|
+
# [v33.6.0](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.5.1...v33.6.0) (2021-07-07 15:45:12)
|
32
|
+
|
33
|
+
## Global changes
|
34
|
+
### Patches
|
35
|
+
|
36
|
+
* [[Feature(connector_ssh)] [Feature(cmdb_host_keys)] [#78] Way to configure the SSH port being used with the ssh_port metadata](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/f1be319eae30eedcf7f901d3ce0a14f6f4d1f2ea)
|
37
|
+
|
38
|
+
## Changes for cmdb_host_keys
|
39
|
+
### Features
|
40
|
+
|
41
|
+
* [[Feature(connector_ssh)] [Feature(cmdb_host_keys)] [#78] Way to configure the SSH port being used with the ssh_port metadata](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/f1be319eae30eedcf7f901d3ce0a14f6f4d1f2ea)
|
42
|
+
|
43
|
+
## Changes for connector_ssh
|
44
|
+
### Features
|
45
|
+
|
46
|
+
* [[Feature(connector_ssh)] [Feature(cmdb_host_keys)] [#78] Way to configure the SSH port being used with the ssh_port metadata](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/f1be319eae30eedcf7f901d3ce0a14f6f4d1f2ea)
|
47
|
+
|
1
48
|
# [v33.5.1](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.5.0...v33.5.1) (2021-07-07 12:01:32)
|
2
49
|
|
3
50
|
### Patches
|
data/README.md
CHANGED
@@ -84,9 +84,11 @@ Here are the various plugin categories:
|
|
84
84
|
* **[Actions](docs/plugins/action)** implement a given **action**. For example: bash code execution, ruby code execution, file transfer...
|
85
85
|
* **[Cmdbs](docs/plugins/cmdb)** parse **metadata** from various sources. For example: a database, Chef/Ansible inventory files, a configuration management database such as Consul...
|
86
86
|
* **[Connectors](docs/plugins/connector)** give ways to execute commands and transfer files on **nodes**. For example: using an SSH connection, a CLI for a Cloud provider...
|
87
|
+
* **[Logs](docs/plugins/log)** handle any deployment log storage strategy. They take deployment logs and send them wherever the plugins want.
|
87
88
|
* **[Platform handlers](docs/plugins/platform_handler)** handle any **platform** of a given **platform type**. They read **nodes**' inventory and **services** from **platforms**, and provide **actions** to deploy a **service** on a **node**.
|
88
89
|
* **[Provisioners](docs/plugins/provisioner)** provision (create, destroy, start, stop...) **nodes**. For example: using OpenShift, Proxmox, Docker, Podman...
|
89
90
|
* **[Reports](docs/plugins/report)** gather **platforms** and **nodes**' inventory information and publish them to some medium. For example: on command line, as a JSON file, on a content management system like Confluence or Mediawiki...
|
91
|
+
* **[Secrets readers](docs/plugins/secrets_reader)** reads secrets from various sources (vaults, APIs, local files...).
|
90
92
|
* **[Tests](docs/plugins/test)** define tests to be performed on **platforms** and **nodes**.
|
91
93
|
* **[Tests reports](docs/plugins/test_report)** publish tests results to some medium. For example: on command line, as a JSON file, on a content management system like Confluence or Mediawiki...
|
92
94
|
|
@@ -21,7 +21,9 @@ None
|
|
21
21
|
|
22
22
|
| Metadata | Type | Usage
|
23
23
|
| --- | --- | --- |
|
24
|
-
| `
|
24
|
+
| `host_ip` | `String` | Used to perform the `ssh-keyscan` |
|
25
|
+
| `hostname` | `String` | Used in place of the `host_ip` in case `host_ip` is not available |
|
26
|
+
| `ssh_port` | `Integer` | Port on which the `ssh-keyscan` will be performed (default: 22) |
|
25
27
|
|
26
28
|
## Used environment variables
|
27
29
|
|
@@ -70,6 +70,7 @@ end
|
|
70
70
|
| `host_keys` | `Array<String>` | The node's host keys used to generate a `known_hosts` file with those to avoid user confirmations when connecting. |
|
71
71
|
| `hostname` | `String` | Host name used to connect in case no IP address can be found in metadata. |
|
72
72
|
| `private_ips` | `Array<String>` | IP list to connect in case `host_ip` is not defined in metadata. |
|
73
|
+
| `ssh_port` | `Integer` | Port used to connect to SSH (default: 22). |
|
73
74
|
| `ssh_session_exec` | `Boolean` | If set to `false`, then consider that the node does not have any SSH SessionExec capabilities. This will make sure that remote command executions is done using stdin piping on interactive sessions instead of SSH commands execution. |
|
74
75
|
|
75
76
|
## Used environment variables
|
@@ -24,7 +24,7 @@ module HybridPlatformsConductor
|
|
24
24
|
# * Hash<Symbol, Symbol or Array<Symbol> >: The list of necessary properties (or single one) that should be set, per property name (:others can also be used here)
|
25
25
|
def property_dependencies
|
26
26
|
{
|
27
|
-
host_keys: %i[hostname host_ip]
|
27
|
+
host_keys: %i[hostname host_ip ssh_port]
|
28
28
|
}
|
29
29
|
end
|
30
30
|
|
@@ -41,19 +41,20 @@ module HybridPlatformsConductor
|
|
41
41
|
# Nodes for which the property can't be fetched can be ommitted.
|
42
42
|
def get_host_keys(_nodes, metadata)
|
43
43
|
updated_metadata = {}
|
44
|
-
# Get the list of nodes, per hostname (just in case several nodes share the same hostname)
|
45
|
-
# Hash<String, Array<String> >
|
44
|
+
# Get the list of nodes, per [hostname, port] (just in case several nodes share the same hostname and port)
|
45
|
+
# Hash<[String, Integer], Array<String> >
|
46
46
|
hostnames = Hash.new { |hash, key| hash[key] = [] }
|
47
47
|
metadata.each do |node, node_metadata|
|
48
|
+
ssh_port = node_metadata[:ssh_port] || 22
|
48
49
|
if node_metadata[:host_ip]
|
49
|
-
hostnames[node_metadata[:host_ip]] << node
|
50
|
+
hostnames[[node_metadata[:host_ip], ssh_port]] << node
|
50
51
|
elsif node_metadata[:hostname]
|
51
|
-
hostnames[node_metadata[:hostname]] << node
|
52
|
+
hostnames[[node_metadata[:hostname], ssh_port]] << node
|
52
53
|
end
|
53
54
|
end
|
54
55
|
unless hostnames.empty?
|
55
|
-
host_keys_for(*hostnames.keys).each do |
|
56
|
-
hostnames[
|
56
|
+
host_keys_for(*hostnames.keys).each do |host_id, ip|
|
57
|
+
hostnames[host_id].each do |node|
|
57
58
|
updated_metadata[node] = ip
|
58
59
|
end
|
59
60
|
end
|
@@ -71,7 +72,7 @@ module HybridPlatformsConductor
|
|
71
72
|
# Discover the host keys associated to a list of hosts.
|
72
73
|
#
|
73
74
|
# Parameters::
|
74
|
-
# * *hosts* (Array<String>): The hosts to check for
|
75
|
+
# * *hosts* (Array<[String, Integer]>): The hosts to check for ([hostname, port])
|
75
76
|
# Result::
|
76
77
|
# * Hash<String, Array<String> >: The corresponding host keys, per host name
|
77
78
|
def host_keys_for(*hosts)
|
@@ -82,9 +83,9 @@ module HybridPlatformsConductor
|
|
82
83
|
parallel: true,
|
83
84
|
nbr_threads_max: MAX_THREADS_SSH_KEY_SCAN,
|
84
85
|
progress: log_debug? ? 'Gather host keys' : nil
|
85
|
-
) do |host|
|
86
|
+
) do |(host, ssh_port)|
|
86
87
|
exit_status, stdout, _stderr = @cmd_runner.run_cmd(
|
87
|
-
"ssh-keyscan #{host}",
|
88
|
+
"ssh-keyscan -p #{ssh_port} #{host}",
|
88
89
|
timeout: TIMEOUT_SSH_KEYSCAN,
|
89
90
|
log_to_stdout: log_debug?,
|
90
91
|
no_exception: true
|
@@ -97,9 +98,9 @@ module HybridPlatformsConductor
|
|
97
98
|
found_keys << "#{type} #{key}"
|
98
99
|
end
|
99
100
|
end
|
100
|
-
results[host] = found_keys.sort unless found_keys.empty?
|
101
|
+
results[[host, ssh_port]] = found_keys.sort unless found_keys.empty?
|
101
102
|
else
|
102
|
-
log_warn "Unable to get host key for #{host}. Ignoring it. Accessing #{host} might require manual acceptance of its host key."
|
103
|
+
log_warn "Unable to get host key for #{host} (port #{ssh_port}). Ignoring it. Accessing #{host} might require manual acceptance of its host key."
|
103
104
|
end
|
104
105
|
end
|
105
106
|
results
|
@@ -384,16 +384,18 @@ module HybridPlatformsConductor
|
|
384
384
|
|
385
385
|
# Add each node
|
386
386
|
# Query for the metadata of all nodes at once
|
387
|
-
@nodes_handler.prefetch_metadata_of nodes, %i[private_ips hostname host_ip description]
|
387
|
+
@nodes_handler.prefetch_metadata_of nodes, %i[private_ips hostname host_ip description ssh_port]
|
388
388
|
nodes.sort.each do |node|
|
389
389
|
# Generate the conf for the node
|
390
390
|
connection, connection_user, gateway, gateway_user = connection_info_for(node, no_exception: true)
|
391
391
|
if connection.nil?
|
392
392
|
config_content << "# #{node} - Not connectable using SSH - #{@nodes_handler.get_description_of(node) || ''}\n"
|
393
393
|
else
|
394
|
+
ssh_port = @nodes_handler.get_ssh_port_of(node)
|
394
395
|
config_content << "# #{node} - #{connection} - #{@nodes_handler.get_description_of(node) || ''}\n"
|
395
396
|
config_content << "Host #{ssh_aliases_for(node).join(' ')}\n"
|
396
397
|
config_content << " Hostname #{connection}\n"
|
398
|
+
config_content << " Port #{ssh_port}\n" unless ssh_port.nil?
|
397
399
|
config_content << " User \"#{connection_user}\"\n" if connection_user != @ssh_user
|
398
400
|
config_content << " ProxyCommand #{ssh_exec} -q -W %h:%p #{gateway_user}@#{gateway}\n" unless gateway.nil?
|
399
401
|
if @passwords.key?(node)
|
@@ -658,7 +660,7 @@ module HybridPlatformsConductor
|
|
658
660
|
existing_users = File.exist?(control_master_users_file) ? File.read(control_master_users_file).split("\n") : []
|
659
661
|
ssh_url = "hpc.#{node}"
|
660
662
|
connection, connection_user, _gateway, _gateway_user = connection_info_for(node)
|
661
|
-
control_path_file = control_master_file(connection,
|
663
|
+
control_path_file = control_master_file(connection, @nodes_handler.get_ssh_port_of(node) || 22, connection_user)
|
662
664
|
if existing_users.empty?
|
663
665
|
# Make sure there is no stale one.
|
664
666
|
if File.exist?(control_path_file)
|
@@ -241,18 +241,25 @@ module HybridPlatformsConductor
|
|
241
241
|
'--json-attributes', "nodes/#{node}.json"
|
242
242
|
]
|
243
243
|
client_options << '--why-run' if use_why_run
|
244
|
+
# client_options.concat ['--log_level', 'debug'] if log_debug?
|
245
|
+
# Force setting of TERM variable and usage of unbuffer to get colored output from chef-client even if executed through a non-interactive SSH session.
|
246
|
+
client_env = {
|
247
|
+
'SSL_CERT_DIR' => '/etc/ssl/certs',
|
248
|
+
'TERM' => 'xterm-256color'
|
249
|
+
}
|
244
250
|
if @nodes_handler.get_use_local_chef_of(node)
|
245
251
|
# Just run the chef-client directly from the packaged repository
|
246
|
-
sudo_prefix = @cmd_runner.root? ? '' : 'sudo '
|
252
|
+
sudo_prefix = @cmd_runner.root? ? '' : 'sudo -E '
|
247
253
|
[
|
248
254
|
{
|
249
255
|
bash: [
|
250
256
|
'set -e',
|
251
257
|
"cd #{package_dir}"
|
252
258
|
] +
|
253
|
-
|
259
|
+
client_env.map { |var_name, value| "export #{var_name}=#{value}" } +
|
260
|
+
gems_to_install.map { |(gem_name, gem_version)| "#{sudo_prefix}/opt/chef-workstation/bin/chef gem install #{gem_name} --version \"#{gem_version}\"" } +
|
254
261
|
[
|
255
|
-
"#{sudo_prefix}
|
262
|
+
"#{sudo_prefix}/opt/chef-workstation/bin/chef-client #{client_options.join(' ')}"
|
256
263
|
]
|
257
264
|
}
|
258
265
|
]
|
@@ -270,7 +277,7 @@ module HybridPlatformsConductor
|
|
270
277
|
remote_bash: [
|
271
278
|
'set -e',
|
272
279
|
'set -o pipefail',
|
273
|
-
"if [ -n \"$(command -v apt)\" ]; then #{sudo}apt update && #{sudo}apt install -y curl build-essential ; else #{sudo}yum groupinstall 'Development Tools' && #{sudo}yum install -y curl ; fi",
|
280
|
+
"if [ -n \"$(command -v apt)\" ]; then #{sudo}apt update && #{sudo}apt install -y curl build-essential expect ; else #{sudo}yum groupinstall 'Development Tools' && #{sudo}yum install -y curl expect ; fi",
|
274
281
|
'mkdir -p ./hpc_deploy',
|
275
282
|
'rm -rf ./hpc_deploy/tmp',
|
276
283
|
'mkdir -p ./hpc_deploy/tmp',
|
@@ -281,16 +288,19 @@ module HybridPlatformsConductor
|
|
281
288
|
},
|
282
289
|
{
|
283
290
|
scp: { package_dir => './hpc_deploy' },
|
284
|
-
remote_bash:
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
gems_to_install.map { |(gem_name, gem_version)| "#{sudo}SSL_CERT_DIR=/etc/ssl/certs /opt/chef/embedded/bin/gem install #{gem_name} --version \"#{gem_version}\"" } +
|
289
|
-
[
|
290
|
-
"#{sudo}SSL_CERT_DIR=/etc/ssl/certs /opt/chef/bin/chef-client #{client_options.join(' ')}",
|
291
|
-
'cd ..'
|
291
|
+
remote_bash: {
|
292
|
+
commands: [
|
293
|
+
'set -e',
|
294
|
+
"cd ./hpc_deploy/#{package_name}"
|
292
295
|
] +
|
293
|
-
|
296
|
+
gems_to_install.map { |(gem_name, gem_version)| "#{sudo}/opt/chef/embedded/bin/gem install #{gem_name} --version \"#{gem_version}\"" } +
|
297
|
+
[
|
298
|
+
"#{sudo}unbuffer /opt/chef/bin/chef-client #{client_options.join(' ')}",
|
299
|
+
'cd ..'
|
300
|
+
] +
|
301
|
+
(log_debug? ? [] : ["#{sudo}rm -rf ./hpc_deploy/#{package_name}"]),
|
302
|
+
env: client_env
|
303
|
+
}
|
294
304
|
}
|
295
305
|
]
|
296
306
|
end
|
@@ -21,7 +21,7 @@ module HybridPlatformsConductor
|
|
21
21
|
::Docker.validate_version!
|
22
22
|
docker_ok = true
|
23
23
|
rescue
|
24
|
-
log_error "
|
24
|
+
log_error "Docker is not installed correctly. Please install it. Error: #{$ERROR_INFO}"
|
25
25
|
end
|
26
26
|
docker_ok
|
27
27
|
end
|
@@ -40,7 +40,7 @@ module HybridPlatformsConductor
|
|
40
40
|
docker_image = nil
|
41
41
|
image_futex_file = "#{Dir.tmpdir}/hpc_docker_image_futexes/#{image_tag}"
|
42
42
|
FileUtils.mkdir_p File.dirname(image_futex_file)
|
43
|
-
Futex.new(image_futex_file).open do
|
43
|
+
Futex.new(image_futex_file, timeout: 600).open do
|
44
44
|
docker_image = ::Docker::Image.all.find { |search_image| !search_image.info['RepoTags'].nil? && search_image.info['RepoTags'].include?("#{image_tag}:latest") }
|
45
45
|
unless docker_image
|
46
46
|
log_debug "[ #{@node}/#{@environment} ] - Creating Docker image #{image_tag}..."
|
@@ -26,7 +26,13 @@ module HybridPlatformsConductor
|
|
26
26
|
# Check that we can connect with root
|
27
27
|
ssh_ok = false
|
28
28
|
begin
|
29
|
-
Net::SSH.start(
|
29
|
+
Net::SSH.start(
|
30
|
+
instance.ip,
|
31
|
+
'root',
|
32
|
+
password: 'root_pwd',
|
33
|
+
auth_methods: ['password'],
|
34
|
+
verify_host_key: :never
|
35
|
+
) do |ssh|
|
30
36
|
ssh_ok = ssh.exec!('echo Works').strip == 'Works'
|
31
37
|
end
|
32
38
|
rescue
|
@@ -53,14 +59,22 @@ module HybridPlatformsConductor
|
|
53
59
|
# System is booting up. See pam_nologin(8)
|
54
60
|
# Authentication failed.
|
55
61
|
instance.stop
|
56
|
-
|
62
|
+
ssh_port = @nodes_handler.get_ssh_port_of(@node) || 22
|
63
|
+
instance.with_running_instance(port: ssh_port) do
|
57
64
|
|
58
65
|
unless @nodes_handler.get_root_access_allowed_of(@node)
|
59
66
|
# ===== Deploy removes root access
|
60
67
|
# Check that we can't connect with root
|
61
68
|
ssh_ok = false
|
62
69
|
begin
|
63
|
-
Net::SSH.start(
|
70
|
+
Net::SSH.start(
|
71
|
+
instance.ip,
|
72
|
+
'root',
|
73
|
+
password: 'root_pwd',
|
74
|
+
auth_methods: ['password'],
|
75
|
+
verify_host_key: :never,
|
76
|
+
port: ssh_port
|
77
|
+
) do |ssh|
|
64
78
|
ssh_ok = ssh.exec!('echo Works').strip == 'Works'
|
65
79
|
end
|
66
80
|
rescue
|
@@ -18,7 +18,13 @@ module HybridPlatformsConductor
|
|
18
18
|
# Check that we can connect with root
|
19
19
|
ssh_ok = false
|
20
20
|
begin
|
21
|
-
Net::SSH.start(
|
21
|
+
Net::SSH.start(
|
22
|
+
instance.ip,
|
23
|
+
'root',
|
24
|
+
password: 'root_pwd',
|
25
|
+
auth_methods: ['password'],
|
26
|
+
verify_host_key: :never
|
27
|
+
) do |ssh|
|
22
28
|
ssh_ok = ssh.exec!('echo Works').strip == 'Works'
|
23
29
|
end
|
24
30
|
rescue
|
@@ -29,17 +35,31 @@ module HybridPlatformsConductor
|
|
29
35
|
deployer.nbr_retries_on_error = 3
|
30
36
|
deployer.deploy_on @node
|
31
37
|
# As sshd is certainly being restarted, start and stop the container to reload it.
|
32
|
-
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
+
# As it's possible sshd has to be restarted because of a change in its conf, restart the container.
|
39
|
+
# Otherwise you'll get the following error upon reconnection:
|
40
|
+
# System is booting up. See pam_nologin(8)
|
41
|
+
# Authentication failed.
|
42
|
+
instance.stop
|
43
|
+
ssh_port = @nodes_handler.get_ssh_port_of(@node) || 22
|
44
|
+
instance.with_running_instance(port: ssh_port) do
|
45
|
+
# Check that we can't connect with root
|
46
|
+
ssh_ok = false
|
47
|
+
begin
|
48
|
+
Net::SSH.start(
|
49
|
+
instance.ip,
|
50
|
+
'root',
|
51
|
+
password: 'root_pwd',
|
52
|
+
auth_methods: ['password'],
|
53
|
+
verify_host_key: :never,
|
54
|
+
port: ssh_port
|
55
|
+
) do |ssh|
|
56
|
+
ssh_ok = ssh.exec!('echo Works').strip == 'Works'
|
57
|
+
end
|
58
|
+
rescue
|
59
|
+
nil
|
38
60
|
end
|
39
|
-
|
40
|
-
nil
|
61
|
+
assert_equal ssh_ok, false, 'Root can still connect on the image after deployment'
|
41
62
|
end
|
42
|
-
assert_equal ssh_ok, false, 'Root can still connect on the image after deployment'
|
43
63
|
end
|
44
64
|
end
|
45
65
|
end
|
@@ -27,7 +27,7 @@ module HybridPlatformsConductor
|
|
27
27
|
# System is booting up. See pam_nologin(8)
|
28
28
|
# Authentication failed.
|
29
29
|
instance.stop
|
30
|
-
instance.with_running_instance(port: 22) do
|
30
|
+
instance.with_running_instance(port: @nodes_handler.get_ssh_port_of(@node) || 22) do
|
31
31
|
# Now that the node has been deployed, use the a_testadmin user for the check-node (as root has no more access)
|
32
32
|
deployer.instance_variable_get(:@actions_executor).connector(:ssh).ssh_user = 'a_testadmin'
|
33
33
|
deployer.instance_variable_get(:@actions_executor).connector(:ssh).passwords.delete(@node)
|
data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb
CHANGED
@@ -132,6 +132,36 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
132
132
|
end
|
133
133
|
end
|
134
134
|
|
135
|
+
it 'creates SSH master to several nodes differing only by the SSH port' do
|
136
|
+
with_test_platform(
|
137
|
+
{
|
138
|
+
nodes: {
|
139
|
+
'node1' => { meta: { host_ip: '192.168.42.1', ssh_port: 6661 } },
|
140
|
+
'node2' => { meta: { host_ip: '192.168.42.1', ssh_port: 6662 } },
|
141
|
+
'node3' => { meta: { host_ip: '192.168.42.1', ssh_port: 6663 } }
|
142
|
+
}
|
143
|
+
}
|
144
|
+
) do
|
145
|
+
with_cmd_runner_mocked(
|
146
|
+
[
|
147
|
+
['which env', proc { [0, "/usr/bin/env\n", ''] }],
|
148
|
+
['ssh -V 2>&1', proc { [0, "OpenSSH_7.4p1 Debian-10+deb9u7, OpenSSL 1.0.2u 20 Dec 2019\n", ''] }]
|
149
|
+
] + ssh_expected_commands_for(
|
150
|
+
{
|
151
|
+
'node1' => { connection: '192.168.42.1', user: 'test_user', port: 6661 },
|
152
|
+
'node2' => { connection: '192.168.42.1', user: 'test_user', port: 6662 },
|
153
|
+
'node3' => { connection: '192.168.42.1', user: 'test_user', port: 6663 }
|
154
|
+
}
|
155
|
+
)
|
156
|
+
) do
|
157
|
+
test_connector.ssh_user = 'test_user'
|
158
|
+
test_connector.with_connection_to(%w[node1 node2 node3]) do |connected_nodes|
|
159
|
+
expect(connected_nodes.sort).to eq %w[node1 node2 node3].sort
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
135
165
|
it 'creates SSH master to several nodes with ssh connections transformed' do
|
136
166
|
with_test_platform(
|
137
167
|
{ nodes: {
|
data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/global_helpers_spec.rb
CHANGED
@@ -175,6 +175,16 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
175
175
|
end
|
176
176
|
end
|
177
177
|
|
178
|
+
it 'generates a simple config for a node with host_ip and a given SSH port' do
|
179
|
+
with_test_platform({ nodes: { 'node' => { meta: { host_ip: '192.168.42.42', ssh_port: 666 } } } }) do
|
180
|
+
expect(ssh_config_for('node')).to eq <<~EO_SSH_CONFIG
|
181
|
+
Host hpc.node
|
182
|
+
Hostname 192.168.42.42
|
183
|
+
Port 666
|
184
|
+
EO_SSH_CONFIG
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
178
188
|
it 'generates a simple config for several nodes' do
|
179
189
|
with_test_platform(
|
180
190
|
{
|
@@ -29,6 +29,17 @@ describe HybridPlatformsConductor::Config do
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
it 'can check if we are in debug mode' do
|
33
|
+
with_platforms(
|
34
|
+
<<~EO_CONFIG
|
35
|
+
os_image :image_1, '/path/to/image_1' if log_debug?
|
36
|
+
os_image :image_2, '/path/to/image_2'
|
37
|
+
EO_CONFIG
|
38
|
+
) do
|
39
|
+
expect(test_config.known_os_images.sort).to eq %i[image_2].sort
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
32
43
|
it 'returns the tests provisioner correctly' do
|
33
44
|
with_platforms 'tests_provisioner :test_provisioner' do
|
34
45
|
expect(test_config.tests_provisioner_id).to eq :test_provisioner
|
@@ -4,7 +4,7 @@ describe HybridPlatformsConductor::NodesHandler do
|
|
4
4
|
|
5
5
|
it 'makes sure to have hostname or host_ip set to compute host_keys' do
|
6
6
|
with_test_platform({}) do
|
7
|
-
expect(cmdb(:host_keys).property_dependencies[:host_keys].sort).to eq %i[hostname host_ip].sort
|
7
|
+
expect(cmdb(:host_keys).property_dependencies[:host_keys].sort).to eq %i[hostname host_ip ssh_port].sort
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -17,17 +17,27 @@ describe HybridPlatformsConductor::NodesHandler do
|
|
17
17
|
it 'returns host keys when hostname is set' do
|
18
18
|
with_test_platform({ nodes: { 'test_node' => {} } }) do
|
19
19
|
with_cmd_runner_mocked [
|
20
|
-
['ssh-keyscan my_host.my_domain', proc { [0, "my_host.my_domain ssh-rsa fake_host_key\n", ''] }]
|
20
|
+
['ssh-keyscan -p 22 my_host.my_domain', proc { [0, "my_host.my_domain ssh-rsa fake_host_key\n", ''] }]
|
21
21
|
] do
|
22
22
|
expect(cmdb(:host_keys).get_host_keys(['test_node'], { 'test_node' => { hostname: 'my_host.my_domain' } })).to eq('test_node' => ['ssh-rsa fake_host_key'])
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
it 'returns host keys for the correct ssh port' do
|
28
|
+
with_test_platform({ nodes: { 'test_node' => {} } }) do
|
29
|
+
with_cmd_runner_mocked [
|
30
|
+
['ssh-keyscan -p 666 my_host.my_domain', proc { [0, "my_host.my_domain ssh-rsa fake_host_key\n", ''] }]
|
31
|
+
] do
|
32
|
+
expect(cmdb(:host_keys).get_host_keys(['test_node'], { 'test_node' => { hostname: 'my_host.my_domain', ssh_port: 666 } })).to eq('test_node' => ['ssh-rsa fake_host_key'])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
27
37
|
it 'returns host keys when host_ip is set' do
|
28
38
|
with_test_platform({ nodes: { 'test_node' => {} } }) do
|
29
39
|
with_cmd_runner_mocked [
|
30
|
-
['ssh-keyscan 192.168.42.42', proc { [0, "192.168.42.42 ssh-rsa fake_host_key\n", ''] }]
|
40
|
+
['ssh-keyscan -p 22 192.168.42.42', proc { [0, "192.168.42.42 ssh-rsa fake_host_key\n", ''] }]
|
31
41
|
] do
|
32
42
|
expect(cmdb(:host_keys).get_host_keys(['test_node'], { 'test_node' => { host_ip: '192.168.42.42' } })).to eq('test_node' => ['ssh-rsa fake_host_key'])
|
33
43
|
end
|
@@ -37,7 +47,7 @@ describe HybridPlatformsConductor::NodesHandler do
|
|
37
47
|
it 'returns several host keys' do
|
38
48
|
with_test_platform({ nodes: { 'test_node' => {} } }) do
|
39
49
|
with_cmd_runner_mocked [
|
40
|
-
['ssh-keyscan 192.168.42.42', proc do
|
50
|
+
['ssh-keyscan -p 22 192.168.42.42', proc do
|
41
51
|
[0, <<~EO_STDOUT, '']
|
42
52
|
192.168.42.42 ssh-rsa fake_host_key_rsa
|
43
53
|
192.168.42.42 ssh-ed25519 fake_host_key_ed25519
|
@@ -55,7 +65,7 @@ describe HybridPlatformsConductor::NodesHandler do
|
|
55
65
|
it 'returns several host keys and ignores comments from ssh-keyscan' do
|
56
66
|
with_test_platform({ nodes: { 'test_node' => {} } }) do
|
57
67
|
with_cmd_runner_mocked [
|
58
|
-
['ssh-keyscan 192.168.42.42', proc do
|
68
|
+
['ssh-keyscan -p 22 192.168.42.42', proc do
|
59
69
|
[0, <<~EO_STDOUT, '']
|
60
70
|
# That's a comment
|
61
71
|
192.168.42.42 ssh-rsa fake_host_key_rsa
|
@@ -78,7 +88,7 @@ describe HybridPlatformsConductor::NodesHandler do
|
|
78
88
|
it 'returns host keys sorted' do
|
79
89
|
with_test_platform({ nodes: { 'test_node' => {} } }) do
|
80
90
|
with_cmd_runner_mocked [
|
81
|
-
['ssh-keyscan 192.168.42.42', proc do
|
91
|
+
['ssh-keyscan -p 22 192.168.42.42', proc do
|
82
92
|
[0, <<~EO_STDOUT, '']
|
83
93
|
192.168.42.42 ssh-dsa fake_host_key_dsa
|
84
94
|
192.168.42.42 ssh-rsa fake_host_key_rsa
|
@@ -100,7 +110,7 @@ describe HybridPlatformsConductor::NodesHandler do
|
|
100
110
|
it 'does not return host keys when ssh-keyscan can\'t retrieve them' do
|
101
111
|
with_test_platform({ nodes: { 'test_node' => {} } }) do
|
102
112
|
with_cmd_runner_mocked [
|
103
|
-
['ssh-keyscan 192.168.42.42', proc { [0, '', ''] }]
|
113
|
+
['ssh-keyscan -p 22 192.168.42.42', proc { [0, '', ''] }]
|
104
114
|
] do
|
105
115
|
expect(cmdb(:host_keys).get_host_keys(['test_node'], { 'test_node' => { host_ip: '192.168.42.42' } })).to eq({})
|
106
116
|
end
|
@@ -119,9 +129,9 @@ describe HybridPlatformsConductor::NodesHandler do
|
|
119
129
|
}
|
120
130
|
) do
|
121
131
|
with_cmd_runner_mocked [
|
122
|
-
['ssh-keyscan 192.168.42.1', proc { [0, "192.168.42.1 ssh-rsa fake_host_key_1\n", ''] }],
|
123
|
-
['ssh-keyscan 192.168.42.2', proc { [0, '', ''] }],
|
124
|
-
['ssh-keyscan my_host_4.my_domain', proc { [0, "my_host_4.my_domain ssh-rsa fake_host_key_4\n", ''] }]
|
132
|
+
['ssh-keyscan -p 22 192.168.42.1', proc { [0, "192.168.42.1 ssh-rsa fake_host_key_1\n", ''] }],
|
133
|
+
['ssh-keyscan -p 22 192.168.42.2', proc { [0, '', ''] }],
|
134
|
+
['ssh-keyscan -p 22 my_host_4.my_domain', proc { [0, "my_host_4.my_domain ssh-rsa fake_host_key_4\n", ''] }]
|
125
135
|
] do
|
126
136
|
expect(
|
127
137
|
cmdb(:host_keys).get_host_keys(
|
@@ -141,6 +151,35 @@ describe HybridPlatformsConductor::NodesHandler do
|
|
141
151
|
end
|
142
152
|
end
|
143
153
|
|
154
|
+
it 'returns different host keys for hosts having the same IPs but different SSH ports' do
|
155
|
+
with_test_platform(
|
156
|
+
{
|
157
|
+
nodes: {
|
158
|
+
'test_node1' => {},
|
159
|
+
'test_node2' => {}
|
160
|
+
}
|
161
|
+
}
|
162
|
+
) do
|
163
|
+
with_cmd_runner_mocked [
|
164
|
+
['ssh-keyscan -p 6661 192.168.42.1', proc { [0, "192.168.42.1 ssh-rsa fake_host_key_1\n", ''] }],
|
165
|
+
['ssh-keyscan -p 6662 192.168.42.1', proc { [0, "192.168.42.1 ssh-rsa fake_host_key_2\n", ''] }]
|
166
|
+
] do
|
167
|
+
expect(
|
168
|
+
cmdb(:host_keys).get_host_keys(
|
169
|
+
['test_node'],
|
170
|
+
{
|
171
|
+
'test_node1' => { host_ip: '192.168.42.1', ssh_port: 6661 },
|
172
|
+
'test_node2' => { host_ip: '192.168.42.1', ssh_port: 6662 }
|
173
|
+
}
|
174
|
+
)
|
175
|
+
).to eq(
|
176
|
+
'test_node1' => ['ssh-rsa fake_host_key_1'],
|
177
|
+
'test_node2' => ['ssh-rsa fake_host_key_2']
|
178
|
+
)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
144
183
|
end
|
145
184
|
|
146
185
|
end
|
@@ -46,7 +46,7 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
46
46
|
remote_bash: [
|
47
47
|
'set -e',
|
48
48
|
'set -o pipefail',
|
49
|
-
"if [ -n \"$(command -v apt)\" ]; then #{sudo}apt update && #{sudo}apt install -y curl build-essential ; else #{sudo}yum groupinstall 'Development Tools' && #{sudo}yum install -y curl ; fi",
|
49
|
+
"if [ -n \"$(command -v apt)\" ]; then #{sudo}apt update && #{sudo}apt install -y curl build-essential expect ; else #{sudo}yum groupinstall 'Development Tools' && #{sudo}yum install -y curl expect ; fi",
|
50
50
|
'mkdir -p ./hpc_deploy',
|
51
51
|
'rm -rf ./hpc_deploy/tmp',
|
52
52
|
'mkdir -p ./hpc_deploy/tmp',
|
@@ -57,16 +57,22 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
57
57
|
},
|
58
58
|
{
|
59
59
|
scp: { "#{repository}/dist/#{env}/#{policy}" => './hpc_deploy' },
|
60
|
-
remote_bash:
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
60
|
+
remote_bash: {
|
61
|
+
commands: [
|
62
|
+
'set -e',
|
63
|
+
"cd ./hpc_deploy/#{policy}"
|
64
|
+
] +
|
65
|
+
gems_install_cmds.map { |gem_install_cmd| "#{sudo}/opt/chef/embedded/bin/#{gem_install_cmd}" } +
|
66
|
+
[
|
67
|
+
"#{sudo}unbuffer /opt/chef/bin/chef-client --local-mode --chef-license accept --json-attributes nodes/#{node}.json#{check_mode ? ' --why-run' : ''}",
|
68
|
+
'cd ..',
|
69
|
+
"#{sudo}rm -rf ./hpc_deploy/#{policy}"
|
70
|
+
],
|
71
|
+
env: {
|
72
|
+
'SSL_CERT_DIR' => '/etc/ssl/certs',
|
73
|
+
'TERM' => 'xterm-256color'
|
74
|
+
}
|
75
|
+
}
|
70
76
|
}
|
71
77
|
]
|
72
78
|
end
|
@@ -323,7 +329,9 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
323
329
|
bash: [
|
324
330
|
'set -e',
|
325
331
|
"cd #{repository}/dist/prod/test_policy_1",
|
326
|
-
'
|
332
|
+
'export SSL_CERT_DIR=/etc/ssl/certs',
|
333
|
+
'export TERM=xterm-256color',
|
334
|
+
'sudo -E /opt/chef-workstation/bin/chef-client --local-mode --chef-license accept --json-attributes nodes/local.json'
|
327
335
|
]
|
328
336
|
}
|
329
337
|
]
|
@@ -352,10 +360,12 @@ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef d
|
|
352
360
|
bash: [
|
353
361
|
'set -e',
|
354
362
|
"cd #{repository}/dist/prod/test_policy_1",
|
355
|
-
'
|
356
|
-
'
|
357
|
-
'sudo
|
358
|
-
'sudo
|
363
|
+
'export SSL_CERT_DIR=/etc/ssl/certs',
|
364
|
+
'export TERM=xterm-256color',
|
365
|
+
'sudo -E /opt/chef-workstation/bin/chef gem install my_gem_1 --version "0.0.1"',
|
366
|
+
'sudo -E /opt/chef-workstation/bin/chef gem install my_gem_2 --version "0.0.2"',
|
367
|
+
'sudo -E /opt/chef-workstation/bin/chef gem install my_gem_3 --version "~> 1.3"',
|
368
|
+
'sudo -E /opt/chef-workstation/bin/chef-client --local-mode --chef-license accept --json-attributes nodes/local.json'
|
359
369
|
]
|
360
370
|
}
|
361
371
|
]
|
@@ -11,6 +11,7 @@ module HybridPlatformsConductorTest
|
|
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
13
|
# * *ip* (String): IP used by SSH (can be different from connection in case of transformed SSH) [default: connection]
|
14
|
+
# * *port* (Integer): SSH port used [default: 22]
|
14
15
|
# * *user* (String): User used by SSH
|
15
16
|
# * *times* (Integer): Number of times this connection should be used [default: 1]
|
16
17
|
# * *control_master_create_error* (String or nil): Error to simulate during the SSH ControlMaster creation, or nil for none [default: nil]
|
@@ -37,6 +38,7 @@ module HybridPlatformsConductorTest
|
|
37
38
|
)
|
38
39
|
nodes_connections.map do |node, node_connection_info|
|
39
40
|
node_connection_info[:times] = 1 unless node_connection_info.key?(:times)
|
41
|
+
node_connection_info[:port] = 22 unless node_connection_info.key?(:port)
|
40
42
|
ssh_commands_once = []
|
41
43
|
ssh_commands_per_connection = []
|
42
44
|
if with_strict_host_key_checking
|
@@ -44,7 +46,7 @@ module HybridPlatformsConductorTest
|
|
44
46
|
ssh_commands_once.concat(
|
45
47
|
[
|
46
48
|
[
|
47
|
-
"ssh-keyscan #{ip}",
|
49
|
+
"ssh-keyscan -p #{node_connection_info[:port]} #{ip}",
|
48
50
|
proc { [0, "#{ip} ssh-rsa fake_host_key_for_#{ip}", ''] }
|
49
51
|
]
|
50
52
|
]
|
@@ -67,7 +69,7 @@ module HybridPlatformsConductorTest
|
|
67
69
|
%r{^xterm -e '.+/ssh -o ControlMaster=yes -o ControlPersist=yes hpc\.#{Regexp.escape(node)}'$}
|
68
70
|
end,
|
69
71
|
proc do
|
70
|
-
control_file = test_actions_executor.connector(:ssh).send(:control_master_file, node_connection_info[:connection],
|
72
|
+
control_file = test_actions_executor.connector(:ssh).send(:control_master_file, node_connection_info[:connection], node_connection_info[:port].to_s, node_connection_info[:user])
|
71
73
|
# Fail if the ControlMaster file already exists, as would SSH do if the file is stalled
|
72
74
|
if File.exist?(control_file)
|
73
75
|
[255, '', "Control file #{control_file} already exists"]
|
@@ -97,7 +99,7 @@ module HybridPlatformsConductorTest
|
|
97
99
|
%r{^.+/ssh -O exit hpc\.#{Regexp.escape(node)} 2>&1 \| grep -v 'Exit request sent\.'$},
|
98
100
|
proc do
|
99
101
|
# Really mock the control file deletion
|
100
|
-
File.unlink(test_actions_executor.connector(:ssh).send(:control_master_file, node_connection_info[:connection],
|
102
|
+
File.unlink(test_actions_executor.connector(:ssh).send(:control_master_file, node_connection_info[:connection], node_connection_info[:port].to_s, node_connection_info[:user]))
|
101
103
|
[1, '', '']
|
102
104
|
end,
|
103
105
|
{ optional: with_control_master_destroy_optional }
|
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: 33.
|
4
|
+
version: 33.7.2
|
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-07-
|
11
|
+
date: 2021-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: range_operators
|