From 0dd73b2641fc0cde80ae81f3dccc24e1253ce057 Mon Sep 17 00:00:00 2001 From: Christophe Siraut Date: Tue, 13 Oct 2020 16:16:47 +0200 Subject: [PATCH] update publik-create-databases --- debian/install | 1 - debian/postinst | 23 ------ publik-create-databases | 179 ++++++++++++++-------------------------- publik.conf.example | 43 ---------- 4 files changed, 63 insertions(+), 183 deletions(-) delete mode 100644 debian/postinst delete mode 100644 publik.conf.example diff --git a/debian/install b/debian/install index dd220cf..8d97e39 100644 --- a/debian/install +++ b/debian/install @@ -2,6 +2,5 @@ publik-create-users /usr/bin publik-create-databases /usr/bin publik-cluster-link /usr/bin publik-emailconf /usr/bin -publik.conf.example /etc/publik nginx/conf.d/* etc/nginx/conf.d nginx/snippets/*.conf etc/nginx/snippets diff --git a/debian/postinst b/debian/postinst deleted file mode 100644 index a97f1fe..0000000 --- a/debian/postinst +++ /dev/null @@ -1,23 +0,0 @@ -#! /bin/sh -set -e - -case "$1" in - configure) - chmod 600 /etc/publik/publik.conf.example - ;; - - triggered) - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 diff --git a/publik-create-databases b/publik-create-databases index fa9654e..ff6fb00 100755 --- a/publik-create-databases +++ b/publik-create-databases @@ -1,130 +1,77 @@ #!/usr/bin/python3 -import os import argparse +import os +import random +import string import subprocess -import yaml - -parser = argparse.ArgumentParser() -parser.add_argument('--config', type=str, default='/etc/publik/publik.conf') -parser.add_argument('--simulate', action='store_true') -parser.add_argument('--configure', action='store_true') -args = parser.parse_args() - -model = """DATABASES['default']['HOST'] = '{host}' -DATABASES['default']['PORT'] = {port} -DATABASES['default']['PASSWORD'] = '{password}'""" +import sys -def run_pg(connection, cmd): - cmd = cmd.replace('"', '\\"') - if connection.get('host') == 'localhost' and not connection.get('admin'): - subprocess.call('echo "%s" | sudo -u postgres psql' % cmd, shell=True) +publik = { + "authentic2-multitenant": { + "database": "authentic2_multitenant", + "user": "authentic-multitenant", + "extensions": ["unaccent", "pg_trgm"], + }, + "bijoe": {}, + "chrono": {}, + "combo": {"extensions": ["unaccent"]}, + "fargo": {}, + "hobo": {}, + "passerelle": {}, + "wcs": {}, + "welco": {}, +} + + +def run(command, database="postgres", fake=False): + cmd = 'sudo -u postgres psql -c "%s" %s' % (command.replace('"', '\\"'), database) + if fake: + print(cmd) else: - admin = connection.get('admin') - subprocess.call("echo '%s' | psql -h -U %s -W" % (cmd, admin), shell=True) + subprocess.run(cmd, shell=True, check=True) -def main(): - if not os.path.isfile(args.config): - raise(Exception('Configuration file not found: %s' % args.config)) - - with open(args.config) as fh: - cfg = yaml.load(fh) - - if 'defaults' in cfg.keys(): - defaults = cfg.get('defaults') - else: - defaults = {} - - if 'databases' not in defaults.keys() and 'instances' not in cfg.keys(): - raise(Exception('No "instances" nor "defaults" keys found in configuration file')) - - for instance, data in cfg['instances'].items(): - if 'databases' not in data.keys(): - data['databases'] = defaults['databases'] - - if 'connection' in defaults.keys(): - connection = defaults['connection'] - if 'connection' in data.keys(): - connection.update(data['connection']) - else: - connection = data['connection'] +def write_setting(brique, host, port, password): + settings_d = "/etc/%s/settings.d" % brique + settings = "%s/database.py" % settings_d + if not os.path.isdir(settings_d): + os.system('mkdir -p %s' % settings_d) + with open(settings, "w") as fh: + fh.write("DATABASES['default']['HOST'] = '{host}'\n" + "DATABASES['default']['PORT'] = {port}\n" + "DATABASES['default']['PASSWORD'] = '{password}'".format(host=host, port=port, password=password)) - if args.configure: - if 'roles' not in data.keys(): - raise(Exception('Not implemented: no passwords defined')) - configure_briques(connection, data['databases'], data['roles']) - else: - if 'roles' not in data.keys(): - print('No "roles" key found, going for passwordless configuration') - data['roles'] = False - create_databases(connection, instance, data['databases'], data['roles']) +def main(args): + for brique, data in publik.items(): + database = data.get("database", brique) + user = data.get("user", brique) + extensions = data.get("extensions") + run('CREATE USER "%s";' % user, fake=args.fake) + if user == "wcs": + run("ALTER USER wcs CREATEDB;", fake=args.fake) + if args.password: + password = "".join(random.choice(string.ascii_letters + string.digits) for _ in range(16)) + run("ALTER USER \"%s\" with password '%s';" % (user, password), fake=args.fake) + run("CREATE DATABASE {} WITH OWNER = \"{}\" TEMPLATE = template0 " + "LC_COLLATE = 'fr_FR.UTF-8' LC_CTYPE = 'fr_FR.UTF-8';".format(database, user), fake=args.fake) + if extensions: + for e in extensions: + run("CREATE EXTENSION %s;" % e, database=database, fake=args.fake) + if not args.fake and args.password: + write_setting(brique, args.host, args.port, password) -def configure_briques(connection, databases, roles): - for database, role in databases.items(): +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--password", action="store_true", help="generate password") + parser.add_argument("--fake", action="store_true", help="dry-run") + parser.add_argument("--host", default="localhost") + parser.add_argument("--port", default="5432") + args = parser.parse_args() - if database == 'wcs': - continue + if not args.fake and os.geteuid() != 0: + sys.exit("You need to have privileges to run this script, please try again with sudo.") - password = roles[role] - if database == 'authentic2_multitenant': - service = 'authentic2-multitenant' - user = 'authentic-multitenant' - else: - user, service = database, database - settings_d = '/etc/%s/settings.d' % service - settings = '%s/connection.py' % settings_d - - if not os.path.isdir(settings_d) and not args.simultate: - os.system('mkdir -p %s' % settings_d) - - s = model.format(database=database, host=connection['host'], - port=connection['port'], password=password) - - if args.simulate: - print(s) - continue - - with open(settings, 'w') as fh: - fh.write(s) - - os.system('chown -R %s %s' % (user, settings_d)) - - -def create_databases(connection, instance, databases, roles): - count = len(databases.keys()) - print('instance {} has {} components'.format(instance, count)) - - cmds = [] - for database, role in databases.items(): - if roles: - password = roles[role] - else: - password = False - cmds.append(gen_cmd(database, role, password)) - - if args.simulate: - print(connection) - for c in cmds: - print(c) - else: - run_pg(connection, " ".join(cmds)) - - -def gen_cmd(database, role, password): - out = [] - if password: - out.append("CREATE USER \"{}\" PASSWORD '{}';".format(role, password)) - else: - out.append("CREATE USER \"{}\";".format(role)) - out.append("CREATE DATABASE {} WITH OWNER = \"{}\" TEMPLATE = template0 " - "LC_COLLATE = 'fr_FR.UTF-8' LC_CTYPE = 'fr_FR.UTF-8';".format(database, role)) - if database == 'wcs': - out.append("ALTER USER wcs CREATEDB;") - return " ".join(out) - - -if __name__ == '__main__': - main() + main(args) diff --git a/publik.conf.example b/publik.conf.example deleted file mode 100644 index fb3f053..0000000 --- a/publik.conf.example +++ /dev/null @@ -1,43 +0,0 @@ -defaults: - connection: - # the following is suitable for a local postgresql service - host: localhost - admin: - password: - databases: - authentic2_multitenant: authentic-multitenant - bijoe: bijoe - chrono: chrono - combo: combo - fargo: fargo - hobo: hobo - passerelle: passerelle - wcs: wcs - welco: welco - briques: - - authentic2-multitenant - - bijoe - - chrono - - combo - - hobo - - fargo - - passerelle - - welco - - wcs - -instances: - local.publik: {} - -## Example -# instances: -# demo.local.publik: -# connection: -# host: w.x.y.z -# admin: admin -# password: secret -# databases: -# authentic2_multitenant: authentic-multitenant -# combo: combo -# roles: -# authentic-multitenant: juzi3Uhi -# combo: j0kl32fa