diff options
-rwxr-xr-x | rp/rcynic/rcynicng | 31 | ||||
-rw-r--r-- | rpki/config.py | 58 | ||||
-rw-r--r-- | rpki/rcynicdb/models.py | 18 |
3 files changed, 91 insertions, 16 deletions
diff --git a/rp/rcynic/rcynicng b/rp/rcynic/rcynicng index 51dbc6a7..ba6dfefe 100755 --- a/rp/rcynic/rcynicng +++ b/rp/rcynic/rcynicng @@ -917,6 +917,18 @@ class Fetcher(object): # tornado.httpclient.AsyncHTTPClient.fetch() # tornado.httpclient.HTTPError + # Might need to do something with If-Modified-Since support + # See if_modified_since argument to + # http://www.tornadoweb.org/en/stable/httpclient.html#request-objects + # (which we can pass to client.fetch(), below). Not sure how + # "you don't need to retrieve this" result comes back, + # probably a benign exception we need to catch. Supporting + # this means adding another null-able timestamp field to the + # RRDPSnapshot model (which probably should be named the + # RRDPZone model instead), and storing a datetime there. + # Would also need to pull timestamp from the Last-Modified + # header in the response object. + try: ok = False t0 = time.time() @@ -1197,10 +1209,13 @@ def final_report(): for s in Status.db.itervalues(): if codes.OBJECT_ACCEPTED in s.status: s.status.discard(codes.OBJECT_REJECTED) - doc = Element("rcynic-summary") # rcynic-version = "", summary-version = "", reporting-hostname = "" + doc = Element("rcynic-summary", date = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())) + doc.set("reporting-hostname", socket.getfqdn()) + doc.set("rcynic-version", "rcynicng") + doc.set("summary-version", "1") labels = SubElement(doc, "labels") for code in codes.all(): - SubElement(labels, code.name).text = code.text + SubElement(labels, code.name, kind = code.kind).text = code.text for uri in Status.db: for sym in sorted(Status.db[uri].status): SubElement(doc, "validation_status", @@ -1285,9 +1300,7 @@ def main(): DJANGO_SETTINGS_MODULE = "rpki.django_settings.rcynic") time.tzset() - parser = argparse.ArgumentParser(description = __doc__) - - parser.add_argument("-c", "--config", default = "/dev/null") + cfg, parser = rpki.config.argparser(section = "rcynic", doc = __doc__, cfg_optional = True) parser.add_argument("--authenticated", default = "rcynic-data/authenticated") parser.add_argument("--unauthenticated", default = "rcynic-data/unauthenticated") @@ -1314,14 +1327,6 @@ def main(): global args args = parser.parse_args() - rpki.config.parser(set_filename = args.config, section = "rcynic") - - # If we're going to allow some options to be controlled from both - # config file and command line, this is where we sort that out. - # Doesn't play well with action=store_true. Might want a more - # generalized mechanism letting us do command-line overrides of - # interesting parameters for other programs as well. - import django django.setup() diff --git a/rpki/config.py b/rpki/config.py index a9bd3219..3cc16626 100644 --- a/rpki/config.py +++ b/rpki/config.py @@ -23,6 +23,7 @@ ConfigParser module. """ import ConfigParser +import argparse import logging import os import re @@ -272,3 +273,60 @@ class parser(object): rpki.up_down.content_type = self.get("up_down_content_type") except ConfigParser.NoOptionError: pass + + +def argparser(section = None, doc = None, cfg_optional = False): + """ + First cut at a combined configuration mechanism based on ConfigParser and argparse. + + General idea here is to do an initial pass on the arguments to handle the config file, + then return the config file and a parser to use for the rest of the arguments. + """ + + # Basic approach here is a variation on: + # http://blog.vwelch.com/2011/04/combining-configparser-and-argparse.html + + # For most of our uses of argparse, this should be a trivial + # drop-in, and should reduce the amount of repetitive code. There + # are a couple of special cases which will require attention: + # + # - rpki.rtr: These modules have their own handling of all the + # logging setup, and use an argparse subparser. I -think- that + # the way they're already handling the logging setup should work + # fine, but there may be a few tricky bits reconciling this code + # with the more generalized version in rpki.log. + # + # - rpki.rpkic: Use of argparse here is very complicated due to + # support for both the external command line and the internal + # command loop. Overall it works quite well, but the setup is + # tricky. rpki.rpkic.main.top_argparse may need to move outside + # the main class, but that may raise its own issues. Maybe we + # can get away with just replacing the current setup of + # top_argparser with a call to this function and otherwise + # leaving the whole structure alone? Try and see, I guess. + + # Setting cfg_optional here doesn't really work, because the cfg + # object returned here is separate from the one that the Django + # ORM gets when it tries to look for databases. Given that just + # about everything which uses this module also uses Django, + # perhaps we should just resign ourselves to the config being a + # global thing we read exactly once, so we can stop playing this + # game. + + topparser = argparse.ArgumentParser(add_help = False) + topparser.add_argument("-c", "--config", + default = os.getenv(rpki_conf_envname, default_filename), + help = "override default location of configuration file") + + cfgparser = argparse.ArgumentParser(parents = [topparser], add_help = False) + cfgparser.add_argument("-h", "--help", action = "store_true") + + args, remaining_argv = cfgparser.parse_known_args() + + cfg = parser(section = section, + set_filename = args.config, + allow_missing = cfg_optional or args.help) + + argparser = argparse.ArgumentParser(parents = [topparser], description = doc) + + return cfg, argparser diff --git a/rpki/rcynicdb/models.py b/rpki/rcynicdb/models.py index 09d513d5..185482b1 100644 --- a/rpki/rcynicdb/models.py +++ b/rpki/rcynicdb/models.py @@ -31,14 +31,26 @@ class RRDPSnapshot(models.Model): # # https://docs.djangoproject.com/en/1.9/ref/models/fields/#django.db.models.ForeignKey.on_delete # -# Might also want to provide names for the reverse relationships, code uses blah_set for now. +# Might also want to provide names for the reverse relationships, code +# uses blah_set for now. + +# Setting unique = True on the der field breaks with PostgreSQL, see +# https://code.djangoproject.com/ticket/14904 +# +# In theory collisions on sha256 are possible, but in practice they're +# not going to occur by accident. Setting unique = True on the sha256 +# field risks deliberate collisions, defending against that would +# require detecting the collision and figuring out which is the +# attacking object (easy in theory, as it probably won't validate), +# then figuring out what to do about it (possibly harder -- do we drop +# an entire RRDP zone because of one evil object?). class RPKIObject(models.Model): - der = models.BinaryField(unique = True) + der = models.BinaryField() # unique = True uri = models.TextField() aki = models.SlugField(max_length = 40) # hex SHA-1 ski = models.SlugField(max_length = 40) # hex SHA-1 - sha256 = models.SlugField(max_length = 64) # hex SHA-256 + sha256 = models.SlugField(max_length = 64, unique = True) # hex SHA-256 retrieved = models.ForeignKey(Retrieval) authenticated = models.ManyToManyField(Authenticated) snapshot = models.ManyToManyField(RRDPSnapshot) |