--- a/pvl/dhcp/hosts.py Sun Feb 10 16:52:51 2013 +0200
+++ b/pvl/dhcp/hosts.py Sun Feb 10 18:31:38 2013 +0200
@@ -23,6 +23,19 @@
log.info("Creating database tables: dhcp_hosts")
db.dhcp_hosts.create(self.db.engine, checkfirst=True)
+ def select (self, distinct=(db.dhcp_hosts.c.gw, db.dhcp_hosts.c.ip), interval=None) :
+ """
+ SELECT unique gw/ip hosts, for given interval.
+ """
+
+ query = db.select(distinct, distinct=True)
+
+ if interval :
+ # timedelta
+ query = query.where(db.func.now() - db.dhcp_hosts.c.last_seen < interval)
+
+ return self.db.select(query)
+
def insert (self, attrs) :
"""
INSERT new host
@@ -119,4 +132,122 @@
log.info("Insert: %s", attrs)
self.insert(attrs)
+import configobj
+from pvl.verkko.utils import IPv4Address, IPv4Network
+class DHCPHostRule (object) :
+ """
+ A rule matching DHCP hosts.
+ """
+
+ @classmethod
+ def load (cls, file, name=None) :
+ """
+ Load from config file.
+ """
+
+ config = configobj.ConfigObj(file)
+
+ return cls.load_section(name, config)
+
+ @classmethod
+ def load_section (cls, name, section) :
+ """
+ Rule from sub-sections and section.
+ """
+
+ # recurse
+ rules = tuple(cls.load_section(subsection, section[subsection]) for subsection in section.sections)
+
+ # rule
+ attrs = dict((name, section[name]) for name in section.scalars)
+
+ try :
+ return cls.config(name, rules, **attrs)
+
+ except ValueError as ex :
+ raise ValueError("[%s] %s" % (name, ex))
+
+ @classmethod
+ def config (cls, name, rules, gateway=None, network=None, interval=None) :
+ """
+ Rule from section.
+ """
+
+ if interval :
+ log.warn("%s: interval: not implemented", name)
+
+ if network :
+ network = IPv4Network(network)
+ else :
+ network = None
+
+ return cls(name, rules,
+ gateway = gateway,
+ network = network,
+ )
+
+ @classmethod
+ def rule (cls, name, gateway=None, network=None) :
+ if network :
+ network = IPv4Network(network)
+ else :
+ network = None
+
+ return cls(name, (),
+ gateway = gateway,
+ network = network,
+ )
+
+ def __init__ (self, name, rules, gateway=None, network=None) :
+ """
+ Match as name by gateway/network.
+ """
+
+ self.name = name
+ self.rules = rules
+
+ self.gateway = gateway
+ self.network = network
+
+ log.info("%s: gateway=%s, network=%s: %s", name, gateway, network, ' '.join(str(rule) for rule in rules))
+
+ def match (self, host) :
+ """
+ Match against given host.
+ """
+
+ if self.gateway and host.gw != self.gateway :
+ return False
+
+ if self.network and IPv4Address(host.ip) not in self.network :
+ return False
+
+ return True
+
+ def apply (self, host) :
+ """
+ Match host against our rule and any sub rules, returning matching DHCPHostRule, or None.
+ """
+
+ match = self.match(host)
+
+ log.debug("%s: match: %s: %s", self, host, match)
+
+ if not match :
+ return
+
+ for rule in self.rules :
+ apply = rule.apply(host)
+
+ if apply :
+ return apply
+
+ log.debug("%s: apply: %s", self, host)
+
+ return self
+
+ def __str__ (self) :
+ return self.name or ''
+
+