Package Products :: Package ZenRRD :: Module zenstep |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenRRD.zenstep

      1  ###########################################################################
      2  #
      3  # This program is part of Zenoss Core, an open source monitoring platform.
      4  # Copyright (C) 2007, Zenoss Inc.
      5  #
      6  # This program is free software; you can redistribute it and/or modify it
      7  # under the terms of the GNU General Public License version 2 as published by
      8  # the Free Software Foundation.
      9  #
     10  # For complete information please visit: http://www.zenoss.com/oss/
     11  #
     12  ###########################################################################
     13
     14  __doc__='''zenstep
     15
     16  Re-write an RRD files to have a different (larger) step.
     17
     18  $Id$
     19  '''
     20
     21  import Globals
     22  from Products.ZenModel.PerformanceConf import performancePath
     23  from Products.ZenUtils.ZCmdBase import ZCmdBase
     24
     25  import os
     26  from itertools import *
     27  import rrdtool
     28  import logging
     29  log = logging.getLogger('zen.updateStep')
     30
     31 -class UpdateStep(ZCmdBase):
     32      """Run over the rrd files in a directory and write the data
     33      into updated config files"""
     34
     35 -    def processRRA(self, fullpath, rra, info, dump):
     36          "process one archive in the file"
     37          step = info['step']
     38          end = info['last_update']
     39          pdp_per_row = rra['pdp_per_row']
     40          rows = rra['rows']
     41          resolution = step*pdp_per_row
     42          start = end - resolution*rows
     43          start = start/resolution*resolution
     44          end = end/resolution*resolution
     45          data = rrdtool.fetch(fullpath,
     46                               'AVERAGE',
     47                               '--resolution', str(resolution),
     48                               '--start', str(start),
     49                               '--end', str(end))
     50          (start, end, resolution), unused, data = data
     51          rnd = lambda x: x
     52          if info['ds[ds0].type'] == 'COUNTER':
     53              rnd = lambda x: int(x+0.5)
     54          result = []
     55          for i, (v,) in enumerate(data):
     56              if v != None:
     57                  dump[start + i*resolution] = rnd(v)
     58          return result
     59
     60
     61 -    def process(self, fullpath):
     62          "convert a single file"
     63          log.debug("processing %s" % fullpath)
     64          newpath = os.path.join(os.path.dirname(fullpath),
     65                                 '.' + os.path.basename(fullpath))
     66          # get type, old step
     67          info = rrdtool.info(fullpath)
     68          dataType = info['ds[ds0].type']
     69
     70          try:
     71              os.unlink(newpath)
     72          except OSError:
     73              pass
     74
     75          rraList = []
     76          for rraIndex in count():
     77              rra = {}
     78              rra['pdp_per_row'] = info.get('rra[%s].pdp_per_row' % rraIndex)
     79              rra['rows'] = info.get('rra[%s].rows' % rraIndex)
     80              if rra['pdp_per_row'] is None or rra['rows'] is None:
     81                  break
     82              rraList.append(rra)
     83
     84          # Collect some information about the current file:
     85          # how far back can the data go?
     86          earliest = info['last_update']
     87
     88          # how wide is the biggest data point?
     89          biggest = 0
     90
     91          for rra in rraList:
     92              size = rra['pdp_per_row'] * info['step']
     93              earliest = min(earliest, info['last_update'] - rra['rows'] * size)
     94              biggest = max(biggest, size)
     95
     96          # create a file with the correct step to accept the data
     97          rrdtool.create(
     98              newpath,
     99              'DS:ds0:%s:%d:U:U' % (dataType, biggest * 2),
    100              '--start', str(earliest),
    101              '--step', str(self.options.step),
    102              *self.defaultRRDCommand.split())
    103
    104          # extract the time and values from each archive
    105          updates = {}
    106
    107          for rra in rraList:
    108              self.processRRA(fullpath, rra, info, updates)
    109
    110          # get the times in order
    111          updates = updates.items()
    112          updates.sort()
    113          rrdtool.update(newpath, *[('%d@%s' % (t, v)) for t, v in updates])
    114          # use a reasonable heartbeat
    115          rrdtool.tune(newpath, '-h','ds0:%d' % (self.options.step*3))
    116          if self.options.commit:
    117              os.rename(newpath, fullpath)
    118
    119
    120 -    def run(self):
    121          monitors = self.dmd.Monitors.Performance
    122          monitor = monitors._getOb(self.options.monitor)
    123          self.defaultRRDCommand = monitor.getDefaultRRDCreateCommand()
    124          if self.options.filename:
    125              self.process(self.options.filename)
    126          else:
    127              for root, dirs, files in os.walk(self.options.root):
    128                  for filename in files:
    129                      # skip working files
    130                      if filename.startswith('.'): continue
    131                      if not filename.endswith('.rrd'): continue
    132                      fullpath = os.path.join(root, filename)
    133                      self.process(fullpath)
    134
    135
    136 -    def buildOptions(self):
    137          ZCmdBase.buildOptions(self)
    138          self.parser.add_option('-s', '--step', dest='step', type='int',
    139                                 default=300, help='Default step size in seconds')
    140          self.parser.add_option('-r', '--root', dest='root',
    141                                 default=performancePath(''),
    142                                 help='Root tree to convert')
    143          self.parser.add_option('-f', '--file', dest='filename',
    144                                 help='Root tree to convert')
    145          self.parser.add_option('--commit', dest='commit', action='store_true',
    146                                 default=False,
    147                                 help='Really put the converted files in place.')
    148          self.parser.add_option('--monitor', dest='monitor',
    149                                 default='localhost',
    150                                 help='Name of this collection host.')
    151
    152  if __name__ == '__main__':
    153      us = UpdateStep()
    154      us.run()
    155