aboutsummaryrefslogtreecommitdiff
path: root/rpki
diff options
context:
space:
mode:
Diffstat (limited to 'rpki')
-rw-r--r--rpki/left_right.py414
-rw-r--r--rpki/publication.py7
-rw-r--r--rpki/publication_control.py7
-rw-r--r--rpki/rootd.py4
-rw-r--r--rpki/rpkic.py1
-rw-r--r--rpki/rpkid.py3
-rw-r--r--rpki/xml_utils.py357
7 files changed, 201 insertions, 592 deletions
diff --git a/rpki/left_right.py b/rpki/left_right.py
index fff3404d..1b3eb581 100644
--- a/rpki/left_right.py
+++ b/rpki/left_right.py
@@ -28,7 +28,6 @@ import rpki.resource_set
import rpki.x509
import rpki.sql
import rpki.exceptions
-import rpki.xml_utils
import rpki.http
import rpki.up_down
import rpki.relaxng
@@ -38,7 +37,7 @@ import rpki.publication
import rpki.async
import rpki.rpkid_tasks
-from lxml.etree import Element, SubElement
+from lxml.etree import Element, SubElement, tostring as ElementToString
logger = logging.getLogger(__name__)
@@ -76,40 +75,208 @@ tag_signing_cert_crl = xmlns + "signing_cert_crl"
enforce_strict_up_down_xml_sender = False
-class left_right_namespace(object):
+class base_elt(rpki.sql.sql_persistent):
"""
- XML namespace parameters for left-right protocol.
+ Virtual class for persistent left-right protocol elements.
+ These classes are being phased out in favor of Django ORM models.
"""
xmlns = rpki.relaxng.left_right.xmlns
nsmap = rpki.relaxng.left_right.nsmap
-class data_elt(rpki.xml_utils.data_elt, rpki.sql.sql_persistent, left_right_namespace):
- """
- Virtual class for top-level left-right protocol data elements.
- """
-
handles = ()
+ attributes = ()
+ elements = ()
+ booleans = ()
+ text_attribute = None
self_id = None
self_handle = None
- @property
- @rpki.sql.cache_reference
- def self(self):
+ def __str__(self):
+ return ElementToString(self.toXML(), pretty_print = True, encoding = "us-ascii")
+
+ @classmethod
+ def fromXML(cls, elt):
+
+ self = cls()
+
+ for key in self.attributes:
+ val = elt.get(key, None)
+ if val is not None:
+ val = val.encode("ascii")
+ if isinstance(self.attributes, dict) and self.attributes[key] is not None:
+ val = self.attributes[key](val)
+ elif val.isdigit() and not key.endswith("_handle"):
+ val = long(val)
+ setattr(self, key, val)
+ for key in self.booleans:
+ setattr(self, key, elt.get(key, False))
+
+ if self.text_attribute is not None:
+ setattr(self, self.text_attribute, elt.text)
+
+ # In the long run, we probably want the key for that to include
+ # the namespace, but that would break the current .toXML() code,
+ # so kludge it for now.
+
+ for b64 in elt:
+ assert b64.tag.startswith(self.xmlns)
+ ename = b64.tag[len(self.xmlns):]
+ etype = self.elements[ename]
+ setattr(self, ename, etype(Base64 = b64.text))
+
+ return self
+
+ def toXML(self):
+ """
+ Default element generator for SQL-based objects. This assumes
+ that sub-elements are Base64-encoded DER objects.
+ """
+
+ elt = Element(self.xmlns + self.element_name, nsmap = self.nsmap)
+ for key in self.attributes:
+ val = getattr(self, key, None)
+ if val is not None:
+ elt.set(key, str(val))
+ for key in self.booleans:
+ if getattr(self, key, False):
+ elt.set(key, "yes")
+ for name in self.elements:
+ value = getattr(self, name, None)
+ if value is not None and not value.empty():
+ SubElement(elt, self.xmlns + name, nsmap = self.nsmap).text = value.get_Base64()
+ return elt
+
+ def make_reply(self, r_pdu = None):
+ """
+ Construct a reply PDU.
+ """
+
+ if r_pdu is None:
+ r_pdu = self.__class__()
+ self.make_reply_clone_hook(r_pdu)
+ handle_name = self.element_name + "_handle"
+ setattr(r_pdu, handle_name, getattr(self, handle_name, None))
+ else:
+ self.make_reply_clone_hook(r_pdu)
+ for b in r_pdu.booleans:
+ setattr(r_pdu, b, False)
+ r_pdu.action = self.action
+ r_pdu.tag = self.tag
+ return r_pdu
+
+ def serve_fetch_one(self):
"""
- Fetch self object to which this object links.
+ Find the object on which a get, set, or destroy method should
+ operate.
"""
+ r = self.serve_fetch_one_maybe()
+ if r is None:
+ raise rpki.exceptions.NotFound
+ return r
+
+ def serve_post_save_hook(self, q_pdu, r_pdu, cb, eb):
+ cb()
+
+ def serve_create(self, r_msg, cb, eb):
+ r_pdu = self.make_reply()
+
+ def one():
+ self.sql_store()
+ setattr(r_pdu, self.sql_template.index, getattr(self, self.sql_template.index))
+ self.serve_post_save_hook(self, r_pdu, two, eb)
+
+ def two():
+ r_msg.append(r_pdu)
+ cb()
+
+ oops = self.serve_fetch_one_maybe()
+ if oops is not None:
+ raise rpki.exceptions.DuplicateObject("Object already exists: %r[%r] %r[%r]" % (self, getattr(self, self.element_name + "_handle"),
+ oops, getattr(oops, oops.element_name + "_handle")))
+
+ self.serve_pre_save_hook(self, r_pdu, one, eb)
+
+ def serve_set(self, r_msg, cb, eb):
+
+ db_pdu = self.serve_fetch_one()
+ r_pdu = self.make_reply()
+ for a in db_pdu.sql_template.columns[1:]:
+ v = getattr(self, a, None)
+ if v is not None:
+ setattr(db_pdu, a, v)
+ db_pdu.sql_mark_dirty()
+
+ def one():
+ db_pdu.sql_store()
+ db_pdu.serve_post_save_hook(self, r_pdu, two, eb)
+
+ def two():
+ r_msg.append(r_pdu)
+ cb()
+
+ db_pdu.serve_pre_save_hook(self, r_pdu, one, eb)
+
+ def serve_get(self, r_msg, cb, eb):
+ r_pdu = self.serve_fetch_one()
+ self.make_reply(r_pdu)
+ r_msg.append(r_pdu)
+ cb()
+
+ def serve_list(self, r_msg, cb, eb):
+ for r_pdu in self.serve_fetch_all():
+ self.make_reply(r_pdu)
+ r_msg.append(r_pdu)
+ cb()
+
+ def serve_destroy_hook(self, cb, eb):
+ cb()
+
+ def serve_destroy(self, r_msg, cb, eb):
+ def done():
+ db_pdu.sql_delete()
+ r_msg.append(self.make_reply())
+ cb()
+ db_pdu = self.serve_fetch_one()
+ db_pdu.serve_destroy_hook(done, eb)
+
+ def serve_dispatch(self, r_msg, cb, eb):
+ # Transition hack: handle the .toXML() call for old handlers.
+
+ fake_r_msg = []
+
+ def fake_convert():
+ r_msg.extend(r_pdu.toXML() if isinstance(r_pdu, base_elt) else r_pdu
+ for r_pdu in fake_r_msg)
+
+ def fake_cb():
+ fake_convert()
+ cb()
+
+ def fake_eb(e):
+ fake_convert()
+ eb(e)
+
+ method = getattr(self, "serve_" + self.action, None)
+ if method is None:
+ raise rpki.exceptions.BadQuery("Unexpected query: action %s" % self.action)
+ method(fake_r_msg, fake_cb, fake_eb)
+
+ def unimplemented_control(self, *controls):
+ unimplemented = [x for x in controls if getattr(self, x, False)]
+ if unimplemented:
+ raise rpki.exceptions.NotImplementedYet("Unimplemented control %s" % ", ".join(unimplemented))
+
+ @property
+ @rpki.sql.cache_reference
+ def self(self):
return self_elt.sql_fetch(self.gctx, self.self_id)
@property
@rpki.sql.cache_reference
def bsc(self):
- """
- Return BSC object to which this object links.
- """
-
return bsc_elt.sql_fetch(self.gctx, self.bsc_id)
def make_reply_clone_hook(self, r_pdu):
@@ -130,10 +297,6 @@ class data_elt(rpki.xml_utils.data_elt, rpki.sql.sql_persistent, left_right_name
@classmethod
def serve_fetch_handle(cls, gctx, self_id, handle):
- """
- Find an object based on its handle.
- """
-
return cls.sql_fetch_where1(gctx, cls.element_name + "_handle = %s AND self_id = %s", (handle, self_id))
def serve_fetch_one_maybe(self):
@@ -173,7 +336,8 @@ class data_elt(rpki.xml_utils.data_elt, rpki.sql.sql_persistent, left_right_name
setattr(self, id_name, getattr(x, id_name))
cb()
-class self_elt(data_elt):
+
+class self_elt(base_elt):
"""
<self/> element.
"""
@@ -211,66 +375,33 @@ class self_elt(data_elt):
@property
def bscs(self):
- """
- Fetch all BSC objects that link to this self object.
- """
-
return bsc_elt.sql_fetch_where(self.gctx, "self_id = %s", (self.self_id,))
@property
def repositories(self):
- """
- Fetch all repository objects that link to this self object.
- """
-
return repository_elt.sql_fetch_where(self.gctx, "self_id = %s", (self.self_id,))
@property
def parents(self):
- """
- Fetch all parent objects that link to this self object.
- """
-
return parent_elt.sql_fetch_where(self.gctx, "self_id = %s", (self.self_id,))
@property
def children(self):
- """
- Fetch all child objects that link to this self object.
- """
-
return child_elt.sql_fetch_where(self.gctx, "self_id = %s", (self.self_id,))
@property
def roas(self):
- """
- Fetch all ROA objects that link to this self object.
- """
-
return rpki.rpkid.roa_obj.sql_fetch_where(self.gctx, "self_id = %s", (self.self_id,))
@property
def ghostbusters(self):
- """
- Fetch all Ghostbuster record objects that link to this self object.
- """
-
return rpki.rpkid.ghostbuster_obj.sql_fetch_where(self.gctx, "self_id = %s", (self.self_id,))
@property
def ee_certificates(self):
- """
- Fetch all EE certificate objects that link to this self object.
- """
-
return rpki.rpkid.ee_cert_obj.sql_fetch_where(self.gctx, "self_id = %s", (self.self_id,))
-
def serve_post_save_hook(self, q_pdu, r_pdu, cb, eb):
- """
- Extra server actions for self_elt.
- """
-
actions = []
if q_pdu.rekey:
actions.append(self.serve_rekey)
@@ -291,65 +422,37 @@ class self_elt(data_elt):
rpki.async.iterator(actions, loop, cb)
def serve_rekey(self, cb, eb):
- """
- Handle a left-right rekey action for this self.
- """
-
def loop(iterator, parent):
parent.serve_rekey(iterator, eb)
rpki.async.iterator(self.parents, loop, cb)
def serve_revoke(self, cb, eb):
- """
- Handle a left-right revoke action for this self.
- """
-
def loop(iterator, parent):
parent.serve_revoke(iterator, eb)
rpki.async.iterator(self.parents, loop, cb)
def serve_reissue(self, cb, eb):
- """
- Handle a left-right reissue action for this self.
- """
-
def loop(iterator, parent):
parent.serve_reissue(iterator, eb)
rpki.async.iterator(self.parents, loop, cb)
def serve_revoke_forgotten(self, cb, eb):
- """
- Handle a left-right revoke_forgotten action for this self.
- """
-
def loop(iterator, parent):
parent.serve_revoke_forgotten(iterator, eb)
rpki.async.iterator(self.parents, loop, cb)
def serve_clear_replay_protection(self, cb, eb):
- """
- Handle a left-right clear_replay_protection action for this self.
- """
-
def loop(iterator, obj):
obj.serve_clear_replay_protection(iterator, eb)
rpki.async.iterator(self.parents + self.children + self.repositories, loop, cb)
def serve_destroy_hook(self, cb, eb):
- """
- Extra cleanup actions when destroying a self_elt.
- """
-
def loop(iterator, parent):
parent.delete(iterator)
rpki.async.iterator(self.parents, loop, cb)
def serve_publish_world_now(self, cb, eb):
- """
- Handle a left-right publish_world_now action for this self.
- """
-
publisher = rpki.rpkid.publication_queue()
repositories = set()
objects = dict()
@@ -417,10 +520,6 @@ class self_elt(data_elt):
rpki.async.iterator(self.parents, loop, done)
def serve_run_now(self, cb, eb):
- """
- Handle a left-right run_now action for this self.
- """
-
logger.debug("Forced immediate run of periodic actions for self %s[%d]",
self.self_handle, self.self_id)
completion = rpki.rpkid_tasks.CompletionHandler(cb)
@@ -438,10 +537,6 @@ class self_elt(data_elt):
@classmethod
def serve_fetch_handle(cls, gctx, self_id, self_handle):
- """
- Find a self object based on its self_handle.
- """
-
return cls.sql_fetch_where1(gctx, "self_handle = %s", (self_handle,))
def serve_fetch_all(self):
@@ -454,13 +549,8 @@ class self_elt(data_elt):
return self.sql_fetch_all(self.gctx)
def schedule_cron_tasks(self, completion):
- """
- Schedule periodic tasks.
- """
-
if self.cron_tasks is None:
self.cron_tasks = tuple(task(self) for task in rpki.rpkid_tasks.task_classes)
-
for task in self.cron_tasks:
self.gctx.task_add(task)
completion.register(task)
@@ -486,7 +576,7 @@ class self_elt(data_elt):
return results
-class bsc_elt(data_elt):
+class bsc_elt(base_elt):
"""
<bsc/> (Business Signing Context) element.
"""
@@ -523,32 +613,19 @@ class bsc_elt(data_elt):
@property
def repositories(self):
- """
- Fetch all repository objects that link to this BSC object.
- """
-
return repository_elt.sql_fetch_where(self.gctx, "bsc_id = %s", (self.bsc_id,))
@property
def parents(self):
- """
- Fetch all parent objects that link to this BSC object.
- """
-
return parent_elt.sql_fetch_where(self.gctx, "bsc_id = %s", (self.bsc_id,))
@property
def children(self):
- """
- Fetch all child objects that link to this BSC object.
- """
-
return child_elt.sql_fetch_where(self.gctx, "bsc_id = %s", (self.bsc_id,))
def serve_pre_save_hook(self, q_pdu, r_pdu, cb, eb):
"""
- Extra server actions for bsc_elt -- handle key generation. For
- now this only allows RSA with SHA-256.
+ Extra server actions -- handle key generation, only RSA with SHA-256 for now.
"""
if q_pdu.generate_keypair:
@@ -556,9 +633,10 @@ class bsc_elt(data_elt):
self.private_key_id = rpki.x509.RSA.generate(keylength = q_pdu.key_length or 2048)
self.pkcs10_request = rpki.x509.PKCS10.create(keypair = self.private_key_id)
r_pdu.pkcs10_request = self.pkcs10_request
- data_elt.serve_pre_save_hook(self, q_pdu, r_pdu, cb, eb)
+ super(bsc_elt, self).serve_pre_save_hook(q_pdu, r_pdu, cb, eb)
-class repository_elt(data_elt):
+
+class repository_elt(base_elt):
"""
<repository/> element.
"""
@@ -594,17 +672,9 @@ class repository_elt(data_elt):
@property
def parents(self):
- """
- Fetch all parent objects that link to this repository object.
- """
-
return parent_elt.sql_fetch_where(self.gctx, "repository_id = %s", (self.repository_id,))
def serve_post_save_hook(self, q_pdu, r_pdu, cb, eb):
- """
- Extra server actions for repository_elt.
- """
-
actions = []
if q_pdu.clear_replay_protection:
actions.append(self.serve_clear_replay_protection)
@@ -613,10 +683,6 @@ class repository_elt(data_elt):
rpki.async.iterator(actions, loop, cb)
def serve_clear_replay_protection(self, cb, eb):
- """
- Handle a left-right clear_replay_protection action for this repository.
- """
-
self.last_cms_timestamp = None
self.sql_mark_dirty()
cb()
@@ -680,7 +746,8 @@ class repository_elt(data_elt):
except Exception, e:
errback(e)
-class parent_elt(data_elt):
+
+class parent_elt(base_elt):
"""
<parent/> element.
"""
@@ -723,25 +790,13 @@ class parent_elt(data_elt):
@property
@rpki.sql.cache_reference
def repository(self):
- """
- Fetch repository object to which this parent object links.
- """
-
return repository_elt.sql_fetch(self.gctx, self.repository_id)
@property
def cas(self):
- """
- Fetch all CA objects that link to this parent object.
- """
-
return rpki.rpkid.ca_obj.sql_fetch_where(self.gctx, "parent_id = %s", (self.parent_id,))
def serve_post_save_hook(self, q_pdu, r_pdu, cb, eb):
- """
- Extra server actions for parent_elt.
- """
-
actions = []
if q_pdu.rekey:
actions.append(self.serve_rekey)
@@ -758,37 +813,21 @@ class parent_elt(data_elt):
rpki.async.iterator(actions, loop, cb)
def serve_rekey(self, cb, eb):
- """
- Handle a left-right rekey action for this parent.
- """
-
def loop(iterator, ca):
ca.rekey(iterator, eb)
rpki.async.iterator(self.cas, loop, cb)
def serve_revoke(self, cb, eb):
- """
- Handle a left-right revoke action for this parent.
- """
-
def loop(iterator, ca):
ca.revoke(cb = iterator, eb = eb)
rpki.async.iterator(self.cas, loop, cb)
def serve_reissue(self, cb, eb):
- """
- Handle a left-right reissue action for this parent.
- """
-
def loop(iterator, ca):
ca.reissue(cb = iterator, eb = eb)
rpki.async.iterator(self.cas, loop, cb)
def serve_clear_replay_protection(self, cb, eb):
- """
- Handle a left-right clear_replay_protection action for this parent.
- """
-
self.last_cms_timestamp = None
self.sql_mark_dirty()
cb()
@@ -883,36 +922,20 @@ class parent_elt(data_elt):
def serve_destroy_hook(self, cb, eb):
- """
- Extra server actions when destroying a parent_elt.
- """
-
self.delete(cb, delete_parent = False)
def _compose_up_down_query(self, query_type):
- """
- Compose top level element of an up-down query to this parent.
- """
-
return Element(rpki.up_down.tag_message, nsmap = rpki.up_down.nsmap, version = rpki.up_down.version,
sender = self.sender_name, recipient = self.recipient_name, type = query_type)
def up_down_list_query(self, cb, eb):
- """
- Send an up-down list query to this parent.
- """
-
q_msg = self._compose_up_down_query("list")
self.query_up_down(q_msg, cb, eb)
def up_down_issue_query(self, ca, ca_detail, cb, eb):
- """
- Send an up-down issue query to this parent.
- """
-
pkcs10 = rpki.x509.PKCS10.create(
keypair = ca_detail.private_key_id,
is_ca = True,
@@ -926,19 +949,12 @@ class parent_elt(data_elt):
def up_down_revoke_query(self, class_name, ski, cb, eb):
- """
- Send an up-down revoke query to this parent.
- """
-
q_msg = self._compose_up_down_query("revoke")
SubElement(q_msg, rpki.up_down.tag_key, class_name = class_name, ski = ski)
self.query_up_down(q_msg, cb, eb)
def query_up_down(self, q_msg, cb, eb):
- """
- Client code for sending one up-down query PDU to this parent.
- """
bsc = self.bsc
if bsc is None:
@@ -976,7 +992,8 @@ class parent_elt(data_elt):
errback = eb,
content_type = rpki.up_down.content_type)
-class child_elt(data_elt):
+
+class child_elt(base_elt):
"""
<child/> element.
"""
@@ -1010,33 +1027,17 @@ class child_elt(data_elt):
return rpki.log.log_repr(self, self.child_handle)
def fetch_child_certs(self, ca_detail = None, ski = None, unique = False):
- """
- Fetch all child_cert objects that link to this child object.
- """
-
return rpki.rpkid.child_cert_obj.fetch(self.gctx, self, ca_detail, ski, unique)
@property
def child_certs(self):
- """
- Fetch all child_cert objects that link to this child object.
- """
-
return self.fetch_child_certs()
@property
def parents(self):
- """
- Fetch all parent objects that link to self object to which this child object links.
- """
-
return parent_elt.sql_fetch_where(self.gctx, "self_id = %s", (self.self_id,))
def serve_post_save_hook(self, q_pdu, r_pdu, cb, eb):
- """
- Extra server actions for child_elt.
- """
-
actions = []
if q_pdu.reissue:
actions.append(self.serve_reissue)
@@ -1047,29 +1048,17 @@ class child_elt(data_elt):
rpki.async.iterator(actions, loop, cb)
def serve_reissue(self, cb, eb):
- """
- Handle a left-right reissue action for this child.
- """
-
publisher = rpki.rpkid.publication_queue()
for child_cert in self.child_certs:
child_cert.reissue(child_cert.ca_detail, publisher, force = True)
publisher.call_pubd(cb, eb)
def serve_clear_replay_protection(self, cb, eb):
- """
- Handle a left-right clear_replay_protection action for this child.
- """
-
self.last_cms_timestamp = None
self.sql_mark_dirty()
cb()
def ca_from_class_name(self, class_name):
- """
- Fetch the CA corresponding to an up-down class_name.
- """
-
if not class_name.isdigit():
raise rpki.exceptions.BadClassNameSyntax("Bad class name %s" % class_name)
ca = rpki.rpkid.ca_obj.sql_fetch(self.gctx, long(class_name))
@@ -1083,10 +1072,6 @@ class child_elt(data_elt):
return ca
def serve_destroy_hook(self, cb, eb):
- """
- Extra server actions when destroying a child_elt.
- """
-
publisher = rpki.rpkid.publication_queue()
for child_cert in self.child_certs:
child_cert.revoke(publisher = publisher,
@@ -1095,9 +1080,6 @@ class child_elt(data_elt):
def up_down_handle_list(self, q_msg, r_msg, callback, errback):
- """
- Serve one up-down "list" PDU.
- """
def got_resources(irdb_resources):
@@ -1132,9 +1114,6 @@ class child_elt(data_elt):
def up_down_handle_issue(self, q_msg, r_msg, callback, errback):
- """
- Serve one issue request PDU.
- """
def got_resources(irdb_resources):
@@ -1205,9 +1184,6 @@ class child_elt(data_elt):
def up_down_handle_revoke(self, q_msg, r_msg, callback, errback):
- """
- Serve one revoke request PDU.
- """
def done():
SubElement(r_msg, key.tag, class_name = class_name, ski = key.get("ski"))
diff --git a/rpki/publication.py b/rpki/publication.py
index e64b729c..58c52d34 100644
--- a/rpki/publication.py
+++ b/rpki/publication.py
@@ -24,15 +24,10 @@ RPKI publication protocol.
import os
import errno
import logging
-import rpki.resource_set
+
import rpki.x509
-import rpki.sql
import rpki.exceptions
-import rpki.http
-import rpki.up_down
import rpki.relaxng
-import rpki.sundial
-import rpki.log
from lxml.etree import Element, SubElement
diff --git a/rpki/publication_control.py b/rpki/publication_control.py
index 06e7aa2d..b5e08f3e 100644
--- a/rpki/publication_control.py
+++ b/rpki/publication_control.py
@@ -26,15 +26,10 @@ protocol itself.
import logging
import collections
-import rpki.resource_set
+
import rpki.x509
-import rpki.sql
import rpki.exceptions
-import rpki.http
-import rpki.up_down
import rpki.relaxng
-import rpki.sundial
-import rpki.log
logger = logging.getLogger(__name__)
diff --git a/rpki/rootd.py b/rpki/rootd.py
index 32b6038b..5a84b5df 100644
--- a/rpki/rootd.py
+++ b/rpki/rootd.py
@@ -28,11 +28,10 @@ import logging
import httplib
import argparse
import urlparse
+
import rpki.resource_set
import rpki.up_down
-import rpki.left_right
import rpki.x509
-import rpki.http
import rpki.http_simple
import rpki.config
import rpki.exceptions
@@ -40,6 +39,7 @@ import rpki.relaxng
import rpki.sundial
import rpki.log
import rpki.daemonize
+import rpki.publication
from lxml.etree import Element, SubElement
diff --git a/rpki/rpkic.py b/rpki/rpkic.py
index 3f899f45..eefa0116 100644
--- a/rpki/rpkic.py
+++ b/rpki/rpkic.py
@@ -38,7 +38,6 @@ import time
import rpki.config
import rpki.sundial
import rpki.log
-import rpki.http
import rpki.resource_set
import rpki.relaxng
import rpki.exceptions
diff --git a/rpki/rpkid.py b/rpki/rpkid.py
index 6cbbc7dd..ddc04bd0 100644
--- a/rpki/rpkid.py
+++ b/rpki/rpkid.py
@@ -28,6 +28,7 @@ import random
import base64
import logging
import argparse
+
import rpki.resource_set
import rpki.up_down
import rpki.left_right
@@ -405,7 +406,7 @@ class main(object):
logger.exception("Unhandled exception serving left-right PDU %r", q_pdu)
# Compatability kludge
- if isinstance(q_pdu, rpki.left_right.data_elt):
+ if isinstance(q_pdu, rpki.left_right.base_elt):
error_self_handle = q_pdu.self_handle
error_tag = q_pdu.tag
else:
diff --git a/rpki/xml_utils.py b/rpki/xml_utils.py
deleted file mode 100644
index da907a0d..00000000
--- a/rpki/xml_utils.py
+++ /dev/null
@@ -1,357 +0,0 @@
-# $Id$
-#
-# Copyright (C) 2009-2012 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 notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS. IN NO EVENT SHALL 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.
-#
-# Portions copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN")
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS. IN NO EVENT SHALL ARIN 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.
-
-"""
-XML utilities.
-"""
-
-import logging
-import lxml.etree
-import rpki.exceptions
-
-logger = logging.getLogger(__name__)
-
-
-class base_elt(object):
- """
- Virtual base class for XML message elements. The left-right and
- publication_control protocols use this.
- """
-
- ## @var attributes
- # XML attributes for this element.
- attributes = ()
-
- ## @var elements
- # XML elements contained by this element.
- elements = ()
-
- ## @var booleans
- # Boolean attributes (value "yes" or "no") for this element.
- booleans = ()
-
- ## @var text_attribute
- # Name of class attribute that tells us where to put text values, if any.
- text_attribute = None
-
- @classmethod
- def fromXML(cls, elt):
- """
- First cut at non-SAX message unpacker. This will probably change.
- """
-
- self = cls()
-
- for key in self.attributes:
- val = elt.get(key, None)
- if val is not None:
- val = val.encode("ascii")
- if isinstance(self.attributes, dict) and self.attributes[key] is not None:
- val = self.attributes[key](val)
- elif val.isdigit() and not key.endswith("_handle"):
- val = long(val)
- setattr(self, key, val)
- for key in self.booleans:
- setattr(self, key, elt.get(key, False))
-
- # This test could go in an extended method in text_elt. Then
- # again, perhaps spreading the logic in as many places as we
- # possibly can is not really helping matters....
-
- if self.text_attribute is not None:
- setattr(self, self.text_attribute, elt.text)
-
- # In the long run, we probably want the key for that to include
- # the namespace, but that would break the current .toXML() code,
- # so kludge it for now.
-
- for b64 in elt:
- assert b64.tag.startswith(self.xmlns)
- ename = b64.tag[len(self.xmlns):]
- etype = self.elements[ename]
- setattr(self, ename, etype(Base64 = b64.text))
-
- return self
-
- def toXML(self):
- """
- Default toXML() element generator.
- """
-
- return self.make_elt()
-
- def read_attrs(self, attrs):
- """
- Template-driven attribute reader.
- """
-
- def make_elt(self):
- """
- XML element constructor.
- """
-
- elt = lxml.etree.Element(self.xmlns + self.element_name, nsmap = self.nsmap)
- for key in self.attributes:
- val = getattr(self, key, None)
- if val is not None:
- elt.set(key, str(val))
- for key in self.booleans:
- if getattr(self, key, False):
- elt.set(key, "yes")
- return elt
-
- def make_b64elt(self, elt, name, value):
- """
- Constructor for Base64-encoded subelement.
- """
-
- if value is not None and not value.empty():
- lxml.etree.SubElement(elt, self.xmlns + name, nsmap = self.nsmap).text = value.get_Base64()
-
- def __str__(self):
- """
- Convert a base_elt object to string format.
- """
-
- return lxml.etree.tostring(self.toXML(), pretty_print = True, encoding = "us-ascii")
-
- @classmethod
- def make_pdu(cls, **kargs):
- """
- Generic PDU constructor.
- """
-
- self = cls()
- for k, v in kargs.items():
- if isinstance(v, bool):
- v = 1 if v else 0
- setattr(self, k, v)
- return self
-
-class text_elt(base_elt):
- """
- Virtual base class for XML message elements that contain text.
- """
-
- def toXML(self):
- """
- Insert text into generated XML.
- """
-
- elt = self.make_elt()
- elt.text = getattr(self, self.text_attribute) or None
- return elt
-
-class data_elt(base_elt):
- """
- Virtual base class for PDUs that map to SQL objects. These objects
- all implement the create/set/get/list/destroy action attribute.
- """
-
- def toXML(self):
- """
- Default element generator for SQL-based objects. This assumes
- that sub-elements are Base64-encoded DER objects.
- """
-
- elt = self.make_elt()
- for i in self.elements:
- self.make_b64elt(elt, i, getattr(self, i, None))
- return elt
-
- def make_reply(self, r_pdu = None):
- """
- Construct a reply PDU.
- """
-
- if r_pdu is None:
- r_pdu = self.__class__()
- self.make_reply_clone_hook(r_pdu)
- handle_name = self.element_name + "_handle"
- setattr(r_pdu, handle_name, getattr(self, handle_name, None))
- else:
- self.make_reply_clone_hook(r_pdu)
- for b in r_pdu.booleans:
- setattr(r_pdu, b, False)
- r_pdu.action = self.action
- r_pdu.tag = self.tag
- return r_pdu
-
- def make_reply_clone_hook(self, r_pdu):
- """
- Overridable hook.
- """
-
- pass
-
- def serve_fetch_one(self):
- """
- Find the object on which a get, set, or destroy method should
- operate.
- """
-
- r = self.serve_fetch_one_maybe()
- if r is None:
- raise rpki.exceptions.NotFound
- return r
-
- def serve_pre_save_hook(self, q_pdu, r_pdu, cb, eb):
- """
- Overridable hook.
- """
-
- cb()
-
- def serve_post_save_hook(self, q_pdu, r_pdu, cb, eb):
- """
- Overridable hook.
- """
-
- cb()
-
- def serve_create(self, r_msg, cb, eb):
- """
- Handle a create action.
- """
-
- r_pdu = self.make_reply()
-
- def one():
- self.sql_store()
- setattr(r_pdu, self.sql_template.index, getattr(self, self.sql_template.index))
- self.serve_post_save_hook(self, r_pdu, two, eb)
-
- def two():
- r_msg.append(r_pdu)
- cb()
-
- oops = self.serve_fetch_one_maybe()
- if oops is not None:
- raise rpki.exceptions.DuplicateObject("Object already exists: %r[%r] %r[%r]" % (self, getattr(self, self.element_name + "_handle"),
- oops, getattr(oops, oops.element_name + "_handle")))
-
- self.serve_pre_save_hook(self, r_pdu, one, eb)
-
- def serve_set(self, r_msg, cb, eb):
- """
- Handle a set action.
- """
-
- db_pdu = self.serve_fetch_one()
- r_pdu = self.make_reply()
- for a in db_pdu.sql_template.columns[1:]:
- v = getattr(self, a, None)
- if v is not None:
- setattr(db_pdu, a, v)
- db_pdu.sql_mark_dirty()
-
- def one():
- db_pdu.sql_store()
- db_pdu.serve_post_save_hook(self, r_pdu, two, eb)
-
- def two():
- r_msg.append(r_pdu)
- cb()
-
- db_pdu.serve_pre_save_hook(self, r_pdu, one, eb)
-
- def serve_get(self, r_msg, cb, eb):
- """
- Handle a get action.
- """
-
- r_pdu = self.serve_fetch_one()
- self.make_reply(r_pdu)
- r_msg.append(r_pdu)
- cb()
-
- def serve_list(self, r_msg, cb, eb):
- """
- Handle a list action for non-self objects.
- """
-
- for r_pdu in self.serve_fetch_all():
- self.make_reply(r_pdu)
- r_msg.append(r_pdu)
- cb()
-
- def serve_destroy_hook(self, cb, eb):
- """
- Overridable hook.
- """
-
- cb()
-
- def serve_destroy(self, r_msg, cb, eb):
- """
- Handle a destroy action.
- """
-
- def done():
- db_pdu.sql_delete()
- r_msg.append(self.make_reply())
- cb()
- db_pdu = self.serve_fetch_one()
- db_pdu.serve_destroy_hook(done, eb)
-
- def serve_dispatch(self, r_msg, cb, eb):
- """
- Action dispatch handler.
- """
-
- # Transition hack: handle the .toXML() call for old handlers.
-
- fake_r_msg = []
-
- def fake_convert():
- r_msg.extend(r_pdu.toXML() if isinstance(r_pdu, base_elt) else r_pdu
- for r_pdu in fake_r_msg)
-
- def fake_cb():
- fake_convert()
- cb()
-
- def fake_eb(e):
- fake_convert()
- eb(e)
-
- method = getattr(self, "serve_" + self.action, None)
- if method is None:
- raise rpki.exceptions.BadQuery("Unexpected query: action %s" % self.action)
- method(fake_r_msg, fake_cb, fake_eb)
-
- def unimplemented_control(self, *controls):
- """
- Uniform handling for unimplemented control operations.
- """
-
- unimplemented = [x for x in controls if getattr(self, x, False)]
- if unimplemented:
- raise rpki.exceptions.NotImplementedYet("Unimplemented control %s" % ", ".join(unimplemented))