chef-dk 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -0
  3. data/lib/chef-dk/builtin_commands.rb +7 -0
  4. data/lib/chef-dk/command/env.rb +90 -0
  5. data/lib/chef-dk/command/export.rb +22 -1
  6. data/lib/chef-dk/command/generate.rb +1 -1
  7. data/lib/chef-dk/command/provision.rb +43 -0
  8. data/lib/chef-dk/command/push_archive.rb +126 -0
  9. data/lib/chef-dk/command/show_policy.rb +166 -0
  10. data/lib/chef-dk/command/verify.rb +58 -1
  11. data/lib/chef-dk/cookbook_omnifetch.rb +3 -2
  12. data/lib/chef-dk/exceptions.rb +27 -0
  13. data/lib/chef-dk/helpers.rb +29 -0
  14. data/lib/chef-dk/policyfile/chef_repo_cookbook_source.rb +8 -0
  15. data/lib/chef-dk/policyfile/chef_server_cookbook_source.rb +8 -0
  16. data/lib/chef-dk/policyfile/community_cookbook_source.rb +8 -0
  17. data/lib/chef-dk/policyfile/cookbook_locks.rb +76 -6
  18. data/lib/chef-dk/policyfile/dsl.rb +10 -5
  19. data/lib/chef-dk/policyfile/lister.rb +230 -0
  20. data/lib/chef-dk/policyfile/null_cookbook_source.rb +8 -0
  21. data/lib/chef-dk/policyfile_compiler.rb +35 -2
  22. data/lib/chef-dk/policyfile_lock.rb +43 -0
  23. data/lib/chef-dk/policyfile_services/clean_policies.rb +94 -0
  24. data/lib/chef-dk/policyfile_services/export_repo.rb +103 -16
  25. data/lib/chef-dk/policyfile_services/push_archive.rb +173 -0
  26. data/lib/chef-dk/policyfile_services/show_policy.rb +237 -0
  27. data/lib/chef-dk/service_exceptions.rb +21 -0
  28. data/lib/chef-dk/skeletons/code_generator/files/default/chefignore +1 -0
  29. data/lib/chef-dk/skeletons/code_generator/files/default/repo/README.md +2 -40
  30. data/lib/chef-dk/skeletons/code_generator/recipes/app.rb +0 -2
  31. data/lib/chef-dk/skeletons/code_generator/templates/default/kitchen.yml.erb +2 -2
  32. data/lib/chef-dk/skeletons/code_generator/templates/default/recipe_spec.rb.erb +1 -1
  33. data/lib/chef-dk/version.rb +1 -1
  34. data/spec/unit/command/env_spec.rb +52 -0
  35. data/spec/unit/command/exec_spec.rb +2 -2
  36. data/spec/unit/command/export_spec.rb +13 -0
  37. data/spec/unit/command/provision_spec.rb +56 -0
  38. data/spec/unit/command/push_archive_spec.rb +153 -0
  39. data/spec/unit/command/show_policy_spec.rb +235 -0
  40. data/spec/unit/command/verify_spec.rb +1 -0
  41. data/spec/unit/helpers_spec.rb +68 -0
  42. data/spec/unit/policyfile/cookbook_locks_spec.rb +107 -1
  43. data/spec/unit/policyfile/lister_spec.rb +256 -0
  44. data/spec/unit/policyfile_demands_spec.rb +202 -10
  45. data/spec/unit/policyfile_evaluation_spec.rb +30 -4
  46. data/spec/unit/policyfile_lock_serialization_spec.rb +45 -0
  47. data/spec/unit/policyfile_services/clean_policies_spec.rb +236 -0
  48. data/spec/unit/policyfile_services/export_repo_spec.rb +99 -6
  49. data/spec/unit/policyfile_services/push_archive_spec.rb +345 -0
  50. data/spec/unit/policyfile_services/show_policy_spec.rb +839 -0
  51. metadata +139 -8
@@ -0,0 +1,237 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2015 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 'chef-dk/policyfile/comparison_base'
19
+ require 'chef-dk/policyfile/lister'
20
+ require 'chef-dk/pager'
21
+
22
+ module ChefDK
23
+ module PolicyfileServices
24
+ class ShowPolicy
25
+ class ReportPrinter
26
+
27
+ attr_reader :ui
28
+
29
+ def initialize(ui)
30
+ @ui = ui
31
+ end
32
+
33
+ def h1(heading)
34
+ ui.msg(heading)
35
+ ui.msg("=" * heading.size)
36
+ ui.msg("")
37
+ end
38
+
39
+ def h2(heading)
40
+ ui.msg(heading)
41
+ ui.msg("-" * heading.size)
42
+ ui.msg("")
43
+ end
44
+
45
+ def table_list(items)
46
+ left_justify_size = items.keys.map(&:size).max.to_i + 2
47
+ items.each do |name, value|
48
+ justified_name = "#{name}:".ljust(left_justify_size)
49
+ ui.msg("* #{justified_name} #{value}")
50
+ end
51
+
52
+ ui.msg("")
53
+ end
54
+
55
+ def list(items)
56
+ items.each { |item| ui.msg("* #{item}") }
57
+ ui.msg("")
58
+ end
59
+ end
60
+
61
+ attr_reader :policy_lister
62
+
63
+ attr_reader :ui
64
+
65
+ attr_reader :policy_name
66
+
67
+ attr_reader :chef_config
68
+
69
+ attr_reader :policy_group
70
+
71
+ def initialize(config: nil, ui: nil, policy_name: nil, policy_group: nil, show_orphans: false, summary_diff: false, pager: false)
72
+ @chef_config = config
73
+ @ui = ui
74
+ @policy_name = policy_name
75
+ @policy_group = policy_group
76
+ @show_orphans = show_orphans
77
+ @summary_diff = summary_diff
78
+ @enable_pager = pager
79
+ end
80
+
81
+ def run
82
+ if show_policy_revision?
83
+ display_policy_revision
84
+ elsif show_all_policies?
85
+ display_all_policies
86
+ else
87
+ display_single_policy
88
+ end
89
+ true
90
+ rescue PolicyfileNestedException
91
+ raise
92
+ rescue => e
93
+ raise PolicyfileListError.new("Failed to list policyfile data from the server", e)
94
+ end
95
+
96
+ def show_policy_revision?
97
+ !!policy_group
98
+ end
99
+
100
+ def show_all_policies?
101
+ !policy_name
102
+ end
103
+
104
+ def show_orphans?
105
+ @show_orphans
106
+ end
107
+
108
+ def show_summary_diff?
109
+ @summary_diff
110
+ end
111
+
112
+ def enable_pager?
113
+ @enable_pager
114
+ end
115
+
116
+ def report
117
+ @report ||= ReportPrinter.new(ui)
118
+ end
119
+
120
+ def policy_lister
121
+ @policy_info_fetcher ||= Policyfile::Lister.new(config: chef_config)
122
+ end
123
+
124
+ def display_policy_revision
125
+ lock = Policyfile::ComparisonBase::PolicyGroup.new(policy_group, policy_name, http_client).lock
126
+ pager = Pager.new(enable_pager: enable_pager?)
127
+ pager.with_pager { |p| p.ui.msg(FFI_Yajl::Encoder.encode(lock, pretty: true)) }
128
+ end
129
+
130
+ def display_all_policies
131
+ if policy_lister.empty?
132
+ ui.err("No policies or policy groups exist on the server")
133
+ return
134
+ end
135
+ if policy_lister.policies_by_name.empty?
136
+ ui.err("No policies exist on the server")
137
+ return
138
+ end
139
+ policy_lister.revision_ids_by_group_for_each_policy do |policy_name, rev_id_by_group|
140
+ report.h1(policy_name)
141
+
142
+ if rev_id_by_group.empty?
143
+ ui.err("Policy #{policy_name} is not assigned to any groups")
144
+ ui.err("")
145
+ else
146
+ rev_ids_for_report = format_rev_ids_for_report(rev_id_by_group)
147
+ report.table_list(rev_ids_for_report)
148
+ end
149
+
150
+ if show_orphans?
151
+ orphans = policy_lister.orphaned_revisions(policy_name)
152
+
153
+ unless orphans.empty?
154
+ report.h2("Orphaned:")
155
+ formatted_orphans = orphans.map { |id| shorten_rev_id(id) }
156
+ report.list(formatted_orphans)
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ def display_single_policy
163
+ report.h1(policy_name)
164
+ rev_id_by_group = policy_lister.revision_ids_by_group_for(policy_name)
165
+
166
+ if rev_id_by_group.empty?
167
+ ui.err("No policies named '#{policy_name}' are associated with a policy group")
168
+ ui.err("")
169
+ elsif show_summary_diff?
170
+ unique_rev_ids = rev_id_by_group.unique_revision_ids
171
+ revision_info = policy_lister.revision_info_for(policy_name, unique_rev_ids)
172
+
173
+ ljust_size = rev_id_by_group.max_group_name_length + 2
174
+
175
+ cbs_with_differing_ids = revision_info.cbs_with_differing_ids
176
+
177
+ rev_id_by_group.each do |group_name, rev_id|
178
+ heading = "#{group_name}:".ljust(ljust_size) + shorten_rev_id(rev_id)
179
+ report.h2(heading)
180
+
181
+ differing_cbs_version_info = cbs_with_differing_ids.inject({}) do |cb_version_info, cb_name|
182
+
183
+ version, identifier = revision_info.cb_info_for(rev_id, cb_name)
184
+
185
+ cb_info_for_report =
186
+ if !version.nil?
187
+ "#{version} (#{shorten_rev_id(identifier)})"
188
+ else
189
+ "*NONE*"
190
+ end
191
+
192
+ cb_version_info[cb_name] = cb_info_for_report
193
+
194
+ cb_version_info
195
+ end
196
+
197
+ report.table_list(differing_cbs_version_info)
198
+ end
199
+
200
+ else
201
+ rev_ids_for_report = format_rev_ids_for_report(rev_id_by_group)
202
+ report.table_list(rev_ids_for_report)
203
+ end
204
+
205
+ if show_orphans?
206
+ orphans = policy_lister.orphaned_revisions(policy_name)
207
+
208
+ unless orphans.empty?
209
+ report.h2("Orphaned:")
210
+ formatted_orphans = orphans.map { |id| shorten_rev_id(id) }
211
+ report.list(formatted_orphans)
212
+ end
213
+ end
214
+ end
215
+
216
+ def shorten_rev_id(revision_id)
217
+ revision_id[0,10]
218
+ end
219
+
220
+ def http_client
221
+ @http_client ||= ChefDK::AuthenticatedHTTP.new(chef_config.chef_server_url,
222
+ signing_key_filename: chef_config.client_key,
223
+ client_name: chef_config.node_name)
224
+ end
225
+
226
+ private
227
+
228
+ def format_rev_ids_for_report(rev_id_by_group)
229
+ rev_id_by_group.format_revision_ids do |rev_id|
230
+ rev_id ? rev_id[0,10] : "*NOT APPLIED*"
231
+ end
232
+ end
233
+
234
+
235
+ end
236
+ end
237
+ end
@@ -31,6 +31,7 @@ module ChefDK
31
31
 
32
32
  def initialize(message, cause)
33
33
  super(message)
34
+ @message = message
34
35
  @inspector = inspector_for(cause)
35
36
  @cause = cause
36
37
  end
@@ -43,6 +44,14 @@ module ChefDK
43
44
  inspector.extended_error_info
44
45
  end
45
46
 
47
+ def message
48
+ @message
49
+ end
50
+
51
+ def to_s
52
+ "#{message}\nCaused by: #{reason}"
53
+ end
54
+
46
55
  private
47
56
 
48
57
  def inspector_for(exception)
@@ -76,6 +85,9 @@ module ChefDK
76
85
  class ExportDirNotEmpty < PolicyfileServiceError
77
86
  end
78
87
 
88
+ class InvalidPolicyArchive < PolicyfileServiceError
89
+ end
90
+
79
91
  class PolicyfileNestedException < PolicyfileServiceError
80
92
 
81
93
  include NestedExceptionWithInspector
@@ -91,12 +103,21 @@ module ChefDK
91
103
  class PolicyfileUpdateError < PolicyfileNestedException
92
104
  end
93
105
 
106
+ class PolicyfilePushArchiveError < PolicyfileNestedException
107
+ end
108
+
94
109
  class PolicyfilePushError < PolicyfileNestedException
95
110
  end
96
111
 
97
112
  class PolicyfileExportRepoError < PolicyfileNestedException
98
113
  end
99
114
 
115
+ class PolicyfileListError < PolicyfileNestedException
116
+ end
117
+
118
+ class PolicyfileCleanError < PolicyfileNestedException
119
+ end
120
+
100
121
  class ChefRunnerError < StandardError
101
122
 
102
123
  include NestedExceptionWithInspector
@@ -53,6 +53,7 @@ test/*
53
53
  features/*
54
54
  Guardfile
55
55
  Procfile
56
+ .kitchen
56
57
 
57
58
  # SCM #
58
59
  #######
@@ -10,53 +10,15 @@ Repository Directories
10
10
 
11
11
  This repository contains several directories, and each directory contains a README file that describes what it is for in greater detail, and how to use it for managing your systems with Chef.
12
12
 
13
- * `certificates/` - SSL certificates generated by `rake ssl_cert` live here.
14
- * `config/` - Contains the Rake configuration file, `rake.rb`.
15
13
  * `cookbooks/` - Cookbooks you download or create.
16
14
  * `data_bags/` - Store data bags and items in .json in the repository.
17
15
  * `roles/` - Store roles in .rb or .json in the repository.
18
-
19
- Rake Tasks
20
- ==========
21
-
22
- The repository contains a `Rakefile` that includes tasks that are installed with the Chef libraries. To view the tasks available with in the repository with a brief description, run `rake -T`.
23
-
24
- The default task (`default`) is run when executing `rake` with no arguments. It will call the task `test_cookbooks`.
25
-
26
- The following tasks are not directly replaced by knife sub-commands.
27
-
28
- * `bundle_cookbook[cookbook]` - Creates cookbook tarballs in the `pkgs/` dir.
29
- * `install` - Calls `update`, `roles` and `upload_cookbooks` Rake tasks.
30
- * `ssl_cert` - Create self-signed SSL certificates in `certificates/` dir.
31
- * `update` - Update the repository from source control server, understands git and svn.
32
-
33
- The following tasks duplicate functionality from knife and may be removed in a future version of Chef.
34
-
35
- * `metadata` - replaced by `knife cookbook metadata -a`.
36
- * `new_cookbook` - replaced by `knife cookbook create`.
37
- * `role[role_name]` - replaced by `knife role from file`.
38
- * `roles` - iterates over the roles and uploads with `knife role from file`.
39
- * `test_cookbooks` - replaced by `knife cookbook test -a`.
40
- * `test_cookbook[cookbook]` - replaced by `knife cookbook test COOKBOOK`.
41
- * `upload_cookbooks` - replaced by `knife cookbook upload -a`.
42
- * `upload_cookbook[cookbook]` - replaced by `knife cookbook upload COOKBOOK`.
16
+ * `environments/` - Store environments in .rb or .json in the repository.
43
17
 
44
18
  Configuration
45
19
  =============
46
20
 
47
- The repository uses two configuration files.
48
-
49
- * config/rake.rb
50
- * .chef/knife.rb
51
-
52
- The first, `config/rake.rb` configures the Rakefile in two sections.
53
-
54
- * Constants used in the `ssl_cert` task for creating the certificates.
55
- * Constants that set the directory locations used in various tasks.
56
-
57
- If you use the `ssl_cert` task, change the values in the `config/rake.rb` file appropriately. These values were also used in the `new_cookbook` task, but that task is replaced by the `knife cookbook create` command which can be configured below.
58
-
59
- The second config file, `.chef/knife.rb` is a repository specific configuration file for knife. If you're using the Opscode Platform, you can download one for your organization from the management console. If you're using the Open Source Chef Server, you can generate a new one with `knife configure`. For more information about configuring Knife, see the Knife documentation.
21
+ The config file, `.chef/knife.rb` is a repository specific configuration file for knife. If you're using the Chef Platform, you can download one for your organization from the management console. If you're using the Open Source Chef Server, you can generate a new one with `knife configure`. For more information about configuring Knife, see the Knife documentation.
60
22
 
61
23
  http://docs.chef.io/knife.html
62
24
 
@@ -5,8 +5,6 @@ app_dir = File.join(context.app_root, context.app_name)
5
5
  cookbooks_dir = context.cookbook_root
6
6
  cookbook_dir = File.join(cookbooks_dir, context.cookbook_name)
7
7
 
8
- cookbook_dir = File.join(cookbooks_dir, context.app_name)
9
-
10
8
  # app root dir
11
9
  directory app_dir
12
10
 
@@ -6,8 +6,8 @@ provisioner:
6
6
  name: chef_zero
7
7
 
8
8
  platforms:
9
- - name: ubuntu-12.04
10
- - name: centos-6.5
9
+ - name: ubuntu-14.04
10
+ - name: centos-7.1
11
11
 
12
12
  suites:
13
13
  - name: default
@@ -14,7 +14,7 @@ describe '<%= cookbook_name %>::<%= recipe_name %>' do
14
14
  end
15
15
 
16
16
  it 'converges successfully' do
17
- chef_run # This should not raise an error
17
+ expect { chef_run }.to_not raise_error
18
18
  end
19
19
  end
20
20
  end
@@ -16,5 +16,5 @@
16
16
  #
17
17
 
18
18
  module ChefDK
19
- VERSION = "0.6.2"
19
+ VERSION = "0.7.0"
20
20
  end
@@ -0,0 +1,52 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2015 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 'yaml'
20
+ require 'chef-dk/command/env'
21
+
22
+ describe ChefDK::Command::Env do
23
+ let(:ui) { TestHelpers::TestUI.new }
24
+ let(:command_instance) { ChefDK::Command::Env.new() }
25
+
26
+ let(:command_options) { [] }
27
+
28
+ let(:user_bin_dir) { File.expand_path(File.join(Gem.user_dir, 'bin')) }
29
+ let(:omnibus_embedded_bin_dir) { "/foo/embedded/bin" }
30
+ let(:omnibus_bin_dir) { "/foo/bin" }
31
+
32
+ before do
33
+ allow(command_instance).to receive(:omnibus_embedded_bin_dir).and_return(omnibus_embedded_bin_dir)
34
+ allow(command_instance).to receive(:omnibus_bin_dir).and_return(omnibus_bin_dir)
35
+ command_instance.ui = ui
36
+ end
37
+
38
+ def run_command
39
+ command_instance.run_with_default_options(command_options)
40
+ end
41
+
42
+ it "has a usage banner" do
43
+ expect(command_instance.banner).to eq("Usage: chef env")
44
+ end
45
+
46
+ describe "when running env command" do
47
+ it "should return valid yaml" do
48
+ run_command
49
+ expect{ YAML.load(ui.output) }.not_to raise_error
50
+ end
51
+ end
52
+ end
@@ -94,7 +94,7 @@ describe ChefDK::Command::Exec do
94
94
  expect(ENV).to receive(:[]=).with("GEM_PATH", expected_GEM_PATH)
95
95
 
96
96
  expect(command_instance).to receive(:exec).with(*command_options)
97
- expect{ run_command }.to raise_error # XXX: this isn't a test we just need to swallow the exception
97
+ expect{ run_command }.to raise_error(RuntimeError) # XXX: this isn't a test we just need to swallow the exception
98
98
  end
99
99
 
100
100
  ['-v', '--version', '-h', '--help'].each do |switch|
@@ -108,7 +108,7 @@ describe ChefDK::Command::Exec do
108
108
  expect(ENV).to receive(:[]=).with("GEM_PATH", expected_GEM_PATH)
109
109
 
110
110
  expect(command_instance).to receive(:exec).with(*command_options)
111
- expect{ run_command }.to raise_error # XXX: this isn't a test we just need to swallow the exception
111
+ expect{ run_command }.to raise_error(RuntimeError) # XXX: this isn't a test we just need to swallow the exception
112
112
  end
113
113
  end
114
114
  end