--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pvl/dns/serial.py Thu May 16 01:14:35 2013 +0300
@@ -0,0 +1,105 @@
+"""
+ Generating zone serials.
+"""
+
+import datetime
+
+import logging; log = logging.getLogger('pvl.dns.serial')
+
+# date fmt to use in serial
+DATE_FMT = '%Y%m%d'
+DATE_LEN = 8
+
+SERIAL_FMT = "{date:8}{count:02}"
+SERIAL_LEN = 10
+
+def format_serial (date, count) :
+ return SERIAL_FMT.format(date=date.strftime(DATE_FMT), count=count)
+
+def next_count (value, date, count) :
+ """
+ Return serial with next count.
+ """
+
+ count += 1
+
+ # check
+ if count > 99 :
+ serial = str(value + 1)
+
+ log.warn("Serial count rollover: %s, %s; fallback -> %s", date, count, serial)
+
+ return serial
+
+ return format_serial(date, count)
+
+def update_serial (serial) :
+ """
+ Parse given serial number (string), returning an updated serial, based on date.
+ """
+
+ today = datetime.date.today()
+
+ # handle
+ if not serial :
+ # fresh
+ log.info("Setting initial serial: %s01", today)
+
+ return format_serial(today, 1)
+
+ elif len(serial) != SERIAL_LEN :
+ log.warn("Invalid serial format: %s", serial)
+
+ value = int(serial)
+ serial = str(value + 1)
+
+ log.info("Incrementing serial: %d -> %s", value, serial)
+
+ return serial
+
+ else :
+ # parse
+ value = int(serial)
+
+ try :
+ date = datetime.datetime.strptime(serial[:DATE_LEN], DATE_FMT).date()
+ count = int(serial[DATE_LEN:])
+
+ except ValueError, e :
+ # invalid date/count format?
+ log.warn("Unable to parse serial: %s: %s", serial, e)
+
+ serial = str(value + 1)
+
+ log.info("Incrementing serial: %d -> %s", value, serial)
+
+ return serial
+
+ log.debug("old serial=%s, value=%d, date=%s, count=%s", serial, value, date, count)
+
+ # update
+ if date < today :
+ log.info("Updating to today: %s -> %s", date, today)
+
+ # update date
+ return format_serial(today, 1)
+
+ elif date == today :
+ # keep date, update count
+ log.info("Updating today's count: %s, %s", date, count)
+
+ # handle count rollover
+ return next_count(value, date, count)
+
+ elif date > today :
+ # keep, update count
+ serial = next_count(value, date, count)
+
+ log.warn("Serial in future; incrementing count: %s, %s -> %s", date, count, serial)
+
+ return serial
+
+ else :
+ raise Exception("Invalid serial: %s:%s", old_date, old_count)
+
+