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.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/lib/chef-dk/builtin_commands.rb +7 -0
- data/lib/chef-dk/command/env.rb +90 -0
- data/lib/chef-dk/command/export.rb +22 -1
- data/lib/chef-dk/command/generate.rb +1 -1
- data/lib/chef-dk/command/provision.rb +43 -0
- data/lib/chef-dk/command/push_archive.rb +126 -0
- data/lib/chef-dk/command/show_policy.rb +166 -0
- data/lib/chef-dk/command/verify.rb +58 -1
- data/lib/chef-dk/cookbook_omnifetch.rb +3 -2
- data/lib/chef-dk/exceptions.rb +27 -0
- data/lib/chef-dk/helpers.rb +29 -0
- data/lib/chef-dk/policyfile/chef_repo_cookbook_source.rb +8 -0
- data/lib/chef-dk/policyfile/chef_server_cookbook_source.rb +8 -0
- data/lib/chef-dk/policyfile/community_cookbook_source.rb +8 -0
- data/lib/chef-dk/policyfile/cookbook_locks.rb +76 -6
- data/lib/chef-dk/policyfile/dsl.rb +10 -5
- data/lib/chef-dk/policyfile/lister.rb +230 -0
- data/lib/chef-dk/policyfile/null_cookbook_source.rb +8 -0
- data/lib/chef-dk/policyfile_compiler.rb +35 -2
- data/lib/chef-dk/policyfile_lock.rb +43 -0
- data/lib/chef-dk/policyfile_services/clean_policies.rb +94 -0
- data/lib/chef-dk/policyfile_services/export_repo.rb +103 -16
- data/lib/chef-dk/policyfile_services/push_archive.rb +173 -0
- data/lib/chef-dk/policyfile_services/show_policy.rb +237 -0
- data/lib/chef-dk/service_exceptions.rb +21 -0
- data/lib/chef-dk/skeletons/code_generator/files/default/chefignore +1 -0
- data/lib/chef-dk/skeletons/code_generator/files/default/repo/README.md +2 -40
- data/lib/chef-dk/skeletons/code_generator/recipes/app.rb +0 -2
- data/lib/chef-dk/skeletons/code_generator/templates/default/kitchen.yml.erb +2 -2
- data/lib/chef-dk/skeletons/code_generator/templates/default/recipe_spec.rb.erb +1 -1
- data/lib/chef-dk/version.rb +1 -1
- data/spec/unit/command/env_spec.rb +52 -0
- data/spec/unit/command/exec_spec.rb +2 -2
- data/spec/unit/command/export_spec.rb +13 -0
- data/spec/unit/command/provision_spec.rb +56 -0
- data/spec/unit/command/push_archive_spec.rb +153 -0
- data/spec/unit/command/show_policy_spec.rb +235 -0
- data/spec/unit/command/verify_spec.rb +1 -0
- data/spec/unit/helpers_spec.rb +68 -0
- data/spec/unit/policyfile/cookbook_locks_spec.rb +107 -1
- data/spec/unit/policyfile/lister_spec.rb +256 -0
- data/spec/unit/policyfile_demands_spec.rb +202 -10
- data/spec/unit/policyfile_evaluation_spec.rb +30 -4
- data/spec/unit/policyfile_lock_serialization_spec.rb +45 -0
- data/spec/unit/policyfile_services/clean_policies_spec.rb +236 -0
- data/spec/unit/policyfile_services/export_repo_spec.rb +99 -6
- data/spec/unit/policyfile_services/push_archive_spec.rb +345 -0
- data/spec/unit/policyfile_services/show_policy_spec.rb +839 -0
- 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
|
@@ -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
|
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
|
|
data/lib/chef-dk/version.rb
CHANGED
@@ -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
|