summaryrefslogtreecommitdiff
path: root/textproc
diff options
context:
space:
mode:
authorgutteridge <gutteridge@pkgsrc.org>2021-09-09 00:21:13 +0000
committergutteridge <gutteridge@pkgsrc.org>2021-09-09 00:21:13 +0000
commit022d251da9b6eabcf31584c5faed4733ba3e8379 (patch)
treeac12ea4dd9f377ab909dd1d26c7456b7193450dd /textproc
parent9e9a3b20dba3ccd74f22587e665e0a27b73c4f87 (diff)
downloadpkgsrc-022d251da9b6eabcf31584c5faed4733ba3e8379.tar.gz
py-isc_dhcp_leases: improve historical lease analysis support
Add two PRs that have been merged in the upstream project. (It simply hasn't had a release cut since 2018.)
Diffstat (limited to 'textproc')
-rw-r--r--textproc/py-isc_dhcp_leases/Makefile3
-rw-r--r--textproc/py-isc_dhcp_leases/distinfo6
-rw-r--r--textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_iscdhcpleases.py168
-rw-r--r--textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_test__iscDhcpLeases.py245
-rw-r--r--textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_test__lease.py86
-rw-r--r--textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_test__lease6.py95
6 files changed, 601 insertions, 2 deletions
diff --git a/textproc/py-isc_dhcp_leases/Makefile b/textproc/py-isc_dhcp_leases/Makefile
index f6b73277a03..92de613a2d2 100644
--- a/textproc/py-isc_dhcp_leases/Makefile
+++ b/textproc/py-isc_dhcp_leases/Makefile
@@ -1,7 +1,8 @@
-# $NetBSD: Makefile,v 1.1 2019/01/06 01:48:50 gutteridge Exp $
+# $NetBSD: Makefile,v 1.2 2021/09/09 00:21:13 gutteridge Exp $
DISTNAME= isc_dhcp_leases-0.9.1
PKGNAME= ${PYPKGPREFIX}-${DISTNAME}
+PKGREVISION= 1
CATEGORIES= textproc python
MASTER_SITES= ${MASTER_SITE_PYPI:=i/isc_dhcp_leases/}
diff --git a/textproc/py-isc_dhcp_leases/distinfo b/textproc/py-isc_dhcp_leases/distinfo
index ab12fd6577c..29eecc0bcfc 100644
--- a/textproc/py-isc_dhcp_leases/distinfo
+++ b/textproc/py-isc_dhcp_leases/distinfo
@@ -1,6 +1,10 @@
-$NetBSD: distinfo,v 1.1 2019/01/06 01:48:50 gutteridge Exp $
+$NetBSD: distinfo,v 1.2 2021/09/09 00:21:13 gutteridge Exp $
SHA1 (isc_dhcp_leases-0.9.1.tar.gz) = ade9f209438045c1cb01b6b3e21587511a914309
RMD160 (isc_dhcp_leases-0.9.1.tar.gz) = e2db1a5675ecba7ba7178e3ae5508a3d40bf11ad
SHA512 (isc_dhcp_leases-0.9.1.tar.gz) = 271b449ae9c90e399596dea986042dd85eac3634005ad602dadcf0489b4213ee3e6845d9ddf69373ce1577da907a74f4d2568394e9dae0dad60ff24c4e9be6f3
Size (isc_dhcp_leases-0.9.1.tar.gz) = 6798 bytes
+SHA1 (patch-isc__dhcp__leases_iscdhcpleases.py) = 5dc3366313d9c25b9bdeaf00da3fb8027a37e702
+SHA1 (patch-isc__dhcp__leases_test__iscDhcpLeases.py) = 94b5ad3b8efd5f07fe49d721b180aab913ca7b47
+SHA1 (patch-isc__dhcp__leases_test__lease.py) = 86518d345541a81dbb0c5053dce0df94b2b32699
+SHA1 (patch-isc__dhcp__leases_test__lease6.py) = c795d104480a155f7b9812d3d1b3979868350514
diff --git a/textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_iscdhcpleases.py b/textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_iscdhcpleases.py
new file mode 100644
index 00000000000..8eeb8ea2792
--- /dev/null
+++ b/textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_iscdhcpleases.py
@@ -0,0 +1,168 @@
+$NetBSD: patch-isc__dhcp__leases_iscdhcpleases.py,v 1.1 2021/09/09 00:21:13 gutteridge Exp $
+
+Support reference datetime for examining historical dhcpd.leases
+https://github.com/MartijnBraam/python-isc-dhcp-leases/pull/32
+https://github.com/MartijnBraam/python-isc-dhcp-leases/pull/33
+
+--- isc_dhcp_leases/iscdhcpleases.py.orig 2018-04-13 13:10:47.000000000 +0000
++++ isc_dhcp_leases/iscdhcpleases.py
+@@ -8,6 +8,31 @@ import gzip
+ from six import iteritems
+
+
++try:
++ utc = datetime.timezone.utc
++except:
++ # Support Python 2.7
++ class UTC(datetime.tzinfo):
++ def fromutc(self, dt):
++ return dt
++
++ def utcffset(self, dt):
++ return datetime.timedelta(0)
++
++ def dst(self, dt):
++ return None
++
++ def tzname(self, dt):
++ return 'UTC'
++
++
++ utc = UTC()
++
++
++def check_datetime(dt):
++ if not (dt is None or (isinstance(dt, datetime.datetime) and dt.tzinfo)):
++ raise ValueError('None or offset-aware datetime required')
++
+ def parse_time(s):
+ """
+ Like datetime.datetime.strptime(s, "%w %Y/%m/%d %H:%M:%S") but 5x faster.
+@@ -23,7 +48,7 @@ def parse_time(s):
+ hour, minute, sec = time_part.split(':')
+ result = datetime.datetime(*map(int, (year, mon, day, hour, minute, sec)))
+
+- return result
++ return result.replace(tzinfo=utc)
+
+
+ def _extract_prop_option(line):
+@@ -108,9 +133,12 @@ class IscDhcpLeases(object):
+ r"ia-(?P<type>ta|na|pd) \"(?P<id>[^\"\\]*(?:\\.[^\"\\]*)*)\" {(?P<config>[\s\S]+?)\n}")
+ regex_iaaddr = re.compile(r"ia(addr|prefix) (?P<ip>[0-9a-f:]+(/[0-9]+)?) {(?P<config>[\s\S]+?)\n\s+}")
+
+- def __init__(self, filename, gzip=False):
++ def __init__(self, filename, gzip=False, now=None):
++ check_datetime(now)
++
+ self.filename = filename
+ self.gzip = gzip
++ self.now = now
+
+ def get(self, include_backups=False):
+ """
+@@ -129,7 +157,7 @@ class IscDhcpLeases(object):
+ if 'hardware' not in properties and not include_backups:
+ # E.g. rows like {'binding': 'state abandoned', ...}
+ continue
+- lease = Lease(block['ip'], properties=properties, options=options, sets=sets)
++ lease = Lease(block['ip'], properties=properties, options=options, sets=sets, now=self.now)
+ leases.append(lease)
+
+ for match in self.regex_leaseblock6.finditer(lease_data):
+@@ -145,7 +173,7 @@ class IscDhcpLeases(object):
+ properties, options, sets = _extract_properties(block['config'])
+
+ lease = Lease6(block['ip'], properties, last_client_communication, host_identifier, block_type,
+- options=options, sets=sets)
++ options=options, sets=sets, now=self.now)
+ leases.append(lease)
+
+ return leases
+@@ -177,7 +205,9 @@ class BaseLease(object):
+ sets Dict of key-value set statement values from this lease
+ """
+
+- def __init__(self, ip, properties, options=None, sets=None):
++ def __init__(self, ip, properties, options=None, sets=None, now=None):
++ check_datetime(now)
++
+ if options is None:
+ options = {}
+
+@@ -189,6 +219,7 @@ class BaseLease(object):
+ self.options = options
+ self.sets = sets
+ _, self.binding_state = properties['binding'].split(' ', 1)
++ self._now = now
+
+ @property
+ def active(self):
+@@ -198,6 +229,15 @@ class BaseLease(object):
+ """
+ return self.binding_state == 'active'
+
++ @property
++ def now(self):
++ """
++ :return: datetime: real current time, unless a historical time is set
++ """
++ if self._now:
++ return self._now
++ else:
++ return datetime.datetime.utcnow().replace(tzinfo=utc)
+
+ class Lease(BaseLease):
+ """
+@@ -214,8 +254,8 @@ class Lease(BaseLease):
+ data Dict of all the info in the dhcpd.leases file for this lease
+ """
+
+- def __init__(self, ip, properties, options=None, sets=None):
+- super(Lease, self).__init__(ip, properties=properties, options=options, sets=sets)
++ def __init__(self, ip, properties, **kwargs):
++ super(Lease, self).__init__(ip, properties=properties, **kwargs)
+ if 'starts' in properties:
+ self.start = parse_time(properties['starts'])
+ else:
+@@ -242,14 +282,14 @@ class Lease(BaseLease):
+ """
+ if self.end is None:
+ if self.start is not None:
+- return self.start <= datetime.datetime.utcnow()
++ return self.start <= self.now
+ else:
+ return True
+ else:
+ if self.start is not None:
+- return self.start <= datetime.datetime.utcnow() <= self.end
++ return self.start <= self.now <= self.end
+ else:
+- return datetime.datetime.utcnow() <= self.end
++ return self.now <= self.end
+
+ def __repr__(self):
+ return "<Lease {} for {} ({})>".format(self.ip, self.ethernet, self.hostname)
+@@ -278,11 +318,8 @@ class Lease6(BaseLease):
+
+ (TEMPORARY, NON_TEMPORARY, PREFIX_DELEGATION) = ('ta', 'na', 'pd')
+
+- def __init__(self, ip, properties, cltt, host_identifier, address_type, options=None, sets=None):
+- options = options or {}
+- sets = sets or {}
+-
+- super(Lease6, self).__init__(ip, properties=properties, options=options, sets=sets)
++ def __init__(self, ip, properties, cltt, host_identifier, address_type, **kwargs):
++ super(Lease6, self).__init__(ip, properties=properties, **kwargs)
+
+ self.type = address_type
+ self.last_communication = cltt
+@@ -315,7 +352,7 @@ class Lease6(BaseLease):
+ if self.end is None:
+ return True
+ else:
+- return datetime.datetime.utcnow() <= self.end
++ return self.now <= self.end
+
+ def __repr__(self):
+ return "<Lease6 {}>".format(self.ip)
diff --git a/textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_test__iscDhcpLeases.py b/textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_test__iscDhcpLeases.py
new file mode 100644
index 00000000000..ee824ab2b7c
--- /dev/null
+++ b/textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_test__iscDhcpLeases.py
@@ -0,0 +1,245 @@
+$NetBSD: patch-isc__dhcp__leases_test__iscDhcpLeases.py,v 1.1 2021/09/09 00:21:13 gutteridge Exp $
+
+Support reference datetime for examining historical dhcpd.leases
+https://github.com/MartijnBraam/python-isc-dhcp-leases/pull/32
+https://github.com/MartijnBraam/python-isc-dhcp-leases/pull/33
+
+--- isc_dhcp_leases/test_iscDhcpLeases.py.orig 2018-04-13 13:10:47.000000000 +0000
++++ isc_dhcp_leases/test_iscDhcpLeases.py
+@@ -1,15 +1,16 @@
++import datetime
+ from unittest import TestCase
+-from isc_dhcp_leases.iscdhcpleases import IscDhcpLeases, Lease, Lease6
++from isc_dhcp_leases.iscdhcpleases import IscDhcpLeases, Lease, Lease6, utc
+ from freezegun import freeze_time
+-from datetime import datetime
+
+ __author__ = 'Martijn Braam <martijn@brixit.nl>'
+
+
+ class TestIscDhcpLeases(TestCase):
+- @freeze_time("2015-07-6 8:15:0")
+- def test_get(self):
+- leases = IscDhcpLeases("isc_dhcp_leases/test_files/debian7.leases")
++ def _test_get(self, now=None):
++ leases = IscDhcpLeases("isc_dhcp_leases/test_files/debian7.leases", now=now)
++ lease_start = datetime.datetime(2013, 12, 10, 12, 57, 4, tzinfo=utc)
++ lease_end = lease_start + datetime.timedelta(minutes=10)
+ result = leases.get()
+ self.assertEqual(len(result), 5)
+ self.assertEqual(result[0].ip, "10.0.0.10")
+@@ -19,11 +20,13 @@ class TestIscDhcpLeases(TestCase):
+ self.assertEqual(result[0].hardware, "ethernet")
+ self.assertEqual(result[0].ethernet, "60:a4:4c:b5:6a:dd")
+ self.assertEqual(result[0].hostname, "")
+- self.assertEqual(result[0].start, datetime(2013, 12, 10, 12, 57, 4))
+- self.assertEqual(result[0].end, datetime(2013, 12, 10, 13, 7, 4))
++ self.assertEqual(result[0].start, lease_start)
++ self.assertEqual(result[0].end, lease_end)
+ self.assertEqual(result[0].sets, {'vendor-class-identifier': 'Some Vendor Identifier'})
+
+- leases = IscDhcpLeases("isc_dhcp_leases/test_files/pfsense.leases")
++ leases = IscDhcpLeases("isc_dhcp_leases/test_files/pfsense.leases", now=now)
++ lease_start = datetime.datetime(2015, 7, 6, 7, 50, 42, tzinfo=utc)
++ lease_end = lease_start + datetime.timedelta(minutes=30)
+ result = leases.get()
+ self.assertEqual(len(result), 2)
+ self.assertEqual(result[0].ip, "10.0.10.72")
+@@ -33,10 +36,10 @@ class TestIscDhcpLeases(TestCase):
+ self.assertEqual(result[0].hardware, "ethernet")
+ self.assertEqual(result[0].ethernet, "64:5a:04:6a:07:a2")
+ self.assertEqual(result[0].hostname, "Satellite-C700")
+- self.assertEqual(result[0].start, datetime(2015, 7, 6, 7, 50, 42))
+- self.assertEqual(result[0].end, datetime(2015, 7, 6, 8, 20, 42))
++ self.assertEqual(result[0].start, lease_start)
++ self.assertEqual(result[0].end, lease_end)
+
+- leases = IscDhcpLeases("isc_dhcp_leases/test_files/dhcpd6-4.2.4.leases")
++ leases = IscDhcpLeases("isc_dhcp_leases/test_files/dhcpd6-4.2.4.leases", now=now)
+ result = leases.get()
+ self.assertEqual(len(result), 2)
+ self.assertEqual(result[0].ip, "2001:610:600:891d::60")
+@@ -48,7 +51,9 @@ class TestIscDhcpLeases(TestCase):
+ self.assertEqual(result[0].binding_state, 'active')
+ self.assertEqual(result[0].preferred_life, 375)
+ self.assertEqual(result[0].max_life, 600)
+- self.assertEqual(result[0].last_communication, datetime(2015, 8, 18, 16, 55, 37))
++ self.assertEqual(
++ result[0].last_communication,
++ datetime.datetime(2015, 8, 18, 16, 55, 37, tzinfo=utc))
+ self.assertEqual(result[0].type, Lease6.NON_TEMPORARY)
+
+ self.assertEqual(result[1].ip, "2001:610:500:fff::/64")
+@@ -60,10 +65,12 @@ class TestIscDhcpLeases(TestCase):
+ self.assertEqual(result[1].binding_state, 'active')
+ self.assertEqual(result[1].preferred_life, 175)
+ self.assertEqual(result[1].max_life, 200)
+- self.assertEqual(result[1].last_communication, datetime(2015, 8, 18, 16, 55, 40))
++ self.assertEqual(
++ result[1].last_communication,
++ datetime.datetime(2015, 8, 18, 16, 55, 40, tzinfo=utc))
+ self.assertEqual(result[1].type, Lease6.PREFIX_DELEGATION)
+
+- leases = IscDhcpLeases("isc_dhcp_leases/test_files/dhcpd6-4.3.3.leases")
++ leases = IscDhcpLeases("isc_dhcp_leases/test_files/dhcpd6-4.3.3.leases", now=now)
+ result = leases.get()
+ self.assertEqual(len(result), 4)
+ self.assertEqual(result[0].ip, "2001:10:10::106")
+@@ -75,7 +82,9 @@ class TestIscDhcpLeases(TestCase):
+ self.assertEqual(result[0].binding_state, 'active')
+ self.assertEqual(result[0].preferred_life, 540)
+ self.assertEqual(result[0].max_life, 864)
+- self.assertEqual(result[0].last_communication, datetime(2016, 1, 6, 14, 50, 34))
++ self.assertEqual(
++ result[0].last_communication,
++ datetime.datetime(2016, 1, 6, 14, 50, 34, tzinfo=utc))
+ self.assertEqual(result[0].type, Lease6.NON_TEMPORARY)
+ self.assertEqual(result[0].sets, dict(iana='2001:10:10:0:0:0:0:106', clientduid='0100011cf710a5002722332b34'))
+
+@@ -88,13 +97,17 @@ class TestIscDhcpLeases(TestCase):
+ self.assertEqual(result[1].binding_state, 'active')
+ self.assertEqual(result[1].preferred_life, 540)
+ self.assertEqual(result[1].max_life, 864)
+- self.assertEqual(result[1].last_communication, datetime(2016, 1, 6, 14, 52, 37))
++ self.assertEqual(
++ result[1].last_communication,
++ datetime.datetime(2016, 1, 6, 14, 52, 37, tzinfo=utc))
+ self.assertEqual(result[1].type, Lease6.PREFIX_DELEGATION)
+ self.assertEqual(result[1].sets, dict(iapd='2001:10:30:ff00:0:0:0:0', pdsize='56',
+ pdnet='2001:10:30:ff00:0:0:0:0/56',
+ clientduid='0100011d344c000025906ba134'))
+
+- leases = IscDhcpLeases("isc_dhcp_leases/test_files/options.leases")
++ leases = IscDhcpLeases("isc_dhcp_leases/test_files/options.leases", now=now)
++ lease_start = datetime.datetime(2016, 2, 27, 7, 11, 41, tzinfo=utc)
++ lease_end = lease_start + datetime.timedelta(hours=2)
+ result = leases.get()
+ self.assertEqual(len(result), 1)
+ self.assertEqual(result[0].ip, "10.10.10.10")
+@@ -104,8 +117,8 @@ class TestIscDhcpLeases(TestCase):
+ self.assertEqual(result[0].hardware, "ethernet")
+ self.assertEqual(result[0].ethernet, "24:65:11:d9:a6:b3")
+ self.assertEqual(result[0].hostname, "KRONOS")
+- self.assertEqual(result[0].start, datetime(2016, 2, 27, 7, 11, 41))
+- self.assertEqual(result[0].end, datetime(2016, 2, 27, 9, 11, 41))
++ self.assertEqual(result[0].start, lease_start)
++ self.assertEqual(result[0].end, lease_end)
+ self.assertEqual(len(result[0].options), 4)
+ self.assertDictEqual(result[0].options,
+ {'agent.DOCSIS-device-class': '2',
+@@ -113,7 +126,9 @@ class TestIscDhcpLeases(TestCase):
+ 'agent.remote-id': 'a4:a2:4a:33:db:e5',
+ 'agent.unknown-9': '0:0:11:8b:6:1:4:1:2:3:0'})
+
+- leases = IscDhcpLeases("isc_dhcp_leases/test_files/static.leases")
++ leases = IscDhcpLeases("isc_dhcp_leases/test_files/static.leases", now=now)
++ lease_start = datetime.datetime(2015, 9, 10, 0, 29, 0, tzinfo=utc)
++ lease_end = None
+ result = leases.get()
+ self.assertEqual(len(result), 1)
+ self.assertEqual(result[0].ip, "10.0.0.15")
+@@ -121,12 +136,28 @@ class TestIscDhcpLeases(TestCase):
+ self.assertEqual(result[0].active, False)
+ self.assertEqual(result[0].binding_state, "free")
+ self.assertEqual(result[0].hardware, "ethernet")
+- self.assertEqual(result[0].start, datetime(2015, 9, 10, 0, 29, 0))
+- self.assertIsNone(result[0].end)
++ self.assertEqual(result[0].start, lease_start)
++ self.assertEqual(result[0].end, lease_end)
++
++ @freeze_time("2015-07-6 8:15:0")
++ def test_get_frozen(self):
++ self._test_get()
++
++ def test_get_historical(self):
++ self._test_get(
++ now=datetime.datetime(2015, 7, 6, 8, 15, 0, tzinfo=utc))
+
+ @freeze_time("2015-06-6 8:15:0")
+ def test_backup_leases(self):
+ leases = IscDhcpLeases("isc_dhcp_leases/test_files/backup.leases")
++ lease_start = [
++ datetime.datetime(2017, 10, 5, 15, 22, 29, tzinfo=utc),
++ datetime.datetime(2017, 10, 10, 12, 5, 14, tzinfo=utc),
++ ]
++ lease_end = [
++ datetime.datetime(2017, 10, 16, 8, 9, 23, tzinfo=utc),
++ None,
++ ]
+ result = leases.get()
+ self.assertEqual(len(result), 1)
+ result = leases.get(include_backups=True)
+@@ -136,19 +167,27 @@ class TestIscDhcpLeases(TestCase):
+ self.assertEqual(result[0].active, False)
+ self.assertEqual(result[0].binding_state, "backup")
+ self.assertEqual(result[0].hardware, "ethernet")
+- self.assertEqual(result[0].start, datetime(2017, 10, 5, 15, 22, 29))
+- self.assertEqual(result[0].end, datetime(2017, 10, 16, 8, 9, 23))
++ self.assertEqual(result[0].start, lease_start[0])
++ self.assertEqual(result[0].end, lease_end[0])
+ self.assertEqual(result[1].ip, "10.0.0.2")
+ self.assertEqual(result[1].valid, False)
+ self.assertEqual(result[1].active, False)
+ self.assertEqual(result[1].binding_state, "backup")
+ self.assertIsNone(result[1].hardware)
+- self.assertEqual(result[1].start, datetime(2017, 10, 10, 12, 5, 14))
+- self.assertIsNone(result[1].end)
++ self.assertEqual(result[1].start, lease_start[1])
++ self.assertEqual(result[1].end, lease_end[1])
+
+ @freeze_time("2015-06-6 8:15:0")
+ def test_epoch_leases(self):
+ leases = IscDhcpLeases("isc_dhcp_leases/test_files/epoch.leases")
++ lease_start = [
++ datetime.datetime(2017, 10, 5, 15, 22, 29, tzinfo=utc),
++ datetime.datetime(2017, 10, 10, 12, 5, 14, tzinfo=utc),
++ ]
++ lease_end = [
++ datetime.datetime(2017, 10, 16, 8, 9, 23, tzinfo=utc),
++ None,
++ ]
+ result = leases.get()
+ self.assertEqual(len(result), 1)
+ result = leases.get(include_backups=True)
+@@ -158,15 +197,15 @@ class TestIscDhcpLeases(TestCase):
+ self.assertEqual(result[0].active, False)
+ self.assertEqual(result[0].binding_state, "backup")
+ self.assertEqual(result[0].hardware, "ethernet")
+- self.assertEqual(result[0].start, datetime(2017, 10, 5, 15, 22, 29))
+- self.assertEqual(result[0].end, datetime(2017, 10, 16, 8, 9, 23))
++ self.assertEqual(result[0].start, lease_start[0])
++ self.assertEqual(result[0].end, lease_end[0])
+ self.assertEqual(result[1].ip, "10.0.0.2")
+ self.assertEqual(result[1].valid, False)
+ self.assertEqual(result[1].active, False)
+ self.assertEqual(result[1].binding_state, "backup")
+ self.assertIsNone(result[1].hardware)
+- self.assertEqual(result[1].start, datetime(2017, 10, 10, 12, 5, 14))
+- self.assertIsNone(result[1].end)
++ self.assertEqual(result[1].start, lease_start[1])
++ self.assertEqual(result[1].end, lease_end[1])
+
+ @freeze_time("2015-07-6 8:15:0")
+ def test_get_current(self):
+@@ -201,6 +240,8 @@ class TestIscDhcpLeases(TestCase):
+
+ def test_gzip_handling(self):
+ leases = IscDhcpLeases("isc_dhcp_leases/test_files/debian7.leases.gz", True)
++ lease_start = datetime.datetime(2013, 12, 10, 12, 57, 4, tzinfo=utc)
++ lease_end = lease_start + datetime.timedelta(minutes=10)
+ result = leases.get()
+ self.assertEqual(len(result), 5)
+ self.assertEqual(result[0].ip, "10.0.0.10")
+@@ -210,6 +251,10 @@ class TestIscDhcpLeases(TestCase):
+ self.assertEqual(result[0].hardware, "ethernet")
+ self.assertEqual(result[0].ethernet, "60:a4:4c:b5:6a:dd")
+ self.assertEqual(result[0].hostname, "")
+- self.assertEqual(result[0].start, datetime(2013, 12, 10, 12, 57, 4))
+- self.assertEqual(result[0].end, datetime(2013, 12, 10, 13, 7, 4))
++ self.assertEqual(result[0].start, lease_start)
++ self.assertEqual(result[0].end, lease_end)
+ self.assertEqual(result[0].sets, {'vendor-class-identifier': 'Some Vendor Identifier'})
++
++ def test_naive_time(self):
++ with self.assertRaises(ValueError):
++ IscDhcpLeases("isc_dhcp_leases/test_files/debian7.leases", now=datetime.datetime.now())
diff --git a/textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_test__lease.py b/textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_test__lease.py
new file mode 100644
index 00000000000..50a65827cc5
--- /dev/null
+++ b/textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_test__lease.py
@@ -0,0 +1,86 @@
+$NetBSD: patch-isc__dhcp__leases_test__lease.py,v 1.1 2021/09/09 00:21:13 gutteridge Exp $
+
+Support reference datetime for examining historical dhcpd.leases
+https://github.com/MartijnBraam/python-isc-dhcp-leases/pull/32
+https://github.com/MartijnBraam/python-isc-dhcp-leases/pull/33
+
+--- isc_dhcp_leases/test_lease.py.orig 2018-04-13 13:10:47.000000000 +0000
++++ isc_dhcp_leases/test_lease.py
+@@ -1,7 +1,7 @@
++import datetime
+ from unittest import TestCase
+-from isc_dhcp_leases.iscdhcpleases import Lease
++from isc_dhcp_leases.iscdhcpleases import Lease, utc
+ from freezegun import freeze_time
+-from datetime import datetime
+
+ __author__ = 'Martijn Braam <martijn@brixit.nl>'
+
+@@ -19,14 +19,14 @@ class TestLease(TestCase):
+ 'client-hostname': '"Satellite-C700"'
+ }
+
+- @freeze_time("2015-07-6 8:15:0")
+ def test_init(self):
+ lease = Lease("192.168.0.1", self.lease_data)
+ self.assertEqual(lease.ip, "192.168.0.1")
+ self.assertEqual(lease.hardware, "ethernet")
+ self.assertEqual(lease.ethernet, "60:a4:4c:b5:6a:dd")
+ self.assertEqual(lease.hostname, "Satellite-C700")
+- self.assertEqual(lease.start, datetime(2013, 12, 10, 12, 57, 4))
++ self.assertEqual(
++ lease.start, datetime.datetime(2013, 12, 10, 12, 57, 4, tzinfo=utc))
+ self.assertIsNone(lease.end)
+ self.assertTrue(lease.valid)
+ self.assertFalse(lease.active)
+@@ -36,21 +36,28 @@ class TestLease(TestCase):
+ lease = Lease("192.168.0.1", self.lease_data)
+ self.assertEqual(repr(lease), '<Lease 192.168.0.1 for 60:a4:4c:b5:6a:dd (Satellite-C700)>')
+
+- @freeze_time("2015-07-6 8:15:0")
+- def test_valid(self):
+- lease = Lease("192.168.0.1", self.lease_data)
++ def _test_valid(self, now=None):
++ lease = Lease("192.168.0.1", self.lease_data, now=now)
+ self.assertTrue(lease.valid) # Lease is forever
+
+- lease.end = datetime(2015, 7, 6, 13, 57, 4)
++ lease.end = datetime.datetime(2015, 7, 6, 13, 57, 4, tzinfo=utc)
+ self.assertTrue(lease.valid) # Lease is within start and end
+
+- lease.end = datetime(2015, 7, 6, 6, 57, 4)
++ lease.end = lease.end - datetime.timedelta(hours=7)
+ self.assertFalse(lease.valid) # Lease is ended
+
+- lease.start = datetime(2015, 7, 6, 12, 57, 4)
+- lease.end = datetime(2015, 7, 6, 13, 57, 4)
++ lease.start = datetime.datetime(2015, 7, 6, 12, 57, 4, tzinfo=utc)
++ lease.end = lease.start + datetime.timedelta(hours=1)
+ self.assertFalse(lease.valid) # Lease is in the future
+
++ @freeze_time("2015-07-6 8:15:0")
++ def test_valid_frozen(self):
++ self._test_valid()
++
++ def test_valid_historical(self):
++ self._test_valid(
++ now=datetime.datetime(2015, 7, 6, 8, 15, 0, tzinfo=utc))
++
+ def test_eq(self):
+ lease_a = Lease("192.168.0.1", self.lease_data)
+ lease_b = Lease("192.168.0.1", self.lease_data)
+@@ -83,8 +90,12 @@ class TestLease(TestCase):
+ lease = Lease("192.168.0.1", self.lease_data)
+ self.assertTrue(lease.valid) # Lease is forever
+
+- lease.end = datetime(2015, 7, 6, 6, 57, 4)
++ lease.end = datetime.datetime(2015, 7, 6, 6, 57, 4, tzinfo=utc)
+ self.assertFalse(lease.valid) # Lease is ended
+
+- lease.end = datetime(2015, 7, 6, 9, 57, 4)
++ lease.end = lease.end + datetime.timedelta(hours=3)
+ self.assertTrue(lease.valid) # Lease is not expired
++
++ def test_naive_time(self):
++ with self.assertRaises(ValueError):
++ Lease("192.168.0.1", self.lease_data, now=datetime.datetime.now())
diff --git a/textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_test__lease6.py b/textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_test__lease6.py
new file mode 100644
index 00000000000..8dc89c8c5d3
--- /dev/null
+++ b/textproc/py-isc_dhcp_leases/patches/patch-isc__dhcp__leases_test__lease6.py
@@ -0,0 +1,95 @@
+$NetBSD: patch-isc__dhcp__leases_test__lease6.py,v 1.1 2021/09/09 00:21:13 gutteridge Exp $
+
+Support reference datetime for examining historical dhcpd.leases
+https://github.com/MartijnBraam/python-isc-dhcp-leases/pull/32
+https://github.com/MartijnBraam/python-isc-dhcp-leases/pull/33
+
+--- isc_dhcp_leases/test_lease6.py.orig 2017-10-18 08:42:39.000000000 +0000
++++ isc_dhcp_leases/test_lease6.py
+@@ -1,13 +1,14 @@
++import datetime
+ from unittest import TestCase
+-from isc_dhcp_leases.iscdhcpleases import Lease6
++from isc_dhcp_leases.iscdhcpleases import Lease6, utc
+ from freezegun import freeze_time
+-from datetime import datetime
+
+ __author__ = 'Martijn Braam <martijn@brixit.nl>'
+
+
+ class TestLease6(TestCase):
+ def setUp(self):
++ self.lease_time = datetime.datetime(2015, 8, 18, 16, 55, 37, tzinfo=utc)
+ self.lease_data = {
+ 'binding': 'state active',
+ 'ends': 'never',
+@@ -15,9 +16,8 @@ class TestLease6(TestCase):
+ 'max-life': '600'
+ }
+
+- @freeze_time("2015-07-6 8:15:0")
+ def test_init(self):
+- lease = Lease6("2001:610:600:891d::60", self.lease_data, datetime(2015, 8, 18, 16, 55, 37),
++ lease = Lease6("2001:610:600:891d::60", self.lease_data, self.lease_time,
+ "4dv\\352\\000\\001\\000\\001\\035f\\037\\342\\012\\000'\\000\\000\\000", "na")
+ self.assertEqual(lease.ip, "2001:610:600:891d::60")
+
+@@ -29,30 +29,38 @@ class TestLease6(TestCase):
+ self.assertEqual(lease.binding_state, 'active')
+ self.assertEqual(lease.preferred_life, 375)
+ self.assertEqual(lease.max_life, 600)
+- self.assertEqual(lease.last_communication, datetime(2015, 8, 18, 16, 55, 37))
++ self.assertEqual(lease.last_communication, self.lease_time)
+ self.assertEqual(lease.type, Lease6.NON_TEMPORARY)
+
+ def test_repr(self):
+- lease = Lease6("2001:610:600:891d::60", self.lease_data, datetime(2015, 8, 18, 16, 55, 37),
++ lease = Lease6("2001:610:600:891d::60", self.lease_data, self.lease_time,
+ "4dv\\352\\000\\001\\000\\001\\035f\\037\\342\\012\\000'\\000\\000\\000", "na")
+ self.assertEqual(repr(lease), '<Lease6 2001:610:600:891d::60>')
+
+- @freeze_time("2015-07-6 8:15:0")
+- def test_valid(self):
+- lease = Lease6("2001:610:600:891d::60", self.lease_data, datetime(2015, 8, 18, 16, 55, 37),
+- "4dv\\352\\000\\001\\000\\001\\035f\\037\\342\\012\\000'\\000\\000\\000", "na")
++ def _test_valid(self, now=None):
++ lease = Lease6("2001:610:600:891d::60", self.lease_data, self.lease_time,
++ "4dv\\352\\000\\001\\000\\001\\035f\\037\\342\\012\\000'\\000\\000\\000", "na",
++ now=now)
+ self.assertTrue(lease.valid) # Lease is forever
+
+- lease.end = datetime(2015, 7, 6, 13, 57, 4)
++ lease.end = datetime.datetime(2015, 7, 6, 13, 57, 4, tzinfo=utc)
+ self.assertTrue(lease.valid) # Lease is before end
+
+- lease.end = datetime(2015, 7, 6, 6, 57, 4)
++ lease.end = lease.end - datetime.timedelta(hours=7)
+ self.assertFalse(lease.valid) # Lease is ended
+
++ @freeze_time("2015-07-6 8:15:0")
++ def test_valid_frozen(self):
++ self._test_valid()
++
++ def test_valid_historical(self):
++ self._test_valid(
++ now=datetime.datetime(2015, 7, 6, 8, 15, 0, tzinfo=utc))
++
+ def test_eq(self):
+- lease_a = Lease6("2001:610:600:891d::60", self.lease_data, datetime(2015, 8, 18, 16, 55, 37),
++ lease_a = Lease6("2001:610:600:891d::60", self.lease_data, self.lease_time,
+ "4dv\\352\\000\\001\\000\\001\\035f\\037\\342\\012\\000'\\000\\000\\000", "na")
+- lease_b = Lease6("2001:610:600:891d::60", self.lease_data, datetime(2015, 8, 18, 16, 55, 37),
++ lease_b = Lease6("2001:610:600:891d::60", self.lease_data, self.lease_time,
+ "4dv\\352\\000\\001\\000\\001\\035f\\037\\342\\012\\000'\\000\\000\\000", "na")
+
+ self.assertEqual(lease_a, lease_b)
+@@ -63,3 +71,9 @@ class TestLease6(TestCase):
+ lease_b.ip = "2001:610:600:891d::60"
+ lease_b.host_identifier = "gd4\352\000\001\000\001\035b\037\322\012\000'\000\000\000"
+ self.assertNotEqual(lease_a, lease_b)
++
++ def test_naive_time(self):
++ with self.assertRaises(ValueError):
++ Lease6("2001:610:600:891d::60", self.lease_data, self.lease_time,
++ "4dv\\352\\000\\001\\000\\001\\035f\\037\\342\\012\\000'\\000\\000\\000", "na",
++ now=datetime.datetime.now())