Sunil Mohan Adapa 9bd1f80d5c
*: Always pass check= argument to subprocess.run()
- Avoid flake8 warnings.

- Makes the call more explicitly readable in case an exception is expected but
check=True is not passed by mistake.

Tests:

- Many tests are skipped since the changes are considered trivial.
check=False is already the default for subprocess.run() method.

- actions/package: Install an app when it is not installed.

- actions/upgrade: Run manual upgrades.

- actions/users: Change a user password. Login. Create/remove a user.

- actions/zoph: Restore a database.

- container: On a fresh repository, run ./container up,ssh,stop,destroy for a
testing container.

- plinth/action_utils.py: Enable/disable an app that has a running service.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
2021-10-11 14:34:40 -04:00

148 lines
5.0 KiB
Python
Executable File

#!/usr/bin/python3
# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Configuration helper for Zoph server.
"""
import argparse
import configparser
import json
import os
import re
import subprocess
from plinth import action_utils
APACHE_CONF = '/etc/apache2/conf-available/zoph.conf'
DB_BACKUP_FILE = '/var/lib/plinth/backups-data/zoph-database.sql'
def parse_arguments():
"""Return parsed command line arguments as dictionary."""
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
subparsers.add_parser('pre-install',
help='Perform Zoph pre-install configuration')
subparser = subparsers.add_parser('setup',
help='Perform Zoph configuration setup')
subparsers.add_parser('get-configuration',
help='Return the current configuration')
subparser = subparsers.add_parser('set-configuration',
help='Configure zoph')
subparser.add_argument('--admin-user', help='Name of the admin user')
subparser.add_argument('--enable-osm', help='Enable OpenSteetMap maps')
subparsers.add_parser('is-configured', help='return true if configured')
subparsers.add_parser('dump-database', help='Dump database to file')
subparsers.add_parser('restore-database',
help='Restore database from file')
subparsers.required = True
return parser.parse_args()
def subcommand_pre_install(_):
"""Preseed debconf values before packages are installed."""
action_utils.debconf_set_selections([
'zoph zoph/dbconfig-install boolean true',
'zoph zoph/mysql/admin-user string root'
])
def subcommand_get_configuration(_):
"""Return the current configuration."""
configuration = {}
process = subprocess.run(['zoph', '--dump-config'], stdout=subprocess.PIPE,
check=True)
for line in process.stdout.decode().splitlines():
name, value = line.partition(':')[::2]
configuration[name.strip()] = value[1:]
print(json.dumps(configuration))
def _zoph_configure(key, value):
"""Set a configure value in Zoph."""
subprocess.run(['zoph', '--config', key, value], check=True)
def subcommand_setup(_):
"""Setup Zoph configuration."""
_zoph_configure('import.enable', 'true')
_zoph_configure('import.upload', 'true')
_zoph_configure('import.rotate', 'true')
_zoph_configure('path.unzip', 'unzip')
_zoph_configure('path.untar', 'tar xvf')
_zoph_configure('path.ungz', 'gunzip')
# Maps using OpenStreetMap is enabled by default.
_zoph_configure('maps.provider', 'osm')
def _get_db_name():
"""Return the name of the database configured by dbconfig."""
config = configparser.ConfigParser()
config.read_file(open('/etc/zoph.ini', 'r'))
return config['zoph']['db_name'].strip('"')
def subcommand_set_configuration(arguments):
"""Setup Zoph Apache configuration."""
_zoph_configure('interface.user.remote', 'true')
# Note that using OpenSteetmap as a mapping provider is a very nice
# feature, but some people may regard its use as a privacy issue
if arguments.enable_osm:
value = 'osm' if arguments.enable_osm == 'True' else ''
_zoph_configure('maps.provider', value)
if arguments.admin_user:
# Edit the database to rename the admin user to FreedomBox admin user.
admin_user = arguments.admin_user
if not re.match(r'^[\w.@][\w.@-]+\Z', admin_user, flags=re.ASCII):
# Check to avoid SQL injection
raise ValueError('Invalid username')
query = f"UPDATE zoph_users SET user_name='{admin_user}' \
WHERE user_name='admin';"
subprocess.run(['mysql', _get_db_name()], input=query.encode(),
check=True)
def subcommand_is_configured(_):
"""Print whether zoph app is configured."""
subprocess.run(['zoph', '--get-config', 'interface.user.remote'],
check=True)
def subcommand_dump_database(_):
"""Dump database to file."""
db_name = _get_db_name()
os.makedirs(os.path.dirname(DB_BACKUP_FILE), exist_ok=True)
with open(DB_BACKUP_FILE, 'w') as db_backup_file:
subprocess.run(['mysqldump', db_name], stdout=db_backup_file,
check=True)
def subcommand_restore_database(_):
"""Restore database from file."""
db_name = _get_db_name()
subprocess.run(['mysqladmin', '--force', 'drop', db_name], check=False)
subprocess.run(['mysqladmin', 'create', db_name], check=True)
with open(DB_BACKUP_FILE, 'r') as db_restore_file:
subprocess.run(['mysql', db_name], stdin=db_restore_file, check=True)
def main():
"""Parse arguments and perform all duties."""
arguments = parse_arguments()
subcommand = arguments.subcommand.replace('-', '_')
subcommand_method = globals()['subcommand_' + subcommand]
subcommand_method(arguments)
if __name__ == '__main__':
main()