diff --git a/client-cli/cli_lib/provisioner.py b/client-cli/cli_lib/provisioner.py index a089834e..108caf42 100644 --- a/client-cli/cli_lib/provisioner.py +++ b/client-cli/cli_lib/provisioner.py @@ -556,7 +556,7 @@ def profile_remove(config, name): return retvalue, response.json()['message'] -def vm_create(config, name, profile): +def vm_create(config, name, profile, wait_flag): """ Create a new VM named {name} with profile {profile} @@ -577,14 +577,18 @@ def vm_create(config, name, profile): if response.status_code == 202: retvalue = True - retdata = 'Task ID: {}'.format(response.json()['task_id']) + if not wait_flag: + retdata = 'Task ID: {}'.format(response.json()['task_id']) + else: + # Just return the task_id raw, instead of formatting it + retdata = response.json()['task_id'] else: retvalue = False retdata = response.json()['message'] return retvalue, retdata -def task_status(config, task_id): +def task_status(config, task_id, is_watching=False): """ Get information about provisioner job {task_id} @@ -602,6 +606,11 @@ def task_status(config, task_id): if response.status_code == 200: retvalue = True respjson = response.json() + + if is_watching: + # Just return the raw JSON to the watching process instead of formatting it + return respjson + job_state = respjson['state'] if job_state == 'RUNNING': retdata = 'Job state: RUNNING\nStage: {}/{}\nStatus: {}'.format( diff --git a/client-cli/pvc.py b/client-cli/pvc.py index bbeb45fb..260ef54e 100755 --- a/client-cli/pvc.py +++ b/client-cli/pvc.py @@ -27,6 +27,7 @@ import os import subprocess import difflib import re +import time import colorama import yaml import json @@ -2928,13 +2929,62 @@ def provisioner_profile_remove(name, confirm_flag): @click.argument( 'profile' ) -def provisioner_create(name, profile): +@click.option( + '-w', '--wait', 'wait_flag', + is_flag=True, default=False, + help='Wait for provisioning to complete, showing progress' +) +def provisioner_create(name, profile, wait_flag): """ Create a new VM NAME with profile PROFILE. """ - retcode, retdata = pvc_provisioner.vm_create(config, name, profile) - cleanup(retcode, retdata) + retcode, retdata = pvc_provisioner.vm_create(config, name, profile, wait_flag) + if retcode and wait_flag: + task_id = retdata + + click.echo("Task ID: {}".format(task_id)) + click.echo() + + # Wait for the task to start + click.echo("Waiting for task to start...", nl=False) + while True: + time.sleep(1) + task_status = pvc_provisioner.task_status(config, task_id, is_watching=True) + if task_status.get('state') != 'PENDING': + break + click.echo(".", nl=False) + click.echo(" done.") + click.echo() + + # Start following the task state, updating progress as we go + with click.progressbar(length=task_status.get('total'), show_eta=False) as bar: + last_task = 0 + maxlen = 0 + while True: + time.sleep(1) + if task_status.get('state') != 'RUNNING': + if task_status.get('state') == 'COMPLETED': + time.sleep(1) + bar.update(1) + break + if task_status.get('current') > last_task: + current_task = int(task_status.get('current')) + bar.update(current_task - last_task) + last_task = current_task + # The extensive spaces at the end cause this to overwrite longer previous messages + curlen = len(str(task_status.get('status'))) + if curlen > maxlen: + maxlen = curlen + lendiff = maxlen - curlen + overwrite_whitespace = " " * lendiff + click.echo(" " + task_status.get('status') + overwrite_whitespace, nl=False) + task_status = pvc_provisioner.task_status(config, task_id, is_watching=True) + + click.echo() + retdata = task_status.get('state') + ": " + task_status.get('status') + + cleanup(retcode, retdata) ############################################################################### # pvc provisioner status