chef-dk 0.4.0 → 0.5.0.rc.1

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 (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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dc8cebdbcdaa5a3c3f4e2b3bf18fc1c3caca8843
4
- data.tar.gz: 9f57e9e37cf5b66823e9a6e3f6470afb369177fe
3
+ metadata.gz: ba6c0ab110f7a9fdc6434c4999a965e966a6d764
4
+ data.tar.gz: 1cdc0b41d6847ad1db3f23a83bcc02eaa33f5c1c
5
5
  SHA512:
6
- metadata.gz: 0f3578a7438281d5360cc4278e16e424e84c1dcec4f7087a8d9ce9dbbecd8a0e74c3b67d5fde04128bf58ee7815a21f3a48e12d444241928f2f2dd75cc1dc082
7
- data.tar.gz: e2e691462cb8febe46e0fec9d07f5f6f21e1bfc73bb89c7bb7556e475253f25ad75f521521cdd523f61c62ceaa3ab7323aead451a568c5339e9bd64c0ca61e21
6
+ metadata.gz: 74ad30f7c8a851fec368a512fb64c352b5bd9e6275598658680394469933a8b9af12fbdeb510f5d04b358ea21ef97ff8afc1b418cf389034944234b6e87fff6c
7
+ data.tar.gz: a621d898759ebe1527bf1b4c43e7619bbc2c6a4ca001c0fc625aea937c2b9087d55262f15f8a7e19428c2e57cadbcf0f5bd2f2aa1657e15007a4f8fbd5ca46c4
@@ -11,9 +11,7 @@ We utilize **Github Issues** for issue tracking and contributions. You can contr
11
11
 
12
12
  We have a 3 step process that utilizes **Github Issues**:
13
13
 
14
- 1. Sign our
15
- [Individual Contributor License Agreement (CLA)](https://secure.echosign.com/public/hostedForm?formid=PJIF5694K6L)
16
- or [Corporate CLA](https://secure.echosign.com/public/hostedForm?formid=PIE6C7AX856) online once.
14
+ 1. Sign or be added to an existing [Contributor License Agreement (CLA)](https://supermarket.chef.io/become-a-contributor).
17
15
  2. Create a Github Pull Request.
18
16
  3. Do [Code Review](#cr) with the **Chef Engineering Team** or **Chef Core Committers** on the pull request.
19
17
 
data/README.md CHANGED
@@ -17,7 +17,7 @@ package is built via the 'chefdk' project in
17
17
  You can get the [latest release of ChefDK from the downloads page][ChefDK].
18
18
 
19
19
  On Mac OS X, you can also use [homebrew-cask](http://caskroom.io)
20
- to install ChefDK.
20
+ to `brew cask install chefdk`.
21
21
 
22
22
  Once you install the package, the `chef-client` suite, `berks`,
23
23
  `kitchen`, and this application (`chef`) will be symlinked into your
@@ -104,8 +104,8 @@ in our build cluster to verify each build).
104
104
 
105
105
  ### `chef exec`
106
106
  `chef exec <command>` runs any arbitrary shell command with the PATH
107
- environment variable and the ruby environment variables (GEM_HOME,
108
- GEM_PATH, etc) setup to point at the embedded ChefDK omnibus environment.
107
+ environment variable and the ruby environment variables (`GEM_HOME`,
108
+ `GEM_PATH`, etc.) setup to point at the embedded ChefDK omnibus environment.
109
109
 
110
110
  ### `chef shell-init`
111
111
  `chef shell-init SHELL_NAME` emits shell commands that modify your
@@ -114,11 +114,11 @@ help you decide if this is desirable and instructions, see "Using ChefDK
114
114
  as Your Primary Development Environment" below.
115
115
 
116
116
  ### `chef install`
117
- `chef install` reads a Policyfile.rb document, which contains a
117
+ `chef install` reads a `Policyfile.rb` document, which contains a
118
118
  `run_list` and optional cookbook version constraints, finds a set of
119
119
  cookbooks that provide the desired recipes and meet dependency
120
- constraints, and emits a Policyfile.lock.json describing the expanded
121
- run list and locked cookbook set. The Policyfile.lock.json can be used
120
+ constraints, and emits a `Policyfile.lock.json` describing the expanded
121
+ run list and locked cookbook set. The `Policyfile.lock.json` can be used
122
122
  to install the cookbooks on another machine. The policy lock can be
123
123
  uploaded to a Chef Server (via the `chef push` command) to apply the
124
124
  expanded run list and locked cookbook set to nodes in your
@@ -152,21 +152,27 @@ ChefDK's environment.
152
152
 
153
153
  To try it temporarily, in a new terminal session, run:
154
154
 
155
- eval "$(chef shell-init SHELL_NAME)"
155
+ ```sh
156
+ eval "$(chef shell-init SHELL_NAME)"
157
+ ```
156
158
 
157
- where `SHELL_NAME` is the name of your shell, (usually bash, but zsh is
159
+ where `SHELL_NAME` is the name of your shell (usually bash, but zsh is
158
160
  also common). This modifies your `PATH` and `GEM_*` environment
159
161
  variables to include ChefDK's paths (run without the `eval` to see the
160
162
  generated code). Now your default `ruby` and associated tools will be
161
163
  the ones from ChefDK:
162
164
 
163
- which ruby
164
- # => /opt/chefdk/embedded/bin/ruby
165
+ ```sh
166
+ which ruby
167
+ # => /opt/chefdk/embedded/bin/ruby
168
+ ```
165
169
 
166
170
  To add ChefDK to your shell's environment permanently, add the
167
171
  initialization step to your shell's profile:
168
172
 
169
- echo 'eval "$(chef shell-init SHELL_NAME)"' >> ~/.YOUR_SHELL_PROFILE
173
+ ```sh
174
+ echo 'eval "$(chef shell-init SHELL_NAME)"' >> ~/.YOUR_SHELL_PROFILE
175
+ ```
170
176
 
171
177
  Where `YOUR_SHELL_PROFILE` is `~/.bash_profile` for most bash users,
172
178
  `~/.zshrc` for zsh, and `~/.bashrc` on Ubuntu.
@@ -177,7 +183,7 @@ Where `YOUR_SHELL_PROFILE` is `~/.bash_profile` for most bash users,
177
183
 
178
184
  You can uninstall Chef Development Kit on Mac using below commands:
179
185
 
180
- ```
186
+ ```sh
181
187
  # Remove the installed files
182
188
  sudo rm -rf /opt/chefdk
183
189
 
@@ -186,7 +192,6 @@ sudo pkgutil --forget com.getchef.pkg.chefdk
186
192
 
187
193
  # Remove the symlinks under /usr/bin for Chef Development Kit
188
194
  ls -la /usr/bin | egrep '/opt/chefdk' | awk '{ print $9 }' | sudo xargs -I % rm -f /usr/bin/%
189
-
190
195
  ```
191
196
 
192
197
  ### Windows
@@ -198,7 +203,7 @@ Kit from your system.
198
203
 
199
204
  You can use `rpm` to uninstall Chef Development Kit on RHEL based systems:
200
205
 
201
- ```
206
+ ```sh
202
207
  rpm -qa *chefdk*
203
208
  yum remove <package>
204
209
  rm -rf /opt/chefdk
@@ -209,7 +214,7 @@ rm -rf ~/.chefdk
209
214
 
210
215
  You can use `dpkg` to uninstall Chef Development Kit on Ubuntu based systems:
211
216
 
212
- ```
217
+ ```sh
213
218
  dpkg --list | grep chefdk # or dpkg --status chefdk
214
219
 
215
220
  # Purge chefdk from the system.
@@ -22,11 +22,14 @@ require 'chef-dk/builtin_commands'
22
22
  require 'chef-dk/helpers'
23
23
  require 'chef-dk/ui'
24
24
  require 'chef/util/path_helper'
25
+ require 'chef/mixin/shell_out'
26
+ require 'bundler'
25
27
 
26
28
  module ChefDK
27
29
  class CLI
28
30
  include Mixlib::CLI
29
31
  include ChefDK::Helpers
32
+ include Chef::Mixin::ShellOut
30
33
 
31
34
  banner(<<-BANNER)
32
35
  Usage:
@@ -84,13 +87,27 @@ BANNER
84
87
  def handle_options
85
88
  parse_options(argv)
86
89
  if config[:version]
87
- msg("Chef Development Kit Version: #{ChefDK::VERSION}")
90
+ show_version
88
91
  else
89
92
  show_help
90
93
  end
91
94
  exit 0
92
95
  end
93
96
 
97
+ def show_version
98
+ msg("Chef Development Kit Version: #{ChefDK::VERSION}")
99
+
100
+ ["chef-client", "berks", "kitchen"].each do |component|
101
+ result = Bundler.with_clean_env { shell_out("#{component} --version") }
102
+ if result.exitstatus != 0
103
+ msg("#{component} version: ERROR")
104
+ else
105
+ version = result.stdout.scan(/[\d+\.]+\S+/).join
106
+ msg("#{component} version: #{version}")
107
+ end
108
+ end
109
+ end
110
+
94
111
  def show_help
95
112
  msg(banner)
96
113
  msg("\nAvailable Commands:")
@@ -98,7 +98,7 @@ module ChefDK
98
98
 
99
99
  add_component "chef-client" do |c|
100
100
  c.base_dir = "chef"
101
- c.unit_test { sh("bundle exec rspec -fp spec/unit") }
101
+ c.unit_test { sh("bundle exec rspec -fp -t '~volatile_from_verify' spec/unit") }
102
102
  c.integration_test { sh("bundle exec rspec -fp spec/integration spec/functional") }
103
103
 
104
104
  c.smoke_test do
@@ -80,7 +80,7 @@ module ChefDK
80
80
 
81
81
  def errors
82
82
  error_messages = []
83
- if installer.nil?
83
+ if source_options_invalid?
84
84
  error_messages << "Cookbook `#{name}' has invalid source options `#{source_options.inspect}'"
85
85
  end
86
86
  error_messages
@@ -124,6 +124,10 @@ module ChefDK
124
124
  installer.lock_data
125
125
  end
126
126
 
127
+ def source_options_invalid?
128
+ !source_options.empty? && installer.nil?
129
+ end
130
+
127
131
  end
128
132
  end
129
133
  end
@@ -22,6 +22,48 @@ require 'chef/cookbook/chefignore'
22
22
 
23
23
  module ChefDK
24
24
  module Policyfile
25
+
26
+ class CookbookLoaderWithChefignore
27
+
28
+ # Convenience method to load a cookbook and return a
29
+ # Chef::CookbookVersion object.
30
+ #
31
+ def self.load(name, directory_path)
32
+ new(name, directory_path).cookbook_version
33
+ end
34
+
35
+ attr_reader :cookbook_name
36
+ attr_reader :directory_path
37
+
38
+ def initialize(cookbook_name, directory_path)
39
+ @cookbook_name = cookbook_name
40
+ @directory_path = directory_path
41
+
42
+ @cookbook_version = nil
43
+ @loader = nil
44
+ end
45
+
46
+ def cookbook_version
47
+ @cookbook_version ||= loader.cookbook_version
48
+ end
49
+
50
+ def loader
51
+ @loader ||=
52
+ begin
53
+ cbvl = Chef::Cookbook::CookbookVersionLoader.new(directory_path, chefignore)
54
+ cbvl.load!
55
+ cbvl
56
+ end
57
+ end
58
+
59
+ def chefignore
60
+ @chefignore ||= Chef::Cookbook::Chefignore.new(File.join(directory_path, "chefignore"))
61
+ end
62
+
63
+ end
64
+
65
+ # TODO: when compat mode is removed, this class should be removed and the
66
+ # file should be renamed
25
67
  class ReadCookbookForCompatModeUpload
26
68
 
27
69
  # Convenience method to load a cookbook, set up name and version overrides
@@ -47,7 +89,9 @@ module ChefDK
47
89
  @cookbook_version ||=
48
90
  begin
49
91
  cookbook_version = loader.cookbook_version
92
+ # TODO: dont do this for non-compat mode
50
93
  cookbook_version.version = version_override
94
+ # TODO: dont do this either
51
95
 
52
96
  # Fixup manifest.
53
97
  # What happens is, the 'manifest' representation of cookbook
@@ -49,7 +49,16 @@ module ChefDK
49
49
  end
50
50
 
51
51
  def upload
52
- ui.msg("WARN: Uploading policy to policy group #{policy_group} in compatibility mode")
52
+ ui.msg("Uploading policy to policy group #{policy_group}")
53
+
54
+ if using_policy_document_native_api?
55
+ ui.msg(<<-DRAGONS)
56
+ WARN: Using native policy API preview mode. You may be required to delete and
57
+ re-upload this data when upgrading to the final release version of the feature.
58
+ DRAGONS
59
+ else
60
+ ui.msg("WARN: Uploading policy to policy group #{policy_group} in compatibility mode")
61
+ end
53
62
 
54
63
  upload_cookbooks
55
64
  upload_policy
@@ -65,7 +74,7 @@ module ChefDK
65
74
  end
66
75
 
67
76
  def upload_policy_native
68
- http_client.put("/policies/#{policy_group}/#{policy_name}", policyfile_lock.to_lock)
77
+ http_client.put("/policy_groups/#{policy_group}/policies/#{policy_name}", policyfile_lock.to_lock)
69
78
  end
70
79
 
71
80
  def data_bag_create
@@ -97,12 +106,17 @@ module ChefDK
97
106
 
98
107
  def uploader
99
108
  # TODO: uploader runs cookbook validation; we want to do this at a different time.
100
- @uploader ||= Chef::CookbookUploader.new(cookbook_versions_to_upload, :rest => http_client)
109
+ @uploader ||= Chef::CookbookUploader.new(cookbook_versions_to_upload, rest: http_client, policy_mode: using_policy_document_native_api?)
101
110
  end
102
111
 
103
112
  def cookbook_versions_to_upload
104
113
  cookbook_versions_for_policy.inject([]) do |versions_to_upload, cookbook_with_lock|
105
114
  cb = cookbook_with_lock.cookbook
115
+ # When we abandon custom identifier support in favor of the one true
116
+ # hash, identifier generation code can be moved into chef proper and
117
+ # this can be removed.
118
+ cb.identifier = cookbook_with_lock.lock.identifier
119
+
106
120
  versions_to_upload << cb unless remote_already_has_cookbook?(cb)
107
121
  versions_to_upload
108
122
  end
@@ -111,13 +125,27 @@ module ChefDK
111
125
  def remote_already_has_cookbook?(cookbook)
112
126
  return false unless existing_cookbook_on_remote.key?(cookbook.name.to_s)
113
127
 
128
+ if using_policy_document_native_api?
129
+ native_mode_cookbook_exists_on_remote?(cookbook)
130
+ else
131
+ compat_mode_cookbook_exists_on_remote?(cookbook)
132
+ end
133
+ end
134
+
135
+ def native_mode_cookbook_exists_on_remote?(cookbook)
136
+ existing_cookbook_on_remote[cookbook.name.to_s]["versions"].any? do |cookbook_info|
137
+ cookbook_info["identifier"] == cookbook.identifier
138
+ end
139
+ end
140
+
141
+ def compat_mode_cookbook_exists_on_remote?(cookbook)
114
142
  existing_cookbook_on_remote[cookbook.name.to_s]["versions"].any? do |cookbook_info|
115
143
  cookbook_info["version"] == cookbook.version
116
144
  end
117
145
  end
118
146
 
119
147
  def existing_cookbook_on_remote
120
- @existing_cookbook_on_remote ||= http_client.get('cookbooks?num_versions=all')
148
+ @existing_cookbook_on_remote ||= http_client.get(list_cookbooks_url)
121
149
  end
122
150
 
123
151
  # An Array of Chef::CookbookVersion objects representing the full set that
@@ -125,7 +153,23 @@ module ChefDK
125
153
  def cookbook_versions_for_policy
126
154
  return @cookbook_versions_for_policy if @cookbook_versions_for_policy
127
155
  policyfile_lock.validate_cookbooks!
128
- @cookbook_versions_for_policy = policyfile_lock.cookbook_locks.map do |name, lock|
156
+ @cookbook_versions_for_policy =
157
+ if using_policy_document_native_api?
158
+ load_cookbooks_in_native_mode
159
+ else
160
+ load_cookbooks_in_compat_mode
161
+ end
162
+ end
163
+
164
+ def load_cookbooks_in_native_mode
165
+ policyfile_lock.cookbook_locks.map do |name, lock|
166
+ cb = CookbookLoaderWithChefignore.load(name, lock.cookbook_path)
167
+ LockedCookbookForUpload.new(cb, lock)
168
+ end
169
+ end
170
+
171
+ def load_cookbooks_in_compat_mode
172
+ policyfile_lock.cookbook_locks.map do |name, lock|
129
173
  cb = ReadCookbookForCompatModeUpload.load(name, lock.dotted_decimal_identifier, lock.cookbook_path)
130
174
  LockedCookbookForUpload.new(cb, lock)
131
175
  end
@@ -137,8 +181,16 @@ module ChefDK
137
181
 
138
182
  private
139
183
 
184
+ def list_cookbooks_url
185
+ if using_policy_document_native_api?
186
+ 'cookbook_artifacts?num_versions=all'
187
+ else
188
+ 'cookbooks?num_versions=all'
189
+ end
190
+ end
191
+
140
192
  def upload_cookbooks
141
- ui.msg("WARN: Uploading cookbooks using semver compat mode")
193
+ ui.msg("WARN: Uploading cookbooks using semver compat mode") unless using_policy_document_native_api?
142
194
 
143
195
  uploader.upload_cookbooks unless cookbook_versions_to_upload.empty?
144
196
 
@@ -15,6 +15,8 @@
15
15
  # limitations under the License.
16
16
  #
17
17
 
18
+ require 'digest/sha1'
19
+
18
20
  require 'chef-dk/policyfile/storage_config'
19
21
  require 'chef-dk/policyfile/cookbook_locks'
20
22
  require 'chef-dk/policyfile/solution_dependencies'
@@ -125,6 +127,7 @@ module ChefDK
125
127
 
126
128
  def to_lock
127
129
  {}.tap do |lock|
130
+ lock["revision_id"] = revision_id
128
131
  lock["name"] = name
129
132
  lock["run_list"] = run_list
130
133
  lock["named_run_lists"] = named_run_lists unless named_run_lists.empty?
@@ -133,6 +136,45 @@ module ChefDK
133
136
  end
134
137
  end
135
138
 
139
+ # Returns a fingerprint of the PolicyfileLock by computing the SHA1 hash of
140
+ # #canonical_revision_string
141
+ def revision_id
142
+ Digest::SHA1.new.hexdigest(canonical_revision_string)
143
+ end
144
+
145
+ # Generates a string representation of the lock data in a specialized
146
+ # format suitable for generating a checksum of the lock itself. Only data
147
+ # that modifies the behavior of a chef-client using the lockfile is
148
+ # included in this format; for example, a modification to the source
149
+ # options in a `Policyfile.rb` that yields identical code (such as
150
+ # switching to a github fork at the same revision) will not cause a change
151
+ # in the PolicyfileLock's canonical_revision_string.
152
+ #
153
+ # This format is intended to be used only for generating an identifier for
154
+ # a particular revision of a PolicyfileLock. It should not be used as a
155
+ # serialization format, and is not guaranteed to be a stable interface.
156
+ def canonical_revision_string
157
+ canonical_rev_text = ""
158
+
159
+ canonical_rev_text << "name:#{name}\n"
160
+
161
+ run_list.each do |item|
162
+ canonical_rev_text << "run-list-item:#{item}\n"
163
+ end
164
+
165
+ named_run_lists.each do |name, run_list|
166
+ run_list.each do |item|
167
+ canonical_rev_text << "named-run-list:#{name};run-list-item:#{item}\n"
168
+ end
169
+ end
170
+
171
+ cookbook_locks_for_lockfile.each do |name, lock|
172
+ canonical_rev_text << "cookbook:#{name};id:#{lock["identifier"]}\n"
173
+ end
174
+
175
+ canonical_rev_text
176
+ end
177
+
136
178
  def cookbook_locks_for_lockfile
137
179
  cookbook_locks.inject({}) do |locks_map, (name, location_spec)|
138
180
  location_spec.validate!
@@ -1,4 +1,4 @@
1
- This directory contains the cookbooks used to configure systems in your infrastructure with Chef.
1
+ This directory contains the cookbooks used to configure systems in your infrastructure with Chef - an example basic cookbook called `example` has been automatically created for you.
2
2
 
3
3
  Knife needs to be configured to know where the cookbooks are located with the `cookbook_path` setting. If this is not set, then several cookbook operations will fail to work properly.
4
4
 
@@ -0,0 +1,7 @@
1
+ # This is a Chef attributes file. It can be used to specify default and override
2
+ # attributes to be applied to nodes that run this cookbook.
3
+
4
+ # Set a default name
5
+ default["example"]["name"] = "Sam Doe"
6
+
7
+ # For further information, see the Chef documentation (http://docs.getchef.com/essentials_cookbook_attribute_files.html).