bin/rrdweb
author Tero Marttila <terom@fixme.fi>
Tue, 25 Jan 2011 01:19:40 +0200
changeset 31 cd9ca8068b09
parent 25 9fa9d881fd87
permissions -rwxr-xr-x
doc: clean up pmacct.conf
#!/usr/bin/env python

import os.path, fnmatch
import optparse, logging

from rrdweb import graph, html


def parse_args (args) :
    global options

    parser = optparse.OptionParser(
        usage   = "%prog [options] <target> [...]"
    )
    
    # generic
    parser.add_option('-q', "--quiet", help="No output in normal operation",
        action='store_const', dest="loglvl", const=logging.WARNING,
    )
    parser.add_option('-v', "--verbose", help="More output",
        action='store_const', dest="loglvl", const=logging.INFO,
    )
    parser.add_option('-D', "--debug", help="Even more output",
        action='store_const', dest="loglvl", const=logging.DEBUG,
    )

    # options
    parser.add_option(      "--rrd-type", default="mrtg", help="RRD style to use: mrtg, collectd_ifoctets")
    
    # paths
    parser.add_option('-R', "--rrd-dir", default="rrd", help="Path to directory containing .rrd files")
    parser.add_option('-I', "--img-dir", default="img", help="Path to directory containing .png files")
    parser.add_option('-W', "--web-dir", default="web", help="Path to directory containing .html files")
    parser.add_option('-T', "--tpl-dir", default="templates", help="Path to directory containing .html templates files")

    # urls
    parser.add_option('-P', "--url-prefix", default="", help="Prefix for URLs")
    parser.add_option(      "--img-url", default="img", help="URL to directory containing .png files")
    parser.add_option(      "--web-url", default="web", help="URL to directory containing .html files")
    
    # defaults
    parser.set_defaults(
        loglvl      = logging.INFO,
    )
    
    ## parse
    options, targets = parser.parse_args(args)
    

    ## apply
    logging.basicConfig(
        format      = "[%(levelname)8s] %(funcName)20s : %(message)s",
        level       = options.loglvl,
    )
    
    return targets


def scan_targets () :
    """
        Scan for targets from rrd_dir
    """
    
    # root dir for searching
    rrd_dir = options.rrd_dir
    
    # recurse
    for dirpath, dirs, files in os.walk(rrd_dir) :
        for name in files :
            # full path
            path = os.path.join(dirpath, name)

            # relative path from rrd_dir
            relpath = path[len(os.path.commonprefix([rrd_dir, path])):]

            # skip dotfiles
            if name.startswith('.') :
                continue
            
            # foo/bar, .rrd
            target, ext = os.path.splitext(relpath)
            
            if ext.lower() == '.rrd' :
                # as target name
                yield target



def check_output_file (path) :
    """
        Create the directory for the given output path if missing
    """
    
    dir, file = os.path.split(path)

    if not os.path.exists(dir) :
        logging.warn("Create directory for output file %s: %s", file, dir)

        os.makedirs(dir)

def target_graph (target, style, interval) : 
    """
        Generate .rrd -> .png for given target
    """

    # XXX: title..
    title = target

    # compose paths
    rrd_path = os.path.join(options.rrd_dir, target) + '.rrd'
    out_path = os.path.join(options.img_dir, style, interval, target) + '.png'

    # create out path if not exists
    check_output_file(out_path)

    logging.debug("%s: %s -> %s", target, rrd_path, out_path)
    
    # graph function to use
    graph_func = getattr(graph, options.rrd_type)

    # graph
    graph_func(style, interval, title, rrd_path, out_path)


def target_html (target, formatter) :
    """
        Generate .html for given target
    """

    # XXX: title..
    title = target
    
    # build paths
    html_path = os.path.join(options.web_dir, target + '.html')
    
    # create out path if not exists
    check_output_file(html_path)

    logging.debug("%s: %s", target, html_path)
    
    # render
    open(html_path, 'w').write(formatter.target(target, title).encode('utf-8'))

def overview_html (targets, formatter) :
    """
        Generate .html index
    """
    
    # paths
    overview_path = os.path.join(options.web_dir, "index.html")

    # create out path if not exists
    check_output_file(overview_path)

    logging.debug("%s", overview_path)
    
    # as (target, title) pairs
    open(overview_path, 'w').write(formatter.overview('/', ((target, target) for target in targets)).encode('utf-8'))


def generate_target (target, formatter) :
    
    # overview
    target_graph(target, 'overview', 'daily')
    
    # details
    for interval in ('daily', 'weekly', 'yearly') :
        target_graph(target, 'detail', interval)

    # html for target
    target_html(target, formatter)


def generate (targets, filters=None):
    if not targets :
        # autodetect
        targets = sorted(list(scan_targets()))
        
        logging.info("Autodetected %d targets", len(targets))

    if filters :
        # filter targets
        targets = [target for target in targets if any(fnmatch.fnmatch(target.name, filter) for filter in filters)]
    
    logging.info("Updating %d targets", len(targets))

    # overview
    formatter = html.Formatter(
        url_prefix      = options.url_prefix,
        img_url         = html.urljoin(options.url_prefix, options.img_url, "%(style)s", "%(interval)s", "%(target)s.png"),
        target_url      = html.urljoin(options.url_prefix, options.web_url, "%(target)s.html"),
    )
    
    # html for overview
    overview_html(targets, formatter)

    for target in targets :
        logging.info("Target: %s", target)
        
        # HTML and PNGs
        generate_target(target, formatter)

def main (args) :
    # parse args
    targets = parse_args(args)
    
    # run
    generate(targets)

if __name__ == '__main__' :
    from sys import argv

    main(argv[1:])