knife-tidy 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,58 +1,58 @@
1
- require 'chef/knife/tidy_base'
1
+ require "chef/knife/tidy_base"
2
2
 
3
3
  class Chef
4
4
  class Knife
5
5
  class TidyNotify < Knife
6
6
  deps do
7
- require 'ffi_yajl'
8
- require 'net/smtp'
7
+ require "ffi_yajl"
8
+ require "net/smtp"
9
9
  end
10
10
 
11
- banner 'knife tidy notify (options)'
11
+ banner "knife tidy notify (options)"
12
12
 
13
13
  option :smtp_server,
14
- short: '-s SERVER_NAME',
15
- long: '--smtp_server SERVER_NAME',
16
- default: 'localhost',
17
- description: 'SMTP Server to be used for emailling reports to organization admins (defaults to localhost)'
14
+ short: "-s SERVER_NAME",
15
+ long: "--smtp_server SERVER_NAME",
16
+ default: "localhost",
17
+ description: "SMTP Server to be used for emailling reports to organization admins (defaults to localhost)"
18
18
 
19
19
  option :smtp_port,
20
- short: '-p SMTP_PORT',
21
- long: '--smtp_port SMTP_PORT',
20
+ short: "-p SMTP_PORT",
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 emailling reports to organization admins (defaults to 25)"
24
24
 
25
25
  option :smtp_helo,
26
- short: '-h SMTP_HELO',
27
- long: '--smtp_helo SMTP_HELO',
28
- default: 'localhost',
29
- description: 'SMTP HELO to be used for emailling reports to organization admins (defaults to localhost)'
26
+ short: "-h SMTP_HELO",
27
+ long: "--smtp_helo SMTP_HELO",
28
+ default: "localhost",
29
+ description: "SMTP HELO to be used for emailling reports to organization admins (defaults to localhost)"
30
30
 
31
31
  option :smtp_username,
32
- short: '-u SMTP_USERNAME',
33
- long: '--smtp_username SMTP_USERNAME',
34
- description: 'SMTP Username to be used for emailling reports to organization admins'
32
+ short: "-u SMTP_USERNAME",
33
+ long: "--smtp_username SMTP_USERNAME",
34
+ description: "SMTP Username to be used for emailling reports to organization admins"
35
35
 
36
36
  option :smtp_password,
37
- long: '--smtp_password SMTP_PASSWORD',
38
- description: 'SMTP Password to be used for emailling reports to organization admins'
37
+ long: "--smtp_password SMTP_PASSWORD",
38
+ description: "SMTP Password to be used for emailling reports to organization admins"
39
39
 
40
40
  option :smtp_from,
41
- long: '--smtp_from SMTP_FROM',
42
- description: 'SMTP From address to be used for emailling reports to organization admins'
41
+ long: "--smtp_from SMTP_FROM",
42
+ description: "SMTP From address to be used for emailling reports to organization admins"
43
43
 
44
44
  option :smtp_use_tls,
45
- long: '--smtp_use_tls',
46
- short: '-t',
45
+ long: "--smtp_use_tls",
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 emailling reports to organization admins (defaults to false if omitted)"
50
50
 
51
51
  include Knife::TidyBase
52
52
 
53
53
  def run
54
54
  reports_dir = tidy.reports_dir
55
- report_file_suffixes = ['_unused_cookbooks.json', '_cookbook_count.json', '_stale_nodes.json']
55
+ report_file_suffixes = ["_unused_cookbooks.json", "_cookbook_count.json", "_stale_nodes.json"]
56
56
  # Only grab the files matching the report_file_suffixes
57
57
  report_files = Dir["#{reports_dir}/*{#{report_file_suffixes.join(',')}}"]
58
58
 
@@ -62,11 +62,11 @@ class Chef
62
62
  begin
63
63
  org_names = report_files.map { |r_file| r_file.match("#{reports_dir}\/(.*)(#{report_file_suffixes.join('|')})").captures.first }.uniq
64
64
  rescue NoMethodError
65
- ui.stderr.puts 'Failed to parse json reports files. Please ensure your reports are valid.'
65
+ ui.stderr.puts "Failed to parse json reports files. Please ensure your reports are valid."
66
66
  return
67
67
  end
68
68
  if config[:org_list]
69
- filter_orgs = config[:org_list].split(',')
69
+ filter_orgs = config[:org_list].split(",")
70
70
  # Take the intersection of org_names and filter_orgs
71
71
  org_names &= filter_orgs
72
72
  end
@@ -76,7 +76,7 @@ class Chef
76
76
  # Iterate through list of collected organizations and parse any report files into JSON objects
77
77
 
78
78
  unless org_names
79
- ui.std.puts 'No valid org reports found to send notifications. Exiting.'
79
+ ui.std.puts "No valid org reports found to send notifications. Exiting."
80
80
  return
81
81
  end
82
82
 
@@ -99,13 +99,13 @@ class Chef
99
99
  ui.info("Fetching admins users for organization #{org}")
100
100
  begin
101
101
  admins = org_admins(org)
102
- reports[org]['admins'] = admins.map { |name, _data| org_user(org, name) unless name == 'pivotal' }
102
+ reports[org]["admins"] = admins.map { |name, _data| org_user(org, name) unless name == "pivotal" }
103
103
  rescue Net::HTTPServerException
104
104
  ui.info(" Cannot fetch admin users for organization #{org} as it does not exist on the server")
105
105
  end
106
106
 
107
107
  # Build list of email recipients from the collected admin users (display name and email address of each)
108
- email_recipients = reports[org]['admins'].map { |admin| { name: admin['display_name'], email: admin['email'] } unless admin.nil? }.compact
108
+ email_recipients = reports[org]["admins"].map { |admin| { name: admin["display_name"], email: admin["email"] } unless admin.nil? }.compact
109
109
 
110
110
  # Send a report email to all admin users of the organization
111
111
  ui.info "Sending email reports for organization #{org}"
@@ -118,73 +118,73 @@ class Chef
118
118
 
119
119
  def generate_email(report_data, organization, recipients, report_file_suffixes)
120
120
  mime_boundary = "==Multipart_Boundary_x#{srand}x"
121
- message = <<MESSAGE_END
122
- From: Knife Tidy <#{config[:smtp_from]}>
123
- To: #{recipients.map { |recipient| "#{recipient[:name]} <#{recipient[:email]}>" }.join(', ')}
124
- MIME-Version: 1.0
125
- Subject: Knife Tidy Cleanup Report for Organization "#{organization}"
126
- Content-Type: multipart/mixed; boundary="#{mime_boundary}";
127
- --#{mime_boundary}
128
- Content-type: text/html
129
- Content-Transfer-Encoding: 7bit
130
-
131
- The following reports were generated by <a href="https://github.com/chef-customers/knife-tidy">knife-tidy</a>, and contain a list of unused cookbooks and stale nodes for the Chef server organization "#{organization}"
132
- #{generate_total_cookbooks_table(report_data, organization)}
133
- #{generate_unused_cookbooks_table(report_data, organization)}
134
- #{generate_node_table(report_data, organization)}
135
- MESSAGE_END
121
+ message = <<~MESSAGE_END
122
+ From: Knife Tidy <#{config[:smtp_from]}>
123
+ To: #{recipients.map { |recipient| "#{recipient[:name]} <#{recipient[:email]}>" }.join(', ')}
124
+ MIME-Version: 1.0
125
+ Subject: Knife Tidy Cleanup Report for Organization "#{organization}"
126
+ Content-Type: multipart/mixed; boundary="#{mime_boundary}";
127
+ --#{mime_boundary}
128
+ Content-type: text/html
129
+ Content-Transfer-Encoding: 7bit
130
+
131
+ The following reports were generated by <a href="https://github.com/chef-customers/knife-tidy">knife-tidy</a>, and contain a list of unused cookbooks and stale nodes for the Chef server organization "#{organization}"
132
+ #{generate_total_cookbooks_table(report_data, organization)}
133
+ #{generate_unused_cookbooks_table(report_data, organization)}
134
+ #{generate_node_table(report_data, organization)}
135
+ MESSAGE_END
136
136
 
137
137
  report_file_suffixes.each do |suffix|
138
- message += <<MESSAGE_END
139
- --#{mime_boundary}
140
- Content-Transfer-Encoding:7bit
141
- Content-Type: plain/text;name="#{organization}#{suffix}";charset="UTF-8"
142
- Content-Disposition: attachment;filename="#{organization}#{suffix}"
138
+ message += <<~MESSAGE_END
139
+ --#{mime_boundary}
140
+ Content-Transfer-Encoding:7bit
141
+ Content-Type: plain/text;name="#{organization}#{suffix}";charset="UTF-8"
142
+ Content-Disposition: attachment;filename="#{organization}#{suffix}"
143
143
 
144
- #{report_data[organization][suffix].to_json}
144
+ #{report_data[organization][suffix].to_json}
145
145
 
146
- MESSAGE_END
146
+ MESSAGE_END
147
147
  end
148
148
 
149
- message += <<MESSAGE_END
150
- --#{mime_boundary}--
151
- MESSAGE_END
149
+ message += <<~MESSAGE_END
150
+ --#{mime_boundary}--
151
+ MESSAGE_END
152
152
  puts message
153
153
  message
154
154
  end
155
155
 
156
156
  def generate_total_cookbooks_table(report_data, organization)
157
157
  table_start = "<h2>Total Versions by Cookbook</h2><p>This table contains the count of versions of each cookbook stored on the Chef Server.<p><table border='1' cellpadding='1' cellspacing='0'>"
158
- table_end = '</table><br/>'
159
- header_string = '<tr><th>Cookbook Name</th><th>Total Version Count</th></tr>'
160
- table_body = if report_data[organization]['_cookbook_count.json'].empty?
158
+ table_end = "</table><br/>"
159
+ header_string = "<tr><th>Cookbook Name</th><th>Total Version Count</th></tr>"
160
+ table_body = if report_data[organization]["_cookbook_count.json"].empty?
161
161
  "<tr><td colspan='2'>No cookbook versions</td></tr>"
162
162
  else
163
- report_data[organization]['_cookbook_count.json'].map { |cookbook_name, cookbook_count| "<tr><td>#{cookbook_name}</td><td>#{cookbook_count}</td></tr>" }.join("\n")
163
+ report_data[organization]["_cookbook_count.json"].map { |cookbook_name, cookbook_count| "<tr><td>#{cookbook_name}</td><td>#{cookbook_count}</td></tr>" }.join("\n")
164
164
  end
165
165
  table_start + header_string + table_body + table_end
166
166
  end
167
167
 
168
168
  def generate_unused_cookbooks_table(report_data, organization)
169
169
  table_start = "<h2>Unused Cookbooks</h2><p>This table contains cookbook names and the count of their versions that are not currently in the runlists of any nodes.<p><table border='1' cellpadding='1' cellspacing='0'>"
170
- table_end = '</table><br/>'
171
- header_string = '<tr><th>Cookbook Name</th><th>Unused Versions</th></tr>'
172
- table_body = if report_data[organization]['_unused_cookbooks.json'].empty?
170
+ table_end = "</table><br/>"
171
+ header_string = "<tr><th>Cookbook Name</th><th>Unused Versions</th></tr>"
172
+ table_body = if report_data[organization]["_unused_cookbooks.json"].empty?
173
173
  "<tr><td colspan='2'>No unused cookbook versions</td></tr>"
174
174
  else
175
- report_data[organization]['_unused_cookbooks.json'].map { |cookbook_name, cookbook_versions| "<tr><td>#{cookbook_name}</td><td>#{cookbook_versions.join('<br>')}</td></tr>" }.join("\n")
175
+ report_data[organization]["_unused_cookbooks.json"].map { |cookbook_name, cookbook_versions| "<tr><td>#{cookbook_name}</td><td>#{cookbook_versions.join('<br>')}</td></tr>" }.join("\n")
176
176
  end
177
177
  table_start + header_string + table_body + table_end
178
178
  end
179
179
 
180
180
  def generate_node_table(report_data, organization)
181
181
  table_start = "<h2>Stale Nodes</h2><p>This table contains nodes that have not checked in to the Chef Server in #{report_data[organization]['_stale_nodes.json']['threshold_days']} days.<p><table border='1' cellpadding='1' cellspacing='0'>"
182
- table_end = '</table>'
183
- header_string = '<tr><th>Node Name</th></tr>'
184
- table_body = if report_data[organization]['_stale_nodes.json'].empty? || report_data[organization]['_stale_nodes.json']['count'] == 0
182
+ table_end = "</table>"
183
+ header_string = "<tr><th>Node Name</th></tr>"
184
+ table_body = if report_data[organization]["_stale_nodes.json"].empty? || report_data[organization]["_stale_nodes.json"]["count"] == 0
185
185
  "<tr><td colspan='2'>No stale nodes</td></tr>"
186
186
  else
187
- report_data[organization]['_stale_nodes.json']['list'].map { |node_name| "<tr><td>#{node_name}</td></tr>" }.join("\n")
187
+ report_data[organization]["_stale_nodes.json"]["list"].map { |node_name| "<tr><td>#{node_name}</td></tr>" }.join("\n")
188
188
  end
189
189
  table_start + header_string + table_body + table_end
190
190
  end
@@ -199,7 +199,7 @@ MESSAGE_END
199
199
 
200
200
  def org_admins(org)
201
201
  admins = {}
202
- rest.get("/organizations/#{org}/groups/admins")['users'].each do |name|
202
+ rest.get("/organizations/#{org}/groups/admins")["users"].each do |name|
203
203
  admins[name] = {}
204
204
  end
205
205
  admins
@@ -1,4 +1,4 @@
1
- require 'chef/knife/tidy_base'
1
+ require "chef/knife/tidy_base"
2
2
 
3
3
  class Chef
4
4
  class Knife
@@ -6,32 +6,32 @@ class Chef
6
6
  include Knife::TidyBase
7
7
 
8
8
  deps do
9
- require 'ffi_yajl'
10
- require 'chef/util/threaded_job_queue'
9
+ require "ffi_yajl"
10
+ require "chef/util/threaded_job_queue"
11
11
  end
12
12
 
13
- banner 'knife tidy server clean (options)'
13
+ banner "knife tidy server clean (options)"
14
14
 
15
15
  option :backup_path,
16
- long: '--backup-path path/to/backup',
17
- description: 'The path to the knife-ec-backup backup directory'
16
+ long: "--backup-path path/to/backup",
17
+ description: "The path to the knife-ec-backup backup directory"
18
18
 
19
19
  option :concurrency,
20
- long: '--concurrency THREADS',
20
+ long: "--concurrency THREADS",
21
21
  default: 1,
22
- description: 'Maximum number of simultaneous requests to send (default: 1)'
22
+ description: "Maximum number of simultaneous requests to send (default: 1)"
23
23
 
24
24
  option :only_cookbooks,
25
- long: '--only-cookbooks',
26
- description: 'Only delete unused cookbooks from Chef Server.'
25
+ long: "--only-cookbooks",
26
+ description: "Only delete unused cookbooks from Chef Server."
27
27
 
28
28
  option :only_nodes,
29
- long: '--only-nodes',
30
- description: 'Only delete stale nodes (and associated clients and ACLs) from Chef Server.'
29
+ long: "--only-nodes",
30
+ description: "Only delete stale nodes (and associated clients and ACLs) from Chef Server."
31
31
 
32
32
  option :dry_run,
33
- long: '--dry-run',
34
- description: 'Do not perform any actual deletion, only report on what would have been deleted.'
33
+ long: "--dry-run",
34
+ description: "Do not perform any actual deletion, only report on what would have been deleted."
35
35
 
36
36
  def run
37
37
  STDOUT.sync = true
@@ -41,37 +41,37 @@ class Chef
41
41
  configure_chef
42
42
 
43
43
  if config[:only_cookbooks] && config[:only_nodes]
44
- ui.error 'Cannot use --only-cookbooks AND --only-nodes'
44
+ ui.error "Cannot use --only-cookbooks AND --only-nodes"
45
45
  exit 1
46
46
  end
47
47
 
48
48
  while config[:backup_path].nil?
49
49
  user_value = ui.ask_question("It is not recommended to run this command without specifying a current backup directory.\nPlease specify a backup directory:")
50
- config[:backup_path] = user_value == '' ? nil : user_value
50
+ config[:backup_path] = user_value == "" ? nil : user_value
51
51
  end
52
52
 
53
53
  unless ::File.directory?(config[:backup_path])
54
- ui.error 'Must specify valid --backup-path'
54
+ ui.error "Must specify valid --backup-path"
55
55
  exit 1
56
56
  end
57
57
 
58
58
  deletions = if config[:only_cookbooks]
59
- 'cookbooks'
59
+ "cookbooks"
60
60
  elsif config[:only_nodes]
61
- 'nodes (and associated clients and ACLs)'
61
+ "nodes (and associated clients and ACLs)"
62
62
  else
63
- 'cookbooks and nodes (and associated clients and ACLs)'
63
+ "cookbooks and nodes (and associated clients and ACLs)"
64
64
  end
65
65
 
66
66
  orgs = if config[:org_list]
67
- config[:org_list].split(',')
67
+ config[:org_list].split(",")
68
68
  else
69
69
  all_orgs
70
70
  end
71
71
 
72
72
  ui.warn "This operation will affect the following Orgs on #{server.root_url}: #{orgs}"
73
73
  if ::File.exist?(server_warnings_file_path)
74
- ::File.read(::File.expand_path('reports/knife-tidy-server-warnings.txt')).each_line do |line|
74
+ ::File.read(::File.expand_path("reports/knife-tidy-server-warnings.txt")).each_line do |line|
75
75
  ui.warn(line)
76
76
  end
77
77
  end
@@ -147,7 +147,7 @@ class Chef
147
147
  end
148
148
 
149
149
  def report_files
150
- Dir[::File.join(tidy.reports_dir, '**.json')]
150
+ Dir[::File.join(tidy.reports_dir, "**.json")]
151
151
  end
152
152
 
153
153
  def all_orgs
@@ -1,4 +1,4 @@
1
- require 'chef/knife/tidy_base'
1
+ require "chef/knife/tidy_base"
2
2
 
3
3
  class Chef
4
4
  class Knife
@@ -7,15 +7,15 @@ class Chef
7
7
  include Knife::TidyBase
8
8
 
9
9
  deps do
10
- require 'ffi_yajl'
10
+ require "ffi_yajl"
11
11
  end
12
12
 
13
13
  banner "knife tidy server report (options)"
14
14
 
15
15
  option :node_threshold,
16
- :long => '--node-threshold NUM_DAYS',
17
- :default => 30,
18
- :description => 'Maximum number of days since last checkin before node is considered stale (default: 30)'
16
+ long: "--node-threshold NUM_DAYS",
17
+ default: 30,
18
+ description: "Maximum number of days since last checkin before node is considered stale (default: 30)"
19
19
 
20
20
  def run
21
21
  ensure_reports_dir!
@@ -25,7 +25,7 @@ class Chef
25
25
  delete_existing_reports
26
26
 
27
27
  orgs = if config[:org_list]
28
- config[:org_list].split(',')
28
+ config[:org_list].split(",")
29
29
  else
30
30
  all_orgs
31
31
  end
@@ -51,23 +51,23 @@ class Chef
51
51
 
52
52
  nodes.each do |node|
53
53
  # If the node hasn't checked in.
54
- if !node['chef_packages']
54
+ if !node["chef_packages"]
55
55
  # If the node is under an hour old.
56
- if (Time.now.to_i - node['ohai_time'].to_i) < 3600
57
- unconverged_recent_nodes << node['name']
56
+ if (Time.now.to_i - node["ohai_time"].to_i) < 3600
57
+ unconverged_recent_nodes << node["name"]
58
58
  end
59
59
  next
60
60
  end
61
- chef_version = Gem::Version.new(node['chef_packages']['chef']['version'])
61
+ chef_version = Gem::Version.new(node["chef_packages"]["chef"]["version"])
62
62
  # If the node has checked in within the node_threshold with a client older than 12.3
63
- if chef_version < Gem::Version.new("12.3") && (Time.now.to_i - node['ohai_time'].to_i) <= node_threshold * 86400
64
- pre_12_3_nodes << node['name']
63
+ if chef_version < Gem::Version.new("12.3") && (Time.now.to_i - node["ohai_time"].to_i) <= node_threshold * 86400
64
+ pre_12_3_nodes << node["name"]
65
65
  end
66
66
  end
67
67
 
68
- nodes.select{|node| !node['cookbooks'].nil?}.each do |node|
69
- node['cookbooks'].each do |name, version_hash|
70
- version = Gem::Version.new(version_hash['version']).to_s
68
+ nodes.select { |node| !node["cookbooks"].nil? }.each do |node|
69
+ node["cookbooks"].each do |name, version_hash|
70
+ version = Gem::Version.new(version_hash["version"]).to_s
71
71
  if used_cookbooks[name]
72
72
  used_cookbooks[name].push(version) unless used_cookbooks[name].include?(version)
73
73
  else
@@ -81,17 +81,17 @@ class Chef
81
81
 
82
82
  stale_nodes = []
83
83
  nodes.each do |n|
84
- if (Time.now.to_i - n['ohai_time'].to_i) >= node_threshold * 86400
85
- stale_nodes.push(n['name'])
84
+ if (Time.now.to_i - n["ohai_time"].to_i) >= node_threshold * 86400
85
+ stale_nodes.push(n["name"])
86
86
  end
87
87
  end
88
88
 
89
- stale_nodes_hash = {'threshold_days': node_threshold, 'org_total_node_count': nodes.count, 'count': stale_nodes.count, 'list': stale_nodes}
89
+ stale_nodes_hash = { 'threshold_days': node_threshold, 'org_total_node_count': nodes.count, 'count': stale_nodes.count, 'list': stale_nodes }
90
90
  stale_orgs.push(org) if stale_nodes.count == nodes.count
91
91
 
92
- tidy.write_new_file(unused_cookbooks(used_cookbooks, cb_list), ::File.join(tidy.reports_dir, "#{org}_unused_cookbooks.json"), backup=false)
93
- tidy.write_new_file(version_count, ::File.join(tidy.reports_dir, "#{org}_cookbook_count.json"), backup=false)
94
- tidy.write_new_file(stale_nodes_hash, ::File.join(tidy.reports_dir, "#{org}_stale_nodes.json"), backup=false)
92
+ tidy.write_new_file(unused_cookbooks(used_cookbooks, cb_list), ::File.join(tidy.reports_dir, "#{org}_unused_cookbooks.json"), backup = false)
93
+ tidy.write_new_file(version_count, ::File.join(tidy.reports_dir, "#{org}_cookbook_count.json"), backup = false)
94
+ tidy.write_new_file(stale_nodes_hash, ::File.join(tidy.reports_dir, "#{org}_stale_nodes.json"), backup = false)
95
95
 
96
96
  if pre_12_3_nodes.length > 0
97
97
  pre_12_3_message = "#{pre_12_3_nodes.length} nodes in organization #{org} have converged in the last #{node_threshold} days with a chef-client < 12.3. These nodes' cookbook versions WILL NOT be factored in the stale cookbooks versions report. Continuing with the server cleanup will delete cookbooks in-use by these nodes."
@@ -113,24 +113,24 @@ class Chef
113
113
  end
114
114
 
115
115
  def delete_existing_reports
116
- files = Dir[::File.join(tidy.reports_dir, '*.json')]
116
+ files = Dir[::File.join(tidy.reports_dir, "*.json")]
117
117
  unless files.empty?
118
118
  ui.confirm("You have existing reports in #{tidy.reports_dir}. Remove")
119
- FileUtils.rm(files, :force => true)
119
+ FileUtils.rm(files, force: true)
120
120
  end
121
121
  end
122
122
 
123
- # Need the block here to get the search method to invoke multiple searches and
123
+ # Need the block here to get the search method to invoke multiple searches and
124
124
  # aggregate results for result sets over 1k.
125
125
  def nodes_list(org)
126
126
  node_results = []
127
127
  Chef::Search::Query.new("#{server.root_url}/organizations/#{org}").search(
128
- :node, '*:*',
129
- :filter_result => {
130
- 'name' => ['name'],
131
- 'cookbooks' => ['cookbooks'],
132
- 'ohai_time' => ['ohai_time'],
133
- 'chef_packages' => ['chef_packages']
128
+ :node, "*:*",
129
+ filter_result: {
130
+ "name" => ["name"],
131
+ "cookbooks" => ["cookbooks"],
132
+ "ohai_time" => ["ohai_time"],
133
+ "chef_packages" => ["chef_packages"],
134
134
  }
135
135
  ) do |node|
136
136
  node_results << node
@@ -141,8 +141,8 @@ class Chef
141
141
  def cookbook_list(org)
142
142
  cb_list = {}
143
143
  rest.get("/organizations/#{org}/cookbooks?num_versions=all").each do |name, data|
144
- data['versions'].each do |version_hash|
145
- version = Gem::Version.new(version_hash['version']).to_s
144
+ data["versions"].each do |version_hash|
145
+ version = Gem::Version.new(version_hash["version"]).to_s
146
146
  if cb_list[name] && !cb_list[name].include?(version)
147
147
  cb_list[name].push(version)
148
148
  else
@@ -164,11 +164,11 @@ class Chef
164
164
  def unused_cookbooks(used_list, cb_list)
165
165
  unused_list = {}
166
166
  cb_list.each do |name, versions|
167
- versions.sort! {| a, b | Gem::Version.new(a) <=> Gem::Version.new(b) }
167
+ versions.sort! { |a, b| Gem::Version.new(a) <=> Gem::Version.new(b) }
168
168
  if used_list[name].nil? # Not in the used list at all (Remove all versions)
169
169
  unused_list[name] = versions
170
- elsif used_list[name].sort != versions # Is in the used cookbook list, but version arrays do not match (Find unused versions)
171
- unused = versions - used_list[name] - [versions.last] # Don't delete the most recent version as it might not be in a run_list yet.
170
+ elsif used_list[name].sort != versions # Is in the used cookbook list, but version arrays do not match (Find unused versions)
171
+ unused = versions - used_list[name] - [versions.last] # Don't delete the most recent version as it might not be in a run_list yet.
172
172
  unused_list[name] = unused unless unused.empty?
173
173
  end
174
174
  end
@@ -176,7 +176,7 @@ class Chef
176
176
  end
177
177
 
178
178
  def all_orgs
179
- rest.get('organizations').keys
179
+ rest.get("organizations").keys
180
180
  end
181
181
 
182
182
  def all_environments(org)
@@ -187,7 +187,7 @@ class Chef
187
187
  constraints = {}
188
188
  all_environments(org).each do |env|
189
189
  e = rest.get(env)
190
- e['cookbook_versions'].each do |cb, version|
190
+ e["cookbook_versions"].each do |cb, version|
191
191
  if constraints[cb]
192
192
  constraints[cb].push(version) unless constraints[cb].include?(version)
193
193
  else
@@ -202,7 +202,7 @@ class Chef
202
202
  if cb_list[cb]
203
203
  cb_list[cb].each do |v|
204
204
  versions_not_satisfied = []
205
- if Gem::Dependency.new('', version).match?('', v)
205
+ if Gem::Dependency.new("", version).match?("", v)
206
206
  return [v]
207
207
  else
208
208
  versions_not_satisfied.push(v)
@@ -214,7 +214,7 @@ class Chef
214
214
  else
215
215
  ui.warn("Cookbook #{cb} #{version} is pinned in an environment, but does not exist on the server in this org.")
216
216
  end
217
- return nil
217
+ nil
218
218
  end
219
219
 
220
220
  def check_environment_pins(used_cookbooks, pins, cb_list)
@@ -224,7 +224,7 @@ class Chef
224
224
  if used_cookbooks[cb]
225
225
  # This pinned cookbook is in the used list, now check for a matching version.
226
226
  used_cookbooks[cb].each do |v|
227
- if Gem::Dependency.new('', version).match?('', v)
227
+ if Gem::Dependency.new("", version).match?("", v)
228
228
  break
229
229
  end
230
230
  end