summaryrefslogtreecommitdiffstats
path: root/bin/python/isc/eventlist.py.in
diff options
context:
space:
mode:
Diffstat (limited to 'bin/python/isc/eventlist.py.in')
-rw-r--r--bin/python/isc/eventlist.py.in178
1 files changed, 178 insertions, 0 deletions
diff --git a/bin/python/isc/eventlist.py.in b/bin/python/isc/eventlist.py.in
new file mode 100644
index 0000000..f2f26aa
--- /dev/null
+++ b/bin/python/isc/eventlist.py.in
@@ -0,0 +1,178 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+from collections import defaultdict
+from .dnskey import *
+from .keydict import *
+from .keyevent import *
+
+
+class eventlist:
+ _K = defaultdict(lambda: defaultdict(list))
+ _Z = defaultdict(lambda: defaultdict(list))
+ _zones = set()
+ _kdict = None
+
+ def __init__(self, kdict):
+ properties = [
+ "SyncPublish",
+ "Publish",
+ "SyncDelete",
+ "Activate",
+ "Inactive",
+ "Delete",
+ ]
+ self._kdict = kdict
+ for zone in kdict.zones():
+ self._zones.add(zone)
+ for alg, keys in kdict[zone].items():
+ for k in keys.values():
+ for prop in properties:
+ t = k.gettime(prop)
+ if not t:
+ continue
+ e = keyevent(prop, k, t)
+ if k.sep:
+ self._K[zone][alg].append(e)
+ else:
+ self._Z[zone][alg].append(e)
+
+ self._K[zone][alg] = sorted(
+ self._K[zone][alg], key=lambda event: event.when
+ )
+ self._Z[zone][alg] = sorted(
+ self._Z[zone][alg], key=lambda event: event.when
+ )
+
+ # scan events per zone, algorithm, and key type, in order of
+ # occurrence, noting inconsistent states when found
+ def coverage(self, zone, keytype, until, output=None):
+ def noop(*args, **kwargs):
+ pass
+
+ if not output:
+ output = noop
+
+ no_zsk = True if (keytype and keytype == "KSK") else False
+ no_ksk = True if (keytype and keytype == "ZSK") else False
+ kok = zok = True
+ found = False
+
+ if zone and not zone in self._zones:
+ output("ERROR: No key events found for %s" % zone)
+ return False
+
+ if zone:
+ found = True
+ if not no_ksk:
+ kok = self.checkzone(zone, "KSK", until, output)
+ if not no_zsk:
+ zok = self.checkzone(zone, "ZSK", until, output)
+ else:
+ for z in self._zones:
+ if not no_ksk and z in self._K.keys():
+ found = True
+ kok = self.checkzone(z, "KSK", until, output)
+ if not no_zsk and z in self._Z.keys():
+ found = True
+ zok = self.checkzone(z, "ZSK", until, output)
+
+ if not found:
+ output("ERROR: No key events found")
+ return False
+
+ return kok and zok
+
+ def checkzone(self, zone, keytype, until, output):
+ allok = True
+ if keytype == "KSK":
+ kz = self._K[zone]
+ else:
+ kz = self._Z[zone]
+
+ for alg in kz.keys():
+ output(
+ "Checking scheduled %s events for zone %s, "
+ "algorithm %s..." % (keytype, zone, dnskey.algstr(alg))
+ )
+ ok = eventlist.checkset(kz[alg], keytype, until, output)
+ if ok:
+ output("No errors found")
+ allok = allok and ok
+
+ return allok
+
+ @staticmethod
+ def showset(eventset, output):
+ if not eventset:
+ return
+ output(" " + eventset[0].showtime() + ":", skip=False)
+ for event in eventset:
+ output(" %s: %s" % (event.what, repr(event.key)), skip=False)
+
+ @staticmethod
+ def checkset(eventset, keytype, until, output):
+ groups = list()
+ group = list()
+
+ # collect up all events that have the same time
+ eventsfound = False
+ for event in eventset:
+ # we found an event
+ eventsfound = True
+
+ # add event to current group
+ if not group or group[0].when == event.when:
+ group.append(event)
+
+ # if we're at the end of the list, we're done. if
+ # we've found an event with a later time, start a new group
+ if group[0].when != event.when:
+ groups.append(group)
+ group = list()
+ group.append(event)
+
+ if group:
+ groups.append(group)
+
+ if not eventsfound:
+ output("ERROR: No %s events found" % keytype)
+ return False
+
+ active = published = None
+ for group in groups:
+ if until and calendar.timegm(group[0].when) > until:
+ output(
+ "Ignoring events after %s"
+ % time.strftime("%a %b %d %H:%M:%S UTC %Y", time.gmtime(until))
+ )
+ return True
+
+ for event in group:
+ (active, published) = event.status(active, published)
+
+ eventlist.showset(group, output)
+
+ # and then check for inconsistencies:
+ if not active:
+ output("ERROR: No %s's are active after this event" % keytype)
+ return False
+ elif not published:
+ output("ERROR: No %s's are published after this event" % keytype)
+ return False
+ elif not published.intersection(active):
+ output(
+ "ERROR: No %s's are both active and published "
+ "after this event" % keytype
+ )
+ return False
+
+ return True