aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xca/irbe_cli2
-rw-r--r--ca/rpki-confgen.xml32
-rwxr-xr-xca/rpki-manage17
-rwxr-xr-xca/rpki-sql-backup2
-rwxr-xr-xca/rpki-sql-setup4
-rwxr-xr-xca/rpki-start-servers4
-rw-r--r--ca/rpki.wsgi3
-rw-r--r--ca/tests/smoketest.py2
-rw-r--r--ca/tests/sql-cleaner.py2
-rw-r--r--ca/tests/sql-dumper.py2
-rw-r--r--ca/tests/yamlconf.py4
-rw-r--r--ca/tests/yamltest.py14
-rw-r--r--potpourri/upgrade-add-ghostbusters.py2
-rw-r--r--rpki/config.py43
-rw-r--r--rpki/db_router.py57
-rw-r--r--rpki/django_settings.py238
-rw-r--r--rpki/fields.py192
-rw-r--r--rpki/gui/default_settings.py171
-rw-r--r--rpki/irdb/models.py120
-rw-r--r--rpki/irdbd.py29
-rw-r--r--rpki/old_irdbd.py2
-rw-r--r--rpki/pubd.py2
-rw-r--r--rpki/pubdb/__init__.py3
-rw-r--r--rpki/rootd.py2
-rw-r--r--rpki/rpkic.py2
-rw-r--r--rpki/rpkid.py2
-rw-r--r--rpki/rpkidb/__init__.py3
27 files changed, 596 insertions, 360 deletions
diff --git a/ca/irbe_cli b/ca/irbe_cli
index 1becd403..c38cf93b 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 = []
diff --git a/ca/rpki-confgen.xml b/ca/rpki-confgen.xml
index e0ed273a..a29ad8cd 100644
--- a/ca/rpki-confgen.xml
+++ b/ca/rpki-confgen.xml
@@ -816,30 +816,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 32f11cc3..d1b15253 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
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/yamlconf.py b/ca/tests/yamlconf.py
index 1b339a89..0f1467f7 100644
--- a/ca/tests/yamlconf.py
+++ b/ca/tests/yamlconf.py
@@ -500,7 +500,7 @@ class allocation(object):
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 +681,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:
diff --git a/ca/tests/yamltest.py b/ca/tests/yamltest.py
index 2b65dbd2..62b1252b 100644
--- a/ca/tests/yamltest.py
+++ b/ca/tests/yamltest.py
@@ -539,14 +539,15 @@ 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.update(YAMLTEST_RPKIC_COUNTER = self.next_rpkic_counter(),
+ RPKI_CONF = self.path("rpki.conf"))
subprocess.check_call(cmd, cwd = self.host.path(), env = env)
def run_python_daemon(self, prog):
@@ -556,12 +557,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())
+ env = os.environ.copy()
+ env.update(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
@@ -672,7 +674,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)
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 f38427c4..c73fe837 100644
--- a/rpki/config.py
+++ b/rpki/config.py
@@ -45,10 +45,10 @@ try:
except ImportError:
default_dirname = 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,14 +61,35 @@ 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 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.
+
+ NB: In most cases, programs which accept configuration filenames on
+ their command lines should pass those filenames to us using
+ set_filename so that we can set the magic environment variable,
+ because constraints from some external libraries (principally
+ Django) sometimes require our own library code to look things up in
+ the configuration file without the knowledge of the controlling
+ program. 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
@@ -77,11 +98,11 @@ class parser(object):
if filename is not None:
filenames.append(filename)
else:
- if default_envname in os.environ:
- filenames.append(os.environ[default_envname])
+ if rpki_conf_envname in os.environ:
+ filenames.append(os.environ[rpki_conf_envname])
filenames.append(default_filename)
if default_dirname is not None:
- filenames.append("%s/%s" % (default_dirname, default_filename))
+ filenames.append(os.path.join(default_dirname, default_filename))
f = fn = None
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..eb3a184b
--- /dev/null
+++ b/rpki/django_settings.py
@@ -0,0 +1,238 @@
+# $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.
+#
+# 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
+
+
+# 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())
+ 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/default_settings.py b/rpki/gui/default_settings.py
deleted file mode 100644
index 3859247c..00000000
--- a/rpki/gui/default_settings.py
+++ /dev/null
@@ -1,171 +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/irdb/models.py b/rpki/irdb/models.py
index 6fa48c59..26901a68 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,103 +76,21 @@ 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 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
+class SignedReferralField(DERField):
+ description = "CMS signed object containing XML"
+ rpki_type = rpki.x509.SignedReferral
-class CertificateField(DERField):
- description = "X.509 certificate"
- rpki_type = rpki.x509.X509
-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 = [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
@@ -231,7 +151,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
@@ -391,7 +311,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
@@ -634,13 +554,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 d53ae67c..856f91bf 100644
--- a/rpki/irdbd.py
+++ b/rpki/irdbd.py
@@ -166,7 +166,7 @@ class main(object):
rpki.log.init("irdbd", args)
- self.cfg = rpki.config.parser(args.config, "irdbd")
+ self.cfg = rpki.config.parser(set_filename = args.config, section = "irdbd")
self.cfg.set_global_flags()
if not args.foreground:
@@ -185,34 +185,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 6c026a31..bb75ae5b 100644
--- a/rpki/old_irdbd.py
+++ b/rpki/old_irdbd.py
@@ -290,7 +290,7 @@ class main(object):
rpki.log.init("irdbd", args)
- self.cfg = rpki.config.parser(args.config, "irdbd")
+ self.cfg = rpki.config.parser(set_filename = args.config, section = "irdbd")
startup_msg = self.cfg.get("startup-message", "")
if startup_msg:
diff --git a/rpki/pubd.py b/rpki/pubd.py
index 79315a78..cf5b1b6a 100644
--- a/rpki/pubd.py
+++ b/rpki/pubd.py
@@ -68,7 +68,7 @@ class main(object):
rpki.log.init("pubd", args)
- self.cfg = rpki.config.parser(args.config, "pubd")
+ self.cfg = rpki.config.parser(set_filename = args.config, 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 fb445213..41c9e656 100644
--- a/rpki/rootd.py
+++ b/rpki/rootd.py
@@ -349,7 +349,7 @@ class main(object):
rpki.log.init("rootd", args)
- self.cfg = rpki.config.parser(args.config, "rootd")
+ self.cfg = rpki.config.parser(set_filename = args.config, section = "rootd")
self.cfg.set_global_flags()
if not args.foreground:
diff --git a/rpki/rpkic.py b/rpki/rpkic.py
index d7b76c51..62921308 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))
diff --git a/rpki/rpkid.py b/rpki/rpkid.py
index 36ee2ea9..db81d56f 100644
--- a/rpki/rpkid.py
+++ b/rpki/rpkid.py
@@ -75,7 +75,7 @@ class main(object):
rpki.log.init("rpkid", args)
- self.cfg = rpki.config.parser(args.config, "rpkid")
+ self.cfg = rpki.config.parser(set_filename = args.config, 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.