#!/usr/bin/python # -*- encoding: utf-8 -*- import optparse import os import subprocess import sys import tempfile from xml.etree import ElementTree as ET suffixnew = '.new' suffixold = '.orig' # Options parser = optparse.OptionParser() parser.add_option('', '--expect', dest='expect', type='int', default=2, metavar=2, help='Number of expected DS') parser.add_option('', '--addds', dest='addds', type='int', default=2, metavar=2, help='Number of DS to add/append') parser.add_option('', '--adddstype', dest='adddstype', default='GAUGE', metavar='GAUGE', help='Type of new DS') parser.add_option('', '--rename', action='store_true', dest='rename', help='Rename old RRD to ".old", new to ".rrd"') parser.add_option('-v', '', action='count', dest='verb', help='Verbose output') (options, args) = parser.parse_args() def add_ds(filename): # rrdtool dump cmdarray = ['rrdtool', 'dump', filename] if options.verb: print 'Dump RRD data out of "%s"' % filename cmd = subprocess.Popen(cmdarray, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (s_out, s_err) = cmd.communicate() if len(s_err) != 0: return (False, s_err[0:255],) # Read file if options.verb: print 'Parse file %s' % filename xml = ET.ElementTree(ET.XML(s_out)) xroot = xml.getroot() # Add "rrd -> ds" if options.verb: print 'add rrd -> ds' dss = xroot.findall('ds') if len(dss) != options.expect: return (False, 'Found %s but expected %s datasources in "rrd"!' % (len(dss), options.expect), ) idx = xroot.getchildren().index(dss[-1]) for name_nr in xrange(len(dss)+1, len(dss)+options.addds+1): idx += 1 ds = ET.Element('ds') subs = ( ('name', str(name_nr),), ('type', 'GAUGE',), ('minimal_heartbeat', '8460'), ('min', 'NaN'), ('max', 'NaN'), ('last_ds', '0'), ('value', '0.0000000000e+00'), ('unknown_sec', ' 0 '), ) for s in subs: el = ET.SubElement(ds, s[0]) el.text = s[1] xroot.insert(idx, ds) # Add "rrd -> rra* -> cdp_prep -> ds" # " -> database -> v" for rra in xroot.findall('rra'): if options.verb: print 'Add "rrd -> rra* -> cdp_prep -> ds' cdpprep = rra.find('cdp_prep') dss = cdpprep.findall('ds') if len(dss) != options.expect: return (False, ' Found %s but expected %s datasources in "cdp_prep"!' % (filename, len(dss), options.expect), ) idx = cdpprep.getchildren().index(dss[-1]) for name_nr in xrange(len(dss)+1, len(dss)+options.addds+1): idx += 1 ds = ET.Element('ds') subs = ( ('primary_value', '0.0000000000e+00',), ('secondary_value', '0.0000000000e+00',), ('value', '0.0000000000e+00',), ('unknown_datapoints', '0',), ) for s in subs: el = ET.SubElement(ds, s[0]) el.text = s[1] cdpprep.insert(idx, ds) if options.verb: print 'Add "rrd -> rra* -> database -> v' database = rra.find('database') rows = database.findall('row') for row in rows: for nr in xrange(0, options.addds): v = ET.SubElement(row, 'v') v.text = 'NaN' # Write temp XML file if options.verb: print 'Dump XML data to temporary file' (tfd, tfn) = tempfile.mkstemp() os.close(tfd) xml.write(tfn, 'utf-8') # Build new RRD file cmdarray = ['rrdtool', 'restore', tfn, filename + suffixnew] print 'Build new RRD file "%s"' % (filename + suffixnew) cmd = subprocess.Popen(cmdarray, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (s_out, s_err) = cmd.communicate() os.remove(tfn) if len(s_err) != 0: return (False, s_err[0:255],) return (True, None,) def get_perms(filename): return os.stat(filename) def set_perms(filename, stat): os.chown(filename, stat.st_uid, stat.st_gid) os.chmod(filename, stat.st_mode) def main(): goodfiles = [] badfiles = [] if os.geteuid() == 0: fixperms = True else: fixperms = False for filename in args: if os.access(filename, os.R_OK): if fixperms: stat = get_perms(filename) (sucessful, reason,) = add_ds(filename) if sucessful: goodfiles.append( filename ) if fixperms: set_perms(filename + suffixnew, stat) else: badfiles.append( (filename, reason,) ) else: badfiles.append( (filename, 'could not read',) ) if options.rename: for fn in goodfiles: try: os.rename(fn, fn + suffixold) except OSError: print 'Could not rename from "%s" to "%s"' % (fn, fn + suffixold) continue try: os.rename(fn + suffixnew, fn) except OSError: print 'Could not rename from "%s" to "%s"' % (fn + suffixnew, fn) continue exitcode = 0 if len(goodfiles) > 0: print 'Sucessful converted:' for fn in goodfiles: print '- %s' %fn print '\n\n' if len(badfiles) > 0: print 'Not converted:' for (fn, reason) in badfiles: print '- %s: %s' % (fn, reason.lstrip().rstrip()) exitcode = 1 sys.exit(exitcode) if __name__ == '__main__': main()