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.
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