"""
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) :
"""
Format serial as string.
>>> format_serial(datetime.date(2013, 9, 10), 0)
'2013091000'
>>> format_serial(datetime.date(2013, 9, 10), 1)
'2013091001'
"""
assert 0 <= count <= 99
return SERIAL_FMT.format(date=date.strftime(DATE_FMT), count=count)
def next_serial (date, count) :
"""
Return serial with next count.
>>> next_serial(datetime.date(2013, 9, 10), 1)
'2013091002'
>>> next_serial(datetime.date(2013, 9, 10), 99)
'2013091100'
"""
# check
if count < 99 :
return format_serial(date, count + 1)
else:
serial = str(int(format_serial(date, count)) + 1)
log.warn("Serial count rollover: %s, %s; fallback -> %s", date, count, serial)
return serial
def update_serial (serial, today=None) :
"""
Parse given serial number (string), returning an updated serial, based on date.
Raises ValueError on invalid (non-numeric) serial.
>>> print update_serial('', today=datetime.date(2013, 9, 10))
2013091001
>>> print update_serial('13', today=datetime.date(2013, 9, 10))
14
>>> print update_serial('2013083501', today=datetime.date(2013, 9, 10))
2013083502
>>> print update_serial('2013083102', today=datetime.date(2013, 9, 10))
2013091001
>>> print update_serial('2013091002', today=datetime.date(2013, 9, 10))
2013091003
>>> print update_serial('2013091102', today=datetime.date(2013, 9, 10))
2013091103
"""
if not today:
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_serial(date, count)
elif date > today :
# keep, update count
serial = next_serial(date, count)
log.warn("Serial in future; incrementing count: %s, %s -> %s", date, count, serial)
return serial
else :
raise Exception("Impossible serial: %s:%s", date, count)