diff options
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. |