terom@12: #!/usr/bin/env python terom@5: terom@5: import os.path, fnmatch terom@12: import optparse, logging terom@5: terom@12: from rrdweb import graph, html terom@12: terom@12: terom@12: def parse_args (args) : terom@12: global options terom@12: terom@12: parser = optparse.OptionParser( terom@12: usage = "%prog [options] [...]" terom@12: ) terom@14: terom@14: # generic terom@14: parser.add_option('-q', "--quiet", help="No output in normal operation", terom@14: action='store_const', dest="loglvl", const=logging.WARNING, terom@14: ) terom@14: parser.add_option('-v', "--verbose", help="More output", terom@14: action='store_const', dest="loglvl", const=logging.INFO, terom@14: ) terom@14: parser.add_option('-D', "--debug", help="Even more output", terom@14: action='store_const', dest="loglvl", const=logging.DEBUG, terom@14: ) terom@18: terom@18: # options terom@18: parser.add_option( "--rrd-type", default="mrtg", help="RRD style to use: mrtg, collectd_ifoctets") terom@14: terom@14: # paths terom@12: parser.add_option('-R', "--rrd-dir", default="rrd", help="Path to directory containing .rrd files") terom@12: parser.add_option('-I', "--img-dir", default="img", help="Path to directory containing .png files") terom@12: parser.add_option('-W', "--web-dir", default="web", help="Path to directory containing .html files") terom@12: parser.add_option('-T', "--tpl-dir", default="templates", help="Path to directory containing .html templates files") terom@14: terom@14: # urls terom@12: parser.add_option('-P', "--url-prefix", default="", help="Prefix for URLs") terom@12: parser.add_option( "--img-url", default="img", help="URL to directory containing .png files") terom@12: parser.add_option( "--web-url", default="web", help="URL to directory containing .html files") terom@12: terom@14: # defaults terom@14: parser.set_defaults( terom@14: loglvl = logging.INFO, terom@14: ) terom@14: terom@14: ## parse terom@12: options, targets = parser.parse_args(args) terom@12: terom@14: terom@14: ## apply terom@14: logging.basicConfig( terom@14: format = "[%(levelname)8s] %(funcName)20s : %(message)s", terom@14: level = options.loglvl, terom@14: ) terom@14: terom@12: return targets terom@12: terom@14: terom@14: def scan_targets () : terom@14: """ terom@14: Scan for targets from rrd_dir terom@14: """ terom@18: terom@18: # root dir for searching terom@18: rrd_dir = options.rrd_dir terom@18: terom@18: # recurse terom@18: for dirpath, dirs, files in os.walk(rrd_dir) : terom@18: for name in files : terom@18: # full path terom@18: path = os.path.join(dirpath, name) terom@14: terom@18: # relative path from rrd_dir terom@18: relpath = path[len(os.path.commonprefix([rrd_dir, path])):] terom@14: terom@18: # skip dotfiles terom@18: if name.startswith('.') : terom@18: continue terom@18: terom@18: # foo/bar, .rrd terom@18: target, ext = os.path.splitext(relpath) terom@18: terom@18: if ext.lower() == '.rrd' : terom@18: # as target name terom@18: yield target terom@14: terom@14: terom@12: terom@18: def check_output_file (path) : terom@18: """ terom@18: Create the directory for the given output path if missing terom@18: """ terom@18: terom@18: dir, file = os.path.split(path) terom@12: terom@18: if not os.path.exists(dir) : terom@18: logging.warn("Create directory for output file %s: %s", file, dir) terom@12: terom@18: os.makedirs(dir) terom@14: terom@5: def target_graph (target, style, interval) : terom@12: """ terom@12: Generate .rrd -> .png for given target terom@12: """ terom@12: terom@12: # XXX: title.. terom@12: title = target terom@12: terom@5: # compose paths terom@12: rrd_path = os.path.join(options.rrd_dir, target) + '.rrd' terom@12: out_path = os.path.join(options.img_dir, style, interval, target) + '.png' terom@5: terom@18: # create out path if not exists terom@18: check_output_file(out_path) terom@18: terom@14: logging.debug("%s: %s -> %s", target, rrd_path, out_path) terom@18: terom@18: # graph function to use terom@18: graph_func = getattr(graph, options.rrd_type) terom@14: terom@5: # graph terom@18: graph_func(style, interval, title, rrd_path, out_path) terom@5: terom@14: terom@12: def target_html (target, formatter) : terom@12: """ terom@12: Generate .html for given target terom@12: """ terom@5: terom@12: # XXX: title.. terom@12: title = target terom@12: terom@12: # build paths terom@12: html_path = os.path.join(options.web_dir, target + '.html') terom@18: terom@18: # create out path if not exists terom@18: check_output_file(html_path) terom@14: terom@14: logging.debug("%s: %s", target, html_path) terom@12: terom@12: # render terom@12: open(html_path, 'w').write(formatter.target(target, title)) terom@12: terom@12: def overview_html (targets, formatter) : terom@12: """ terom@12: Generate .html index terom@12: """ terom@12: terom@12: # paths terom@12: overview_path = os.path.join(options.web_dir, "index.html") terom@14: terom@18: # create out path if not exists terom@18: check_output_file(overview_path) terom@18: terom@14: logging.debug("%s", overview_path) terom@12: terom@12: # as (target, title) pairs terom@12: open(overview_path, 'w').write(formatter.overview((target, target) for target in targets)) terom@12: terom@14: terom@14: def generate_target (target, formatter) : terom@14: terom@14: # overview terom@14: target_graph(target, 'overview', 'daily') terom@14: terom@14: # details terom@14: for interval in ('daily', 'weekly', 'yearly') : terom@14: target_graph(target, 'detail', interval) terom@14: terom@14: # html for target terom@14: target_html(target, formatter) terom@14: terom@14: terom@12: def generate (targets, filters=None): terom@14: if not targets : terom@14: # autodetect terom@14: targets = list(scan_targets()) terom@14: terom@14: logging.info("Autodetected %d targets", len(targets)) terom@14: terom@5: if filters : terom@5: # filter targets terom@5: targets = [target for target in targets if any(fnmatch.fnmatch(target.name, filter) for filter in filters)] terom@14: terom@12: logging.info("Updating %d targets", len(targets)) terom@12: terom@5: # overview terom@12: formatter = html.Formatter( terom@12: url_prefix = options.url_prefix, terom@14: img_url = html.urljoin(options.url_prefix, options.img_url, "%(style)s", "%(interval)s", "%(target)s.png"), terom@14: target_url = html.urljoin(options.url_prefix, options.web_url, "%(target)s.html"), terom@5: ) terom@12: terom@12: # html for overview terom@12: overview_html(targets, formatter) terom@5: terom@5: for target in targets : terom@12: logging.info("Target: %s", target) terom@12: terom@14: # HTML and PNGs terom@14: generate_target(target, formatter) terom@12: terom@12: def main (args) : terom@12: # parse args terom@12: targets = parse_args(args) terom@12: terom@12: # run terom@12: generate(targets) terom@5: terom@5: if __name__ == '__main__' : terom@12: from sys import argv terom@5: terom@12: main(argv[1:]) terom@5: