hswaw/checkinator: implement support for kea dhcp server

Also bump version number and fix typo in README.

Change-Id: I116ef706d99df4ace70ccceefc6a23d41fd1adb6
Reviewed-on: https://gerrit.hackerspace.pl/c/hscloud/+/1942
Reviewed-by: q3k <q3k@hackerspace.pl>
diff --git a/hswaw/checkinator/at/dhcp.py b/hswaw/checkinator/at/dhcp.py
index bee2ace..df40dae 100644
--- a/hswaw/checkinator/at/dhcp.py
+++ b/hswaw/checkinator/at/dhcp.py
@@ -140,6 +140,26 @@
             lease database. Once this file has been written to disk, the old
             file is renamed dhcpd.leases~, and the new file is renamed
             dhcpd.leases.
+
+        Kea documentation[0] suggests identical behavior:
+
+            For performance reasons, the server does not update the existing
+            client's lease in the file, as this would potentially require
+            rewriting the entire file. Instead, it simply appends the new lease
+            information to the end of the file; the previous lease entries for
+            the client are not removed.
+
+            [ ... ]
+
+            Lease file cleanup is performed by a separate process (in the
+            background) to avoid a performance impact on the server process. To
+            avoid conflicts between two processes using the same lease files,
+            the LFC process starts with Kea opening a new lease file; the actual
+            LFC process operates on the lease file that is no longer used by the
+            server. There are also other files created as a side effect of the
+            lease file cleanup
+
+        [0]: https://kea.readthedocs.io/en/latest/arm/dhcp4-srv.html#why-is-lease-file-cleanup-necessary
         """
         while True:
             try:
@@ -232,3 +252,16 @@
         offset, devices = parse_isc_dhcpd_leases(f)
         self.update(devices)
         return offset
+
+class KeaUpdater(MtimeUpdater):
+    def file_changed(self, f):
+        leases = ActiveDevices()
+        for line in f:
+            # header line
+            if(line.startswith('address,')):
+                continue
+            # taken directly from kea leases file header
+            address, hwaddr, client_id, valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, state, user_context, pool_id = line.split(',')
+            leases.add(DhcpLease(hwaddr, int(expire) - int(valid_lifetime), address, hostname))
+        self.update(leases)
+        return f.tell()