hybrid_platforms_conductor 32.13.3 → 32.16.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -0
  3. data/bin/get_impacted_nodes +1 -1
  4. data/bin/setup +6 -1
  5. data/docs/plugins.md +1 -0
  6. data/docs/plugins/platform_handler/serverless_chef.md +111 -0
  7. data/lib/hybrid_platforms_conductor/cmd_runner.rb +13 -1
  8. data/lib/hybrid_platforms_conductor/connector.rb +4 -2
  9. data/lib/hybrid_platforms_conductor/deployer.rb +2 -1
  10. data/lib/hybrid_platforms_conductor/hpc_plugins/connector/local.rb +1 -1
  11. data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb +535 -0
  12. data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef/dsl_parser.rb +51 -0
  13. data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef/recipes_tree_builder.rb +232 -0
  14. data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +1 -0
  15. data/lib/hybrid_platforms_conductor/nodes_handler.rb +9 -5
  16. data/lib/hybrid_platforms_conductor/version.rb +1 -1
  17. data/spec/hybrid_platforms_conductor_test.rb +3 -0
  18. data/spec/hybrid_platforms_conductor_test/api/cmd_runner_spec.rb +7 -0
  19. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioner_spec.rb +23 -0
  20. data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs_plugins_api_spec.rb +11 -0
  21. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/config_dsl_spec.rb +17 -0
  22. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/deploy_output_parsing_spec.rb +94 -0
  23. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/diff_impacts_spec.rb +317 -0
  24. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/inventory_spec.rb +65 -0
  25. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/packaging_spec.rb +292 -0
  26. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/services_deployment_spec.rb +272 -0
  27. data/spec/hybrid_platforms_conductor_test/helpers/cmd_runner_helpers.rb +1 -1
  28. data/spec/hybrid_platforms_conductor_test/helpers/serverless_chef_helpers.rb +53 -0
  29. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_node/chef_versions.yml +3 -0
  30. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_node/nodes/node.json +14 -0
  31. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_node/policyfiles/test_policy.rb +3 -0
  32. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/data_bags/chef_versions.yml +3 -0
  33. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/data_bags/data_bags/my_bag/my_item.json +4 -0
  34. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/data_bags/nodes/node.json +14 -0
  35. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/data_bags/policyfiles/test_policy.rb +3 -0
  36. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/hpc_test/chef_versions.yml +3 -0
  37. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/hpc_test/cookbooks/hpc_test/recipes/after_run.rb +1 -0
  38. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/hpc_test/cookbooks/hpc_test/recipes/before_run.rb +1 -0
  39. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/hpc_test/nodes/node.json +10 -0
  40. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/hpc_test/policyfiles/test_policy.rb +3 -0
  41. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/cookbooks/test_cookbook_1/recipes/default.rb +1 -0
  42. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/cookbooks/test_cookbook_2/libraries/default.rb +4 -0
  43. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/cookbooks/test_cookbook_2/recipes/default.rb +1 -0
  44. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/cookbooks/test_cookbook_2/recipes/other_recipe.rb +1 -0
  45. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/cookbooks/test_cookbook_2/resources/my_resource.rb +1 -0
  46. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/nodes/node1.json +10 -0
  47. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/nodes/node2.json +10 -0
  48. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/policyfiles/test_policy_1.rb +4 -0
  49. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/policyfiles/test_policy_2.rb +4 -0
  50. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/config.rb +1 -0
  51. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/cookbooks/test_cookbook_1/recipes/default.rb +1 -0
  52. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/nodes/node1.json +10 -0
  53. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/nodes/node2.json +10 -0
  54. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/other_cookbooks/test_cookbook_2/libraries/default.rb +4 -0
  55. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/other_cookbooks/test_cookbook_2/recipes/default.rb +1 -0
  56. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/other_cookbooks/test_cookbook_2/recipes/other_recipe.rb +1 -0
  57. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/other_cookbooks/test_cookbook_2/resources/my_resource.rb +1 -0
  58. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/policyfiles/test_policy_1.rb +4 -0
  59. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/policyfiles/test_policy_2.rb +4 -0
  60. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_nodes/chef_versions.yml +3 -0
  61. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_nodes/nodes/local.json +10 -0
  62. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_nodes/nodes/node1.json +10 -0
  63. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_nodes/nodes/node2.json +10 -0
  64. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_nodes/policyfiles/test_policy_1.rb +3 -0
  65. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_nodes/policyfiles/test_policy_2.rb +3 -0
  66. metadata +192 -143
@@ -0,0 +1,317 @@
1
+ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef do
2
+
3
+ context 'checking files diff impacts' do
4
+
5
+ it 'returns no impact for no diffs' do
6
+ with_serverless_chef_platforms('recipes') do |platform, repository|
7
+ expect(platform.impacts_from({})).to eq [
8
+ [],
9
+ [],
10
+ false
11
+ ]
12
+ end
13
+ end
14
+
15
+ it 'ignores files with no impact' do
16
+ with_serverless_chef_platforms('recipes') do |platform, repository|
17
+ expect(platform.impacts_from(
18
+ 'cookbooks/test_cookbook_1/README.md' => {}
19
+ )).to eq [
20
+ [],
21
+ [],
22
+ false
23
+ ]
24
+ end
25
+ end
26
+
27
+ it 'returns all nodes impact for global files' do
28
+ with_serverless_chef_platforms('recipes') do |platform, repository|
29
+ expect(platform.impacts_from(
30
+ 'global.rb' => {}
31
+ )).to eq [
32
+ [],
33
+ [],
34
+ true
35
+ ]
36
+ end
37
+ end
38
+
39
+ it 'returns direct impacted nodes' do
40
+ with_serverless_chef_platforms('recipes') do |platform, repository|
41
+ expect(platform.impacts_from(
42
+ 'nodes/node1.json' => {}
43
+ )).to eq [
44
+ %w[node1],
45
+ [],
46
+ false
47
+ ]
48
+ end
49
+ end
50
+
51
+ it 'returns direct impacted nodes with strange characters' do
52
+ with_serverless_chef_platforms('recipes') do |platform, repository|
53
+ expect(platform.impacts_from(
54
+ 'nodes/node-v45.env_@user.json' => {}
55
+ )).to eq [
56
+ ['node-v45.env_@user'],
57
+ [],
58
+ false
59
+ ]
60
+ end
61
+ end
62
+
63
+ it 'returns impacted service due to a change in its recipes' do
64
+ with_serverless_chef_platforms('recipes') do |platform, repository|
65
+ expect(platform.impacts_from(
66
+ 'cookbooks/test_cookbook_1/recipes/default.rb' => {}
67
+ )).to eq [
68
+ [],
69
+ %w[test_policy_1],
70
+ false
71
+ ]
72
+ end
73
+ end
74
+
75
+ it 'returns impacted service due to a change in its attributes' do
76
+ with_serverless_chef_platforms('recipes') do |platform, repository|
77
+ expect(platform.impacts_from(
78
+ 'cookbooks/test_cookbook_1/attributes/default.rb' => {}
79
+ )).to eq [
80
+ [],
81
+ %w[test_policy_1],
82
+ false
83
+ ]
84
+ end
85
+ end
86
+
87
+ it 'returns impacted service due to a change in an included template' do
88
+ with_serverless_chef_platforms('recipes') do |platform, repository|
89
+ File.write("#{repository}/cookbooks/test_cookbook_1/recipes/default.rb", <<~EOS)
90
+ template '/home/file' do
91
+ source 'test_template.erb'
92
+ end
93
+ EOS
94
+ expect(platform.impacts_from(
95
+ 'cookbooks/test_cookbook_1/templates/default/test_template.erb' => {}
96
+ )).to eq [
97
+ [],
98
+ %w[test_policy_1],
99
+ false
100
+ ]
101
+ end
102
+ end
103
+
104
+ it 'does not return impacted service due to a change in a non included template' do
105
+ with_serverless_chef_platforms('recipes') do |platform, repository|
106
+ expect(platform.impacts_from(
107
+ 'cookbooks/test_cookbook_1/templates/default/test_template.erb' => {}
108
+ )).to eq [
109
+ [],
110
+ [],
111
+ false
112
+ ]
113
+ end
114
+ end
115
+
116
+ it 'returns impacted service due to a change in an included file' do
117
+ with_serverless_chef_platforms('recipes') do |platform, repository|
118
+ File.write("#{repository}/cookbooks/test_cookbook_1/recipes/default.rb", <<~EOS)
119
+ file '/home/file' do
120
+ source 'test_file'
121
+ end
122
+ EOS
123
+ expect(platform.impacts_from(
124
+ 'cookbooks/test_cookbook_1/files/default/test_file' => {}
125
+ )).to eq [
126
+ [],
127
+ %w[test_policy_1],
128
+ false
129
+ ]
130
+ end
131
+ end
132
+
133
+ it 'does not return impacted service due to a change in a non included file' do
134
+ with_serverless_chef_platforms('recipes') do |platform, repository|
135
+ expect(platform.impacts_from(
136
+ 'cookbooks/test_cookbook_1/files/default/test_file' => {}
137
+ )).to eq [
138
+ [],
139
+ [],
140
+ false
141
+ ]
142
+ end
143
+ end
144
+
145
+ it 'returns impacted service due to a resource usage in a recipe' do
146
+ with_serverless_chef_platforms('recipes') do |platform, repository|
147
+ File.write("#{repository}/cookbooks/test_cookbook_1/recipes/default.rb", <<~EOS)
148
+ test_cookbook_2_my_resource
149
+ EOS
150
+ expect(platform.impacts_from(
151
+ 'cookbooks/test_cookbook_2/resources/my_resource.rb' => {}
152
+ )).to eq [
153
+ [],
154
+ %w[test_policy_1],
155
+ false
156
+ ]
157
+ end
158
+ end
159
+
160
+ it 'does not return impacted service due to a resource not being used in a recipe' do
161
+ with_serverless_chef_platforms('recipes') do |platform, repository|
162
+ expect(platform.impacts_from(
163
+ 'cookbooks/test_cookbook_2/resources/my_resource.rb' => {}
164
+ )).to eq [
165
+ [],
166
+ [],
167
+ false
168
+ ]
169
+ end
170
+ end
171
+
172
+ it 'returns impacted service due to a library helper usage in a recipe' do
173
+ with_serverless_chef_platforms('recipes') do |platform, repository|
174
+ File.write("#{repository}/cookbooks/test_cookbook_1/recipes/default.rb", <<~EOS)
175
+ a = my_library_helper(42)
176
+ EOS
177
+ expect(platform.impacts_from(
178
+ 'cookbooks/test_cookbook_2/libraries/default.rb' => {}
179
+ )).to eq [
180
+ [],
181
+ %w[test_policy_1],
182
+ false
183
+ ]
184
+ end
185
+ end
186
+
187
+ it 'ignored impacted service from an unknown helper' do
188
+ with_serverless_chef_platforms('recipes') do |platform, repository|
189
+ File.write("#{repository}/cookbooks/test_cookbook_1/recipes/default.rb", <<~EOS)
190
+ a = unknown_helper(42)
191
+ EOS
192
+ expect(platform.impacts_from(
193
+ 'cookbooks/test_cookbook_2/recipes/default.rb' => {}
194
+ )).to eq [
195
+ [],
196
+ %w[test_policy_2],
197
+ false
198
+ ]
199
+ end
200
+ end
201
+
202
+ it 'returns impacted service due to an unknown library helper usage that has been configured' do
203
+ with_serverless_chef_platforms(
204
+ 'recipes',
205
+ additional_config: <<~EOS
206
+ helpers_including_recipes(unknown_helper: ['test_cookbook_2'])
207
+ EOS
208
+ ) do |platform, repository|
209
+ File.write("#{repository}/cookbooks/test_cookbook_1/recipes/default.rb", <<~EOS)
210
+ a = unknown_helper(42)
211
+ EOS
212
+ expect(platform.impacts_from(
213
+ 'cookbooks/test_cookbook_2/recipes/default.rb' => {}
214
+ )).to eq [
215
+ [],
216
+ %w[test_policy_1 test_policy_2],
217
+ false
218
+ ]
219
+ end
220
+ end
221
+
222
+ it 'does not return impacted service due to a library helper not being used in a recipe' do
223
+ with_serverless_chef_platforms('recipes') do |platform, repository|
224
+ expect(platform.impacts_from(
225
+ 'cookbooks/test_cookbook_2/libraries/default.rb' => {}
226
+ )).to eq [
227
+ [],
228
+ [],
229
+ false
230
+ ]
231
+ end
232
+ end
233
+
234
+ it 'returns impacted service due to a usage of another cookbook\'s default recipe' do
235
+ with_serverless_chef_platforms('recipes') do |platform, repository|
236
+ File.write("#{repository}/cookbooks/test_cookbook_1/recipes/default.rb", <<~EOS)
237
+ include_recipe 'test_cookbook_2'
238
+ EOS
239
+ expect(platform.impacts_from(
240
+ 'cookbooks/test_cookbook_2/recipes/default.rb' => {}
241
+ )).to eq [
242
+ [],
243
+ %w[test_policy_1 test_policy_2],
244
+ false
245
+ ]
246
+ end
247
+ end
248
+
249
+ it 'returns impacted service due to a usage of another cookbook\'s recipe' do
250
+ with_serverless_chef_platforms('recipes') do |platform, repository|
251
+ File.write("#{repository}/cookbooks/test_cookbook_1/recipes/default.rb", <<~EOS)
252
+ include_recipe 'test_cookbook_2::other_recipe'
253
+ EOS
254
+ expect(platform.impacts_from(
255
+ 'cookbooks/test_cookbook_2/recipes/other_recipe.rb' => {}
256
+ )).to eq [
257
+ [],
258
+ %w[test_policy_1],
259
+ false
260
+ ]
261
+ end
262
+ end
263
+
264
+ it 'ignores cookbooks from cookbook paths that are not configured' do
265
+ with_serverless_chef_platforms('several_cookbooks') do |platform, repository|
266
+ File.write("#{repository}/cookbooks/test_cookbook_1/recipes/default.rb", <<~EOS)
267
+ include_recipe 'test_cookbook_2'
268
+ EOS
269
+ expect(platform.impacts_from(
270
+ 'other_cookbooks/test_cookbook_2/recipes/default.rb' => {}
271
+ )).to eq [
272
+ [],
273
+ %w[],
274
+ true
275
+ ]
276
+ end
277
+ end
278
+
279
+ it 'considers cookbooks from non-standard cookbook paths that are configured' do
280
+ with_serverless_chef_platforms('several_cookbooks') do |platform, repository|
281
+ File.write("#{repository}/cookbooks/test_cookbook_1/recipes/default.rb", <<~EOS)
282
+ include_recipe 'test_cookbook_2'
283
+ EOS
284
+ ENV['hpc_test_cookbooks_path'] = 'other_cookbooks'
285
+ expect(platform.impacts_from(
286
+ 'other_cookbooks/test_cookbook_2/recipes/default.rb' => {}
287
+ )).to eq [
288
+ [],
289
+ %w[test_policy_1 test_policy_2],
290
+ false
291
+ ]
292
+ end
293
+ end
294
+
295
+ it 'ignores cookbooks from cookbook paths that are configured but lie outside the platform' do
296
+ with_repository('other_cookbooks') do |other_repo|
297
+ FileUtils.mkdir_p("#{other_repo}/cookbooks/test_cookbook_2/recipes")
298
+ File.write("#{other_repo}/cookbooks/test_cookbook_2/recipes/default.rb", '')
299
+ with_serverless_chef_platforms('several_cookbooks') do |platform, repository|
300
+ File.write("#{repository}/cookbooks/test_cookbook_1/recipes/default.rb", <<~EOS)
301
+ include_recipe 'test_cookbook_2'
302
+ EOS
303
+ ENV['hpc_test_cookbooks_path'] = "#{other_repo}:other_cookbooks"
304
+ expect(platform.impacts_from(
305
+ 'unknown_cookbooks/test_cookbook_2/recipes/default.rb' => {}
306
+ )).to eq [
307
+ [],
308
+ %w[],
309
+ true
310
+ ]
311
+ end
312
+ end
313
+ end
314
+
315
+ end
316
+
317
+ end
@@ -0,0 +1,65 @@
1
+ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef do
2
+
3
+ context 'checking inventory' do
4
+
5
+ context 'with an empty platform' do
6
+
7
+ it 'returns no node' do
8
+ with_serverless_chef_platforms('empty') do |platform|
9
+ expect(platform.known_nodes).to eq []
10
+ end
11
+ end
12
+
13
+ it 'returns no nodes list' do
14
+ with_serverless_chef_platforms('empty') do |platform|
15
+ expect(platform.respond_to?(:known_nodes_lists)).to eq false
16
+ end
17
+ end
18
+
19
+ it 'returns no deployable services' do
20
+ with_serverless_chef_platforms('empty') do |platform|
21
+ expect(platform.deployable_services).to eq []
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ context 'with a platform having 1 node' do
28
+
29
+ it 'returns the node' do
30
+ with_serverless_chef_platforms('1_node') do |platform|
31
+ expect(platform.known_nodes).to eq ['node']
32
+ end
33
+ end
34
+
35
+ it 'returns correct metadata for this node' do
36
+ with_serverless_chef_platforms('1_node') do |platform|
37
+ expect(platform.metadata_for('node')).to eq(
38
+ description: 'Single test node',
39
+ image: 'debian_9',
40
+ private_ips: ['172.16.0.1'],
41
+ property1: {
42
+ 'property11' => 'value11'
43
+ },
44
+ property2: 'value2'
45
+ )
46
+ end
47
+ end
48
+
49
+ it 'returns correct service for this node' do
50
+ with_serverless_chef_platforms('1_node') do |platform|
51
+ expect(platform.services_for('node')).to eq %w[test_policy]
52
+ end
53
+ end
54
+
55
+ it 'returns deployable services' do
56
+ with_serverless_chef_platforms('1_node') do |platform|
57
+ expect(platform.deployable_services).to eq %w[test_policy]
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,292 @@
1
+ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef do
2
+
3
+ context 'checking services packaging' do
4
+
5
+ # Expect a repository to be packaged and mock it
6
+ #
7
+ # Parameters::
8
+ # * *repository* (String): Repository to be packaged
9
+ # * *policy* (String): Expected policy to be packaged [default: 'test_policy']
10
+ # * *policy_file* (String): Expected policy file used [default: "policyfiles/#{policy}.rb"]
11
+ # * *install* (Boolean): Are we expecting the chef install stage? [default: true]
12
+ # * *export* (Boolean): Are we expecting the chef export stage? [default: true]
13
+ # * *data_bags* (Boolean): Do we expect data bags copy? [default: false]
14
+ # * *env* (String): Expected environment being packaged [default: 'prod']
15
+ # * Proc: Code called with mock in place
16
+ def with_packaging_mocked(
17
+ repository,
18
+ policy: 'test_policy',
19
+ policy_file: "policyfiles/#{policy}.rb",
20
+ install: true,
21
+ export: true,
22
+ data_bags: false,
23
+ env: 'prod'
24
+ )
25
+ with_cmd_runner_mocked(
26
+ if install
27
+ [
28
+ [
29
+ "cd #{repository} && /opt/chef-workstation/bin/chef install #{policy_file}",
30
+ proc do
31
+ # Mock the run_list stored in the lock file
32
+ File.write(
33
+ "#{repository}/#{policy_file.gsub(/.rb$/, '.lock.json')}",
34
+ {
35
+ run_list: eval("[#{File.read("#{repository}/#{policy_file}").split("\n").select { |line| line =~ /^run_list.+$/ }.last.match(/^run_list(.+)$/)[1]}]").flatten
36
+ }.to_json
37
+ )
38
+ [0, 'Chef install done', '']
39
+ end
40
+ ]
41
+ ]
42
+ else
43
+ []
44
+ end +
45
+ if export
46
+ [
47
+ [
48
+ /^cd #{Regexp.escape(repository)} &&\s+sudo rm -rf dist\/#{Regexp.escape(env)}\/#{Regexp.escape(policy)} &&\s+\/opt\/chef-workstation\/bin\/chef export #{Regexp.escape(policy_file)} dist\/#{Regexp.escape(env)}\/#{Regexp.escape(policy)}#{data_bags ? " && cp -ar data_bags/ dist/#{Regexp.escape(env)}/#{Regexp.escape(policy)}/" : ''}$/,
49
+ proc do
50
+ FileUtils.mkdir_p "#{repository}/dist/#{env}/#{policy}"
51
+ FileUtils.cp_r("#{repository}/data_bags", "#{repository}/dist/#{env}/#{policy}/") if data_bags
52
+ [0, 'Chef export done', '']
53
+ end
54
+ ]
55
+ ]
56
+ else
57
+ []
58
+ end
59
+ ) do
60
+ yield
61
+ end
62
+ end
63
+
64
+ context 'with an empty platform' do
65
+
66
+ it 'packages the repository doing nothing' do
67
+ with_serverless_chef_platforms('empty') do |platform, repository|
68
+ with_cmd_runner_mocked([]) do
69
+ platform.package(services: {}, secrets: {}, local_environment: false)
70
+ end
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ context 'with a platform having 1 node' do
77
+
78
+ it 'packages the repository for a given node and service' do
79
+ with_serverless_chef_platforms('1_node') do |platform, repository|
80
+ with_packaging_mocked(repository) do
81
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
82
+ end
83
+ end
84
+ end
85
+
86
+ it 'packages the repository without resolving dependencies when the lock file already exists' do
87
+ with_serverless_chef_platforms('1_node') do |platform, repository|
88
+ File.write("#{repository}/policyfiles/test_policy.lock.json", '{}')
89
+ with_packaging_mocked(repository, install: false) do
90
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
91
+ end
92
+ end
93
+ end
94
+
95
+ it 'packages the repository with secrets' do
96
+ with_serverless_chef_platforms('1_node') do |platform, repository|
97
+ with_packaging_mocked(repository) do
98
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: { secret: 'value' }, local_environment: false)
99
+ secret_file = "#{repository}/dist/prod/test_policy/data_bags/hpc_secrets/hpc_secrets.json"
100
+ expect(File.exist?(secret_file)).to eq true
101
+ expect(JSON.parse(File.read(secret_file))).to eq(
102
+ 'id' => 'hpc_secrets',
103
+ 'secret' => 'value'
104
+ )
105
+ end
106
+ end
107
+ end
108
+
109
+ it 'packages the repository for a given node and service in local mode' do
110
+ with_serverless_chef_platforms('1_node') do |platform, repository|
111
+ with_packaging_mocked(repository, policy_file: 'policyfiles/test_policy.local.rb', env: 'local') do
112
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: true)
113
+ local_policy_file = "#{repository}/policyfiles/test_policy.local.lock.json"
114
+ expect(File.exist?(local_policy_file)).to eq true
115
+ expect(JSON.parse(File.read(local_policy_file))).to eq('run_list' => ['recipe[test_cookbook]'])
116
+ end
117
+ end
118
+ end
119
+
120
+ it 'packages the repository without resolving dependencies when the lock file already exists' do
121
+ with_serverless_chef_platforms('1_node') do |platform, repository|
122
+ File.write("#{repository}/policyfiles/test_policy.lock.json", '{}')
123
+ with_packaging_mocked(repository, install: false) do
124
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
125
+ end
126
+ end
127
+ end
128
+
129
+ it 'does not package the repository twice for the same config' do
130
+ with_serverless_chef_platforms('1_node', as_git: true) do |platform, repository|
131
+ with_packaging_mocked(repository) do
132
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
133
+ end
134
+ with_cmd_runner_mocked([]) do
135
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
136
+ end
137
+ end
138
+ end
139
+
140
+ it 'packages the repository twice when the platform is not taken from git' do
141
+ with_serverless_chef_platforms('1_node') do |platform, repository|
142
+ with_packaging_mocked(repository) do
143
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
144
+ end
145
+ # Wait 2 seconds so that we are sure later Time.now will return different timestamps
146
+ sleep 2
147
+ with_packaging_mocked(repository, install: false) do
148
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
149
+ end
150
+ end
151
+ end
152
+
153
+ it 'packages the repository twice when the platform needs different secrets' do
154
+ with_serverless_chef_platforms('1_node', as_git: true) do |platform, repository|
155
+ with_packaging_mocked(repository) do
156
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: { secret: 'value1' }, local_environment: false)
157
+ end
158
+ with_packaging_mocked(repository, install: false) do
159
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: { secret: 'value2' }, local_environment: false)
160
+ end
161
+ end
162
+ end
163
+
164
+ it 'packages the repository twice when the platform has new local files' do
165
+ with_serverless_chef_platforms('1_node', as_git: true) do |platform, repository|
166
+ with_packaging_mocked(repository) do
167
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
168
+ end
169
+ # Make sure we clean the cache (this mocks another Platform Handler instance running)
170
+ platform.remove_instance_variable :@info
171
+ with_packaging_mocked(repository, install: false) do
172
+ File.write("#{repository}/new_file", 'New file')
173
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
174
+ end
175
+ end
176
+ end
177
+
178
+ it 'packages the repository twice when the platform has modified local files' do
179
+ with_serverless_chef_platforms('1_node', as_git: true) do |platform, repository|
180
+ with_packaging_mocked(repository) do
181
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
182
+ end
183
+ # Wait 2 seconds so that we are sure the modified file will return a different timestamp
184
+ sleep 2
185
+ with_packaging_mocked(repository, install: false) do
186
+ File.write("#{repository}/chef_versions.yml", File.read("#{repository}/chef_versions.yml") + "\n\n")
187
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
188
+ end
189
+ end
190
+ end
191
+
192
+ end
193
+
194
+ context 'with a platform having several nodes' do
195
+
196
+ it 'packages 1 service independently from another' do
197
+ with_serverless_chef_platforms('several_nodes') do |platform, repository|
198
+ with_packaging_mocked(repository, policy: 'test_policy_1') do
199
+ platform.package(services: { 'node1' => %w[test_policy_1] }, secrets: {}, local_environment: false)
200
+ end
201
+ with_packaging_mocked(repository, policy: 'test_policy_2') do
202
+ platform.package(services: { 'node2' => %w[test_policy_2] }, secrets: {}, local_environment: false)
203
+ end
204
+ with_cmd_runner_mocked([]) do
205
+ platform.package(services: { 'node1' => %w[test_policy_1] }, secrets: {}, local_environment: false)
206
+ end
207
+ end
208
+ end
209
+
210
+ it 'packages 1 service independently of the node on which it is to be deployed' do
211
+ with_serverless_chef_platforms('several_nodes') do |platform, repository|
212
+ with_packaging_mocked(repository, policy: 'test_policy_1') do
213
+ platform.package(services: { 'node1' => %w[test_policy_1] }, secrets: {}, local_environment: false)
214
+ end
215
+ with_cmd_runner_mocked([]) do
216
+ platform.package(services: { 'node2' => %w[test_policy_1] }, secrets: {}, local_environment: false)
217
+ end
218
+ end
219
+ end
220
+
221
+ end
222
+
223
+ context 'with a platform having data bags' do
224
+
225
+ it 'packages data bags' do
226
+ with_serverless_chef_platforms('data_bags') do |platform, repository|
227
+ with_packaging_mocked(repository, data_bags: true) do
228
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
229
+ data_bag_file = "#{repository}/dist/prod/test_policy/data_bags/my_bag/my_item.json"
230
+ expect(File.exist?(data_bag_file)).to eq true
231
+ expect(JSON.parse(File.read(data_bag_file))).to eq(
232
+ 'id' => 'my_item',
233
+ 'content' => 'Bag content'
234
+ )
235
+ end
236
+ end
237
+ end
238
+
239
+ end
240
+
241
+ context 'with a platform having hpc_test cookbook' do
242
+
243
+ it 'packages the repository with before_run and after_run recipes wrapping the run list' do
244
+ with_serverless_chef_platforms('hpc_test') do |platform, repository|
245
+ with_packaging_mocked(repository, policy_file: 'policyfiles/test_policy.local.rb', env: 'local') do
246
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: true)
247
+ local_policy_file = "#{repository}/policyfiles/test_policy.local.lock.json"
248
+ expect(File.exist?(local_policy_file)).to eq true
249
+ expect(JSON.parse(File.read(local_policy_file))).to eq('run_list' => [
250
+ 'hpc_test::before_run',
251
+ 'recipe[test_cookbook]',
252
+ 'hpc_test::after_run'
253
+ ])
254
+ end
255
+ end
256
+ end
257
+
258
+ it 'packages the repository with before_run only recipe' do
259
+ with_serverless_chef_platforms('hpc_test') do |platform, repository|
260
+ File.unlink "#{repository}/cookbooks/hpc_test/recipes/after_run.rb"
261
+ with_packaging_mocked(repository, policy_file: 'policyfiles/test_policy.local.rb', env: 'local') do
262
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: true)
263
+ local_policy_file = "#{repository}/policyfiles/test_policy.local.lock.json"
264
+ expect(File.exist?(local_policy_file)).to eq true
265
+ expect(JSON.parse(File.read(local_policy_file))).to eq('run_list' => [
266
+ 'hpc_test::before_run',
267
+ 'recipe[test_cookbook]'
268
+ ])
269
+ end
270
+ end
271
+ end
272
+
273
+ it 'packages the repository with after_run only recipe' do
274
+ with_serverless_chef_platforms('hpc_test') do |platform, repository|
275
+ File.unlink "#{repository}/cookbooks/hpc_test/recipes/before_run.rb"
276
+ with_packaging_mocked(repository, policy_file: 'policyfiles/test_policy.local.rb', env: 'local') do
277
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: true)
278
+ local_policy_file = "#{repository}/policyfiles/test_policy.local.lock.json"
279
+ expect(File.exist?(local_policy_file)).to eq true
280
+ expect(JSON.parse(File.read(local_policy_file))).to eq('run_list' => [
281
+ 'recipe[test_cookbook]',
282
+ 'hpc_test::after_run'
283
+ ])
284
+ end
285
+ end
286
+ end
287
+
288
+ end
289
+
290
+ end
291
+
292
+ end