#!/usr/bin/python

import os
import sys
import argparse
import libvirt
from lxml import etree

lease_fields = ('time', 'macaddr', 'ipaddr', 'f1', 'f2')

def parse_args():
    p = argparse.ArgumentParser()
    p.add_argument('--connect', '-c')
    p.add_argument('--network', '-N', default='default')
    p.add_argument('--domain', '-D')
    p.add_argument('--leases', '-L')
    p.add_argument('--hosts', '-H')
    p.add_argument('--short', '-s', action='store_true')
    p.add_argument('--reload-dnsmasq', '-r', action='store_true')
    p.add_argument('--update', '-u', action='store_true')
    return p.parse_args()

def read_leases_file(path):
    leases = {}
    with open(path) as fd:
        for leaseEntry in fd.readlines():
            lease = dict(zip(lease_fields, leaseEntry.split()))
            leases[lease['macaddr']] = lease

    return leases

def main():
    args = parse_args()

    if args.domain is None:
        args.domain = '%s.virt' % args.network

    if args.leases is None:
        args.leases = '/var/lib/libvirt/dnsmasq/%s.leases' % args.network
    if args.hosts is None:
        args.hosts = '/var/lib/libvirt/dnsmasq/%s.addnhosts' % args.network

    assert os.path.exists(args.leases)

    with open(args.hosts, 'w') if args.update else sys.stdout as fd:

        leases = read_leases_file(args.leases)

        con = libvirt.openReadOnly(args.connect)
        assert con is not None

        for domId in con.listDomainsID():
            dom = con.lookupByID(domId)
            desc = etree.fromstring(dom.XMLDesc())

            primary=True
            for iface in desc.xpath('/domain/devices/interface[@type="network"]'):
                source = iface.find('source')

                if source.get('network') != args.network:
                    continue

                macaddr = iface.find('mac').get('address')
                alias = iface.find('alias').get('name')

                if macaddr in leases:
                    ipaddr = leases[macaddr]['ipaddr']
                    fd.write('%s\t%s' % (
                        ipaddr,
                        '%s-%s.%s' % (dom.name(), alias, args.domain)))

                    if primary:
                        fd.write(' %s.%s' % (dom.name(), args.domain))
                        if args.short:
                            fd.write(' %s' % (dom.name()))
                    fd.write('\n')
                    primary=False

    # This is a hack barring a more structured way of getting the
    # appropriate dnsmasq pid from NetworkManager.
    if args.reload_dnsmasq:
        os.system('killall -HUP dnsmasq')

if __name__ == '__main__':
    main()