diff --git a/src/apic-extension/azext_apic_extension/custom.py b/src/apic-extension/azext_apic_extension/custom.py index 28346b2c221..477bf7e72a0 100644 --- a/src/apic-extension/azext_apic_extension/custom.py +++ b/src/apic-extension/azext_apic_extension/custom.py @@ -23,7 +23,7 @@ from .command_patches import ExportAPIDefinitionExtension from .command_patches import ExportMetadataExtension -from azure.cli.core.azclierror import InvalidArgumentValueError +from azure.cli.core.azclierror import InvalidArgumentValueError, UserFault logger = get_logger(__name__) @@ -158,6 +158,13 @@ def writeResultsToFile(self, results, file_name): f.write(results) +class CustomCommandInternalError(UserFault): + """ Internal error in custom command. """ + def __init__(self, error_msg, code=None): + error_msg = f'Code: {code}\nMessage: {error_msg}' + super(CustomCommandInternalError, self).__init__(error_msg) + + # Quick Import def register_apic(cmd, api_location, resource_group, service_name, environment_id=None): @@ -230,180 +237,183 @@ def register_apic(cmd, api_location, resource_group, service_name, environment_i # TODO how to determine other kinds - enum={"graphql": "graphql", "grpc": "grpc", "rest": "rest", "soap": "soap", "webhook": "webhook", "websocket": "websocket"} # Create API and Create API Version - info = data['info'] - if info: - # Create API and Create API Version - extracted_api_name = _generate_api_id(info.get('title', 'Default-API')).lower() - extracted_api_description = info.get('description', 'API Description')[:1000] - extracted_api_title = info.get('title', 'API Title') - extracted_api_version = info.get('version', 'v1').replace(".", "-").lower() - extracted_api_version_title = info.get('version', 'v1').replace(".", "-").lower() - # TODO -Create API Version lifecycle_stage - - # Create API - Get the contact details from info in spec - contacts = None - contact = info.get('contact') - if contact: - extracted_api_contact_email = contact.get('email') - extracted_api_contact_name = contact.get('name') - extracted_api_contact_url = contact.get('url') - contacts = [{'email': extracted_api_contact_email, 'name': extracted_api_contact_name, 'url': extracted_api_contact_url}] - - # Create API - Get the license details from info in spec - extracted_api_license = None - licenseDetails = info.get('license') - if licenseDetails: - extracted_api_license_identifier = licenseDetails.get('identifier') - extracted_api_license_name = licenseDetails.get('name') - extracted_api_license_url = licenseDetails.get('url') - extracted_api_license = {'identifier': extracted_api_license_identifier, 'name': extracted_api_license_name, 'url': extracted_api_license_url} - - # Create API - Get the terms of service from info in spec - extracted_api_terms_of_service = {'url': None} - extracted_api_terms_of_service_value = info.get('termsOfService') - if extracted_api_terms_of_service_value: - extracted_api_terms_of_service = {'url': extracted_api_terms_of_service_value} - - # Create API - Get the external documentation in spec - extracted_api_external_documentation = [] - external_documentation = data.get('externalDocs') - if external_documentation: - extracted_api_external_documentation_description = external_documentation.get('description') - extracted_api_external_documentation_url = external_documentation.get('url') - extracted_api_external_documentation.append({'description': extracted_api_external_documentation_description, 'title': 'Title', 'url': extracted_api_external_documentation_url}) - - # TODO: Create API - custom-properties - # "The custom metadata defined for API catalog entities. #1 - - # Create API ------------------------------------------------------------------------------------- - from .aaz.latest.apic.api import Create as CreateAPI - - api_args = { - 'api_id': extracted_api_name, - 'resource_group': resource_group, - 'service_name': service_name, - 'workspace_name': 'default', - 'title': extracted_api_title, - 'type': extracted_api_kind, - 'contacts': contacts, - 'license': extracted_api_license, - 'terms_of_service': extracted_api_terms_of_service, - 'external_documentation': extracted_api_external_documentation, - 'description': extracted_api_description, - } - - CreateAPI(cli_ctx=cmd.cli_ctx)(command_args=api_args) - logger.warning('API was created successfully') - - # Create API Version ----------------------------------------------------------------------------- - from .aaz.latest.apic.api.version import Create as CreateAPIVersion - - api_version_args = { - 'api_id': extracted_api_name, - 'resource_group': resource_group, - 'service_name': service_name, - 'version_id': extracted_api_version, - 'workspace_name': 'default', - 'lifecycle_stage': 'design', # TODO: Extract from spec or not pass. was it required? - 'title': extracted_api_version_title - } - - CreateAPIVersion(cli_ctx=cmd.cli_ctx)(command_args=api_version_args) - logger.warning('API version was created successfully') - - # Create API Definition ----------------------------------------------------------------------------- - from .aaz.latest.apic.api.definition import Create as CreateAPIDefinition - - api_definition_args = { - 'api_id': extracted_api_name, - 'resource_group': resource_group, - 'service_name': service_name, - 'version_id': extracted_api_version, - 'workspace_name': 'default', - 'definition_id': extracted_definition_name, - 'title': extracted_definition_name, # TODO Extract from spec - 'description': extracted_api_description, # TODO Extract from spec - } - - CreateAPIDefinition(cli_ctx=cmd.cli_ctx)(command_args=api_definition_args) - logger.warning('API definition was created successfully') - - # Import Specification ----------------------------------------------------------------------------- - from azure.cli.core.commands import LongRunningOperation - - # uses customized ImportSpecificationExtension class - specification_details = {'name': extracted_definition_name, 'version': extracted_definition_version} - # TODO format - Link - what if the link is just pasted in the value? - # TODO format - inline - what if spec is just pasted in the value? - # TODO - other non json spec formats - - api_specification_args = { - 'resource_group': resource_group, - 'service_name': service_name, - 'workspace_name': 'default', - 'api_id': extracted_api_name, - 'version_id': extracted_api_version, - 'definition_id': extracted_definition_name, - 'format': custom_format, - 'specification': specification_details, # TODO write the correct spec object - 'value': value - } - - importAPISpecificationResults = ImportSpecificationExtension(cli_ctx=cmd.cli_ctx)(command_args=api_specification_args) - LongRunningOperation(cmd.cli_ctx)(importAPISpecificationResults) - logger.warning('API specification was created successfully') - - # Create API Deployment ----------------------------------------------------------------------------- - from .aaz.latest.apic.api.deployment import Create as CreateAPIDeployment - from .aaz.latest.apic.environment import Show as GetEnvironment - - environment_id = None - if environment_id: - # GET Environment ID - environment_args = { + try: + info = data['info'] + if info: + # Create API and Create API Version + extracted_api_name = _generate_api_id(info.get('title', 'Default-API')).lower() + extracted_api_description = info.get('description', 'API Description')[:1000] + extracted_api_title = info.get('title', 'API Title') + extracted_api_version = info.get('version', 'v1').replace(".", "-").lower() + extracted_api_version_title = info.get('version', 'v1').replace(".", "-").lower() + # TODO -Create API Version lifecycle_stage + + # Create API - Get the contact details from info in spec + contacts = None + contact = info.get('contact') + if contact: + extracted_api_contact_email = contact.get('email') + extracted_api_contact_name = contact.get('name') + extracted_api_contact_url = contact.get('url') + contacts = [{'email': extracted_api_contact_email, 'name': extracted_api_contact_name, 'url': extracted_api_contact_url}] + + # Create API - Get the license details from info in spec + extracted_api_license = None + licenseDetails = info.get('license') + if licenseDetails: + extracted_api_license_identifier = licenseDetails.get('identifier') + extracted_api_license_name = licenseDetails.get('name') + extracted_api_license_url = licenseDetails.get('url') + extracted_api_license = {'identifier': extracted_api_license_identifier, 'name': extracted_api_license_name, 'url': extracted_api_license_url} + + # Create API - Get the terms of service from info in spec + extracted_api_terms_of_service = {'url': None} + extracted_api_terms_of_service_value = info.get('termsOfService') + if extracted_api_terms_of_service_value: + extracted_api_terms_of_service = {'url': extracted_api_terms_of_service_value} + + # Create API - Get the external documentation in spec + extracted_api_external_documentation = [] + external_documentation = data.get('externalDocs') + if external_documentation: + extracted_api_external_documentation_description = external_documentation.get('description') + extracted_api_external_documentation_url = external_documentation.get('url') + extracted_api_external_documentation.append({'description': extracted_api_external_documentation_description, 'title': 'Title', 'url': extracted_api_external_documentation_url}) + + # TODO: Create API - custom-properties + # "The custom metadata defined for API catalog entities. #1 + + # Create API ------------------------------------------------------------------------------------- + from .aaz.latest.apic.api import Create as CreateAPI + + api_args = { + 'api_id': extracted_api_name, + 'resource_group': resource_group, + 'service_name': service_name, + 'workspace_name': 'default', + 'title': extracted_api_title, + 'type': extracted_api_kind, + 'contacts': contacts, + 'license': extracted_api_license, + 'terms_of_service': extracted_api_terms_of_service, + 'external_documentation': extracted_api_external_documentation, + 'description': extracted_api_description, + } + + CreateAPI(cli_ctx=cmd.cli_ctx)(command_args=api_args) + logger.warning('API was created successfully') + + # Create API Version ----------------------------------------------------------------------------- + from .aaz.latest.apic.api.version import Create as CreateAPIVersion + + api_version_args = { + 'api_id': extracted_api_name, + 'resource_group': resource_group, + 'service_name': service_name, + 'version_id': extracted_api_version, + 'workspace_name': 'default', + 'lifecycle_stage': 'design', # TODO: Extract from spec or not pass. was it required? + 'title': extracted_api_version_title + } + + CreateAPIVersion(cli_ctx=cmd.cli_ctx)(command_args=api_version_args) + logger.warning('API version was created successfully') + + # Create API Definition ----------------------------------------------------------------------------- + from .aaz.latest.apic.api.definition import Create as CreateAPIDefinition + + api_definition_args = { + 'api_id': extracted_api_name, 'resource_group': resource_group, 'service_name': service_name, + 'version_id': extracted_api_version, 'workspace_name': 'default', - 'environment_id': environment_id + 'definition_id': extracted_definition_name, + 'title': extracted_definition_name, # TODO Extract from spec + 'description': extracted_api_description, # TODO Extract from spec } - getEnvironmentResults = GetEnvironment(cli_ctx=cmd.cli_ctx)(command_args=environment_args) - environment_id = getEnvironmentResults['id'] - # full envId, extract actual envId if to be used later - - servers = data.get('servers') - if environment_id and servers: - for server in servers: - default_deployment_title = (extracted_api_name + "deployment").replace("-", "") - extracted_deployment_name = server.get('name', default_deployment_title).replace(" ", "-") - extracted_deployment_title = server.get('title', default_deployment_title).replace(" ", "-") - extracted_deployment_description = server.get('description', default_deployment_title) - extracted_definition_id = '/workspaces/default/apis/' + extracted_api_name + '/versions/' + extracted_api_version + '/definitions/' + extracted_definition_name - extracted_environment_id = '/workspaces/default/environments/' + environment_id - extracted_state = server.get('state', 'active') - - extracted_server_urls = [] - extracted_server_url = server.get('url') - extracted_server_urls.append(extracted_server_url) - extracted_server = {'runtime_uri': extracted_server_urls} - - api_deployment_args = { + CreateAPIDefinition(cli_ctx=cmd.cli_ctx)(command_args=api_definition_args) + logger.warning('API definition was created successfully') + + # Import Specification ----------------------------------------------------------------------------- + from azure.cli.core.commands import LongRunningOperation + + # uses customized ImportSpecificationExtension class + specification_details = {'name': extracted_definition_name, 'version': extracted_definition_version} + # TODO format - Link - what if the link is just pasted in the value? + # TODO format - inline - what if spec is just pasted in the value? + # TODO - other non json spec formats + + api_specification_args = { + 'resource_group': resource_group, + 'service_name': service_name, + 'workspace_name': 'default', + 'api_id': extracted_api_name, + 'version_id': extracted_api_version, + 'definition_id': extracted_definition_name, + 'format': custom_format, + 'specification': specification_details, # TODO write the correct spec object + 'value': value + } + + importAPISpecificationResults = ImportSpecificationExtension(cli_ctx=cmd.cli_ctx)(command_args=api_specification_args) + LongRunningOperation(cmd.cli_ctx)(importAPISpecificationResults) + logger.warning('API specification was created successfully') + + # Create API Deployment ----------------------------------------------------------------------------- + from .aaz.latest.apic.api.deployment import Create as CreateAPIDeployment + from .aaz.latest.apic.environment import Show as GetEnvironment + + environment_id = None + if environment_id: + # GET Environment ID + environment_args = { 'resource_group': resource_group, 'service_name': service_name, 'workspace_name': 'default', - 'api_id': extracted_api_name, - 'deployment_id': extracted_deployment_name, - 'description': extracted_deployment_description, - 'title': extracted_deployment_title, - 'definition_id': extracted_definition_id, - 'environment_id': extracted_environment_id, - 'server': extracted_server, - 'state': extracted_state - # TODO custom properties + 'environment_id': environment_id } - CreateAPIDeployment(cli_ctx=cmd.cli_ctx)(command_args=api_deployment_args) - logger.warning('API deployment was created successfully') + getEnvironmentResults = GetEnvironment(cli_ctx=cmd.cli_ctx)(command_args=environment_args) + environment_id = getEnvironmentResults['id'] + # full envId, extract actual envId if to be used later + + servers = data.get('servers') + if environment_id and servers: + for server in servers: + default_deployment_title = (extracted_api_name + "deployment").replace("-", "") + extracted_deployment_name = server.get('name', default_deployment_title).replace(" ", "-") + extracted_deployment_title = server.get('title', default_deployment_title).replace(" ", "-") + extracted_deployment_description = server.get('description', default_deployment_title) + extracted_definition_id = '/workspaces/default/apis/' + extracted_api_name + '/versions/' + extracted_api_version + '/definitions/' + extracted_definition_name + extracted_environment_id = '/workspaces/default/environments/' + environment_id + extracted_state = server.get('state', 'active') + + extracted_server_urls = [] + extracted_server_url = server.get('url') + extracted_server_urls.append(extracted_server_url) + extracted_server = {'runtime_uri': extracted_server_urls} + + api_deployment_args = { + 'resource_group': resource_group, + 'service_name': service_name, + 'workspace_name': 'default', + 'api_id': extracted_api_name, + 'deployment_id': extracted_deployment_name, + 'description': extracted_deployment_description, + 'title': extracted_deployment_title, + 'definition_id': extracted_definition_id, + 'environment_id': extracted_environment_id, + 'server': extracted_server, + 'state': extracted_state + # TODO custom properties + } + + CreateAPIDeployment(cli_ctx=cmd.cli_ctx)(command_args=api_deployment_args) + logger.warning('API deployment was created successfully') + except Exception as e: + raise CustomCommandInternalError(error_msg=f'Error while creating API. Field missing: {e}', code='KeyError') if type(e).__name__ == 'KeyError' else e def _generate_api_id(title: str) -> str: