diff options
Diffstat (limited to 'scripts/docker/files/bin/setup-test-env.py')
-rwxr-xr-x | scripts/docker/files/bin/setup-test-env.py | 647 |
1 files changed, 0 insertions, 647 deletions
diff --git a/scripts/docker/files/bin/setup-test-env.py b/scripts/docker/files/bin/setup-test-env.py deleted file mode 100755 index bbf5267c..00000000 --- a/scripts/docker/files/bin/setup-test-env.py +++ /dev/null @@ -1,647 +0,0 @@ -#!/usr/bin/env python - - -""" -This script knows how to build a minimum environment for Soledad Server, which -includes the following: - - - Couch server startup - - Token and shared database initialization - - Soledad Server startup - -Options can be passed for configuring the different environments, so this may -be used by other programs to setup different environments for arbitrary tests. -Use the --help option to get information on usage. - -For some commands you will need an environment with Soledad python packages -available, thus you might want to explicitly call python and not rely in the -shebang line. -""" - - -import time -import os -import signal -import tempfile -import psutil -from argparse import ArgumentParser -from subprocess import call -from couchdb import Server -from couchdb.http import PreconditionFailed -from couchdb.http import ResourceConflict -from couchdb.http import ResourceNotFound -from hashlib import sha512 - -from leap.soledad.common.l2db.errors import DatabaseDoesNotExist - - -# -# Utilities -# - -def get_pid(pidfile): - if not os.path.isfile(pidfile): - return 0 - try: - with open(pidfile) as f: - return int(f.read()) - except IOError: - return 0 - - -def pid_is_running(pid): - try: - psutil.Process(pid) - return True - except psutil.NoSuchProcess: - return False - - -def pidfile_is_running(pidfile): - try: - pid = get_pid(pidfile) - psutil.Process(pid) - return pid - except psutil.NoSuchProcess: - return False - - -def status_from_pidfile(args, default_basedir, name): - basedir = _get_basedir(args, default_basedir) - pidfile = os.path.join(basedir, args.pidfile) - try: - pid = get_pid(pidfile) - psutil.Process(pid) - print "[+] %s is running with pid %d" % (name, pid) - except (IOError, psutil.NoSuchProcess): - print "[-] %s stopped" % name - - -def kill_all_executables(args): - basename = os.path.basename(args.executable) - pids = [int(pid) for pid in os.listdir('/proc') if pid.isdigit()] - for pid in pids: - try: - p = psutil.Process(pid) - if p.name() == basename: - print '[!] killing - pid: %d' % pid - os.kill(pid, signal.SIGKILL) - except: - pass - - -# -# Couch Server control -# - -COUCH_EXECUTABLE = '/usr/bin/couchdb' -ERLANG_EXECUTABLE = 'beam.smp' -COUCH_TEMPLATE = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - './conf/couchdb_default.ini') -COUCH_TEMPLATE -COUCH_PIDFILE = 'couchdb.pid' -COUCH_LOGFILE = 'couchdb.log' -COUCH_PORT = 5984 -COUCH_HOST = '127.0.0.1' -COUCH_BASEDIR = '/tmp/couch_test' - - -def _get_basedir(args, default): - basedir = args.basedir - if not basedir: - basedir = default - if not os.path.isdir(basedir): - os.mkdir(basedir) - return basedir - - -def couch_server_start(args): - basedir = _get_basedir(args, COUCH_BASEDIR) - pidfile = os.path.join(basedir, args.pidfile) - logfile = os.path.join(basedir, args.logfile) - - # check if already running - pid = get_pid(pidfile) - if pid_is_running(pid): - print '[*] error: already running - pid: %d' % pid - exit(1) - if os.path.isfile(pidfile): - os.unlink(pidfile) - - # generate a config file from template if needed - config_file = args.config_file - if not config_file: - config_file = tempfile.mktemp(prefix='couch_config_', dir=basedir) - lines = [] - with open(args.template) as f: - lines = f.readlines() - lines = map(lambda l: l.replace('BASEDIR', basedir), lines) - with open(config_file, 'w') as f: - f.writelines(lines) - - # start couch server - try: - call([ - args.executable, - '-n', # reset configuration file chain (including system default) - '-a %s' % config_file, # add configuration FILE to chain - '-b', # spawn as a background process - '-p %s' % pidfile, # set the background PID FILE - '-o %s' % logfile, # redirect background stdout to FILE - '-e %s' % logfile]) # redirect background stderr to FILE - except Exception as e: - print '[*] error: could not start couch server - %s' % str(e) - exit(1) - - # couch may take a bit to store the pid in the pidfile, so we just wait - # until it does - pid = None - while not pid: - try: - pid = get_pid(pidfile) - break - except: - time.sleep(0.1) - - print '[+] couch is running with pid: %d' % pid - - -def couch_server_stop(args): - basedir = _get_basedir(args, COUCH_BASEDIR) - pidfile = os.path.join(basedir, args.pidfile) - pid = get_pid(pidfile) - if not pid_is_running(pid): - print '[*] error: no running server found' - exit(1) - call([ - args.executable, - '-p %s' % pidfile, # set the background PID FILE - '-k']) # kill the background process, will respawn if needed - print '[-] stopped couch server with pid %d ' % pid - - -def couch_status_from_pidfile(args): - status_from_pidfile(args, COUCH_BASEDIR, 'couch') - - -# -# User DB maintenance # -# - -def user_db_create(args): - from leap.soledad.common.couch import CouchDatabase - url = 'http://localhost:%d/user-%s' % (args.port, args.uuid) - try: - CouchDatabase.open_database( - url=url, create=False, replica_uid=None) - print '[*] error: database "user-%s" already exists' % args.uuid - exit(1) - except DatabaseDoesNotExist: - CouchDatabase.open_database( - url=url, create=True, replica_uid=None) - print '[+] database created: user-%s' % args.uuid - - -def user_db_delete(args): - s = _couch_get_server(args) - try: - dbname = 'user-%s' % args.uuid - s.delete(dbname) - print '[-] database deleted: %s' % dbname - except ResourceNotFound: - print '[*] error: database "%s" does not exist' % dbname - exit(1) - - -# -# Soledad Server control -# - -TWISTD_EXECUTABLE = 'twistd' # use whatever is available on path - -SOLEDAD_SERVER_BASEDIR = '/tmp/soledad_server_test' -SOLEDAD_SERVER_CONFIG_FILE = './conf/soledad_default.ini' -SOLEDAD_SERVER_PIDFILE = 'soledad.pid' -SOLEDAD_SERVER_LOGFILE = 'soledad.log' -SOLEDAD_SERVER_PRIVKEY = 'soledad_privkey.pem' -SOLEDAD_SERVER_CERTKEY = 'soledad_certkey.pem' -SOLEDAD_SERVER_PORT = 2424 -SOLEDAD_SERVER_AUTH_TOKEN = 'an-auth-token' -SOLEDAD_SERVER_URL = 'https://localhost:2424' - -SOLEDAD_CLIENT_PASS = '12345678' -SOLEDAD_CLIENT_BASEDIR = '/tmp/soledad_client_test' -SOLEDAD_CLIENT_UUID = '1234567890abcdef' - - -def soledad_server_start(args): - basedir = _get_basedir(args, SOLEDAD_SERVER_BASEDIR) - pidfile = os.path.join(basedir, args.pidfile) - logfile = os.path.join(basedir, args.logfile) - private_key = os.path.join(basedir, args.private_key) - cert_key = os.path.join(basedir, args.cert_key) - - pid = get_pid(pidfile) - if pid_is_running(pid): - pid = get_pid(pidfile) - print "[*] error: already running - pid: %d" % pid - exit(1) - - port = args.port - if args.tls: - port = 'ssl:%d:privateKey=%s:certKey=%s:sslmethod=SSLv23_METHOD' \ - % (args.port, private_key, cert_key) - params = [ - '--logfile=%s' % logfile, - '--pidfile=%s' % pidfile, - 'web', - '--wsgi=leap.soledad.server.application.wsgi_application', - '--port=%s' % port - ] - if args.no_daemonize: - params.insert(0, '--nodaemon') - - call([args.executable] + params) - - pid = get_pid(pidfile) - print '[+] soledad-server is running with pid %d' % pid - - -def soledad_server_stop(args): - basedir = _get_basedir(args, SOLEDAD_SERVER_BASEDIR) - pidfile = os.path.join(basedir, args.pidfile) - pid = get_pid(pidfile) - if not pid_is_running(pid): - print '[*] error: no running server found' - exit(1) - os.kill(pid, signal.SIGKILL) - print '[-] stopped - pid: %d' % pid - - -def soledad_server_status_from_pidfile(args): - status_from_pidfile(args, SOLEDAD_SERVER_BASEDIR, 'soledad-server') - - -# couch helpers - -def _couch_get_server(args): - url = 'http://%s:%d/' % (args.host, args.port) - return Server(url=url) - - -def _couch_create_db(args, dbname): - s = _couch_get_server(args) - # maybe create the database - try: - s.create(dbname) - print '[+] database created: %s' % dbname - except PreconditionFailed as e: - error_code, _ = e.message - if error_code == 'file_exists': - print '[*] error: "%s" database already exists' % dbname - exit(1) - return s - - -def _couch_delete_db(args, dbname): - s = _couch_get_server(args) - # maybe create the database - try: - s.delete(dbname) - print '[-] database deleted: %s' % dbname - except ResourceNotFound: - print '[*] error: "%s" database does not exist' % dbname - exit(1) - - -def _token_dbname(): - dbname = 'tokens_' + \ - str(int(time.time() / (30 * 24 * 3600))) - return dbname - - -def token_db_create(args): - dbname = _token_dbname() - _couch_create_db(args, dbname) - - -def token_db_insert_token(args): - s = _couch_get_server(args) - try: - dbname = _token_dbname() - db = s[dbname] - token = sha512(args.auth_token).hexdigest() - db[token] = { - 'type': 'Token', - 'user_id': args.uuid, - } - print '[+] token for uuid "%s" created in tokens database' % args.uuid - except ResourceConflict: - print '[*] error: token for uuid "%s" already exists in tokens database' \ - % args.uuid - exit(1) - - -def token_db_delete(args): - dbname = _token_dbname() - _couch_delete_db(args, dbname) - - -# -# Shared DB creation -# - -def shared_db_create(args): - _couch_create_db(args, 'shared') - - -def shared_db_delete(args): - _couch_delete_db(args, 'shared') - - -# -# Certificate creation -# - -CERT_CONFIG_FILE = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - './conf/cert_default.conf') - - -def cert_create(args): - private_key = os.path.join(args.basedir, args.private_key) - cert_key = os.path.join(args.basedir, args.cert_key) - try: - os.mkdir(args.basedir) - except OSError: - pass - call([ - 'openssl', - 'req', - '-x509', - '-sha256', - '-nodes', - '-days', '365', - '-newkey', 'rsa:2048', - '-config', args.config_file, - '-keyout', private_key, - '-out', cert_key]) - - -def cert_delete(args): - private_key = os.path.join(args.basedir, args.private_key) - cert_key = os.path.join(args.basedir, args.cert_key) - try: - os.unlink(private_key) - os.unlink(cert_key) - except OSError: - pass - - -# -# Soledad Client Control -# - -def soledad_client_test(args): - - # maybe infer missing parameters - basedir = args.basedir - if not basedir: - basedir = tempfile.mkdtemp() - server_url = args.server_url - if not server_url: - server_url = 'http://127.0.0.1:%d' % args.port - - # get a soledad instance - from client_side_db import _get_soledad_instance - _get_soledad_instance( - args.uuid, - unicode(args.passphrase), - basedir, - server_url, - args.cert_key, - args.auth_token) - - -# -# Command Line Interface -# - -class Command(object): - - def __init__(self, parser=ArgumentParser()): - self.commands = [] - self.parser = parser - self.subparsers = None - - def add_command(self, *args, **kwargs): - # pop out the func parameter to use later - func = None - if 'func' in kwargs.keys(): - func = kwargs.pop('func') - # eventually create a subparser - if not self.subparsers: - self.subparsers = self.parser.add_subparsers() - # create command and associate a function with it - command = Command(self.subparsers.add_parser(*args, **kwargs)) - if func: - command.parser.set_defaults(func=func) - self.commands.append(command) - return command - - def set_func(self, func): - self.parser.set_defaults(func=func) - - def add_argument(self, *args, **kwargs): - self.parser.add_argument(*args, **kwargs) - - def add_arguments(self, arglist): - for args, kwargs in arglist: - self.add_argument(*args, **kwargs) - - def parse_args(self): - return self.parser.parse_args() - - -# -# Command Line Interface -# - -def run_cli(): - cli = Command() - - # couch command with subcommands - cmd_couch = cli.add_command('couch', help="manage couch server") - - cmd_couch_start = cmd_couch.add_command('start', func=couch_server_start) - cmd_couch_start.add_arguments([ - (['--executable', '-e'], {'default': COUCH_EXECUTABLE}), - (['--basedir', '-b'], {}), - (['--config-file', '-c'], {}), - (['--template', '-t'], {'default': COUCH_TEMPLATE}), - (['--pidfile', '-p'], {'default': COUCH_PIDFILE}), - (['--logfile', '-l'], {'default': COUCH_LOGFILE}) - ]) - - cmd_couch_stop = cmd_couch.add_command('stop', func=couch_server_stop) - cmd_couch_stop.add_arguments([ - (['--executable', '-e'], {'default': COUCH_EXECUTABLE}), - (['--basedir', '-b'], {}), - (['--pidfile', '-p'], {'default': COUCH_PIDFILE}), - ]) - - cmd_couch_status = cmd_couch.add_command( - 'status', func=couch_status_from_pidfile) - cmd_couch_status.add_arguments([ - (['--basedir', '-b'], {}), - (['--pidfile', '-p'], {'default': COUCH_PIDFILE})]) - - cmd_couch_kill = cmd_couch.add_command('kill', func=kill_all_executables) - cmd_couch_kill.add_argument( - '--executable', '-e', default=ERLANG_EXECUTABLE) - - # user database maintenance - cmd_user_db = cli.add_command('user-db') - - cmd_user_db_create = cmd_user_db.add_command('create', func=user_db_create) - cmd_user_db_create.add_arguments([ - (['--host', '-H'], {'default': COUCH_HOST}), - (['--port', '-P'], {'type': int, 'default': COUCH_PORT}), - (['--uuid', '-u'], {'default': SOLEDAD_CLIENT_UUID}), - ]) - - cmd_user_db_create = cmd_user_db.add_command( - 'delete', func=user_db_delete) - cmd_user_db_create.add_arguments([ - (['--host', '-H'], {'default': COUCH_HOST}), - (['--port', '-P'], {'type': int, 'default': COUCH_PORT}), - (['--uuid', '-u'], {'default': SOLEDAD_CLIENT_UUID}) - ]) - - # soledad server command with subcommands - cmd_sol_server = cli.add_command( - 'soledad-server', help="manage soledad server") - - cmd_sol_server_start = cmd_sol_server.add_command( - 'start', func=soledad_server_start) - cmd_sol_server_start.add_arguments([ - (['--executable', '-e'], {'default': TWISTD_EXECUTABLE}), - (['--config-file', '-c'], {'default': SOLEDAD_SERVER_CONFIG_FILE}), - (['--pidfile', '-p'], {'default': SOLEDAD_SERVER_PIDFILE}), - (['--logfile', '-l'], {'default': SOLEDAD_SERVER_LOGFILE}), - (['--port', '-P'], {'type': int, 'default': SOLEDAD_SERVER_PORT}), - (['--tls', '-t'], {'action': 'store_true'}), - (['--private-key', '-K'], {'default': SOLEDAD_SERVER_PRIVKEY}), - (['--cert-key', '-C'], {'default': SOLEDAD_SERVER_CERTKEY}), - (['--no-daemonize', '-n'], {'action': 'store_true'}), - (['--basedir', '-b'], {'default': SOLEDAD_SERVER_BASEDIR}), - ]) - - cmd_sol_server_stop = cmd_sol_server.add_command( - 'stop', func=soledad_server_stop) - cmd_sol_server_stop.add_arguments([ - (['--basedir', '-b'], {'default': SOLEDAD_SERVER_BASEDIR}), - (['--pidfile', '-p'], {'default': SOLEDAD_SERVER_PIDFILE}), - ]) - - cmd_sol_server_status = cmd_sol_server.add_command( - 'status', func=soledad_server_status_from_pidfile) - cmd_sol_server_status.add_arguments([ - (['--basedir', '-b'], {'default': SOLEDAD_SERVER_BASEDIR}), - (['--pidfile', '-p'], {'default': SOLEDAD_SERVER_PIDFILE}), - ]) - - cmd_sol_server_kill = cmd_sol_server.add_command( - 'kill', func=kill_all_executables) - cmd_sol_server_kill.add_argument( - '--executable', '-e', default=TWISTD_EXECUTABLE) - - # token db maintenance - cmd_token_db = cli.add_command('token-db') - cmd_token_db_create = cmd_token_db.add_command( - 'create', func=token_db_create) - cmd_token_db_create.add_arguments([ - (['--host', '-H'], {'default': COUCH_HOST}), - (['--uuid', '-u'], {'default': SOLEDAD_CLIENT_UUID}), - (['--port', '-P'], {'type': int, 'default': COUCH_PORT}), - ]) - - cmd_token_db_insert_token = cmd_token_db.add_command( - 'insert-token', func=token_db_insert_token) - cmd_token_db_insert_token.add_arguments([ - (['--host', '-H'], {'default': COUCH_HOST}), - (['--uuid', '-u'], {'default': SOLEDAD_CLIENT_UUID}), - (['--port', '-P'], {'type': int, 'default': COUCH_PORT}), - (['--auth-token', '-a'], {'default': SOLEDAD_SERVER_AUTH_TOKEN}), - ]) - - cmd_token_db_delete = cmd_token_db.add_command( - 'delete', func=token_db_delete) - cmd_token_db_delete.add_arguments([ - (['--host', '-H'], {'default': COUCH_HOST}), - (['--uuid', '-u'], {'default': SOLEDAD_CLIENT_UUID}), - (['--port', '-P'], {'type': int, 'default': COUCH_PORT}), - ]) - - # shared db creation - cmd_shared_db = cli.add_command('shared-db') - - cmd_shared_db_create = cmd_shared_db.add_command( - 'create', func=shared_db_create) - cmd_shared_db_create.add_arguments([ - (['--host', '-H'], {'default': COUCH_HOST}), - (['--port', '-P'], {'type': int, 'default': COUCH_PORT}), - ]) - - cmd_shared_db_delete = cmd_shared_db.add_command( - 'delete', func=shared_db_delete) - cmd_shared_db_delete.add_arguments([ - (['--host', '-H'], {'default': COUCH_HOST}), - (['--port', '-P'], {'type': int, 'default': COUCH_PORT}), - ]) - - # certificate generation - cmd_cert = cli.add_command('cert', help="create tls certificates") - - cmd_cert_create = cmd_cert.add_command('create', func=cert_create) - cmd_cert_create.add_arguments([ - (['--basedir', '-b'], {'default': SOLEDAD_SERVER_BASEDIR}), - (['--config-file', '-c'], {'default': CERT_CONFIG_FILE}), - (['--private-key', '-K'], {'default': SOLEDAD_SERVER_PRIVKEY}), - (['--cert-key', '-C'], {'default': SOLEDAD_SERVER_CERTKEY}), - ]) - - cmd_cert_create = cmd_cert.add_command('delete', func=cert_delete) - cmd_cert_create.add_arguments([ - (['--basedir', '-b'], {'default': SOLEDAD_SERVER_BASEDIR}), - (['--private-key', '-K'], {'default': SOLEDAD_SERVER_PRIVKEY}), - (['--cert-key', '-C'], {'default': SOLEDAD_SERVER_CERTKEY}), - ]) - - # soledad client command with subcommands - cmd_sol_client = cli.add_command( - 'soledad-client', help="manage soledad client") - - cmd_sol_client_test = cmd_sol_client.add_command( - 'test', func=soledad_client_test) - cmd_sol_client_test.add_arguments([ - (['--port', '-P'], {'type': int, 'default': SOLEDAD_SERVER_PORT}), - (['--tls', '-t'], {'action': 'store_true'}), - (['--uuid', '-u'], {'default': SOLEDAD_CLIENT_UUID}), - (['--passphrase', '-k'], {'default': SOLEDAD_CLIENT_PASS}), - (['--basedir', '-b'], {'default': SOLEDAD_CLIENT_BASEDIR}), - (['--server-url', '-s'], {'default': SOLEDAD_SERVER_URL}), - (['--cert-key', '-C'], {'default': os.path.join( - SOLEDAD_SERVER_BASEDIR, - SOLEDAD_SERVER_CERTKEY)}), - (['--auth-token', '-a'], {'default': SOLEDAD_SERVER_AUTH_TOKEN}), - ]) - - # parse and run cli - args = cli.parse_args() - args.func(args) - - -if __name__ == '__main__': - run_cli() |