hybrid_platforms_conductor 32.16.3 → 33.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -0
  3. data/README.md +6 -3
  4. data/bin/last_deploys +4 -1
  5. data/bin/nodes_to_deploy +5 -5
  6. data/docs/config_dsl.md +45 -1
  7. data/docs/executables.md +6 -7
  8. data/docs/executables/check-node.md +3 -3
  9. data/docs/executables/deploy.md +3 -3
  10. data/docs/executables/dump_nodes_json.md +3 -3
  11. data/docs/executables/test.md +3 -3
  12. data/docs/executables/topograph.md +3 -3
  13. data/docs/gen/mermaid/README.md-0.png +0 -0
  14. data/docs/gen/mermaid/docs/executables/check-node.md-0.png +0 -0
  15. data/docs/gen/mermaid/docs/executables/deploy.md-0.png +0 -0
  16. data/docs/gen/mermaid/docs/executables/free_ips.md-0.png +0 -0
  17. data/docs/gen/mermaid/docs/executables/get_impacted_nodes.md-0.png +0 -0
  18. data/docs/gen/mermaid/docs/executables/last_deploys.md-0.png +0 -0
  19. data/docs/gen/mermaid/docs/executables/nodes_to_deploy.md-0.png +0 -0
  20. data/docs/gen/mermaid/docs/executables/report.md-0.png +0 -0
  21. data/docs/gen/mermaid/docs/executables/run.md-0.png +0 -0
  22. data/docs/gen/mermaid/docs/executables/ssh_config.md-0.png +0 -0
  23. data/docs/gen/mermaid/docs/executables/test.md-0.png +0 -0
  24. data/docs/plugins.md +47 -0
  25. data/docs/plugins/connector/ssh.md +1 -1
  26. data/docs/plugins/log/remote_fs.md +26 -0
  27. data/docs/plugins/secrets_reader/cli.md +31 -0
  28. data/docs/plugins/secrets_reader/thycotic.md +46 -0
  29. data/docs/plugins/test/bitbucket_conf.md +1 -1
  30. data/docs/plugins/test/check_deploy_and_idempotence.md +1 -1
  31. data/docs/plugins/test/connection.md +1 -0
  32. data/docs/plugins/test/deploy_removes_root_access.md +1 -1
  33. data/docs/plugins/test/file_system.md +1 -0
  34. data/docs/plugins/test/github_ci.md +48 -0
  35. data/docs/plugins/test/hostname.md +1 -0
  36. data/docs/plugins/test/ip.md +1 -0
  37. data/docs/plugins/test/jenkins_ci_conf.md +1 -1
  38. data/docs/plugins/test/jenkins_ci_masters_ok.md +1 -1
  39. data/docs/plugins/test/local_users.md +1 -0
  40. data/docs/plugins/test/mounts.md +1 -0
  41. data/docs/plugins/test/orphan_files.md +1 -0
  42. data/docs/plugins/test/ports.md +1 -0
  43. data/docs/plugins/test/spectre.md +1 -0
  44. data/docs/plugins/test/vulnerabilities.md +1 -0
  45. data/lib/hybrid_platforms_conductor/actions_executor.rb +8 -1
  46. data/lib/hybrid_platforms_conductor/common_config_dsl/github.rb +62 -0
  47. data/lib/hybrid_platforms_conductor/deployer.rb +193 -141
  48. data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +3 -3
  49. data/lib/hybrid_platforms_conductor/hpc_plugins/log/my_log_plugin.rb.sample +100 -0
  50. data/lib/hybrid_platforms_conductor/hpc_plugins/log/remote_fs.rb +179 -0
  51. data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/cli.rb +75 -0
  52. data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/my_secrets_reader_plugin.rb.sample +46 -0
  53. data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/thycotic.rb +87 -0
  54. data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_deploy_and_idempotence.rb +1 -1
  55. data/lib/hybrid_platforms_conductor/hpc_plugins/test/connection.rb +3 -1
  56. data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_freshness.rb +7 -20
  57. data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_removes_root_access.rb +1 -1
  58. data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system.rb +2 -1
  59. data/lib/hybrid_platforms_conductor/hpc_plugins/test/github_ci.rb +32 -0
  60. data/lib/hybrid_platforms_conductor/hpc_plugins/test/hostname.rb +3 -1
  61. data/lib/hybrid_platforms_conductor/hpc_plugins/test/ip.rb +3 -1
  62. data/lib/hybrid_platforms_conductor/hpc_plugins/test/local_users.rb +3 -1
  63. data/lib/hybrid_platforms_conductor/hpc_plugins/test/mounts.rb +3 -1
  64. data/lib/hybrid_platforms_conductor/hpc_plugins/test/orphan_files.rb +3 -1
  65. data/lib/hybrid_platforms_conductor/hpc_plugins/test/ports.rb +3 -1
  66. data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre.rb +3 -1
  67. data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +2 -1
  68. data/lib/hybrid_platforms_conductor/log.rb +31 -0
  69. data/lib/hybrid_platforms_conductor/plugins.rb +1 -0
  70. data/lib/hybrid_platforms_conductor/secrets_reader.rb +31 -0
  71. data/lib/hybrid_platforms_conductor/test_only_remote_node.rb +18 -0
  72. data/lib/hybrid_platforms_conductor/version.rb +1 -1
  73. data/spec/hybrid_platforms_conductor_test.rb +27 -6
  74. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb +3 -3
  75. data/spec/hybrid_platforms_conductor_test/api/deployer/config_dsl_spec.rb +46 -4
  76. data/spec/hybrid_platforms_conductor_test/api/deployer/deploy_spec.rb +187 -212
  77. data/spec/hybrid_platforms_conductor_test/api/deployer/log_plugins/remote_fs_spec.rb +223 -0
  78. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioner_spec.rb +4 -4
  79. data/spec/hybrid_platforms_conductor_test/api/deployer/secrets_reader_plugins/cli_spec.rb +63 -0
  80. data/spec/hybrid_platforms_conductor_test/api/deployer/secrets_reader_plugins/thycotic_spec.rb +253 -0
  81. data/spec/hybrid_platforms_conductor_test/api/tests_runner/global_spec.rb +1 -1
  82. data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_plugins/github_ci_spec.rb +72 -0
  83. data/spec/hybrid_platforms_conductor_test/executables/last_deploys_spec.rb +146 -98
  84. data/spec/hybrid_platforms_conductor_test/executables/nodes_to_deploy_spec.rb +240 -83
  85. data/spec/hybrid_platforms_conductor_test/executables/options/common_spec.rb +2 -1
  86. data/spec/hybrid_platforms_conductor_test/executables/options/deployer_spec.rb +0 -182
  87. data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +1 -1
  88. data/spec/hybrid_platforms_conductor_test/helpers/deployer_helpers.rb +40 -53
  89. data/spec/hybrid_platforms_conductor_test/helpers/deployer_test_helpers.rb +251 -15
  90. data/spec/hybrid_platforms_conductor_test/test_log_no_read_plugin.rb +82 -0
  91. data/spec/hybrid_platforms_conductor_test/test_log_plugin.rb +103 -0
  92. data/spec/hybrid_platforms_conductor_test/test_secrets_reader_plugin.rb +45 -0
  93. metadata +41 -2
@@ -8,23 +8,43 @@ describe 'nodes_to_deploy executable' do
8
8
  # * Parameters::
9
9
  # * *repository* (String): Platform's repository
10
10
  def with_test_platform_for_nodes_to_deploy(additional_platforms_content: '')
11
- with_test_platform({ nodes: { 'node1' => {}, 'node2' => {} } }, false, additional_platforms_content) do |repository|
11
+ with_test_platform(
12
+ { nodes: { 'node1' => {}, 'node2' => {} } },
13
+ false,
14
+ additional_platforms_content + "\nsend_logs_to :test_log"
15
+ ) do |repository|
12
16
  yield repository
13
17
  end
14
18
  end
15
19
 
16
20
  it 'returns all nodes by default' do
17
21
  with_test_platform_for_nodes_to_deploy do
18
- expect_actions_executor_runs([proc do |actions|
19
- expect(actions).to eq(
20
- 'node1' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" },
21
- 'node2' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" }
22
- )
22
+ expect(test_deployer).to receive(:deployment_info_from).with(%w[node1 node2]) do
23
23
  {
24
- 'node1' => [0, "repo_name_0: platform\nexit_status: 0\ncommit_id_0: abcdef1", ''],
25
- 'node2' => [0, "repo_name_0: platform\nexit_status: 0\ncommit_id_0: abcdef2", '']
24
+ 'node1' => {
25
+ services: %w[service1],
26
+ deployment_info: {
27
+ repo_name_0: 'platform',
28
+ commit_id_0: 'abcdef1',
29
+ exit_status: 0
30
+ },
31
+ exit_status: 0,
32
+ stdout: '',
33
+ stderr: ''
34
+ },
35
+ 'node2' => {
36
+ services: %w[service2],
37
+ deployment_info: {
38
+ repo_name_0: 'platform',
39
+ commit_id_0: 'abcdef2',
40
+ exit_status: 0
41
+ },
42
+ exit_status: 0,
43
+ stdout: '',
44
+ stderr: ''
45
+ }
26
46
  }
27
- end])
47
+ end
28
48
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform', from_commit: 'abcdef1', to_commit: 'master') { [%w[node1 node2], [], [], false] }
29
49
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform', from_commit: 'abcdef2', to_commit: 'master') { [%w[node1 node2], [], [], false] }
30
50
  exit_code, stdout, stderr = run 'nodes_to_deploy'
@@ -41,14 +61,21 @@ describe 'nodes_to_deploy executable' do
41
61
 
42
62
  it 'can filter nodes' do
43
63
  with_test_platform_for_nodes_to_deploy do
44
- expect_actions_executor_runs([proc do |actions|
45
- expect(actions).to eq(
46
- 'node2' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" }
47
- )
64
+ expect(test_deployer).to receive(:deployment_info_from).with(%w[node2]) do
48
65
  {
49
- 'node2' => [0, "repo_name_0: platform\nexit_status: 0\ncommit_id_0: abcdef2", '']
66
+ 'node2' => {
67
+ services: %w[service2],
68
+ deployment_info: {
69
+ repo_name_0: 'platform',
70
+ commit_id_0: 'abcdef2',
71
+ exit_status: 0
72
+ },
73
+ exit_status: 0,
74
+ stdout: '',
75
+ stderr: ''
76
+ }
50
77
  }
51
- end])
78
+ end
52
79
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform', from_commit: 'abcdef2', to_commit: 'master') { [%w[node1 node2], [], [], false] }
53
80
  exit_code, stdout, stderr = run 'nodes_to_deploy', '--node', 'node2'
54
81
  expect(exit_code).to eq 0
@@ -63,16 +90,32 @@ describe 'nodes_to_deploy executable' do
63
90
 
64
91
  it 'does not return nodes that have no impact' do
65
92
  with_test_platform_for_nodes_to_deploy do
66
- expect_actions_executor_runs([proc do |actions|
67
- expect(actions).to eq(
68
- 'node1' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" },
69
- 'node2' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" }
70
- )
93
+ expect(test_deployer).to receive(:deployment_info_from).with(%w[node1 node2]) do
71
94
  {
72
- 'node1' => [0, "repo_name_0: platform\nexit_status: 0\ncommit_id_0: abcdef1", ''],
73
- 'node2' => [0, "repo_name_0: platform\nexit_status: 0\ncommit_id_0: abcdef2", '']
95
+ 'node1' => {
96
+ services: %w[service1],
97
+ deployment_info: {
98
+ repo_name_0: 'platform',
99
+ commit_id_0: 'abcdef1',
100
+ exit_status: 0
101
+ },
102
+ exit_status: 0,
103
+ stdout: '',
104
+ stderr: ''
105
+ },
106
+ 'node2' => {
107
+ services: %w[service2],
108
+ deployment_info: {
109
+ repo_name_0: 'platform',
110
+ commit_id_0: 'abcdef2',
111
+ exit_status: 0
112
+ },
113
+ exit_status: 0,
114
+ stdout: '',
115
+ stderr: ''
116
+ }
74
117
  }
75
- end])
118
+ end
76
119
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform', from_commit: 'abcdef1', to_commit: 'master') { [%w[node1], [], [], false] }
77
120
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform', from_commit: 'abcdef2', to_commit: 'master') { [%w[], [], [], false] }
78
121
  exit_code, stdout, stderr = run 'nodes_to_deploy'
@@ -86,16 +129,28 @@ describe 'nodes_to_deploy executable' do
86
129
 
87
130
  it 'considers nodes having no repository info in their logs to be deployed' do
88
131
  with_test_platform_for_nodes_to_deploy do
89
- expect_actions_executor_runs([proc do |actions|
90
- expect(actions).to eq(
91
- 'node1' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" },
92
- 'node2' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" }
93
- )
132
+ expect(test_deployer).to receive(:deployment_info_from).with(%w[node1 node2]) do
94
133
  {
95
- 'node1' => [0, "exit_status: 0\n", ''],
96
- 'node2' => [0, "repo_name_0: platform\nexit_status: 0\ncommit_id_0: abcdef2", '']
134
+ 'node1' => {
135
+ services: %w[service1],
136
+ deployment_info: {},
137
+ exit_status: 0,
138
+ stdout: '',
139
+ stderr: ''
140
+ },
141
+ 'node2' => {
142
+ services: %w[service2],
143
+ deployment_info: {
144
+ repo_name_0: 'platform',
145
+ commit_id_0: 'abcdef2',
146
+ exit_status: 0
147
+ },
148
+ exit_status: 0,
149
+ stdout: '',
150
+ stderr: ''
151
+ }
97
152
  }
98
- end])
153
+ end
99
154
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform', from_commit: 'abcdef2', to_commit: 'master') { [%w[], [], [], false] }
100
155
  exit_code, stdout, stderr = run 'nodes_to_deploy'
101
156
  expect(exit_code).to eq 0
@@ -108,16 +163,32 @@ describe 'nodes_to_deploy executable' do
108
163
 
109
164
  it 'considers nodes having invalid commit ids in their logs to be deployed' do
110
165
  with_test_platform_for_nodes_to_deploy do
111
- expect_actions_executor_runs([proc do |actions|
112
- expect(actions).to eq(
113
- 'node1' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" },
114
- 'node2' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" }
115
- )
166
+ expect(test_deployer).to receive(:deployment_info_from).with(%w[node1 node2]) do
116
167
  {
117
- 'node1' => [0, "repo_name_0: platform\nexit_status: 0\ncommit_id_0: abcdef1", ''],
118
- 'node2' => [0, "repo_name_0: platform\nexit_status: 0\ncommit_id_0: abcdef2", '']
168
+ 'node1' => {
169
+ services: %w[service1],
170
+ deployment_info: {
171
+ repo_name_0: 'platform',
172
+ commit_id_0: 'abcdef1',
173
+ exit_status: 0
174
+ },
175
+ exit_status: 0,
176
+ stdout: '',
177
+ stderr: ''
178
+ },
179
+ 'node2' => {
180
+ services: %w[service2],
181
+ deployment_info: {
182
+ repo_name_0: 'platform',
183
+ commit_id_0: 'abcdef2',
184
+ exit_status: 0
185
+ },
186
+ exit_status: 0,
187
+ stdout: '',
188
+ stderr: ''
189
+ }
119
190
  }
120
- end])
191
+ end
121
192
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform', from_commit: 'abcdef1', to_commit: 'master') do
122
193
  raise HybridPlatformsConductor::NodesHandler::GitError, 'Mocked git error due to an invalid commit id'
123
194
  end
@@ -148,14 +219,21 @@ describe 'nodes_to_deploy executable' do
148
219
  for_nodes(\'node1\') { deployment_schedule(IceCube::Schedule.new(Time.now.utc - 120, duration: 60)) }
149
220
  for_nodes(\'node2\') { deployment_schedule(IceCube::Schedule.new(Time.now.utc - 60, duration: 120)) }
150
221
  ') do
151
- expect_actions_executor_runs([proc do |actions|
152
- expect(actions).to eq(
153
- 'node2' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" }
154
- )
222
+ expect(test_deployer).to receive(:deployment_info_from).with(%w[node2]) do
155
223
  {
156
- 'node2' => [0, "repo_name_0: platform\nexit_status: 0\ncommit_id_0: abcdef2", '']
224
+ 'node2' => {
225
+ services: %w[service2],
226
+ deployment_info: {
227
+ repo_name_0: 'platform',
228
+ commit_id_0: 'abcdef2',
229
+ exit_status: 0
230
+ },
231
+ exit_status: 0,
232
+ stdout: '',
233
+ stderr: ''
234
+ }
157
235
  }
158
- end])
236
+ end
159
237
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform', from_commit: 'abcdef2', to_commit: 'master') { [%w[node1 node2], [], [], false] }
160
238
  exit_code, stdout, stderr = run 'nodes_to_deploy'
161
239
  expect(exit_code).to eq 0
@@ -172,14 +250,21 @@ describe 'nodes_to_deploy executable' do
172
250
  for_nodes(\'node1\') { deployment_schedule(IceCube::Schedule.new(Time.now.utc - 120, duration: 60)) }
173
251
  for_nodes(\'node2\') { deployment_schedule(IceCube::Schedule.new(Time.now.utc - 60, duration: 120)) }
174
252
  ') do
175
- expect_actions_executor_runs([proc do |actions|
176
- expect(actions).to eq(
177
- 'node1' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" }
178
- )
253
+ expect(test_deployer).to receive(:deployment_info_from).with(%w[node1]) do
179
254
  {
180
- 'node1' => [0, "repo_name_0: platform\nexit_status: 0\ncommit_id_0: abcdef1", '']
255
+ 'node1' => {
256
+ services: %w[service1],
257
+ deployment_info: {
258
+ repo_name_0: 'platform',
259
+ commit_id_0: 'abcdef1',
260
+ exit_status: 0
261
+ },
262
+ exit_status: 0,
263
+ stdout: '',
264
+ stderr: ''
265
+ }
181
266
  }
182
- end])
267
+ end
183
268
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform', from_commit: 'abcdef1', to_commit: 'master') { [%w[node1 node2], [], [], false] }
184
269
  # 90 seconds before now, the schedule should match only node1
185
270
  exit_code, stdout, stderr = run 'nodes_to_deploy', '--deployment-time', (Time.now.utc - 90).strftime('%F %T')
@@ -197,16 +282,32 @@ describe 'nodes_to_deploy executable' do
197
282
  for_nodes(\'node1\') { deployment_schedule(IceCube::Schedule.new(Time.now.utc - 120, duration: 60)) }
198
283
  for_nodes(\'node2\') { deployment_schedule(IceCube::Schedule.new(Time.now.utc - 60, duration: 120)) }
199
284
  ') do
200
- expect_actions_executor_runs([proc do |actions|
201
- expect(actions).to eq(
202
- 'node1' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" },
203
- 'node2' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" }
204
- )
285
+ expect(test_deployer).to receive(:deployment_info_from).with(%w[node1 node2]) do
205
286
  {
206
- 'node1' => [0, "repo_name_0: platform\nexit_status: 0\ncommit_id_0: abcdef1", ''],
207
- 'node2' => [0, "repo_name_0: platform\nexit_status: 0\ncommit_id_0: abcdef2", '']
287
+ 'node1' => {
288
+ services: %w[service1],
289
+ deployment_info: {
290
+ repo_name_0: 'platform',
291
+ commit_id_0: 'abcdef1',
292
+ exit_status: 0
293
+ },
294
+ exit_status: 0,
295
+ stdout: '',
296
+ stderr: ''
297
+ },
298
+ 'node2' => {
299
+ services: %w[service2],
300
+ deployment_info: {
301
+ repo_name_0: 'platform',
302
+ commit_id_0: 'abcdef2',
303
+ exit_status: 0
304
+ },
305
+ exit_status: 0,
306
+ stdout: '',
307
+ stderr: ''
308
+ }
208
309
  }
209
- end])
310
+ end
210
311
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform', from_commit: 'abcdef1', to_commit: 'master') { [%w[node1 node2], [], [], false] }
211
312
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform', from_commit: 'abcdef2', to_commit: 'master') { [%w[node1 node2], [], [], false] }
212
313
  exit_code, stdout, stderr = run 'nodes_to_deploy', '--ignore-schedule'
@@ -225,16 +326,32 @@ describe 'nodes_to_deploy executable' do
225
326
  'platform1' => { nodes: { 'node1' => {}, 'node2' => {} } },
226
327
  'platform2' => { nodes: {} }
227
328
  ) do
228
- expect_actions_executor_runs([proc do |actions|
229
- expect(actions).to eq(
230
- 'node1' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" },
231
- 'node2' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" }
232
- )
329
+ expect(test_deployer).to receive(:deployment_info_from).with(%w[node1 node2]) do
233
330
  {
234
- 'node1' => [0, "repo_name_0: platform1\nexit_status: 0\ncommit_id_0: abcdef1", ''],
235
- 'node2' => [0, "repo_name_0: platform2\nexit_status: 0\ncommit_id_0: abcdef2", '']
331
+ 'node1' => {
332
+ services: %w[service1],
333
+ deployment_info: {
334
+ repo_name_0: 'platform1',
335
+ commit_id_0: 'abcdef1',
336
+ exit_status: 0
337
+ },
338
+ exit_status: 0,
339
+ stdout: '',
340
+ stderr: ''
341
+ },
342
+ 'node2' => {
343
+ services: %w[service2],
344
+ deployment_info: {
345
+ repo_name_0: 'platform2',
346
+ commit_id_0: 'abcdef2',
347
+ exit_status: 0
348
+ },
349
+ exit_status: 0,
350
+ stdout: '',
351
+ stderr: ''
352
+ }
236
353
  }
237
- end])
354
+ end
238
355
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform1', from_commit: 'abcdef1', to_commit: 'master') { [%w[node1], [], [], false] }
239
356
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform2', from_commit: 'abcdef2', to_commit: 'master') { [%w[node2], [], [], false] }
240
357
  exit_code, stdout, stderr = run 'nodes_to_deploy'
@@ -253,16 +370,36 @@ describe 'nodes_to_deploy executable' do
253
370
  'platform2' => { nodes: {} },
254
371
  'platform3' => { nodes: {} }
255
372
  ) do
256
- expect_actions_executor_runs([proc do |actions|
257
- expect(actions).to eq(
258
- 'node1' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" },
259
- 'node2' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" }
260
- )
373
+ expect(test_deployer).to receive(:deployment_info_from).with(%w[node1 node2]) do
261
374
  {
262
- 'node1' => [0, "exit_status: 0\nrepo_name_0: platform1\ncommit_id_0: abcdef1\nrepo_name_1: platform2\ncommit_id_1: 1234567", ''],
263
- 'node2' => [0, "exit_status: 0\nrepo_name_0: platform2\ncommit_id_0: abcdef2\nrepo_name_1: platform3\ncommit_id_1: 2345678", '']
375
+ 'node1' => {
376
+ services: %w[service1],
377
+ deployment_info: {
378
+ repo_name_0: 'platform1',
379
+ commit_id_0: 'abcdef1',
380
+ repo_name_1: 'platform2',
381
+ commit_id_1: '1234567',
382
+ exit_status: 0
383
+ },
384
+ exit_status: 0,
385
+ stdout: '',
386
+ stderr: ''
387
+ },
388
+ 'node2' => {
389
+ services: %w[service2],
390
+ deployment_info: {
391
+ repo_name_0: 'platform2',
392
+ commit_id_0: 'abcdef2',
393
+ repo_name_1: 'platform3',
394
+ commit_id_1: '2345678',
395
+ exit_status: 0
396
+ },
397
+ exit_status: 0,
398
+ stdout: '',
399
+ stderr: ''
400
+ }
264
401
  }
265
- end])
402
+ end
266
403
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform1', from_commit: 'abcdef1', to_commit: 'master') { [%w[], [], [], false] }
267
404
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform2', from_commit: '1234567', to_commit: 'master') { [%w[node1], [], [], false] }
268
405
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform2', from_commit: 'abcdef2', to_commit: 'master') { [%w[], [], [], false] }
@@ -283,16 +420,36 @@ describe 'nodes_to_deploy executable' do
283
420
  'platform2' => { nodes: {} },
284
421
  'platform3' => { nodes: {} }
285
422
  ) do
286
- expect_actions_executor_runs([proc do |actions|
287
- expect(actions).to eq(
288
- 'node1' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" },
289
- 'node2' => { remote_bash: "cd /var/log/deployments && ls -t | head -1 | xargs sed '/===== STDOUT =====/q'" }
290
- )
423
+ expect(test_deployer).to receive(:deployment_info_from).with(%w[node1 node2]) do
291
424
  {
292
- 'node1' => [0, "exit_status: 0\nrepo_name_0: platform1\ncommit_id_0: abcdef1\nrepo_name_1: platform2\ncommit_id_1: 1234567", ''],
293
- 'node2' => [0, "exit_status: 0\nrepo_name_0: platform2\ncommit_id_0: abcdef2\nrepo_name_1: platform3\ncommit_id_1: 2345678", '']
425
+ 'node1' => {
426
+ services: %w[service1],
427
+ deployment_info: {
428
+ repo_name_0: 'platform1',
429
+ commit_id_0: 'abcdef1',
430
+ repo_name_1: 'platform2',
431
+ commit_id_1: '1234567',
432
+ exit_status: 0
433
+ },
434
+ exit_status: 0,
435
+ stdout: '',
436
+ stderr: ''
437
+ },
438
+ 'node2' => {
439
+ services: %w[service2],
440
+ deployment_info: {
441
+ repo_name_0: 'platform2',
442
+ commit_id_0: 'abcdef2',
443
+ repo_name_1: 'platform3',
444
+ commit_id_1: '2345678',
445
+ exit_status: 0
446
+ },
447
+ exit_status: 0,
448
+ stdout: '',
449
+ stderr: ''
450
+ }
294
451
  }
295
- end])
452
+ end
296
453
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform1', from_commit: 'abcdef1', to_commit: 'master') { [%w[node1], [], [], false] }
297
454
  expect(test_nodes_handler).to receive(:impacted_nodes_from_git_diff).with('platform2', from_commit: 'abcdef2', to_commit: 'master') { [%w[node2], [], [], false] }
298
455
  exit_code, stdout, stderr = run 'nodes_to_deploy'
@@ -12,7 +12,8 @@ describe 'executables\' common options' do
12
12
  nodes: { 'node1' => { meta: { host_ip: '192.168.42.42' }, services: ['node1_service'] } },
13
13
  deployable_services: %w[node1_service]
14
14
  },
15
- true
15
+ true,
16
+ 'send_logs_to :test_log'
16
17
  ) do |repository|
17
18
  yield repository
18
19
  end
@@ -12,188 +12,6 @@ describe 'executables\' Deployer options' do
12
12
  end
13
13
  end
14
14
 
15
- # Mock calls being made to a Thycotic SOAP API using Savon
16
- #
17
- # Parameters::
18
- # * *url* (String): Mocked URL
19
- # * *secret_id* (String): The mocked secret ID
20
- # * *mocked_secrets_file* (String or nil): The mocked secrets file stored in Thycotic, or nil to mock a missing secret
21
- # * *user* (String or nil): The user to be expected, or nil if it should be read from netrc [default: nil]
22
- # * *password* (String or nil): The password to be expected, or nil if it should be read from netrc [default: nil]
23
- def mock_thycotic_file_download_on(url, secret_id, mocked_secrets_file, user: nil, password: nil)
24
- if user.nil?
25
- user = 'thycotic_user_from_netrc'
26
- password = 'thycotic_password_from_netrc'
27
- expect(HybridPlatformsConductor::Credentials).to receive(:with_credentials_for) do |id, _logger, _logger_stderr, url: nil, &client_code|
28
- expect(id).to eq :thycotic
29
- expect(url).to eq url
30
- client_code.call user, password
31
- end
32
- end
33
- # Mock the Savon calls
34
- mocked_savon_client = double 'Mocked Savon client'
35
- expect(Savon).to receive(:client) do |params|
36
- expect(params[:wsdl]).to eq "#{url}/webservices/SSWebservice.asmx?wsdl"
37
- expect(params[:ssl_verify_mode]).to eq :none
38
- mocked_savon_client
39
- end
40
- expect(mocked_savon_client).to receive(:call).with(
41
- :authenticate,
42
- message: {
43
- username: user,
44
- password: password,
45
- domain: 'thycotic_auth_domain'
46
- }
47
- ) do
48
- { authenticate_response: { authenticate_result: { token: 'soap_token' } } }
49
- end
50
- expect(mocked_savon_client).to receive(:call).with(
51
- :get_secret,
52
- message: {
53
- token: 'soap_token',
54
- secretId: secret_id
55
- }
56
- ) do
57
- {
58
- get_secret_response: {
59
- get_secret_result:
60
- if mocked_secrets_file
61
- { secret: { items: { secret_item: { id: '4242' } } } }
62
- else
63
- { errors: { string: 'Access Denied'}, secret_error: { error_code: 'LOAD', error_message: 'Access Denied', allows_response: false } }
64
- end
65
- }
66
- }
67
- end
68
- if mocked_secrets_file
69
- expect(mocked_savon_client).to receive(:call).with(
70
- :download_file_attachment_by_item_id,
71
- message: {
72
- token: 'soap_token',
73
- secretId: secret_id,
74
- secretItemId: '4242'
75
- }
76
- ) do
77
- {
78
- download_file_attachment_by_item_id_response: {
79
- download_file_attachment_by_item_id_result: {
80
- file_attachment: Base64.encode64(mocked_secrets_file)
81
- }
82
- }
83
- }
84
- end
85
- end
86
- ENV['hpc_domain_for_thycotic'] = 'thycotic_auth_domain'
87
- end
88
-
89
- it 'gets secrets from a file' do
90
- with_test_platform_for_deployer_options do |repository|
91
- secrets_file = "#{repository}/my_secrets.json"
92
- File.write(secrets_file, '{ "secret_name": "secret_value" }')
93
- expect(test_deployer).to receive(:deploy_on).with(['node']) do
94
- expect(test_deployer.secrets).to eq [{ 'secret_name' => 'secret_value' }]
95
- {}
96
- end
97
- exit_code, stdout, stderr = run 'deploy', '--node', 'node', '--secrets', secrets_file
98
- expect(exit_code).to eq 0
99
- expect(stderr).to eq ''
100
- end
101
- end
102
-
103
- it 'gets secrets from several files' do
104
- with_test_platform_for_deployer_options do |repository|
105
- secrets_file1 = "#{repository}/my_secrets1.json"
106
- File.write(secrets_file1, '{ "secret1": "value1" }')
107
- secrets_file2 = "#{repository}/my_secrets2.json"
108
- File.write(secrets_file2, '{ "secret2": "value2" }')
109
- expect(test_deployer).to receive(:deploy_on).with(['node']) do
110
- expect(test_deployer.secrets).to eq [{ 'secret1' => 'value1' }, { 'secret2' => 'value2' }]
111
- {}
112
- end
113
- exit_code, stdout, stderr = run 'deploy', '--node', 'node', '--secrets', secrets_file1, '--secrets', secrets_file2
114
- expect(exit_code).to eq 0
115
- expect(stderr).to eq ''
116
- end
117
- end
118
-
119
- it 'fails to get secrets from a missing file' do
120
- with_test_platform_for_deployer_options do
121
- expect do
122
- run 'deploy', '--node', 'node', '--secrets', 'unknown_file.json'
123
- end.to raise_error 'Missing secret file: unknown_file.json'
124
- end
125
- end
126
-
127
- it 'gets secrets from a Thycotic Secret Server' do
128
- with_test_platform_for_deployer_options do
129
- expect(test_deployer).to receive(:deploy_on).with(['node']) do
130
- expect(test_deployer.secrets).to eq [{ 'secret_name' => 'secret_value' }]
131
- {}
132
- end
133
- mock_thycotic_file_download_on('https://my_thycotic.domain.com/SecretServer', '1107', '{ "secret_name": "secret_value" }')
134
- exit_code, stdout, stderr = run 'deploy', '--node', 'node', '--secrets', 'https://my_thycotic.domain.com/SecretServer:1107'
135
- expect(exit_code).to eq 0
136
- expect(stderr).to eq ''
137
- end
138
- end
139
-
140
- it 'gets secrets from a Thycotic Secret Server using env variables' do
141
- with_test_platform_for_deployer_options do
142
- expect(test_deployer).to receive(:deploy_on).with(['node']) do
143
- expect(test_deployer.secrets).to eq [{ 'secret_name' => 'secret_value' }]
144
- {}
145
- end
146
- mock_thycotic_file_download_on(
147
- 'https://my_thycotic.domain.com/SecretServer',
148
- '1107',
149
- '{ "secret_name": "secret_value" }',
150
- user: 'thycotic_user_from_env',
151
- password: 'thycotic_password_from_env'
152
- )
153
- ENV['hpc_user_for_thycotic'] = 'thycotic_user_from_env'
154
- ENV['hpc_password_for_thycotic'] = 'thycotic_password_from_env'
155
- exit_code, stdout, stderr = run 'deploy', '--node', 'node', '--secrets', 'https://my_thycotic.domain.com/SecretServer:1107'
156
- expect(exit_code).to eq 0
157
- expect(stderr).to eq ''
158
- end
159
- end
160
-
161
- it 'gets secrets from several Thycotic Secret Servers and files' do
162
- with_test_platform_for_deployer_options do |repository|
163
- secrets_file1 = "#{repository}/my_secrets1.json"
164
- File.write(secrets_file1, '{ "secret1": "value1" }')
165
- secrets_file3 = "#{repository}/my_secrets3.json"
166
- File.write(secrets_file3, '{ "secret3": "value3" }')
167
- expect(test_deployer).to receive(:deploy_on).with(['node']) do
168
- expect(test_deployer.secrets).to eq [
169
- { 'secret1' => 'value1' },
170
- { 'secret2' => 'value2' },
171
- { 'secret3' => 'value3' },
172
- { 'secret4' => 'value4' }
173
- ]
174
- {}
175
- end
176
- mock_thycotic_file_download_on('https://my_thycotic2.domain.com/SecretServer', '110702', '{ "secret2": "value2" }')
177
- mock_thycotic_file_download_on('https://my_thycotic4.domain.com/SecretServer', '110704', '{ "secret4": "value4" }')
178
- exit_code, stdout, stderr = run 'deploy', '--node', 'node',
179
- '--secrets', secrets_file1,
180
- '--secrets', 'https://my_thycotic2.domain.com/SecretServer:110702',
181
- '--secrets', secrets_file3,
182
- '--secrets', 'https://my_thycotic4.domain.com/SecretServer:110704'
183
- expect(exit_code).to eq 0
184
- expect(stderr).to eq ''
185
- end
186
- end
187
-
188
- it 'fails to get secrets from a missing Thycotic Secret Server' do
189
- with_test_platform_for_deployer_options do
190
- mock_thycotic_file_download_on('https://my_thycotic.domain.com/SecretServer', '1107', nil)
191
- expect do
192
- run 'deploy', '--node', 'node', '--secrets', 'https://my_thycotic.domain.com/SecretServer:1107'
193
- end.to raise_error 'Unable to fetch secret file ID https://my_thycotic.domain.com/SecretServer:1107'
194
- end
195
- end
196
-
197
15
  it 'uses parallel mode' do
198
16
  with_test_platform_for_deployer_options do |repository|
199
17
  expect(test_deployer).to receive(:deploy_on).with(['node']) do