import pprint import shlex import shutil import signal import boto3 import click from subprocess import call, Popen import json import os import redis as redis_lib from jinja2 import Environment, FileSystemLoader import pkg_resources from owsdev.service import get_service, active_services, known_services from owsdev.config import config, grass_session_token, grass_expiration_time, DYNAMODB_TABLE_NAME from owsdev.proxy import run_proxy from owsdev import tmux as tmux_lib import tempfile def load_service(ctx, param, value): try: return get_service(value) except KeyError as err: click.echo(err) exit(1) @click.group(help="Tools to help run an array of collaborating services.") def main(): pass @main.command(help='Check for problems with source dirs') def doctor(): for service in active_services(): service.doctor() click.echo('Done!') @main.group(name='tmux', help="Start and stop an array of services") def tmux_group(): pass @tmux_group.command(name='start') @click.option('--panes', is_flag=True) @click.option('--attach', is_flag=True) def tmux_start(panes, attach): services = [ service for service in active_services() if service.type != 'proxy-only'] tmux = tmux_lib.Tmux(panes, len(services)) tmux.setup() for index, service in enumerate(services): command = 'owsdev run_service {} '.format(service.name) tmux.run_command(index, service.name, command) if attach: tmux_lib.attach() else: click.echo('Created tmux session with name {}'.format(tmux_lib.session_name)) @tmux_group.command(name='attach') def tmux_attach(): tmux_lib.attach() @tmux_group.command(name='stop') def tmux_stop(): tmux_lib.stop() @main.command(help='Run proxy that maps services to local ports') def proxy(): if os.geteuid() != 0: click.echo('Must be run as root.') exit(1) run_proxy(reporter=click) @main.group(help='Map or unmap qa services to localhost') def hosts(): pass @hosts.command() def restore(): if os.geteuid() != 0: click.echo('Must be run as root.') exit(1) if os.path.exists('/etc/hosts.orig'): shutil.copyfile('/etc/hosts.orig', '/etc/hosts') _reload_dns() click.echo('Stopped.') @hosts.command() def remap(): if os.geteuid() != 0: click.echo('Must be run as root.') exit(1) if not os.path.exists('/etc/hosts.orig'): click.echo( "Error: /etc/hosts.orig doesn't exist. Please create.") exit(1) template_dir = pkg_resources.resource_filename('owsdev', 'data') env = Environment( loader=FileSystemLoader(template_dir) ) services = [ service for service in known_services() if service.is_proxied()] hosts_base_path = pkg_resources.resource_filename('owsdev', 'data/hosts.base') with open(hosts_base_path) as hosts_base_file: hosts_base = hosts_base_file.read() template = env.get_template('dev.hosts.j2') new_hosts = tempfile.NamedTemporaryFile('w', delete=False) with new_hosts as output: output.write( template.render({"services": services, "hosts_base": hosts_base})) shutil.copyfile(new_hosts.name, '/etc/hosts') _reload_dns() def _reload_dns(): call(['dscacheutil', '-flushcache']) call(['killall', '-HUP', 'mDNSResponder']) @main.group(help='Start and stop DynamoDBLocal') def dynamodb(): pass @dynamodb.command(name="start") @click.option('--skip-check', is_flag=True) @click.option('--force', is_flag=True) def dynamodb_start(skip_check, force): os.makedirs(config['dynamodblocal']['log_dir'], exist_ok=True) os.makedirs(config['dynamodblocal']['data_dir'], exist_ok=True) pidpath = os.path.join(config['dynamodblocal']['log_dir'], 'dynamodb.pid') logpath = os.path.join(config['dynamodblocal']['log_dir'], 'dynamodb.log') if os.path.exists(pidpath) and not force: click.echo('PIDFILE already exists. Aborting. Use --force to ignore.') exit(1) with open(logpath, 'wb') as logfile: cmd = 'java -Djava.library.path={dynamodb_install_dir} -jar {dynamodb_install_dir}/DynamoDBLocal.jar -dbPath {dbdir} -port {port}'.format( dynamodb_install_dir=config['dynamodblocal']['install_dir'], dbdir=config['dynamodblocal']['data_dir'], port=config['dynamodblocal']['port']) args = shlex.split(cmd) process = Popen(args, stdout=logfile, stderr=logfile) with open(pidpath, 'wt') as pidfile: pidfile.write(str(process.pid)) if not skip_check: click.echo('Checking for table.') client = boto3.client( 'dynamodb', endpoint_url='http://localhost:{}'.format(config['dynamodblocal']['port']), aws_access_key_id=config['dynamodblocal']['access_key_id'], aws_secret_access_key=config['dynamodblocal']['secret_access_key'], region_name='us-east-1') result = client.list_tables() if DYNAMODB_TABLE_NAME in result['TableNames']: click.echo("Table already exists. Skipping.") else: click.echo("Table not found, creating.") client.create_table( TableName=DYNAMODB_TABLE_NAME, AttributeDefinitions=[ {'AttributeName': 'authorization', 'AttributeType': 'S'} ], KeySchema=[ {'AttributeName': 'authorization', 'KeyType': 'HASH'}, ], ProvisionedThroughput={ 'ReadCapacityUnits': 5, 'WriteCapacityUnits': 5 } ) click.echo("Table created.") click.echo('Started server with PID {}.'.format(process.pid)) @dynamodb.command(name="stop") def dynamodb_stop(): pidfile = os.path.join(config['dynamodblocal']['log_dir'], 'dynamodb.pid') if not os.path.exists(pidfile): click.echo('No PIDFILE found. Aborting.') return with open(pidfile, 'rt') as pidfile_stream: pid = int(pidfile_stream.read().strip()) try: os.kill(pid, signal.SIGTERM) except ProcessLookupError: click.echo('No process found.') os.remove(pidfile) @dynamodb.command(name="reset") def dynamodb_reset(): client = boto3.client( 'dynamodb', endpoint_url='http://localhost:{}'.format(config['dynamodblocal']['port']), aws_access_key_id=config['dynamodblocal']['access_key_id'], aws_secret_access_key=config['dynamodblocal']['secret_access_key'], region_name='us-east-1') response = client.delete_table(TableName=DYNAMODB_TABLE_NAME) print(response) @dynamodb.command(name="scan") def dynamodb_scan(): client = boto3.client( 'dynamodb', endpoint_url='http://localhost:{}'.format(config['dynamodblocal']['port']), aws_access_key_id=config['dynamodblocal']['access_key_id'], aws_secret_access_key=config['dynamodblocal']['secret_access_key'], region_name='us-east-1') result = client.scan(TableName=DYNAMODB_TABLE_NAME) printer = pprint.PrettyPrinter() click.echo(printer.pformat(result)) @main.command(help="Show env vars for running a service") @click.argument("service", callback=load_service) def print_env(service): service.print_env() @main.command(name="redis_setup", help="Setup session token in redis") def redis_setup(): r = redis_lib.StrictRedis(host='localhost', port=6379, db=0) value = json.dumps(dict(user_id=config['grass']['user_id'], client_id=config['grass']['client_id'])) key = 'session:{}'.format(grass_session_token) r.set(key, value, ex=grass_expiration_time) @main.command(help="Run a service using owsdev config") @click.argument("service", callback=load_service) def run_service(service): service.run() if __name__ == "__main__": main()