hybrid_platforms_conductor 32.16.3 → 33.0.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/CHANGELOG.md +42 -0
- data/README.md +6 -3
- data/bin/last_deploys +4 -1
- data/bin/nodes_to_deploy +5 -5
- data/docs/config_dsl.md +45 -1
- data/docs/executables.md +6 -7
- data/docs/executables/check-node.md +3 -3
- data/docs/executables/deploy.md +3 -3
- data/docs/executables/dump_nodes_json.md +3 -3
- data/docs/executables/test.md +3 -3
- data/docs/executables/topograph.md +3 -3
- data/docs/gen/mermaid/README.md-0.png +0 -0
- data/docs/gen/mermaid/docs/executables/check-node.md-0.png +0 -0
- data/docs/gen/mermaid/docs/executables/deploy.md-0.png +0 -0
- data/docs/gen/mermaid/docs/executables/free_ips.md-0.png +0 -0
- data/docs/gen/mermaid/docs/executables/get_impacted_nodes.md-0.png +0 -0
- data/docs/gen/mermaid/docs/executables/last_deploys.md-0.png +0 -0
- data/docs/gen/mermaid/docs/executables/nodes_to_deploy.md-0.png +0 -0
- data/docs/gen/mermaid/docs/executables/report.md-0.png +0 -0
- data/docs/gen/mermaid/docs/executables/run.md-0.png +0 -0
- data/docs/gen/mermaid/docs/executables/ssh_config.md-0.png +0 -0
- data/docs/gen/mermaid/docs/executables/test.md-0.png +0 -0
- data/docs/plugins.md +47 -0
- data/docs/plugins/connector/ssh.md +1 -1
- data/docs/plugins/log/remote_fs.md +26 -0
- data/docs/plugins/secrets_reader/cli.md +31 -0
- data/docs/plugins/secrets_reader/thycotic.md +46 -0
- data/docs/plugins/test/bitbucket_conf.md +1 -1
- data/docs/plugins/test/check_deploy_and_idempotence.md +1 -1
- data/docs/plugins/test/connection.md +1 -0
- data/docs/plugins/test/deploy_removes_root_access.md +1 -1
- data/docs/plugins/test/file_system.md +1 -0
- data/docs/plugins/test/github_ci.md +48 -0
- data/docs/plugins/test/hostname.md +1 -0
- data/docs/plugins/test/ip.md +1 -0
- data/docs/plugins/test/jenkins_ci_conf.md +1 -1
- data/docs/plugins/test/jenkins_ci_masters_ok.md +1 -1
- data/docs/plugins/test/local_users.md +1 -0
- data/docs/plugins/test/mounts.md +1 -0
- data/docs/plugins/test/orphan_files.md +1 -0
- data/docs/plugins/test/ports.md +1 -0
- data/docs/plugins/test/spectre.md +1 -0
- data/docs/plugins/test/vulnerabilities.md +1 -0
- data/lib/hybrid_platforms_conductor/actions_executor.rb +8 -1
- data/lib/hybrid_platforms_conductor/common_config_dsl/github.rb +62 -0
- data/lib/hybrid_platforms_conductor/deployer.rb +193 -141
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +3 -3
- data/lib/hybrid_platforms_conductor/hpc_plugins/log/my_log_plugin.rb.sample +100 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/log/remote_fs.rb +179 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/cli.rb +75 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/my_secrets_reader_plugin.rb.sample +46 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/thycotic.rb +87 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_deploy_and_idempotence.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/connection.rb +3 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_freshness.rb +7 -20
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_removes_root_access.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system.rb +2 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/github_ci.rb +32 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/hostname.rb +3 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/ip.rb +3 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/local_users.rb +3 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/mounts.rb +3 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/orphan_files.rb +3 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/ports.rb +3 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre.rb +3 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +2 -1
- data/lib/hybrid_platforms_conductor/log.rb +31 -0
- data/lib/hybrid_platforms_conductor/plugins.rb +1 -0
- data/lib/hybrid_platforms_conductor/secrets_reader.rb +31 -0
- data/lib/hybrid_platforms_conductor/test_only_remote_node.rb +18 -0
- data/lib/hybrid_platforms_conductor/version.rb +1 -1
- data/spec/hybrid_platforms_conductor_test.rb +27 -6
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb +3 -3
- data/spec/hybrid_platforms_conductor_test/api/deployer/config_dsl_spec.rb +46 -4
- data/spec/hybrid_platforms_conductor_test/api/deployer/deploy_spec.rb +187 -212
- data/spec/hybrid_platforms_conductor_test/api/deployer/log_plugins/remote_fs_spec.rb +223 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioner_spec.rb +4 -4
- data/spec/hybrid_platforms_conductor_test/api/deployer/secrets_reader_plugins/cli_spec.rb +63 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/secrets_reader_plugins/thycotic_spec.rb +253 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/global_spec.rb +1 -1
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_plugins/github_ci_spec.rb +72 -0
- data/spec/hybrid_platforms_conductor_test/executables/last_deploys_spec.rb +146 -98
- data/spec/hybrid_platforms_conductor_test/executables/nodes_to_deploy_spec.rb +240 -83
- data/spec/hybrid_platforms_conductor_test/executables/options/common_spec.rb +2 -1
- data/spec/hybrid_platforms_conductor_test/executables/options/deployer_spec.rb +0 -182
- data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +1 -1
- data/spec/hybrid_platforms_conductor_test/helpers/deployer_helpers.rb +40 -53
- data/spec/hybrid_platforms_conductor_test/helpers/deployer_test_helpers.rb +251 -15
- data/spec/hybrid_platforms_conductor_test/test_log_no_read_plugin.rb +82 -0
- data/spec/hybrid_platforms_conductor_test/test_log_plugin.rb +103 -0
- data/spec/hybrid_platforms_conductor_test/test_secrets_reader_plugin.rb +45 -0
- metadata +41 -2
|
@@ -136,7 +136,7 @@ module HybridPlatformsConductorTest
|
|
|
136
136
|
session_exec: true
|
|
137
137
|
)
|
|
138
138
|
with_test_platform(
|
|
139
|
-
{ nodes: { 'node' => { meta: { host_ip: '192.168.42.42', ssh_session_exec: session_exec
|
|
139
|
+
{ nodes: { 'node' => { meta: { host_ip: '192.168.42.42', ssh_session_exec: session_exec } } } },
|
|
140
140
|
false,
|
|
141
141
|
additional_config
|
|
142
142
|
) do
|
|
@@ -68,71 +68,21 @@ module HybridPlatformsConductorTest
|
|
|
68
68
|
Hash[nodes.map { |node| [node, [0, 'Release mutex successful', '']] }]
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
-
# Expect a given set of actions to upload log files on a list of nodes
|
|
71
|
+
# Expect a given set of actions to upload log files on a list of nodes (using the test_log log plugin)
|
|
72
72
|
#
|
|
73
73
|
# Parameters::
|
|
74
74
|
# * *actions* (Object): Actions
|
|
75
75
|
# * *nodes* (String or Array<String>): Node (or list of nodes) that should be checked
|
|
76
|
-
|
|
77
|
-
def expect_actions_to_upload_logs(actions, nodes, sudo: 'sudo -u root')
|
|
76
|
+
def expect_actions_to_upload_logs(actions, nodes)
|
|
78
77
|
nodes = [nodes] if nodes.is_a?(String)
|
|
79
78
|
expect(actions.size).to eq nodes.size
|
|
80
79
|
nodes.each do |node|
|
|
81
80
|
expect(actions.key?(node)).to eq true
|
|
82
|
-
expect(actions[node]
|
|
83
|
-
expect(actions[node][:scp].first[1]).to eq '/var/log/deployments'
|
|
84
|
-
expect(actions[node][:scp][:group]).to eq 'root'
|
|
85
|
-
expect(actions[node][:scp][:owner]).to eq 'root'
|
|
86
|
-
expect(actions[node][:scp][:sudo]).to eq (!sudo.nil?)
|
|
81
|
+
expect(actions[node]).to eq [{ bash: "echo Save test logs to #{node}" }]
|
|
87
82
|
end
|
|
88
83
|
Hash[nodes.map { |node| [node, [0, 'Logs uploaded', '']] }]
|
|
89
84
|
end
|
|
90
85
|
|
|
91
|
-
# Expect some logs to have the following information.
|
|
92
|
-
# Expected logs format:
|
|
93
|
-
#
|
|
94
|
-
# date: 2019-08-14 17:02:57
|
|
95
|
-
# user: muriel
|
|
96
|
-
# debug: Yes
|
|
97
|
-
# repo_name: my_remote_platform
|
|
98
|
-
# commit_id: c0d16b1b7ae286ae4a059185957e08f0ddc95517
|
|
99
|
-
# commit_message: Test commit
|
|
100
|
-
# diff_files:
|
|
101
|
-
# ===== STDOUT =====
|
|
102
|
-
# Deploy successful
|
|
103
|
-
# ===== STDERR =====
|
|
104
|
-
#
|
|
105
|
-
# Parameters::
|
|
106
|
-
# * *logs* (String): The logs content
|
|
107
|
-
# * *stdout* (String): Expected STDOUT
|
|
108
|
-
# * *stderr* (String): Expected STDERR
|
|
109
|
-
# * *properties* (Hash<Symbol, String or Regexp>): Expected properties values, per name. Values can be exact strings or regexps.
|
|
110
|
-
def expect_logs_to_be(logs, stdout, stderr, properties)
|
|
111
|
-
lines = logs.split("\n")
|
|
112
|
-
idx_stdout = lines.index('===== STDOUT =====')
|
|
113
|
-
expect(idx_stdout).not_to eq nil
|
|
114
|
-
idx_stderr = lines.index('===== STDERR =====')
|
|
115
|
-
expect(idx_stderr).not_to eq nil
|
|
116
|
-
logs_properties = Hash[lines[0..idx_stdout - 1].map do |property_line|
|
|
117
|
-
property_fields = property_line.split(': ')
|
|
118
|
-
[
|
|
119
|
-
property_fields.first.to_sym,
|
|
120
|
-
property_fields[1..-1].join(': ')
|
|
121
|
-
]
|
|
122
|
-
end]
|
|
123
|
-
expect(logs_properties.size).to eq properties.size
|
|
124
|
-
properties.each do |expected_property, expected_property_value|
|
|
125
|
-
expect(logs_properties.key?(expected_property)).to eq true
|
|
126
|
-
if expected_property_value.is_a?(String)
|
|
127
|
-
expect(logs_properties[expected_property]).to eq expected_property_value
|
|
128
|
-
else
|
|
129
|
-
expect(logs_properties[expected_property]).to match expected_property_value
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
expect(lines[idx_stdout + 1..idx_stderr - 1].join("\n")).to eq stdout
|
|
133
|
-
expect(lines[idx_stderr + 1..-1].join("\n")).to eq stderr
|
|
134
|
-
end
|
|
135
|
-
|
|
136
86
|
# Get a test Deployer
|
|
137
87
|
#
|
|
138
88
|
# Result::
|
|
@@ -142,6 +92,43 @@ module HybridPlatformsConductorTest
|
|
|
142
92
|
@deployer
|
|
143
93
|
end
|
|
144
94
|
|
|
95
|
+
# Expect the test services handler to be called to deploy a given list of services
|
|
96
|
+
#
|
|
97
|
+
# Parameters::
|
|
98
|
+
# * *services* (Hash<String, Array<String> >): List of services to be expected, per node name
|
|
99
|
+
def expect_services_handler_to_deploy(services)
|
|
100
|
+
expect(test_services_handler).to receive(:deploy_allowed?).with(
|
|
101
|
+
services: services,
|
|
102
|
+
secrets: {},
|
|
103
|
+
local_environment: false
|
|
104
|
+
) do
|
|
105
|
+
nil
|
|
106
|
+
end
|
|
107
|
+
expect(test_services_handler).to receive(:package).with(
|
|
108
|
+
services: services,
|
|
109
|
+
secrets: {},
|
|
110
|
+
local_environment: false
|
|
111
|
+
)
|
|
112
|
+
expect(test_services_handler).to receive(:prepare_for_deploy).with(
|
|
113
|
+
services: services,
|
|
114
|
+
secrets: {},
|
|
115
|
+
local_environment: false,
|
|
116
|
+
why_run: false
|
|
117
|
+
)
|
|
118
|
+
services.each do |node, services|
|
|
119
|
+
expect(test_services_handler).to receive(:actions_to_deploy_on).with(node, services, false) do
|
|
120
|
+
[{ bash: "echo \"Deploying on #{node}\"" }]
|
|
121
|
+
end
|
|
122
|
+
expect(test_services_handler).to receive(:log_info_for).with(node, services) do
|
|
123
|
+
{
|
|
124
|
+
repo_name_0: 'platform',
|
|
125
|
+
commit_id_0: '123456',
|
|
126
|
+
commit_message_0: "Test commit for #{node}: #{services.join(', ')}"
|
|
127
|
+
}
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
145
132
|
end
|
|
146
133
|
|
|
147
134
|
end
|
|
@@ -69,7 +69,7 @@ module HybridPlatformsConductorTest
|
|
|
69
69
|
}
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
|
-
actions << proc { |actions_per_nodes| expect_actions_to_upload_logs(actions_per_nodes, services.keys
|
|
72
|
+
actions << proc { |actions_per_nodes| expect_actions_to_upload_logs(actions_per_nodes, services.keys) }
|
|
73
73
|
end
|
|
74
74
|
actions
|
|
75
75
|
end
|
|
@@ -78,6 +78,8 @@ module HybridPlatformsConductorTest
|
|
|
78
78
|
#
|
|
79
79
|
# Parameters::
|
|
80
80
|
# * *nodes_info* (Hash): Node info to give the platform [default: 1 node having 1 service]
|
|
81
|
+
# * *expect_services_to_deploy* (Hash<String,Array<String>>): Expected services to be deployed [default: all services from nodes_info]
|
|
82
|
+
# * *expect_deploy_allowed* (Boolean): Should we expect the call to deploy_allowed? [default: true]
|
|
81
83
|
# * *expect_package* (Boolean): Should we expect packaging? [default: true]
|
|
82
84
|
# * *expect_prepare_for_deploy* (Boolean): Should we expect calls to prepare for deploy? [default: true]
|
|
83
85
|
# * *expect_connections_to_nodes* (Boolean): Should we expect connections to nodes? [default: true]
|
|
@@ -95,6 +97,8 @@ module HybridPlatformsConductorTest
|
|
|
95
97
|
# * *repository* (String): Path to the repository
|
|
96
98
|
def with_platform_to_deploy(
|
|
97
99
|
nodes_info: { nodes: { 'node' => { services: %w[service] } } },
|
|
100
|
+
expect_services_to_deploy: Hash[nodes_info[:nodes].map { |node, node_info| [node, node_info[:services]] }],
|
|
101
|
+
expect_deploy_allowed: true,
|
|
98
102
|
expect_package: true,
|
|
99
103
|
expect_prepare_for_deploy: true,
|
|
100
104
|
expect_connections_to_nodes: true,
|
|
@@ -109,12 +113,9 @@ module HybridPlatformsConductorTest
|
|
|
109
113
|
additional_config: ''
|
|
110
114
|
)
|
|
111
115
|
platform_name = check_mode ? 'platform' : 'my_remote_platform'
|
|
112
|
-
with_test_platform(nodes_info, !check_mode, additional_config) do |repository|
|
|
116
|
+
with_test_platform(nodes_info, !check_mode, additional_config + "\nsend_logs_to :test_log") do |repository|
|
|
113
117
|
# Mock the ServicesHandler accesses
|
|
114
|
-
|
|
115
|
-
[node, node_info[:services]]
|
|
116
|
-
end]
|
|
117
|
-
unless check_mode
|
|
118
|
+
if !check_mode && expect_deploy_allowed
|
|
118
119
|
expect(test_services_handler).to receive(:deploy_allowed?).with(
|
|
119
120
|
services: expect_services_to_deploy,
|
|
120
121
|
secrets: expect_secrets,
|
|
@@ -144,7 +145,7 @@ module HybridPlatformsConductorTest
|
|
|
144
145
|
end
|
|
145
146
|
test_deployer.use_why_run = true if check_mode
|
|
146
147
|
if expect_connections_to_nodes
|
|
147
|
-
with_connections_mocked_on(
|
|
148
|
+
with_connections_mocked_on(expect_services_to_deploy.keys) do
|
|
148
149
|
expect_actions_executor_runs(expected_actions_for_deploy_on(
|
|
149
150
|
services: expect_services_to_deploy,
|
|
150
151
|
check_mode: check_mode,
|
|
@@ -218,14 +219,7 @@ module HybridPlatformsConductorTest
|
|
|
218
219
|
|
|
219
220
|
it 'deploys on 1 node using 1 secret' do
|
|
220
221
|
with_platform_to_deploy(expect_secrets: { 'secret1' => 'password1' }) do
|
|
221
|
-
test_deployer.
|
|
222
|
-
expect(test_deployer.deploy_on('node')).to eq('node' => expected_deploy_result)
|
|
223
|
-
end
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
it 'deploys on 1 node using several secrets' do
|
|
227
|
-
with_platform_to_deploy(expect_secrets: { 'secret1' => 'password1', 'secret2' => 'password2' }) do
|
|
228
|
-
test_deployer.secrets = [{ 'secret1' => 'password1' }, { 'secret2' => 'password2' }]
|
|
222
|
+
test_deployer.override_secrets('secret1' => 'password1')
|
|
229
223
|
expect(test_deployer.deploy_on('node')).to eq('node' => expected_deploy_result)
|
|
230
224
|
end
|
|
231
225
|
end
|
|
@@ -901,6 +895,248 @@ module HybridPlatformsConductorTest
|
|
|
901
895
|
|
|
902
896
|
end
|
|
903
897
|
|
|
898
|
+
context 'checking secrets handling' do
|
|
899
|
+
|
|
900
|
+
it 'calls secrets readers only for nodes and services to be deployed and merges their secrets' do
|
|
901
|
+
register_plugins(
|
|
902
|
+
:secrets_reader,
|
|
903
|
+
{
|
|
904
|
+
secrets_reader1: HybridPlatformsConductorTest::TestSecretsReaderPlugin,
|
|
905
|
+
secrets_reader2: HybridPlatformsConductorTest::TestSecretsReaderPlugin,
|
|
906
|
+
secrets_reader3: HybridPlatformsConductorTest::TestSecretsReaderPlugin
|
|
907
|
+
}
|
|
908
|
+
)
|
|
909
|
+
with_platform_to_deploy(
|
|
910
|
+
nodes_info: {
|
|
911
|
+
nodes: {
|
|
912
|
+
'node1' => { services: %w[service1 service2] },
|
|
913
|
+
'node2' => { services: %w[service2 service3] },
|
|
914
|
+
'node3' => { services: %w[service3] },
|
|
915
|
+
'node4' => { services: %w[service1 service3] }
|
|
916
|
+
}
|
|
917
|
+
},
|
|
918
|
+
expect_services_to_deploy: {
|
|
919
|
+
'node1' => %w[service1 service2],
|
|
920
|
+
'node2' => %w[service2 service3],
|
|
921
|
+
'node3' => %w[service3]
|
|
922
|
+
},
|
|
923
|
+
expect_secrets: {
|
|
924
|
+
'node1' => {
|
|
925
|
+
'service1' => {
|
|
926
|
+
'secrets_reader1' => 'Secret value',
|
|
927
|
+
'secrets_reader2' => 'Secret value'
|
|
928
|
+
},
|
|
929
|
+
'service2' => {
|
|
930
|
+
'secrets_reader1' => 'Secret value',
|
|
931
|
+
'secrets_reader2' => 'Secret value'
|
|
932
|
+
}
|
|
933
|
+
},
|
|
934
|
+
'node2' => {
|
|
935
|
+
'service2' => {
|
|
936
|
+
'secrets_reader1' => 'Secret value',
|
|
937
|
+
'secrets_reader2' => 'Secret value',
|
|
938
|
+
'secrets_reader3' => 'Secret value'
|
|
939
|
+
},
|
|
940
|
+
'service3' => {
|
|
941
|
+
'secrets_reader1' => 'Secret value',
|
|
942
|
+
'secrets_reader2' => 'Secret value',
|
|
943
|
+
'secrets_reader3' => 'Secret value'
|
|
944
|
+
}
|
|
945
|
+
},
|
|
946
|
+
'node3' => {
|
|
947
|
+
'service3' => {
|
|
948
|
+
'secrets_reader1' => 'Secret value',
|
|
949
|
+
'secrets_reader2' => 'Secret value'
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
},
|
|
953
|
+
additional_config: <<~EOS
|
|
954
|
+
read_secrets_from %i[secrets_reader1 secrets_reader2]
|
|
955
|
+
for_nodes('node2') { read_secrets_from :secrets_reader3 }
|
|
956
|
+
EOS
|
|
957
|
+
) do
|
|
958
|
+
TestSecretsReaderPlugin.deployer = test_deployer
|
|
959
|
+
expect(test_deployer.deploy_on(%w[node1 node2 node3])).to eq(
|
|
960
|
+
'node1' => expected_deploy_result,
|
|
961
|
+
'node2' => expected_deploy_result,
|
|
962
|
+
'node3' => expected_deploy_result
|
|
963
|
+
)
|
|
964
|
+
expect(HybridPlatformsConductorTest::TestSecretsReaderPlugin.calls).to eq [
|
|
965
|
+
{ instance: :secrets_reader1, node: 'node1', service: 'service1' },
|
|
966
|
+
{ instance: :secrets_reader1, node: 'node1', service: 'service2' },
|
|
967
|
+
{ instance: :secrets_reader2, node: 'node1', service: 'service1' },
|
|
968
|
+
{ instance: :secrets_reader2, node: 'node1', service: 'service2' },
|
|
969
|
+
{ instance: :secrets_reader1, node: 'node2', service: 'service2' },
|
|
970
|
+
{ instance: :secrets_reader1, node: 'node2', service: 'service3' },
|
|
971
|
+
{ instance: :secrets_reader2, node: 'node2', service: 'service2' },
|
|
972
|
+
{ instance: :secrets_reader2, node: 'node2', service: 'service3' },
|
|
973
|
+
{ instance: :secrets_reader3, node: 'node2', service: 'service2' },
|
|
974
|
+
{ instance: :secrets_reader3, node: 'node2', service: 'service3' },
|
|
975
|
+
{ instance: :secrets_reader1, node: 'node3', service: 'service3' },
|
|
976
|
+
{ instance: :secrets_reader2, node: 'node3', service: 'service3' }
|
|
977
|
+
]
|
|
978
|
+
end
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
it 'merges secrets having same values' do
|
|
982
|
+
register_plugins(
|
|
983
|
+
:secrets_reader,
|
|
984
|
+
{
|
|
985
|
+
secrets_reader1: HybridPlatformsConductorTest::TestSecretsReaderPlugin,
|
|
986
|
+
secrets_reader2: HybridPlatformsConductorTest::TestSecretsReaderPlugin
|
|
987
|
+
}
|
|
988
|
+
)
|
|
989
|
+
with_platform_to_deploy(
|
|
990
|
+
nodes_info: {
|
|
991
|
+
nodes: {
|
|
992
|
+
'node1' => { services: %w[service1] },
|
|
993
|
+
'node2' => { services: %w[service2] }
|
|
994
|
+
}
|
|
995
|
+
},
|
|
996
|
+
expect_secrets: {
|
|
997
|
+
'global1' => 'value1',
|
|
998
|
+
'global2' => 'value2',
|
|
999
|
+
'global3' => 'value3',
|
|
1000
|
+
'global4' => 'value4'
|
|
1001
|
+
},
|
|
1002
|
+
additional_config: <<~EOS
|
|
1003
|
+
read_secrets_from :secrets_reader1
|
|
1004
|
+
for_nodes('node2') { read_secrets_from :secrets_reader2 }
|
|
1005
|
+
EOS
|
|
1006
|
+
) do
|
|
1007
|
+
TestSecretsReaderPlugin.deployer = test_deployer
|
|
1008
|
+
TestSecretsReaderPlugin.mocked_secrets = {
|
|
1009
|
+
'node1' => {
|
|
1010
|
+
'service1' => {
|
|
1011
|
+
secrets_reader1: {
|
|
1012
|
+
'global1' => 'value1',
|
|
1013
|
+
'global2' => 'value2'
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
},
|
|
1017
|
+
'node2' => {
|
|
1018
|
+
'service2' => {
|
|
1019
|
+
secrets_reader1: {
|
|
1020
|
+
'global2' => 'value2',
|
|
1021
|
+
'global3' => 'value3'
|
|
1022
|
+
},
|
|
1023
|
+
secrets_reader2: {
|
|
1024
|
+
'global3' => 'value3',
|
|
1025
|
+
'global4' => 'value4'
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
expect(test_deployer.deploy_on(%w[node1 node2])).to eq(
|
|
1031
|
+
'node1' => expected_deploy_result,
|
|
1032
|
+
'node2' => expected_deploy_result
|
|
1033
|
+
)
|
|
1034
|
+
expect(HybridPlatformsConductorTest::TestSecretsReaderPlugin.calls).to eq [
|
|
1035
|
+
{ instance: :secrets_reader1, node: 'node1', service: 'service1' },
|
|
1036
|
+
{ instance: :secrets_reader1, node: 'node2', service: 'service2' },
|
|
1037
|
+
{ instance: :secrets_reader2, node: 'node2', service: 'service2' }
|
|
1038
|
+
]
|
|
1039
|
+
end
|
|
1040
|
+
end
|
|
1041
|
+
|
|
1042
|
+
it 'fails when merging secrets having different values' do
|
|
1043
|
+
register_plugins(
|
|
1044
|
+
:secrets_reader,
|
|
1045
|
+
{
|
|
1046
|
+
secrets_reader1: HybridPlatformsConductorTest::TestSecretsReaderPlugin,
|
|
1047
|
+
secrets_reader2: HybridPlatformsConductorTest::TestSecretsReaderPlugin
|
|
1048
|
+
}
|
|
1049
|
+
)
|
|
1050
|
+
with_platform_to_deploy(
|
|
1051
|
+
nodes_info: {
|
|
1052
|
+
nodes: {
|
|
1053
|
+
'node1' => { services: %w[service1] },
|
|
1054
|
+
'node2' => { services: %w[service2] }
|
|
1055
|
+
}
|
|
1056
|
+
},
|
|
1057
|
+
expect_deploy_allowed: false,
|
|
1058
|
+
expect_package: false,
|
|
1059
|
+
expect_prepare_for_deploy: false,
|
|
1060
|
+
expect_connections_to_nodes: false,
|
|
1061
|
+
additional_config: <<~EOS
|
|
1062
|
+
read_secrets_from :secrets_reader1
|
|
1063
|
+
for_nodes('node2') { read_secrets_from :secrets_reader2 }
|
|
1064
|
+
EOS
|
|
1065
|
+
) do
|
|
1066
|
+
TestSecretsReaderPlugin.deployer = test_deployer
|
|
1067
|
+
TestSecretsReaderPlugin.mocked_secrets = {
|
|
1068
|
+
'node1' => {
|
|
1069
|
+
'service1' => {
|
|
1070
|
+
secrets_reader1: {
|
|
1071
|
+
'global1' => 'value1',
|
|
1072
|
+
'global2' => 'value2'
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
},
|
|
1076
|
+
'node2' => {
|
|
1077
|
+
'service2' => {
|
|
1078
|
+
secrets_reader1: {
|
|
1079
|
+
'global2' => 'value2',
|
|
1080
|
+
'global3' => {
|
|
1081
|
+
'sub_key' => 'value3'
|
|
1082
|
+
}
|
|
1083
|
+
},
|
|
1084
|
+
secrets_reader2: {
|
|
1085
|
+
'global3' => {
|
|
1086
|
+
'sub_key' => 'Other value'
|
|
1087
|
+
},
|
|
1088
|
+
'global4' => 'value4'
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
expect { test_deployer.deploy_on(%w[node1 node2]) }.to raise_error 'Secret set at path global3->sub_key by secrets_reader2 for service service2 on node node2 has conflicting values (set debug for value details).'
|
|
1094
|
+
expect(HybridPlatformsConductorTest::TestSecretsReaderPlugin.calls).to eq [
|
|
1095
|
+
{ instance: :secrets_reader1, node: 'node1', service: 'service1' },
|
|
1096
|
+
{ instance: :secrets_reader1, node: 'node2', service: 'service2' },
|
|
1097
|
+
{ instance: :secrets_reader2, node: 'node2', service: 'service2' }
|
|
1098
|
+
]
|
|
1099
|
+
end
|
|
1100
|
+
end
|
|
1101
|
+
|
|
1102
|
+
it 'does not call secrets readers when secrets are overridden' do
|
|
1103
|
+
register_plugins(
|
|
1104
|
+
:secrets_reader,
|
|
1105
|
+
{
|
|
1106
|
+
secrets_reader1: HybridPlatformsConductorTest::TestSecretsReaderPlugin,
|
|
1107
|
+
secrets_reader2: HybridPlatformsConductorTest::TestSecretsReaderPlugin,
|
|
1108
|
+
secrets_reader3: HybridPlatformsConductorTest::TestSecretsReaderPlugin
|
|
1109
|
+
}
|
|
1110
|
+
)
|
|
1111
|
+
with_platform_to_deploy(
|
|
1112
|
+
nodes_info: {
|
|
1113
|
+
nodes: {
|
|
1114
|
+
'node1' => { services: %w[service1] },
|
|
1115
|
+
'node2' => { services: %w[service2] },
|
|
1116
|
+
'node3' => { services: %w[service3] }
|
|
1117
|
+
}
|
|
1118
|
+
},
|
|
1119
|
+
expect_secrets: {
|
|
1120
|
+
'overridden_secrets' => 'value'
|
|
1121
|
+
},
|
|
1122
|
+
additional_config: <<~EOS
|
|
1123
|
+
read_secrets_from %i[secrets_reader1 secrets_reader2]
|
|
1124
|
+
for_nodes('node2') { read_secrets_from :secrets_reader3 }
|
|
1125
|
+
EOS
|
|
1126
|
+
) do
|
|
1127
|
+
TestSecretsReaderPlugin.deployer = test_deployer
|
|
1128
|
+
test_deployer.override_secrets('overridden_secrets' => 'value')
|
|
1129
|
+
expect(test_deployer.deploy_on(%w[node1 node2 node3])).to eq(
|
|
1130
|
+
'node1' => expected_deploy_result,
|
|
1131
|
+
'node2' => expected_deploy_result,
|
|
1132
|
+
'node3' => expected_deploy_result
|
|
1133
|
+
)
|
|
1134
|
+
expect(HybridPlatformsConductorTest::TestSecretsReaderPlugin.calls).to eq []
|
|
1135
|
+
end
|
|
1136
|
+
end
|
|
1137
|
+
|
|
1138
|
+
end
|
|
1139
|
+
|
|
904
1140
|
end
|
|
905
1141
|
|
|
906
1142
|
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module HybridPlatformsConductorTest
|
|
2
|
+
|
|
3
|
+
# Test log without reading actions
|
|
4
|
+
class TestLogNoReadPlugin < HybridPlatformsConductor::Log
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
attr_accessor :calls
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Get actions to save logs
|
|
11
|
+
# [API] - This method is mandatory.
|
|
12
|
+
# [API] - The following API components are accessible:
|
|
13
|
+
# * *@config* (Config): Main configuration API.
|
|
14
|
+
# * *@nodes_handler* (NodesHandler): Nodes handler API.
|
|
15
|
+
# * *@actions_executor* (ActionsExecutor): Actions executor API.
|
|
16
|
+
#
|
|
17
|
+
# Parameters::
|
|
18
|
+
# * *node* (String): Node for which logs are being saved
|
|
19
|
+
# * *services* (Array<String>): The list of services that have been deployed on this node
|
|
20
|
+
# * *deployment_info* (Hash<Symbol,Object>): Additional information to attach to the logs
|
|
21
|
+
# * *exit_status* (Integer or Symbol): Exit status of the deployment
|
|
22
|
+
# * *stdout* (String): Deployment's stdout
|
|
23
|
+
# * *stderr* (String): Deployment's stderr
|
|
24
|
+
# Result::
|
|
25
|
+
# * Array< Hash<Symbol,Object> >: List of actions to be done
|
|
26
|
+
def actions_to_save_logs(node, services, deployment_info, exit_status, stdout, stderr)
|
|
27
|
+
TestLogNoReadPlugin.calls << {
|
|
28
|
+
method: :actions_to_save_logs,
|
|
29
|
+
node: node,
|
|
30
|
+
services: services,
|
|
31
|
+
# Don't store the date
|
|
32
|
+
deployment_info: deployment_info.select { |k, _v| k != :date },
|
|
33
|
+
exit_status: exit_status,
|
|
34
|
+
stdout: stdout,
|
|
35
|
+
stderr: stderr
|
|
36
|
+
}
|
|
37
|
+
[{ bash: "echo Save test logs to #{node}" }]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Get deployment logs from a node.
|
|
41
|
+
# This method can use the result of actions previously run to read logs, as returned by the actions_to_read_logs method.
|
|
42
|
+
# [API] - This method is mandatory.
|
|
43
|
+
# [API] - The following API components are accessible:
|
|
44
|
+
# * *@config* (Config): Main configuration API.
|
|
45
|
+
# * *@nodes_handler* (NodesHandler): Nodes handler API.
|
|
46
|
+
# * *@actions_executor* (ActionsExecutor): Actions executor API.
|
|
47
|
+
#
|
|
48
|
+
# Parameters::
|
|
49
|
+
# * *node* (String): The node we want deployment logs from
|
|
50
|
+
# * *exit_status* (Integer, Symbol or nil): Exit status of actions to read logs, or nil if no action was returned by actions_to_read_logs
|
|
51
|
+
# * *stdout* (String or nil): stdout of actions to read logs, or nil if no action was returned by actions_to_read_logs
|
|
52
|
+
# * *stderr* (String or nil): stderr of actions to read logs, or nil if no action was returned by actions_to_read_logs
|
|
53
|
+
# Result::
|
|
54
|
+
# * Hash<Symbol,Object>: Deployment log information:
|
|
55
|
+
# * *error* (String): Error string in case deployment logs could not be retrieved. If set then further properties will be ignored. [optional]
|
|
56
|
+
# * *services* (Array<String>): List of services deployed on the node
|
|
57
|
+
# * *deployment_info* (Hash<Symbol,Object>): Deployment metadata
|
|
58
|
+
# * *exit_status* (Integer or Symbol): Deployment exit status
|
|
59
|
+
# * *stdout* (String): Deployment stdout
|
|
60
|
+
# * *stderr* (String): Deployment stderr
|
|
61
|
+
def logs_for(node, exit_status, stdout, stderr)
|
|
62
|
+
TestLogNoReadPlugin.calls << {
|
|
63
|
+
method: :logs_for,
|
|
64
|
+
node: node,
|
|
65
|
+
exit_status: exit_status,
|
|
66
|
+
stdout: stdout,
|
|
67
|
+
stderr: stderr
|
|
68
|
+
}
|
|
69
|
+
{
|
|
70
|
+
services: %w[unknown],
|
|
71
|
+
deployment_info: {
|
|
72
|
+
user: 'test_user'
|
|
73
|
+
},
|
|
74
|
+
exit_status: 666,
|
|
75
|
+
stdout: 'Deployment test stdout',
|
|
76
|
+
stderr: 'Deployment test stderr'
|
|
77
|
+
}
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end
|