Skip to content

Instantly share code, notes, and snippets.

@JoeButler99
Created January 28, 2016 10:52
Show Gist options
  • Save JoeButler99/9a3e200ef5b950e48682 to your computer and use it in GitHub Desktop.
Save JoeButler99/9a3e200ef5b950e48682 to your computer and use it in GitHub Desktop.
Puppet run analyser: parsing last_run_report.yaml
#!/usr/bin/env python
'''
@author: joebutler99
@about:
This script can analyse a puppet last report to give
detailed analysis of where the execution time is spent
Puppet enterprise stores this file (by default) in: /var/opt/lib/pe-puppet/state/last_run_report.yaml
@examples:
$ python puppet_last_run_report_analyser.py -h
usage: puppet_last_run_report_analyser.py [-h] -f FILENAME [-l LIMITROWS]
Puppet last_run_report.yaml analyser
optional arguments:
-h, --help show this help message and exit
-f FILENAME The location of the report file to analyse
-l LIMITROWS, --limit-results LIMITROWS
Set row limit for the results table.
$ python puppet_last_run_report_analyser.py -f last_run_report.yaml -l 5
Resource Type Time Taken
--------------- ------------
Selmodule 11.0498
File 7.40753
Exec 7.34574
Service 5.02793
Package 1.60277
Containment Time Taken
------------------------------- ------------
Aproject::Selinux 12.6255
Aproject::Splunk::Agent 5.28557
Pe_mcollective::Server::Plugins 3.57463
Aproject::Tripwire::Client 0.962972
Base 0.877463
Manifest Time Taken
----------------------------------------------------------------------------------- ------------
/etc/puppetlabs/puppet/environments/pprod/modules/selinux/manifests/module.pp 12.3087
/etc/puppetlabs/puppet/environments/pprod/modules/splunk/manifests/input/monitor.pp 5.05627
3.92938
/etc/puppetlabs/puppet/environments/pprod/modules/base/manifests/init.pp 1.68767
/etc/puppetlabs/puppet/environments/pprod/modules/aproject/manifests/tripwire.pp 0.962324
Resource Title Time Taken
---------------------- ------------
Selmodule[httpd_1] 1.89811
Selmodule[nrpe_sudo_1] 1.84505
Selmodule[logrotate_1] 1.83417
Selmodule[nrpe_sudo_2] 1.82795
Selmodule[sshd] 1.8242
@requirements:
These should all be available in pip, and work with python 2.7
PyYAML
tabulate
'''
import yaml
import os.path
from tabulate import tabulate
from argparse import ArgumentParser, ArgumentTypeError
import operator
class ReportParser:
def __init__(self,params):
self.params = params
self.limit = self.params.limitrows # Max results per table
self.results = {"resource_name" : {}, "manifest" : {},
"containment" : {}, "resource_type" : {}}
def _add_time_to_group(self,group,name,elapsed_time):
if self.results[group].has_key(name):
self.results[group][name] += elapsed_time
else:
self.results[group][name] = elapsed_time
def _add_resource_times_to_result(self,report):
for resource_name , resource_details in report['resource_statuses'].iteritems():
if not resource_details.has_key('evaluation_time'):
#print resource_name
continue
self._add_time_to_group("resource_name", resource_name,resource_details['evaluation_time'] )
self._add_time_to_group("manifest", resource_details['file'],resource_details['evaluation_time'] )
try: # There are disctint types of containment path
c = resource_details['containment_path'][1]
except:
c = resource_details['containment_path'][0]
self._add_time_to_group("containment", c, resource_details['evaluation_time'])
self._add_time_to_group("resource_type",resource_details["resource_type"], resource_details['evaluation_time'])
def _display_results(self):
sorted_resource_names = sorted(self.results["resource_name"].items(), key=operator.itemgetter(1),reverse=True)
sorted_manifests = sorted(self.results["manifest"].items(), key=operator.itemgetter(1),reverse=True)
sorted_containment = sorted(self.results["containment"].items(), key=operator.itemgetter(1),reverse=True)
sorted_resource_type = sorted(self.results["resource_type"].items(), key=operator.itemgetter(1),reverse=True)
print tabulate(sorted_resource_type[:self.limit],headers=['Resource Type','Time Taken']) + "\n"
print tabulate(sorted_containment[:self.limit],headers=['Containment','Time Taken']) + "\n"
print tabulate(sorted_manifests[:self.limit],headers=['Manifest','Time Taken']) + "\n"
print tabulate(sorted_resource_names[:self.limit],headers=['Resource Title','Time Taken']) + "\n"
def run(self):
with open(self.params.filename,'r') as f:
report = yaml.load(f)
self._add_resource_times_to_result(report)
self._display_results()
class CLIParser:
def check_valid_file(self,filename):
if os.path.isfile(os.path.expanduser(filename)):
return filename
else:
raise ArgumentTypeError("\n\n{0} is not a valid file.\n".format(filename))
def get_params(self):
parser = ArgumentParser(description='Puppet last_run_report.yaml analyser')
parser.add_argument("-f", required=True, action='store', dest="filename", type=self.check_valid_file, help="The location of the report file to analyse")
parser.add_argument("-l","--limit-results", required=False, action="store", dest="limitrows", help="Set row limit for the results table.", default=20,type=int)
return parser.parse_args()
#
# Puppet Yaml Objects
#
def construct_ruby_object(loader, suffix, node):
return loader.construct_yaml_map(node)
def construct_ruby_sym(loader, node):
return loader.construct_yaml_str(node)
#
# Main Execution
#
if __name__ == "__main__":
yaml.add_multi_constructor(u"!ruby/object:", construct_ruby_object)
yaml.add_constructor(u"!ruby/sym", construct_ruby_sym)
cli_params = CLIParser().get_params()
rp = ReportParser(cli_params)
rp.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment