diff --git a/client-cli/cli_lib/provisioner.py b/client-cli/cli_lib/provisioner.py index 2210a0f0..92a58af8 100644 --- a/client-cli/cli_lib/provisioner.py +++ b/client-cli/cli_lib/provisioner.py @@ -226,7 +226,7 @@ def userdata_list(config, limit): """ Get list information about userdatas (limited by {limit}) - API endpoint: GET /api/v1/provisioner/userdata/{userdata_type} + API endpoint: GET /api/v1/provisioner/userdata API arguments: limit={limit} API schema: [{json_data_object},{json_data_object},etc.] """ @@ -354,7 +354,7 @@ def script_list(config, limit): """ Get list information about scripts (limited by {limit}) - API endpoint: GET /api/v1/provisioner/script/{script_type} + API endpoint: GET /api/v1/provisioner/script API arguments: limit={limit} API schema: [{json_data_object},{json_data_object},etc.] """ @@ -455,10 +455,161 @@ def script_remove(config, name): return retvalue, response.json()['message'] +def profile_info(config, profile): + """ + Get information about profile + + API endpoint: GET /api/v1/provisioner/profile/{profile} + API arguments: + API schema: {json_data_object} + """ + request_uri = get_request_uri(config, '/provisioner/profile/{profile}'.format(profile=profile)) + response = requests.get( + request_uri + ) + + if config['debug']: + print('API endpoint: GET {}'.format(request_uri)) + print('Response code: {}'.format(response.status_code)) + print('Response headers: {}'.format(response.headers)) + + if response.status_code == 200: + return True, response.json()[0] + else: + return False, response.json()['message'] + +def profile_list(config, limit): + """ + Get list information about profiles (limited by {limit}) + + API endpoint: GET /api/v1/provisioner/profile/{profile_type} + API arguments: limit={limit} + API schema: [{json_data_object},{json_data_object},etc.] + """ + params = dict() + if limit: + params['limit'] = limit + + request_uri = get_request_uri(config, '/provisioner/profile') + response = requests.get( + request_uri, + params=params + ) + + if config['debug']: + print('API endpoint: GET {}'.format(request_uri)) + print('Response code: {}'.format(response.status_code)) + print('Response headers: {}'.format(response.headers)) + + if response.status_code == 200: + return True, response.json() + else: + return False, response.json()['message'] + +def profile_add(config, params): + """ + Add a new profile with {params} + + API endpoint: POST /api/v1/provisioner/profile + API_arguments: args + API schema: {message} + """ + request_uri = get_request_uri(config, '/provisioner/profile') + response = requests.post( + request_uri, + params=params + ) + + if config['debug']: + print('API endpoint: POST {}'.format(request_uri)) + print('Response code: {}'.format(response.status_code)) + print('Response headers: {}'.format(response.headers)) + + if response.status_code == 200: + retvalue = True + else: + retvalue = False + + return retvalue, response.json()['message'] + +def profile_modify(config, name, params): + """ + Modify profile {name} with {params} + + API endpoint: PUT /api/v1/provisioner/profile/{name} + API_arguments: args + API schema: {message} + """ + request_uri = get_request_uri(config, '/provisioner/profile/{name}'.format(name=name)) + response = requests.put( + request_uri, + params=params + ) + + if config['debug']: + print('API endpoint: PUT {}'.format(request_uri)) + print('Response code: {}'.format(response.status_code)) + print('Response headers: {}'.format(response.headers)) + + if response.status_code == 200: + retvalue = True + else: + retvalue = False + + return retvalue, response.json()['message'] + +def profile_remove(config, name): + """ + Remove profile {name} + + API endpoint: DELETE /api/v1/provisioner/profile/{name} + API_arguments: + API schema: {message} + """ + request_uri = get_request_uri(config, '/provisioner/profile/{name}'.format(name=name)) + response = requests.delete( + request_uri + ) + + if config['debug']: + print('API endpoint: DELETE {}'.format(request_uri)) + print('Response code: {}'.format(response.status_code)) + print('Response headers: {}'.format(response.headers)) + + if response.status_code == 200: + retvalue = True + else: + retvalue = False + + return retvalue, response.json()['message'] + +def profile_info(config, profile): + """ + Get information about profile + + API endpoint: GET /api/v1/provisioner/profile/{profile} + API arguments: + API schema: {json_data_object} + """ + request_uri = get_request_uri(config, '/provisioner/profile/{profile}'.format(profile=profile)) + response = requests.get( + request_uri + ) + + if config['debug']: + print('API endpoint: GET {}'.format(request_uri)) + print('Response code: {}'.format(response.status_code)) + print('Response headers: {}'.format(response.headers)) + + if response.status_code == 200: + return True, response.json()[0] + else: + return False, response.json()['message'] + # # Format functions # -def format_list_template(template_template, template_type=None): +def format_list_template(template_data, template_type=None): """ Format the returned template template @@ -466,43 +617,43 @@ def format_list_template(template_template, template_type=None): reuse with more limited output options. """ template_types = [ 'system', 'network', 'storage' ] - normalized_template_template = dict() + normalized_template_data = dict() if template_type in template_types: template_types = [ template_type ] - template_template_type = '{}_templates'.format(template_type) - normalized_template_template[template_template_type] = template_template + template_data_type = '{}_templates'.format(template_type) + normalized_template_data[template_data_type] = template_data else: - normalized_template_template = template_template + normalized_template_data = template_data if 'system' in template_types: click.echo('System templates:') click.echo() - format_list_template_system(normalized_template_template['system_templates']) + format_list_template_system(normalized_template_data['system_templates']) if len(template_types) > 1: click.echo() if 'network' in template_types: click.echo('Network templates:') click.echo() - format_list_template_network(normalized_template_template['network_templates']) + format_list_template_network(normalized_template_data['network_templates']) if len(template_types) > 1: click.echo() if 'storage' in template_types: click.echo('Storage templates:') click.echo() - format_list_template_storage(normalized_template_template['storage_templates']) + format_list_template_storage(normalized_template_data['storage_templates']) -def format_list_template_system(template_template): - if isinstance(template_template, dict): - template_template = [ template_template ] +def format_list_template_system(template_data): + if isinstance(template_data, dict): + template_data = [ template_data ] template_list_output = [] # Determine optimal column widths template_name_length = 5 - template_id_length = 4 + template_id_length = 3 template_vcpu_length = 6 template_vram_length = 10 template_serial_length = 7 @@ -512,7 +663,7 @@ def format_list_template_system(template_template): template_node_selector_length = 11 template_node_autostart_length = 11 - for template in template_template: + for template in template_data: # template_name column _template_name_length = len(str(template['name'])) + 1 if _template_name_length > template_name_length: @@ -594,7 +745,7 @@ Metatemplate: {template_node_limit: <{template_node_limit_length}} \ valid_net_list = [] # Format the string (elements) - for template in sorted(template_template, key=lambda i: i.get('name', None)): + for template in sorted(template_data, key=lambda i: i.get('name', None)): template_list_output.append( '{bold}{template_name: <{template_name_length}} {template_id: <{template_id_length}} \ {template_vcpu: <{template_vcpu_length}} \ @@ -642,7 +793,7 @@ def format_list_template_network(template_template): # Determine optimal column widths template_name_length = 5 - template_id_length = 4 + template_id_length = 3 template_mac_template_length = 13 template_networks_length = 10 @@ -718,7 +869,7 @@ def format_list_template_storage(template_template): # Determine optimal column widths template_name_length = 5 - template_id_length = 4 + template_id_length = 3 template_disk_id_length = 8 template_disk_pool_length = 8 template_disk_size_length = 10 @@ -842,157 +993,264 @@ def format_list_template_storage(template_template): return True, '' -def format_list_userdata(userdata, lines=None): - if isinstance(userdata, dict): - userdata = [ userdata ] +def format_list_userdata(userdata_data, lines=None): + if isinstance(userdata_data, dict): + userdata_data = [ userdata_data ] - data_list_output = [] + userdata_list_output = [] # Determine optimal column widths - data_name_length = 5 - data_id_length = 4 - data_userdata_length = 8 + userdata_name_length = 5 + userdata_id_length = 3 + userdata_useruserdata_length = 8 - for data in userdata: - # data_name column - _data_name_length = len(str(data['name'])) + 1 - if _data_name_length > data_name_length: - data_name_length = _data_name_length - # data_id column - _data_id_length = len(str(data['id'])) + 1 - if _data_id_length > data_id_length: - data_id_length = _data_id_length + for userdata in userdata_data: + # userdata_name column + _userdata_name_length = len(str(userdata['name'])) + 1 + if _userdata_name_length > userdata_name_length: + userdata_name_length = _userdata_name_length + # userdata_id column + _userdata_id_length = len(str(userdata['id'])) + 1 + if _userdata_id_length > userdata_id_length: + userdata_id_length = _userdata_id_length # Format the string (header) - data_list_output_header = '{bold}{data_name: <{data_name_length}} {data_id: <{data_id_length}} \ -{data_userdata}{end_bold}'.format( - data_name_length=data_name_length, - data_id_length=data_id_length, + userdata_list_output_header = '{bold}{userdata_name: <{userdata_name_length}} {userdata_id: <{userdata_id_length}} \ +{userdata_data}{end_bold}'.format( + userdata_name_length=userdata_name_length, + userdata_id_length=userdata_id_length, bold=ansiprint.bold(), end_bold=ansiprint.end(), - data_name='Name', - data_id='ID', - data_userdata='Document' + userdata_name='Name', + userdata_id='ID', + userdata_data='Document' ) # Format the string (elements) - for data in sorted(userdata, key=lambda i: i.get('name', None)): + for data in sorted(userdata_data, key=lambda i: i.get('name', None)): line_count = 0 for line in data['userdata'].split('\n'): if line_count < 1: - data_name = data['name'] - data_id = data['id'] + userdata_name = data['name'] + userdata_id = data['id'] else: - data_name = '' - data_id = '' + userdata_name = '' + userdata_id = '' line_count += 1 if lines and line_count > lines: - data_list_output.append( - '{bold}{data_name: <{data_name_length}} {data_id: <{data_id_length}} \ -{data_script}{end_bold}'.format( - data_name_length=data_name_length, - data_id_length=data_id_length, + userdata_list_output.append( + '{bold}{userdata_name: <{userdata_name_length}} {userdata_id: <{userdata_id_length}} \ +{userdata_data}{end_bold}'.format( + userdata_name_length=userdata_name_length, + userdata_id_length=userdata_id_length, bold='', end_bold='', - data_name=data_name, - data_id=data_id, - data_script='[...]' + userdata_name=userdata_name, + userdata_id=userdata_id, + userdata_data='[...]' ) ) break - data_list_output.append( - '{bold}{data_name: <{data_name_length}} {data_id: <{data_id_length}} \ -{data_userdata}{end_bold}'.format( - data_name_length=data_name_length, - data_id_length=data_id_length, + userdata_list_output.append( + '{bold}{userdata_name: <{userdata_name_length}} {userdata_id: <{userdata_id_length}} \ +{userdata_data}{end_bold}'.format( + userdata_name_length=userdata_name_length, + userdata_id_length=userdata_id_length, bold='', end_bold='', - data_name=data_name, - data_id=data_id, - data_userdata=str(line) + userdata_name=userdata_name, + userdata_id=userdata_id, + userdata_data=str(line) ) ) - click.echo('\n'.join([data_list_output_header] + data_list_output)) + click.echo('\n'.join([userdata_list_output_header] + userdata_list_output)) return True, '' -def format_list_script(script, lines=None): - if isinstance(script, dict): - script = [ script ] +def format_list_script(script_data, lines=None): + if isinstance(script_data, dict): + script_data = [ script_data ] - data_list_output = [] + script_list_output = [] # Determine optimal column widths - data_name_length = 5 - data_id_length = 4 - data_script_length = 8 + script_name_length = 5 + script_id_length = 3 + script_script_length = 8 - for data in script: - # data_name column - _data_name_length = len(str(data['name'])) + 1 - if _data_name_length > data_name_length: - data_name_length = _data_name_length - # data_id column - _data_id_length = len(str(data['id'])) + 1 - if _data_id_length > data_id_length: - data_id_length = _data_id_length + for script in script_data: + # script_name column + _script_name_length = len(str(script['name'])) + 1 + if _script_name_length > script_name_length: + script_name_length = _script_name_length + # script_id column + _script_id_length = len(str(script['id'])) + 1 + if _script_id_length > script_id_length: + script_id_length = _script_id_length # Format the string (header) - data_list_output_header = '{bold}{data_name: <{data_name_length}} {data_id: <{data_id_length}} \ -{data_script}{end_bold}'.format( - data_name_length=data_name_length, - data_id_length=data_id_length, + script_list_output_header = '{bold}{script_name: <{script_name_length}} {script_id: <{script_id_length}} \ +{script_data}{end_bold}'.format( + script_name_length=script_name_length, + script_id_length=script_id_length, bold=ansiprint.bold(), end_bold=ansiprint.end(), - data_name='Name', - data_id='ID', - data_script='Script' + script_name='Name', + script_id='ID', + script_data='Script' ) # Format the string (elements) - for data in sorted(script, key=lambda i: i.get('name', None)): + for script in sorted(script_data, key=lambda i: i.get('name', None)): line_count = 0 - for line in data['script'].split('\n'): + for line in script['script'].split('\n'): if line_count < 1: - data_name = data['name'] - data_id = data['id'] + script_name = script['name'] + script_id = script['id'] else: - data_name = '' - data_id = '' + script_name = '' + script_id = '' line_count += 1 if lines and line_count > lines: - data_list_output.append( - '{bold}{data_name: <{data_name_length}} {data_id: <{data_id_length}} \ -{data_script}{end_bold}'.format( - data_name_length=data_name_length, - data_id_length=data_id_length, + script_list_output.append( + '{bold}{script_name: <{script_name_length}} {script_id: <{script_id_length}} \ +{script_data}{end_bold}'.format( + script_name_length=script_name_length, + script_id_length=script_id_length, bold='', end_bold='', - data_name=data_name, - data_id=data_id, - data_script='[...]' + script_name=script_name, + script_id=script_id, + script_data='[...]' ) ) break - data_list_output.append( - '{bold}{data_name: <{data_name_length}} {data_id: <{data_id_length}} \ -{data_script}{end_bold}'.format( - data_name_length=data_name_length, - data_id_length=data_id_length, + script_list_output.append( + '{bold}{script_name: <{script_name_length}} {script_id: <{script_id_length}} \ +{script_data}{end_bold}'.format( + script_name_length=script_name_length, + script_id_length=script_id_length, bold='', end_bold='', - data_name=data_name, - data_id=data_id, - data_script=str(line) + script_name=script_name, + script_id=script_id, + script_data=str(line) ) ) - click.echo('\n'.join([data_list_output_header] + data_list_output)) + click.echo('\n'.join([script_list_output_header] + script_list_output)) + + return True, '' + +def format_list_profile(profile_data): + if isinstance(profile_data, dict): + profile_data = [ profile_data ] + + profile_list_output = [] + + # Determine optimal column widths + profile_name_length = 5 + profile_id_length = 3 + + profile_system_template_length = 7 + profile_network_template_length = 8 + profile_storage_template_length = 8 + profile_userdata_length = 9 + profile_script_length = 7 + + for profile in profile_data: + # profile_name column + _profile_name_length = len(str(profile['name'])) + 1 + if _profile_name_length > profile_name_length: + profile_name_length = _profile_name_length + # profile_id column + _profile_id_length = len(str(profile['id'])) + 1 + if _profile_id_length > profile_id_length: + profile_id_length = _profile_id_length + # profile_system_template column + _profile_system_template_length = len(str(profile['system_template'])) + 1 + if _profile_system_template_length > profile_system_template_length: + profile_system_template_length = _profile_system_template_length + # profile_network_template column + _profile_network_template_length = len(str(profile['network_template'])) + 1 + if _profile_network_template_length > profile_network_template_length: + profile_network_template_length = _profile_network_template_length + # profile_storage_template column + _profile_storage_template_length = len(str(profile['storage_template'])) + 1 + if _profile_storage_template_length > profile_storage_template_length: + profile_storage_template_length = _profile_storage_template_length + # profile_userdata column + _profile_userdata_length = len(str(profile['userdata'])) + 1 + if _profile_userdata_length > profile_userdata_length: + profile_userdata_length = _profile_userdata_length + # profile_script column + _profile_script_length = len(str(profile['script'])) + 1 + if _profile_script_length > profile_script_length: + profile_script_length = _profile_script_length + + # Format the string (header) + profile_list_output_header = '{bold}{profile_name: <{profile_name_length}} {profile_id: <{profile_id_length}} \ +Templates: {profile_system_template: <{profile_system_template_length}} \ +{profile_network_template: <{profile_network_template_length}} \ +{profile_storage_template: <{profile_storage_template_length}} \ +Data: {profile_userdata: <{profile_userdata_length}} \ +{profile_script: <{profile_script_length}} \ +{profile_arguments}{end_bold}'.format( + profile_name_length=profile_name_length, + profile_id_length=profile_id_length, + profile_system_template_length=profile_system_template_length, + profile_network_template_length=profile_network_template_length, + profile_storage_template_length=profile_storage_template_length, + profile_userdata_length=profile_userdata_length, + profile_script_length=profile_script_length, + bold=ansiprint.bold(), + end_bold=ansiprint.end(), + profile_name='Name', + profile_id='ID', + profile_system_template='System', + profile_network_template='Network', + profile_storage_template='Storage', + profile_userdata='Userdata', + profile_script='Script', + profile_arguments='Script Arguments' + ) + + # Format the string (elements) + for profile in sorted(profile_data, key=lambda i: i.get('name', None)): + profile_list_output.append( + '{bold}{profile_name: <{profile_name_length}} {profile_id: <{profile_id_length}} \ + {profile_system_template: <{profile_system_template_length}} \ +{profile_network_template: <{profile_network_template_length}} \ +{profile_storage_template: <{profile_storage_template_length}} \ + {profile_userdata: <{profile_userdata_length}} \ +{profile_script: <{profile_script_length}} \ +{profile_arguments}{end_bold}'.format( + profile_name_length=profile_name_length, + profile_id_length=profile_id_length, + profile_system_template_length=profile_system_template_length, + profile_network_template_length=profile_network_template_length, + profile_storage_template_length=profile_storage_template_length, + profile_userdata_length=profile_userdata_length, + profile_script_length=profile_script_length, + bold='', + end_bold='', + profile_name=profile['name'], + profile_id=profile['id'], + profile_system_template=profile['system_template'], + profile_network_template=profile['network_template'], + profile_storage_template=profile['storage_template'], + profile_userdata=profile['userdata'], + profile_script=profile['script'], + profile_arguments=', '.join(profile['arguments']) + ) + ) + + click.echo('\n'.join([profile_list_output_header] + profile_list_output)) return True, '' diff --git a/client-cli/pvc.py b/client-cli/pvc.py index df938a20..f323739b 100755 --- a/client-cli/pvc.py +++ b/client-cli/pvc.py @@ -418,7 +418,7 @@ def node_info(node, long_output): ) def node_list(limit): """ - List all nodes in the cluster; optionally only match names matching regex LIMIT. + List all nodes; optionally only match names matching regex LIMIT. """ retcode, retdata = pvc_node.node_list(config, limit) @@ -534,7 +534,7 @@ def vm_modify(domain, cfgfile, editor, restart): retcode, vm_information = pvc_vm.vm_info(config, domain) if not retcode and not vm_information.get('name', None): - cleanup(False, 'ERROR: Could not find VM "{}" in the cluster!'.format(domain)) + cleanup(False, 'ERROR: Could not find VM "{}"!'.format(domain)) dom_uuid = vm_information.get('uuid') dom_name = vm_information.get('name') @@ -612,7 +612,7 @@ def vm_modify(domain, cfgfile, editor, restart): ) def vm_undefine(domain): """ - Stop virtual machine DOMAIN and remove it from the cluster database, preserving disks. DOMAIN may be a UUID or name. + Stop virtual machine DOMAIN and remove it database, preserving disks. DOMAIN may be a UUID or name. """ retcode, retmsg = pvc_vm.vm_remove(config, domain, delete_disks=False) @@ -627,7 +627,7 @@ def vm_undefine(domain): ) def vm_remove(domain): """ - Stop virtual machine DOMAIN and remove it, along with all disks, from the cluster. DOMAIN may be a UUID or name. + Stop virtual machine DOMAIN and remove it, along with all disks,. DOMAIN may be a UUID or name. """ retcode, retmsg = pvc_vm.vm_remove(config, domain, delete_disks=True) @@ -844,7 +844,7 @@ def vm_dump(domain): retcode, vm_information = pvc_vm.vm_info(config, domain) if not retcode and not vm_information.get('name', None): - cleanup(False, 'ERROR: Could not find VM "{}" in the cluster!'.format(domain)) + cleanup(False, 'ERROR: Could not find VM "{}"!'.format(domain)) # Grab the current config current_vm_cfg_raw = vm_information.get('xml') @@ -873,7 +873,7 @@ def vm_dump(domain): ) def vm_list(target_node, target_state, limit, raw): """ - List all virtual machines in the cluster; optionally only match names matching regex LIMIT. + List all virtual machines; optionally only match names matching regex LIMIT. NOTE: Red-coloured network lists indicate one or more configured networks are missing/invalid. """ @@ -899,7 +899,7 @@ def cli_network(): ############################################################################### # pvc network add ############################################################################### -@click.command(name='add', short_help='Add a new virtual network to the cluster.') +@click.command(name='add', short_help='Add a new virtual network.') @click.option( '-d', '--description', 'description', required=True, @@ -962,7 +962,7 @@ def cli_network(): ) def net_add(vni, description, nettype, domain, ip_network, ip_gateway, ip6_network, ip6_gateway, dhcp_flag, dhcp_start, dhcp_end, name_servers): """ - Add a new virtual network with VXLAN identifier VNI to the cluster. + Add a new virtual network with VXLAN identifier VNI. Examples: @@ -1056,13 +1056,13 @@ def net_modify(vni, description, domain, name_servers, ip6_network, ip6_gateway, ############################################################################### # pvc network remove ############################################################################### -@click.command(name='remove', short_help='Remove a virtual network from the cluster.') +@click.command(name='remove', short_help='Remove a virtual network.') @click.argument( 'net' ) def net_remove(net): """ - Remove an existing virtual network NET from the cluster; NET must be a VNI. + Remove an existing virtual network NET; NET must be a VNI. WARNING: PVC does not verify whether clients are still present in this network. Before removing, ensure that all client VMs have been removed from the network or undefined behaviour may occur. @@ -1102,7 +1102,7 @@ def net_info(vni, long_output): ) def net_list(limit): """ - List all virtual networks in the cluster; optionally only match VNIs or Descriptions matching regex LIMIT. + List all virtual networks; optionally only match VNIs or Descriptions matching regex LIMIT. """ retcode, retdata = pvc_network.net_list(config, limit) @@ -1399,7 +1399,7 @@ def ceph_osd(): ) def ceph_osd_add(node, device, weight, yes): """ - Add a new Ceph OSD on node NODE with block device DEVICE to the cluster. + Add a new Ceph OSD on node NODE with block device DEVICE. """ if not yes: @@ -1425,7 +1425,7 @@ def ceph_osd_add(node, device, weight, yes): ) def ceph_osd_remove(osdid, yes): """ - Remove a Ceph OSD with ID OSDID from the cluster. + Remove a Ceph OSD with ID OSDID. """ if not yes: @@ -1446,7 +1446,7 @@ def ceph_osd_remove(osdid, yes): ) def ceph_osd_in(osdid): """ - Set a Ceph OSD with ID OSDID online in the cluster. + Set a Ceph OSD with ID OSDID online. """ retcode, retmsg = pvc_ceph.ceph_osd_state(config, osdid, 'in') @@ -1461,7 +1461,7 @@ def ceph_osd_in(osdid): ) def ceph_osd_out(osdid): """ - Set a Ceph OSD with ID OSDID offline in the cluster. + Set a Ceph OSD with ID OSDID offline. """ retcode, retmsg = pvc_ceph.ceph_osd_state(config, osdid, 'out') @@ -1514,7 +1514,7 @@ def ceph_osd_unset(osd_property): ) def ceph_osd_list(limit): """ - List all Ceph OSDs in the cluster; optionally only match elements matching ID regex LIMIT. + List all Ceph OSDs; optionally only match elements matching ID regex LIMIT. """ retcode, retdata = pvc_ceph.ceph_osd_list(config, limit) @@ -1599,7 +1599,7 @@ def ceph_pool_remove(name, yes): ) def ceph_pool_list(limit): """ - List all Ceph RBD pools in the cluster; optionally only match elements matching name regex LIMIT. + List all Ceph RBD pools; optionally only match elements matching name regex LIMIT. """ retcode, retdata = pvc_ceph.ceph_pool_list(config, limit) @@ -1744,7 +1744,7 @@ def ceph_volume_clone(pool, name, new_name): ) def ceph_volume_list(limit, pool): """ - List all Ceph RBD volumes in the cluster; optionally only match elements matching name regex LIMIT. + List all Ceph RBD volumes; optionally only match elements matching name regex LIMIT. """ retcode, retdata = pvc_ceph.ceph_volume_list(config, limit, pool) @@ -1898,7 +1898,7 @@ def provisioner_template(): ############################################################################### # pvc provisioner template list ############################################################################### -@click.command(name='list', short_help='List all templates in the cluster.') +@click.command(name='list', short_help='List all templates.') @click.argument( 'limit', default=None, required=False ) @@ -1927,7 +1927,7 @@ def provisioner_template_system(): ############################################################################### # pvc provisioner template system list ############################################################################### -@click.command(name='list', short_help='List all system templates in the cluster.') +@click.command(name='list', short_help='List all system templates.') @click.argument( 'limit', default=None, required=False ) @@ -1944,7 +1944,7 @@ def provisioner_template_system_list(limit): ############################################################################### # pvc provisioner template system add ############################################################################### -@click.command(name='add', short_help='Add new system template to the cluster.') +@click.command(name='add', short_help='Add new system template.') @click.argument( 'name' ) @@ -2014,7 +2014,7 @@ def provisioner_template_system_add(name, vcpus, vram, serial, vnc, vnc_bind, no ############################################################################### # pvc provisioner template system remove ############################################################################### -@click.command(name='remove', short_help='Remove system template from the cluster.') +@click.command(name='remove', short_help='Remove system template.') @click.argument( 'name' ) @@ -2041,7 +2041,7 @@ def provisioner_template_network(): ############################################################################### # pvc provisioner template network list ############################################################################### -@click.command(name='list', short_help='List all network templates in the cluster.') +@click.command(name='list', short_help='List all network templates.') @click.argument( 'limit', default=None, required=False ) @@ -2058,7 +2058,7 @@ def provisioner_template_network_list(limit): ############################################################################### # pvc provisioner template network add ############################################################################### -@click.command(name='add', short_help='Add new network template to the cluster.') +@click.command(name='add', short_help='Add new network template.') @click.argument( 'name' ) @@ -2107,7 +2107,7 @@ def provisioner_template_network_add(name, mac_template): ############################################################################### # pvc provisioner template network remove ############################################################################### -@click.command(name='remove', short_help='Remove network template from the cluster.') +@click.command(name='remove', short_help='Remove network template.') @click.argument( 'name' ) @@ -2184,7 +2184,7 @@ def provisioner_template_storage(): ############################################################################### # pvc provisioner template storage list ############################################################################### -@click.command(name='list', short_help='List all storage templates in the cluster.') +@click.command(name='list', short_help='List all storage templates.') @click.argument( 'limit', default=None, required=False ) @@ -2201,7 +2201,7 @@ def provisioner_template_storage_list(limit): ############################################################################### # pvc provisioner template storage add ############################################################################### -@click.command(name='add', short_help='Add new storage template to the cluster.') +@click.command(name='add', short_help='Add new storage template.') @click.argument( 'name' ) @@ -2218,7 +2218,7 @@ def provisioner_template_storage_add(name): ############################################################################### # pvc provisioner template storage remove ############################################################################### -@click.command(name='remove', short_help='Remove storage template from the cluster.') +@click.command(name='remove', short_help='Remove storage template.') @click.argument( 'name' ) @@ -2339,7 +2339,7 @@ def provisioner_userdata(): ############################################################################### # pvc provisioner userdata list ############################################################################### -@click.command(name='list', short_help='List all userdata documents in the cluster.') +@click.command(name='list', short_help='List all userdata documents.') @click.argument( 'limit', default=None, required=False ) @@ -2474,7 +2474,7 @@ def provisioner_userdata_modify(name, filename, editor): ############################################################################### # pvc provisioner userdata remove ############################################################################### -@click.command(name='remove', short_help='Remove userdata document from the cluster.') +@click.command(name='remove', short_help='Remove userdata document.') @click.argument( 'name' ) @@ -2501,7 +2501,7 @@ def provisioner_script(): ############################################################################### # pvc provisioner script list ############################################################################### -@click.command(name='list', short_help='List all scripts in the cluster.') +@click.command(name='list', short_help='List all scripts.') @click.argument( 'limit', default=None, required=False ) @@ -2636,7 +2636,7 @@ def provisioner_script_modify(name, filename, editor): ############################################################################### # pvc provisioner script remove ############################################################################### -@click.command(name='remove', short_help='Remove script from the cluster.') +@click.command(name='remove', short_help='Remove script.') @click.argument( 'name' ) @@ -2648,6 +2648,167 @@ def provisioner_script_remove(name): cleanup(retcode, retdata) +############################################################################### +# pvc provisioner profile +############################################################################### +@click.group(name='profile', short_help='Manage PVC provisioner profiless.', context_settings=CONTEXT_SETTINGS) +def provisioner_profile(): + """ + Manage profiles in the PVC provisioner. + """ + # Abort commands under this group if config is bad + if config.get('badcfg', None): + exit(1) + +############################################################################### +# pvc provisioner profile list +############################################################################### +@click.command(name='list', short_help='List all profiles.') +@click.argument( + 'limit', default=None, required=False +) +def provisioner_profile_list(limit): + """ + List all profiles in the PVC cluster provisioner. + """ + retcode, retdata = pvc_provisioner.profile_list(config, limit) + if retcode: + pvc_provisioner.format_list_profile(retdata) + retdata = '' + cleanup(retcode, retdata) + +############################################################################### +# pvc provisioner profile add +############################################################################### +@click.command(name='add', short_help='Add provisioner profile.') +@click.argument( + 'name' +) +@click.option( + '-s', '--system-template', 'system_template', + required=True, + help='The system template for the profile.' +) +@click.option( + '-n', '--network-template', 'network_template', + required=True, + help='The network template for the profile.' +) +@click.option( + '-t', '--storage-template', 'storage_template', + required=True, + help='The storage template for the profile.' +) +@click.option( + '-u', '--userdata', 'userdata', + required=True, + help='The userdata document for the profile.' +) +@click.option( + '-x', '--script', 'script', + required=True, + help='The script for the profile.' +) +@click.option( + '-a', '--script-arg', 'script_args', + default=[], multiple=True, + help='Additional argument to the script install() function in key=value format.' +) +def provisioner_profile_add(name, system_template, network_template, storage_template, userdata, script, script_args): + """ + Add a new provisioner profile NAME. + """ + params = dict() + params['name'] = name + params['system_template'] = system_template + params['network_template'] = network_template + params['storage_template'] = storage_template + params['userdata'] = userdata + params['script'] = script + params['arg'] = script_args + + retcode, retdata = pvc_provisioner.profile_add(config, params) + cleanup(retcode, retdata) + +############################################################################### +# pvc provisioner profile modify +############################################################################### +@click.command(name='modify', short_help='Modify provisioner profile.') +@click.argument( + 'name' +) +@click.option( + '-s', '--system-template', 'system_template', + default=None, + help='The system template for the profile.' +) +@click.option( + '-n', '--network-template', 'network_template', + default=None, + help='The network template for the profile.' +) +@click.option( + '-t', '--storage-template', 'storage_template', + default=None, + help='The storage template for the profile.' +) +@click.option( + '-u', '--userdata', 'userdata', + default=None, + help='The userdata document for the profile.' +) +@click.option( + '-x', '--script', 'script', + default=None, + help='The script for the profile.' +) +@click.option( + '-d', '--delete-script-args', 'delete_script_args', + default=False, is_flag=True, + help="Delete any existing script arguments." +) +@click.option( + '-a', '--script-arg', 'script_args', + default=None, multiple=True, + help='Additional argument to the script install() function in key=value format.' +) +def provisioner_profile_modify(name, system_template, network_template, storage_template, userdata, script, delete_script_args, script_args): + """ + Modify existing provisioner profile NAME. + """ + params = dict() + if system_template is not None: + params['system_template'] = system_template + if network_template is not None: + params['network_template'] = network_template + if storage_template is not None: + params['storage_template'] = storage_template + if userdata is not None: + params['userdata'] = userdata + if script is not None: + params['script'] = script + if delete_script_args: + params['arg'] = [] + if script_args is not None: + params['arg'] = script_args + + retcode, retdata = pvc_provisioner.profile_modify(config, name, params) + cleanup(retcode, retdata) + +############################################################################### +# pvc provisioner profile remove +############################################################################### +@click.command(name='remove', short_help='Remove profile.') +@click.argument( + 'name' +) +def provisioner_profile_remove(name): + """ + Remove profile NAME from the PVC cluster provisioner. + """ + retcode, retdata = pvc_provisioner.profile_remove(config, name) + cleanup(retcode, retdata) + @@ -2869,9 +3030,15 @@ provisioner_script.add_command(provisioner_script_add) provisioner_script.add_command(provisioner_script_modify) provisioner_script.add_command(provisioner_script_remove) +provisioner_profile.add_command(provisioner_profile_list) +provisioner_profile.add_command(provisioner_profile_add) +provisioner_profile.add_command(provisioner_profile_modify) +provisioner_profile.add_command(provisioner_profile_remove) + cli_provisioner.add_command(provisioner_template) cli_provisioner.add_command(provisioner_userdata) cli_provisioner.add_command(provisioner_script) +cli_provisioner.add_command(provisioner_profile) cli.add_command(cli_cluster) cli.add_command(cli_node)