--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/pvl.verkko-rrd-interfaces Sun Jan 27 15:07:04 2013 +0200
@@ -0,0 +1,214 @@
+#!/usr/bin/python
+
+"""
+ Setup symlinks for pvl.verkko-rrd -> collectd based on define host/interface names
+"""
+
+__version__ = '0.1'
+
+import shlex
+import os
+
+import pvl.args
+
+import optparse
+import logging; log = logging.getLogger('main')
+
+def hostjoin (*hosts) :
+ """
+ DNS hostname join.
+ """
+
+ return '.'.join(hosts)
+
+def collectd_interfaces (options, file, collectd_domain) :
+ """
+ Read collectd (host, type-instance, name) items, and yield (collectd-rrd, out-rrd) tuples.
+
+ collectd_domain - append given domain to collectd hosts
+ dir - output directory
+ """
+
+ host = None
+
+ for idx, line in enumerate(file, 1) :
+ line = line.rstrip()
+
+ if not line :
+ continue
+
+ # comment?
+ if line.startswith('#') :
+ continue
+
+ # line
+ parts = shlex.split(line)
+
+ if not line[0].isspace() :
+ host = parts.pop(0)
+
+ # host-spec?
+ if '=' in host :
+ collectd_host, interface_host = host.split('=')
+ else :
+ collectd_host = interface_host = host
+
+ # flip from DNS-ordering -> path-ordering
+ if options.reverse_host :
+ interface_host = '.'.join(reversed(interface_host.split('.')))
+
+ # host has domain in collectd?
+ if collectd_domain :
+ collectd_host = hostjoin(collectd_host, collectd_domain)
+
+ if not parts :
+ # keep host for following lines
+ continue
+
+ port = parts.pop(0)
+
+ # possibly multiple tags..
+ for tag in parts :
+ collectd_name = options.collectd_type + '-' + port + '.rrd'
+ collectd_rrd = os.path.join(options.collectd_rrd, collectd_host, options.collectd_plugin, collectd_name)
+
+ if not os.path.exists(collectd_rrd) :
+ log.warn("%s: non-existant rrd: %s", idx, rrd)
+ continue
+
+ # out
+ interface_rrd = os.path.join(interface_host, tag + '.rrd')
+
+ log.debug("%s: %s", interface_rrd, collectd_rrd)
+
+ yield collectd_rrd, interface_rrd
+
+def sync_links (options, links, dir) :
+ """
+ Sync given (collectd, name) symlinks in given dir.
+ """
+
+ for path, name in links :
+ link = os.path.join(dir, name)
+
+ # sync
+ if os.path.exists(link) :
+ continue
+
+ log.info("%s: %s: %s", dir, link, path)
+
+ yield link, path
+
+def apply_links (options, links) :
+ """
+ Apply given symlinks
+ """
+
+ for link, path in links :
+ linkdir = os.path.dirname(link)
+
+ # do
+ if not os.path.exists(linkdir) :
+ log.warn("mkdir: %s", linkdir)
+ os.mkdir(linkdir)
+
+ print path
+
+ os.symlink(path, link)
+
+COLLECTD_RRD = '/var/lib/collectd/rrd'
+COLLECTD_PLUGIN = 'interfaces'
+COLLECTD_TYPE = 'if_octets'
+
+def parse_argv (argv, doc = __doc__) :
+ """
+ Parse command-line argv, returning (options, args).
+ """
+
+ prog = argv.pop(0)
+ args = argv
+
+ # optparse
+ parser = optparse.OptionParser(
+ prog = prog,
+ usage = '%prog: [options] [<input.txt> [...]]',
+ version = __version__,
+ description = doc,
+ )
+
+ # common
+ parser.add_option_group(pvl.args.parser(parser))
+
+ # options
+ parser.add_option('--collectd-rrd', metavar='PATH', default=COLLECTD_RRD,
+ help="Path to collectd rrd: %default")
+ parser.add_option('--collectd-plugin', metavar='PLUGIN', default=COLLECTD_PLUGIN,
+ help="Collectd plugin to use: %default")
+ parser.add_option('--collectd-type', metavar='TYPE', default=COLLECTD_TYPE,
+ help="Collectd type to use: %default")
+
+ # hostnames
+ parser.add_option('--reverse-host', action='store_true',
+ help="Flip host.domain -> domain.host (default)")
+ parser.add_option('--no-reverse-host', action='store_false', dest='reverse_host',
+ help="Keep host.domain as host.domain")
+ parser.add_option('--domain', metavar='DOMAIN',
+ help="Append domain to collectd hostnames: <input>.txt -> <input>")
+
+ # output
+ parser.add_option('--rrd', metavar='PATH',
+ help="Output directory for .rrd symlinks: <input>.txt -> <input>/")
+ parser.add_option('--noop', action='store_true',
+ help="Scan symlinks, but do not update")
+
+ parser.set_defaults(
+ reverse_host = True,
+ )
+
+ # parse
+ options, args = parser.parse_args(args)
+
+ # apply
+ pvl.args.apply(options)
+
+ return options, args
+
+def main (argv) :
+ options, args = parse_argv(argv)
+
+ for txt in args :
+ # defaults from .txt name
+ base, _ = os.path.splitext(txt)
+ _, basename = os.path.split(base)
+
+ if options.domain is None :
+ domain = '.'.join(reversed(basename.split('.')))
+ else :
+ # may be ''
+ domain = options.domain
+
+ # generate links from spec
+ links = list(collectd_interfaces(options, open(txt),
+ collectd_domain = domain,
+ ))
+
+ # sync missing links
+ links = list(sync_links(options, links,
+ dir = options.rrd or base,
+ ))
+
+ # verbose
+ if not options.quiet :
+ for link, path in links :
+ print link, '->', path
+
+ # apply
+ if not options.noop :
+ apply_links(options, links)
+
+ return 0
+
+if __name__ == '__main__':
+ import sys
+
+ sys.exit(main(sys.argv))