pvl/verkko/hosts.py
author Tero Marttila <terom@paivola.fi>
Wed, 10 Oct 2012 21:59:34 +0300
changeset 1 731d2df704f0
parent 0 91c739202f06
child 3 5990b188c54b
permissions -rw-r--r--
fixup index + non-chunked response (?) + hosts + evil hardcoded db url
from pvl.verkko import db, web

from pvl.html import tags as html

import socket # dns

import logging; log = logging.getLogger('pvl.verkko.hosts')

# XXX: this should actually be DHCPHost
class Host (object) :
    DATE_FMT = '%Y%m%d'

    def __init__ (self, ip, mac, name=None) :
        self.ip = ip
        self.mac = mac
        self.name = name
   
    def render_mac (self) :
        if not self.mac :
            return None

        elif len(self.mac) > (6 * 2 + 5) :
            return u'???'

        else :
            return unicode(self.mac)

    def render_name (self) :
        if self.name :
            return self.name.decode('ascii', 'replace')
        else :
            return None

    def when (self) :
        return '{frm} - {to}'.format(
                frm = self.first_seen.strftime(self.DATE_FMT),
                to  = self.last_seen.strftime(self.DATE_FMT),
        )

    def dns (self) :
        """
            Reverse-DNS lookup.
        """

        if not self.ip :
            return None
        
        sockaddrs = set(sockaddr for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo(self.ip, 0, 0, 0, 0, socket.AI_NUMERICHOST))

        for sockaddr in sockaddrs :
            try :
                host, port = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD)
            except socket.gaierror :
                continue

            return host

    def __unicode__ (self) :
        return u"{host.ip} ({host.mac})".format(host=self)

db.mapper(Host, db.dhcp_hosts, properties=dict(
    id      = db.dhcp_hosts.c.rowid,
    #_mac    = db.dhcp_hosts.c.mac,
    #_name   = db.dhcp_hosts.c.name,
))

HOST_SORT = {
    'id':   Host.id,
    'ip':   Host.ip,
    'mac':  Host.mac,
    'name': Host.name,
    'seen': Host.last_seen,
    None:   Host.last_seen.desc(),
}

def render_hosts (hosts, title=None) :
    COLS = (
        #title          sort
        ('#',           None),
        ('IP',          'ip'),
        ('MAC',         'mac'),
        ('Hostname',    'name'),
        ('Seen',        'seen'),
    )

    return html.table(
        html.caption(title) if title else None,
        html.thead(
            html.tr(
                html.th(
                    html.a(href='?sort={name}'.format(name=sort))(title) if sort else (title)
                ) for title, sort in COLS
            )
        ),
        html.tbody(
            html.tr(class_=('alternate' if i % 2 else None), id=host.id)(
                html.td(class_='id')(
                    html.a(href='/hosts/{host.id}'.format(host=host))(
                        '#' #host['rowid'])
                    )
                ),
                html.td(class_='ip')(
                    html.a(href='/hosts/ip/{host.ip}'.format(host=host))(host.ip)
                ),
                html.td(class_='mac')(
                    html.a(href='/hosts/mac/{host.mac}'.format(host=host))(
                        host.render_mac()
                    )
                ),
                html.td(host.render_name()),
                html.td(host.when()),
            ) for i, host in enumerate(hosts)
        )
    )

def render_host (host, hosts) :
    title = 'DHCP Host: {host}'.format(host=host)
    
    attrs = (
            ('IP',          host.ip),
            ('MAC',         host.mac),
            ('Hostname',    host.name),
            ('DNS',         host.dns()),
    )

    return (
        html.h2('Host'),
        html.dl(
            (html.dt(title), html.dd(value)) for title, value in attrs
        ),

        html.h2('Related'),
        render_hosts(hosts),

        html.a(href='/hosts')(html('&laquo;'), 'Back'),
    )

def respond (request, db, path) :
    """
        Handle request
    """

    hosts = db.query(Host)

    # sort ?
    sort = request.args.get('sort')
    sort = HOST_SORT[sort]
    log.debug("sort: %s", sort)

    hosts = hosts.order_by(sort)
    
    # index
    if not path :
        title = "DHCP Hosts"
        html = render_hosts(hosts)
    
    # id
    elif len(path) == 1 :
        id, = path
        id = int(id)

        host = hosts.get(id)
        hosts = hosts.filter((Host.ip == host.ip) | (Host.mac == host.mac))
        
        # render
        title = "DHCP Host: {host}".format(host=unicode(host))
        html = render_host(host, hosts)
    
    # query
    elif len(path) == 2 :
        attr, value = path
        
        # fake host
        host = { 'ip': None, 'mac': None, 'name': None }
        host[attr] = value

        host = Host(**host)

        # query
        attr = HOST_SORT[attr]
        log.debug("%s == %s", attr, value)

        hosts = hosts.filter(attr == value)
        
        # render
        title = "DHCP Hosts: {value}".format(value=value)
        html = render_host(host, hosts)

    else :
        return Response("Not Found", status=404)

    # render
    html = web.render_layout(title, html)

    return web.Response(html, content_type='text/html; charset=UTF-8')