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

# Source Code for Module Products.ZenRRD.zenstep

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