update publik-create-databases

This commit is contained in:
Christophe Siraut 2020-10-13 16:16:47 +02:00
parent d9bd5ee59d
commit 0dd73b2641
4 changed files with 63 additions and 183 deletions

1
debian/install vendored
View File

@ -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

23
debian/postinst vendored
View File

@ -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

View File

@ -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)

View File

@ -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