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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 20ead315f5ba6d98327f23b83076eb7204362143
4
- data.tar.gz: 8431be0109945a59cba7b7e6498a240ff611ec12
3
+ metadata.gz: 0b190d248ebfddfe1f8ba7c211cf779396daae1e
4
+ data.tar.gz: a1f372988af3570d26d80aaa5d459bc5193a95f5
5
5
  SHA512:
6
- metadata.gz: d292509903debe72d884dc499e202782a01bcf51c8251d55542bc4460ddc54e9a4bc51e0873c78272698ed7206cc9b033d9fb399edbe69480e6148e58befbccf
7
- data.tar.gz: 7378fc8d7d0b78722f634b670affd99f918c478f964a1f0b4edb51501882168a3da4b7bbb40bc8aff74063c61efba237b4c8b6d056fce5795b7b107995cd694f
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
- Now use the "--env-constraints", "universe" and "expanded-run-list" options to provide all the information required for local depsolver calculations.
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
- Now it is easy to modify the environment cookbook version constraints or the cookbook universe input files to see the impact on the depsolver.
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
- #### --print-trimmed-universe
125
+ #### --filter-universe
120
126
 
121
- Sometimes you want to only see the list of cookbooks, and their cookbook dependency version constraints, that ultimately 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. This can be done by using the `--print-trimmed-universe` option.
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 --print-trimmed-universe
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 list of cookbooks as a starting point for setting version constraints in the environment input file. 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.
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
 
@@ -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 :env_constraints_filter_universe,
49
- long: '--env-constraints-filter-universe',
50
- description: 'Filter the cookbook universe using the environment cookbook version constraints.'
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 :print_trimmed_universe,
53
- long: '--print-trimmed-universe',
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 config[:env_constraints_filter_universe]
61
- if config[:node] || config[:environment] || config[:timeout] || config[:capture] || config[:expanded_run_list] || config[:csv_universe_to_json]
62
- msg("ERROR: The --env-constraints-filter-universe option is only compatible with the --env-constraints and --universe options")
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
- elsif !(config[:env_constraints] && config[:universe])
65
- msg("ERROR: The --env-constraints-filter-universe option requires the --env-constraints and --universe options to be set")
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[:universe] || config[:expanded_run_list]
70
- if config[:env_constraints] && config[:universe] && config[:expanded_run_list]
71
- use_local_depsolver = true
72
- unless name_args.empty?
73
- puts "ERROR: Setting a run list on the command line is not compatible with the --env-constraints, --universe or --expanded-run-list options"
74
- exit!
75
- end
76
- if config[:node]
77
- puts "ERROR: The --node option is not compatible with the --env-constraints, --universe or --expanded-run-list options"
78
- exit!
79
- end
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[:node] && !(config[:env_constraints_filter_universe] && config[:env_constraints])
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[:env_constraints]
185
- unless File.file?(config[:env_constraints])
186
- msg("ERROR: #{config[:env_constraints]} does not exist or is not a file.")
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
- env_ckbk_constraints = environment_cookbook_versions.map do |ckbk_name, ckbk_constraint|
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 get_trimmed_universe(data)
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
- constrained_cookbook_set = selector.send(:trim_unreachable_packages, selector.dep_graph, run_list)
388
- trimmed_universe = Hash.new { |h,k| h[k] = Hash.new { |h,k| h[k] = Hash.new { |h,k| h[k] = Hash.new } } }
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
- trimmed_universe[ckbk.name][ckbk_version.version]["dependencies"] = Hash.new
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
- trimmed_universe[ckbk.name][ckbk_version.version]["dependencies"][ckbk_version_dep.package.name] = "#{constraint.op} #{constraint_version}"
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
- trimmed_universe
397
+ filtered_universe
400
398
  end
401
399
  end
402
400
  end
@@ -1,3 +1,3 @@
1
1
  module KnifeDepsolver
2
- VERSION = "2.1.0"
2
+ VERSION = "2.2.0"
3
3
  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.1.0
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-15 00:00:00.000000000 Z
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.