diff options
Diffstat (limited to 'ca/rpki-sql-setup')
-rwxr-xr-x | ca/rpki-sql-setup | 348 |
1 files changed, 0 insertions, 348 deletions
diff --git a/ca/rpki-sql-setup b/ca/rpki-sql-setup deleted file mode 100755 index c72c97c5..00000000 --- a/ca/rpki-sql-setup +++ /dev/null @@ -1,348 +0,0 @@ -#!/usr/bin/env python - -# $Id$ -# -# Copyright (C) 2014 Dragon Research Labs ("DRL") -# Portions copyright (C) 2009-2013 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. - -""" -Automated setup of SQL stuff used by the RPKI tools. Pulls -configuration from rpki.conf, prompts for SQL password when needed. -""" - -import os -import pwd -import sys -import getpass -import textwrap -import argparse -import rpki.config - - -class Abstract_Driver(object): - - # Kludge to make classes derived from this into singletons. Net - # of a Million Lies says this is Not Pythonic, but it seems to - # work, so long as one doesn't attempt to subclass the resulting - # driver classes. For our purposes, it will do. - - __instance = None - - def __new__(cls, *args, **kwargs): - if cls.__instance is None: - cls.__instance = object.__new__(cls, *args, **kwargs) - return cls.__instance - - def db_accessible(self, udb): - try: - self._db_accessible_test(udb) - except: - return False - else: - return True - - def db_exists(self, udb): - self.execute("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = %s", (udb.database,)) - return bool(self.fetchone()[0]) - - def fetchone(self): - return self._cur.fetchone() - - def fetchall(self): - return self._cur.fetchall() - - def close(self): - self._cur.close() - self._db.close() - - def log(self, msg): - if self.args.verbose: - sys.stderr.write(msg + "\n") - - -class MySQL_Driver(Abstract_Driver): - - _initialized = False - - def __init__(self, args): - try: - self.driver - except AttributeError: - from rpki.mysql_import import MySQLdb - self.driver = MySQLdb - self.args = args - - def _db_accessible_test(self, udb): - self.driver.connect(db = udb.database, user = udb.username, passwd = udb.password).close() - - def execute(*args): - try: - self._cur - except AttributeError: - self.log("MySQL driver initializing root connection") - if self.args.mysql_defaults: - mysql_cfg = rpki.config.parser(set_filename = self.args.mysql_defaults, section = "client") - self._db = self.driver.connect(db = "mysql", - user = mysql_cfg.get("user"), - passwd = mysql_cfg.get("password")) - else: - self._db = self.driver.connect(db = "mysql", - user = "root", - passwd = getpass.getpass("Please enter your MySQL root password: ")) - self._db.autocommit(True) - self._cur = self._db.cursor() - self.log("MySQL driver executing {}".format(", ".join(args))) - return self._cur.execute(*args) - - def create(self, udb): - self.execute("CREATE DATABASE IF NOT EXISTS {0.database}".format(udb)) - self.fix_grants(udb) - - def drop(self, udb): - self.execute("DROP DATABASE IF EXISTS {0.database}".format(udb)) - - def script_drop(self, udb): - self.args.script_output.write("DROP DATABASE IF EXISTS {};\n".format(udb.database)) - - def fix_grants(self, udb): - self.execute("GRANT ALL ON {0.database}.* TO {0.username}@localhost IDENTIFIED BY %s".format(udb), - (udb.password,)) - -class SQLite3_Driver(Abstract_Driver): - - def __init__(self, args): - try: - self.driver - except AttributeError: - import sqlite3 - self.driver = sqlite3 - self.args = args - - def _db_accessible_test(self, udb): - self.driver.connect(udb.database).close() - - def db_exists(self, udb): - return os.path.exists(udb.database) - - def _grant(self, udb): - if udb.username and os.geteuid() == 0: - pw = pwd.getpwnam(udb.username) - os.chown(udb.database, pw.pw_uid, pw.pw_gid) - - def create(self, udb): - self._db_accessible_test(udb.database) - self._grant(udb) - - def drop(self, udb): - os.unlink(udb.database) - - def script_drop(self, udb): - self.args.script_output.write("rm {}\n".format(udb.database)) - - def fix_grants(self, udb): - self._grant(udb) - - -class PostgreSQL_Driver(Abstract_Driver): - - def __init__(self, args): - try: - self.driver - except AttributeError: - import psycopg2 - self.driver = psycopg2 - self.args = args - if args.postgresql_root_username and (os.getuid() == 0 or os.geteuid() == 0): - self._pw = pwd.getpwnam(args.postgresql_root_username) - else: - self._pw = None - self.log("Initialized PostgreSQL driver, pw {!r}".format(self._pw)) - - def _seteuid(self, new_uid): - old_uid = os.geteuid() - if new_uid != old_uid: - self.log("PostgreSQL driver changing EUID from {} to {}".format(old_uid, new_uid)) - os.seteuid(new_uid) - return old_uid - - def execute(self, *args): - try: - self._cur - except AttributeError: - self.log("PostgreSQL driver opening connection to database {}".format(self.args.postgresql_root_database)) - if self._pw is not None: - euid = self._seteuid(self._pw.pw_uid) - try: - self._db = self.driver.connect(database = self.args.postgresql_root_database) - self._db.autocommit = True - self._cur = self._db.cursor() - finally: - if self._pw is not None: - self._seteuid(euid) - self.log("PostgreSQL driver executing {}".format(", ".join(args))) - return self._cur.execute(*args) - - def _db_accessible_test(self, udb): - pw = pwd.getpwnam(udb.username) - uid = self._seteuid(pw.pw_uid) - try: - self.driver.connect(database = udb.database, user = udb.username , password = usb.password).close() - finally: - self._seteuid(uid) - - def _role_in_use(self, udb): - self.execute('''\ - SELECT COUNT(*) FROM pg_database - JOIN pg_roles ON pg_database.datdba = pg_roles.oid - WHERE pg_roles.rolname = %s''', (udb.username,)) - return bool(self.fetchone()[0]) - - def create(self, udb): - self.execute('''\ - DO $$ BEGIN - IF NOT EXISTS (SELECT * FROM pg_catalog.pg_roles - WHERE rolname = '{0.username}') - THEN - CREATE ROLE {0.username} LOGIN PASSWORD '{0.password}'; - END IF; - END $$'''.format(udb)) - self.execute("CREATE DATABASE {0.database} OWNER {0.username}".format(udb)) - - def drop(self, udb): - self.execute("DROP DATABASE IF EXISTS {0.database}".format(udb)) - if not self._role_in_use(udb): - self.execute("DROP ROLE IF EXISTS {0.username}".format(udb)) - - def script_drop(self, udb): - self.args.script_output.write(textwrap.dedent('''\ - DROP DATABASE IF EXISTS {0.database}; - DO $$ BEGIN - IF NOT EXISTS (SELECT * FROM pg_database JOIN pg_roles - ON pg_database.datdba = pg_roles.oid - WHERE pg_roles.rolname = '{0.username}') - THEN - DROP ROLE IF EXISTS {0.username}; - END IF; - END $$; - '''.format(udb))) - - def fix_grants(self, udb): - self.execute("ALTER DATABASE {0.database} OWNER TO {0.username}".format(udb)) - self.execute("ALTER ROLE {0.username} WITH PASSWORD '{0.password}".format(udb)) - - -class UserDB(object): - """ - Class to wrap access parameters for a particular database. - """ - - drivers = dict(sqlite3 = SQLite3_Driver, - mysql = MySQL_Driver, - postgresql = PostgreSQL_Driver) - - def __init__(self, args, name): - self.database = cfg.get("sql-database", section = name) - self.username = cfg.get("sql-username", section = name) - self.password = cfg.get("sql-password", section = name) - self.engine = cfg.get("sql-engine", section = name) - self.driver = self.drivers[self.engine](args) - self.args = args - - def drop(self): - if self.args.force or self.driver.db_accessible(self): - self.driver.drop(self) - - def create(self): - if self.args.force or not self.driver.db_accessible(self): - self.driver.create(self) - - def script_drop(self): - self.driver.script_drop(self) - - def drop_and_create(self): - if self.args.force or self.driver.db_accessible(self): - self.driver.drop(self) - self.driver.create(self) - - def fix_grants(self): - if self.args.force or not self.driver.db_accessible(self): - self.driver.fix_grants(self) - - -parser = argparse.ArgumentParser(description = __doc__) -parser.add_argument("-c", "--config", - help = "specify alternate location for rpki.conf") -parser.add_argument("-d", "--debug", action = "store_true", - help = "enable debugging (eg, Python backtraces)") -parser.add_argument("-v", "--verbose", action = "store_true", - help = "whistle while you work") -parser.add_argument("-f", "--force", action = "store_true", - help = "force database create, drop, or grant regardless of current state") - -parser.add_argument("--mysql-defaults", - help = "specify MySQL root access credentials via a configuration file") - - -parser.add_argument("--postgresql-root-database", default = "postgres", - help = "name of PostgreSQL control database") -parser.add_argument("--postgresql-root-username", - help = "username of PostgreSQL control role") - -subparsers = parser.add_subparsers(title = "Commands", metavar = "", dest = "dispatch") - -subparsers.add_parser("create", - help = "create databases and load schemas") - -subparsers.add_parser("drop", - help = "drop databases") - -subparser = subparsers.add_parser("script-drop", - help = "show SQL commands to drop databases") -subparser.add_argument("script_output", - nargs = "?", type = argparse.FileType("w"), default = "-", - help = "destination for drop script") - -subparsers.add_parser("drop-and-create", - help = "drop databases then recreate them and load schemas") - -subparsers.add_parser("fix-grants", - help = "whack database to match configuration file") - -args = parser.parse_args() - -try: - - cfg = rpki.config.parser(set_filename = args.config, section = "myrpki") - - names = [name for name in ("irdbd", "rpkid", "pubd") - if cfg.getboolean("start_" + name, False)] - names.append("rcynic") - - # For now, we quietly ignore missing sections rather than throwing an exception. - # I could make a case either way for this, but ignoring missing sections is a - # lot easier to clean up while debugging the installation scripts. - - for name in names: - if cfg.has_section(name): - udb = UserDB(args = args, name = name) - method = args.dispatch.replace("-", "_") - getattr(udb, method)() - -except Exception, e: - if args.debug: - raise - else: - sys.exit(str(e)) |