hybrid_platforms_conductor 33.4.0 → 33.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -0
- data/README.md +5 -5
- data/docs/config_dsl.md +7 -5
- data/docs/plugins/cmdb/host_keys.md +3 -1
- data/docs/plugins/connector/ssh.md +1 -0
- data/lib/hybrid_platforms_conductor/actions_executor.rb +29 -1
- data/lib/hybrid_platforms_conductor/bitbucket.rb +2 -2
- data/lib/hybrid_platforms_conductor/cmd_runner.rb +4 -4
- data/lib/hybrid_platforms_conductor/config.rb +2 -0
- data/lib/hybrid_platforms_conductor/confluence.rb +2 -2
- data/lib/hybrid_platforms_conductor/connector.rb +5 -2
- data/lib/hybrid_platforms_conductor/credentials.rb +20 -12
- data/lib/hybrid_platforms_conductor/deployer.rb +5 -7
- data/lib/hybrid_platforms_conductor/github.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/bash.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/remote_bash.rb +27 -17
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/host_keys.rb +13 -12
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/local.rb +6 -4
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/my_connector.rb.sample +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +37 -25
- data/lib/hybrid_platforms_conductor/hpc_plugins/log/remote_fs.rb +5 -6
- data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb +23 -14
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/docker.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +3 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/keepass.rb +1 -1
- 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/file_system.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/hostname.rb +1 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/idempotence.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/ip.rb +1 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_conf.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_masters_ok.rb +2 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/local_users.rb +1 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/mounts.rb +1 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/orphan_files.rb +1 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +1 -2
- data/lib/hybrid_platforms_conductor/logger_helpers.rb +17 -0
- data/lib/hybrid_platforms_conductor/test.rb +21 -7
- data/lib/hybrid_platforms_conductor/tests_runner.rb +7 -6
- data/lib/hybrid_platforms_conductor/thycotic.rb +2 -2
- data/lib/hybrid_platforms_conductor/version.rb +1 -1
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/bash_spec.rb +15 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/remote_bash_spec.rb +32 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/local/remote_actions_spec.rb +87 -0
- 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/actions_executor/connectors/ssh/remote_actions_spec.rb +38 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/helpers_spec.rb +195 -0
- data/spec/hybrid_platforms_conductor_test/api/cmd_runner_spec.rb +14 -0
- data/spec/hybrid_platforms_conductor_test/api/config_spec.rb +11 -0
- data/spec/hybrid_platforms_conductor_test/api/credentials_spec.rb +8 -4
- data/spec/hybrid_platforms_conductor_test/api/deployer/log_plugins/remote_fs_spec.rb +215 -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 +64 -16
- data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +5 -3
- data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/chef_versions.yml +3 -0
- data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/nodes/node.json +15 -0
- data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_local_node/policyfiles/test_policy.rb +3 -0
- data/spec/hybrid_platforms_conductor_test/shared_examples/deployer.rb +134 -0
- data/spec/hybrid_platforms_conductor_test/test_connector.rb +2 -2
- metadata +20 -2
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
|
{
|
data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/remote_actions_spec.rb
CHANGED
|
@@ -13,6 +13,15 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
it 'executes bash commands remotely from a SecretString' do
|
|
17
|
+
with_test_platform_for_remote_testing(
|
|
18
|
+
expected_cmds: [[%r{.+/ssh hpc\.node /bin/bash <<'HPC_EOF'\nbash_cmd.bash\nHPC_EOF}, proc { [0, 'Bash commands executed on node', ''] }]],
|
|
19
|
+
expected_stdout: 'Bash commands executed on node'
|
|
20
|
+
) do
|
|
21
|
+
test_connector.remote_bash(SecretString.new('bash_cmd.bash', silenced_str: '__INVALID_BASH__'))
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
16
25
|
it 'executes bash commands remotely with timeout' do
|
|
17
26
|
with_test_platform_for_remote_testing(
|
|
18
27
|
expected_cmds: [
|
|
@@ -88,6 +97,25 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
|
88
97
|
end
|
|
89
98
|
end
|
|
90
99
|
|
|
100
|
+
it 'executes really big bash commands remotely using a SecretString' do
|
|
101
|
+
cmd = "echo #{'1' * 131_060}"
|
|
102
|
+
with_test_platform_for_remote_testing(
|
|
103
|
+
expected_cmds: [
|
|
104
|
+
[
|
|
105
|
+
%r{.+/hpc_temp_cmds_.+\.sh$},
|
|
106
|
+
proc do |received_cmd|
|
|
107
|
+
expect(File.read(received_cmd)).to match(%r{.+/ssh hpc\.node /bin/bash <<'HPC_EOF'\n#{Regexp.escape(cmd)}\nHPC_EOF})
|
|
108
|
+
[0, 'Bash commands executed on node', '']
|
|
109
|
+
end
|
|
110
|
+
]
|
|
111
|
+
],
|
|
112
|
+
expected_stdout: 'Bash commands executed on node'
|
|
113
|
+
) do
|
|
114
|
+
# Use an argument that exceeds the max arg length limit
|
|
115
|
+
test_connector.remote_bash(SecretString.new(cmd, silenced_str: '__INVALID_BASH__'))
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
91
119
|
it 'copies files remotely with sudo' do
|
|
92
120
|
with_test_platform_for_remote_testing(
|
|
93
121
|
expected_cmds: [
|
|
@@ -153,6 +181,16 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
|
153
181
|
end
|
|
154
182
|
end
|
|
155
183
|
|
|
184
|
+
it 'executes bash commands remotely without Session Exec capabilities using a SecretString' do
|
|
185
|
+
with_test_platform_for_remote_testing(
|
|
186
|
+
expected_cmds: [[%r{^\{ cat \| .+/ssh hpc\.node -T; \} <<'HPC_EOF'\nbash_cmd.bash\nHPC_EOF$}, proc { [0, 'Bash commands executed on node', ''] }]],
|
|
187
|
+
expected_stdout: 'Bash commands executed on node',
|
|
188
|
+
session_exec: false
|
|
189
|
+
) do
|
|
190
|
+
test_connector.remote_bash(SecretString.new('bash_cmd.bash', silenced_str: '__INVALID_BASH__'))
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
156
194
|
it 'copies files remotely without Session Exec capabilities' do
|
|
157
195
|
with_test_platform_for_remote_testing(
|
|
158
196
|
expected_cmds: [
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
describe HybridPlatformsConductor::ActionsExecutor do
|
|
2
|
+
|
|
3
|
+
context 'when checking helpers' do
|
|
4
|
+
|
|
5
|
+
it 'gives access to connectors' do
|
|
6
|
+
with_test_platform({}) do
|
|
7
|
+
expect(test_actions_executor.connector(:ssh)).not_to be_nil
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'returns if a user has privileged access on a node' do
|
|
12
|
+
with_test_platform({ nodes: { 'node' => {} } }) do
|
|
13
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
14
|
+
expect(test_actions_executor.privileged_access?('node')).to eq false
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'returns if a user has privileged access on a node when connecting with root' do
|
|
19
|
+
with_test_platform({ nodes: { 'node' => {} } }) do
|
|
20
|
+
test_actions_executor.connector(:ssh).ssh_user = 'root'
|
|
21
|
+
expect(test_actions_executor.privileged_access?('node')).to eq true
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'returns if a user has privileged access on a local node' do
|
|
26
|
+
with_test_platform({ nodes: { 'node' => { meta: { local_node: true } } } }) do
|
|
27
|
+
with_cmd_runner_mocked [
|
|
28
|
+
['whoami', proc { [0, 'test_user', ''] }]
|
|
29
|
+
] do
|
|
30
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
31
|
+
expect(test_actions_executor.privileged_access?('node')).to eq false
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'returns if a user has privileged access on a local node when local user is root' do
|
|
37
|
+
with_test_platform({ nodes: { 'node' => { meta: { local_node: true } } } }) do
|
|
38
|
+
with_cmd_runner_mocked [
|
|
39
|
+
['whoami', proc { [0, 'root', ''] }]
|
|
40
|
+
] do
|
|
41
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
42
|
+
expect(test_actions_executor.privileged_access?('node')).to eq true
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context 'with connection on a remote node' do
|
|
48
|
+
|
|
49
|
+
it 'returns the correct sudo prefix' do
|
|
50
|
+
with_test_platform({ nodes: { 'node' => {} } }) do
|
|
51
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
52
|
+
expect(test_actions_executor.sudo_prefix('node')).to eq 'sudo -u root '
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'returns the correct sudo prefix with env forwarding' do
|
|
57
|
+
with_test_platform({ nodes: { 'node' => {} } }) do
|
|
58
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
59
|
+
expect(test_actions_executor.sudo_prefix('node', forward_env: true)).to eq 'sudo -u root -E '
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'returns the correct sudo prefix when connecting as root' do
|
|
64
|
+
with_test_platform({ nodes: { 'node' => {} } }) do
|
|
65
|
+
test_actions_executor.connector(:ssh).ssh_user = 'root'
|
|
66
|
+
expect(test_actions_executor.sudo_prefix('node')).to eq ''
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'returns the correct sudo prefix with a different sudo' do
|
|
71
|
+
with_test_platform(
|
|
72
|
+
{ nodes: { 'node' => {} } },
|
|
73
|
+
additional_config: <<~'EO_CONFIG'
|
|
74
|
+
sudo_for { |user| "other_sudo --user #{user}" }
|
|
75
|
+
EO_CONFIG
|
|
76
|
+
) do
|
|
77
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
78
|
+
expect(test_actions_executor.sudo_prefix('node')).to eq 'other_sudo --user root '
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'returns the correct sudo prefix with a different sudo and env forwarding' do
|
|
83
|
+
with_test_platform(
|
|
84
|
+
{ nodes: { 'node' => {} } },
|
|
85
|
+
additional_config: <<~'EO_CONFIG'
|
|
86
|
+
sudo_for { |user| "other_sudo --user #{user}" }
|
|
87
|
+
EO_CONFIG
|
|
88
|
+
) do
|
|
89
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
90
|
+
expect(test_actions_executor.sudo_prefix('node', forward_env: true)).to eq 'other_sudo --user root -E '
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'returns the correct sudo prefix with a different sudo when connecting as root' do
|
|
95
|
+
with_test_platform(
|
|
96
|
+
{ nodes: { 'node' => {} } },
|
|
97
|
+
additional_config: <<~'EO_CONFIG'
|
|
98
|
+
sudo_for { |user| "other_sudo --user #{user}" }
|
|
99
|
+
EO_CONFIG
|
|
100
|
+
) do
|
|
101
|
+
test_actions_executor.connector(:ssh).ssh_user = 'root'
|
|
102
|
+
expect(test_actions_executor.sudo_prefix('node')).to eq ''
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
context 'with connection on a local node' do
|
|
109
|
+
|
|
110
|
+
it 'returns the correct sudo prefix' do
|
|
111
|
+
with_test_platform({ nodes: { 'node' => { meta: { local_node: true } } } }) do
|
|
112
|
+
with_cmd_runner_mocked [
|
|
113
|
+
['whoami', proc { [0, 'test_user', ''] }]
|
|
114
|
+
] do
|
|
115
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
116
|
+
expect(test_actions_executor.sudo_prefix('node')).to eq 'sudo -u root '
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'returns the correct sudo prefix with env forwarding' do
|
|
122
|
+
with_test_platform({ nodes: { 'node' => { meta: { local_node: true } } } }) do
|
|
123
|
+
with_cmd_runner_mocked [
|
|
124
|
+
['whoami', proc { [0, 'test_user', ''] }]
|
|
125
|
+
] do
|
|
126
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
127
|
+
expect(test_actions_executor.sudo_prefix('node', forward_env: true)).to eq 'sudo -u root -E '
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it 'returns the correct sudo prefix when connecting as root' do
|
|
133
|
+
with_test_platform({ nodes: { 'node' => { meta: { local_node: true } } } }) do
|
|
134
|
+
with_cmd_runner_mocked [
|
|
135
|
+
['whoami', proc { [0, 'root', ''] }]
|
|
136
|
+
] do
|
|
137
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
138
|
+
expect(test_actions_executor.sudo_prefix('node')).to eq ''
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it 'returns the correct sudo prefix with a different sudo' do
|
|
144
|
+
with_test_platform(
|
|
145
|
+
{ nodes: { 'node' => { meta: { local_node: true } } } },
|
|
146
|
+
additional_config: <<~'EO_CONFIG'
|
|
147
|
+
sudo_for { |user| "other_sudo --user #{user}" }
|
|
148
|
+
EO_CONFIG
|
|
149
|
+
) do
|
|
150
|
+
with_cmd_runner_mocked [
|
|
151
|
+
['whoami', proc { [0, 'test_user', ''] }]
|
|
152
|
+
] do
|
|
153
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
154
|
+
expect(test_actions_executor.sudo_prefix('node')).to eq 'other_sudo --user root '
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it 'returns the correct sudo prefix with a different sudo and env forwarding' do
|
|
160
|
+
with_test_platform(
|
|
161
|
+
{ nodes: { 'node' => { meta: { local_node: true } } } },
|
|
162
|
+
additional_config: <<~'EO_CONFIG'
|
|
163
|
+
sudo_for { |user| "other_sudo --user #{user}" }
|
|
164
|
+
EO_CONFIG
|
|
165
|
+
) do
|
|
166
|
+
with_cmd_runner_mocked [
|
|
167
|
+
['whoami', proc { [0, 'test_user', ''] }]
|
|
168
|
+
] do
|
|
169
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
170
|
+
expect(test_actions_executor.sudo_prefix('node', forward_env: true)).to eq 'other_sudo --user root -E '
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it 'returns the correct sudo prefix with a different sudo when connecting as root' do
|
|
176
|
+
with_test_platform(
|
|
177
|
+
{ nodes: { 'node' => { meta: { local_node: true } } } },
|
|
178
|
+
additional_config: <<~'EO_CONFIG'
|
|
179
|
+
sudo_for { |user| "other_sudo --user #{user}" }
|
|
180
|
+
EO_CONFIG
|
|
181
|
+
) do
|
|
182
|
+
with_cmd_runner_mocked [
|
|
183
|
+
['whoami', proc { [0, 'root', ''] }]
|
|
184
|
+
] do
|
|
185
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
186
|
+
expect(test_actions_executor.sudo_prefix('node')).to eq ''
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
end
|
|
@@ -7,6 +7,13 @@ describe HybridPlatformsConductor::CmdRunner do
|
|
|
7
7
|
end
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
+
it 'runs a simple bash command in a SecretString' do
|
|
11
|
+
with_repository do |repository|
|
|
12
|
+
test_cmd_runner.run_cmd SecretString.new("echo TestContent >#{repository}/test_file", silenced_str: '__INVALID_BASH__')
|
|
13
|
+
expect(File.read("#{repository}/test_file")).to eq "TestContent\n"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
10
17
|
it 'runs a simple bash command and returns exit code, stdout and stderr correctly' do
|
|
11
18
|
with_repository do
|
|
12
19
|
expect(test_cmd_runner.run_cmd('echo TestStderr 1>&2 ; echo TestStdout')).to eq [0, "TestStdout\n", "TestStderr\n"]
|
|
@@ -20,6 +27,13 @@ describe HybridPlatformsConductor::CmdRunner do
|
|
|
20
27
|
end
|
|
21
28
|
end
|
|
22
29
|
|
|
30
|
+
it 'runs a simple bash command and forces usage of bash in a SecretString' do
|
|
31
|
+
with_repository do
|
|
32
|
+
# Use set -o pipefail that does not work in /bin/sh
|
|
33
|
+
expect(test_cmd_runner.run_cmd(SecretString.new('set -o pipefail ; echo TestStderr 1>&2 ; echo TestStdout', silenced_str: '__INVALID_BASH__'), force_bash: true)).to eq [0, "TestStdout\n", "TestStderr\n"]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
23
37
|
it 'runs a simple bash command and logs stdout and stderr to a file' do
|
|
24
38
|
with_repository do |repository|
|
|
25
39
|
test_cmd_runner.run_cmd 'echo TestStderr 1>&2 ; sleep 1 ; echo TestStdout', log_to_file: "#{repository}/test_file"
|
|
@@ -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
|
|
@@ -15,15 +15,19 @@ describe HybridPlatformsConductor::Credentials do
|
|
|
15
15
|
# * *resource* (String or nil): The resource for which we query the credentials, or nil if none [default: nil]
|
|
16
16
|
def expect_credentials_to_be(expected_user, expected_password, resource: nil)
|
|
17
17
|
creds = {}
|
|
18
|
+
password_class = nil
|
|
18
19
|
credential_tester_class.new(logger: logger, logger_stderr: logger, config: test_config).instance_exec do
|
|
19
20
|
with_credentials_for(:test_credential, resource: resource) do |user, password|
|
|
21
|
+
password_class = password.class
|
|
20
22
|
creds = {
|
|
21
23
|
user: user,
|
|
22
24
|
# We clone the value as for security reasons it is removed when exiting the block
|
|
23
|
-
password: password.clone
|
|
25
|
+
password: password&.to_unprotected.clone
|
|
24
26
|
}
|
|
25
27
|
end
|
|
26
28
|
end
|
|
29
|
+
# Make sure we always return a SecretString for the password
|
|
30
|
+
expect(password_class).to be SecretString unless password_class == NilClass
|
|
27
31
|
expect(creds).to eq(
|
|
28
32
|
user: expected_user,
|
|
29
33
|
password: expected_password
|
|
@@ -64,7 +68,7 @@ describe HybridPlatformsConductor::Credentials do
|
|
|
64
68
|
leaked_password = password
|
|
65
69
|
end
|
|
66
70
|
end
|
|
67
|
-
expect(leaked_password).to eq
|
|
71
|
+
expect(leaked_password.to_unprotected).to eq "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
68
72
|
ensure
|
|
69
73
|
ENV.delete('hpc_user_for_test_credential')
|
|
70
74
|
ENV.delete('hpc_password_for_test_credential')
|
|
@@ -96,7 +100,7 @@ describe HybridPlatformsConductor::Credentials do
|
|
|
96
100
|
end
|
|
97
101
|
end
|
|
98
102
|
|
|
99
|
-
it 'erases the value of the password taken from netrc' do
|
|
103
|
+
it 'erases the value of the password taken from netrc after usage' do
|
|
100
104
|
with_platforms '' do
|
|
101
105
|
netrc_data = [['mocked_data']]
|
|
102
106
|
expect(::Netrc).to receive(:read) do
|
|
@@ -111,7 +115,7 @@ describe HybridPlatformsConductor::Credentials do
|
|
|
111
115
|
leaked_password = password
|
|
112
116
|
end
|
|
113
117
|
end
|
|
114
|
-
expect(leaked_password).to eq
|
|
118
|
+
expect(leaked_password).to eq "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
115
119
|
expect(netrc_data).to eq [['GotYou!!!' * 100]]
|
|
116
120
|
end
|
|
117
121
|
end
|
|
@@ -129,6 +129,127 @@ describe HybridPlatformsConductor::Deployer do
|
|
|
129
129
|
end
|
|
130
130
|
end
|
|
131
131
|
|
|
132
|
+
it 'returns actions to save logs on a local node' do
|
|
133
|
+
with_test_platform({ nodes: { 'node' => { meta: { local_node: true }, services: %w[service1 service2] } } }, additional_config: 'send_logs_to :remote_fs') do
|
|
134
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
135
|
+
expect_services_handler_to_deploy('node' => %w[service1 service2])
|
|
136
|
+
expect_actions_executor_runs [
|
|
137
|
+
# First run, we expect the mutex to be setup, and the deployment actions to be run
|
|
138
|
+
proc do |actions_per_nodes|
|
|
139
|
+
expect_actions_to_deploy_on(
|
|
140
|
+
actions_per_nodes,
|
|
141
|
+
'node',
|
|
142
|
+
mocked_result: { 'node' => [0, 'Deploy successful stdout', 'Deploy successful stderr'] }
|
|
143
|
+
)
|
|
144
|
+
end,
|
|
145
|
+
# Second run, we expect the mutex to be released
|
|
146
|
+
proc { |actions_per_nodes| expect_actions_to_unlock(actions_per_nodes, 'node') },
|
|
147
|
+
# Third run, we expect logs to be uploaded on the node
|
|
148
|
+
proc do |actions_per_nodes|
|
|
149
|
+
expect(actions_per_nodes['node'].size).to eq 3
|
|
150
|
+
expect(actions_per_nodes['node'][0].keys.sort).to eq %i[ruby remote_bash].sort
|
|
151
|
+
expect(actions_per_nodes['node'][0][:remote_bash]).to eq 'sudo -u root mkdir -p /var/log/deployments && sudo -u root chmod 600 /var/log/deployments'
|
|
152
|
+
expect(actions_per_nodes['node'][1].keys.sort).to eq %i[scp].sort
|
|
153
|
+
expect(actions_per_nodes['node'][1][:scp].delete(:sudo)).to eq true
|
|
154
|
+
expect(actions_per_nodes['node'][1][:scp].delete(:owner)).to eq 'root'
|
|
155
|
+
expect(actions_per_nodes['node'][1][:scp].delete(:group)).to eq 'root'
|
|
156
|
+
expect(actions_per_nodes['node'][1][:scp].size).to eq 1
|
|
157
|
+
tmp_log_file = actions_per_nodes['node'][1][:scp].first[0]
|
|
158
|
+
expect(actions_per_nodes['node'][1][:scp].first[1]).to eq '/var/log/deployments'
|
|
159
|
+
expect(actions_per_nodes['node'][2].keys.sort).to eq %i[ruby remote_bash].sort
|
|
160
|
+
expect(actions_per_nodes['node'][2][:remote_bash]).to eq "sudo -u root chmod 600 /var/log/deployments/#{File.basename(tmp_log_file)}"
|
|
161
|
+
# Call the Ruby codes to be tested
|
|
162
|
+
actions_per_nodes['node'][0][:ruby].call
|
|
163
|
+
expect(File.exist?(tmp_log_file)).to eq true
|
|
164
|
+
file_content_regexp = Regexp.new <<~EOREGEXP
|
|
165
|
+
repo_name_0: platform
|
|
166
|
+
commit_id_0: 123456
|
|
167
|
+
commit_message_0: Test commit for node: service1, service2
|
|
168
|
+
date: \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}
|
|
169
|
+
user: test_user
|
|
170
|
+
debug: No
|
|
171
|
+
services: service1, service2
|
|
172
|
+
exit_status: 0
|
|
173
|
+
===== STDOUT =====
|
|
174
|
+
Deploy successful stdout
|
|
175
|
+
===== STDERR =====
|
|
176
|
+
Deploy successful stderr
|
|
177
|
+
EOREGEXP
|
|
178
|
+
expect(File.read(tmp_log_file)).to match file_content_regexp
|
|
179
|
+
actions_per_nodes['node'][2][:ruby].call
|
|
180
|
+
# Check temporary log file gets deleted for security reasons
|
|
181
|
+
expect(File.exist?(tmp_log_file)).to eq false
|
|
182
|
+
end
|
|
183
|
+
]
|
|
184
|
+
with_cmd_runner_mocked [
|
|
185
|
+
['whoami', proc { [0, 'test_user', ''] }]
|
|
186
|
+
] do
|
|
187
|
+
expect(test_deployer.deploy_on('node')).to eq('node' => [0, 'Deploy successful stdout', 'Deploy successful stderr'])
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it 'returns actions to save logs on a local node as root' do
|
|
193
|
+
with_test_platform({ nodes: { 'node' => { meta: { local_node: true }, services: %w[service1 service2] } } }, additional_config: 'send_logs_to :remote_fs') do
|
|
194
|
+
test_actions_executor.connector(:ssh).ssh_user = 'test_user'
|
|
195
|
+
expect_services_handler_to_deploy('node' => %w[service1 service2])
|
|
196
|
+
expect_actions_executor_runs [
|
|
197
|
+
# First run, we expect the mutex to be setup, and the deployment actions to be run
|
|
198
|
+
proc do |actions_per_nodes|
|
|
199
|
+
expect_actions_to_deploy_on(
|
|
200
|
+
actions_per_nodes,
|
|
201
|
+
'node',
|
|
202
|
+
sudo: nil,
|
|
203
|
+
mocked_result: { 'node' => [0, 'Deploy successful stdout', 'Deploy successful stderr'] }
|
|
204
|
+
)
|
|
205
|
+
end,
|
|
206
|
+
# Second run, we expect the mutex to be released
|
|
207
|
+
proc { |actions_per_nodes| expect_actions_to_unlock(actions_per_nodes, 'node', sudo: nil) },
|
|
208
|
+
# Third run, we expect logs to be uploaded on the node
|
|
209
|
+
proc do |actions_per_nodes|
|
|
210
|
+
expect(actions_per_nodes['node'].size).to eq 3
|
|
211
|
+
expect(actions_per_nodes['node'][0].keys.sort).to eq %i[ruby remote_bash].sort
|
|
212
|
+
expect(actions_per_nodes['node'][0][:remote_bash]).to eq 'mkdir -p /var/log/deployments && chmod 600 /var/log/deployments'
|
|
213
|
+
expect(actions_per_nodes['node'][1].keys.sort).to eq %i[scp].sort
|
|
214
|
+
expect(actions_per_nodes['node'][1][:scp].delete(:sudo)).to eq false
|
|
215
|
+
expect(actions_per_nodes['node'][1][:scp].delete(:owner)).to eq 'root'
|
|
216
|
+
expect(actions_per_nodes['node'][1][:scp].delete(:group)).to eq 'root'
|
|
217
|
+
expect(actions_per_nodes['node'][1][:scp].size).to eq 1
|
|
218
|
+
tmp_log_file = actions_per_nodes['node'][1][:scp].first[0]
|
|
219
|
+
expect(actions_per_nodes['node'][1][:scp].first[1]).to eq '/var/log/deployments'
|
|
220
|
+
expect(actions_per_nodes['node'][2].keys.sort).to eq %i[ruby remote_bash].sort
|
|
221
|
+
expect(actions_per_nodes['node'][2][:remote_bash]).to eq "chmod 600 /var/log/deployments/#{File.basename(tmp_log_file)}"
|
|
222
|
+
# Call the Ruby codes to be tested
|
|
223
|
+
actions_per_nodes['node'][0][:ruby].call
|
|
224
|
+
expect(File.exist?(tmp_log_file)).to eq true
|
|
225
|
+
file_content_regexp = Regexp.new <<~EOREGEXP
|
|
226
|
+
repo_name_0: platform
|
|
227
|
+
commit_id_0: 123456
|
|
228
|
+
commit_message_0: Test commit for node: service1, service2
|
|
229
|
+
date: \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}
|
|
230
|
+
user: test_user
|
|
231
|
+
debug: No
|
|
232
|
+
services: service1, service2
|
|
233
|
+
exit_status: 0
|
|
234
|
+
===== STDOUT =====
|
|
235
|
+
Deploy successful stdout
|
|
236
|
+
===== STDERR =====
|
|
237
|
+
Deploy successful stderr
|
|
238
|
+
EOREGEXP
|
|
239
|
+
expect(File.read(tmp_log_file)).to match file_content_regexp
|
|
240
|
+
actions_per_nodes['node'][2][:ruby].call
|
|
241
|
+
# Check temporary log file gets deleted for security reasons
|
|
242
|
+
expect(File.exist?(tmp_log_file)).to eq false
|
|
243
|
+
end
|
|
244
|
+
]
|
|
245
|
+
with_cmd_runner_mocked [
|
|
246
|
+
['whoami', proc { [0, 'root', ''] }]
|
|
247
|
+
] do
|
|
248
|
+
expect(test_deployer.deploy_on('node')).to eq('node' => [0, 'Deploy successful stdout', 'Deploy successful stderr'])
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
132
253
|
it 'reads logs' do
|
|
133
254
|
with_test_platform_for_remote_fs do
|
|
134
255
|
expect_actions_executor_runs [
|
|
@@ -216,6 +337,100 @@ describe HybridPlatformsConductor::Deployer do
|
|
|
216
337
|
end
|
|
217
338
|
end
|
|
218
339
|
|
|
340
|
+
it 'reads logs on a local node' do
|
|
341
|
+
with_test_platform({ nodes: { 'node' => { meta: { local_node: true }, services: %w[service1 service2] } } }, additional_config: 'send_logs_to :remote_fs') do
|
|
342
|
+
expect_actions_executor_runs [
|
|
343
|
+
# Expect the actions to get log files
|
|
344
|
+
proc do |actions_per_nodes|
|
|
345
|
+
expect(actions_per_nodes).to eq('node' => [{ remote_bash: 'sudo -u root cat /var/log/deployments/`sudo -u root ls -t /var/log/deployments/ | head -1`' }])
|
|
346
|
+
{ 'node' => [0, <<~EO_STDOUT, ''] }
|
|
347
|
+
repo_name_0: platform
|
|
348
|
+
commit_id_0: 123456
|
|
349
|
+
commit_message_0: Test commit for node: service1, service2
|
|
350
|
+
diff_files_0: file1, file2, file3
|
|
351
|
+
date: 2017-11-23 18:43:01
|
|
352
|
+
user: test_user
|
|
353
|
+
debug: Yes
|
|
354
|
+
services: service1, service2, service3
|
|
355
|
+
exit_status: 0
|
|
356
|
+
===== STDOUT =====
|
|
357
|
+
Deploy successful stdout
|
|
358
|
+
===== STDERR =====
|
|
359
|
+
Deploy successful stderr
|
|
360
|
+
EO_STDOUT
|
|
361
|
+
end
|
|
362
|
+
]
|
|
363
|
+
with_cmd_runner_mocked [
|
|
364
|
+
['whoami', proc { [0, 'test_user', ''] }]
|
|
365
|
+
] do
|
|
366
|
+
expect(test_deployer.deployment_info_from('node')).to eq(
|
|
367
|
+
'node' => {
|
|
368
|
+
deployment_info: {
|
|
369
|
+
repo_name_0: 'platform',
|
|
370
|
+
commit_id_0: '123456',
|
|
371
|
+
commit_message_0: 'Test commit for node: service1, service2',
|
|
372
|
+
diff_files_0: %w[file1 file2 file3],
|
|
373
|
+
date: Time.parse('2017-11-23 18:43:01 UTC'),
|
|
374
|
+
debug: true,
|
|
375
|
+
user: 'test_user'
|
|
376
|
+
},
|
|
377
|
+
exit_status: 0,
|
|
378
|
+
services: %w[service1 service2 service3],
|
|
379
|
+
stderr: 'Deploy successful stderr',
|
|
380
|
+
stdout: 'Deploy successful stdout'
|
|
381
|
+
}
|
|
382
|
+
)
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
it 'reads logs on a local node as root' do
|
|
388
|
+
with_test_platform({ nodes: { 'node' => { meta: { local_node: true }, services: %w[service1 service2] } } }, additional_config: 'send_logs_to :remote_fs') do
|
|
389
|
+
expect_actions_executor_runs [
|
|
390
|
+
# Expect the actions to get log files
|
|
391
|
+
proc do |actions_per_nodes|
|
|
392
|
+
expect(actions_per_nodes).to eq('node' => [{ remote_bash: 'cat /var/log/deployments/`ls -t /var/log/deployments/ | head -1`' }])
|
|
393
|
+
{ 'node' => [0, <<~EO_STDOUT, ''] }
|
|
394
|
+
repo_name_0: platform
|
|
395
|
+
commit_id_0: 123456
|
|
396
|
+
commit_message_0: Test commit for node: service1, service2
|
|
397
|
+
diff_files_0: file1, file2, file3
|
|
398
|
+
date: 2017-11-23 18:43:01
|
|
399
|
+
user: test_user
|
|
400
|
+
debug: Yes
|
|
401
|
+
services: service1, service2, service3
|
|
402
|
+
exit_status: 0
|
|
403
|
+
===== STDOUT =====
|
|
404
|
+
Deploy successful stdout
|
|
405
|
+
===== STDERR =====
|
|
406
|
+
Deploy successful stderr
|
|
407
|
+
EO_STDOUT
|
|
408
|
+
end
|
|
409
|
+
]
|
|
410
|
+
with_cmd_runner_mocked [
|
|
411
|
+
['whoami', proc { [0, 'root', ''] }]
|
|
412
|
+
] do
|
|
413
|
+
expect(test_deployer.deployment_info_from('node')).to eq(
|
|
414
|
+
'node' => {
|
|
415
|
+
deployment_info: {
|
|
416
|
+
repo_name_0: 'platform',
|
|
417
|
+
commit_id_0: '123456',
|
|
418
|
+
commit_message_0: 'Test commit for node: service1, service2',
|
|
419
|
+
diff_files_0: %w[file1 file2 file3],
|
|
420
|
+
date: Time.parse('2017-11-23 18:43:01 UTC'),
|
|
421
|
+
debug: true,
|
|
422
|
+
user: 'test_user'
|
|
423
|
+
},
|
|
424
|
+
exit_status: 0,
|
|
425
|
+
services: %w[service1 service2 service3],
|
|
426
|
+
stderr: 'Deploy successful stderr',
|
|
427
|
+
stdout: 'Deploy successful stdout'
|
|
428
|
+
}
|
|
429
|
+
)
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
|
|
219
434
|
end
|
|
220
435
|
|
|
221
436
|
end
|