diff options
author | Rob Austein <sra@hactrn.net> | 2015-10-26 06:29:00 +0000 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2015-10-26 06:29:00 +0000 |
commit | b46deb1417dc3596e9ac9fe2fe8cc0b7f42457e7 (patch) | |
tree | ca0dc0276d1adc168bc3337ce0564c4ec4957c1b /rpki/pubdb | |
parent | 397beaf6d9900dc3b3cb612c89ebf1d57b1d16f6 (diff) |
"Any programmer who fails to comply with the standard naming, formatting,
or commenting conventions should be shot. If it so happens that it is
inconvenient to shoot him, then he is to be politely requested to recode
his program in adherence to the above standard."
-- Michael Spier, Digital Equipment Corporation
svn path=/branches/tk705/; revision=6152
Diffstat (limited to 'rpki/pubdb')
-rw-r--r-- | rpki/pubdb/models.py | 476 |
1 files changed, 238 insertions, 238 deletions
diff --git a/rpki/pubdb/models.py b/rpki/pubdb/models.py index 2b6d67e4..46dcf493 100644 --- a/rpki/pubdb/models.py +++ b/rpki/pubdb/models.py @@ -48,266 +48,266 @@ rrdp_tag_withdraw = rrdp_xmlns + "withdraw" # sure quite where to put it at the moment. def DERSubElement(elt, name, der, attrib = None, **kwargs): - """ - Convenience wrapper around SubElement for use with Base64 text. - """ + """ + Convenience wrapper around SubElement for use with Base64 text. + """ - se = SubElement(elt, name, attrib, **kwargs) - se.text = rpki.x509.base64_with_linebreaks(der) - se.tail = "\n" - return se + se = SubElement(elt, name, attrib, **kwargs) + se.text = rpki.x509.base64_with_linebreaks(der) + se.tail = "\n" + return se class Client(models.Model): - client_handle = models.CharField(unique = True, max_length = 255) - base_uri = models.TextField() - bpki_cert = CertificateField() - bpki_glue = CertificateField(null = True) - last_cms_timestamp = SundialField(blank = True, null = True) + client_handle = models.CharField(unique = True, max_length = 255) + base_uri = models.TextField() + bpki_cert = CertificateField() + bpki_glue = CertificateField(null = True) + last_cms_timestamp = SundialField(blank = True, null = True) - def check_allowed_uri(self, uri): - """ - Make sure that a target URI is within this client's allowed URI space. - """ + def check_allowed_uri(self, uri): + """ + Make sure that a target URI is within this client's allowed URI space. + """ - if not uri.startswith(self.base_uri): - raise rpki.exceptions.ForbiddenURI + if not uri.startswith(self.base_uri): + raise rpki.exceptions.ForbiddenURI class Session(models.Model): - uuid = models.CharField(unique = True, max_length=36) - serial = models.BigIntegerField() - snapshot = models.TextField(blank = True) - hash = models.CharField(max_length = 64, blank = True) - - ## @var keep_all_rrdp_files - # Debugging flag to prevent expiration of old RRDP files. - # This simplifies debugging delta code. Need for this - # may go away once RRDP is fully integrated into rcynic. - keep_all_rrdp_files = False - - def new_delta(self, expires): - """ - Construct a new delta associated with this session. - """ + uuid = models.CharField(unique = True, max_length=36) + serial = models.BigIntegerField() + snapshot = models.TextField(blank = True) + hash = models.CharField(max_length = 64, blank = True) + + ## @var keep_all_rrdp_files + # Debugging flag to prevent expiration of old RRDP files. + # This simplifies debugging delta code. Need for this + # may go away once RRDP is fully integrated into rcynic. + keep_all_rrdp_files = False + + def new_delta(self, expires): + """ + Construct a new delta associated with this session. + """ + + delta = Delta(session = self, + serial = self.serial + 1, + expires = expires) + delta.elt = Element(rrdp_tag_delta, + nsmap = rrdp_nsmap, + version = rrdp_version, + session_id = self.uuid, + serial = str(delta.serial)) + return delta + + + def expire_deltas(self): + """ + Delete deltas whose expiration date has passed. + """ + + self.delta_set.filter(expires__lt = rpki.sundial.now()).delete() + + + def generate_snapshot(self): + """ + Generate an XML snapshot of this session. + """ + + xml = Element(rrdp_tag_snapshot, nsmap = rrdp_nsmap, + version = rrdp_version, + session_id = self.uuid, + serial = str(self.serial)) + xml.text = "\n" + for obj in self.publishedobject_set.all(): + DERSubElement(xml, rrdp_tag_publish, + der = obj.der, + uri = obj.uri) + rpki.relaxng.rrdp.assertValid(xml) + self.snapshot = ElementToString(xml, pretty_print = True) + self.hash = rpki.x509.sha256(self.snapshot).encode("hex") + self.save() + + + @property + def snapshot_fn(self): + return "%s/snapshot/%s.xml" % (self.uuid, self.serial) + + + @property + def notification_fn(self): + return "notify.xml" + + + @staticmethod + def _write_rrdp_file(fn, text, rrdp_publication_base, overwrite = False): + if overwrite or not os.path.exists(os.path.join(rrdp_publication_base, fn)): + tn = os.path.join(rrdp_publication_base, fn + ".%s.tmp" % os.getpid()) + if not os.path.isdir(os.path.dirname(tn)): + os.makedirs(os.path.dirname(tn)) + with open(tn, "w") as f: + f.write(text) + os.rename(tn, os.path.join(rrdp_publication_base, fn)) + + + @staticmethod + def _rrdp_filename_to_uri(fn, rrdp_uri_base): + return "%s/%s" % (rrdp_uri_base.rstrip("/"), fn) + + + def _generate_update_xml(self, rrdp_uri_base): + xml = Element(rrdp_tag_notification, nsmap = rrdp_nsmap, + version = rrdp_version, + session_id = self.uuid, + serial = str(self.serial)) + SubElement(xml, rrdp_tag_snapshot, + uri = self._rrdp_filename_to_uri(self.snapshot_fn, rrdp_uri_base), + hash = self.hash) + for delta in self.delta_set.all(): + SubElement(xml, rrdp_tag_delta, + uri = self._rrdp_filename_to_uri(delta.fn, rrdp_uri_base), + hash = delta.hash, + serial = str(delta.serial)) + rpki.relaxng.rrdp.assertValid(xml) + return ElementToString(xml, pretty_print = True) + + + def synchronize_rrdp_files(self, rrdp_publication_base, rrdp_uri_base): + """ + Write current RRDP files to disk, clean up old files and directories. + """ + + current_filenames = set() + + for delta in self.delta_set.all(): + self._write_rrdp_file(delta.fn, delta.xml, rrdp_publication_base) + current_filenames.add(delta.fn) + + self._write_rrdp_file(self.snapshot_fn, self.snapshot, rrdp_publication_base) + current_filenames.add(self.snapshot_fn) + + self._write_rrdp_file(self.notification_fn, self._generate_update_xml(rrdp_uri_base), + rrdp_publication_base, overwrite = True) + current_filenames.add(self.notification_fn) + + if not self.keep_all_rrdp_files: + for root, dirs, files in os.walk(rrdp_publication_base, topdown = False): + for fn in files: + fn = os.path.join(root, fn) + if fn[len(rrdp_publication_base):].lstrip("/") not in current_filenames: + os.remove(fn) + for dn in dirs: + try: + os.rmdir(os.path.join(root, dn)) + except OSError: + pass - delta = Delta(session = self, - serial = self.serial + 1, - expires = expires) - delta.elt = Element(rrdp_tag_delta, - nsmap = rrdp_nsmap, - version = rrdp_version, - session_id = self.uuid, - serial = str(delta.serial)) - return delta +class Delta(models.Model): + serial = models.BigIntegerField() + xml = models.TextField() + hash = models.CharField(max_length = 64) + expires = SundialField() + session = models.ForeignKey(Session) - def expire_deltas(self): - """ - Delete deltas whose expiration date has passed. - """ - self.delta_set.filter(expires__lt = rpki.sundial.now()).delete() + @staticmethod + def _uri_to_filename(uri, publication_base): + if not uri.startswith("rsync://"): + raise rpki.exceptions.BadURISyntax(uri) + path = uri.split("/")[4:] + path.insert(0, publication_base.rstrip("/")) + filename = "/".join(path) + if "/../" in filename or filename.endswith("/.."): + raise rpki.exceptions.BadURISyntax(filename) + return filename - def generate_snapshot(self): - """ - Generate an XML snapshot of this session. - """ + @property + def fn(self): + return "%s/deltas/%s.xml" % (self.session.uuid, self.serial) - xml = Element(rrdp_tag_snapshot, nsmap = rrdp_nsmap, - version = rrdp_version, - session_id = self.uuid, - serial = str(self.serial)) - xml.text = "\n" - for obj in self.publishedobject_set.all(): - DERSubElement(xml, rrdp_tag_publish, - der = obj.der, - uri = obj.uri) - rpki.relaxng.rrdp.assertValid(xml) - self.snapshot = ElementToString(xml, pretty_print = True) - self.hash = rpki.x509.sha256(self.snapshot).encode("hex") - self.save() - - - @property - def snapshot_fn(self): - return "%s/snapshot/%s.xml" % (self.uuid, self.serial) - - - @property - def notification_fn(self): - return "notify.xml" - - - @staticmethod - def _write_rrdp_file(fn, text, rrdp_publication_base, overwrite = False): - if overwrite or not os.path.exists(os.path.join(rrdp_publication_base, fn)): - tn = os.path.join(rrdp_publication_base, fn + ".%s.tmp" % os.getpid()) - if not os.path.isdir(os.path.dirname(tn)): - os.makedirs(os.path.dirname(tn)) - with open(tn, "w") as f: - f.write(text) - os.rename(tn, os.path.join(rrdp_publication_base, fn)) - - - @staticmethod - def _rrdp_filename_to_uri(fn, rrdp_uri_base): - return "%s/%s" % (rrdp_uri_base.rstrip("/"), fn) - - - def _generate_update_xml(self, rrdp_uri_base): - xml = Element(rrdp_tag_notification, nsmap = rrdp_nsmap, - version = rrdp_version, - session_id = self.uuid, - serial = str(self.serial)) - SubElement(xml, rrdp_tag_snapshot, - uri = self._rrdp_filename_to_uri(self.snapshot_fn, rrdp_uri_base), - hash = self.hash) - for delta in self.delta_set.all(): - SubElement(xml, rrdp_tag_delta, - uri = self._rrdp_filename_to_uri(delta.fn, rrdp_uri_base), - hash = delta.hash, - serial = str(delta.serial)) - rpki.relaxng.rrdp.assertValid(xml) - return ElementToString(xml, pretty_print = True) - - - def synchronize_rrdp_files(self, rrdp_publication_base, rrdp_uri_base): - """ - Write current RRDP files to disk, clean up old files and directories. - """ - current_filenames = set() - - for delta in self.delta_set.all(): - self._write_rrdp_file(delta.fn, delta.xml, rrdp_publication_base) - current_filenames.add(delta.fn) - - self._write_rrdp_file(self.snapshot_fn, self.snapshot, rrdp_publication_base) - current_filenames.add(self.snapshot_fn) - - self._write_rrdp_file(self.notification_fn, self._generate_update_xml(rrdp_uri_base), - rrdp_publication_base, overwrite = True) - current_filenames.add(self.notification_fn) - - if not self.keep_all_rrdp_files: - for root, dirs, files in os.walk(rrdp_publication_base, topdown = False): - for fn in files: - fn = os.path.join(root, fn) - if fn[len(rrdp_publication_base):].lstrip("/") not in current_filenames: - os.remove(fn) - for dn in dirs: - try: - os.rmdir(os.path.join(root, dn)) - except OSError: - pass + def activate(self): + rpki.relaxng.rrdp.assertValid(self.elt) + self.xml = ElementToString(self.elt, pretty_print = True) + self.hash = rpki.x509.sha256(self.xml).encode("hex") + self.save() + self.session.serial += 1 + self.session.save() -class Delta(models.Model): - serial = models.BigIntegerField() - xml = models.TextField() - hash = models.CharField(max_length = 64) - expires = SundialField() - session = models.ForeignKey(Session) - - - @staticmethod - def _uri_to_filename(uri, publication_base): - if not uri.startswith("rsync://"): - raise rpki.exceptions.BadURISyntax(uri) - path = uri.split("/")[4:] - path.insert(0, publication_base.rstrip("/")) - filename = "/".join(path) - if "/../" in filename or filename.endswith("/.."): - raise rpki.exceptions.BadURISyntax(filename) - return filename - - - @property - def fn(self): - return "%s/deltas/%s.xml" % (self.session.uuid, self.serial) - - - def activate(self): - rpki.relaxng.rrdp.assertValid(self.elt) - self.xml = ElementToString(self.elt, pretty_print = True) - self.hash = rpki.x509.sha256(self.xml).encode("hex") - self.save() - self.session.serial += 1 - self.session.save() - - - def publish(self, client, der, uri, obj_hash): - try: - obj = client.publishedobject_set.get(session = self.session, uri = uri) - if obj.hash == obj_hash: - obj.delete() - elif obj_hash is None: - raise rpki.exceptions.ExistingObjectAtURI("Object already published at %s" % uri) - else: - raise rpki.exceptions.DifferentObjectAtURI("Found different object at %s (old %s, new %s)" % (uri, obj.hash, obj_hash)) - except rpki.pubdb.models.PublishedObject.DoesNotExist: - pass - logger.debug("Publishing %s", uri) - PublishedObject.objects.create(session = self.session, client = client, der = der, uri = uri, - hash = rpki.x509.sha256(der).encode("hex")) - se = DERSubElement(self.elt, rrdp_tag_publish, der = der, uri = uri) - if obj_hash is not None: - se.set("hash", obj_hash) - rpki.relaxng.rrdp.assertValid(self.elt) - - - def withdraw(self, client, uri, obj_hash): - obj = client.publishedobject_set.get(session = self.session, uri = uri) - if obj.hash != obj_hash: - raise rpki.exceptions.DifferentObjectAtURI("Found different object at %s (old %s, new %s)" % (uri, obj.hash, obj_hash)) - logger.debug("Withdrawing %s", uri) - obj.delete() - SubElement(self.elt, rrdp_tag_withdraw, uri = uri, hash = obj_hash).tail = "\n" - rpki.relaxng.rrdp.assertValid(self.elt) - - - def update_rsync_files(self, publication_base): - from errno import ENOENT - min_path_len = len(publication_base.rstrip("/")) - for pdu in self.elt: - assert pdu.tag in (rrdp_tag_publish, rrdp_tag_withdraw) - fn = self._uri_to_filename(pdu.get("uri"), publication_base) - if pdu.tag == rrdp_tag_publish: - tn = fn + ".tmp" - dn = os.path.dirname(fn) - if not os.path.isdir(dn): - os.makedirs(dn) - with open(tn, "wb") as f: - f.write(pdu.text.decode("base64")) - os.rename(tn, fn) - else: + def publish(self, client, der, uri, obj_hash): try: - os.remove(fn) - except OSError, e: - if e.errno != ENOENT: - raise - dn = os.path.dirname(fn) - while len(dn) > min_path_len: - try: - os.rmdir(dn) - except OSError: - break - else: - dn = os.path.dirname(dn) - del self.elt + obj = client.publishedobject_set.get(session = self.session, uri = uri) + if obj.hash == obj_hash: + obj.delete() + elif obj_hash is None: + raise rpki.exceptions.ExistingObjectAtURI("Object already published at %s" % uri) + else: + raise rpki.exceptions.DifferentObjectAtURI("Found different object at %s (old %s, new %s)" % (uri, obj.hash, obj_hash)) + except rpki.pubdb.models.PublishedObject.DoesNotExist: + pass + logger.debug("Publishing %s", uri) + PublishedObject.objects.create(session = self.session, client = client, der = der, uri = uri, + hash = rpki.x509.sha256(der).encode("hex")) + se = DERSubElement(self.elt, rrdp_tag_publish, der = der, uri = uri) + if obj_hash is not None: + se.set("hash", obj_hash) + rpki.relaxng.rrdp.assertValid(self.elt) + + + def withdraw(self, client, uri, obj_hash): + obj = client.publishedobject_set.get(session = self.session, uri = uri) + if obj.hash != obj_hash: + raise rpki.exceptions.DifferentObjectAtURI("Found different object at %s (old %s, new %s)" % (uri, obj.hash, obj_hash)) + logger.debug("Withdrawing %s", uri) + obj.delete() + SubElement(self.elt, rrdp_tag_withdraw, uri = uri, hash = obj_hash).tail = "\n" + rpki.relaxng.rrdp.assertValid(self.elt) + + + def update_rsync_files(self, publication_base): + from errno import ENOENT + min_path_len = len(publication_base.rstrip("/")) + for pdu in self.elt: + assert pdu.tag in (rrdp_tag_publish, rrdp_tag_withdraw) + fn = self._uri_to_filename(pdu.get("uri"), publication_base) + if pdu.tag == rrdp_tag_publish: + tn = fn + ".tmp" + dn = os.path.dirname(fn) + if not os.path.isdir(dn): + os.makedirs(dn) + with open(tn, "wb") as f: + f.write(pdu.text.decode("base64")) + os.rename(tn, fn) + else: + try: + os.remove(fn) + except OSError, e: + if e.errno != ENOENT: + raise + dn = os.path.dirname(fn) + while len(dn) > min_path_len: + try: + os.rmdir(dn) + except OSError: + break + else: + dn = os.path.dirname(dn) + del self.elt class PublishedObject(models.Model): - uri = models.CharField(max_length = 255) - der = models.BinaryField() - hash = models.CharField(max_length = 64) - client = models.ForeignKey(Client) - session = models.ForeignKey(Session) - - class Meta: # pylint: disable=C1001,W0232 - unique_together = (("session", "hash"), - ("session", "uri")) + uri = models.CharField(max_length = 255) + der = models.BinaryField() + hash = models.CharField(max_length = 64) + client = models.ForeignKey(Client) + session = models.ForeignKey(Session) + + class Meta: # pylint: disable=C1001,W0232 + unique_together = (("session", "hash"), + ("session", "uri")) |