knife-tidy 2.0.9 → 2.1.2

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
  SHA256:
3
- metadata.gz: e4a97cf801ae4409e19040e77f743f2169d1e068401baae60529ad6d89f40798
4
- data.tar.gz: 84a994d03f9aa44208af4e227a97bc7beb230bb206421b02da166e23e87a479e
3
+ metadata.gz: ebbadbfe49e6402c189f63e8e0290eeb93d409f89f4220ef9ad6bdc96b0b455f
4
+ data.tar.gz: ee7f3392eac804aeec3490c33c1e02d9d22d1bd038f3a1eb8222fd9d9c660dd9
5
5
  SHA512:
6
- metadata.gz: 98873e41d798dbcb80ce8e1640e170edc635772c010f85c6cf736bcdcf483271c42c6afde97f1db9e573cb44a2c72d719546493f74cfd3e9680dd332862fedfd
7
- data.tar.gz: 3c179e8babe63a01eed66aa5a88c062a4540a7d885d1b978dcfdc60051f1e394925f8bf19c57ab39ccade673a7b323c558158644e68c136b696353cc1335cda5
6
+ metadata.gz: e78b266e0482121cd3d551a9d683cd79b85aae16bb31d53260c2c73a7ceae1080052cd582957b55a23099c7799ed8312e0a5fcde1b920640497af04872894ab7
7
+ data.tar.gz: b1e97749b9ed73fe512b76a45291541b070eb730ded2f86dc4de1f355258e319017338e183c53a0dd2b4671f98a513ba4a5ca69053e6dc834359f396e15257ee
@@ -0,0 +1,10 @@
1
+ {
2
+ "your-problem-descriptor":{
3
+ "organizations/*/cookbooks/*/metadata.rb":[
4
+ {
5
+ "pattern":"^version .*GO_PIPELINE_LABEL",
6
+ "replace":"version !COOKBOOK_VERSION!"
7
+ }
8
+ ]
9
+ }
10
+ }
@@ -4,15 +4,15 @@ class Chef
4
4
  class Knife
5
5
  class TidyBackupClean < Knife
6
6
  deps do
7
- require "chef/cookbook_loader"
7
+ require "chef/cookbook/cookbook_version_loader"
8
8
  require "chef/cookbook/metadata"
9
9
  require "chef/role"
10
10
  require "chef/run_list"
11
11
  require_relative "../tidy_substitutions"
12
12
  require_relative "../tidy_acls"
13
- require "ffi_yajl"
14
- require "fileutils"
15
- require "securerandom"
13
+ require "ffi_yajl" unless defined?(FFI_Yajl)
14
+ require "fileutils" unless defined?(FileUtils)
15
+ require "securerandom" unless defined?(SecureRandom)
16
16
  end
17
17
 
18
18
  banner "knife tidy backup clean (options)"
@@ -25,7 +25,7 @@ class Chef
25
25
 
26
26
  option :gsub_file,
27
27
  long: "--gsub-file path/to/gsub/file",
28
- description: "The path to the file used for substitutions. If non-existant, a boiler plate one will be created."
28
+ description: "The path to the file used for substitutions. If non-existent, a boiler plate one will be created."
29
29
 
30
30
  option :gen_gsub,
31
31
  long: "--gen-gsub",
@@ -75,7 +75,7 @@ class Chef
75
75
  tidy.global_user_names.each do |user|
76
76
  email = ""
77
77
  ui.stdout.puts "INFO: Validating #{user}"
78
- the_user = FFI_Yajl::Parser.parse(::File.read(::File.join(tidy.users_path, "#{user}.json")), symbolize_names: false)
78
+ the_user = tidy.json_file_to_hash(File.join(tidy.users_path, "#{user}.json"), symbolize_names: false)
79
79
  if the_user.key?("email") && the_user["email"].match(/\A[^@\s]+@[^@\s]+\z/)
80
80
  if emails_seen.include?(the_user["email"])
81
81
  ui.stdout.puts "REPAIRING: Already saw #{user}'s email, creating a unique one."
@@ -147,7 +147,7 @@ class Chef
147
147
  add_cookbook_name_to_metadata(cookbook_name, rb_path) if lines.empty?
148
148
  else
149
149
  if ::File.exist?(json_path)
150
- metadata = FFI_Yajl::Parser.parse(::File.read(json_path), symbolize_names: false)
150
+ metadata = tidy.json_file_to_hash(json_path, symbolize_names: false)
151
151
  if metadata["name"] != cookbook_name
152
152
  metadata["name"] = cookbook_name
153
153
  ui.stdout.puts "REPAIRING: Correcting `name` in #{json_path}`"
@@ -161,26 +161,24 @@ class Chef
161
161
  end
162
162
 
163
163
  def load_cookbooks(org)
164
- cl = Chef::CookbookLoader.new(tidy.cookbooks_path(org))
165
- for_each_cookbook_basename(org) do |cookbook|
164
+ for_each_cookbook_path(org) do |cookbook|
165
+ cl = Chef::Cookbook::CookbookVersionLoader.new(cookbook)
166
166
  ui.stdout.puts "INFO: Loading #{cookbook}"
167
- ret = cl.load_cookbook(cookbook)
167
+ ret = cl.load!
168
168
  if ret.nil?
169
169
  action_needed("ACTION NEEDED: Something's wrong with the #{cookbook} cookbook in org #{org} - cannot load it! Moving to cookbooks.broken folder.")
170
- broken_cookooks_add(org, cookbook)
170
+ broken_cookbooks_add(org, cookbook)
171
171
  end
172
172
  end
173
- rescue LoadError => e
173
+ rescue LoadError, Exceptions::MetadataNotValid => e
174
174
  ui.error e
175
175
  exit 1
176
176
  end
177
177
 
178
- def broken_cookooks_add(org, cookbook)
178
+ def broken_cookbooks_add(org, cookbook_path)
179
179
  broken_path = ::File.join(tidy.org_path(org), "cookbooks.broken")
180
180
  FileUtils.mkdir(broken_path) unless ::File.directory?(broken_path)
181
- Dir[::File.join(tidy.cookbooks_path(org), "#{cookbook}*")].each do |cb|
182
- FileUtils.mv(cb, broken_path, verbose: true, force: true)
183
- end
181
+ FileUtils.mv(cookbook_path, broken_path, verbose: true, force: true)
184
182
  end
185
183
 
186
184
  def generate_new_metadata(org)
@@ -229,7 +227,7 @@ class Chef
229
227
 
230
228
  def fix_metadata_fields(cookbook_path)
231
229
  json_path = ::File.join(cookbook_path, "metadata.json")
232
- metadata = FFI_Yajl::Parser.parse(::File.read(json_path), symbolize_names: false)
230
+ metadata = tidy.json_file_to_hash(json_path, symbolize_names: false)
233
231
  md = metadata.dup
234
232
  metadata.each_pair do |key, value|
235
233
  if value.nil?
@@ -299,7 +297,7 @@ class Chef
299
297
 
300
298
  def substitutions_file
301
299
  sub_file_path = ::File.expand_path(config[:gsub_file])
302
- ui.error "Subtitutions file #{sub_file_path} does not exist!" unless ::File.exist?(sub_file_path)
300
+ ui.error "Substitutions file #{sub_file_path} does not exist!" unless ::File.exist?(sub_file_path)
303
301
  @substitutions_file ||= sub_file_path
304
302
  end
305
303
 
@@ -351,7 +349,7 @@ class Chef
351
349
  end
352
350
 
353
351
  def repair_role_run_lists(role_path)
354
- the_role = FFI_Yajl::Parser.parse(::File.read(role_path), symbolize_names: false)
352
+ the_role = tidy.json_file_to_hash(role_path, symbolize_names: false)
355
353
  new_role = the_role.clone
356
354
  rl = Chef::RunList.new
357
355
  new_role["run_list"] = []
@@ -384,7 +382,7 @@ class Chef
384
382
  for_each_role(org) do |role_path|
385
383
  ui.stdout.puts "INFO: Validating Role at #{role_path}"
386
384
  begin
387
- Chef::Role.from_hash(FFI_Yajl::Parser.parse(::File.read(role_path), symbolize_names: false))
385
+ Chef::Role.from_hash(tidy.json_file_to_hash(role_path, symbolize_names: false))
388
386
  rescue ArgumentError
389
387
  repair_role_run_lists(role_path)
390
388
  end
@@ -394,21 +392,22 @@ class Chef
394
392
  def validate_clients_group(org)
395
393
  ui.stdout.puts "INFO: validating all clients for org #{org} exist in clients group"
396
394
  clients_group_path = ::File.join(tidy.groups_path(org), "clients.json")
397
- existing_group_data = FFI_Yajl::Parser.parse(::File.read(clients_group_path), symbolize_names: false)
395
+ existing_group_data = tidy.json_file_to_hash(clients_group_path, symbolize_names: false)
398
396
  existing_group_data["clients"] = [] unless existing_group_data.key?("clients")
399
397
  if existing_group_data["clients"].length != tidy.client_names(org).length
400
398
  ui.stdout.puts "REPAIRING: Adding #{(existing_group_data["clients"].length - tidy.client_names(org).length).abs} missing clients into #{org}'s client group file #{clients_group_path}"
401
399
  existing_group_data["clients"] = (existing_group_data["clients"] + tidy.client_names(org)).uniq
402
- ::File.open(clients_group_path, "w") do |f|
403
- f.write(Chef::JSONCompat.to_json_pretty(existing_group_data))
404
- end
400
+ end
401
+ existing_group_data["clients"] = existing_group_data["clients"].sort
402
+ ::File.open(clients_group_path, "w") do |f|
403
+ f.write(Chef::JSONCompat.to_json_pretty(existing_group_data))
405
404
  end
406
405
  end
407
406
 
408
407
  def validate_invitations(org)
409
408
  invite_file = tidy.invitations_path(org)
410
409
  ui.stdout.puts "INFO: validating org #{org} invites in #{invite_file}"
411
- invitations = FFI_Yajl::Parser.parse(::File.read(invite_file), symbolize_names: false)
410
+ invitations = tidy.json_file_to_hash(invite_file, symbolize_names: false)
412
411
  invitations_new = []
413
412
  invitations.each do |invite|
414
413
  if invite["username"].nil?
@@ -4,7 +4,7 @@ class Chef
4
4
  class Knife
5
5
  class TidyNotify < Knife
6
6
  deps do
7
- require "ffi_yajl"
7
+ require "ffi_yajl" unless defined?(FFI_Yajl)
8
8
  require "net/smtp"
9
9
  end
10
10
 
@@ -14,39 +14,39 @@ class Chef
14
14
  short: "-s SERVER_NAME",
15
15
  long: "--smtp_server SERVER_NAME",
16
16
  default: "localhost",
17
- description: "SMTP Server to be used for emailling reports to organization admins (defaults to localhost)"
17
+ description: "SMTP Server to be used for emailing reports to organization admins (defaults to localhost)"
18
18
 
19
19
  option :smtp_port,
20
20
  short: "-p SMTP_PORT",
21
21
  long: "--smtp_port SMTP_PORT",
22
22
  default: 25,
23
- description: "SMTP port to be used for emailling reports to organization admins (defaults to 25)"
23
+ description: "SMTP port to be used for emailing reports to organization admins (defaults to 25)"
24
24
 
25
25
  option :smtp_helo,
26
26
  short: "-h SMTP_HELO",
27
27
  long: "--smtp_helo SMTP_HELO",
28
28
  default: "localhost",
29
- description: "SMTP HELO to be used for emailling reports to organization admins (defaults to localhost)"
29
+ description: "SMTP HELO to be used for emailing reports to organization admins (defaults to localhost)"
30
30
 
31
31
  option :smtp_username,
32
32
  short: "-u SMTP_USERNAME",
33
33
  long: "--smtp_username SMTP_USERNAME",
34
- description: "SMTP Username to be used for emailling reports to organization admins"
34
+ description: "SMTP Username to be used for emailing reports to organization admins"
35
35
 
36
36
  option :smtp_password,
37
37
  long: "--smtp_password SMTP_PASSWORD",
38
- description: "SMTP Password to be used for emailling reports to organization admins"
38
+ description: "SMTP Password to be used for emailing reports to organization admins"
39
39
 
40
40
  option :smtp_from,
41
41
  long: "--smtp_from SMTP_FROM",
42
- description: "SMTP From address to be used for emailling reports to organization admins"
42
+ description: "SMTP From address to be used for emailing reports to organization admins"
43
43
 
44
44
  option :smtp_use_tls,
45
45
  long: "--smtp_use_tls",
46
46
  short: "-t",
47
47
  default: false,
48
48
  boolean: true | false,
49
- description: "Whether TLS should be used for emailling reports to organization admins (defaults to false if omitted)"
49
+ description: "Whether TLS should be used for emailing reports to organization admins (defaults to false if omitted)"
50
50
 
51
51
  include Knife::TidyBase
52
52
 
@@ -88,7 +88,7 @@ class Chef
88
88
  file_name = "#{reports_dir}/#{org}#{report}"
89
89
  ui.info(" Parsing file #{file_name}")
90
90
  json_string = File.read(file_name)
91
- reports[org][report] = FFI_Yajl::Parser.parse(json_string)
91
+ reports[org][report] = tidy.json_file_to_hash(json_string, symbolize_names: false)
92
92
  rescue Errno::ENOENT
93
93
  ui.info(" Skipping file #{file_name} - not found for organization #{org}")
94
94
  reports[org][report] = {}
@@ -6,7 +6,7 @@ class Chef
6
6
  include Knife::TidyBase
7
7
 
8
8
  deps do
9
- require "ffi_yajl"
9
+ require "ffi_yajl" unless defined?(FFI_Yajl)
10
10
  require "chef/util/threaded_job_queue"
11
11
  end
12
12
 
@@ -91,7 +91,7 @@ class Chef
91
91
  return unless ::File.exist?(unused_cookbooks_file)
92
92
 
93
93
  ui.stdout.puts "INFO: Cleaning cookbooks for Org: #{org}, using #{unused_cookbooks_file}"
94
- unused_cookbooks = FFI_Yajl::Parser.parse(::File.read(unused_cookbooks_file), symbolize_names: true)
94
+ unused_cookbooks = tidy.json_file_to_hash(unused_cookbooks_file, symbolize_names: true)
95
95
  unused_cookbooks.keys.each do |cookbook|
96
96
  versions = unused_cookbooks[cookbook]
97
97
  versions.each do |version|
@@ -118,7 +118,7 @@ class Chef
118
118
  return unless ::File.exist?(stale_nodes_file)
119
119
 
120
120
  ui.stdout.puts "INFO: Cleaning stale nodes for Org: #{org}, using #{stale_nodes_file}"
121
- stale_nodes = FFI_Yajl::Parser.parse(::File.read(stale_nodes_file), symbolize_names: true)
121
+ stale_nodes = tidy.json_file_to_hash(stale_nodes_file, symbolize_names: true)
122
122
  stale_nodes[:list].each do |node|
123
123
  queue << -> { delete_node_job(org, node) }
124
124
  end
@@ -7,7 +7,7 @@ class Chef
7
7
  include Knife::TidyBase
8
8
 
9
9
  deps do
10
- require "ffi_yajl"
10
+ require "ffi_yajl" unless defined?(FFI_Yajl)
11
11
  end
12
12
 
13
13
  banner "knife tidy server report (options)"
@@ -17,6 +17,11 @@ class Chef
17
17
  default: 30,
18
18
  description: "Maximum number of days since last checkin before node is considered stale (default: 30)"
19
19
 
20
+ option :keep_versions,
21
+ long: "--keep-versions MIN",
22
+ default: 0,
23
+ description: "Keep a minimum of this many versions of each cookbook (default: 0)"
24
+
20
25
  def run
21
26
  ensure_reports_dir!
22
27
  FileUtils.rm_f(server_warnings_file_path)
@@ -32,6 +37,7 @@ class Chef
32
37
 
33
38
  stale_orgs = []
34
39
  node_threshold = config[:node_threshold].to_i
40
+ keep_versions = config[:keep_versions].to_i
35
41
 
36
42
  orgs.each do |org|
37
43
  pre_12_3_nodes = []
@@ -76,6 +82,9 @@ class Chef
76
82
  end
77
83
  end
78
84
 
85
+ used_cookbooks = keep_cookbook_versions(cb_list, keep_versions)
86
+
87
+ Chef::Log.debug("Used cookbook list before checking environments: #{used_cookbooks}")
79
88
  pins = environment_constraints(org)
80
89
  used_cookbooks = check_environment_pins(used_cookbooks, pins, cb_list)
81
90
 
@@ -99,7 +108,7 @@ class Chef
99
108
  action_needed(pre_12_3_message, server_warnings_file_path)
100
109
  end
101
110
  if unconverged_recent_nodes.length > 0
102
- unconverged_recent_message = "#{unconverged_recent_nodes.length} nodes have been created in the last hour that have yet to converge in organization #{org}. These nodes WILL NOT be factored in the stale cookbook verisons report. Continuing with the server cleanup will delete cookbooks in-use by these nodes."
111
+ unconverged_recent_message = "#{unconverged_recent_nodes.length} nodes have been created in the last hour that have yet to converge in organization #{org}. These nodes WILL NOT be factored in the stale cookbook versions report. Continuing with the server cleanup will delete cookbooks in-use by these nodes."
103
112
  ui.warn(unconverged_recent_message)
104
113
  action_needed(unconverged_recent_message, server_warnings_file_path)
105
114
  end
@@ -153,6 +162,15 @@ class Chef
153
162
  cb_list
154
163
  end
155
164
 
165
+ def keep_cookbook_versions(cb_list, min)
166
+ retain = {}
167
+ cb_list.each do |name, versions|
168
+ keep = versions.sort { |a, b| Gem::Version.new(a) <=> Gem::Version.new(b) }.last(min)
169
+ retain[name] = keep
170
+ end
171
+ retain
172
+ end
173
+
156
174
  def cookbook_count(cb_list)
157
175
  cb_count_list = {}
158
176
  cb_list.each do |name, versions|
@@ -1,5 +1,5 @@
1
- require "ffi_yajl"
2
- require "fileutils"
1
+ require "ffi_yajl" unless defined?(FFI_Yajl)
2
+ require "fileutils" unless defined?(FileUtils)
3
3
  require "chef/log"
4
4
 
5
5
  class Chef
@@ -20,26 +20,26 @@ class Chef
20
20
  def load_users
21
21
  @tidy.ui.stdout.puts "INFO: Loading users"
22
22
  Dir[::File.join(@tidy.users_path, "*.json")].each do |user|
23
- @users.push(FFI_Yajl::Parser.parse(::File.read(user), symbolize_names: true))
23
+ @users.push(@tidy.json_file_to_hash(user, symbolize_names: true))
24
24
  end
25
25
  end
26
26
 
27
27
  def load_members
28
28
  @tidy.ui.stdout.puts "INFO: Loading members for #{@org}"
29
- @members = FFI_Yajl::Parser.parse(::File.read(@tidy.members_path(@org)), symbolize_names: true)
29
+ @members = @tidy.json_file_to_hash(@tidy.members_path(@org), symbolize_names: true)
30
30
  end
31
31
 
32
32
  def load_clients
33
33
  @tidy.ui.stdout.puts "INFO: Loading clients for #{@org}"
34
34
  Dir[::File.join(@tidy.clients_path(@org), "*.json")].each do |client|
35
- @clients.push(FFI_Yajl::Parser.parse(::File.read(client), symbolize_names: true))
35
+ @clients.push(@tidy.json_file_to_hash(client, symbolize_names: true))
36
36
  end
37
37
  end
38
38
 
39
39
  def load_groups
40
40
  @tidy.ui.stdout.puts "INFO: Loading groups for #{@org}"
41
41
  Dir[::File.join(@tidy.groups_path(@org), "*.json")].each do |group|
42
- @groups.push(FFI_Yajl::Parser.parse(::File.read(group), symbolize_names: true))
42
+ @groups.push(@tidy.json_file_to_hash(group, symbolize_names: true))
43
43
  end
44
44
  end
45
45
 
@@ -111,7 +111,7 @@ class Chef
111
111
 
112
112
  def add_client_to_org(actor)
113
113
  # TODO
114
- @tidy.ui.stdout.puts "ACTION NEEDED: Client referenced in acl non-existant: #{actor}"
114
+ @tidy.ui.stdout.puts "ACTION NEEDED: Client referenced in acl non-existent: #{actor}"
115
115
  end
116
116
 
117
117
  def add_actor_to_members(actor)
@@ -128,7 +128,7 @@ class Chef
128
128
 
129
129
  def remove_group_from_acl(group, acl_file)
130
130
  @tidy.ui.stdout.puts "REPAIRING: Removing invalid group: #{group} from #{acl_file}"
131
- acl = FFI_Yajl::Parser.parse(::File.read(acl_file), symbolize_names: false)
131
+ acl = @tidy.json_file_to_hash(acl_file, symbolize_names: false)
132
132
  acl_ops.each do |op|
133
133
  acl[op]["groups"].reject! { |the_group| the_group == group }
134
134
  end
@@ -137,7 +137,7 @@ class Chef
137
137
 
138
138
  # Appends the proper acls for ::server-admins and the org's read access group if they are missing.
139
139
  def ensure_global_group_acls(acl_file)
140
- acl = FFI_Yajl::Parser.parse(::File.read(acl_file), symbolize_names: false)
140
+ acl = @tidy.json_file_to_hash(acl_file, symbolize_names: false)
141
141
  acl_ops.each do |op|
142
142
  unless acl[op]["groups"].include? "::server-admins"
143
143
  @tidy.ui.stdout.puts "REPAIRING: Adding #{op} acl for ::server-admins in #{acl_file}"
@@ -152,7 +152,7 @@ class Chef
152
152
  end
153
153
 
154
154
  def ensure_client_read_acls(acl_file)
155
- acl = FFI_Yajl::Parser.parse(::File.read(acl_file), symbolize_names: false)
155
+ acl = @tidy.json_file_to_hash(acl_file, symbolize_names: false)
156
156
  %w{users admins}.each do |group|
157
157
  unless acl["read"]["groups"].include? group
158
158
  @tidy.ui.stdout.puts "REPAIRING: Adding read acl for #{group} in #{acl_file}"
@@ -164,7 +164,7 @@ class Chef
164
164
 
165
165
  def validate_acls
166
166
  org_acls.each do |acl_file|
167
- acl = FFI_Yajl::Parser.parse(::File.read(acl_file), symbolize_names: false)
167
+ acl = @tidy.json_file_to_hash(acl_file, symbolize_names: false)
168
168
  actors_groups = acl_actors_groups(acl)
169
169
  actors_groups[:actors].each do |actor|
170
170
  next if actor == "pivotal"
@@ -203,11 +203,11 @@ class Chef
203
203
  @members.each do |member|
204
204
  user_acl_path = ::File.join(@tidy.user_acls_path, "#{member[:user][:username]}.json")
205
205
  begin
206
- user_acl = FFI_Yajl::Parser.parse(::File.read(user_acl_path), symbolize_names: false)
206
+ user_acl = @tidy.json_file_to_hash(user_acl_path, symbolize_names: false)
207
207
  rescue Errno::ENOENT
208
208
  @tidy.ui.stdout.puts "REPAIRING: Replacing missing user acl for #{member[:user][:username]}."
209
209
  @tidy.write_new_file(default_user_acl(member), user_acl_path, backup = false)
210
- user_acl = FFI_Yajl::Parser.parse(::File.read(user_acl_path), symbolize_names: false)
210
+ user_acl = @tidy.json_file_to_hash(user_acl_path, symbolize_names: false)
211
211
  end
212
212
  ensure_global_group_acls(user_acl_path)
213
213
  actors_groups = acl_actors_groups(user_acl)
@@ -221,11 +221,11 @@ class Chef
221
221
  @clients.each do |client|
222
222
  client_acl_path = ::File.join(@tidy.org_acls_path(@org), "clients", "#{client[:name]}.json")
223
223
  begin
224
- client_acl = FFI_Yajl::Parser.parse(::File.read(client_acl_path), symbolize_names: false)
224
+ client_acl = @tidy.json_file_to_hash(client_acl_path, symbolize_names: false)
225
225
  rescue Errno::ENOENT
226
226
  @tidy.ui.stdout.puts "REPAIRING: Replacing missing client acl for #{client[:name]} in #{client_acl_path}."
227
227
  @tidy.write_new_file(default_client_acl(client[:name]), client_acl_path, backup = false)
228
- client_acl = FFI_Yajl::Parser.parse(::File.read(client_acl_path), symbolize_names: false)
228
+ client_acl = @tidy.json_file_to_hash(client_acl_path, symbolize_names: false)
229
229
  end
230
230
  ensure_client_read_acls(client_acl_path)
231
231
  end
@@ -1,5 +1,5 @@
1
- require "ffi_yajl"
2
- require "fileutils"
1
+ require "ffi_yajl" unless defined?(FFI_Yajl)
2
+ require "fileutils" unless defined?(FileUtils)
3
3
  require "chef/knife/core/ui"
4
4
 
5
5
  class Chef
@@ -149,6 +149,23 @@ class Chef
149
149
  end
150
150
  end
151
151
 
152
+ # Read a json file and return a hash of parsed content with optional symbolized keys
153
+ #
154
+ # @param [String] path to file
155
+ # @param [double splat] options to pass FFI_Yajl::Parser.parse()
156
+ #
157
+ # @return [Hash] original json content as hash
158
+ #
159
+ # @example
160
+ # json_file_to_hash('/path/to/file.json', symbolize_names: true) => { foo: "bar" }
161
+ #
162
+ def json_file_to_hash(file_path, **options)
163
+ FFI_Yajl::Parser.parse(File.read(file_path), options)
164
+ rescue Errno::ENOENT, Errno::EACCES, FFI_Yajl::ParseError
165
+ puts "ERROR: unable to parse file: '#{file_path}'"
166
+ raise
167
+ end
168
+
152
169
  #
153
170
  # Determine the cookbook name from path
154
171
  #
@@ -1,6 +1,6 @@
1
- require "ffi_yajl"
2
- require "tempfile"
3
- require "fileutils"
1
+ require "ffi_yajl" unless defined?(FFI_Yajl)
2
+ require "tempfile" unless defined?(Tempfile)
3
+ require "fileutils" unless defined?(FileUtils)
4
4
  require "chef/log"
5
5
 
6
6
  class Chef
@@ -17,7 +17,7 @@ class Chef
17
17
 
18
18
  def load_data
19
19
  @tidy.ui.stdout.puts "INFO: Loading substitutions from #{file_path}"
20
- @data = FFI_Yajl::Parser.parse(::File.read(@file_path), symbolize_names: false)
20
+ @data = @tidy.json_file_to_hash(@file_path, symbolize_names: false)
21
21
  rescue Errno::ENOENT
22
22
  raise NoSubstitutionFile, file_path
23
23
  end
@@ -1,4 +1,4 @@
1
1
  module KnifeTidy
2
- VERSION = "2.0.9".freeze
2
+ VERSION = "2.1.2".freeze
3
3
  MAJOR, MINOR, TINY = VERSION.split(".")
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-tidy
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.9
4
+ version: 2.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Miller
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-21 00:00:00.000000000 Z
11
+ date: 2020-08-21 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Report on stale Chef Server nodes and cookbooks and clean up data integrity
14
14
  issues in a knife-ec-backup object based backup
@@ -19,6 +19,7 @@ extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
21
  - LICENSE
22
+ - conf/substitutions.json.example
22
23
  - lib/chef/knife/tidy_backup_clean.rb
23
24
  - lib/chef/knife/tidy_base.rb
24
25
  - lib/chef/knife/tidy_notify.rb