aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xca/irbe_cli31
-rw-r--r--ca/rpki-confgen.xml32
-rwxr-xr-xca/rpki-manage17
-rwxr-xr-xca/rpki-sql-backup2
-rwxr-xr-xca/rpki-sql-setup4
-rwxr-xr-xca/rpki-start-servers4
-rw-r--r--ca/rpki.wsgi3
-rw-r--r--ca/tests/smoketest.py19
-rw-r--r--ca/tests/sql-cleaner.py2
-rw-r--r--ca/tests/sql-dumper.py2
-rwxr-xr-xca/tests/test-rrdp.py2
-rw-r--r--ca/tests/yamlconf.py29
-rw-r--r--ca/tests/yamltest.py107
-rw-r--r--potpourri/upgrade-add-ghostbusters.py2
-rw-r--r--rpki/config.py87
-rw-r--r--rpki/db_router.py57
-rw-r--r--rpki/django_settings.py245
-rw-r--r--rpki/fields.py192
-rw-r--r--rpki/gui/decorators.py14
-rw-r--r--rpki/gui/default_settings.py172
-rw-r--r--rpki/gui/script_util.py43
-rw-r--r--rpki/irdb/migrations/0001_initial.py595
-rw-r--r--rpki/irdb/migrations/__init__.py0
-rw-r--r--rpki/irdb/models.py124
-rw-r--r--rpki/irdbd.py31
-rw-r--r--rpki/old_irdbd.py4
-rw-r--r--rpki/pubd.py4
-rw-r--r--rpki/pubdb/__init__.py3
-rw-r--r--rpki/rootd.py4
-rw-r--r--rpki/rpkic.py44
-rw-r--r--rpki/rpkid.py4
-rw-r--r--rpki/rpkidb/__init__.py3
32 files changed, 1404 insertions, 478 deletions
diff --git a/ca/irbe_cli b/ca/irbe_cli
index 1becd403..cd9c2165 100755
--- a/ca/irbe_cli
+++ b/ca/irbe_cli
@@ -305,7 +305,7 @@ for o, a in opts:
if not argv:
usage(1)
-cfg = rpki.config.parser(cfg_file, "irbe_cli")
+cfg = rpki.config.parser(set_filename = cfg_file, section = "irbe_cli")
q_msg_left_right = []
q_msg_publication = []
@@ -322,19 +322,22 @@ while argv:
argv = q_pdu.client_getopt(argv[1:])
q_msg.append(q_pdu)
-from django.conf import settings
-
-settings.configure(
- DATABASES = { "default" : {
- "ENGINE" : "django.db.backends.mysql",
- "NAME" : cfg.get("sql-database", section = "irdbd"),
- "USER" : cfg.get("sql-username", section = "irdbd"),
- "PASSWORD" : cfg.get("sql-password", section = "irdbd"),
- "HOST" : "",
- "PORT" : "",
- "OPTIONS" : { "init_command": "SET storage_engine=INNODB" }}},
- INSTALLED_APPS = ("rpki.irdb",),
-)
+if True:
+ os.environ.update(DJANGO_SETTINGS_MODULE = "rpki.django_settings")
+
+else:
+ from django.conf import settings
+ settings.configure(
+ DATABASES = { "default" : {
+ "ENGINE" : "django.db.backends.mysql",
+ "NAME" : cfg.get("sql-database", section = "irdbd"),
+ "USER" : cfg.get("sql-username", section = "irdbd"),
+ "PASSWORD" : cfg.get("sql-password", section = "irdbd"),
+ "HOST" : "",
+ "PORT" : "",
+ "OPTIONS" : { "init_command": "SET storage_engine=INNODB" }}},
+ INSTALLED_APPS = ("rpki.irdb",),
+ )
import rpki.irdb
diff --git a/ca/rpki-confgen.xml b/ca/rpki-confgen.xml
index 1928c2db..b3e50823 100644
--- a/ca/rpki-confgen.xml
+++ b/ca/rpki-confgen.xml
@@ -862,30 +862,18 @@
<section name = "web_portal">
<doc>
- Glue to allow the Django application to pull user configuration
- from this file rather than directly editing settings.py.
+ Glue to allow Django to pull user configuration from this file
+ rather than requiring the user to edit settings.py.
</doc>
- <option name = "sql-database"
- value = "${myrpki::irdbd_sql_database}">
- <doc>
- SQL database name the web portal should use.
- </doc>
- </option>
-
- <option name = "sql-username"
- value = "${myrpki::irdbd_sql_username}">
- <doc>
- SQL user name the web portal should use.
- </doc>
- </option>
-
- <option name = "sql-password"
- value = "${myrpki::irdbd_sql_password}">
- <doc>
- SQL password the web portal should use.
- </doc>
- </option>
+ <!--
+ We used to have SQL settings for the GUI here, but since
+ they're pretty much required to be identical to the ones for
+ irdbd at this point, the duplicate entries were just another
+ chance to misconfigure something, so I removed them. Not yet
+ sure whether this was the right approach. Too much historical
+ baggage in this file.
+ -->
<option name = "secret-key">
<doc>
diff --git a/ca/rpki-manage b/ca/rpki-manage
index 0d581ce9..db1e9ce3 100755
--- a/ca/rpki-manage
+++ b/ca/rpki-manage
@@ -5,9 +5,20 @@ from django.core.management import execute_from_command_line
# django-admin seems to have problems creating the superuser account when
# $LANG is unset or is set to something totally incompatible with UTF-8.
-if os.environ.get('LANG') in (None, "", "C"):
- os.environ['LANG'] = 'en_US.UTF-8'
-os.environ['DJANGO_SETTINGS_MODULE'] = 'rpki.gui.default_settings'
+if os.environ.get("LANG") in (None, "", "C"):
+ os.environ["LANG"] = "en_US.UTF-8"
+
+# Where to find the Django settings module
+
+os.environ.update(DJANGO_SETTINGS_MODULE = "rpki.django_settings")
+
+# We don't know whether we're being used to configure the GUI or not
+# (well, not without examining the specific command, which we'd like
+# to avoid). Default to enabling the GUI so that such commands will
+# work, but allow the user to override via the environment variable.
+
+if not os.environ.get("RPKI_GUI_ENABLE"):
+ os.environ["RPKI_GUI_ENABLE"] = "yes"
execute_from_command_line()
diff --git a/ca/rpki-sql-backup b/ca/rpki-sql-backup
index e60f9ae3..02835956 100755
--- a/ca/rpki-sql-backup
+++ b/ca/rpki-sql-backup
@@ -41,7 +41,7 @@ parser.add_argument("-o", "--output",
help = "destination for SQL dump (default: stdout)")
args = parser.parse_args()
-cfg = rpki.config.parser(args.config, "myrpki")
+cfg = rpki.config.parser(set_filename = args.config, section = "myrpki")
for name in ("rpkid", "irdbd", "pubd"):
if cfg.getboolean("start_" + name, False):
diff --git a/ca/rpki-sql-setup b/ca/rpki-sql-setup
index edc2c242..848e3d0f 100755
--- a/ca/rpki-sql-setup
+++ b/ca/rpki-sql-setup
@@ -54,7 +54,7 @@ class RootDB(object):
user = "root",
passwd = getpass.getpass("Please enter your MySQL root password: "))
else:
- mysql_cfg = rpki.config.parser(self.mysql_defaults, "client")
+ mysql_cfg = rpki.config.parser(set_filename = self.mysql_defaults, section = "client")
self.db = MySQLdb.connect(db = "mysql",
user = mysql_cfg.get("user"),
passwd = mysql_cfg.get("password"))
@@ -299,7 +299,7 @@ parser.set_defaults(dispatch = do_create_if_missing)
args = parser.parse_args()
try:
- cfg = rpki.config.parser(args.config, "myrpki")
+ cfg = rpki.config.parser(set_filename = args.config, section = "myrpki")
root = RootDB(args.mysql_defaults)
current_version = Version(rpki.version.VERSION)
for program_name in ("irdbd", "rpkid", "pubd"):
diff --git a/ca/rpki-start-servers b/ca/rpki-start-servers
index 8a745896..f1f70aa8 100755
--- a/ca/rpki-start-servers
+++ b/ca/rpki-start-servers
@@ -64,13 +64,13 @@ group.add_argument("--log-syslog", default = "daemon", nargs = "?",
help = "log syslog")
args = parser.parse_args()
-cfg = rpki.config.parser(args.config, "myrpki")
+cfg = rpki.config.parser(set_filename = args.config, section = "myrpki")
def run(name, old_flag = None):
if cfg.getboolean("start_" + name, cfg.getboolean("run_" + name if old_flag is None else old_flag, False)):
# pylint: disable=E1103
log_file = os.path.join(args.log_directory, name + ".log")
- cmd = (os.path.join(rpki.autoconf.libexecdir, name), "--config", cfg.filename, "--log-level", args.log_level)
+ cmd = (os.path.join(rpki.autoconf.libexecdir, name), "--log-level", args.log_level)
if args.log_file:
cmd += ("--log-file", log_file)
elif args.log_rotating_file_kbytes:
diff --git a/ca/rpki.wsgi b/ca/rpki.wsgi
index 72ba75ac..7fa85d73 100644
--- a/ca/rpki.wsgi
+++ b/ca/rpki.wsgi
@@ -21,7 +21,8 @@ import sys
import os
import rpki.autoconf
-os.environ['DJANGO_SETTINGS_MODULE'] = 'rpki.gui.default_settings'
+os.environ.update(DJANGO_SETTINGS_MODULE = "rpki.django_settings",
+ RPKI_GUI_ENABLE = "yes")
# Needed for local_settings.py
sys.path.insert(1, rpki.autoconf.sysconfdir + '/rpki')
diff --git a/ca/tests/smoketest.py b/ca/tests/smoketest.py
index 28905d90..bf949a97 100644
--- a/ca/tests/smoketest.py
+++ b/ca/tests/smoketest.py
@@ -68,7 +68,7 @@ parser.add_argument("yaml_file", type = argparse.FileType("r"),
help = "YAML description of test network")
args = parser.parse_args()
-cfg = rpki.config.parser(args.config, "smoketest", allow_missing = True)
+cfg = rpki.config.parser(set_filename = args.config, section = "smoketest", allow_missing = True)
# Load the YAML script early, so we can report errors ASAP
@@ -233,11 +233,13 @@ def main():
try:
logger.info("Starting rootd")
- rootd_process = subprocess.Popen((prog_python, prog_rootd, "--foreground", "--log-stdout", "--log-level", "debug", "--config", rootd_name + ".conf"))
+ rootd_process = subprocess.Popen((prog_python, prog_rootd, "--foreground", "--log-stdout", "--log-level", "debug"),
+ env = dict(os.environ, RPKI_CONF = rootd_name + ".conf"))
logger.info("Starting pubd")
- pubd_process = subprocess.Popen((prog_python, prog_pubd, "--foreground", "--log-stdout", "--log-level", "debug", "--config", pubd_name + ".conf") +
- (("-p", pubd_name + ".prof") if args.profile else ()))
+ pubd_process = subprocess.Popen((prog_python, prog_pubd, "--foreground", "--log-stdout", "--log-level", "debug") +
+ (("-p", pubd_name + ".prof") if args.profile else ()),
+ env = dict(os.environ, RPKI_CONF = pubd_name + ".conf"))
logger.info("Starting rsyncd")
rsyncd_process = subprocess.Popen((prog_rsyncd, "--daemon", "--no-detach", "--config", rsyncd_name + ".conf"))
@@ -864,9 +866,12 @@ class allocation(object):
"""
logger.info("Running daemons for %s", self.name)
- self.rpkid_process = subprocess.Popen((prog_python, prog_rpkid, "--foreground", "--log-stdout", "--log-level", "debug", "--config", self.name + ".conf") +
- (("--profile", self.name + ".prof") if args.profile else ()))
- self.irdbd_process = subprocess.Popen((prog_python, prog_irdbd, "--foreground", "--log-stdout", "--log-level", "debug", "--config", self.name + ".conf"))
+ env = dict(os.environ, RPKI_CONF = self.name + ".conf")
+ self.rpkid_process = subprocess.Popen((prog_python, prog_rpkid, "--foreground", "--log-stdout", "--log-level", "debug") +
+ (("--profile", self.name + ".prof") if args.profile else ()),
+ env = env)
+ self.irdbd_process = subprocess.Popen((prog_python, prog_irdbd, "--foreground", "--log-stdout", "--log-level", "debug"),
+ env = env)
def kill_daemons(self):
"""
diff --git a/ca/tests/sql-cleaner.py b/ca/tests/sql-cleaner.py
index ca88d456..0f0b55b1 100644
--- a/ca/tests/sql-cleaner.py
+++ b/ca/tests/sql-cleaner.py
@@ -22,7 +22,7 @@ import rpki.config
import rpki.sql_schemas
from rpki.mysql_import import MySQLdb
-cfg = rpki.config.parser(None, "yamltest", allow_missing = True)
+cfg = rpki.config.parser(section = "yamltest", allow_missing = True)
for name in ("rpkid", "irdbd", "pubd"):
diff --git a/ca/tests/sql-dumper.py b/ca/tests/sql-dumper.py
index 19cc1b34..d0fe3489 100644
--- a/ca/tests/sql-dumper.py
+++ b/ca/tests/sql-dumper.py
@@ -22,7 +22,7 @@ import subprocess
import rpki.config
from rpki.mysql_import import MySQLdb
-cfg = rpki.config.parser(None, "yamltest", allow_missing = True)
+cfg = rpki.config.parser(section = "yamltest", allow_missing = True)
for name in ("rpkid", "irdbd", "pubd"):
diff --git a/ca/tests/test-rrdp.py b/ca/tests/test-rrdp.py
index de30a0f4..98918bad 100755
--- a/ca/tests/test-rrdp.py
+++ b/ca/tests/test-rrdp.py
@@ -52,7 +52,7 @@ def snapshot_to_serial(fn):
def delta_to_serial(fn):
return int(os.path.splitext(os.path.basename(fn))[0].split("-")[1])
-top = os.path.expanduser("~/rpki/subvert-rpki.hactrn.net/branches/tk705")
+top = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "..", ".."))
rrdp_test_tool = os.path.join(top, "potpourri/rrdp-test-tool")
rcynic = os.path.join(top, "rp/rcynic/rcynic")
diff --git a/ca/tests/yamlconf.py b/ca/tests/yamlconf.py
index 8f956c6b..bb82ef74 100644
--- a/ca/tests/yamlconf.py
+++ b/ca/tests/yamlconf.py
@@ -125,7 +125,7 @@ class router_cert(object):
def __init__(self, asn, router_id):
self.asn = rpki.resource_set.resource_set_as("".join(str(asn).split()))
self.router_id = router_id
- self.keypair = rpki.x509.ECDSA.generate(self.ecparams())
+ self.keypair = rpki.x509.ECDSA.generate(params = self.ecparams(), quiet = True)
self.pkcs10 = rpki.x509.PKCS10.create(keypair = self.keypair)
self.gski = self.pkcs10.gSKI()
@@ -491,16 +491,18 @@ class allocation(object):
def syncdb(self):
import django.core.management
assert not self.is_hosted
- django.core.management.call_command("syncdb",
- database = self.irdb_name,
- load_initial_data = False,
- interactive = False,
- verbosity = 0)
+ django.core.management.call_command(
+ "syncdb",
+ verbosity = 0,
+ database = self.irdb_name,
+ migrate = True,
+ load_initial_data = False,
+ interactive = False)
def hire_zookeeper(self):
assert not self.is_hosted
self._zoo = rpki.irdb.Zookeeper(
- cfg = rpki.config.parser(self.path("rpki.conf")),
+ cfg = rpki.config.parser(filename = self.path("rpki.conf")),
logstream = None if quiet else sys.stdout)
@property
@@ -681,7 +683,7 @@ def main():
# passwords: this is mostly so that I can show a complete working
# example without publishing my own server's passwords.
- cfg = rpki.config.parser(args.config, "yamlconf", allow_missing = True)
+ cfg = rpki.config.parser(set_filename = args.config, section = "yamlconf", allow_missing = True)
try:
cfg.set_global_flags()
except:
@@ -755,9 +757,13 @@ def body():
pre_django_sql_setup(set(d.irdb_name for d in db if not d.is_hosted))
# Now ready for fun with multiple databases in Django!
-
+ #
# https://docs.djangoproject.com/en/1.4/topics/db/multi-db/
# https://docs.djangoproject.com/en/1.4/topics/db/sql/
+ #
+ # This program's use of the ORM is sufficiently different that it's
+ # not worth straining to use rpki.django_settings, so we just use
+ # Django's settings API directly.
database_template = {
"ENGINE" : "django.db.backends.mysql",
@@ -767,8 +773,7 @@ def body():
"PORT" : "",
"OPTIONS" : { "init_command": "SET storage_engine=INNODB" }}
- databases = dict((d.irdb_name,
- dict(database_template, NAME = d.irdb_name))
+ databases = dict((d.irdb_name, dict(database_template, NAME = d.irdb_name))
for d in db if not d.is_hosted)
databases["default"] = databases[db.root.irdb_name]
@@ -778,7 +783,7 @@ def body():
settings.configure(
DATABASES = databases,
DATABASE_ROUTERS = ["rpki.irdb.router.DBContextRouter"],
- INSTALLED_APPS = ("rpki.irdb",))
+ INSTALLED_APPS = ("rpki.irdb", "south"))
import rpki.irdb
diff --git a/ca/tests/yamltest.py b/ca/tests/yamltest.py
index 67758e82..84355e59 100644
--- a/ca/tests/yamltest.py
+++ b/ca/tests/yamltest.py
@@ -43,6 +43,7 @@ import re
import os
import logging
import argparse
+import webbrowser
import sys
import yaml
import signal
@@ -74,13 +75,14 @@ def cleanpath(*names):
this_dir = os.getcwd()
test_dir = cleanpath(this_dir, "yamltest.dir")
-rpkid_dir = cleanpath(this_dir, "..")
+ca_dir = cleanpath(this_dir, "..")
-prog_rpkic = cleanpath(rpkid_dir, "rpkic")
-prog_rpkid = cleanpath(rpkid_dir, "rpkid")
-prog_irdbd = cleanpath(rpkid_dir, "irdbd")
-prog_pubd = cleanpath(rpkid_dir, "pubd")
-prog_rootd = cleanpath(rpkid_dir, "rootd")
+prog_rpkic = cleanpath(ca_dir, "rpkic")
+prog_rpkid = cleanpath(ca_dir, "rpkid")
+prog_irdbd = cleanpath(ca_dir, "irdbd")
+prog_pubd = cleanpath(ca_dir, "pubd")
+prog_rootd = cleanpath(ca_dir, "rootd")
+prog_rpki_manage = cleanpath(ca_dir, "rpki-manage")
class roa_request(object):
"""
@@ -131,7 +133,7 @@ class router_cert(object):
def __init__(self, asn, router_id):
self.asn = rpki.resource_set.resource_set_as("".join(str(asn).split()))
self.router_id = router_id
- self.keypair = rpki.x509.ECDSA.generate(self.ecparams())
+ self.keypair = rpki.x509.ECDSA.generate(params = self.ecparams(), quiet = True)
self.pkcs10 = rpki.x509.PKCS10.create(keypair = self.keypair)
self.gski = self.pkcs10.gSKI()
@@ -156,7 +158,7 @@ class allocation_db(list):
def __init__(self, yaml):
list.__init__(self)
self.root = allocation(yaml, self)
- assert self.root.is_root
+ assert self.root.is_root and not any(a.is_root for a in self if a is not self.root) and self[0] is self.root
if self.root.crl_interval is None:
self.root.crl_interval = 60 * 60
if self.root.regen_margin is None:
@@ -506,7 +508,7 @@ class allocation(object):
print "Writing", f.name
section = None
- for line in open(cleanpath(rpkid_dir, "examples/rpki.conf")):
+ for line in open(cleanpath(ca_dir, "examples/rpki.conf")):
m = section_regexp.match(line)
if m:
section = m.group(1)
@@ -551,16 +553,42 @@ class allocation(object):
Run rpkic for this entity.
"""
- cmd = [prog_rpkic, "-i", self.name, "-c", self.path("rpki.conf")]
+ cmd = [prog_rpkic, "-i", self.name]
if args.profile:
cmd.append("--profile")
cmd.append(self.path("rpkic.%s.prof" % rpki.sundial.now()))
cmd.extend(str(a) for a in argv if a is not None)
print 'Running "%s"' % " ".join(cmd)
- env = os.environ.copy()
- env["YAMLTEST_RPKIC_COUNTER"] = self.next_rpkic_counter()
+ env = dict(os.environ,
+ YAMLTEST_RPKIC_COUNTER = self.next_rpkic_counter(),
+ RPKI_CONF = self.path("rpki.conf"))
subprocess.check_call(cmd, cwd = self.host.path(), env = env)
+ def syncdb(self, run_gui):
+ """
+ Run whatever Django ORM commands are necessary to set up the
+ database this week.
+
+ This may end up moving back into rpkic as an explicit command, but
+ for the moment I'm assuming that production use handle this via
+ rpki-sql-setup and that we therefore must do it ourselves for
+ testing. We'll see.
+ """
+
+ if not os.fork():
+ os.environ.update(RPKI_CONF = self.path("rpki.conf"),
+ RPKI_GUI_ENABLE = "yes")
+ logging.getLogger().setLevel(logging.WARNING)
+ import django.core.management
+ django.core.management.call_command("syncdb", migrate = True, verbosity = 0,
+ load_initial_data = False, interactive = False)
+ from django.contrib.auth.models import User
+ User.objects.create_superuser("root", "root@example.org", "fnord")
+ sys.exit(0)
+
+ if os.wait()[1]:
+ raise RuntimeError("Django setup failed for %s" % self.name)
+
def run_python_daemon(self, prog):
"""
Start a Python daemon and return a subprocess.Popen object
@@ -569,13 +597,13 @@ class allocation(object):
basename = os.path.splitext(os.path.basename(prog))[0]
cmd = [prog, "--foreground", "--log-level", "debug",
- "--log-file", self.path(basename + ".log"),
- "--config", self.path("rpki.conf")]
+ "--log-file", self.path(basename + ".log")]
if args.profile and basename != "rootd":
cmd.extend((
"--profile", self.path(basename + ".prof")))
- p = subprocess.Popen(cmd, cwd = self.path())
- print 'Running %s for %s: pid %d process %r' % (" ".join(cmd), self.name, p.pid, p)
+ env = dict(os.environ, RPKI_CONF = self.path("rpki.conf"))
+ p = subprocess.Popen(cmd, cwd = self.path(), env = env)
+ print "Running %s for %s: pid %d process %r" % (" ".join(cmd), self.name, p.pid, p)
return p
def run_rpkid(self):
@@ -616,6 +644,24 @@ class allocation(object):
print "Running rsyncd for %s: pid %d process %r" % (self.name, p.pid, p)
return p
+ def run_gui(self):
+ """
+ Start an instance of the RPKI GUI under the Django test server and
+ return a subprocess.Popen object representing the running daemon.
+ """
+
+ port = 8000 + self.engine
+ cmd = (prog_rpki_manage, "runserver", str(port))
+ env = dict(os.environ,
+ RPKI_CONF = self.path("rpki.conf"),
+ RPKI_DJANGO_DEBUG = "yes",
+ ALLOW_PLAIN_HTTP_FOR_TESTING = "I solemnly swear that I am not running this in production")
+ p = subprocess.Popen(cmd, cwd = self.path(), env = env,
+ stdout = open(self.path("gui.log"), "w"), stderr = subprocess.STDOUT)
+ print "Running %s for %s: pid %d process %r" % (" ".join(cmd), self.name, p.pid, p)
+ return p
+
+
def create_root_certificate(db_root):
print "Creating rootd RPKI root certificate"
@@ -650,8 +696,10 @@ def create_root_certificate(db_root):
f.write(root_key.get_public().get_Base64())
+logger = logging.getLogger(__name__)
-os.environ["TZ"] = "UTC"
+os.environ.update(DJANGO_SETTINGS_MODULE = "rpki.django_settings",
+ TZ = "UTC")
time.tzset()
parser = argparse.ArgumentParser(description = __doc__)
@@ -671,6 +719,10 @@ parser.add_argument("--synchronize", action = "store_true",
help = "synchronize IRDB with daemons")
parser.add_argument("--profile", action = "store_true",
help = "enable profiling")
+parser.add_argument("-g", "--run_gui", action = "store_true",
+ help = "enable GUI using django-admin runserver")
+parser.add_argument("--browser", action = "store_true",
+ help = "create web browser tabs for GUI")
parser.add_argument("yaml_file", type = argparse.FileType("r"),
help = "YAML description of test network")
args = parser.parse_args()
@@ -687,7 +739,7 @@ try:
# passwords: this is mostly so that I can show a complete working
# example without publishing my own server's passwords.
- cfg = rpki.config.parser(args.config, "yamltest", allow_missing = True)
+ cfg = rpki.config.parser(set_filename = args.config, section = "yamltest", allow_missing = True)
only_one_pubd = cfg.getboolean("only_one_pubd", True)
allocation.base_port = cfg.getint("base_port", 4400)
@@ -728,6 +780,7 @@ try:
for d in db:
if not d.is_hosted:
+ print "Initializing", d.name
os.makedirs(d.path())
d.dump_conf()
if d.runs_pubd:
@@ -735,7 +788,9 @@ try:
d.dump_rsyncd()
if d.is_root:
os.makedirs(d.path("publication.root"))
+ d.syncdb(args.run_gui)
d.run_rpkic("initialize_server_bpki")
+ print
# Initialize resource holding BPKI and generate self-descriptor
# for each entity.
@@ -773,6 +828,8 @@ try:
if d.runs_pubd:
progs.append(d.run_pubd())
progs.append(d.run_rsyncd())
+ if args.run_gui:
+ progs.append(d.run_gui())
if args.synchronize or not args.skip_config:
@@ -841,6 +898,20 @@ try:
d.dump_ghostbusters()
d.dump_router_certificates()
+ if args.run_gui:
+ print
+ print 'GUI user "root", password "fnord"'
+ for d in db:
+ if not d.is_hosted:
+ url = "http://127.0.0.1:%d/rpki/" % (8000 + d.engine)
+ print "GUI URL", url, "for", d.name
+ if args.browser:
+ if d is db.root:
+ webbrowser.open_new(url)
+ else:
+ webbrowser.open_new_tab(url)
+ time.sleep(2)
+
# Wait until something terminates.
if not args.stop_after_config or args.keep_going:
diff --git a/potpourri/upgrade-add-ghostbusters.py b/potpourri/upgrade-add-ghostbusters.py
index a8c8a92b..2548487c 100644
--- a/potpourri/upgrade-add-ghostbusters.py
+++ b/potpourri/upgrade-add-ghostbusters.py
@@ -43,7 +43,7 @@ for o, a in opts:
if o in ("-c", "--config"):
cfg_file = a
-cfg = rpki.config.parser(cfg_file, "myrpki")
+cfg = rpki.config.parser(filename = cfg_file, section = "myrpki")
fix("irdbd", """
CREATE TABLE ghostbuster_request (
diff --git a/rpki/config.py b/rpki/config.py
index 0e30982b..b8d25896 100644
--- a/rpki/config.py
+++ b/rpki/config.py
@@ -32,23 +32,16 @@ logger = logging.getLogger(__name__)
## @var default_filename
# Default name of config file if caller doesn't specify one explictly.
-default_filename = "rpki.conf"
-
-## @var default_dirname
-# Default name of directory to check for global config file, or None
-# if no global config file. Autoconf-generated code may set this to a
-# non-None value during script startup.
-
try:
import rpki.autoconf
- default_dirname = rpki.autoconf.sysconfdir
+ default_filename = os.path.join(rpki.autoconf.sysconfdir, "rpki.conf")
except ImportError:
- default_dirname = None
+ default_filename = None
-## @var default_envname
+## @var rpki_conf_envname
# Name of environment variable containing config file name.
-default_envname = "RPKI_CONF"
+rpki_conf_envname = "RPKI_CONF"
class parser(object):
"""
@@ -61,44 +54,48 @@ class parser(object):
get-methods with default values and default section name.
- If no filename is given to the constructor (filename = None), we
- check for an environment variable naming the config file, then we
- check for a default filename in the current directory, then finally
- we check for a global config file if autoconf provided a directory
- name to check.
+ If no filename is given to the constructor (filename and
+ set_filename both None), we check for an environment variable naming
+ the config file, then finally we check for a global config file if
+ autoconf provided a directory name to check.
+
+ NB: Programs which accept a configuration filename on the command
+ lines should pass that filename using set_filename so that we can
+ set the magic environment variable. Constraints from some external
+ libraries (principally Django) sometimes require library code to
+ look things up in the configuration file without the knowledge of
+ the controlling program, but setting the environment variable
+ insures that everybody's reading from the same script, as it were.
"""
- def __init__(self, filename = None, section = None, allow_missing = False):
+ # Odd keyword-only calling sequence is a defense against old code
+ # that thinks it knows how __init__() handles positional arguments.
+
+ def __init__(self, **kwargs):
+ section = kwargs.pop("section", None)
+ allow_missing = kwargs.pop("allow_missing", False)
+ set_filename = kwargs.pop("set_filename", None)
+ filename = kwargs.pop("filename", set_filename)
+
+ assert not kwargs, "Unexpected keyword arguments: " + ", ".join("%s = %r" % kv for kv in kwargs.iteritems())
+
+ if set_filename is not None:
+ os.environ[rpki_conf_envname] = set_filename
self.cfg = ConfigParser.RawConfigParser()
self.default_section = section
- filenames = []
- if filename is not None:
- filenames.append(filename)
- else:
- if default_envname in os.environ:
- filenames.append(os.environ[default_envname])
- filenames.append(default_filename)
- if default_dirname is not None:
- filenames.append("%s/%s" % (default_dirname, default_filename))
+ self.filename = filename or os.getenv(rpki_conf_envname) or default_filename
- f = fn = None
+ try:
+ with open(self.filename, "r") as f:
+ self.cfg.readfp(f)
+ except IOError:
+ if allow_missing:
+ self.filename = None
+ else:
+ raise
- for fn in filenames:
- try:
- f = open(fn)
- break
- except IOError:
- f = None
-
- if f is not None:
- self.filename = fn
- self.cfg.readfp(f, fn)
- elif allow_missing:
- self.filename = None
- else:
- raise
def has_section(self, section):
"""
@@ -107,6 +104,7 @@ class parser(object):
return self.cfg.has_section(section)
+
def has_option(self, option, section = None):
"""
Test whether an option exists.
@@ -116,6 +114,7 @@ class parser(object):
section = self.default_section
return self.cfg.has_option(section, option)
+
def multiget(self, option, section = None):
"""
Parse OpenSSL-style foo.0, foo.1, ... subscripted options.
@@ -134,6 +133,7 @@ class parser(object):
for option in matches:
yield self.cfg.get(section, option)
+
_regexp = re.compile("\\${(.*?)::(.*?)}")
def _repl(self, m):
@@ -148,6 +148,7 @@ class parser(object):
else:
return self.cfg.get(section, option)
+
def get(self, option, default = None, section = None):
"""
Get an option, perhaps with a default value.
@@ -163,6 +164,7 @@ class parser(object):
if not modified:
return val
+
def getboolean(self, option, default = None, section = None):
"""
Get a boolean option, perhaps with a default value.
@@ -176,6 +178,7 @@ class parser(object):
v = self.cfg._boolean_states[v]
return v
+
def getint(self, option, default = None, section = None):
"""
Get an integer option, perhaps with a default value.
@@ -183,6 +186,7 @@ class parser(object):
return int(self.get(option, default, section))
+
def getlong(self, option, default = None, section = None):
"""
Get a long integer option, perhaps with a default value.
@@ -190,6 +194,7 @@ class parser(object):
return long(self.get(option, default, section))
+
def set_global_flags(self):
"""
Consolidated control for all the little global control flags
diff --git a/rpki/db_router.py b/rpki/db_router.py
new file mode 100644
index 00000000..89ed6e5d
--- /dev/null
+++ b/rpki/db_router.py
@@ -0,0 +1,57 @@
+# $Id$
+
+# Copyright (C) 2014 Dragon Research Labs ("DRL")
+#
+# 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 DRL DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL DRL 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.
+
+"""
+Global Django ORM database router for the RPKI CA code.
+"""
+
+# Reference:
+# https://docs.djangoproject.com/en/1.6/topics/db/multi-db/
+
+class RPKIDBRouter(object):
+ """
+ Django ORM database router for RPKI code. rpkid and pubd get their
+ own databases, named "rpkidb" and "pubdb", respectively. Everything
+ else goes to the "default" database.
+ """
+
+ dedicated = ("rpkidb", "pubdb")
+
+ def db_for_read(self, model, **hints):
+ if model._meta.app_label in self.dedicated:
+ return model._meta.app_label
+ else:
+ return "default"
+
+ def db_for_write(self, model, **hints):
+ if model._meta.app_label in self.dedicated:
+ return model._meta.app_label
+ else:
+ return "default"
+
+ def allow_relation(self, obj1, obj2, **hints):
+ if obj1._meta.app_label in self.dedicated and obj1._meta.app_label == obj2._meta.app_label:
+ return True
+ elif obj1._meta.app_label not in self.dedicated and obj2._meta.app_label not in self.dedicated:
+ return True
+ else:
+ return None
+
+ def allow_syncdb(self, db, model):
+ if model._meta.app_label in self.dedicated:
+ return db == model._meta.app_label
+ else:
+ return db not in self.dedicated
diff --git a/rpki/django_settings.py b/rpki/django_settings.py
new file mode 100644
index 00000000..d3cadcfc
--- /dev/null
+++ b/rpki/django_settings.py
@@ -0,0 +1,245 @@
+# $Id$
+
+# Copyright (C) 2014 Dragon Research Labs ("DRL")
+#
+# 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 DRL DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL DRL 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.
+
+"""
+This module contains configuration settings for Django libraries.
+
+Most of our CA code uses at least the Django ORM; the web interface
+uses a lot more of Django. We also want to handle all normal user
+configuration via rpki.conf, so some of the code here is just pulling
+settings from rpki.conf and stuffing them into the form Django wants.
+"""
+
+__version__ = "$Id$"
+
+import os
+import socket
+
+import rpki.config
+import rpki.autoconf
+
+# Some configuration, including SQL authorization, comes from rpki.conf.
+cfg = rpki.config.parser()
+
+
+# Do -not- turn on DEBUG here except for short-lived tests, otherwise
+# long-running programs like irdbd will eventually run out of memory
+# and crash. This is also why this is controlled by an environment
+# variable rather than by an rpki.conf setting: just because we want
+# debugging enabled in the GUI doesn't mean we want it in irdb.
+#
+# If you must enable debugging, you may need to add code that uses
+# django.db.reset_queries() to clear the query list manually, but it's
+# probably better just to run with debugging disabled, since that's
+# the expectation for production code.
+#
+# https://docs.djangoproject.com/en/dev/faq/models/#why-is-django-leaking-memory
+
+if os.getenv("RPKI_DJANGO_DEBUG") == "yes":
+ DEBUG = True
+
+
+# Database configuration. This is always enabled, and uses a database
+# "router" to handle multiple databases. We may want to add yet
+# another database to hold South's migration tables, to avoid the
+# silliness of requiring an IRDB on, eg, a pubd-only server.
+#
+# We used to set an option to force MySQL to create InnnoDB databases,
+# and we used to set HOST and PORT to the null string, but all of
+# these are the defaults with recent versions of MySQL and Django, so
+# in theory none of them should be necessary.
+
+DATABASES = dict(
+ default = dict(ENGINE = "django.db.backends.mysql",
+ NAME = cfg.get("sql-database", section = "irdbd"),
+ USER = cfg.get("sql-username", section = "irdbd"),
+ PASSWORD = cfg.get("sql-password", section = "irdbd")))
+
+if cfg.getboolean("start_rpkid", section = "myrpki"):
+ DATABASES.update(
+ rpkidb = dict(ENGINE = "django.db.backends.mysql",
+ NAME = cfg.get("sql-database", section = "rpkid"),
+ USER = cfg.get("sql-username", section = "rpkid"),
+ PASSWORD = cfg.get("sql-password", section = "rpkid")))
+
+if cfg.getboolean("start_pubd", section = "myrpki"):
+ DATABASES.update(
+ pubdb = dict(ENGINE = "django.db.backends.mysql",
+ NAME = cfg.get("sql-database", section = "pubd"),
+ USER = cfg.get("sql-username", section = "pubd"),
+ PASSWORD = cfg.get("sql-password", section = "pubd")))
+
+# ORM database "router" to sort out which apps use which databases.
+
+DATABASE_ROUTERS = ["rpki.db_router.RPKIDBRouter"]
+
+# Figure out which apps we're running -- GUI code below adds many more.
+
+INSTALLED_APPS = ["south"]
+
+if cfg.getboolean("start_irdbd", section = "myrpki"):
+ INSTALLED_APPS.append("rpki.irdb")
+
+if cfg.getboolean("start_rpkid", section = "myrpki"):
+ INSTALLED_APPS.append("rpki.rpkidb")
+
+if cfg.getboolean("start_pubd", section = "myrpki"):
+ INSTALLED_APPS.append("rpki.pubdb")
+
+# That's about it if we just need the ORM, but Django throws a hissy
+# fit if SECRET_KEY isn't set, whether we use it for anything or not.
+#
+# Make this unique, and don't share it with anybody.
+if cfg.has_option("secret-key", section = "web_portal"):
+ SECRET_KEY = cfg.get("secret-key", section = "web_portal")
+else:
+ SECRET_KEY = os.urandom(66).encode("hex")
+
+
+# If we're the GUI (or a program like rpki-manage that might be
+# configuring the GUI) we need a lot of other stuff, so check for an
+# environment variable that rpki.wsgi and rpki-manage set for us.
+
+if os.getenv("RPKI_GUI_ENABLE") == "yes":
+
+ # Where to put static files.
+ STATIC_ROOT = rpki.autoconf.datarootdir + "/rpki/media"
+
+ # Must end with a slash!
+ STATIC_URL = "/media/"
+
+ # Where to email server errors.
+ ADMINS = (("Administrator", "root@localhost"),)
+
+ LOGGING = {
+ "version": 1,
+ "formatters": {
+ "verbose": {
+ # see http://docs.python.org/2.7/library/logging.html#logging.LogRecord
+ "format": "%(levelname)s %(asctime)s %(name)s %(message)s"
+ },
+ },
+ "handlers": {
+ "stderr": {
+ "class": "logging.StreamHandler",
+ "level": "DEBUG",
+ "formatter": "verbose",
+ },
+ "mail_admins": {
+ "level": "ERROR",
+ "class": "django.utils.log.AdminEmailHandler",
+ },
+ },
+ "loggers": {
+ "django": {
+ "level": "ERROR",
+ "handlers": ["stderr", "mail_admins"],
+ },
+ "rpki.gui": {
+ "level": "WARNING",
+ "handlers": ["stderr"],
+ },
+ },
+ }
+
+ def select_tz():
+ "Find a supported timezone that looks like UTC"
+ for tz in ("UTC", "GMT", "Etc/UTC", "Etc/GMT"):
+ if os.path.exists("/usr/share/zoneinfo/" + tz):
+ return tz
+ # Can't determine the proper timezone, fall back to UTC and let Django
+ # report the error to the user.
+ return "UTC"
+
+ # Local time zone for this installation. Choices can be found here:
+ # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+ # although not all choices may be available on all operating systems.
+ # If running in a Windows environment this must be set to the same as your
+ # system time zone.
+ TIME_ZONE = select_tz()
+
+ # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
+ # for details on why you might need this.
+ def get_allowed_hosts():
+ allowed_hosts = set(cfg.multiget("allowed-hosts", section = "web_portal"))
+ allowed_hosts.add(socket.getfqdn())
+ allowed_hosts.add("127.0.0.1")
+ allowed_hosts.add("::1")
+ try:
+ import netifaces
+ for interface in netifaces.interfaces():
+ addresses = netifaces.ifaddresses(interface)
+ for af in (netifaces.AF_INET, netifaces.AF_INET6):
+ if af in addresses:
+ for address in addresses[af]:
+ if "addr" in address:
+ allowed_hosts.add(address["addr"])
+ except ImportError:
+ pass
+ return list(allowed_hosts)
+
+ ALLOWED_HOSTS = get_allowed_hosts()
+
+ # List of callables that know how to import templates from various sources.
+ TEMPLATE_LOADERS = (
+ "django.template.loaders.filesystem.Loader",
+ "django.template.loaders.app_directories.Loader",
+ "django.template.loaders.eggs.Loader"
+ )
+
+ MIDDLEWARE_CLASSES = (
+ "django.middleware.common.CommonMiddleware",
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.middleware.csrf.CsrfViewMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "django.contrib.messages.middleware.MessageMiddleware"
+ )
+
+ ROOT_URLCONF = "rpki.gui.urls"
+
+ INSTALLED_APPS.extend((
+ "django.contrib.auth",
+ #"django.contrib.admin",
+ #"django.contrib.admindocs",
+ "django.contrib.contenttypes",
+ "django.contrib.sessions",
+ "django.contrib.staticfiles",
+ "rpki.gui.app",
+ "rpki.gui.cacheview",
+ "rpki.gui.routeview",
+ ))
+
+ TEMPLATE_CONTEXT_PROCESSORS = (
+ "django.contrib.auth.context_processors.auth",
+ "django.core.context_processors.debug",
+ "django.core.context_processors.i18n",
+ "django.core.context_processors.media",
+ "django.contrib.messages.context_processors.messages",
+ "django.core.context_processors.request",
+ "django.core.context_processors.static"
+ )
+
+# End of GUI-specific settings.
+
+
+# Allow local site to override any setting above -- but if there's
+# anything that local sites routinely need to modify, please consider
+# putting that configuration into rpki.conf and just adding code here
+# to read that configuration.
+try:
+ from local_settings import *
+except:
+ pass
diff --git a/rpki/fields.py b/rpki/fields.py
new file mode 100644
index 00000000..3d859aaa
--- /dev/null
+++ b/rpki/fields.py
@@ -0,0 +1,192 @@
+# $Id$
+#
+# Copyright (C) 2013--2014 Dragon Research Labs ("DRL")
+# Portions copyright (C) 2011--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 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.
+
+"""
+Common Django ORM field classes.
+
+Many of these are complex ASN.1 DER objects stored as SQL BLOBs, since
+the only sane text representation would just be the Base64 encoding of
+the DER and thus would add no value.
+"""
+
+from django.db import models
+from south.modelsinspector import add_introspection_rules
+
+import rpki.x509
+import rpki.sundial
+
+
+class EnumField(models.PositiveSmallIntegerField):
+ """
+ An enumeration type that uses strings in Python and small integers
+ in SQL.
+ """
+
+ description = "An enumeration type"
+
+ __metaclass__ = models.SubfieldBase
+
+ def __init__(self, *args, **kwargs):
+ if isinstance(kwargs.get("choices"), (tuple, list)) and isinstance(kwargs["choices"][0], (str, unicode)):
+ kwargs["choices"] = tuple(enumerate(kwargs["choices"], 1))
+ models.PositiveSmallIntegerField.__init__(self, *args, **kwargs)
+ self.enum_i2s = dict(self.flatchoices)
+ self.enum_s2i = dict((v, k) for k, v in self.flatchoices)
+
+ def to_python(self, value):
+ return self.enum_i2s.get(value, value)
+
+ def get_prep_value(self, value):
+ return self.enum_s2i.get(value, value)
+
+
+class SundialField(models.DateTimeField):
+ """
+ A field type for our customized datetime objects.
+ """
+ __metaclass__ = models.SubfieldBase
+
+ description = "A datetime type using our customized datetime objects"
+
+ def to_python(self, value):
+ if isinstance(value, rpki.sundial.pydatetime.datetime):
+ return rpki.sundial.datetime.from_datetime(
+ models.DateTimeField.to_python(self, value))
+ else:
+ return value
+
+ def get_prep_value(self, value):
+ if isinstance(value, rpki.sundial.datetime):
+ return value.to_datetime()
+ else:
+ return value
+
+
+class BlobField(models.Field):
+ """
+ Basic BLOB field, no type conversion, just an opaque byte string.
+
+ "BLOB" = "Binary Large OBject". Most SQL implementations seem to
+ have such a thing, but support appears to predate standardization,
+ so they all do it slightly differently and we have to cope.
+
+ In PostgreSQL, BLOBs are called "bytea".
+
+ In MySQL, there are different sizes of BLOBs and one must pick the
+ right one to avoid data truncation. RPKI manifests and CRLs can be
+ longer than 65535 octets, so in MySQL the only safe BLOB type for
+ general use is "LONGBLOB".
+
+ SQLite...is not like the other children: data types are more like
+ guidelines than actual rules. But "BLOB" works.
+
+ For anything else, we just use "BLOB" and hope for the best.
+ """
+
+ __metaclass__ = models.SubfieldBase
+ description = "Raw BLOB type without ASN.1 encoding/decoding"
+
+ def __init__(self, *args, **kwargs):
+ self.blob_type = kwargs.pop("blob_type", None)
+ kwargs["serialize"] = False
+ kwargs["blank"] = True
+ kwargs["default"] = None
+ models.Field.__init__(self, *args, **kwargs)
+
+ def db_type(self, connection):
+ if self.blob_type is not None:
+ return self.blob_type
+ elif connection.settings_dict['ENGINE'] == "django.db.backends.mysql":
+ return "LONGBLOB"
+ elif connection.settings_dict['ENGINE'] == "django.db.backends.posgresql":
+ return "bytea"
+ else:
+ return "BLOB"
+
+
+# For reasons which now escape me, I had a few fields in the old
+# hand-coded SQL which used MySQL type BINARY(20) to hold SKIs.
+# Presumably this was so that I could then use those SKIs in indexes
+# and searches, but apparently I never got around to that part.
+#
+# SKIs probably would be better stored as hex strings anyway, so not
+# bothering with a separate binary type model for this. Deal with
+# this if and when it ever becomes an issue.
+
+
+class DERField(BlobField):
+ """
+ Field class for DER objects. These are derived from BLOBs, but with
+ automatic translation between ASN.1 and Python types.
+
+ DERField itself is an abstract class, concrete field classes are
+ derived from it.
+ """
+
+ __metaclass__ = models.SubfieldBase
+
+ def to_python(self, value):
+ assert value is None or isinstance(value, (self.rpki_type, str))
+ if isinstance(value, str):
+ return self.rpki_type(DER = value)
+ else:
+ return value
+
+ def get_prep_value(self, value):
+ assert value is None or isinstance(value, (self.rpki_type, str))
+ if isinstance(value, self.rpki_type):
+ return value.get_DER()
+ else:
+ return value
+
+class CertificateField(DERField):
+ description = "X.509 certificate"
+ rpki_type = rpki.x509.X509
+
+class KeyField(DERField):
+ description = "RSA keypair"
+ rpki_type = rpki.x509.RSA
+
+class CRLField(DERField):
+ description = "Certificate Revocation List"
+ rpki_type = rpki.x509.CRL
+
+class PKCS10Field(DERField):
+ description = "PKCS #10 certificate request"
+ rpki_type = rpki.x509.PKCS10
+
+class ManifestField(DERField):
+ description = "RPKI Manifest"
+ rpki_type = rpki.x509.SignedManifest
+
+class ROAField(DERField):
+ description = "ROA"
+ rpki_type = rpki.x509.ROA
+
+class GhostbusterField(DERField):
+ description = "Ghostbuster Record"
+ rpki_type = rpki.x509.Ghostbuster
+
+
+field_classes = (EnumField, SundialField, BlobField, CertificateField, KeyField,
+ CRLField, PKCS10Field, ManifestField, ROAField, GhostbusterField)
+
+add_introspection_rules([(field_classes, [], {})],
+ [r"^rpki\.fields\." + cls.__name__ for cls in field_classes])
+
+del field_classes
diff --git a/rpki/gui/decorators.py b/rpki/gui/decorators.py
index ed10f3d9..d197acff 100644
--- a/rpki/gui/decorators.py
+++ b/rpki/gui/decorators.py
@@ -15,15 +15,23 @@
__version__ = '$Id$'
from django import http
+from os import getenv
+
+
+# Don't set this in production, ever. Really. You have been warned.
+#
+_allow_plain_http_for_testing = getenv("ALLOW_PLAIN_HTTP_FOR_TESTING") == "I solemnly swear that I am not running this in production"
def tls_required(f):
- """Decorator which returns a 500 error if the connection is not secured
- with TLS (https).
+ """
+ Decorator which returns a 500 error if the connection is not
+ secured with TLS (https).
+ """
"""
def _tls_required(request, *args, **kwargs):
- if not request.is_secure():
+ if not request.is_secure() and not _allow_plain_http_for_testing:
return http.HttpResponseServerError(
'This resource may only be accessed securely via https',
content_type='text/plain')
diff --git a/rpki/gui/default_settings.py b/rpki/gui/default_settings.py
deleted file mode 100644
index e0626965..00000000
--- a/rpki/gui/default_settings.py
+++ /dev/null
@@ -1,172 +0,0 @@
-"""
-This module contains static configuration settings for the web portal.
-"""
-
-__version__ = '$Id$'
-
-import os
-import random
-import string
-import socket
-
-import rpki.config
-import rpki.autoconf
-
-# Where to put static files.
-STATIC_ROOT = rpki.autoconf.datarootdir + '/rpki/media'
-
-# Must end with a slash!
-STATIC_URL = '/media/'
-
-# Where to email server errors.
-ADMINS = (('Administrator', 'root@localhost'),)
-
-LOGGING = {
- 'version': 1,
- 'formatters': {
- 'verbose': {
- # see http://docs.python.org/2.7/library/logging.html#logging.LogRecord
- 'format': '%(levelname)s %(asctime)s %(name)s %(message)s'
- },
- },
- 'handlers': {
- 'stderr': {
- 'class': 'logging.StreamHandler',
- 'level': 'DEBUG',
- 'formatter': 'verbose',
- },
- 'mail_admins': {
- 'level': 'ERROR',
- 'class': 'django.utils.log.AdminEmailHandler',
- },
- },
- 'loggers': {
- 'django': {
- 'level': 'ERROR',
- 'handlers': ['stderr', 'mail_admins'],
- },
- 'rpki.gui': {
- 'level': 'WARNING',
- 'handlers': ['stderr'],
- },
- },
-}
-
-# Load the SQL authentication bits from the system rpki.conf.
-rpki_config = rpki.config.parser(section='web_portal')
-
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.mysql',
- 'NAME': rpki_config.get('sql-database'),
- 'USER': rpki_config.get('sql-username'),
- 'PASSWORD': rpki_config.get('sql-password'),
-
- # Ensure the default storage engine is InnoDB since we need
- # foreign key support. The Django documentation suggests
- # removing this after the syncdb is performed as an optimization,
- # but there isn't an easy way to do this automatically.
-
- 'OPTIONS': {
- 'init_command': 'SET storage_engine=INNODB',
- }
- }
-}
-
-
-def select_tz():
- "Find a supported timezone that looks like UTC"
- for tz in ('UTC', 'GMT', 'Etc/UTC', 'Etc/GMT'):
- if os.path.exists('/usr/share/zoneinfo/' + tz):
- return tz
- # Can't determine the proper timezone, fall back to UTC and let Django
- # report the error to the user.
- return 'UTC'
-
-# Local time zone for this installation. Choices can be found here:
-# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
-# although not all choices may be available on all operating systems.
-# If running in a Windows environment this must be set to the same as your
-# system time zone.
-TIME_ZONE = select_tz()
-
-def get_secret_key():
- """Retrieve the secret-key value from rpki.conf or generate a random value
- if it is not present."""
-
- d = string.letters + string.digits
- val = ''.join([random.choice(d) for _ in range(50)])
- return rpki_config.get('secret-key', val)
-
-# Make this unique, and don't share it with anybody.
-SECRET_KEY = get_secret_key()
-
-# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
-# for details on why you might need this.
-def get_allowed_hosts():
- allowed_hosts = set(rpki_config.multiget("allowed-hosts"))
- allowed_hosts.add(socket.getfqdn())
- try:
- import netifaces
- for interface in netifaces.interfaces():
- addresses = netifaces.ifaddresses(interface)
- for af in (netifaces.AF_INET, netifaces.AF_INET6):
- if af in addresses:
- for address in addresses[af]:
- if "addr" in address:
- allowed_hosts.add(address["addr"])
- except ImportError:
- pass
- return list(allowed_hosts)
-
-ALLOWED_HOSTS = get_allowed_hosts()
-
-# List of callables that know how to import templates from various sources.
-TEMPLATE_LOADERS = (
- 'django.template.loaders.filesystem.Loader',
- 'django.template.loaders.app_directories.Loader',
- 'django.template.loaders.eggs.Loader'
-)
-
-MIDDLEWARE_CLASSES = (
- 'django.middleware.common.CommonMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.messages.middleware.MessageMiddleware'
-)
-
-ROOT_URLCONF = 'rpki.gui.urls'
-
-INSTALLED_APPS = (
- 'django.contrib.auth',
- #'django.contrib.admin',
- #'django.contrib.admindocs',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.staticfiles',
- 'rpki.irdb',
- 'rpki.gui.app',
- 'rpki.gui.cacheview',
- 'rpki.gui.routeview',
- 'south',
-)
-
-TEMPLATE_CONTEXT_PROCESSORS = (
- "django.contrib.auth.context_processors.auth",
- "django.core.context_processors.debug",
- "django.core.context_processors.i18n",
- "django.core.context_processors.media",
- "django.contrib.messages.context_processors.messages",
- "django.core.context_processors.request",
- "django.core.context_processors.static"
-)
-
-# Allow local site to override any setting above -- but if there's
-# anything that local sites routinely need to modify, please consider
-# putting that configuration into rpki.conf and just adding code here
-# to read that configuration.
-try:
- from local_settings import *
-except:
- pass
diff --git a/rpki/gui/script_util.py b/rpki/gui/script_util.py
index 46545d83..678ddae6 100644
--- a/rpki/gui/script_util.py
+++ b/rpki/gui/script_util.py
@@ -16,11 +16,6 @@
This module contains utility functions for use in standalone scripts.
"""
-from django.conf import settings
-
-from rpki import config
-from rpki import autoconf
-
__version__ = '$Id$'
@@ -29,16 +24,28 @@ def setup():
Configure Django enough to use the ORM.
"""
- cfg = config.parser(section='web_portal')
- # INSTALLED_APPS doesn't seem necessary so long as you are only accessing
- # existing tables.
- settings.configure(
- DATABASES={
- 'default': {
- 'ENGINE': 'django.db.backends.mysql',
- 'NAME': cfg.get('sql-database'),
- 'USER': cfg.get('sql-username'),
- 'PASSWORD': cfg.get('sql-password'),
- }
- },
- )
+ # In theory we no longer need to call settings.configure, which
+ # probably means this whole module can go away soon, but leave
+ # breadcrumbs for now.
+
+ if True:
+ os.environ.update(DJANGO_SETTINGS_MODULE = "rpki.django_settings")
+
+ else:
+ from rpki import config
+ from rpki import autoconf
+ from django.conf import settings
+
+ cfg = config.parser(section='web_portal')
+ # INSTALLED_APPS doesn't seem necessary so long as you are only accessing
+ # existing tables.
+ settings.configure(
+ DATABASES={
+ 'default': {
+ 'ENGINE': 'django.db.backends.mysql',
+ 'NAME': cfg.get('sql-database'),
+ 'USER': cfg.get('sql-username'),
+ 'PASSWORD': cfg.get('sql-password'),
+ }
+ },
+ )
diff --git a/rpki/irdb/migrations/0001_initial.py b/rpki/irdb/migrations/0001_initial.py
new file mode 100644
index 00000000..bc0b9743
--- /dev/null
+++ b/rpki/irdb/migrations/0001_initial.py
@@ -0,0 +1,595 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'ServerCA'
+ db.create_table(u'irdb_serverca', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('certificate', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('private_key', self.gf('rpki.fields.KeyField')(default=None, blank=True)),
+ ('latest_crl', self.gf('rpki.fields.CRLField')(default=None, blank=True)),
+ ('next_serial', self.gf('django.db.models.fields.BigIntegerField')(default=1)),
+ ('next_crl_number', self.gf('django.db.models.fields.BigIntegerField')(default=1)),
+ ('last_crl_update', self.gf('rpki.fields.SundialField')()),
+ ('next_crl_update', self.gf('rpki.fields.SundialField')()),
+ ))
+ db.send_create_signal(u'irdb', ['ServerCA'])
+
+ # Adding model 'ResourceHolderCA'
+ db.create_table(u'irdb_resourceholderca', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('certificate', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('private_key', self.gf('rpki.fields.KeyField')(default=None, blank=True)),
+ ('latest_crl', self.gf('rpki.fields.CRLField')(default=None, blank=True)),
+ ('next_serial', self.gf('django.db.models.fields.BigIntegerField')(default=1)),
+ ('next_crl_number', self.gf('django.db.models.fields.BigIntegerField')(default=1)),
+ ('last_crl_update', self.gf('rpki.fields.SundialField')()),
+ ('next_crl_update', self.gf('rpki.fields.SundialField')()),
+ ('handle', self.gf('rpki.irdb.models.HandleField')(unique=True, max_length=120)),
+ ))
+ db.send_create_signal(u'irdb', ['ResourceHolderCA'])
+
+ # Adding model 'HostedCA'
+ db.create_table(u'irdb_hostedca', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('certificate', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('issuer', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['irdb.ServerCA'])),
+ ('hosted', self.gf('django.db.models.fields.related.OneToOneField')(related_name='hosted_by', unique=True, to=orm['irdb.ResourceHolderCA'])),
+ ))
+ db.send_create_signal(u'irdb', ['HostedCA'])
+
+ # Adding unique constraint on 'HostedCA', fields ['issuer', 'hosted']
+ db.create_unique(u'irdb_hostedca', ['issuer_id', 'hosted_id'])
+
+ # Adding model 'ServerRevocation'
+ db.create_table(u'irdb_serverrevocation', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('serial', self.gf('django.db.models.fields.BigIntegerField')()),
+ ('revoked', self.gf('rpki.fields.SundialField')()),
+ ('expires', self.gf('rpki.fields.SundialField')()),
+ ('issuer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='revocations', to=orm['irdb.ServerCA'])),
+ ))
+ db.send_create_signal(u'irdb', ['ServerRevocation'])
+
+ # Adding unique constraint on 'ServerRevocation', fields ['issuer', 'serial']
+ db.create_unique(u'irdb_serverrevocation', ['issuer_id', 'serial'])
+
+ # Adding model 'ResourceHolderRevocation'
+ db.create_table(u'irdb_resourceholderrevocation', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('serial', self.gf('django.db.models.fields.BigIntegerField')()),
+ ('revoked', self.gf('rpki.fields.SundialField')()),
+ ('expires', self.gf('rpki.fields.SundialField')()),
+ ('issuer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='revocations', to=orm['irdb.ResourceHolderCA'])),
+ ))
+ db.send_create_signal(u'irdb', ['ResourceHolderRevocation'])
+
+ # Adding unique constraint on 'ResourceHolderRevocation', fields ['issuer', 'serial']
+ db.create_unique(u'irdb_resourceholderrevocation', ['issuer_id', 'serial'])
+
+ # Adding model 'ServerEE'
+ db.create_table(u'irdb_serveree', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('certificate', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('private_key', self.gf('rpki.fields.KeyField')(default=None, blank=True)),
+ ('issuer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='ee_certificates', to=orm['irdb.ServerCA'])),
+ ('purpose', self.gf('rpki.fields.EnumField')()),
+ ))
+ db.send_create_signal(u'irdb', ['ServerEE'])
+
+ # Adding unique constraint on 'ServerEE', fields ['issuer', 'purpose']
+ db.create_unique(u'irdb_serveree', ['issuer_id', 'purpose'])
+
+ # Adding model 'Referral'
+ db.create_table(u'irdb_referral', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('certificate', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('private_key', self.gf('rpki.fields.KeyField')(default=None, blank=True)),
+ ('issuer', self.gf('django.db.models.fields.related.OneToOneField')(related_name='referral_certificate', unique=True, to=orm['irdb.ResourceHolderCA'])),
+ ))
+ db.send_create_signal(u'irdb', ['Referral'])
+
+ # Adding model 'Turtle'
+ db.create_table(u'irdb_turtle', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('service_uri', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ))
+ db.send_create_signal(u'irdb', ['Turtle'])
+
+ # Adding model 'Rootd'
+ db.create_table(u'irdb_rootd', (
+ (u'turtle_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['irdb.Turtle'], unique=True, primary_key=True)),
+ ('certificate', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('private_key', self.gf('rpki.fields.KeyField')(default=None, blank=True)),
+ ('issuer', self.gf('django.db.models.fields.related.OneToOneField')(related_name='rootd', unique=True, to=orm['irdb.ResourceHolderCA'])),
+ ))
+ db.send_create_signal(u'irdb', ['Rootd'])
+
+ # Adding model 'BSC'
+ db.create_table(u'irdb_bsc', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('certificate', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('issuer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='bscs', to=orm['irdb.ResourceHolderCA'])),
+ ('handle', self.gf('rpki.irdb.models.HandleField')(max_length=120)),
+ ('pkcs10', self.gf('rpki.fields.PKCS10Field')(default=None, blank=True)),
+ ))
+ db.send_create_signal(u'irdb', ['BSC'])
+
+ # Adding unique constraint on 'BSC', fields ['issuer', 'handle']
+ db.create_unique(u'irdb_bsc', ['issuer_id', 'handle'])
+
+ # Adding model 'Child'
+ db.create_table(u'irdb_child', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('certificate', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('handle', self.gf('rpki.irdb.models.HandleField')(max_length=120)),
+ ('ta', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('valid_until', self.gf('rpki.fields.SundialField')()),
+ ('issuer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='children', to=orm['irdb.ResourceHolderCA'])),
+ ('name', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+ ))
+ db.send_create_signal(u'irdb', ['Child'])
+
+ # Adding unique constraint on 'Child', fields ['issuer', 'handle']
+ db.create_unique(u'irdb_child', ['issuer_id', 'handle'])
+
+ # Adding model 'ChildASN'
+ db.create_table(u'irdb_childasn', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('start_as', self.gf('django.db.models.fields.BigIntegerField')()),
+ ('end_as', self.gf('django.db.models.fields.BigIntegerField')()),
+ ('child', self.gf('django.db.models.fields.related.ForeignKey')(related_name='asns', to=orm['irdb.Child'])),
+ ))
+ db.send_create_signal(u'irdb', ['ChildASN'])
+
+ # Adding unique constraint on 'ChildASN', fields ['child', 'start_as', 'end_as']
+ db.create_unique(u'irdb_childasn', ['child_id', 'start_as', 'end_as'])
+
+ # Adding model 'ChildNet'
+ db.create_table(u'irdb_childnet', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('start_ip', self.gf('django.db.models.fields.CharField')(max_length=40)),
+ ('end_ip', self.gf('django.db.models.fields.CharField')(max_length=40)),
+ ('version', self.gf('rpki.fields.EnumField')()),
+ ('child', self.gf('django.db.models.fields.related.ForeignKey')(related_name='address_ranges', to=orm['irdb.Child'])),
+ ))
+ db.send_create_signal(u'irdb', ['ChildNet'])
+
+ # Adding unique constraint on 'ChildNet', fields ['child', 'start_ip', 'end_ip', 'version']
+ db.create_unique(u'irdb_childnet', ['child_id', 'start_ip', 'end_ip', 'version'])
+
+ # Adding model 'Parent'
+ db.create_table(u'irdb_parent', (
+ (u'turtle_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['irdb.Turtle'], unique=True, primary_key=True)),
+ ('certificate', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('handle', self.gf('rpki.irdb.models.HandleField')(max_length=120)),
+ ('ta', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('issuer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='parents', to=orm['irdb.ResourceHolderCA'])),
+ ('parent_handle', self.gf('rpki.irdb.models.HandleField')(max_length=120)),
+ ('child_handle', self.gf('rpki.irdb.models.HandleField')(max_length=120)),
+ ('repository_type', self.gf('rpki.fields.EnumField')()),
+ ('referrer', self.gf('rpki.irdb.models.HandleField')(max_length=120, null=True, blank=True)),
+ ('referral_authorization', self.gf('rpki.irdb.models.SignedReferralField')(default=None, null=True, blank=True)),
+ ))
+ db.send_create_signal(u'irdb', ['Parent'])
+
+ # Adding unique constraint on 'Parent', fields ['issuer', 'handle']
+ db.create_unique(u'irdb_parent', ['issuer_id', 'handle'])
+
+ # Adding model 'ROARequest'
+ db.create_table(u'irdb_roarequest', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('issuer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='roa_requests', to=orm['irdb.ResourceHolderCA'])),
+ ('asn', self.gf('django.db.models.fields.BigIntegerField')()),
+ ))
+ db.send_create_signal(u'irdb', ['ROARequest'])
+
+ # Adding model 'ROARequestPrefix'
+ db.create_table(u'irdb_roarequestprefix', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('roa_request', self.gf('django.db.models.fields.related.ForeignKey')(related_name='prefixes', to=orm['irdb.ROARequest'])),
+ ('version', self.gf('rpki.fields.EnumField')()),
+ ('prefix', self.gf('django.db.models.fields.CharField')(max_length=40)),
+ ('prefixlen', self.gf('django.db.models.fields.PositiveSmallIntegerField')()),
+ ('max_prefixlen', self.gf('django.db.models.fields.PositiveSmallIntegerField')()),
+ ))
+ db.send_create_signal(u'irdb', ['ROARequestPrefix'])
+
+ # Adding unique constraint on 'ROARequestPrefix', fields ['roa_request', 'version', 'prefix', 'prefixlen', 'max_prefixlen']
+ db.create_unique(u'irdb_roarequestprefix', ['roa_request_id', 'version', 'prefix', 'prefixlen', 'max_prefixlen'])
+
+ # Adding model 'GhostbusterRequest'
+ db.create_table(u'irdb_ghostbusterrequest', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('issuer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='ghostbuster_requests', to=orm['irdb.ResourceHolderCA'])),
+ ('parent', self.gf('django.db.models.fields.related.ForeignKey')(related_name='ghostbuster_requests', null=True, to=orm['irdb.Parent'])),
+ ('vcard', self.gf('django.db.models.fields.TextField')()),
+ ))
+ db.send_create_signal(u'irdb', ['GhostbusterRequest'])
+
+ # Adding model 'EECertificateRequest'
+ db.create_table(u'irdb_eecertificaterequest', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('valid_until', self.gf('rpki.fields.SundialField')()),
+ ('issuer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='ee_certificate_requests', to=orm['irdb.ResourceHolderCA'])),
+ ('pkcs10', self.gf('rpki.fields.PKCS10Field')(default=None, blank=True)),
+ ('gski', self.gf('django.db.models.fields.CharField')(max_length=27)),
+ ('cn', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ('sn', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ('eku', self.gf('django.db.models.fields.TextField')(null=True)),
+ ))
+ db.send_create_signal(u'irdb', ['EECertificateRequest'])
+
+ # Adding unique constraint on 'EECertificateRequest', fields ['issuer', 'gski']
+ db.create_unique(u'irdb_eecertificaterequest', ['issuer_id', 'gski'])
+
+ # Adding model 'EECertificateRequestASN'
+ db.create_table(u'irdb_eecertificaterequestasn', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('start_as', self.gf('django.db.models.fields.BigIntegerField')()),
+ ('end_as', self.gf('django.db.models.fields.BigIntegerField')()),
+ ('ee_certificate_request', self.gf('django.db.models.fields.related.ForeignKey')(related_name='asns', to=orm['irdb.EECertificateRequest'])),
+ ))
+ db.send_create_signal(u'irdb', ['EECertificateRequestASN'])
+
+ # Adding unique constraint on 'EECertificateRequestASN', fields ['ee_certificate_request', 'start_as', 'end_as']
+ db.create_unique(u'irdb_eecertificaterequestasn', ['ee_certificate_request_id', 'start_as', 'end_as'])
+
+ # Adding model 'EECertificateRequestNet'
+ db.create_table(u'irdb_eecertificaterequestnet', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('start_ip', self.gf('django.db.models.fields.CharField')(max_length=40)),
+ ('end_ip', self.gf('django.db.models.fields.CharField')(max_length=40)),
+ ('version', self.gf('rpki.fields.EnumField')()),
+ ('ee_certificate_request', self.gf('django.db.models.fields.related.ForeignKey')(related_name='address_ranges', to=orm['irdb.EECertificateRequest'])),
+ ))
+ db.send_create_signal(u'irdb', ['EECertificateRequestNet'])
+
+ # Adding unique constraint on 'EECertificateRequestNet', fields ['ee_certificate_request', 'start_ip', 'end_ip', 'version']
+ db.create_unique(u'irdb_eecertificaterequestnet', ['ee_certificate_request_id', 'start_ip', 'end_ip', 'version'])
+
+ # Adding model 'Repository'
+ db.create_table(u'irdb_repository', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('certificate', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('handle', self.gf('rpki.irdb.models.HandleField')(max_length=120)),
+ ('ta', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('issuer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='repositories', to=orm['irdb.ResourceHolderCA'])),
+ ('client_handle', self.gf('rpki.irdb.models.HandleField')(max_length=120)),
+ ('service_uri', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('sia_base', self.gf('django.db.models.fields.TextField')()),
+ ('turtle', self.gf('django.db.models.fields.related.OneToOneField')(related_name='repository', unique=True, to=orm['irdb.Turtle'])),
+ ))
+ db.send_create_signal(u'irdb', ['Repository'])
+
+ # Adding unique constraint on 'Repository', fields ['issuer', 'handle']
+ db.create_unique(u'irdb_repository', ['issuer_id', 'handle'])
+
+ # Adding model 'Client'
+ db.create_table(u'irdb_client', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('certificate', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('handle', self.gf('rpki.irdb.models.HandleField')(max_length=120)),
+ ('ta', self.gf('rpki.fields.CertificateField')(default=None, blank=True)),
+ ('issuer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='clients', to=orm['irdb.ServerCA'])),
+ ('sia_base', self.gf('django.db.models.fields.TextField')()),
+ ('parent_handle', self.gf('rpki.irdb.models.HandleField')(max_length=120)),
+ ))
+ db.send_create_signal(u'irdb', ['Client'])
+
+ # Adding unique constraint on 'Client', fields ['issuer', 'handle']
+ db.create_unique(u'irdb_client', ['issuer_id', 'handle'])
+
+
+ def backwards(self, orm):
+ # Removing unique constraint on 'Client', fields ['issuer', 'handle']
+ db.delete_unique(u'irdb_client', ['issuer_id', 'handle'])
+
+ # Removing unique constraint on 'Repository', fields ['issuer', 'handle']
+ db.delete_unique(u'irdb_repository', ['issuer_id', 'handle'])
+
+ # Removing unique constraint on 'EECertificateRequestNet', fields ['ee_certificate_request', 'start_ip', 'end_ip', 'version']
+ db.delete_unique(u'irdb_eecertificaterequestnet', ['ee_certificate_request_id', 'start_ip', 'end_ip', 'version'])
+
+ # Removing unique constraint on 'EECertificateRequestASN', fields ['ee_certificate_request', 'start_as', 'end_as']
+ db.delete_unique(u'irdb_eecertificaterequestasn', ['ee_certificate_request_id', 'start_as', 'end_as'])
+
+ # Removing unique constraint on 'EECertificateRequest', fields ['issuer', 'gski']
+ db.delete_unique(u'irdb_eecertificaterequest', ['issuer_id', 'gski'])
+
+ # Removing unique constraint on 'ROARequestPrefix', fields ['roa_request', 'version', 'prefix', 'prefixlen', 'max_prefixlen']
+ db.delete_unique(u'irdb_roarequestprefix', ['roa_request_id', 'version', 'prefix', 'prefixlen', 'max_prefixlen'])
+
+ # Removing unique constraint on 'Parent', fields ['issuer', 'handle']
+ db.delete_unique(u'irdb_parent', ['issuer_id', 'handle'])
+
+ # Removing unique constraint on 'ChildNet', fields ['child', 'start_ip', 'end_ip', 'version']
+ db.delete_unique(u'irdb_childnet', ['child_id', 'start_ip', 'end_ip', 'version'])
+
+ # Removing unique constraint on 'ChildASN', fields ['child', 'start_as', 'end_as']
+ db.delete_unique(u'irdb_childasn', ['child_id', 'start_as', 'end_as'])
+
+ # Removing unique constraint on 'Child', fields ['issuer', 'handle']
+ db.delete_unique(u'irdb_child', ['issuer_id', 'handle'])
+
+ # Removing unique constraint on 'BSC', fields ['issuer', 'handle']
+ db.delete_unique(u'irdb_bsc', ['issuer_id', 'handle'])
+
+ # Removing unique constraint on 'ServerEE', fields ['issuer', 'purpose']
+ db.delete_unique(u'irdb_serveree', ['issuer_id', 'purpose'])
+
+ # Removing unique constraint on 'ResourceHolderRevocation', fields ['issuer', 'serial']
+ db.delete_unique(u'irdb_resourceholderrevocation', ['issuer_id', 'serial'])
+
+ # Removing unique constraint on 'ServerRevocation', fields ['issuer', 'serial']
+ db.delete_unique(u'irdb_serverrevocation', ['issuer_id', 'serial'])
+
+ # Removing unique constraint on 'HostedCA', fields ['issuer', 'hosted']
+ db.delete_unique(u'irdb_hostedca', ['issuer_id', 'hosted_id'])
+
+ # Deleting model 'ServerCA'
+ db.delete_table(u'irdb_serverca')
+
+ # Deleting model 'ResourceHolderCA'
+ db.delete_table(u'irdb_resourceholderca')
+
+ # Deleting model 'HostedCA'
+ db.delete_table(u'irdb_hostedca')
+
+ # Deleting model 'ServerRevocation'
+ db.delete_table(u'irdb_serverrevocation')
+
+ # Deleting model 'ResourceHolderRevocation'
+ db.delete_table(u'irdb_resourceholderrevocation')
+
+ # Deleting model 'ServerEE'
+ db.delete_table(u'irdb_serveree')
+
+ # Deleting model 'Referral'
+ db.delete_table(u'irdb_referral')
+
+ # Deleting model 'Turtle'
+ db.delete_table(u'irdb_turtle')
+
+ # Deleting model 'Rootd'
+ db.delete_table(u'irdb_rootd')
+
+ # Deleting model 'BSC'
+ db.delete_table(u'irdb_bsc')
+
+ # Deleting model 'Child'
+ db.delete_table(u'irdb_child')
+
+ # Deleting model 'ChildASN'
+ db.delete_table(u'irdb_childasn')
+
+ # Deleting model 'ChildNet'
+ db.delete_table(u'irdb_childnet')
+
+ # Deleting model 'Parent'
+ db.delete_table(u'irdb_parent')
+
+ # Deleting model 'ROARequest'
+ db.delete_table(u'irdb_roarequest')
+
+ # Deleting model 'ROARequestPrefix'
+ db.delete_table(u'irdb_roarequestprefix')
+
+ # Deleting model 'GhostbusterRequest'
+ db.delete_table(u'irdb_ghostbusterrequest')
+
+ # Deleting model 'EECertificateRequest'
+ db.delete_table(u'irdb_eecertificaterequest')
+
+ # Deleting model 'EECertificateRequestASN'
+ db.delete_table(u'irdb_eecertificaterequestasn')
+
+ # Deleting model 'EECertificateRequestNet'
+ db.delete_table(u'irdb_eecertificaterequestnet')
+
+ # Deleting model 'Repository'
+ db.delete_table(u'irdb_repository')
+
+ # Deleting model 'Client'
+ db.delete_table(u'irdb_client')
+
+
+ models = {
+ u'irdb.bsc': {
+ 'Meta': {'unique_together': "(('issuer', 'handle'),)", 'object_name': 'BSC'},
+ 'certificate': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ 'handle': ('rpki.irdb.models.HandleField', [], {'max_length': '120'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'bscs'", 'to': u"orm['irdb.ResourceHolderCA']"}),
+ 'pkcs10': ('rpki.fields.PKCS10Field', [], {'default': 'None', 'blank': 'True'})
+ },
+ u'irdb.child': {
+ 'Meta': {'unique_together': "(('issuer', 'handle'),)", 'object_name': 'Child'},
+ 'certificate': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ 'handle': ('rpki.irdb.models.HandleField', [], {'max_length': '120'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'to': u"orm['irdb.ResourceHolderCA']"}),
+ 'name': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'ta': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ 'valid_until': ('rpki.fields.SundialField', [], {})
+ },
+ u'irdb.childasn': {
+ 'Meta': {'unique_together': "(('child', 'start_as', 'end_as'),)", 'object_name': 'ChildASN'},
+ 'child': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'asns'", 'to': u"orm['irdb.Child']"}),
+ 'end_as': ('django.db.models.fields.BigIntegerField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'start_as': ('django.db.models.fields.BigIntegerField', [], {})
+ },
+ u'irdb.childnet': {
+ 'Meta': {'unique_together': "(('child', 'start_ip', 'end_ip', 'version'),)", 'object_name': 'ChildNet'},
+ 'child': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'address_ranges'", 'to': u"orm['irdb.Child']"}),
+ 'end_ip': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'start_ip': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'version': ('rpki.fields.EnumField', [], {})
+ },
+ u'irdb.client': {
+ 'Meta': {'unique_together': "(('issuer', 'handle'),)", 'object_name': 'Client'},
+ 'certificate': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ 'handle': ('rpki.irdb.models.HandleField', [], {'max_length': '120'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'clients'", 'to': u"orm['irdb.ServerCA']"}),
+ 'parent_handle': ('rpki.irdb.models.HandleField', [], {'max_length': '120'}),
+ 'sia_base': ('django.db.models.fields.TextField', [], {}),
+ 'ta': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'})
+ },
+ u'irdb.eecertificaterequest': {
+ 'Meta': {'unique_together': "(('issuer', 'gski'),)", 'object_name': 'EECertificateRequest'},
+ 'cn': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'eku': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'gski': ('django.db.models.fields.CharField', [], {'max_length': '27'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ee_certificate_requests'", 'to': u"orm['irdb.ResourceHolderCA']"}),
+ 'pkcs10': ('rpki.fields.PKCS10Field', [], {'default': 'None', 'blank': 'True'}),
+ 'sn': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'valid_until': ('rpki.fields.SundialField', [], {})
+ },
+ u'irdb.eecertificaterequestasn': {
+ 'Meta': {'unique_together': "(('ee_certificate_request', 'start_as', 'end_as'),)", 'object_name': 'EECertificateRequestASN'},
+ 'ee_certificate_request': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'asns'", 'to': u"orm['irdb.EECertificateRequest']"}),
+ 'end_as': ('django.db.models.fields.BigIntegerField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'start_as': ('django.db.models.fields.BigIntegerField', [], {})
+ },
+ u'irdb.eecertificaterequestnet': {
+ 'Meta': {'unique_together': "(('ee_certificate_request', 'start_ip', 'end_ip', 'version'),)", 'object_name': 'EECertificateRequestNet'},
+ 'ee_certificate_request': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'address_ranges'", 'to': u"orm['irdb.EECertificateRequest']"}),
+ 'end_ip': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'start_ip': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'version': ('rpki.fields.EnumField', [], {})
+ },
+ u'irdb.ghostbusterrequest': {
+ 'Meta': {'object_name': 'GhostbusterRequest'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ghostbuster_requests'", 'to': u"orm['irdb.ResourceHolderCA']"}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ghostbuster_requests'", 'null': 'True', 'to': u"orm['irdb.Parent']"}),
+ 'vcard': ('django.db.models.fields.TextField', [], {})
+ },
+ u'irdb.hostedca': {
+ 'Meta': {'unique_together': "(('issuer', 'hosted'),)", 'object_name': 'HostedCA'},
+ 'certificate': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ 'hosted': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'hosted_by'", 'unique': 'True', 'to': u"orm['irdb.ResourceHolderCA']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['irdb.ServerCA']"})
+ },
+ u'irdb.parent': {
+ 'Meta': {'unique_together': "(('issuer', 'handle'),)", 'object_name': 'Parent', '_ormbases': [u'irdb.Turtle']},
+ 'certificate': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ 'child_handle': ('rpki.irdb.models.HandleField', [], {'max_length': '120'}),
+ 'handle': ('rpki.irdb.models.HandleField', [], {'max_length': '120'}),
+ 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'parents'", 'to': u"orm['irdb.ResourceHolderCA']"}),
+ 'parent_handle': ('rpki.irdb.models.HandleField', [], {'max_length': '120'}),
+ 'referral_authorization': ('rpki.irdb.models.SignedReferralField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
+ 'referrer': ('rpki.irdb.models.HandleField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}),
+ 'repository_type': ('rpki.fields.EnumField', [], {}),
+ 'ta': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ u'turtle_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['irdb.Turtle']", 'unique': 'True', 'primary_key': 'True'})
+ },
+ u'irdb.referral': {
+ 'Meta': {'object_name': 'Referral'},
+ 'certificate': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issuer': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'referral_certificate'", 'unique': 'True', 'to': u"orm['irdb.ResourceHolderCA']"}),
+ 'private_key': ('rpki.fields.KeyField', [], {'default': 'None', 'blank': 'True'})
+ },
+ u'irdb.repository': {
+ 'Meta': {'unique_together': "(('issuer', 'handle'),)", 'object_name': 'Repository'},
+ 'certificate': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ 'client_handle': ('rpki.irdb.models.HandleField', [], {'max_length': '120'}),
+ 'handle': ('rpki.irdb.models.HandleField', [], {'max_length': '120'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'repositories'", 'to': u"orm['irdb.ResourceHolderCA']"}),
+ 'service_uri': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'sia_base': ('django.db.models.fields.TextField', [], {}),
+ 'ta': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ 'turtle': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'repository'", 'unique': 'True', 'to': u"orm['irdb.Turtle']"})
+ },
+ u'irdb.resourceholderca': {
+ 'Meta': {'object_name': 'ResourceHolderCA'},
+ 'certificate': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ 'handle': ('rpki.irdb.models.HandleField', [], {'unique': 'True', 'max_length': '120'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_crl_update': ('rpki.fields.SundialField', [], {}),
+ 'latest_crl': ('rpki.fields.CRLField', [], {'default': 'None', 'blank': 'True'}),
+ 'next_crl_number': ('django.db.models.fields.BigIntegerField', [], {'default': '1'}),
+ 'next_crl_update': ('rpki.fields.SundialField', [], {}),
+ 'next_serial': ('django.db.models.fields.BigIntegerField', [], {'default': '1'}),
+ 'private_key': ('rpki.fields.KeyField', [], {'default': 'None', 'blank': 'True'})
+ },
+ u'irdb.resourceholderrevocation': {
+ 'Meta': {'unique_together': "(('issuer', 'serial'),)", 'object_name': 'ResourceHolderRevocation'},
+ 'expires': ('rpki.fields.SundialField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revocations'", 'to': u"orm['irdb.ResourceHolderCA']"}),
+ 'revoked': ('rpki.fields.SundialField', [], {}),
+ 'serial': ('django.db.models.fields.BigIntegerField', [], {})
+ },
+ u'irdb.roarequest': {
+ 'Meta': {'object_name': 'ROARequest'},
+ 'asn': ('django.db.models.fields.BigIntegerField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'roa_requests'", 'to': u"orm['irdb.ResourceHolderCA']"})
+ },
+ u'irdb.roarequestprefix': {
+ 'Meta': {'unique_together': "(('roa_request', 'version', 'prefix', 'prefixlen', 'max_prefixlen'),)", 'object_name': 'ROARequestPrefix'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'max_prefixlen': ('django.db.models.fields.PositiveSmallIntegerField', [], {}),
+ 'prefix': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'prefixlen': ('django.db.models.fields.PositiveSmallIntegerField', [], {}),
+ 'roa_request': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'prefixes'", 'to': u"orm['irdb.ROARequest']"}),
+ 'version': ('rpki.fields.EnumField', [], {})
+ },
+ u'irdb.rootd': {
+ 'Meta': {'object_name': 'Rootd', '_ormbases': [u'irdb.Turtle']},
+ 'certificate': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ 'issuer': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'rootd'", 'unique': 'True', 'to': u"orm['irdb.ResourceHolderCA']"}),
+ 'private_key': ('rpki.fields.KeyField', [], {'default': 'None', 'blank': 'True'}),
+ u'turtle_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['irdb.Turtle']", 'unique': 'True', 'primary_key': 'True'})
+ },
+ u'irdb.serverca': {
+ 'Meta': {'object_name': 'ServerCA'},
+ 'certificate': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_crl_update': ('rpki.fields.SundialField', [], {}),
+ 'latest_crl': ('rpki.fields.CRLField', [], {'default': 'None', 'blank': 'True'}),
+ 'next_crl_number': ('django.db.models.fields.BigIntegerField', [], {'default': '1'}),
+ 'next_crl_update': ('rpki.fields.SundialField', [], {}),
+ 'next_serial': ('django.db.models.fields.BigIntegerField', [], {'default': '1'}),
+ 'private_key': ('rpki.fields.KeyField', [], {'default': 'None', 'blank': 'True'})
+ },
+ u'irdb.serveree': {
+ 'Meta': {'unique_together': "(('issuer', 'purpose'),)", 'object_name': 'ServerEE'},
+ 'certificate': ('rpki.fields.CertificateField', [], {'default': 'None', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ee_certificates'", 'to': u"orm['irdb.ServerCA']"}),
+ 'private_key': ('rpki.fields.KeyField', [], {'default': 'None', 'blank': 'True'}),
+ 'purpose': ('rpki.fields.EnumField', [], {})
+ },
+ u'irdb.serverrevocation': {
+ 'Meta': {'unique_together': "(('issuer', 'serial'),)", 'object_name': 'ServerRevocation'},
+ 'expires': ('rpki.fields.SundialField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issuer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revocations'", 'to': u"orm['irdb.ServerCA']"}),
+ 'revoked': ('rpki.fields.SundialField', [], {}),
+ 'serial': ('django.db.models.fields.BigIntegerField', [], {})
+ },
+ u'irdb.turtle': {
+ 'Meta': {'object_name': 'Turtle'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'service_uri': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ }
+ }
+
+ complete_apps = ['irdb'] \ No newline at end of file
diff --git a/rpki/irdb/migrations/__init__.py b/rpki/irdb/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/rpki/irdb/migrations/__init__.py
diff --git a/rpki/irdb/models.py b/rpki/irdb/models.py
index c5cf7f15..f89cebd4 100644
--- a/rpki/irdb/models.py
+++ b/rpki/irdb/models.py
@@ -34,6 +34,8 @@ import socket
import rpki.POW
from south.modelsinspector import add_introspection_rules
+from rpki.fields import EnumField, SundialField, CertificateField, DERField, KeyField, CRLField, PKCS10Field
+
## @var ip_version_choices
# Choice argument for fields implementing IP version numbers.
@@ -61,11 +63,11 @@ ee_certificate_lifetime = rpki.sundial.timedelta(days = 60)
###
-# Field types
+# Field classes
class HandleField(django.db.models.CharField):
"""
- A handle field type.
+ A handle field class. Replace this with SlugField?
"""
description = 'A "handle" in one of the RPKI protocols'
@@ -74,104 +76,26 @@ class HandleField(django.db.models.CharField):
kwargs["max_length"] = 120
django.db.models.CharField.__init__(self, *args, **kwargs)
-class EnumField(django.db.models.PositiveSmallIntegerField):
- """
- An enumeration type that uses strings in Python and small integers
- in SQL.
- """
-
- description = "An enumeration type"
-
- __metaclass__ = django.db.models.SubfieldBase
-
- def __init__(self, *args, **kwargs):
- if isinstance(kwargs.get("choices"), (tuple, list)) and isinstance(kwargs["choices"][0], str):
- kwargs["choices"] = tuple(enumerate(kwargs["choices"], 1))
- django.db.models.PositiveSmallIntegerField.__init__(self, *args, **kwargs)
- self.enum_i2s = dict(self.flatchoices)
- self.enum_s2i = dict((v, k) for k, v in self.flatchoices)
-
- def to_python(self, value):
- return self.enum_i2s.get(value, value)
-
- def get_prep_value(self, value):
- return self.enum_s2i.get(value, value)
-
-class SundialField(django.db.models.DateTimeField):
- """
- A field type for our customized datetime objects.
- """
-
- __metaclass__ = django.db.models.SubfieldBase
-
- description = "A datetime type using our customized datetime objects"
-
- def to_python(self, value):
- if isinstance(value, rpki.sundial.pydatetime.datetime):
- return rpki.sundial.datetime.from_datetime(
- django.db.models.DateTimeField.to_python(self, value))
- else:
- return value
-
- def get_prep_value(self, value):
- if isinstance(value, rpki.sundial.datetime):
- return value.to_datetime()
- else:
- return value
+class SignedReferralField(DERField):
+ description = "CMS signed object containing XML"
+ rpki_type = rpki.x509.SignedReferral
-class DERField(django.db.models.Field):
- """
- Field types for DER objects.
- """
-
- __metaclass__ = django.db.models.SubfieldBase
-
- def __init__(self, *args, **kwargs):
- kwargs["serialize"] = False
- kwargs["blank"] = True
- kwargs["default"] = None
- django.db.models.Field.__init__(self, *args, **kwargs)
-
- def db_type(self, connection):
- if connection.settings_dict['ENGINE'] == "django.db.backends.posgresql":
- return "bytea"
- else:
- return "BLOB"
-
- def to_python(self, value):
- assert value is None or isinstance(value, (self.rpki_type, str))
- if isinstance(value, str):
- return self.rpki_type(DER = value)
- else:
- return value
-
- def get_prep_value(self, value):
- assert value is None or isinstance(value, (self.rpki_type, str))
- if isinstance(value, self.rpki_type):
- return value.get_DER()
- else:
- return value
+# Alias to keep old rpki.gui migrations happy. Would generating a new
+# schema migration for rpki.gui remove the need, or do we have to
+# preserve every old field class we've ever used forever? Dunno.
-class CertificateField(DERField):
- description = "X.509 certificate"
- rpki_type = rpki.x509.X509
+RSAKeyField = KeyField
-class RSAKeyField(DERField):
- description = "RSA keypair"
- rpki_type = rpki.x509.RSA
+# Introspection rules for Django South
-class CRLField(DERField):
- description = "Certificate Revocation List"
- rpki_type = rpki.x509.CRL
+field_classes = [HandleField, SignedReferralField]
-class PKCS10Field(DERField):
- description = "PKCS #10 certificate request"
- rpki_type = rpki.x509.PKCS10
+add_introspection_rules([(field_classes, [], {})],
+ [r"^rpki\.irdb\.models\." + cls.__name__
+ for cls in field_classes])
-class SignedReferralField(DERField):
- description = "CMS signed object containing XML"
- rpki_type = rpki.x509.SignedReferral
+del field_classes
# Custom managers
@@ -232,7 +156,7 @@ class ResourceHolderEEManager(CertificateManager):
class CA(django.db.models.Model):
certificate = CertificateField()
- private_key = RSAKeyField()
+ private_key = KeyField()
latest_crl = CRLField()
# Might want to bring these into line with what rpkid does. Current
@@ -392,7 +316,7 @@ class ResourceHolderRevocation(Revocation):
issuer = django.db.models.ForeignKey(ResourceHolderCA, related_name = "revocations")
class EECertificate(Certificate):
- private_key = RSAKeyField()
+ private_key = KeyField()
class Meta:
abstract = True
@@ -635,13 +559,3 @@ class Client(CrossCertification):
# This shouldn't be necessary
class Meta:
unique_together = ("issuer", "handle")
-
-# for Django South -- these are just simple subclasses
-add_introspection_rules([],
- (r'^rpki\.irdb\.models\.CertificateField',
- r'^rpki\.irdb\.models\.CRLField',
- r'^rpki\.irdb\.models\.EnumField',
- r'^rpki\.irdb\.models\.HandleField',
- r'^rpki\.irdb\.models\.RSAKeyField',
- r'^rpki\.irdb\.models\.SignedReferralField',
- r'^rpki\.irdb\.models\.SundialField'))
diff --git a/rpki/irdbd.py b/rpki/irdbd.py
index bfc48d87..2b697cc8 100644
--- a/rpki/irdbd.py
+++ b/rpki/irdbd.py
@@ -149,8 +149,6 @@ class main(object):
time.tzset()
parser = argparse.ArgumentParser(description = __doc__)
- parser.add_argument("-c", "--config",
- help = "override default location of configuration file")
parser.add_argument("-f", "--foreground", action = "store_true",
help = "do not daemonize")
parser.add_argument("--pidfile",
@@ -162,7 +160,7 @@ class main(object):
rpki.log.init("irdbd", args)
- self.cfg = rpki.config.parser(args.config, "irdbd")
+ self.cfg = rpki.config.parser(section = "irdbd")
self.cfg.set_global_flags()
if not args.foreground:
@@ -181,34 +179,15 @@ class main(object):
def main(self):
- global rpki # pylint: disable=W0602
- from django.conf import settings
-
startup_msg = self.cfg.get("startup-message", "")
if startup_msg:
logger.info(startup_msg)
- # Do -not- turn on DEBUG here except for short-lived tests,
- # otherwise irdbd will eventually run out of memory and crash.
- #
- # If you must enable debugging, use django.db.reset_queries() to
- # clear the query list manually, but it's probably better just to
- # run with debugging disabled, since that's the expectation for
- # production code.
- #
- # https://docs.djangoproject.com/en/dev/faq/models/#why-is-django-leaking-memory
-
- settings.configure(
- DATABASES = {
- "default" : {
- "ENGINE" : "django.db.backends.mysql",
- "NAME" : self.cfg.get("sql-database"),
- "USER" : self.cfg.get("sql-username"),
- "PASSWORD" : self.cfg.get("sql-password"),
- "HOST" : "",
- "PORT" : "" }},
- INSTALLED_APPS = ("rpki.irdb",),)
+ # Now that we know which configuration file to use, it's OK to
+ # load modules that require Django's settings module.
+ os.environ.update(DJANGO_SETTINGS_MODULE = "rpki.django_settings")
+ global rpki # pylint: disable=W0602
import rpki.irdb # pylint: disable=W0621
# Entirely too much fun with read-only access to transactional databases.
diff --git a/rpki/old_irdbd.py b/rpki/old_irdbd.py
index a2ce4e94..3fd476f2 100644
--- a/rpki/old_irdbd.py
+++ b/rpki/old_irdbd.py
@@ -272,8 +272,6 @@ class main(object):
time.tzset()
parser = argparse.ArgumentParser(description = __doc__)
- parser.add_argument("-c", "--config",
- help = "override default location of configuration file")
parser.add_argument("-f", "--foreground", action = "store_true",
help = "do not daemonize (ignored, old_irdbd never daemonizes)")
rpki.log.argparse_setup(parser)
@@ -281,7 +279,7 @@ class main(object):
rpki.log.init("irdbd", args)
- self.cfg = rpki.config.parser(args.config, "irdbd")
+ self.cfg = rpki.config.parser(section = "irdbd")
startup_msg = self.cfg.get("startup-message", "")
if startup_msg:
diff --git a/rpki/pubd.py b/rpki/pubd.py
index 3c6e3130..fe7987d1 100644
--- a/rpki/pubd.py
+++ b/rpki/pubd.py
@@ -93,8 +93,6 @@ class main(object):
self.irbe_cms_timestamp = None
parser = argparse.ArgumentParser(description = __doc__)
- parser.add_argument("-c", "--config",
- help = "override default location of configuration file")
parser.add_argument("-f", "--foreground", action = "store_true",
help = "do not daemonize")
parser.add_argument("--pidfile",
@@ -108,7 +106,7 @@ class main(object):
rpki.log.init("pubd", args)
- self.cfg = rpki.config.parser(args.config, "pubd")
+ self.cfg = rpki.config.parser(section = "pubd")
self.cfg.set_global_flags()
if not args.foreground:
diff --git a/rpki/pubdb/__init__.py b/rpki/pubdb/__init__.py
new file mode 100644
index 00000000..5e25c7e3
--- /dev/null
+++ b/rpki/pubdb/__init__.py
@@ -0,0 +1,3 @@
+# $Id$
+#
+# Placeholder for pubdb Django models not yet written.
diff --git a/rpki/rootd.py b/rpki/rootd.py
index 0508dc49..6b6aa0fa 100644
--- a/rpki/rootd.py
+++ b/rpki/rootd.py
@@ -428,8 +428,6 @@ class main(object):
time.tzset()
parser = argparse.ArgumentParser(description = __doc__)
- parser.add_argument("-c", "--config",
- help = "override default location of configuration file")
parser.add_argument("-f", "--foreground", action = "store_true",
help = "do not daemonize")
parser.add_argument("--pidfile",
@@ -439,7 +437,7 @@ class main(object):
rpki.log.init("rootd", args)
- self.cfg = rpki.config.parser(args.config, "rootd")
+ self.cfg = rpki.config.parser(section = "rootd")
self.cfg.set_global_flags()
if not args.foreground:
diff --git a/rpki/rpkic.py b/rpki/rpkic.py
index d7b76c51..fdde6056 100644
--- a/rpki/rpkic.py
+++ b/rpki/rpkic.py
@@ -124,7 +124,7 @@ class main(Cmd):
global rpki # pylint: disable=W0602
try:
- cfg = rpki.config.parser(self.cfg_file, "myrpki")
+ cfg = rpki.config.parser(set_filename = self.cfg_file, section = "myrpki")
cfg.set_global_flags()
except IOError, e:
sys.exit("%s: %s" % (e.strerror, e.filename))
@@ -132,19 +132,29 @@ class main(Cmd):
self.histfile = cfg.get("history_file", os.path.expanduser("~/.rpkic_history"))
self.autosync = cfg.getboolean("autosync", True, section = "rpkic")
- from django.conf import settings
+ # This should go away now that we have rpki.django_settings, but
+ # let's get a verbose log with it present first to see what
+ # changes.
+
+ use_south = True
+ setup_db = False
+
+ if use_south:
+ os.environ.update(DJANGO_SETTINGS_MODULE = "rpki.django_settings")
+
+ else:
+ from django.conf import settings
+ settings.configure(
+ DATABASES = { "default" : {
+ "ENGINE" : "django.db.backends.mysql",
+ "NAME" : cfg.get("sql-database", section = "irdbd"),
+ "USER" : cfg.get("sql-username", section = "irdbd"),
+ "PASSWORD" : cfg.get("sql-password", section = "irdbd"),
+ "HOST" : "",
+ "PORT" : "",
+ "OPTIONS" : { "init_command": "SET storage_engine=INNODB" }}},
+ INSTALLED_APPS = ["rpki.irdb"])
- settings.configure(
- DATABASES = { "default" : {
- "ENGINE" : "django.db.backends.mysql",
- "NAME" : cfg.get("sql-database", section = "irdbd"),
- "USER" : cfg.get("sql-username", section = "irdbd"),
- "PASSWORD" : cfg.get("sql-password", section = "irdbd"),
- "HOST" : "",
- "PORT" : "",
- "OPTIONS" : { "init_command": "SET storage_engine=INNODB" }}},
- INSTALLED_APPS = ("rpki.irdb",),
- )
import rpki.irdb # pylint: disable=W0621
@@ -166,8 +176,12 @@ class main(Cmd):
except rpki.config.ConfigParser.Error:
pass
- import django.core.management
- django.core.management.call_command("syncdb", verbosity = 0, load_initial_data = False)
+ if setup_db:
+ import django.core.management
+ django.core.management.call_command("syncdb", verbosity = 3, load_initial_data = False)
+
+ if setup_db and use_south:
+ django.core.management.call_command("migrate", verbosity = 3)
self.zoo = rpki.irdb.Zookeeper(cfg = cfg, handle = self.handle, logstream = sys.stdout)
diff --git a/rpki/rpkid.py b/rpki/rpkid.py
index e3120b75..e9a05abb 100644
--- a/rpki/rpkid.py
+++ b/rpki/rpkid.py
@@ -60,8 +60,6 @@ class main(object):
self.task_queue = []
parser = argparse.ArgumentParser(description = __doc__)
- parser.add_argument("-c", "--config",
- help = "override default location of configuration file")
parser.add_argument("-f", "--foreground", action = "store_true",
help = "do not daemonize")
parser.add_argument("--pidfile",
@@ -75,7 +73,7 @@ class main(object):
rpki.log.init("rpkid", args)
- self.cfg = rpki.config.parser(args.config, "rpkid")
+ self.cfg = rpki.config.parser(section = "rpkid")
self.cfg.set_global_flags()
if not args.foreground:
diff --git a/rpki/rpkidb/__init__.py b/rpki/rpkidb/__init__.py
new file mode 100644
index 00000000..7764913c
--- /dev/null
+++ b/rpki/rpkidb/__init__.py
@@ -0,0 +1,3 @@
+# $Id$
+#
+# Placeholder for rpkidb Django models not yet written.