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