diff options
Diffstat (limited to 'potpourri/rpki-rtr-replay')
-rwxr-xr-x | potpourri/rpki-rtr-replay | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/potpourri/rpki-rtr-replay b/potpourri/rpki-rtr-replay new file mode 100755 index 00000000..6f8de99e --- /dev/null +++ b/potpourri/rpki-rtr-replay @@ -0,0 +1,139 @@ +#!/usr/bin/env python + +# $Id$ +# +# Copyright (C) 2014 Dragon Research Labs ("DRL") +# Portions copyright (C) 2009-2013 Internet Systems Consortium ("ISC") +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notices and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND DRL AND ISC DISCLAIM ALL +# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL OR +# ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA +# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +import asyncore +import bisect +import glob +import logging +import os +import shutil +import sqlite3 +import subprocess +import sys +import time + +import rpki.POW +import rpki.oids +import rpki.rtr.channels +import rpki.rtr.client +import rpki.rtr.generator +import rpki.rtr.pdus +import rpki.rtr.server + +from rpki.rtr.channels import Timestamp + + +class ReplayClock(object): + """ + Internal clock for replaying a set of rpki-rtr database files. + + This class replaces the normal on-disk serial number mechanism with + an in-memory version based on pre-computed data. + + DO NOT USE THIS IN PRODUCTION. + + You have been warned. + """ + + def __init__(self): + self.timestamps = dict((v, sorted(set(Timestamp(int(f.split(".")[0])) + for f in glob.iglob("*.ax.v%d" % v)))) + for v in rpki.rtr.pdus.PDU.version_map) + self.epoch = min(t[0] for t in self.timestamps.itervalues()) + self.offset = self.epoch - Timestamp.now() + self.nonce = rpki.rtr.generator.AXFRSet.new_nonce(0) + + def __nonzero__(self): + return sum(len(t) for t in self.timestamps.itervalues()) > 0 + + def now(self): + now = Timestamp.now(self.offset) + return now + + def read_current(self, version): + now = self.now() + if version is None: + return self.epoch, self.nonce + while len(self.timestamps[version]) > 1 and now >= self.timestamps[version][1]: + del self.timestamps[version][0] + return self.timestamps[version][0], self.nonce + + def siesta(self): + try: + when = min(t[1] for t in self.timestamps.itervalues() if len(t) > 1) + except ValueError: + return None + now = self.now() + if now < when: + return when - now + else: + return 1 + + +def server_main(args): + """ + Reply rpki-data from a historical database. + + This is a clone of server_main() which replaces the external serial + number updates triggered via the kickme channel by cronjob_main with + an internal clocking mechanism to replay historical test data. + + DO NOT USE THIS IN PRODUCTION. + + You have been warned. + """ + + logger = logging.LoggerAdapter(logging.root, dict(connection = rpki.rtr.server._hostport_tag())) + + logger.debug("[Starting]") + + if args.rpki_rtr_dir: + try: + os.chdir(args.rpki_rtr_dir) + except OSError, e: + sys.exit(e) + + # Yes, this really does replace a global function defined in another + # module with a bound method to our clock object. Fun stuff, huh? + + clock = ReplayClock() + rpki.rtr.server.read_current = clock.read_current + + try: + server = rpki.rtr.server.ServerChannel(logger = logger, refresh = args.refresh, retry = args.retry, expire = args.expire) + old_serial = server.get_serial() + logger.debug("[Starting at serial %d (%s)]", old_serial, old_serial) + while clock: + new_serial = server.get_serial() + if old_serial != new_serial: + logger.debug("[Serial bumped from %d (%s) to %d (%s)]", old_serial, old_serial, new_serial, new_serial) + server.notify(force = True) + old_serial = new_serial + asyncore.loop(timeout = clock.siesta(), count = 1) + except KeyboardInterrupt: + sys.exit(0) + + +# Splice our extensions into server +rpki.rtr.server.server_main = server_main + +# And run the program +import rpki.rtr.main +rpki.rtr.main.main() |