knife-depsolver 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +20 -6
- data/lib/chef/knife/depsolver.rb +120 -122
- data/lib/knife-depsolver/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b190d248ebfddfe1f8ba7c211cf779396daae1e
|
4
|
+
data.tar.gz: a1f372988af3570d26d80aaa5d459bc5193a95f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a8ef5c1d2e361d0bfc6e1ddaeeb1ffd3264c7c7589c4a40bdc941184f99e28a5bcd93023329815b311964a5caeeac021a6dfdf0581b582004f5f73b4791be86
|
7
|
+
data.tar.gz: 9368b84cf5d6de137e8ad00abe7943e6d1a7a174e9766eb8d09059cb685a48576ea0cec15f54d8815ae4e4185365baa582e3b18a5f757762edee3fd36db7a4ab
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 2.2.0 (2017-05-19)
|
4
|
+
|
5
|
+
* Rename --print-trimmed-universe to --filter-universe
|
6
|
+
* Remove --env-constraints-filter-universe option
|
7
|
+
* Don't filter cookbook universe by run list when run list is empty
|
8
|
+
* Add --version-pin-cookbooks option
|
9
|
+
|
3
10
|
## 2.1.0 (2017-05-15)
|
4
11
|
|
5
12
|
* Replace --print-constrained-cookbook-set with --print-trimmed-universe
|
data/README.md
CHANGED
@@ -75,6 +75,8 @@ In the first post he goes on to talk about the importance of troubleshooting the
|
|
75
75
|
|
76
76
|
knife-depsolver can provide many troubleshooting options by using the depsolver embedded in your workstation's Chef DK to make an identical calculation as the Chef Server.
|
77
77
|
|
78
|
+
#### Use the appropriate version of Chef DK
|
79
|
+
|
78
80
|
First, you need to make sure that your version of Chef DK is using the same version of the dep_selector gem as your version of Chef Server. If your Chef DK is using a different version of the dep_selector gem then knife-depsolver's calculations will not be identical to the Chef Server's calculations which will confuse troubleshooting efforts.
|
79
81
|
|
80
82
|
| dep_selector gem | Chef Server | Chef DK |
|
@@ -82,6 +84,8 @@ First, you need to make sure that your version of Chef DK is using the same vers
|
|
82
84
|
| 1.0.3 | <= 12.8.0 | <= 0.16.28 |
|
83
85
|
| 1.0.4 | >= 12.9.0 | >= 0.17.17 |
|
84
86
|
|
87
|
+
#### --capture
|
88
|
+
|
85
89
|
Once you are sure you are using the correct version of Chef DK and you have installed the knife-depsolver plugin you can use the "--capture" option which queries the Chef Server and creates a separate file on the workstation for each of the following pieces of information.
|
86
90
|
|
87
91
|
1. environment cookbook version constraints
|
@@ -98,7 +102,9 @@ OR
|
|
98
102
|
knife depsolver -E production 'role[base],cookbook-B,cookbook-A::foo@3.1.4,cookbook-R' --capture
|
99
103
|
```
|
100
104
|
|
101
|
-
|
105
|
+
#### --env-constraints, --universe and --expanded-run-list
|
106
|
+
|
107
|
+
Now use the "--env-constraints", "--universe" and "--expanded-run-list" options to provide the information required for local depsolver calculations.
|
102
108
|
|
103
109
|
For example:
|
104
110
|
|
@@ -106,7 +112,7 @@ For example:
|
|
106
112
|
knife depsolver --expanded-run-list expanded-run-list-2017-05-01-18.52.40-387d90499514747792a805213c30be13d830d31f.txt --universe my-org-universe-2017-05-01-18.52.40-1c8e59e23530b1e1a8e0b3b3cc5236a29c84e469.txt --env-constraints production-environment-2017-05-01-18.52.40-5f5843d819ecb0b174f308d76d4336bb7bbfacbf.txt
|
107
113
|
```
|
108
114
|
|
109
|
-
|
115
|
+
This makes it easy to modify the input files to see the impact on the depsolver.
|
110
116
|
|
111
117
|
#### --timeout
|
112
118
|
|
@@ -116,17 +122,25 @@ Sometimes it can help to give the depsolver more than the default five seconds t
|
|
116
122
|
knife depsolver --expanded-run-list expanded-run-list-2017-05-01-18.52.40-387d90499514747792a805213c30be13d830d31f.txt --universe my-org-universe-2017-05-01-18.52.40-1c8e59e23530b1e1a8e0b3b3cc5236a29c84e469.txt --env-constraints production-environment-2017-05-01-18.52.40-5f5843d819ecb0b174f308d76d4336bb7bbfacbf.txt --timeout 120
|
117
123
|
```
|
118
124
|
|
119
|
-
#### --
|
125
|
+
#### --filter-universe
|
120
126
|
|
121
|
-
|
127
|
+
Combine the --universe and the --filter-universe options with --env-constraints and/or --expanded-run-list options to filter the cookbook universe based on the environment cookbook version constraints and/or the expanded run list. This provides the ability to focus only on relevant information that would be sent to the depsolver without actually triggering the depsolver calculation. This is especially helpful when the depsolver isn't returning any results because it can't calculate a solution in a reasonable amount of time.
|
122
128
|
|
123
129
|
```
|
124
|
-
knife depsolver --expanded-run-list expanded-run-list-2017-05-01-18.52.40-387d90499514747792a805213c30be13d830d31f.txt --universe my-org-universe-2017-05-01-18.52.40-1c8e59e23530b1e1a8e0b3b3cc5236a29c84e469.txt --env-constraints production-environment-2017-05-01-18.52.40-5f5843d819ecb0b174f308d76d4336bb7bbfacbf.txt --
|
130
|
+
knife depsolver --expanded-run-list expanded-run-list-2017-05-01-18.52.40-387d90499514747792a805213c30be13d830d31f.txt --universe my-org-universe-2017-05-01-18.52.40-1c8e59e23530b1e1a8e0b3b3cc5236a29c84e469.txt --env-constraints production-environment-2017-05-01-18.52.40-5f5843d819ecb0b174f308d76d4336bb7bbfacbf.txt --filter-universe > filtered-universe.txt
|
125
131
|
```
|
126
132
|
|
127
133
|
Now you can review the output to see if you can find anything that could be causing problems for the depsolver. You can make changes to the input files to see the impact on the list of cookbooks that would be sent to the depsolver.
|
128
134
|
|
129
|
-
If necessary you could also use the
|
135
|
+
If necessary you could also use the results along with the --version-pin-cookbooks option to create an environment input file that pins a version for each cookbook. Then you can modify that set of version constraints and run the depsolver in an effort to get a solution in a reasonable amount of time or to isolate the problem.
|
136
|
+
|
137
|
+
#### --version-pin-cookbooks
|
138
|
+
|
139
|
+
The --version-pin-cookbooks option takes a filename as an argument. The file must be in the JSON format of a cookbook universe or filtered cookbook universe. The --version-pin-cookbooks option creates an environment JSON file with cookbook version constraints for that pin every cookbook to its latest version. This environment file can then be used with the --env-constraints option to provide a strictly constrained starting point when troubleshooting a depsolver issue.
|
140
|
+
|
141
|
+
```
|
142
|
+
knife depsolver --version-pin-cookbooks filtered-universe.txt > version-pinned-cookbooks.txt
|
143
|
+
```
|
130
144
|
|
131
145
|
#### /tmp/DepSelectorDebugOn
|
132
146
|
|
data/lib/chef/knife/depsolver.rb
CHANGED
@@ -45,59 +45,48 @@ class Chef
|
|
45
45
|
long: '--csv-universe-to-json FILENAME',
|
46
46
|
description: 'Convert a CSV cookbook universe, FILENAME, to JSON.'
|
47
47
|
|
48
|
-
option :
|
49
|
-
long: '--
|
50
|
-
description: 'Filter the cookbook universe
|
48
|
+
option :filter_universe,
|
49
|
+
long: '--filter-universe',
|
50
|
+
description: 'Filter the cookbook universe by environment cookbook version constraints and an optional run list.'
|
51
51
|
|
52
|
-
option :
|
53
|
-
long: '--
|
52
|
+
option :version_pin_cookbooks,
|
53
|
+
long: '--version-pin-cookbooks FILENAME',
|
54
54
|
description: 'Print the cookbooks and dependency data that would be sent to the depsolver.'
|
55
55
|
|
56
56
|
def run
|
57
57
|
begin
|
58
58
|
DepSelector::Debug.log.level = Logger::INFO if defined?(DepSelector::Debug)
|
59
|
-
use_local_depsolver = false
|
60
|
-
if
|
61
|
-
|
62
|
-
|
59
|
+
use_local_depsolver = config[:universe] ? true : false
|
60
|
+
if use_local_depsolver
|
61
|
+
unless name_args.empty?
|
62
|
+
puts "ERROR: Setting a run list on the command line is not compatible with the --universe option"
|
63
|
+
exit!
|
64
|
+
end
|
65
|
+
if config[:node]
|
66
|
+
puts "ERROR: The --node option is not compatible with the --universe option"
|
63
67
|
exit!
|
64
|
-
|
65
|
-
|
68
|
+
end
|
69
|
+
if config[:environment]
|
70
|
+
puts "ERROR: The --environment option is not compatible with the --universe option"
|
71
|
+
exit!
|
72
|
+
end
|
73
|
+
if config[:capture]
|
74
|
+
puts "ERROR: The --capture option is not compatible with the --universe option"
|
66
75
|
exit!
|
67
76
|
end
|
68
77
|
else
|
69
|
-
if config[:env_constraints] || config[:
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
if config[:environment]
|
81
|
-
puts "ERROR: The --environment option is not compatible with the --env-constraints, --universe or --expanded-run-list options"
|
82
|
-
exit!
|
83
|
-
end
|
84
|
-
if config[:capture]
|
85
|
-
puts "ERROR: The --capture option is not compatible with the --env-constraints, --universe or --expanded-run-list options"
|
86
|
-
exit!
|
87
|
-
end
|
88
|
-
else
|
89
|
-
puts "ERROR: The --env-constraints, --universe and --expanded-run-list options must be used together to use the local depsolver"
|
90
|
-
exit!
|
91
|
-
end
|
78
|
+
if (config[:env_constraints] || config[:expanded_run_list])
|
79
|
+
puts "ERROR: The --env-constraints and --expanded-run-list options require the --universe option to be set"
|
80
|
+
exit!
|
81
|
+
end
|
82
|
+
if config[:timeout]
|
83
|
+
msg("ERROR: The --timeout option requires the --env-constraints, --universe and --expanded-run-list options to be set")
|
84
|
+
exit!
|
85
|
+
end
|
86
|
+
if config[:filter_universe]
|
87
|
+
msg("ERROR: The --filter-universe option requires the --universe option and optionally the --env-constraints and/or --expanded-run-list options")
|
88
|
+
exit!
|
92
89
|
end
|
93
|
-
end
|
94
|
-
if config[:timeout] && !use_local_depsolver
|
95
|
-
msg("ERROR: The --timeout option requires the --env-constraints, --universe and --expanded-run-list options to be set")
|
96
|
-
exit!
|
97
|
-
end
|
98
|
-
if config[:print_constrained_cookbook_set] && !use_local_depsolver
|
99
|
-
msg("ERROR: The --print-constrained-cookbook-set option requires the --env-constraints, --universe and --expanded-run-list options to be set")
|
100
|
-
exit!
|
101
90
|
end
|
102
91
|
|
103
92
|
timeout = (config[:timeout].to_f * 1000).to_i if config[:timeout]
|
@@ -121,7 +110,22 @@ class Chef
|
|
121
110
|
exit!
|
122
111
|
end
|
123
112
|
|
124
|
-
if config[:
|
113
|
+
if config[:version_pin_cookbooks]
|
114
|
+
unless File.file?(config[:version_pin_cookbooks])
|
115
|
+
msg("ERROR: #{config[:version_pin_cookbooks]} does not exist or is not a file.")
|
116
|
+
exit!
|
117
|
+
end
|
118
|
+
cookbooks = JSON.parse(IO.read(config[:version_pin_cookbooks]))
|
119
|
+
version_pinned_cookbooks = Hash.new
|
120
|
+
cookbooks.each do |cookbook_name, versions|
|
121
|
+
max_version = versions.keys.max_by {|v| DepSelector::Version.new(v) }
|
122
|
+
version_pinned_cookbooks[cookbook_name] = "= #{max_version}" if max_version
|
123
|
+
end
|
124
|
+
puts JSON.pretty_generate({name: "version-pinned-cookbooks", cookbook_versions: version_pinned_cookbooks})
|
125
|
+
exit!
|
126
|
+
end
|
127
|
+
|
128
|
+
if config[:node]
|
125
129
|
node = Chef::Node.load(config[:node])
|
126
130
|
else
|
127
131
|
node = Chef::Node.new
|
@@ -152,7 +156,11 @@ class Chef
|
|
152
156
|
end
|
153
157
|
end
|
154
158
|
|
159
|
+
# node.chef_environment must be set before expanding the run list in case the run list includes
|
160
|
+
# roles with environment specific run lists
|
155
161
|
node.chef_environment = config[:environment] if config[:environment]
|
162
|
+
run_list_expansion = node.run_list.expand(node.chef_environment, 'server')
|
163
|
+
expanded_run_list_with_versions = run_list_expansion.recipes.with_version_constraints_strings
|
156
164
|
|
157
165
|
if config[:capture]
|
158
166
|
if node.chef_environment == '_default'
|
@@ -179,86 +187,18 @@ class Chef
|
|
179
187
|
puts "WARNING: Try capturing the cookbook universe using the SQL query found in the knife-depsolver README."
|
180
188
|
puts "WARNING: Then convert the results using knife-depsolver's --csv-universe-to-json option"
|
181
189
|
end
|
190
|
+
exit
|
182
191
|
end
|
183
192
|
|
184
|
-
if config[:
|
185
|
-
|
186
|
-
|
187
|
-
exit!
|
188
|
-
end
|
189
|
-
env = JSON.parse(IO.read(config[:env_constraints]))
|
190
|
-
if env['name'].to_s.empty?
|
191
|
-
msg("ERROR: #{config[:env_constraints]} does not contain an environment name.")
|
192
|
-
exit!
|
193
|
-
else
|
194
|
-
node.chef_environment = env['name']
|
195
|
-
end
|
196
|
-
if !env['cookbook_versions'].is_a?(Hash)
|
197
|
-
msg("ERROR: #{config[:env_constraints]} does not contain a Hash of cookbook version constraints.")
|
198
|
-
exit!
|
199
|
-
else
|
200
|
-
environment_cookbook_versions = env['cookbook_versions']
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
if config[:universe]
|
205
|
-
unless File.file?(config[:universe])
|
206
|
-
msg("ERROR: #{config[:universe]} does not exist or is not a file.")
|
207
|
-
exit!
|
208
|
-
end
|
209
|
-
universe = JSON.parse(IO.read(config[:universe]))
|
210
|
-
if !universe.is_a?(Hash)
|
211
|
-
msg("ERROR: #{config[:universe]} does not contain a cookbook universe Hash.")
|
212
|
-
exit!
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
if config[:env_constraints_filter_universe]
|
217
|
-
env_constraints = environment_cookbook_versions.each_with_object({}) do |env_constraint, memo|
|
218
|
-
name, constraint = env_constraint
|
219
|
-
constraint, version = constraint.split
|
220
|
-
memo[name] = DepSelector::VersionConstraint.new(constraint_to_str(constraint, version))
|
221
|
-
end
|
222
|
-
universe.each do |name, versions|
|
223
|
-
versions.delete_if {|version, v| !env_constraints[name].include?(version)} if env_constraints[name]
|
224
|
-
end
|
225
|
-
filtered_universe_json = JSON.pretty_generate(universe)
|
226
|
-
filtered_universe_filename = "filtered-universe-#{Time.now.strftime("%Y-%m-%d-%H.%M.%S")}-#{Digest::SHA1.hexdigest(filtered_universe_json)}.txt"
|
227
|
-
IO.write(filtered_universe_filename, filtered_universe_json)
|
228
|
-
puts "Filtered cookbook universe saved to #{filtered_universe_filename}"
|
193
|
+
if config[:filter_universe]
|
194
|
+
data = get_depsolver_data(node, expanded_run_list_with_versions, timeout)
|
195
|
+
puts JSON.pretty_generate(filter_universe(data))
|
229
196
|
exit!
|
230
197
|
end
|
231
198
|
|
232
|
-
run_list_expansion = node.run_list.expand(node.chef_environment, 'server')
|
233
|
-
expanded_run_list_with_versions = run_list_expansion.recipes.with_version_constraints_strings
|
234
|
-
|
235
|
-
exit if config[:capture]
|
236
|
-
|
237
199
|
depsolver_results = Hash.new
|
238
200
|
if use_local_depsolver
|
239
|
-
|
240
|
-
[ckbk_name, ckbk_constraint.split.reverse].flatten
|
241
|
-
end
|
242
|
-
|
243
|
-
all_versions = universe.map do |ckbk_name, ckbk_metadata|
|
244
|
-
ckbk_versions = ckbk_metadata.map do |version, version_metadata|
|
245
|
-
[version, version_metadata['dependencies'].map { |dep_ckbk_name, dep_ckbk_constraint| [dep_ckbk_name, dep_ckbk_constraint.split.reverse].flatten }]
|
246
|
-
end
|
247
|
-
[ckbk_name, ckbk_versions]
|
248
|
-
end
|
249
|
-
|
250
|
-
expanded_run_list_with_split_versions = expanded_run_list_with_versions.map do |run_list_item|
|
251
|
-
name, version = run_list_item.split('@')
|
252
|
-
name.sub!(/::.*/, '')
|
253
|
-
version ? [name, version] : name
|
254
|
-
end
|
255
|
-
|
256
|
-
data = {environment_constraints: env_ckbk_constraints, all_versions: all_versions, run_list: expanded_run_list_with_split_versions, timeout_ms: timeout}
|
257
|
-
|
258
|
-
if config[:print_trimmed_universe]
|
259
|
-
puts JSON.pretty_generate(get_trimmed_universe(data))
|
260
|
-
exit!
|
261
|
-
end
|
201
|
+
data = get_depsolver_data(node, expanded_run_list_with_versions, timeout)
|
262
202
|
|
263
203
|
depsolver_start_time = Time.now
|
264
204
|
|
@@ -338,7 +278,61 @@ class Chef
|
|
338
278
|
end
|
339
279
|
end
|
340
280
|
|
341
|
-
def
|
281
|
+
def get_depsolver_data(node, expanded_run_list_with_versions, timeout)
|
282
|
+
if config[:env_constraints]
|
283
|
+
unless File.file?(config[:env_constraints])
|
284
|
+
msg("ERROR: #{config[:env_constraints]} does not exist or is not a file.")
|
285
|
+
exit!
|
286
|
+
end
|
287
|
+
env = JSON.parse(IO.read(config[:env_constraints]))
|
288
|
+
if env['name'].to_s.empty?
|
289
|
+
msg("ERROR: #{config[:env_constraints]} does not contain an environment name.")
|
290
|
+
exit!
|
291
|
+
else
|
292
|
+
node.chef_environment = env['name']
|
293
|
+
end
|
294
|
+
if !env['cookbook_versions'].is_a?(Hash)
|
295
|
+
msg("ERROR: #{config[:env_constraints]} does not contain a Hash of cookbook version constraints.")
|
296
|
+
exit!
|
297
|
+
else
|
298
|
+
environment_cookbook_versions = env['cookbook_versions']
|
299
|
+
end
|
300
|
+
else
|
301
|
+
environment_cookbook_versions = Hash.new
|
302
|
+
end
|
303
|
+
|
304
|
+
env_ckbk_constraints = environment_cookbook_versions.map do |ckbk_name, ckbk_constraint|
|
305
|
+
[ckbk_name, ckbk_constraint.split.reverse].flatten
|
306
|
+
end
|
307
|
+
|
308
|
+
unless File.file?(config[:universe])
|
309
|
+
msg("ERROR: #{config[:universe]} does not exist or is not a file.")
|
310
|
+
exit!
|
311
|
+
end
|
312
|
+
universe = JSON.parse(IO.read(config[:universe]))
|
313
|
+
if !universe.is_a?(Hash)
|
314
|
+
msg("ERROR: #{config[:universe]} does not contain a cookbook universe Hash.")
|
315
|
+
exit!
|
316
|
+
end
|
317
|
+
|
318
|
+
all_versions = universe.map do |ckbk_name, ckbk_metadata|
|
319
|
+
ckbk_versions = ckbk_metadata.map do |version, version_metadata|
|
320
|
+
[version, version_metadata['dependencies'].map { |dep_ckbk_name, dep_ckbk_constraint| [dep_ckbk_name, dep_ckbk_constraint.split.reverse].flatten }]
|
321
|
+
end
|
322
|
+
[ckbk_name, ckbk_versions]
|
323
|
+
end
|
324
|
+
|
325
|
+
expanded_run_list_with_split_versions = expanded_run_list_with_versions.map do |run_list_item|
|
326
|
+
name, version = run_list_item.split('@')
|
327
|
+
name.sub!(/::.*/, '')
|
328
|
+
version ? [name, version] : name
|
329
|
+
end
|
330
|
+
|
331
|
+
depsolver_data = {environment_constraints: env_ckbk_constraints, all_versions: all_versions, run_list: expanded_run_list_with_split_versions, timeout_ms: timeout}
|
332
|
+
depsolver_data
|
333
|
+
end
|
334
|
+
|
335
|
+
def filter_universe(data)
|
342
336
|
# create dependency graph from cookbooks
|
343
337
|
graph = DepSelector::DependencyGraph.new
|
344
338
|
|
@@ -384,19 +378,23 @@ class Chef
|
|
384
378
|
timeout_ms = data[:timeout_ms]
|
385
379
|
selector = DepSelector::Selector.new(graph, (timeout_ms / 1000.0))
|
386
380
|
|
387
|
-
|
388
|
-
|
381
|
+
if run_list.empty?
|
382
|
+
constrained_cookbook_set = selector.dep_graph.packages.values
|
383
|
+
else
|
384
|
+
constrained_cookbook_set = selector.send(:trim_unreachable_packages, selector.dep_graph, run_list)
|
385
|
+
end
|
386
|
+
filtered_universe = Hash.new { |h,k| h[k] = Hash.new { |h,k| h[k] = Hash.new { |h,k| h[k] = Hash.new } } }
|
389
387
|
constrained_cookbook_set.each do |ckbk|
|
390
388
|
ckbk.versions.each do |ckbk_version|
|
391
|
-
|
389
|
+
filtered_universe[ckbk.name][ckbk_version.version]["dependencies"] = Hash.new
|
392
390
|
ckbk_version.dependencies.each do |ckbk_version_dep|
|
393
391
|
constraint = ckbk_version_dep.constraint
|
394
392
|
constraint_version = constraint.missing_patch_level ? "#{constraint.version.major}.#{constraint.version.minor}" : "#{constraint.version}"
|
395
|
-
|
393
|
+
filtered_universe[ckbk.name][ckbk_version.version]["dependencies"][ckbk_version_dep.package.name] = "#{constraint.op} #{constraint_version}"
|
396
394
|
end
|
397
395
|
end
|
398
396
|
end
|
399
|
-
|
397
|
+
filtered_universe
|
400
398
|
end
|
401
399
|
end
|
402
400
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife-depsolver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremiah Snapp
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Knife plugin that uses Chef Server to calculate cookbook dependencies
|
14
14
|
for a given run_list.
|