chef-dk 0.3.5 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +4 -4
- data/README.md +4 -4
- data/lib/chef-dk/builtin_commands.rb +4 -0
- data/lib/chef-dk/chef_runner.rb +7 -1
- data/lib/chef-dk/command/exec.rb +9 -0
- data/lib/chef-dk/command/export.rb +132 -0
- data/lib/chef-dk/command/generator_commands.rb +1 -1
- data/lib/chef-dk/command/generator_commands/app.rb +8 -0
- data/lib/chef-dk/command/generator_commands/base.rb +46 -4
- data/lib/chef-dk/command/generator_commands/cookbook.rb +8 -0
- data/lib/chef-dk/command/generator_commands/cookbook_code_file.rb +1 -0
- data/lib/chef-dk/command/push.rb +3 -6
- data/lib/chef-dk/command/shell_init.rb +28 -5
- data/lib/chef-dk/command/update.rb +106 -0
- data/lib/chef-dk/command/verify.rb +72 -0
- data/lib/chef-dk/component_test.rb +12 -1
- data/lib/chef-dk/configurable.rb +52 -0
- data/lib/chef-dk/cookbook_metadata.rb +10 -1
- data/lib/chef-dk/cookbook_profiler/git.rb +1 -1
- data/lib/chef-dk/exceptions.rb +17 -2
- data/lib/chef-dk/helpers.rb +2 -2
- data/lib/chef-dk/policyfile/community_cookbook_source.rb +1 -1
- data/lib/chef-dk/policyfile/dsl.rb +7 -0
- data/lib/chef-dk/policyfile/uploader.rb +25 -4
- data/lib/chef-dk/policyfile_compiler.rb +21 -1
- data/lib/chef-dk/policyfile_lock.rb +5 -0
- data/lib/chef-dk/policyfile_services/export_repo.rb +194 -0
- data/lib/chef-dk/policyfile_services/install.rb +8 -2
- data/lib/chef-dk/policyfile_services/push.rb +4 -1
- data/lib/chef-dk/service_exceptions.rb +6 -0
- data/lib/chef-dk/skeletons/code_generator/files/default/Berksfile +1 -1
- data/lib/chef-dk/skeletons/code_generator/files/default/repo/README.md +1 -1
- data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/README.md +1 -1
- data/lib/chef-dk/skeletons/code_generator/files/default/repo/environments/README.md +2 -2
- data/lib/chef-dk/skeletons/code_generator/files/default/serverspec_spec_helper.rb +3 -0
- data/lib/chef-dk/skeletons/code_generator/files/default/spec_helper.rb +1 -7
- data/lib/chef-dk/skeletons/code_generator/metadata.rb +1 -1
- data/lib/chef-dk/skeletons/code_generator/recipes/app.rb +31 -1
- data/lib/chef-dk/skeletons/code_generator/recipes/cookbook.rb +32 -2
- data/lib/chef-dk/skeletons/code_generator/recipes/recipe.rb +18 -0
- data/lib/chef-dk/skeletons/code_generator/templates/default/recipe.rb.erb +5 -0
- data/lib/chef-dk/skeletons/code_generator/templates/default/recipe_spec.rb.erb +23 -0
- data/lib/chef-dk/skeletons/code_generator/templates/default/serverspec_default_spec.rb.erb +12 -0
- data/lib/chef-dk/version.rb +1 -1
- data/lib/kitchen/provisioner/policyfile_zero.rb +149 -0
- data/spec/shared/a_file_generator.rb +1 -0
- data/spec/shared/command_with_ui_object.rb +11 -0
- data/spec/shared/custom_generator_cookbook.rb +117 -0
- data/spec/unit/chef_runner_spec.rb +26 -0
- data/spec/unit/command/exec_spec.rb +46 -5
- data/spec/unit/command/export_spec.rb +176 -0
- data/spec/unit/command/generator_commands/app_spec.rb +38 -0
- data/spec/unit/command/generator_commands/cookbook_spec.rb +37 -28
- data/spec/unit/command/generator_commands/recipe_spec.rb +4 -2
- data/spec/unit/command/install_spec.rb +3 -6
- data/spec/unit/command/push_spec.rb +3 -6
- data/spec/unit/command/shell_init_spec.rb +77 -49
- data/spec/unit/command/update_spec.rb +155 -0
- data/spec/unit/command/verify_spec.rb +22 -7
- data/spec/unit/cookbook_metadata_spec.rb +44 -8
- data/spec/unit/cookbook_profiler/git_spec.rb +12 -0
- data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/Berksfile +1 -1
- data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/Berksfile +1 -1
- data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/Berksfile +1 -1
- data/spec/unit/fixtures/cookbooks_api/small_universe.json +667 -667
- data/spec/unit/fixtures/cookbooks_api/universe.json +1 -1
- data/spec/unit/fixtures/cookbooks_api/update_fixtures.rb +1 -1
- data/spec/unit/fixtures/example_cookbook/Berksfile +1 -1
- data/spec/unit/fixtures/example_cookbook_metadata_json_only/.gitignore +17 -0
- data/spec/unit/fixtures/example_cookbook_metadata_json_only/.kitchen.yml +16 -0
- data/spec/unit/fixtures/example_cookbook_metadata_json_only/Berksfile +3 -0
- data/spec/unit/fixtures/example_cookbook_metadata_json_only/README.md +4 -0
- data/spec/unit/fixtures/example_cookbook_metadata_json_only/chefignore +96 -0
- data/spec/unit/fixtures/example_cookbook_metadata_json_only/metadata.json +5 -0
- data/spec/unit/fixtures/example_cookbook_metadata_json_only/recipes/default.rb +8 -0
- data/spec/unit/fixtures/example_cookbook_no_metadata/.gitignore +17 -0
- data/spec/unit/fixtures/example_cookbook_no_metadata/.kitchen.yml +16 -0
- data/spec/unit/fixtures/example_cookbook_no_metadata/Berksfile +3 -0
- data/spec/unit/fixtures/example_cookbook_no_metadata/README.md +4 -0
- data/spec/unit/fixtures/example_cookbook_no_metadata/chefignore +96 -0
- data/spec/unit/fixtures/example_cookbook_no_metadata/recipes/default.rb +8 -0
- data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/Berksfile +1 -1
- data/spec/unit/policyfile/community_cookbook_source_spec.rb +2 -2
- data/spec/unit/policyfile/cookbook_location_specification_spec.rb +3 -3
- data/spec/unit/policyfile/uploader_spec.rb +61 -25
- data/spec/unit/policyfile_demands_spec.rb +47 -0
- data/spec/unit/policyfile_evaluation_spec.rb +1 -1
- data/spec/unit/policyfile_lock_build_spec.rb +60 -3
- data/spec/unit/policyfile_services/export_repo_spec.rb +321 -0
- data/spec/unit/policyfile_services/install_spec.rb +20 -1
- data/spec/unit/policyfile_services/push_spec.rb +36 -9
- metadata +53 -38
- data/lib/chef-dk/skeletons/code_generator/files/default/converge_spec.rb +0 -9
- data/lib/chef-dk/skeletons/code_generator/templates/default/default_recipe.rb.erb +0 -5
|
@@ -148,6 +148,29 @@ describe ChefDK::PolicyfileCompiler, "when expressing the Policyfile graph deman
|
|
|
148
148
|
expect(policyfile.normalized_run_list).to eq(["recipe[local-cookbook::jazz_hands]"])
|
|
149
149
|
end
|
|
150
150
|
|
|
151
|
+
describe "in an alternate run list" do
|
|
152
|
+
|
|
153
|
+
it "normalizes a bare cookbook name" do
|
|
154
|
+
policyfile.named_run_list(:foo, "local-cookbook")
|
|
155
|
+
expect(policyfile.normalized_named_run_lists[:foo]).to eq(["recipe[local-cookbook::default]"])
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it "normalizes a bare cookbook::recipe item" do
|
|
159
|
+
policyfile.named_run_list(:foo, "local-cookbook::server")
|
|
160
|
+
expect(policyfile.normalized_named_run_lists[:foo]).to eq(["recipe[local-cookbook::server]"])
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "normalizes a recipe[] item with implicit default" do
|
|
164
|
+
policyfile.named_run_list(:foo, "recipe[local-cookbook]")
|
|
165
|
+
expect(policyfile.normalized_named_run_lists[:foo]).to eq(["recipe[local-cookbook::default]"])
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it "does not modify a fully qualified recipe" do
|
|
169
|
+
policyfile.named_run_list(:foo, "recipe[local-cookbook::jazz_hands]")
|
|
170
|
+
expect(policyfile.normalized_named_run_lists[:foo]).to eq(["recipe[local-cookbook::jazz_hands]"])
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
end
|
|
151
174
|
end
|
|
152
175
|
|
|
153
176
|
before do
|
|
@@ -628,6 +651,30 @@ describe ChefDK::PolicyfileCompiler, "when expressing the Policyfile graph deman
|
|
|
628
651
|
end
|
|
629
652
|
end
|
|
630
653
|
|
|
654
|
+
context "Given a run_list and named run_lists" do
|
|
655
|
+
|
|
656
|
+
before do
|
|
657
|
+
policyfile.dsl.named_run_list(:foo, 'local-cookbook', 'nginx')
|
|
658
|
+
policyfile.dsl.named_run_list(:bar, 'remote-cb', 'nginx')
|
|
659
|
+
policyfile.dsl.run_list('private-cookbook', 'nginx')
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
it "demands a solution that satisfies all of the run lists, with no duplicates" do
|
|
663
|
+
expect(policyfile.graph_demands).to include(["private-cookbook", ">= 0.0.0"])
|
|
664
|
+
expect(policyfile.graph_demands).to include(["nginx", ">= 0.0.0"])
|
|
665
|
+
expect(policyfile.graph_demands).to include(["remote-cb", ">= 0.0.0"])
|
|
666
|
+
expect(policyfile.graph_demands).to include(["local-cookbook", ">= 0.0.0"])
|
|
667
|
+
|
|
668
|
+
# ensure there are no duplicates:
|
|
669
|
+
expected_demands = [["private-cookbook", ">= 0.0.0"],
|
|
670
|
+
["nginx", ">= 0.0.0"],
|
|
671
|
+
["local-cookbook", ">= 0.0.0"],
|
|
672
|
+
["remote-cb", ">= 0.0.0"]]
|
|
673
|
+
expect(policyfile.graph_demands).to eq(expected_demands)
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
end
|
|
677
|
+
|
|
631
678
|
context "Given a run_list with roles" do
|
|
632
679
|
it "expands the roles from the given role source" do
|
|
633
680
|
skip
|
|
@@ -185,7 +185,7 @@ E
|
|
|
185
185
|
|
|
186
186
|
it "has a default source" do
|
|
187
187
|
expect(policyfile.errors).to eq([])
|
|
188
|
-
expected = ChefDK::Policyfile::CommunityCookbookSource.new("https://supermarket.
|
|
188
|
+
expected = ChefDK::Policyfile::CommunityCookbookSource.new("https://supermarket.chef.io")
|
|
189
189
|
expect(policyfile.default_source).to eq(expected)
|
|
190
190
|
end
|
|
191
191
|
|
|
@@ -341,7 +341,7 @@ describe ChefDK::PolicyfileLock, "building a lockfile" do
|
|
|
341
341
|
|
|
342
342
|
# Optional attribute that humans can use to understand where a cookbook
|
|
343
343
|
# came from.
|
|
344
|
-
cb.origin = "https://community.
|
|
344
|
+
cb.origin = "https://community.chef.io/api/cookbooks/foo/1.0.0"
|
|
345
345
|
end
|
|
346
346
|
|
|
347
347
|
p.local_cookbook("bar") do |cb|
|
|
@@ -375,7 +375,7 @@ describe ChefDK::PolicyfileLock, "building a lockfile" do
|
|
|
375
375
|
"version" => "1.0.0",
|
|
376
376
|
"identifier" => cookbook_foo_cksum,
|
|
377
377
|
"dotted_decimal_identifier" => cookbook_foo_cksum_dotted,
|
|
378
|
-
"origin" => "https://community.
|
|
378
|
+
"origin" => "https://community.chef.io/api/cookbooks/foo/1.0.0",
|
|
379
379
|
"cache_key" => "foo-1.0.0",
|
|
380
380
|
"source_options" => nil
|
|
381
381
|
},
|
|
@@ -492,6 +492,56 @@ describe ChefDK::PolicyfileLock, "building a lockfile" do
|
|
|
492
492
|
end
|
|
493
493
|
|
|
494
494
|
end
|
|
495
|
+
|
|
496
|
+
context "with named run_lists specified" do
|
|
497
|
+
|
|
498
|
+
let(:policyfile_lock) do
|
|
499
|
+
ChefDK::PolicyfileLock.build(storage_config) do |p|
|
|
500
|
+
|
|
501
|
+
p.name = "minimal_policyfile"
|
|
502
|
+
|
|
503
|
+
p.run_list = [ "recipe[foo]" ]
|
|
504
|
+
|
|
505
|
+
p.named_run_lists = { "rl2" => [ "recipe[foo::bar]" ] }
|
|
506
|
+
|
|
507
|
+
p.cached_cookbook("foo") do |cb|
|
|
508
|
+
cb.cache_key = "foo-1.0.0"
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
let(:compiled_policyfile) do
|
|
515
|
+
{
|
|
516
|
+
|
|
517
|
+
"name" => "minimal_policyfile",
|
|
518
|
+
|
|
519
|
+
"run_list" => ["recipe[foo]"],
|
|
520
|
+
|
|
521
|
+
"named_run_lists" => { "rl2" => [ "recipe[foo::bar]" ] },
|
|
522
|
+
|
|
523
|
+
"cookbook_locks" => {
|
|
524
|
+
|
|
525
|
+
"foo" => {
|
|
526
|
+
"version" => "1.0.0",
|
|
527
|
+
"identifier" => cookbook_foo_cksum,
|
|
528
|
+
"dotted_decimal_identifier" => cookbook_foo_cksum_dotted,
|
|
529
|
+
"cache_key" => "foo-1.0.0",
|
|
530
|
+
"origin" => nil,
|
|
531
|
+
"source_options" => nil
|
|
532
|
+
},
|
|
533
|
+
},
|
|
534
|
+
|
|
535
|
+
"solution_dependencies" => { "Policyfile" => [], "dependencies" => {} }
|
|
536
|
+
}
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
it "includes the named run lists in the compiled policyfile" do
|
|
540
|
+
expect(policyfile_lock.to_lock).to eq(compiled_policyfile)
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
end
|
|
544
|
+
|
|
495
545
|
describe "building a policyfile lock from a policyfile compiler" do
|
|
496
546
|
|
|
497
547
|
include_context "setup git cookbooks"
|
|
@@ -500,7 +550,7 @@ describe ChefDK::PolicyfileLock, "building a lockfile" do
|
|
|
500
550
|
tempdir
|
|
501
551
|
end
|
|
502
552
|
|
|
503
|
-
let(:cached_cookbook_uri) { "https://supermarket.
|
|
553
|
+
let(:cached_cookbook_uri) { "https://supermarket.chef.io/api/v1/cookbooks/foo/versions/1.0.0/download" }
|
|
504
554
|
|
|
505
555
|
let(:cached_location_spec) do
|
|
506
556
|
double( "ChefDK::Policyfile::CookbookLocationSpecification",
|
|
@@ -530,6 +580,7 @@ describe ChefDK::PolicyfileLock, "building a lockfile" do
|
|
|
530
580
|
double( "ChefDK::PolicyfileCompiler",
|
|
531
581
|
name: "my-policyfile",
|
|
532
582
|
normalized_run_list: %w[recipe[foo::default] recipe[bar::default]],
|
|
583
|
+
normalized_named_run_lists: { "rl2" => %w[recipe[bar::default]] },
|
|
533
584
|
all_cookbook_location_specs: {"foo" => cached_location_spec, "bar" => local_location_spec},
|
|
534
585
|
solution_dependencies: policyfile_solution_dependencies )
|
|
535
586
|
end
|
|
@@ -545,6 +596,8 @@ describe ChefDK::PolicyfileLock, "building a lockfile" do
|
|
|
545
596
|
|
|
546
597
|
"run_list" => ["recipe[foo::default]", "recipe[bar::default]"],
|
|
547
598
|
|
|
599
|
+
"named_run_lists" => { "rl2" => ["recipe[bar::default]"] },
|
|
600
|
+
|
|
548
601
|
"cookbook_locks" => {
|
|
549
602
|
|
|
550
603
|
"foo" => {
|
|
@@ -595,6 +648,10 @@ describe ChefDK::PolicyfileLock, "building a lockfile" do
|
|
|
595
648
|
expect(cb_lock.source).to eq(local_location_spec.relative_path)
|
|
596
649
|
end
|
|
597
650
|
|
|
651
|
+
it "sets named run lists on the policyfile lock" do
|
|
652
|
+
expect(policyfile_lock.named_run_lists).to eq("rl2" => %w[recipe[bar::default]])
|
|
653
|
+
end
|
|
654
|
+
|
|
598
655
|
it "generates a lockfile data structure" do
|
|
599
656
|
expect(policyfile_lock.to_lock).to eq(compiled_policyfile)
|
|
600
657
|
end
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright:: Copyright (c) 2014 Chef Software Inc.
|
|
3
|
+
# License:: Apache License, Version 2.0
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require 'spec_helper'
|
|
19
|
+
require 'chef-dk/policyfile_services/export_repo'
|
|
20
|
+
|
|
21
|
+
describe ChefDK::PolicyfileServices::ExportRepo do
|
|
22
|
+
|
|
23
|
+
let(:working_dir) do
|
|
24
|
+
path = File.join(tempdir, "policyfile_services_test_working_dir")
|
|
25
|
+
Dir.mkdir(path)
|
|
26
|
+
path
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
let(:export_dir) { File.join(tempdir, "export_repo_export_dir") }
|
|
30
|
+
|
|
31
|
+
let(:policyfile_rb_explicit_name) { nil }
|
|
32
|
+
|
|
33
|
+
let(:policyfile_rb_name) { policyfile_rb_explicit_name || "Policyfile.rb" }
|
|
34
|
+
|
|
35
|
+
let(:expanded_policyfile_path) { File.join(working_dir, policyfile_rb_name) }
|
|
36
|
+
|
|
37
|
+
let(:policyfile_lock_name) { "Policyfile.lock.json" }
|
|
38
|
+
|
|
39
|
+
let(:policyfile_lock_path) { File.join(working_dir, policyfile_lock_name) }
|
|
40
|
+
|
|
41
|
+
let(:force_export) { false }
|
|
42
|
+
|
|
43
|
+
subject(:export_service) do
|
|
44
|
+
described_class.new(policyfile: policyfile_rb_explicit_name,
|
|
45
|
+
root_dir: working_dir,
|
|
46
|
+
export_dir: export_dir,
|
|
47
|
+
force: force_export)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "uses Policyfile.rb as the default Policyfile name" do
|
|
51
|
+
expect(export_service.policyfile_filename).to eq(expanded_policyfile_path)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context "when given an explicit Policyfile name" do
|
|
55
|
+
|
|
56
|
+
let(:policyfile_rb_explicit_name) { "MyPolicy.rb" }
|
|
57
|
+
|
|
58
|
+
it "uses the given Policyfile name" do
|
|
59
|
+
expect(export_service.policyfile_filename).to eq(expanded_policyfile_path)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "has a destination directory for the export" do
|
|
65
|
+
expect(export_service.export_dir).to eq(export_dir)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
context "when the policyfile lock is missing" do
|
|
69
|
+
|
|
70
|
+
it "raises an error that suggests you run `chef install'" do
|
|
71
|
+
expect { export_service.run }.to raise_error(ChefDK::LockfileNotFound)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
context "when a lockfile is present" do
|
|
77
|
+
|
|
78
|
+
before do
|
|
79
|
+
File.open(policyfile_lock_path, "w+") { |f| f.print(lockfile_content) }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
context "and the lockfile has invalid JSON" do
|
|
83
|
+
|
|
84
|
+
let(:lockfile_content) { ":::" }
|
|
85
|
+
|
|
86
|
+
it "errors out" do
|
|
87
|
+
expect { export_service.run }.to raise_error(ChefDK::PolicyfileExportRepoError, /Error reading lockfile/)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
context "and the lockfile is semantically invalid" do
|
|
93
|
+
|
|
94
|
+
let(:lockfile_content) { '{ }' }
|
|
95
|
+
|
|
96
|
+
it "errors out" do
|
|
97
|
+
expect { export_service.run }.to raise_error(ChefDK::PolicyfileExportRepoError, /Invalid lockfile data/)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
context "and the lockfile is valid" do
|
|
103
|
+
|
|
104
|
+
let(:local_cookbook_path) { File.join(fixtures_path, "local_path_cookbooks/local-cookbook") }
|
|
105
|
+
|
|
106
|
+
let(:lockfile_content) do
|
|
107
|
+
<<-E
|
|
108
|
+
{
|
|
109
|
+
"name": "install-example",
|
|
110
|
+
"run_list": [
|
|
111
|
+
"recipe[local-cookbook::default]"
|
|
112
|
+
],
|
|
113
|
+
"cookbook_locks": {
|
|
114
|
+
"local-cookbook": {
|
|
115
|
+
"version": "2.3.4",
|
|
116
|
+
"identifier": "fab501cfaf747901bd82c1bc706beae7dc3a350c",
|
|
117
|
+
"dotted_decimal_identifier": "70567763561641081.489844270461035.258281553147148",
|
|
118
|
+
"source": "#{local_cookbook_path}",
|
|
119
|
+
"cache_key": null,
|
|
120
|
+
"scm_info": null,
|
|
121
|
+
"source_options": {
|
|
122
|
+
"path": "#{local_cookbook_path}"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"solution_dependencies": {
|
|
127
|
+
"Policyfile": [
|
|
128
|
+
[
|
|
129
|
+
"local-cookbook",
|
|
130
|
+
">= 0.0.0"
|
|
131
|
+
]
|
|
132
|
+
],
|
|
133
|
+
"dependencies": {
|
|
134
|
+
"local-cookbook (2.3.4)": [
|
|
135
|
+
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
E
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "reads the lockfile data" do
|
|
144
|
+
lock = export_service.policyfile_lock
|
|
145
|
+
expect(lock).to be_an_instance_of(ChefDK::PolicyfileLock)
|
|
146
|
+
expect(lock.name).to eq("install-example")
|
|
147
|
+
expect(lock.cookbook_locks.size).to eq(1)
|
|
148
|
+
expect(lock.cookbook_locks).to have_key("local-cookbook")
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "delegates #policy_name to the lockfile" do
|
|
152
|
+
expect(export_service.policy_name).to eq("install-example")
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
describe "writing updates to the policyfile lock" do
|
|
156
|
+
|
|
157
|
+
let(:updated_lockfile_io) { StringIO.new }
|
|
158
|
+
|
|
159
|
+
it "validates the lockfile and writes updates to disk" do
|
|
160
|
+
allow(File).to receive(:open).and_call_original
|
|
161
|
+
expect(File).to receive(:open).with(policyfile_lock_path, "wb+").and_yield(updated_lockfile_io)
|
|
162
|
+
|
|
163
|
+
export_service.run
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
context "copying the cookbooks to the export dir" do
|
|
169
|
+
|
|
170
|
+
context "when the export dir is empty" do
|
|
171
|
+
before do
|
|
172
|
+
allow(export_service.policyfile_lock).to receive(:validate_cookbooks!).and_return(true)
|
|
173
|
+
export_service.run
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
let(:cookbook_files) do
|
|
177
|
+
base_pathname = Pathname.new(local_cookbook_path)
|
|
178
|
+
Dir.glob("#{local_cookbook_path}/**/*").map do |full_path|
|
|
179
|
+
Pathname.new(full_path).relative_path_from(base_pathname)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
let(:expected_files_relative) do
|
|
184
|
+
metadata_rb = Pathname.new("metadata.rb")
|
|
185
|
+
expected = cookbook_files.delete_if { |p| p == metadata_rb }
|
|
186
|
+
expected << Pathname.new("metadata.json")
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
let(:cookbook_with_version) { "local-cookbook-70567763561641081.489844270461035.258281553147148" }
|
|
190
|
+
|
|
191
|
+
let(:exported_cookbook_root) { Pathname.new(File.join(export_dir, "cookbooks", cookbook_with_version)) }
|
|
192
|
+
|
|
193
|
+
let(:expected_files) do
|
|
194
|
+
expected_files_relative.map do |file_rel_path|
|
|
195
|
+
exported_cookbook_root + file_rel_path
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it "copies cookbooks to the target dir in versioned_cookbooks format" do
|
|
200
|
+
expected_files.each do |expected_file|
|
|
201
|
+
expect(expected_file).to exist
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# This behavior does two things:
|
|
206
|
+
# * ensures that Chef Zero uses our hacked version number
|
|
207
|
+
# * works around external dependencies (e.g., using `git` in backticks)
|
|
208
|
+
# in metadata.rb issue
|
|
209
|
+
it "writes metadata.json in the exported cookbook, removing metadata.rb" do
|
|
210
|
+
metadata_json_path = File.join(exported_cookbook_root, "metadata.json")
|
|
211
|
+
metadata_json = FFI_Yajl::Parser.parse(IO.read(metadata_json_path))
|
|
212
|
+
expect(metadata_json["version"]).to eq("70567763561641081.489844270461035.258281553147148")
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it "copies the policyfile lock in data item format to data_bags/policyfiles" do
|
|
216
|
+
data_bag_item_path = File.join(export_dir, "data_bags", "policyfiles", "install-example-local.json")
|
|
217
|
+
data_item_json = FFI_Yajl::Parser.parse(IO.read(data_bag_item_path))
|
|
218
|
+
expect(data_item_json["id"]).to eq("install-example-local")
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
context "When an error occurs creating the export" do
|
|
224
|
+
|
|
225
|
+
before do
|
|
226
|
+
allow(export_service.policyfile_lock).to receive(:validate_cookbooks!).and_return(true)
|
|
227
|
+
expect(export_service).to receive(:create_repo_structure).
|
|
228
|
+
and_raise(Errno::EACCES.new("Permission denied @ rb_sysopen - /etc/foobarbaz.txt"))
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
it "wraps the error in a custom error class" do
|
|
232
|
+
message = "Failed to export policy (in #{expanded_policyfile_path}) to #{export_dir}"
|
|
233
|
+
expect { export_service.run }.to raise_error(ChefDK::PolicyfileExportRepoError, message)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
context "When the export dir has non-conflicting content" do
|
|
239
|
+
|
|
240
|
+
let(:file_in_export_dir) { File.join(export_dir, "some_random_cruft") }
|
|
241
|
+
|
|
242
|
+
let(:extra_data_bag_dir) { File.join(export_dir, "data_bags", "extraneous") }
|
|
243
|
+
|
|
244
|
+
let(:extra_data_bag_item) { File.join(extra_data_bag_dir, "an_item.json") }
|
|
245
|
+
|
|
246
|
+
before do
|
|
247
|
+
FileUtils.mkdir_p(export_dir)
|
|
248
|
+
File.open(file_in_export_dir, "wb+") { |f| f.print "some random cruft" }
|
|
249
|
+
FileUtils.mkdir_p(extra_data_bag_dir)
|
|
250
|
+
File.open(extra_data_bag_item, "wb+") { |f| f.print "some random cruft" }
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
it "ignores the non-conflicting content and exports" do
|
|
254
|
+
export_service.run
|
|
255
|
+
|
|
256
|
+
expect(File).to exist(file_in_export_dir)
|
|
257
|
+
expect(File).to exist(extra_data_bag_item)
|
|
258
|
+
|
|
259
|
+
expect(File).to be_directory(File.join(export_dir, "cookbooks"))
|
|
260
|
+
expect(File).to be_directory(File.join(export_dir, "data_bags"))
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
context "When the export dir has conflicting content" do
|
|
265
|
+
|
|
266
|
+
let(:non_conflicting_file_in_export_dir) { File.join(export_dir, "some_random_cruft") }
|
|
267
|
+
|
|
268
|
+
let(:cookbooks_dir) { File.join(export_dir, "cookbooks") }
|
|
269
|
+
|
|
270
|
+
let(:file_in_cookbooks_dir) { File.join(cookbooks_dir, "some_random_cruft") }
|
|
271
|
+
|
|
272
|
+
let(:policyfiles_data_bag_dir) { File.join(export_dir, "data_bags", "policyfiles") }
|
|
273
|
+
|
|
274
|
+
let(:extra_policyfile_data_item) { File.join(policyfiles_data_bag_dir, "leftover-policy.json") }
|
|
275
|
+
|
|
276
|
+
before do
|
|
277
|
+
FileUtils.mkdir_p(export_dir)
|
|
278
|
+
FileUtils.mkdir_p(cookbooks_dir)
|
|
279
|
+
FileUtils.mkdir_p(policyfiles_data_bag_dir)
|
|
280
|
+
File.open(non_conflicting_file_in_export_dir, "wb+") { |f| f.print "some random cruft" }
|
|
281
|
+
File.open(file_in_cookbooks_dir, "wb+") { |f| f.print "some random cruft" }
|
|
282
|
+
File.open(extra_policyfile_data_item, "wb+") { |f| f.print "some random cruft" }
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
it "raises a PolicyfileExportRepoError" do
|
|
286
|
+
message = "Export dir (#{export_dir}) not clean. Refusing to export. (Conflicting files: #{file_in_cookbooks_dir}, #{extra_policyfile_data_item})"
|
|
287
|
+
expect { export_service.run }.to raise_error(ChefDK::ExportDirNotEmpty, message)
|
|
288
|
+
expect(File).to exist(non_conflicting_file_in_export_dir)
|
|
289
|
+
expect(File).to exist(file_in_cookbooks_dir)
|
|
290
|
+
expect(File).to exist(extra_policyfile_data_item)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
context "and the force option is set" do
|
|
294
|
+
|
|
295
|
+
let(:force_export) { true }
|
|
296
|
+
|
|
297
|
+
it "clears the export dir and exports" do
|
|
298
|
+
export_service.run
|
|
299
|
+
|
|
300
|
+
expect(File).to_not exist(file_in_cookbooks_dir)
|
|
301
|
+
expect(File).to_not exist(extra_policyfile_data_item)
|
|
302
|
+
|
|
303
|
+
expect(File).to exist(non_conflicting_file_in_export_dir)
|
|
304
|
+
|
|
305
|
+
expect(File).to be_directory(File.join(export_dir, "cookbooks"))
|
|
306
|
+
expect(File).to be_directory(File.join(export_dir, "data_bags"))
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
end
|
|
321
|
+
|