diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-03-04 12:28:24 +0100 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-03-04 12:33:05 +0100 |
commit | 2499f7e73946cd5147a1158b48ebe4b06e4e530d (patch) | |
tree | b1435c23f21afee1a8d150d0d96da40070916fc5 /modules/base_installation | |
parent | 85abd2fdbad83430df4824843764719064afb9b4 (diff) | |
download | Puppet-2499f7e73946cd5147a1158b48ebe4b06e4e530d.tar.gz Puppet-2499f7e73946cd5147a1158b48ebe4b06e4e530d.tar.zst Puppet-2499f7e73946cd5147a1158b48ebe4b06e4e530d.zip |
Add helpers and remove logs from cronie
Diffstat (limited to 'modules/base_installation')
5 files changed, 425 insertions, 3 deletions
diff --git a/modules/base_installation/files/cronie/puppet-post-merge b/modules/base_installation/files/cronie/puppet-post-merge index 35fa2d7..ac5e3ff 100644 --- a/modules/base_installation/files/cronie/puppet-post-merge +++ b/modules/base_installation/files/cronie/puppet-post-merge | |||
@@ -1,7 +1,7 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | ## Run Puppet locally using puppet apply | 2 | ## Run Puppet locally using puppet apply |
3 | git submodule update --init | 3 | git submodule update --init |
4 | /usr/bin/puppet apply --test `pwd`/manifests/site.pp | 4 | /usr/bin/puppet apply `pwd`/manifests/site.pp |
5 | 5 | ||
6 | ## Log status of the Puppet run | 6 | ## Log status of the Puppet run |
7 | if [ $? -eq 0 ] | 7 | if [ $? -eq 0 ] |
diff --git a/modules/base_installation/files/scripts/puppet_reset_and_apply b/modules/base_installation/files/scripts/puppet_reset_and_apply new file mode 100644 index 0000000..ff71aa8 --- /dev/null +++ b/modules/base_installation/files/scripts/puppet_reset_and_apply | |||
@@ -0,0 +1,14 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | cd /etc/puppetlabs/code | ||
4 | git fetch origin | ||
5 | |||
6 | branch="master" | ||
7 | if [ -n "$1" ]; then | ||
8 | branch="$1" | ||
9 | fi | ||
10 | |||
11 | git reset --hard origin/$1 | ||
12 | |||
13 | git submodule update --init | ||
14 | puppet apply --test manifests/site.pp | ||
diff --git a/modules/base_installation/files/scripts/report_print.rb b/modules/base_installation/files/scripts/report_print.rb new file mode 100644 index 0000000..632374c --- /dev/null +++ b/modules/base_installation/files/scripts/report_print.rb | |||
@@ -0,0 +1,396 @@ | |||
1 | #!/usr/bin/env ruby | ||
2 | # This file was modified from its original version at | ||
3 | # https://github.com/ripienaar/puppet-reportprint/ | ||
4 | # | ||
5 | # Copyright 2013-2016 R.I.Pienaar and contributors | ||
6 | # | ||
7 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
8 | # you may not use this file except in compliance with the License. | ||
9 | # You may obtain a copy of the License at | ||
10 | # | ||
11 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
12 | # | ||
13 | # Unless required by applicable law or agreed to in writing, software | ||
14 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
16 | # See the License for the specific language governing permissions and | ||
17 | # limitations under the License. | ||
18 | |||
19 | require 'puppet' | ||
20 | require 'pp' | ||
21 | require 'optparse' | ||
22 | |||
23 | def get_server_reports_dir | ||
24 | Puppet.settings[:reportdir] | ||
25 | end | ||
26 | |||
27 | class ::Numeric | ||
28 | def bytes_to_human | ||
29 | # Prevent nonsense values being returned for fractions | ||
30 | if self >= 1 | ||
31 | units = ['B', 'KB', 'MB' ,'GB' ,'TB'] | ||
32 | e = (Math.log(self)/Math.log(1024)).floor | ||
33 | # Cap at TB | ||
34 | e = 4 if e > 4 | ||
35 | s = "%.2f " % (to_f / 1024**e) | ||
36 | s.sub(/\.?0*$/, units[e]) | ||
37 | else | ||
38 | "0 B" | ||
39 | end | ||
40 | end | ||
41 | end | ||
42 | |||
43 | def load_report(path) | ||
44 | YAML.load_file(path) | ||
45 | end | ||
46 | |||
47 | def report_resources(report) | ||
48 | report.resource_statuses | ||
49 | end | ||
50 | |||
51 | def resource_with_evaluation_time(report) | ||
52 | report_resources(report).select{|r_name, r| !r.evaluation_time.nil? } | ||
53 | end | ||
54 | |||
55 | def resource_by_eval_time(report) | ||
56 | report_resources(report).reject{|r_name, r| r.evaluation_time.nil? }.sort_by{|r_name, r| r.evaluation_time rescue 0} | ||
57 | end | ||
58 | |||
59 | def resources_of_type(report, type) | ||
60 | report_resources(report).select{|r_name, r| r.resource_type == type} | ||
61 | end | ||
62 | |||
63 | def color(code, msg, reset=false) | ||
64 | colors = { | ||
65 | :red => "[31m", | ||
66 | :green => "[32m", | ||
67 | :yellow => "[33m", | ||
68 | :cyan => "[36m", | ||
69 | :bold => "[1m", | ||
70 | :underline => "[4m", | ||
71 | :reset => "[0m", | ||
72 | } | ||
73 | |||
74 | colors.merge!( | ||
75 | :changed => colors[:yellow], | ||
76 | :unchanged => colors[:green], | ||
77 | :failed => colors[:red] | ||
78 | ) | ||
79 | |||
80 | return "%s%s%s%s" % [colors.fetch(code, ""), msg, colors[:reset], reset ? colors.fetch(reset, "") : ""] if @options[:color] | ||
81 | |||
82 | msg | ||
83 | end | ||
84 | |||
85 | def print_report_summary(report) | ||
86 | puts color(:bold, "Report for %s in environment %s at %s" % [color(:underline, report.host, :bold), color(:underline, report.environment, :bold), color(:underline, report.time, :bold)]) | ||
87 | puts | ||
88 | puts " Report File: %s" % @options[:report] | ||
89 | puts " Report Status: %s" % report.status | ||
90 | puts " Puppet Version: %s" % report.puppet_version | ||
91 | puts " Report Format: %s" % report.report_format | ||
92 | puts " Configuration Version: %s" % report.configuration_version | ||
93 | puts " UUID: %s" % report.transaction_uuid rescue nil | ||
94 | puts " Log Lines: %s %s" % [report.logs.size, @options[:logs] ? "" : "(show with --log)"] | ||
95 | |||
96 | puts | ||
97 | end | ||
98 | |||
99 | def print_report_motd(report, motd_path) | ||
100 | motd = [] | ||
101 | header = "# #{report.host} #" | ||
102 | headline = "#" * header.size | ||
103 | motd << headline << header << headline << '' | ||
104 | |||
105 | motd << "Last puppet run happened at %s in environment %s." % [report.time, report.environment] | ||
106 | |||
107 | motd << "The result of this puppet run was %s." % color(report.status.to_sym, report.status) | ||
108 | |||
109 | if report.metrics.empty? or report.metrics["events"].nil? | ||
110 | motd << 'No Report Metrics.' | ||
111 | else | ||
112 | motd << 'Events:' | ||
113 | report.metrics["events"].values.each do |metric| | ||
114 | i, m, v = metric | ||
115 | motd.last << ' ' << [m, v].join(': ') << '.' | ||
116 | end | ||
117 | end | ||
118 | |||
119 | motd << '' << '' | ||
120 | |||
121 | File.write(motd_path, motd.join("\n")) | ||
122 | end | ||
123 | |||
124 | def print_report_metrics(report) | ||
125 | if report.metrics.empty? | ||
126 | puts color(:bold, "No Report Metrics") | ||
127 | puts | ||
128 | return | ||
129 | end | ||
130 | |||
131 | puts color(:bold, "Report Metrics:") | ||
132 | puts | ||
133 | |||
134 | padding = report.metrics.map{|i, m| m.values}.flatten(1).map{|i, m, v| m.size}.sort[-1] + 6 | ||
135 | |||
136 | report.metrics.sort_by{|i, m| m.label}.each do |i, metric| | ||
137 | puts " %s:" % metric.label | ||
138 | |||
139 | metric.values.sort_by{|j, m, v| v}.reverse.each do |j, m, v| | ||
140 | puts "%#{padding}s: %s" % [m, v] | ||
141 | end | ||
142 | |||
143 | puts | ||
144 | end | ||
145 | |||
146 | puts | ||
147 | end | ||
148 | |||
149 | def print_summary_by_type(report) | ||
150 | summary = {} | ||
151 | |||
152 | report_resources(report).each do |resource| | ||
153 | if resource[0] =~ /^(.+?)\[/ | ||
154 | name = $1 | ||
155 | |||
156 | summary[name] ||= 0 | ||
157 | summary[name] += 1 | ||
158 | else | ||
159 | STDERR.puts "ERROR: Cannot parse type %s" % resource[0] | ||
160 | end | ||
161 | end | ||
162 | |||
163 | puts color(:bold, "Resources by resource type:") | ||
164 | puts | ||
165 | |||
166 | summary.sort_by{|k, v| v}.reverse.each do |type, count| | ||
167 | puts " %4d %s" % [count, type] | ||
168 | end | ||
169 | |||
170 | puts | ||
171 | end | ||
172 | |||
173 | def print_slow_resources(report, number=20) | ||
174 | if report.report_format < 4 | ||
175 | puts color(:red, " Cannot print slow resources for report versions %d" % report.report_format) | ||
176 | puts | ||
177 | return | ||
178 | end | ||
179 | |||
180 | resources = resource_by_eval_time(report) | ||
181 | |||
182 | number = resources.size if resources.size < number | ||
183 | |||
184 | puts color(:bold, "Slowest %d resources by evaluation time:" % number) | ||
185 | puts | ||
186 | |||
187 | resources[(0-number)..-1].reverse.each do |r_name, r| | ||
188 | puts " %7.2f %s" % [r.evaluation_time, r_name] | ||
189 | end | ||
190 | |||
191 | puts | ||
192 | end | ||
193 | |||
194 | def print_logs(report) | ||
195 | puts color(:bold, "%d Log lines:" % report.logs.size) | ||
196 | puts | ||
197 | |||
198 | report.logs.each do |log| | ||
199 | puts " %s" % log.to_report | ||
200 | end | ||
201 | |||
202 | puts | ||
203 | end | ||
204 | |||
205 | def print_summary_by_containment_path(report, number=20) | ||
206 | resources = resource_with_evaluation_time(report) | ||
207 | |||
208 | containment = Hash.new(0) | ||
209 | |||
210 | resources.each do |r_name, r| | ||
211 | r.containment_path.each do |containment_path| | ||
212 | #if containment_path !~ /\[/ | ||
213 | containment[containment_path] += r.evaluation_time | ||
214 | #end | ||
215 | end | ||
216 | end | ||
217 | |||
218 | number = containment.size if containment.size < number | ||
219 | |||
220 | puts color(:bold, "%d most time consuming containment" % number) | ||
221 | puts | ||
222 | |||
223 | containment.sort_by{|c, s| s}[(0-number)..-1].reverse.each do |c_name, evaluation_time| | ||
224 | puts " %7.2f %s" % [evaluation_time, c_name] | ||
225 | end | ||
226 | |||
227 | puts | ||
228 | end | ||
229 | |||
230 | def print_files(report, number=20) | ||
231 | resources = resources_of_type(report, "File") | ||
232 | |||
233 | files = {} | ||
234 | |||
235 | resources.each do |r_name, r| | ||
236 | if r_name =~ /^File\[(.+)\]$/ | ||
237 | file = $1 | ||
238 | |||
239 | if File.exist?(file) && File.readable?(file) && File.file?(file) && !File.symlink?(file) | ||
240 | files[file] = File.size?(file) || 0 | ||
241 | end | ||
242 | end | ||
243 | end | ||
244 | |||
245 | number = files.size if files.size < number | ||
246 | |||
247 | puts color(:bold, "%d largest managed files" % number) + " (only those with full path as resource name that are readable)" | ||
248 | puts | ||
249 | |||
250 | files.sort_by{|f, s| s}[(0-number)..-1].reverse.each do |f_name, size| | ||
251 | puts " %9s %s" % [size.bytes_to_human, f_name] | ||
252 | end | ||
253 | |||
254 | puts | ||
255 | end | ||
256 | |||
257 | def get_reports_for_node(nodename) | ||
258 | Dir.glob("%s/%s/*.yaml" % [get_server_reports_dir, nodename]).sort_by{|p|File.basename(p, ".*")} | ||
259 | end | ||
260 | |||
261 | def load_report_for_node(nodename, report) | ||
262 | report_path = "%s/%s/%s.yaml" % [get_server_reports_dir, nodename, report] | ||
263 | puts report_path | ||
264 | load_report(report_path) unless report_path.nil? | ||
265 | end | ||
266 | |||
267 | def load_report_by_id(report) | ||
268 | report_glob = "%s/*/%s.yaml" % [get_server_reports_dir, report] | ||
269 | Dir.glob(report_glob).map do |report_path| | ||
270 | puts report_path | ||
271 | load_report(report_path) unless report_path.nil? | ||
272 | end.first | ||
273 | end | ||
274 | |||
275 | def load_last_report_for_node(nodename) | ||
276 | report_path = get_reports_for_node(nodename).last | ||
277 | load_report(report_path) unless report_path.nil? | ||
278 | end | ||
279 | |||
280 | def print_reports_for_node(nodename) | ||
281 | puts color(:bold, "Reports for %s" % nodename) | ||
282 | get_reports_for_node(nodename).each do |report_path| | ||
283 | prefix = File.basename(report_path, ".*") | ||
284 | report = load_report(report_path) | ||
285 | print_report_oneliner(report, prefix) | ||
286 | end | ||
287 | end | ||
288 | |||
289 | def print_report_oneliner(report, prefix) | ||
290 | puts "%s: %s" % [prefix, color(report.status.to_sym, report.status)] | ||
291 | end | ||
292 | |||
293 | def print_node_oneliner(nodename) | ||
294 | report = load_last_report_for_node(nodename) | ||
295 | print_report_oneliner(report, report.name) unless report.nil? | ||
296 | end | ||
297 | |||
298 | def print_server_nodes_status | ||
299 | puts color(:bold, 'Nodes list') | ||
300 | dir = get_server_reports_dir | ||
301 | puts color(:bold, 'No nodes found!') unless Puppet::FileSystem.exist?(dir) | ||
302 | Dir.glob("%s/*/" % dir).each do |node_path| | ||
303 | print_node_oneliner(File.basename(node_path)) | ||
304 | end | ||
305 | end | ||
306 | |||
307 | def initialize_puppet | ||
308 | require 'puppet/util/run_mode' | ||
309 | Puppet.settings.preferred_run_mode = :agent | ||
310 | Puppet.settings.initialize_global_settings([]) | ||
311 | Puppet.settings.initialize_app_defaults(Puppet::Settings.app_defaults_for_run_mode(Puppet.run_mode)) | ||
312 | end | ||
313 | |||
314 | initialize_puppet | ||
315 | |||
316 | opt = OptionParser.new | ||
317 | |||
318 | @options = { | ||
319 | :logs => false, | ||
320 | :history => false, | ||
321 | :server => false, | ||
322 | :node => nil, | ||
323 | :motd => false, | ||
324 | :motd_path => '/etc/motd', | ||
325 | :count => 20, | ||
326 | :report => Puppet[:lastrunreport], | ||
327 | :reportid => nil, | ||
328 | :color => STDOUT.tty?} | ||
329 | |||
330 | opt.on("--logs", "Show logs") do |val| | ||
331 | @options[:logs] = val | ||
332 | end | ||
333 | |||
334 | opt.on("--nodelist", "(Puppet Server) List Puppet nodes and the status of their last report") do |val| | ||
335 | @options[:server] = val | ||
336 | end | ||
337 | |||
338 | opt.on("--node [NODE]", "(Puppet Server) Use last report of a node") do |val| | ||
339 | @options[:node] = val | ||
340 | end | ||
341 | |||
342 | opt.on("--history", "(with --node) Print the reports history for a node") do |val| | ||
343 | @options[:history] = val | ||
344 | end | ||
345 | |||
346 | opt.on("--motd", "Produce an output suitable for MOTD") do |val| | ||
347 | @options[:motd] = val | ||
348 | end | ||
349 | |||
350 | opt.on("--motd-path [PATH]", "Path to the MOTD file to overwrite with the --motd option") do |val| | ||
351 | @options[:motd_path] = val | ||
352 | end | ||
353 | |||
354 | opt.on("--count [RESOURCES]", Integer, "Number of resources to show evaluation times for") do |val| | ||
355 | @options[:count] = val | ||
356 | end | ||
357 | |||
358 | opt.on("--report [REPORT]", "Path to the Puppet last run report") do |val| | ||
359 | abort("Could not find report %s" % val) unless File.readable?(val) | ||
360 | @options[:report] = val | ||
361 | end | ||
362 | |||
363 | opt.on("--report-id [REPORTID]", "(with --node) ID of the report to load") do |val| | ||
364 | @options[:reportid] = val | ||
365 | end | ||
366 | |||
367 | opt.on("--[no-]color", "Colorize the report") do |val| | ||
368 | @options[:color] = val | ||
369 | end | ||
370 | |||
371 | opt.parse! | ||
372 | |||
373 | report = load_report(@options[:report]) unless @options[:server] or @options[:node] | ||
374 | if @options[:node] and not @options[:history] and not @options[:reportid] | ||
375 | report = load_last_report_for_node(@options[:node]) | ||
376 | elsif @options[:node] and @options[:reportid] | ||
377 | report = load_report_for_node(@options[:node], @options[:reportid]) | ||
378 | elsif @options[:reportid] | ||
379 | report = load_report_by_id(@options[:reportid]) | ||
380 | end | ||
381 | |||
382 | if @options[:server] | ||
383 | print_server_nodes_status | ||
384 | elsif @options[:node] and @options[:history] | ||
385 | print_reports_for_node(@options[:node]) | ||
386 | elsif @options[:motd] | ||
387 | print_report_motd(report, @options[:motd_path]) | ||
388 | else | ||
389 | print_report_summary(report) | ||
390 | print_report_metrics(report) | ||
391 | print_summary_by_type(report) | ||
392 | print_slow_resources(report, @options[:count]) | ||
393 | print_files(report, @options[:count]) | ||
394 | print_summary_by_containment_path(report, @options[:count]) | ||
395 | print_logs(report) if @options[:logs] | ||
396 | end | ||
diff --git a/modules/base_installation/manifests/cronie.pp b/modules/base_installation/manifests/cronie.pp index 4df0e37..72f2d8f 100644 --- a/modules/base_installation/manifests/cronie.pp +++ b/modules/base_installation/manifests/cronie.pp | |||
@@ -19,13 +19,13 @@ class base_installation::cronie inherits base_installation { | |||
19 | } | 19 | } |
20 | cron { 'puppet-apply': | 20 | cron { 'puppet-apply': |
21 | ensure => present, | 21 | ensure => present, |
22 | command => "cd $base_installation::puppet_code_path ; puppet apply --test $base_installation::puppet_code_path/manifests/site.pp", | 22 | command => "cd $base_installation::puppet_code_path ; puppet apply $base_installation::puppet_code_path/manifests/site.pp", |
23 | user => root, | 23 | user => root, |
24 | minute => '*/20' | 24 | minute => '*/20' |
25 | } | 25 | } |
26 | cron { 'puppet-apply-reboot': | 26 | cron { 'puppet-apply-reboot': |
27 | ensure => present, | 27 | ensure => present, |
28 | command => "cd $base_installation::puppet_code_path ; puppet apply --test $base_installation::puppet_code_path/manifests/site.pp", | 28 | command => "cd $base_installation::puppet_code_path ; puppet apply $base_installation::puppet_code_path/manifests/site.pp", |
29 | user => root, | 29 | user => root, |
30 | special => "reboot" | 30 | special => "reboot" |
31 | } | 31 | } |
diff --git a/modules/base_installation/manifests/puppet.pp b/modules/base_installation/manifests/puppet.pp index a8dc641..b3ce492 100644 --- a/modules/base_installation/manifests/puppet.pp +++ b/modules/base_installation/manifests/puppet.pp | |||
@@ -27,6 +27,18 @@ class base_installation::puppet ( | |||
27 | } | 27 | } |
28 | ### | 28 | ### |
29 | 29 | ||
30 | file { '/usr/local/sbin/i_puppet_reset_and_apply': | ||
31 | mode => "0755", | ||
32 | ensure => present, | ||
33 | source => "puppet:///modules/base_installation/scripts/puppet_reset_and_apply" | ||
34 | } | ||
35 | |||
36 | file { '/usr/local/sbin/i_puppet_report_print': | ||
37 | mode => "0755", | ||
38 | ensure => present, | ||
39 | source => "puppet:///modules/base_installation/scripts/report_print.rb" | ||
40 | } | ||
41 | |||
30 | unless empty(find_file($password_seed)) { | 42 | unless empty(find_file($password_seed)) { |
31 | $ldap_password = generate_password(24, $password_seed, "ldap") | 43 | $ldap_password = generate_password(24, $password_seed, "ldap") |
32 | $ssha_ldap_seed = generate_password(5, $password_seed, "ldap_seed") | 44 | $ssha_ldap_seed = generate_password(5, $password_seed, "ldap_seed") |