]> git.immae.eu Git - perso/Immae/Projets/Puppet.git/commitdiff
Add helpers and remove logs from cronie
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Sun, 4 Mar 2018 11:28:24 +0000 (12:28 +0100)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Sun, 4 Mar 2018 11:33:05 +0000 (12:33 +0100)
modules/base_installation/files/cronie/puppet-post-merge
modules/base_installation/files/scripts/puppet_reset_and_apply [new file with mode: 0644]
modules/base_installation/files/scripts/report_print.rb [new file with mode: 0644]
modules/base_installation/manifests/cronie.pp
modules/base_installation/manifests/puppet.pp

index 35fa2d7730c734fc7ffaf941e67a821cb6c173bd..ac5e3ff1cc57456ad93054d7fff9a697a1f7f035 100644 (file)
@@ -1,7 +1,7 @@
 #!/bin/bash
 ## Run Puppet locally using puppet apply
 git submodule update --init
-/usr/bin/puppet apply --test `pwd`/manifests/site.pp
+/usr/bin/puppet apply `pwd`/manifests/site.pp
 
 ## Log status of the Puppet run
 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 (file)
index 0000000..ff71aa8
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+cd /etc/puppetlabs/code
+git fetch origin
+
+branch="master"
+if [ -n "$1" ]; then
+  branch="$1"
+fi
+
+git reset --hard origin/$1
+
+git submodule update --init
+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 (file)
index 0000000..632374c
--- /dev/null
@@ -0,0 +1,396 @@
+#!/usr/bin/env ruby
+# This file was modified from its original version at
+# https://github.com/ripienaar/puppet-reportprint/
+#
+# Copyright 2013-2016 R.I.Pienaar and contributors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'puppet'
+require 'pp'
+require 'optparse'
+
+def get_server_reports_dir
+  Puppet.settings[:reportdir]
+end
+
+class ::Numeric
+  def bytes_to_human
+    # Prevent nonsense values being returned for fractions
+    if self >= 1
+      units = ['B', 'KB', 'MB' ,'GB' ,'TB']
+      e = (Math.log(self)/Math.log(1024)).floor
+      # Cap at TB
+      e = 4 if e > 4
+      s = "%.2f " % (to_f / 1024**e)
+      s.sub(/\.?0*$/, units[e])
+    else
+      "0 B"
+    end
+  end
+end
+
+def load_report(path)
+  YAML.load_file(path)
+end
+
+def report_resources(report)
+  report.resource_statuses
+end
+
+def resource_with_evaluation_time(report)
+  report_resources(report).select{|r_name, r| !r.evaluation_time.nil? }
+end
+
+def resource_by_eval_time(report)
+  report_resources(report).reject{|r_name, r| r.evaluation_time.nil? }.sort_by{|r_name, r| r.evaluation_time rescue 0}
+end
+
+def resources_of_type(report, type)
+  report_resources(report).select{|r_name, r| r.resource_type == type}
+end
+
+def color(code, msg, reset=false)
+  colors = {
+    :red       => "\e[31m",
+    :green     => "\e[32m",
+    :yellow    => "\e[33m",
+    :cyan      => "\e[36m",
+    :bold      => "\e[1m",
+    :underline => "\e[4m",
+    :reset     => "\e[0m",
+  }
+
+  colors.merge!(
+    :changed   => colors[:yellow],
+    :unchanged => colors[:green],
+    :failed    => colors[:red]
+  )
+
+  return "%s%s%s%s" % [colors.fetch(code, ""), msg, colors[:reset], reset ? colors.fetch(reset, "") : ""] if @options[:color]
+
+  msg
+end
+
+def print_report_summary(report)
+  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)])
+  puts
+  puts "             Report File: %s" % @options[:report]
+  puts "           Report Status: %s" % report.status
+  puts "          Puppet Version: %s" % report.puppet_version
+  puts "           Report Format: %s" % report.report_format
+  puts "   Configuration Version: %s" % report.configuration_version
+  puts "                    UUID: %s" % report.transaction_uuid rescue nil
+  puts "               Log Lines: %s %s" % [report.logs.size, @options[:logs] ? "" : "(show with --log)"]
+
+  puts
+end
+
+def print_report_motd(report, motd_path)
+  motd = []
+  header = "# #{report.host} #"
+  headline = "#" * header.size
+  motd << headline << header << headline << ''
+
+  motd << "Last puppet run happened at %s in environment %s." % [report.time, report.environment]
+
+  motd << "The result of this puppet run was %s." % color(report.status.to_sym, report.status)
+
+  if report.metrics.empty? or report.metrics["events"].nil?
+    motd << 'No Report Metrics.'
+  else
+    motd << 'Events:'
+    report.metrics["events"].values.each do |metric|
+      i, m, v = metric
+      motd.last << ' ' << [m, v].join(': ') << '.'
+    end
+  end
+
+  motd << '' << ''
+
+  File.write(motd_path, motd.join("\n"))
+end
+
+def print_report_metrics(report)
+  if report.metrics.empty?
+    puts color(:bold, "No Report Metrics")
+    puts
+    return
+  end
+
+  puts color(:bold, "Report Metrics:")
+  puts
+
+  padding = report.metrics.map{|i, m| m.values}.flatten(1).map{|i, m, v| m.size}.sort[-1] + 6
+
+  report.metrics.sort_by{|i, m| m.label}.each do |i, metric|
+    puts "   %s:" % metric.label
+
+    metric.values.sort_by{|j, m, v| v}.reverse.each do |j, m, v|
+      puts "%#{padding}s: %s" % [m, v]
+    end
+
+    puts
+  end
+
+  puts
+end
+
+def print_summary_by_type(report)
+  summary = {}
+
+  report_resources(report).each do |resource|
+    if resource[0] =~ /^(.+?)\[/
+      name = $1
+
+      summary[name] ||= 0
+      summary[name] += 1
+    else
+      STDERR.puts "ERROR: Cannot parse type %s" % resource[0]
+    end
+  end
+
+  puts color(:bold, "Resources by resource type:")
+  puts
+
+  summary.sort_by{|k, v| v}.reverse.each do |type, count|
+    puts "   %4d %s" % [count, type]
+  end
+
+  puts
+end
+
+def print_slow_resources(report, number=20)
+  if report.report_format < 4
+    puts color(:red, "   Cannot print slow resources for report versions %d" % report.report_format)
+    puts
+    return
+  end
+
+  resources = resource_by_eval_time(report)
+
+  number = resources.size if resources.size < number
+
+  puts color(:bold, "Slowest %d resources by evaluation time:" % number)
+  puts
+
+  resources[(0-number)..-1].reverse.each do |r_name, r|
+    puts "   %7.2f %s" % [r.evaluation_time, r_name]
+  end
+
+  puts
+end
+
+def print_logs(report)
+  puts color(:bold, "%d Log lines:" % report.logs.size)
+  puts
+
+  report.logs.each do |log|
+    puts "   %s" % log.to_report
+  end
+
+  puts
+end
+
+def print_summary_by_containment_path(report, number=20)
+  resources = resource_with_evaluation_time(report)
+
+  containment = Hash.new(0)
+
+  resources.each do |r_name, r|
+    r.containment_path.each do |containment_path|
+      #if containment_path !~ /\[/
+        containment[containment_path] += r.evaluation_time
+      #end
+    end
+  end
+
+  number = containment.size if containment.size < number
+
+  puts color(:bold, "%d most time consuming containment" % number)
+  puts
+
+  containment.sort_by{|c, s| s}[(0-number)..-1].reverse.each do |c_name, evaluation_time|
+    puts "   %7.2f %s" % [evaluation_time, c_name]
+  end
+
+  puts
+end
+
+def print_files(report, number=20)
+  resources = resources_of_type(report, "File")
+
+  files = {}
+
+  resources.each do |r_name, r|
+    if r_name =~ /^File\[(.+)\]$/
+      file = $1
+
+      if File.exist?(file) && File.readable?(file) && File.file?(file) && !File.symlink?(file)
+        files[file] = File.size?(file) || 0
+      end
+    end
+  end
+
+  number = files.size if files.size < number
+
+  puts color(:bold, "%d largest managed files" % number) + " (only those with full path as resource name that are readable)"
+  puts
+
+  files.sort_by{|f, s| s}[(0-number)..-1].reverse.each do |f_name, size|
+    puts "   %9s %s" % [size.bytes_to_human, f_name]
+  end
+
+  puts
+end
+
+def get_reports_for_node(nodename)
+  Dir.glob("%s/%s/*.yaml" % [get_server_reports_dir, nodename]).sort_by{|p|File.basename(p, ".*")}
+end
+
+def load_report_for_node(nodename, report)
+  report_path = "%s/%s/%s.yaml" % [get_server_reports_dir, nodename, report]
+  puts report_path
+  load_report(report_path) unless report_path.nil?
+end
+
+def load_report_by_id(report)
+  report_glob = "%s/*/%s.yaml" % [get_server_reports_dir, report]
+  Dir.glob(report_glob).map do |report_path|
+    puts report_path
+    load_report(report_path) unless report_path.nil?
+  end.first
+end
+
+def load_last_report_for_node(nodename)
+  report_path = get_reports_for_node(nodename).last
+  load_report(report_path) unless report_path.nil?
+end
+
+def print_reports_for_node(nodename)
+  puts color(:bold, "Reports for %s" % nodename)
+  get_reports_for_node(nodename).each do |report_path|
+    prefix = File.basename(report_path, ".*")
+    report = load_report(report_path)
+    print_report_oneliner(report, prefix)
+  end
+end
+
+def print_report_oneliner(report, prefix)
+  puts "%s: %s" % [prefix, color(report.status.to_sym, report.status)]
+end
+
+def print_node_oneliner(nodename)
+  report = load_last_report_for_node(nodename)
+  print_report_oneliner(report, report.name) unless report.nil?
+end
+
+def print_server_nodes_status
+  puts color(:bold, 'Nodes list')
+  dir = get_server_reports_dir
+  puts color(:bold, 'No nodes found!') unless Puppet::FileSystem.exist?(dir)
+  Dir.glob("%s/*/" % dir).each do |node_path|
+    print_node_oneliner(File.basename(node_path))
+  end
+end
+
+def initialize_puppet
+  require 'puppet/util/run_mode'
+  Puppet.settings.preferred_run_mode = :agent
+  Puppet.settings.initialize_global_settings([])
+  Puppet.settings.initialize_app_defaults(Puppet::Settings.app_defaults_for_run_mode(Puppet.run_mode))
+end
+
+initialize_puppet
+
+opt = OptionParser.new
+
+@options = {
+  :logs      => false,
+  :history   => false,
+  :server    => false,
+  :node      => nil,
+  :motd      => false,
+  :motd_path => '/etc/motd',
+  :count     => 20,
+  :report    => Puppet[:lastrunreport],
+  :reportid  => nil,
+  :color     => STDOUT.tty?}
+
+opt.on("--logs", "Show logs") do |val|
+  @options[:logs] = val
+end
+
+opt.on("--nodelist", "(Puppet Server) List Puppet nodes and the status of their last report") do |val|
+  @options[:server] = val
+end
+
+opt.on("--node [NODE]", "(Puppet Server) Use last report of a node") do |val|
+  @options[:node] = val
+end
+
+opt.on("--history", "(with --node) Print the reports history for a node") do |val|
+  @options[:history] = val
+end
+
+opt.on("--motd", "Produce an output suitable for MOTD") do |val|
+  @options[:motd] = val
+end
+
+opt.on("--motd-path [PATH]", "Path to the MOTD file to overwrite with the --motd option") do |val|
+  @options[:motd_path] = val
+end
+
+opt.on("--count [RESOURCES]", Integer, "Number of resources to show evaluation times for") do |val|
+  @options[:count] = val
+end
+
+opt.on("--report [REPORT]", "Path to the Puppet last run report") do |val|
+  abort("Could not find report %s" % val) unless File.readable?(val)
+  @options[:report] = val
+end
+
+opt.on("--report-id [REPORTID]", "(with --node) ID of the report to load") do |val|
+  @options[:reportid] = val
+end
+
+opt.on("--[no-]color", "Colorize the report") do |val|
+  @options[:color] = val
+end
+
+opt.parse!
+
+report = load_report(@options[:report]) unless @options[:server] or @options[:node]
+if @options[:node] and not @options[:history] and not @options[:reportid]
+  report = load_last_report_for_node(@options[:node])
+elsif @options[:node] and @options[:reportid]
+  report = load_report_for_node(@options[:node], @options[:reportid])
+elsif @options[:reportid]
+  report = load_report_by_id(@options[:reportid])
+end
+
+if @options[:server]
+  print_server_nodes_status
+elsif @options[:node] and @options[:history]
+  print_reports_for_node(@options[:node])
+elsif @options[:motd]
+  print_report_motd(report, @options[:motd_path])
+else
+  print_report_summary(report)
+  print_report_metrics(report)
+  print_summary_by_type(report)
+  print_slow_resources(report, @options[:count])
+  print_files(report, @options[:count])
+  print_summary_by_containment_path(report, @options[:count])
+  print_logs(report) if @options[:logs]
+end
index 4df0e37de3e09f764fbc4c200f957949365f89a2..72f2d8f709b97b98566b8e54cd1123638fd336a8 100644 (file)
@@ -19,13 +19,13 @@ class base_installation::cronie inherits base_installation {
     }
     cron { 'puppet-apply':
       ensure  => present,
-      command => "cd $base_installation::puppet_code_path ; puppet apply --test $base_installation::puppet_code_path/manifests/site.pp",
+      command => "cd $base_installation::puppet_code_path ; puppet apply $base_installation::puppet_code_path/manifests/site.pp",
       user    => root,
       minute  => '*/20'
     }
     cron { 'puppet-apply-reboot':
       ensure  => present,
-      command => "cd $base_installation::puppet_code_path ; puppet apply --test $base_installation::puppet_code_path/manifests/site.pp",
+      command => "cd $base_installation::puppet_code_path ; puppet apply $base_installation::puppet_code_path/manifests/site.pp",
       user    => root,
       special => "reboot"
     }
index a8dc641949e83edb3c23a2164037e5c88d299596..b3ce49207a67007266df1ba5ca1b1883c76015ff 100644 (file)
@@ -27,6 +27,18 @@ class base_installation::puppet (
   }
   ###
 
+  file { '/usr/local/sbin/i_puppet_reset_and_apply':
+    mode   => "0755",
+    ensure => present,
+    source => "puppet:///modules/base_installation/scripts/puppet_reset_and_apply"
+  }
+
+  file { '/usr/local/sbin/i_puppet_report_print':
+    mode   => "0755",
+    ensure => present,
+    source => "puppet:///modules/base_installation/scripts/report_print.rb"
+  }
+
   unless empty(find_file($password_seed)) {
     $ldap_password = generate_password(24, $password_seed, "ldap")
     $ssha_ldap_seed = generate_password(5, $password_seed, "ldap_seed")