chef-dk 0.4.0 → 0.5.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +1 -3
  3. data/README.md +20 -15
  4. data/lib/chef-dk/cli.rb +18 -1
  5. data/lib/chef-dk/command/verify.rb +1 -1
  6. data/lib/chef-dk/policyfile/cookbook_location_specification.rb +5 -1
  7. data/lib/chef-dk/policyfile/read_cookbook_for_compat_mode_upload.rb +44 -0
  8. data/lib/chef-dk/policyfile/uploader.rb +58 -6
  9. data/lib/chef-dk/policyfile_lock.rb +42 -0
  10. data/lib/chef-dk/skeletons/code_generator/files/default/{repo/cookbooks → cookbook_readmes}/README-policy.md +0 -0
  11. data/lib/chef-dk/skeletons/code_generator/files/default/{repo/cookbooks → cookbook_readmes}/README.md +1 -1
  12. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/attributes/default.rb +7 -0
  13. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/metadata.rb +3 -0
  14. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/recipes/default.rb +8 -0
  15. data/lib/chef-dk/skeletons/code_generator/files/default/repo/data_bags/README.md +13 -18
  16. data/lib/chef-dk/skeletons/code_generator/files/default/repo/data_bags/example/example_item.json +4 -0
  17. data/lib/chef-dk/skeletons/code_generator/files/default/repo/environments/README.md +7 -3
  18. data/lib/chef-dk/skeletons/code_generator/files/default/repo/environments/example.json +13 -0
  19. data/lib/chef-dk/skeletons/code_generator/files/default/repo/roles/README.md +6 -13
  20. data/lib/chef-dk/skeletons/code_generator/files/default/repo/roles/example.json +13 -0
  21. data/lib/chef-dk/skeletons/code_generator/recipes/app.rb +5 -1
  22. data/lib/chef-dk/skeletons/code_generator/recipes/cookbook.rb +5 -1
  23. data/lib/chef-dk/skeletons/code_generator/recipes/repo.rb +5 -20
  24. data/lib/chef-dk/version.rb +1 -1
  25. data/lib/kitchen/provisioner/policyfile_zero.rb +21 -9
  26. data/spec/spec_helper.rb +8 -0
  27. data/spec/unit/cli_spec.rb +49 -3
  28. data/spec/unit/command/generator_commands/app_spec.rb +1 -1
  29. data/spec/unit/command/generator_commands/cookbook_spec.rb +1 -1
  30. data/spec/unit/command/generator_commands/repo_spec.rb +46 -50
  31. data/spec/unit/policyfile/uploader_spec.rb +225 -171
  32. data/spec/unit/policyfile_evaluation_spec.rb +16 -0
  33. data/spec/unit/policyfile_lock_build_spec.rb +156 -0
  34. metadata +18 -9
  35. data/lib/chef-dk/skeletons/code_generator/files/default/repo/Rakefile +0 -65
  36. data/lib/chef-dk/skeletons/code_generator/files/default/repo/certificates/README.md +0 -19
  37. data/lib/chef-dk/skeletons/code_generator/templates/default/repo/config/rake.rb.erb +0 -38
@@ -0,0 +1,3 @@
1
+ name 'example'
2
+ description 'An example cookbook'
3
+ version '1.0.0'
@@ -0,0 +1,8 @@
1
+ # This is a Chef recipe file. It can be used to specify resources which will
2
+ # apply configuration to a server.
3
+
4
+ log "Welcome to Chef, #{node["example"]["name"]}!" do
5
+ level :info
6
+ end
7
+
8
+ # For more information, see the documentation: http://docs.getchef.com/essentials_cookbook_recipes.html
@@ -3,28 +3,19 @@ Data Bags
3
3
 
4
4
  This directory contains directories of the various data bags you create for your infrastructure. Each subdirectory corresponds to a data bag on the Chef Server, and contains JSON files of the items that go in the bag.
5
5
 
6
- First, create a directory for the data bag.
6
+ For example, in this directory you'll find an example data bag directory called `example`, which contains an item definition called `example_item.json`
7
+
8
+ Before uploading this item to the server, we must first create the data bag on the Chef Server.
7
9
 
8
- mkdir data_bags/BAG
10
+ knife data bag create example
9
11
 
10
- Then create the JSON files for items that will go into that bag.
12
+ Then we can upload the items in the data bag's directory to the Chef Server.
11
13
 
12
- $EDITOR data_bags/BAG/ITEM.json
13
-
14
- The JSON for the ITEM must contain a key named "id" with a value equal to "ITEM". For example,
15
-
16
- {
17
- "id": "foo"
18
- }
19
-
20
- Next, create the data bag on the Chef Server.
21
-
22
- knife data bag create BAG
23
-
24
- Then upload the items in the data bag's directory to the Chef Server.
25
-
26
- knife data bag from file BAG ITEM.json
14
+ knife data bag from file example example_item.json
27
15
 
16
+ For more information on data bags, see the Chef wiki page:
17
+
18
+ https://docs.getchef.com/essentials_data_bags.html
28
19
 
29
20
  Encrypted Data Bags
30
21
  -------------------
@@ -61,3 +52,7 @@ Use the secret_key to view the contents.
61
52
  id: mysql
62
53
  password: abc123
63
54
 
55
+
56
+ For more information on encrypted data bags, see the Chef wiki page:
57
+
58
+ https://docs.getchef.com/essentials_data_bags.html
@@ -1,5 +1,9 @@
1
- Requires Chef 0.10.0+.
1
+ Create environments here, in either the Role Ruby DSL (.rb) or JSON (.json) files. To install environments on the server, use knife.
2
2
 
3
- This directory is for Ruby DSL and JSON files for environments. For more information see "About Environments" in the Chef documentation:
3
+ For example, in this directory you'll find an example environment file called `example.json` which can be uploaded to the Chef Server:
4
4
 
5
- http://docs.chef.io/environments.html
5
+ knife environment from file environments/example.json
6
+
7
+ For more information on environments, see the Chef wiki page:
8
+
9
+ https://docs.chef.io/environments.html
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "example",
3
+ "description": "This is an example environment defined as JSON",
4
+ "chef_type": "environment",
5
+ "json_class": "Chef::Environment",
6
+ "default_attributes": {
7
+ },
8
+ "override_attributes": {
9
+ },
10
+ "cookbook_versions": {
11
+ "example": "= 1.0.0"
12
+ }
13
+ }
@@ -1,16 +1,9 @@
1
1
  Create roles here, in either the Role Ruby DSL (.rb) or JSON (.json) files. To install roles on the server, use knife.
2
2
 
3
- For example, create `roles/base_example.rb`:
4
-
5
- name "base_example"
6
- description "Example base role applied to all nodes."
7
- # List of recipes and roles to apply. Requires Chef 0.8, earlier versions use 'recipes()'.
8
- #run_list()
9
- # Attributes applied if the node doesn't have it set already.
10
- #default_attributes()
11
- # Attributes applied no matter what the node has set already.
12
- #override_attributes()
13
-
14
- Then upload it to the Chef Server:
3
+ For example, in this directory you'll find an example role file called `example.json` which can be uploaded to the Chef Server:
15
4
 
16
- knife role from file roles/base_example.rb
5
+ knife role from file roles/example.json
6
+
7
+ For more information on roles, see the Chef wiki page:
8
+
9
+ https://docs.getchef.com/essentials_roles.html
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "example",
3
+ "description": "This is an example role defined as JSON",
4
+ "chef_type": "role",
5
+ "json_class": "Chef::Role",
6
+ "default_attributes": {
7
+ },
8
+ "override_attributes": {
9
+ },
10
+ "run_list": [
11
+ "recipe[example]"
12
+ ]
13
+ }
@@ -22,7 +22,11 @@ directory "#{app_dir}/test/integration/default/serverspec" do
22
22
  recursive true
23
23
  end
24
24
 
25
- cookbook_file "#{app_dir}/test/integration/default/serverspec/spec_helper.rb" do
25
+ directory "#{app_dir}/test/integration/helpers/serverspec" do
26
+ recursive true
27
+ end
28
+
29
+ cookbook_file "#{app_dir}/test/integration/helpers/serverspec/spec_helper.rb" do
26
30
  source 'serverspec_spec_helper.rb'
27
31
  action :create_if_missing
28
32
  end
@@ -36,7 +36,11 @@ directory "#{cookbook_dir}/test/integration/default/serverspec" do
36
36
  recursive true
37
37
  end
38
38
 
39
- cookbook_file "#{cookbook_dir}/test/integration/default/serverspec/spec_helper.rb" do
39
+ directory "#{cookbook_dir}/test/integration/helpers/serverspec" do
40
+ recursive true
41
+ end
42
+
43
+ cookbook_file "#{cookbook_dir}/test/integration/helpers/serverspec/spec_helper.rb" do
40
44
  source 'serverspec_spec_helper.rb'
41
45
  action :create_if_missing
42
46
  end
@@ -14,36 +14,21 @@ cookbook_file "#{repo_dir}/README.md" do
14
14
  source "repo/README.md"
15
15
  end
16
16
 
17
- cookbook_file "#{repo_dir}/Rakefile" do
18
- source "repo/Rakefile"
19
- end
20
-
21
17
  cookbook_file "#{repo_dir}/chefignore" do
22
18
  source "chefignore"
23
19
  end
24
20
 
25
- directory "#{repo_dir}/config"
26
-
27
- template "#{repo_dir}/config/rake.rb" do
28
- source "repo/config/rake.rb.erb"
29
- helpers(ChefDK::Generator::TemplateHelper)
30
- end
31
-
32
- %w{certificates data_bags environments roles}.each do |tlo|
33
- directory "#{repo_dir}/#{tlo}"
34
-
35
- cookbook_file "#{repo_dir}/#{tlo}/README.md" do
36
- source "repo/#{tlo}/README.md"
21
+ %w{cookbooks data_bags environments roles}.each do |tlo|
22
+ remote_directory "#{repo_dir}/#{tlo}" do
23
+ source "repo/#{tlo}"
37
24
  end
38
25
  end
39
26
 
40
- directory "#{repo_dir}/cookbooks"
41
-
42
27
  cookbook_file "#{repo_dir}/cookbooks/README.md" do
43
28
  if context.policy_only
44
- source "repo/cookbooks/README-policy.md"
29
+ source "cookbook_readmes/README-policy.md"
45
30
  else
46
- source "repo/cookbooks/README.md"
31
+ source "cookbook_readmes/README.md"
47
32
  end
48
33
  end
49
34
 
@@ -16,5 +16,5 @@
16
16
  #
17
17
 
18
18
  module ChefDK
19
- VERSION = "0.4.0"
19
+ VERSION = "0.5.0.rc.1"
20
20
  end
@@ -19,7 +19,7 @@
19
19
  require "kitchen/provisioner/chef_base"
20
20
 
21
21
  # TODO: chef-dk and kitchen can only co-exist if kitchen and chef-dk agree on
22
- # the version of mixlib-shellout to use. Kitchen currently locked at 1.x,
22
+ # the version of mixlib-shellout to use. Kitchen currently locked at 1.4,
23
23
  # chef-dk is on 2.x
24
24
  require 'chef-dk/policyfile_services/export_repo'
25
25
 
@@ -38,15 +38,19 @@ module Kitchen
38
38
  # * `deployment_group`: `POLICY_NAME-local`
39
39
  # Since it makes no sense to modify these, they are hardcoded elsewhere.
40
40
  default_config :client_rb, {}
41
- default_config :ruby_bindir, "/opt/chef/embedded/bin"
42
-
43
- # Policyfile mode does not support the `-j dna.json` option to
44
- # `chef-client`.
45
- default_config :json_attributes, false
41
+ default_config :json_attributes, true
42
+ default_config :chef_zero_host, nil
46
43
  default_config :chef_zero_port, 8889
47
44
 
48
45
  default_config :chef_client_path do |provisioner|
49
- File.join(provisioner[:chef_omnibus_root], %w[bin chef-client])
46
+ provisioner.
47
+ remote_path_join(%W[#{provisioner[:chef_omnibus_root]} bin chef-client]).
48
+ tap { |path| path.concat(".bat") if provisioner.windows_os? }
49
+ end
50
+
51
+ default_config :ruby_bindir do |provisioner|
52
+ provisioner.
53
+ remote_path_join(%W[#{provisioner[:chef_omnibus_root]} embedded bin])
50
54
  end
51
55
 
52
56
  # Emit a warning that Policyfile stuff is still experimental.
@@ -62,6 +66,7 @@ module Kitchen
62
66
  # (see Base#create_sandbox)
63
67
  def create_sandbox
64
68
  super
69
+ prepare_cookbooks
65
70
  prepare_validation_pem
66
71
  prepare_client_rb
67
72
  end
@@ -85,7 +90,10 @@ module Kitchen
85
90
  args << "--logfile #{config[:log_file]}"
86
91
  end
87
92
 
88
- Util.wrap_command([cmd, *args].join(" "))
93
+ wrap_shell_code(
94
+ [cmd, *args].join(" ").
95
+ tap { |str| str.insert(0, reload_ps1_path) if windows_os? }
96
+ )
89
97
  end
90
98
 
91
99
  private
@@ -112,7 +120,9 @@ module Kitchen
112
120
  #
113
121
  # @api private
114
122
  def policy_exporter
115
- @policy_exporter ||= ChefDK::PolicyfileServices::ExportRepo.new(export_dir: sandbox_path)
123
+ # Must force this because TK by default copies the current cookbook to the sandbox
124
+ # See ChefDK::PolicyfileServices::ExportRepo#assert_export_dir_clean!
125
+ @policy_exporter ||= ChefDK::PolicyfileServices::ExportRepo.new(export_dir: sandbox_path, force: true)
116
126
  end
117
127
 
118
128
  # Writes a fake (but valid) validation.pem into the sandbox directory.
@@ -135,6 +145,8 @@ module Kitchen
135
145
  data["use_policyfile"] = true
136
146
  data["versioned_cookbooks"] = true
137
147
  data["deployment_group"] = "#{policy_exporter.policy_name}-local"
148
+ # TODO this will need to be updated when chef-zero supports erchef paths (policy_group vs policies)
149
+ data["policy_document_native_api"] = false
138
150
 
139
151
  info("Preparing client.rb")
140
152
  debug("Creating client.rb from #{data.inspect}")
@@ -19,10 +19,18 @@ require 'rubygems'
19
19
  require 'rspec/mocks'
20
20
  require 'test_helpers'
21
21
 
22
+ # needed since we stub it for every test
23
+ require 'chef/workstation_config_loader'
24
+
22
25
  RSpec.configure do |c|
23
26
  c.include ChefDK
24
27
  c.include TestHelpers
25
28
 
29
+ # Avoid loading config.rb/knife.rb unintentionally
30
+ c.before(:each) do
31
+ allow_any_instance_of(Chef::WorkstationConfigLoader).to receive(:load)
32
+ end
33
+
26
34
  c.after(:all) { clear_tempdir }
27
35
 
28
36
  c.filter_run :focus => true
@@ -67,6 +67,14 @@ E
67
67
  cli.run
68
68
  end
69
69
 
70
+ def mock_shell_out(exitstatus, stdout, stderr)
71
+ shell_out = double("mixlib_shell_out")
72
+ allow(shell_out).to receive(:exitstatus).and_return(exitstatus)
73
+ allow(shell_out).to receive(:stdout).and_return(stdout)
74
+ allow(shell_out).to receive(:stderr).and_return(stderr)
75
+ shell_out
76
+ end
77
+
70
78
  subject(:cli) do
71
79
  ChefDK::CLI.new(argv).tap do |c|
72
80
  allow(c).to receive(:commands_map).and_return(commands_map)
@@ -106,12 +114,50 @@ E
106
114
  context "given -v" do
107
115
  let(:argv) { %w[-v] }
108
116
 
109
- it "prints the version" do
117
+ let(:tools) {
118
+ {
119
+ "chef-client" => {
120
+ "version_output" => "Chef: 12.0.3",
121
+ "expected_version" => "12.0.3"
122
+ },
123
+ "berks" => {
124
+ "version_output" => "3.2.3",
125
+ "expected_version" => "3.2.3"
126
+ },
127
+ "kitchen" => {
128
+ "version_output" => "Test Kitchen version 1.3.1",
129
+ "expected_version" => "1.3.1"
130
+ }
131
+ }
132
+ }
133
+
134
+ it "does not print versions of tools with missing or errored tools" do
135
+ full_version_message = version_message
136
+ tools.each do |name, version|
137
+ if name == "berks"
138
+ expect(cli).to receive(:shell_out).with("#{name} --version").and_return(mock_shell_out(1, "#{version["version_output"]}", ''))
139
+ full_version_message += "#{name} version: ERROR\n"
140
+ else
141
+ expect(cli).to receive(:shell_out).with("#{name} --version").and_return(mock_shell_out(0, "#{version["version_output"]}", ''))
142
+ full_version_message += "#{name} version: #{version["expected_version"]}\n"
143
+ end
144
+ end
145
+ run_cli(0)
146
+ expect(stdout).to eq(full_version_message)
147
+ end
148
+
149
+ it "prints the version and versions of chef-dk tools" do
150
+ full_version_message = version_message
151
+ tools.each do |name, version|
152
+ expect(cli).to receive(:shell_out).with("#{name} --version").and_return(mock_shell_out(0, "#{version["version_output"]}", ''))
153
+ full_version_message += "#{name} version: #{version["expected_version"]}\n"
154
+ end
110
155
  run_cli(0)
111
- expect(stdout).to eq(version_message)
156
+ expect(stdout).to eq(full_version_message)
112
157
  end
113
158
  end
114
159
 
160
+
115
161
  context "given an invalid option" do
116
162
 
117
163
  let(:argv) { %w[-nope] }
@@ -179,7 +225,7 @@ E
179
225
 
180
226
  let(:ruby_path) { '/opt/chefdk/embedded/bin/ruby' }
181
227
  let(:chefdk_embedded_path) { '/opt/chefdk/embedded/apps/chef-dk' }
182
-
228
+
183
229
  before do
184
230
  stub_const("File::PATH_SEPARATOR", ':')
185
231
  allow(Chef::Util::PathHelper).to receive(:cleanpath) do |path|
@@ -35,7 +35,7 @@ describe ChefDK::Command::GeneratorCommands::App do
35
35
  test/integration/default
36
36
  test/integration/default/serverspec
37
37
  test/integration/default/serverspec/default_spec.rb
38
- test/integration/default/serverspec/spec_helper.rb
38
+ test/integration/helpers/serverspec/spec_helper.rb
39
39
  README.md
40
40
  cookbooks/new_app/Berksfile
41
41
  cookbooks/new_app/chefignore
@@ -35,7 +35,7 @@ describe ChefDK::Command::GeneratorCommands::Cookbook do
35
35
  test/integration/default
36
36
  test/integration/default/serverspec
37
37
  test/integration/default/serverspec/default_spec.rb
38
- test/integration/default/serverspec/spec_helper.rb
38
+ test/integration/helpers/serverspec/spec_helper.rb
39
39
  Berksfile
40
40
  chefignore
41
41
  metadata.rb
@@ -153,14 +153,6 @@ describe ChefDK::Command::GeneratorCommands::Repo do
153
153
  end
154
154
  end
155
155
 
156
- describe "Rakefile" do
157
- let(:file) { "Rakefile" }
158
-
159
- it "loads the common tasks" do
160
- expect(file_contents).to match(/load 'chef\/tasks\/chef_repo\.rake'/)
161
- end
162
- end
163
-
164
156
  describe "chefignore" do
165
157
  let(:file) { "chefignore" }
166
158
 
@@ -189,16 +181,6 @@ describe ChefDK::Command::GeneratorCommands::Repo do
189
181
  end
190
182
  end
191
183
 
192
- describe "certificates" do
193
- describe "README.md" do
194
- let(:file) { "certificates/README.md" }
195
-
196
- it "has the right contents" do
197
- expect(file_contents).to match(/rake ssl_cert FQDN=monitoring.example.com/)
198
- end
199
- end
200
- end
201
-
202
184
  describe "cookbooks" do
203
185
  describe "README.md" do
204
186
  let(:file) { "cookbooks/README.md" }
@@ -215,6 +197,30 @@ describe ChefDK::Command::GeneratorCommands::Repo do
215
197
  end
216
198
  end
217
199
  end
200
+
201
+ describe "example/metadata.rb" do
202
+ let(:file) { "cookbooks/example/metadata.rb" }
203
+
204
+ it "has the right contents" do
205
+ expect(file_contents).to match(/name 'example'/)
206
+ end
207
+ end
208
+
209
+ describe "example/attributes/default.rb" do
210
+ let(:file) { "cookbooks/example/attributes/default.rb" }
211
+
212
+ it "has the right contents" do
213
+ expect(file_contents).to match(/default\["example"\]\["name"\] = "Sam Doe"/)
214
+ end
215
+ end
216
+
217
+ describe "example/recipes/default.rb" do
218
+ let(:file) { "cookbooks/example/recipes/default.rb" }
219
+
220
+ it "has the right contents" do
221
+ expect(file_contents).to match(/log "Welcome to Chef, \#\{node\["example"\]\["name"\]\}!" do/)
222
+ end
223
+ end
218
224
  end
219
225
 
220
226
  describe "data_bags" do
@@ -225,58 +231,48 @@ describe ChefDK::Command::GeneratorCommands::Repo do
225
231
  expect(file_contents).to match(/This directory contains directories of the various data bags/)
226
232
  end
227
233
  end
228
- end
229
234
 
230
- describe "environments" do
231
- describe "README.md" do
232
- let(:file) { "environments/README.md" }
235
+ describe "example_item.json" do
236
+ let(:file) { "data_bags/example/example_item.json" }
233
237
 
234
238
  it "has the right contents" do
235
- expect(file_contents).to match(/This directory is for Ruby DSL and JSON files for environments\./)
239
+ expect(file_contents).to match(/"id": "example_item"/)
236
240
  end
237
241
  end
238
242
  end
239
243
 
240
- describe "roles" do
244
+ describe "environments" do
241
245
  describe "README.md" do
242
- let(:file) { "roles/README.md" }
246
+ let(:file) { "environments/README.md" }
243
247
 
244
248
  it "has the right contents" do
245
- expect(file_contents).to match(/Create roles here/)
249
+ expect(file_contents).to match(/Create environments here, in either the Role Ruby DSL \(\.rb\) or JSON \(\.json\) files\./)
246
250
  end
247
251
  end
248
- end
249
252
 
250
- describe "config" do
251
- describe "rake.rb" do
252
- let(:file) { "config/rake.rb" }
253
+ describe "example.json" do
254
+ let(:file) { "environments/example.json" }
253
255
 
254
- it "has the preamble" do
255
- expect(file_contents).to match(/Configure the Rakefile's tasks\./)
256
- end
257
-
258
- it "defaults the copyright to The Authors" do
259
- expect(file_contents).to match(/COMPANY_NAME = "The Authors"/)
260
- end
261
-
262
- it "defaults the license to all_rights" do
263
- expect(file_contents).to match(/NEW_COOKBOOK_LICENSE = :all_rights/)
256
+ it "has the right contents" do
257
+ expect(file_contents).to match(/"description": "This is an example environment defined as JSON"/)
264
258
  end
259
+ end
260
+ end
265
261
 
266
- context "with a license" do
267
- let(:argv) { ["new_repo", "-I", "gplv3" ] }
262
+ describe "roles" do
263
+ describe "README.md" do
264
+ let(:file) { "roles/README.md" }
268
265
 
269
- it "uses the license" do
270
- expect(file_contents).to match(/NEW_COOKBOOK_LICENSE = :gplv3/)
271
- end
266
+ it "has the right contents" do
267
+ expect(file_contents).to match(/Create roles here, in either the Role Ruby DSL \(\.rb\) or JSON \(\.json\) files\./)
272
268
  end
269
+ end
273
270
 
274
- context "with a copyright holder" do
275
- let(:argv) { ["new_repo", "-C", "GiantCo, Inc." ] }
271
+ describe "example.json" do
272
+ let(:file) { "roles/example.json" }
276
273
 
277
- it "uses the copyright holder" do
278
- expect(file_contents).to match(/COMPANY_NAME = "GiantCo, Inc\."/)
279
- end
274
+ it "has the right contents" do
275
+ expect(file_contents).to match(/"description": "This is an example role defined as JSON"/)
280
276
  end
281
277
  end
282
278
  end