pvl/rrd/api.py
author Tero Marttila <terom@paivola.fi>
Sun, 22 Dec 2013 19:03:57 +0200
changeset 336 edaa5d0aa57d
parent 232 5894c70dc6a8
permissions -rw-r--r--
version 0.6.1: pvl.hosts forward/reverse delegation, and include= support
143
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     1
import rrdtool
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     2
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     3
import pvl.invoke
148
92fd0898188d pvl.rrd.api: fix templfile
Tero Marttila <terom@paivola.fi>
parents: 143
diff changeset
     4
import tempfile
143
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     5
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     6
import logging; log = logging.getLogger('pvl.rrd.api')
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     7
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     8
"""
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     9
    Wrapper around the rrdtool python interface
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    10
"""
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    11
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    12
def timestamp (time=None) :
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    13
    """
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    14
        Format datetime value for rrdtool.
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    15
    """
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    16
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    17
    if not time :
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    18
        return None
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    19
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    20
    elif isinstance(time, datetime.datetime) :
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    21
        return int(time.mktime(dt.timetuple()))
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    22
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    23
    elif isinstance(time, datetime.timedelta) :
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    24
        raise NotImplementedError("pvl.rrd.api.timestamp: timedelta")
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    25
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    26
    else :
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    27
        # dunno
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    28
        return str(dt)
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    29
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    30
def cmd (func, pre, opts, post) :
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    31
    """
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    32
        Run the given rrdtool.* function, formatting the given positional arguments and options.
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    33
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    34
        Returns the return value, which varies...
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    35
    """
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    36
    
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    37
    log.debug("%s: %s: %s: %s", func, pre, opts, post)
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    38
    
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    39
    # { opt: arg } -> [ '--opt', arg ]
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    40
    opts = pvl.invoke.optargs(**opts)
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    41
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    42
    # positional arguments
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    43
    pre = pvl.invoke.optargs(*pre)
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    44
    post = pvl.invoke.optargs(*post)
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    45
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    46
    return func(*(pre + opts + post))
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    47
155
9f2967ba81ef pvl.rrd.graph: refactor to use Graph -> Interface -> Mrtg/CollectdIfOctets
Tero Marttila <terom@paivola.fi>
parents: 148
diff changeset
    48
def graph (out=None, *defs, **opts) :
143
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    49
    """
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    50
        Render a graph image and/or print a report from data stored in one or several RRDs.
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    51
        
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    52
            out     - None  -> tempfile
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    53
                    - False -> stdout
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    54
                    - path  -> write to file
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    55
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    56
        Returns:
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    57
            (width, height)         - pixel dimensions of the resulting graph image
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    58
            report_output           - any PRINT'd output (?)
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    59
            graph_file              - file-like object containing graph image, unless out=False -> stdout
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    60
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    61
        With out=None, the returned graph_file is a tempfile which will be cleaned up by Python once close()'d!
148
92fd0898188d pvl.rrd.api: fix templfile
Tero Marttila <terom@paivola.fi>
parents: 143
diff changeset
    62
92fd0898188d pvl.rrd.api: fix templfile
Tero Marttila <terom@paivola.fi>
parents: 143
diff changeset
    63
        XXX: tempfile suffix as .png?
143
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    64
    """
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    65
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    66
    if out is None :
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    67
        # tempfile
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    68
        out_file = tempfile.NamedTemporaryFile(suffix='.png', delete=True) # python2.6
148
92fd0898188d pvl.rrd.api: fix templfile
Tero Marttila <terom@paivola.fi>
parents: 143
diff changeset
    69
        out_path = out_file.name
143
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    70
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    71
    elif out is False :
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    72
        out_file = None
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    73
        out_path = '-'
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    74
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    75
    else :
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    76
        # for reading
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    77
        out_path = out
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    78
        out_file = True # open later
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    79
    
148
92fd0898188d pvl.rrd.api: fix templfile
Tero Marttila <terom@paivola.fi>
parents: 143
diff changeset
    80
    log.debug("%s", out_path)
92fd0898188d pvl.rrd.api: fix templfile
Tero Marttila <terom@paivola.fi>
parents: 143
diff changeset
    81
143
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    82
    # XXX: handle tempfile close?
155
9f2967ba81ef pvl.rrd.graph: refactor to use Graph -> Interface -> Mrtg/CollectdIfOctets
Tero Marttila <terom@paivola.fi>
parents: 148
diff changeset
    83
    width, height, out_lines = cmd(rrdtool.graph, (out_path, ), opts, defs)
143
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    84
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    85
    if out_file is True :
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    86
        out_file = open(out_path)
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    87
            
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    88
    return (width, height), out_lines, out_file
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    89
232
5894c70dc6a8 pvl.rrd: api.report()
Tero Marttila <terom@paivola.fi>
parents: 155
diff changeset
    90
def report (*defs, **opts) :
5894c70dc6a8 pvl.rrd: api.report()
Tero Marttila <terom@paivola.fi>
parents: 155
diff changeset
    91
    """
5894c70dc6a8 pvl.rrd: api.report()
Tero Marttila <terom@paivola.fi>
parents: 155
diff changeset
    92
        Render an output-less graph with only PRINT statements as a textual report.
5894c70dc6a8 pvl.rrd: api.report()
Tero Marttila <terom@paivola.fi>
parents: 155
diff changeset
    93
5894c70dc6a8 pvl.rrd: api.report()
Tero Marttila <terom@paivola.fi>
parents: 155
diff changeset
    94
        Returns output lines.
5894c70dc6a8 pvl.rrd: api.report()
Tero Marttila <terom@paivola.fi>
parents: 155
diff changeset
    95
    """
5894c70dc6a8 pvl.rrd: api.report()
Tero Marttila <terom@paivola.fi>
parents: 155
diff changeset
    96
    
5894c70dc6a8 pvl.rrd: api.report()
Tero Marttila <terom@paivola.fi>
parents: 155
diff changeset
    97
    # exec
5894c70dc6a8 pvl.rrd: api.report()
Tero Marttila <terom@paivola.fi>
parents: 155
diff changeset
    98
    width, height, out_lines = cmd(rrdtool.graph, ('/dev/null', ), opts, defs)
5894c70dc6a8 pvl.rrd: api.report()
Tero Marttila <terom@paivola.fi>
parents: 155
diff changeset
    99
5894c70dc6a8 pvl.rrd: api.report()
Tero Marttila <terom@paivola.fi>
parents: 155
diff changeset
   100
    return out_lines
5894c70dc6a8 pvl.rrd: api.report()
Tero Marttila <terom@paivola.fi>
parents: 155
diff changeset
   101
143
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   102
def fetch (rrd, cf, **opts) :
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   103
    """
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   104
        Fetch values from RRD.
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   105
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   106
        Returns
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   107
            (start, end, step)          - xrange(...) for row timestamps
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   108
            (ds, ...)                   - columns (ds name)
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   109
            ((value, ...), ...)         - rows (data by ds)
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   110
    """
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   111
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   112
    return cmd(rrdtool.fetch, (rrd, cf), opts, ())
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   113
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   114
def _fetch (rrd, cf='AVERAGE', resolution=None, start=None, end=None, **opts) :
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   115
    """
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   116
        Yields (timestamp, { ds: value }) for given ds-values, or all.
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   117
    """
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   118
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   119
    steps, sources, rows = fetch(rrd, cf,
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   120
        resolution  = resolution,
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   121
        start       = timestamp(start),
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   122
        end         = timestamp(end),
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   123
        **opts
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   124
    )
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   125
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   126
    for ts, row in zip(xrange(*steps), rows) :
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   127
        yield datetime.fromtimestamp(ts), dict(zip(sources, row))
fb48ba17ae3e pvl.rrd: copy+update from old rrdweb
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   128