From a1ba9d2eeb96decfd2401e5e96ac3cd067a7651e Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Wed, 8 Jul 2020 13:18:12 -0400 Subject: [PATCH] Allow specifying arbitrary script_args on CLI Allow the specifying of arbitrary provisioner script install() args on the provisioner create CLI, either overriding or adding additional per-VM arguments to those found in the profile. Reference example is setting a "vm_fqdn" on a per-run basis. Closes #100 --- api-daemon/pvcapid/flaskapi.py | 15 +++++++++++---- api-daemon/pvcapid/provisioner.py | 9 ++++++++- client-cli/cli_lib/provisioner.py | 7 ++++--- client-cli/pvc.py | 12 ++++++++++-- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/api-daemon/pvcapid/flaskapi.py b/api-daemon/pvcapid/flaskapi.py index e64c69c8..96010df2 100755 --- a/api-daemon/pvcapid/flaskapi.py +++ b/api-daemon/pvcapid/flaskapi.py @@ -195,8 +195,9 @@ def Authenticator(function): # Job functions # @celery.task(bind=True) -def create_vm(self, vm_name, profile_name, define_vm=True, start_vm=True): - return api_provisioner.create_vm(self, vm_name, profile_name, define_vm=define_vm, start_vm=start_vm) +def create_vm(self, vm_name, profile_name, define_vm=True, start_vm=True, script_run_args=[]): + print(script_run_args) + return api_provisioner.create_vm(self, vm_name, profile_name, define_vm=define_vm, start_vm=start_vm, script_run_args=script_run_args) ########################################################## @@ -5974,7 +5975,8 @@ class API_Provisioner_Create_Root(Resource): { 'name': 'name', 'required': True, 'helpmsg': "A VM name must be specified." }, { 'name': 'profile', 'required': True, 'helpmsg': "A profile name must be specified." }, { 'name': 'define_vm' }, - { 'name': 'start_vm' } + { 'name': 'start_vm' }, + { 'name': 'arg', 'action': 'append' } ]) @Authenticator def post(self, reqargs): @@ -6005,6 +6007,10 @@ class API_Provisioner_Create_Root(Resource): type: boolean required: false description: Whether to start the VM after provisioning + - in: query + name: arg + type: string + description: Script install() function keywork argument in "arg=data" format; may be specified multiple times to add multiple arguments responses: 200: description: OK @@ -6039,7 +6045,8 @@ class API_Provisioner_Create_Root(Resource): reqargs.get('name', None), reqargs.get('profile', None), define_vm=define_vm, - start_vm=start_vm + start_vm=start_vm, + script_run_args=reqargs.get('arg', []), ) return { "task_id": task.id }, 202, { 'Location': Api.url_for(api, API_Provisioner_Status_Element, task_id=task.id) } api.add_resource(API_Provisioner_Create_Root, '/provisioner/create') diff --git a/api-daemon/pvcapid/provisioner.py b/api-daemon/pvcapid/provisioner.py index 2ab7af24..5ed4a3c9 100755 --- a/api-daemon/pvcapid/provisioner.py +++ b/api-daemon/pvcapid/provisioner.py @@ -1026,7 +1026,7 @@ def delete_profile(name): # # Main VM provisioning function - executed by the Celery worker # -def create_vm(self, vm_name, vm_profile, define_vm=True, start_vm=True): +def create_vm(self, vm_name, vm_profile, define_vm=True, start_vm=True, script_run_args=[]): # Runtime imports import time import importlib @@ -1542,6 +1542,13 @@ def create_vm(self, vm_name, vm_profile, define_vm=True, start_vm=True): argument_name, argument_data = argument.split('=') script_arguments[argument_name] = argument_data + # Parse the runtime arguments + for argument in script_run_args: + argument_name, argument_data = argument.split('=') + script_arguments[argument_name] = argument_data + + print("Script arguments: {}".format(script_arguments)) + # Run the script try: installer_script.install( diff --git a/client-cli/cli_lib/provisioner.py b/client-cli/cli_lib/provisioner.py index bbd6847f..6b8bd9d3 100644 --- a/client-cli/cli_lib/provisioner.py +++ b/client-cli/cli_lib/provisioner.py @@ -557,19 +557,20 @@ def profile_remove(config, name): return retvalue, response.json()['message'] -def vm_create(config, name, profile, wait_flag, define_flag, start_flag): +def vm_create(config, name, profile, wait_flag, define_flag, start_flag, script_args): """ Create a new VM named {name} with profile {profile} API endpoint: POST /api/v1/provisioner/create - API_arguments: name={name}, profile={profile} + API_arguments: name={name}, profile={profile}, arg={script_args} API schema: {message} """ params = { 'name': name, 'profile': profile, 'start_vm': start_flag, - 'define_vm': define_flag + 'define_vm': define_flag, + 'arg': script_args } response = call_api(config, 'post', '/provisioner/create', params=params) diff --git a/client-cli/pvc.py b/client-cli/pvc.py index 5b07c473..77e1bbdf 100755 --- a/client-cli/pvc.py +++ b/client-cli/pvc.py @@ -3316,6 +3316,11 @@ def provisioner_profile_remove(name, confirm_flag): @click.argument( 'profile' ) +@click.option( + '-a', '--script-arg', 'script_args', + default=[], multiple=True, + help='Additional argument to the script install() function in key=value format.' +) @click.option( '-d/-D', '--define/--no-define', 'define_flag', is_flag=True, default=True, show_default=True, @@ -3332,7 +3337,7 @@ def provisioner_profile_remove(name, confirm_flag): help='Wait for provisioning to complete, showing progress' ) @cluster_req -def provisioner_create(name, profile, wait_flag, define_flag, start_flag): +def provisioner_create(name, profile, wait_flag, define_flag, start_flag, script_args): """ Create a new VM NAME with profile PROFILE. @@ -3345,11 +3350,14 @@ def provisioner_create(name, profile, wait_flag, define_flag, start_flag): created VM on the PVC cluster. This can be useful for the administrator to create a "template" set of VM disks via the normal provisioner, but without ever starting the resulting VM. The resulting disk(s) can then be used as source volumes in other disk templates. + + The "--script-arg" option can be specified as many times as required to pass additional, + VM-specific arguments to the provisioner install() function, beyond those set by the profile. """ if not define_flag: start_flag = False - retcode, retdata = pvc_provisioner.vm_create(config, name, profile, wait_flag, define_flag, start_flag) + retcode, retdata = pvc_provisioner.vm_create(config, name, profile, wait_flag, define_flag, start_flag, script_args) if retcode and wait_flag: task_id = retdata