hybrid_platforms_conductor 32.13.4 → 32.16.2

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 (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/provisioner/podman.rb +1 -1
  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 +293 -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,293 @@
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
+ ['whoami', proc { [0, 'test_user', ''] }, { optional: true }],
48
+ [
49
+ /^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)}/" : ''}$/,
50
+ proc do
51
+ FileUtils.mkdir_p "#{repository}/dist/#{env}/#{policy}"
52
+ FileUtils.cp_r("#{repository}/data_bags", "#{repository}/dist/#{env}/#{policy}/") if data_bags
53
+ [0, 'Chef export done', '']
54
+ end
55
+ ]
56
+ ]
57
+ else
58
+ []
59
+ end
60
+ ) do
61
+ yield
62
+ end
63
+ end
64
+
65
+ context 'with an empty platform' do
66
+
67
+ it 'packages the repository doing nothing' do
68
+ with_serverless_chef_platforms('empty') do |platform, repository|
69
+ with_cmd_runner_mocked([]) do
70
+ platform.package(services: {}, secrets: {}, local_environment: false)
71
+ end
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ context 'with a platform having 1 node' do
78
+
79
+ it 'packages the repository for a given node and service' do
80
+ with_serverless_chef_platforms('1_node') do |platform, repository|
81
+ with_packaging_mocked(repository) do
82
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
83
+ end
84
+ end
85
+ end
86
+
87
+ it 'packages the repository without resolving dependencies when the lock file already exists' do
88
+ with_serverless_chef_platforms('1_node') do |platform, repository|
89
+ File.write("#{repository}/policyfiles/test_policy.lock.json", '{}')
90
+ with_packaging_mocked(repository, install: false) do
91
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
92
+ end
93
+ end
94
+ end
95
+
96
+ it 'packages the repository with secrets' do
97
+ with_serverless_chef_platforms('1_node') do |platform, repository|
98
+ with_packaging_mocked(repository) do
99
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: { secret: 'value' }, local_environment: false)
100
+ secret_file = "#{repository}/dist/prod/test_policy/data_bags/hpc_secrets/hpc_secrets.json"
101
+ expect(File.exist?(secret_file)).to eq true
102
+ expect(JSON.parse(File.read(secret_file))).to eq(
103
+ 'id' => 'hpc_secrets',
104
+ 'secret' => 'value'
105
+ )
106
+ end
107
+ end
108
+ end
109
+
110
+ it 'packages the repository for a given node and service in local mode' do
111
+ with_serverless_chef_platforms('1_node') do |platform, repository|
112
+ with_packaging_mocked(repository, policy_file: 'policyfiles/test_policy.local.rb', env: 'local') do
113
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: true)
114
+ local_policy_file = "#{repository}/policyfiles/test_policy.local.lock.json"
115
+ expect(File.exist?(local_policy_file)).to eq true
116
+ expect(JSON.parse(File.read(local_policy_file))).to eq('run_list' => ['recipe[test_cookbook]'])
117
+ end
118
+ end
119
+ end
120
+
121
+ it 'packages the repository without resolving dependencies when the lock file already exists' do
122
+ with_serverless_chef_platforms('1_node') do |platform, repository|
123
+ File.write("#{repository}/policyfiles/test_policy.lock.json", '{}')
124
+ with_packaging_mocked(repository, install: false) do
125
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
126
+ end
127
+ end
128
+ end
129
+
130
+ it 'does not package the repository twice for the same config' do
131
+ with_serverless_chef_platforms('1_node', as_git: true) do |platform, repository|
132
+ with_packaging_mocked(repository) do
133
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
134
+ end
135
+ with_cmd_runner_mocked([]) do
136
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
137
+ end
138
+ end
139
+ end
140
+
141
+ it 'packages the repository twice when the platform is not taken from git' do
142
+ with_serverless_chef_platforms('1_node') do |platform, repository|
143
+ with_packaging_mocked(repository) do
144
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
145
+ end
146
+ # Wait 2 seconds so that we are sure later Time.now will return different timestamps
147
+ sleep 2
148
+ with_packaging_mocked(repository, install: false) do
149
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
150
+ end
151
+ end
152
+ end
153
+
154
+ it 'packages the repository twice when the platform needs different secrets' do
155
+ with_serverless_chef_platforms('1_node', as_git: true) do |platform, repository|
156
+ with_packaging_mocked(repository) do
157
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: { secret: 'value1' }, local_environment: false)
158
+ end
159
+ with_packaging_mocked(repository, install: false) do
160
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: { secret: 'value2' }, local_environment: false)
161
+ end
162
+ end
163
+ end
164
+
165
+ it 'packages the repository twice when the platform has new local files' do
166
+ with_serverless_chef_platforms('1_node', as_git: true) do |platform, repository|
167
+ with_packaging_mocked(repository) do
168
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
169
+ end
170
+ # Make sure we clean the cache (this mocks another Platform Handler instance running)
171
+ platform.remove_instance_variable :@info
172
+ with_packaging_mocked(repository, install: false) do
173
+ File.write("#{repository}/new_file", 'New file')
174
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
175
+ end
176
+ end
177
+ end
178
+
179
+ it 'packages the repository twice when the platform has modified local files' do
180
+ with_serverless_chef_platforms('1_node', as_git: true) do |platform, repository|
181
+ with_packaging_mocked(repository) do
182
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
183
+ end
184
+ # Wait 2 seconds so that we are sure the modified file will return a different timestamp
185
+ sleep 2
186
+ with_packaging_mocked(repository, install: false) do
187
+ File.write("#{repository}/chef_versions.yml", File.read("#{repository}/chef_versions.yml") + "\n\n")
188
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
189
+ end
190
+ end
191
+ end
192
+
193
+ end
194
+
195
+ context 'with a platform having several nodes' do
196
+
197
+ it 'packages 1 service independently from another' do
198
+ with_serverless_chef_platforms('several_nodes') do |platform, repository|
199
+ with_packaging_mocked(repository, policy: 'test_policy_1') do
200
+ platform.package(services: { 'node1' => %w[test_policy_1] }, secrets: {}, local_environment: false)
201
+ end
202
+ with_packaging_mocked(repository, policy: 'test_policy_2') do
203
+ platform.package(services: { 'node2' => %w[test_policy_2] }, secrets: {}, local_environment: false)
204
+ end
205
+ with_cmd_runner_mocked([]) do
206
+ platform.package(services: { 'node1' => %w[test_policy_1] }, secrets: {}, local_environment: false)
207
+ end
208
+ end
209
+ end
210
+
211
+ it 'packages 1 service independently of the node on which it is to be deployed' do
212
+ with_serverless_chef_platforms('several_nodes') do |platform, repository|
213
+ with_packaging_mocked(repository, policy: 'test_policy_1') do
214
+ platform.package(services: { 'node1' => %w[test_policy_1] }, secrets: {}, local_environment: false)
215
+ end
216
+ with_cmd_runner_mocked([]) do
217
+ platform.package(services: { 'node2' => %w[test_policy_1] }, secrets: {}, local_environment: false)
218
+ end
219
+ end
220
+ end
221
+
222
+ end
223
+
224
+ context 'with a platform having data bags' do
225
+
226
+ it 'packages data bags' do
227
+ with_serverless_chef_platforms('data_bags') do |platform, repository|
228
+ with_packaging_mocked(repository, data_bags: true) do
229
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: false)
230
+ data_bag_file = "#{repository}/dist/prod/test_policy/data_bags/my_bag/my_item.json"
231
+ expect(File.exist?(data_bag_file)).to eq true
232
+ expect(JSON.parse(File.read(data_bag_file))).to eq(
233
+ 'id' => 'my_item',
234
+ 'content' => 'Bag content'
235
+ )
236
+ end
237
+ end
238
+ end
239
+
240
+ end
241
+
242
+ context 'with a platform having hpc_test cookbook' do
243
+
244
+ it 'packages the repository with before_run and after_run recipes wrapping the run list' do
245
+ with_serverless_chef_platforms('hpc_test') do |platform, repository|
246
+ with_packaging_mocked(repository, policy_file: 'policyfiles/test_policy.local.rb', env: 'local') do
247
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: true)
248
+ local_policy_file = "#{repository}/policyfiles/test_policy.local.lock.json"
249
+ expect(File.exist?(local_policy_file)).to eq true
250
+ expect(JSON.parse(File.read(local_policy_file))).to eq('run_list' => [
251
+ 'hpc_test::before_run',
252
+ 'recipe[test_cookbook]',
253
+ 'hpc_test::after_run'
254
+ ])
255
+ end
256
+ end
257
+ end
258
+
259
+ it 'packages the repository with before_run only recipe' do
260
+ with_serverless_chef_platforms('hpc_test') do |platform, repository|
261
+ File.unlink "#{repository}/cookbooks/hpc_test/recipes/after_run.rb"
262
+ with_packaging_mocked(repository, policy_file: 'policyfiles/test_policy.local.rb', env: 'local') do
263
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: true)
264
+ local_policy_file = "#{repository}/policyfiles/test_policy.local.lock.json"
265
+ expect(File.exist?(local_policy_file)).to eq true
266
+ expect(JSON.parse(File.read(local_policy_file))).to eq('run_list' => [
267
+ 'hpc_test::before_run',
268
+ 'recipe[test_cookbook]'
269
+ ])
270
+ end
271
+ end
272
+ end
273
+
274
+ it 'packages the repository with after_run only recipe' do
275
+ with_serverless_chef_platforms('hpc_test') do |platform, repository|
276
+ File.unlink "#{repository}/cookbooks/hpc_test/recipes/before_run.rb"
277
+ with_packaging_mocked(repository, policy_file: 'policyfiles/test_policy.local.rb', env: 'local') do
278
+ platform.package(services: { 'node' => %w[test_policy] }, secrets: {}, local_environment: true)
279
+ local_policy_file = "#{repository}/policyfiles/test_policy.local.lock.json"
280
+ expect(File.exist?(local_policy_file)).to eq true
281
+ expect(JSON.parse(File.read(local_policy_file))).to eq('run_list' => [
282
+ 'recipe[test_cookbook]',
283
+ 'hpc_test::after_run'
284
+ ])
285
+ end
286
+ end
287
+ end
288
+
289
+ end
290
+
291
+ end
292
+
293
+ end