diff --git a/ckan_cloud_operator/providers/ckan/instance/cli.py b/ckan_cloud_operator/providers/ckan/instance/cli.py index 9a7365a..38a1bbe 100644 --- a/ckan_cloud_operator/providers/ckan/instance/cli.py +++ b/ckan_cloud_operator/providers/ckan/instance/cli.py @@ -149,18 +149,17 @@ def delete(instance_id_or_name, no_dry_run): @instance.command('logs') -@click.option('--service', help='Service name. One of `ckan`, `giftless`, `jobs`, `jobs-db`, `redis`. Defaults to `ckan`') +@click.argument('INSTANCE_ID') +@click.option('--service', help='Service name. One of `ckan`, `giftless`, `jobs`, `jobs-db`, `redis`. Defaults to `ckan`', default='ckan') @click.option('--since', help='Only return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to all logs.') @click.option('--follow', help='Specify if the logs should be streamed.') @click.option('--tail', help='Lines of recent log file to display. Defaults to -1 with no selector, showing all log lines otherwise 10, if a selector is provided.') @click.option('--container', help='Conainer name if multiple') -@click.option('--grep', help='Filter logs by the given word (case insensitive)') -def ckan_logs(command): +def ckan_logs(instance_id, **kubectl_args): ''' Check CKAN and other service container logs ''' - pass - + manager.get_container_logs(instance_id, **kubectl_args) @instance.command('ckan-exec') @click.argument('INSTANCE_ID') @@ -181,13 +180,14 @@ def ckan_exec(instance_id, command, use_paster): @instance.command('ssh') -@click.option('--service', help='Service name. One of `ckan`, `giftless`, `jobs`, `jobs-db`, `redis`. Defaults to `ckan`') -@click.option('--command', help='One of `bash`, `sh`. Defaults to `bash`') -def ckan_ssh(service, command): +@click.argument('INSTANCE_ID') +@click.option('--service', help='Service name. One of `ckan`, `giftless`, `jobs`, `jobs-db`, `redis`. Defaults to `ckan`', default='ckan') +@click.option('--command', help='One of `bash`, `sh`. Defaults to `bash`', default='bash') +def ckan_ssh(instance_id, service, command): ''' SSH into the running container. ''' - pass + manager.ssh_into_container(instance_id, service, command) @instance.command('shell') diff --git a/ckan_cloud_operator/providers/ckan/instance/manager.py b/ckan_cloud_operator/providers/ckan/instance/manager.py index 5d771ee..65fb9ba 100644 --- a/ckan_cloud_operator/providers/ckan/instance/manager.py +++ b/ckan_cloud_operator/providers/ckan/instance/manager.py @@ -437,11 +437,25 @@ def run_ckan_commands(instance_id_or_name, command, dry_run=False, use_paster=Fa logs.info(str(line)) -def _get_running_pod_name(instance_id): +def get_container_logs(instance_id, **kubectl_args): + service = kubectl_args.pop('service') + pod_name = _get_running_pod_name(instance_id, service=service) + stream_logs = '-f ' if kubectl_args.pop('follow', None) else '' + k_args = [f'--{k}={v}' for k,v in kubectl_args.items() if v is not None] + full_args = stream_logs + ' '.join(k_args) + _stream_logs(f'kubectl -n {instance_id} logs {pod_name} {full_args}') + + +def ssh_into_container(instance_id, service, command): + pod_name = _get_running_pod_name(instance_id, service=service) + subprocess.run(f'kubectl -n {instance_id} exec -it {pod_name} {command}', shell=True) + + +def _get_running_pod_name(instance_id, service='ckan'): pod_name = None while not pod_name: try: - pod_name = kubectl.get_deployment_pod_name('ckan', instance_id, use_first_pod=True, required_phase='Running') + pod_name = kubectl.get_deployment_pod_name(service, instance_id, use_first_pod=True, required_phase='Running') break except Exception as e: logs.warning('Failed to find running ckan pod', str(e)) @@ -484,3 +498,9 @@ def _get_instance_id_and_type(instance_id_or_name=None, instance_id=None, requir def _generate_password(length): return binascii.hexlify(os.urandom(length)).decode() + + +def _stream_logs(command): + process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True) + for c in iter(lambda: process.stdout.read(1), b''): + sys.stdout.buffer.write(c)