From 807a27558910072730c82989ec9fda9ecf5b1190 Mon Sep 17 00:00:00 2001 From: ninpan-ms <71061174+ninpan-ms@users.noreply.github.com> Date: Thu, 16 Dec 2021 16:08:30 +0800 Subject: [PATCH] Add scg & api portal commands (#36) * Add scg & api portal commands * fix comment Co-authored-by: Yuwei Zhou --- src/spring-cloud/azext_spring_cloud/_help.py | 179 +++++++++++++++ .../azext_spring_cloud/_params.py | 55 ++++- .../azext_spring_cloud/_validators.py | 1 + .../_validators_enterprise.py | 29 ++- .../azext_spring_cloud/api_portal.py | 88 +++++++ .../azext_spring_cloud/commands.py | 76 ++++++- .../azext_spring_cloud/gateway.py | 215 ++++++++++++++++++ 7 files changed, 639 insertions(+), 4 deletions(-) create mode 100644 src/spring-cloud/azext_spring_cloud/api_portal.py create mode 100644 src/spring-cloud/azext_spring_cloud/gateway.py diff --git a/src/spring-cloud/azext_spring_cloud/_help.py b/src/spring-cloud/azext_spring_cloud/_help.py index 07b0079973..0be2575421 100644 --- a/src/spring-cloud/azext_spring_cloud/_help.py +++ b/src/spring-cloud/azext_spring_cloud/_help.py @@ -569,6 +569,11 @@ text: az spring-cloud app-insights update -n MyService -g MyResourceGroup --disable """ +helps['spring-cloud service-registry'] = """ + type: group + short-summary: (Enterprise Tier Only) Commands to manage Service Registry in Azure Spring Cloud. +""" + helps['spring-cloud service-registry show'] = """ type: command short-summary: Show the provisioning status and runtime status of Service Registry. @@ -590,6 +595,11 @@ text: az spring-cloud service-registry unbind --app MyApp -s MyService -g MyResourceGroup """ +helps['spring-cloud application-configuration-service'] = """ + type: group + short-summary: (Enterprise Tier Only) Commands to manage Application Configuration Service in Azure Spring Cloud. +""" + helps['spring-cloud application-configuration-service show'] = """ type: command short-summary: Show the provisioning status, runtime status, and settings of Application Configuration Service. @@ -687,3 +697,172 @@ - name: Delete a buildpacks binding. text: az spring-cloud build-service buildpacks-binding delete --name first-binding """ + +helps['spring-cloud gateway'] = """ + type: group + short-summary: (Enterprise Tier Only) Commands to manage gateway in Azure Spring Cloud. +""" + +helps['spring-cloud gateway clear'] = """ + type: command + short-summary: Clear all settings of gateway. +""" + +helps['spring-cloud gateway show'] = """ + type: command + short-summary: Show the settings, provisioning status and runtime status of gateway. +""" + +helps['spring-cloud gateway update'] = """ + type: command + short-summary: Update an existing gateway properties. + examples: + - name: Update gateway property. + text: az spring-cloud gateway update -s MyService -g MyResourceGroup --name MyName --assign-endpoint true --https-only true +""" + +helps['spring-cloud gateway route-config'] = """ + type: group + short-summary: Commands to manage gateway route configs in Azure Spring Cloud. +""" + +helps['spring-cloud gateway route-config create'] = """ + type: command + short-summary: Create a gateway route config with routing rules of Json array format. + examples: + - name: Create a gateway route config targeting the app in Azure Spring Cloud. + text: az spring-cloud gateway route-config create -s MyService -g MyResourceGroup --name MyName --app-name MyApp --routes-file MyJson.json +""" + +helps['spring-cloud gateway route-config update'] = """ + type: command + short-summary: Update an existing gateway route config with routing rules of Json array format. + examples: + - name: Update an existing gateway route config targeting the app in Azure Spring Cloud. + text: az spring-cloud gateway route-config update -s MyService -g MyResourceGroup --name MyName --app-name MyApp --routes-file MyJson.json +""" + +helps['spring-cloud gateway route-config remove'] = """ + type: command + short-summary: Delete an existing gateway route config. + examples: + - name: Delete an existing gateway route config. + text: az spring-cloud gateway route-config delete -s MyService -g MyResourceGroup --name MyName +""" + +helps['spring-cloud gateway route-config show'] = """ + type: command + short-summary: Get an existing gateway route config. + examples: + - name: Get an existing gateway route config. + text: az spring-cloud gateway route-config show -s MyService -g MyResourceGroup --name MyName +""" + +helps['spring-cloud gateway route-config list'] = """ + type: command + short-summary: List all existing gateway route configs. + examples: + - name: List all existing gateway route configs. + text: az spring-cloud gateway route-config list -s MyService -g MyResourceGroup +""" + +helps['spring-cloud gateway custom-domain'] = """ + type: group + short-summary: Commands to manage custom domains for gateway. +""" + +helps['spring-cloud gateway custom-domain bind'] = """ + type: command + short-summary: Bind a custom domain with the gateway. + examples: + - name: Bind a custom domain to gateway. + text: az spring-cloud gateway custom-domain bind --domain-name MyDomainName --certificate MyCertName --service MyCluster --resource-group MyResourceGroup +""" + +helps['spring-cloud gateway custom-domain show'] = """ + type: command + short-summary: Show details of a custom domain. +""" + +helps['spring-cloud gateway custom-domain list'] = """ + type: command + short-summary: List all custom domains of the gateway. + examples: + - name: List all custom domains of the gateway. + text: az spring-cloud gateway custom-domain list --service MyCluster --resource-group MyResourceGroup +""" + +helps['spring-cloud gateway custom-domain update'] = """ + type: command + short-summary: Update a custom domain of the gateway. + examples: + - name: Bind custom domain with a specified certificate. + text: az spring-cloud gateway custom-domain update --domain-name MyDomainName --certificate MCertName --service MyCluster --resource-group MyResourceGroup +""" + +helps['spring-cloud gateway custom-domain unbind'] = """ + type: command + short-summary: Unbind a custom-domain of the gateway. +""" + +helps['spring-cloud api-portal'] = """ + type: group + short-summary: (Enterprise Tier Only) Commands to manage API portal in Azure Spring Cloud. +""" + +helps['spring-cloud api-portal clear'] = """ + type: command + short-summary: Clear all settings of API portal. +""" + +helps['spring-cloud api-portal show'] = """ + type: command + short-summary: Show the settings, provisioning status and runtime status of API portal. +""" + +helps['spring-cloud api-portal update'] = """ + type: command + short-summary: Update an existing API portal properties. + examples: + - name: Update API portal property. + text: az spring-cloud api-portal update -s MyService -g MyResourceGroup --name MyName --assign-endpoint true --https-only true +""" + +helps['spring-cloud api-portal custom-domain'] = """ + type: group + short-summary: Commands to manage custom domains for API portal. +""" + +helps['spring-cloud api-portal custom-domain bind'] = """ + type: command + short-summary: Bind a custom domain with the API portal. + examples: + - name: Bind a custom domain to API portal. + text: az spring-cloud api-portal custom-domain bind --domain-name MyDomainName --certificate MyCertName --service MyCluster --resource-group MyResourceGroup +""" + +helps['spring-cloud api-portal custom-domain show'] = """ + type: command + short-summary: Show details of a custom domain. +""" + +helps['spring-cloud api-portal custom-domain list'] = """ + type: command + short-summary: List all custom domains of the API portal. + examples: + - name: List all custom domains of the API portal. + text: az spring-cloud api-portal custom-domain list --service MyCluster --resource-group MyResourceGroup +""" + +helps['spring-cloud api-portal custom-domain update'] = """ + type: command + short-summary: Update a custom domain of the API portal. + examples: + - name: Bind custom domain with a specified certificate. + text: az spring-cloud api-portal custom-domain update --domain-name MyDomainName --certificate MCertName --service MyCluster --resource-group MyResourceGroup +""" + +helps['spring-cloud api-portal custom-domain unbind'] = """ + type: command + short-summary: Unbind a custom-domain of the API portal. +""" diff --git a/src/spring-cloud/azext_spring_cloud/_params.py b/src/spring-cloud/azext_spring_cloud/_params.py index 695cf8f0a4..4d7507a933 100644 --- a/src/spring-cloud/azext_spring_cloud/_params.py +++ b/src/spring-cloud/azext_spring_cloud/_params.py @@ -18,7 +18,7 @@ validate_buildpacks_binding_properties, validate_buildpacks_binding_secrets, only_support_enterprise, validate_buildpacks_binding_not_exist, validate_buildpacks_binding_exist, - validate_git_uri, validate_acs_patterns, validate_builder, + validate_git_uri, validate_acs_patterns, validate_routes, validate_builder, validate_build_pool_size) from ._app_validator import (fulfill_deployment_param, active_deployment_exist, active_deployment_exist_under_app, ensure_not_active_deployment) from ._utils import ApiType @@ -412,7 +412,8 @@ def prepare_logs_argument(c): help="Disable Application Insights.", validator=validate_app_insights_parameters) - for scope in ['spring-cloud application-configuration-service', 'spring-cloud service-registry']: + for scope in ['spring-cloud application-configuration-service', 'spring-cloud service-registry', + 'spring-cloud gateway', 'spring-cloud api-portal']: with self.argument_context(scope) as c: c.argument('service', service_name_type, validator=only_support_enterprise) @@ -450,6 +451,56 @@ def prepare_logs_argument(c): with self.argument_context(scope) as c: c.argument('name', help="Required unique name to label each item of git configs.") + for scope in ['spring-cloud gateway update', + 'spring-cloud api-portal update']: + with self.argument_context(scope) as c: + c.argument('instance_count', type=int, help='Number of instance.') + c.argument('assign_endpoint', arg_type=get_three_state_flag(), help='If true, assign endpoint URL for direct access.') + c.argument('https_only', arg_type=get_three_state_flag(), help='If true, access endpoint via https') + c.argument('scope', arg_group='Single Sign On (SSO)', help="Comma-separated list of the specific actions applications can be allowed to do on a user's behalf.") + c.argument('client_id', arg_group='Single Sign On (SSO)', help="The public identifier for the application.") + c.argument('client_secret', arg_group='Single Sign On (SSO)', help="The secret known only to the application and the authorization server.") + c.argument('issuer_uri', arg_group='Single Sign On (SSO)', help="The URI of Issuer Identifier.") + + with self.argument_context('spring-cloud gateway update') as c: + c.argument('cpu', type=str, help='CPU resource quantity. Should be 500m or number of CPU cores.') + c.argument('memory', type=str, help='Memory resource quantity. Should be 512Mi or #Gi, e.g., 1Gi, 3Gi.') + c.argument('api_title', arg_group='API metadata', help="Title describing the context of the APIs available on the Gateway instance.") + c.argument('api_description', arg_group='API metadata', help="Detailed description of the APIs available on the Gateway instance.") + c.argument('api_documentation_location', arg_group='API metadata', help="Location of additional documentation for the APIs available on the Gateway instance.") + c.argument('api_version', arg_group='API metadata', help="Version of APIs available on this Gateway instance.") + c.argument('server_url', arg_group='API metadata', help="Base URL that API consumers will use to access APIs on the Gateway instance.") + c.argument('allowed_origins', arg_group='Cross-origin Resource Sharing (CORS)', help="Comma-separated list of allowed origins to make cross-site requests. The special value `*` allows all domains.") + c.argument('allowed_methods', arg_group='Cross-origin Resource Sharing (CORS)', help="Comma-separated list of allowed HTTP methods on cross-site requests. The special value `*` allows all methods.") + c.argument('allowed_headers', arg_group='Cross-origin Resource Sharing (CORS)', help="Comma-separated list of allowed headers in cross-site requests. The special value `*` allows actual requests to send any header.") + c.argument('max_age', arg_group='Cross-origin Resource Sharing (CORS)', type=int, + help="How long, in seconds, the response from a pre-flight request can be cached by clients.") + c.argument('allow_credentials', arg_group='Cross-origin Resource Sharing (CORS)', arg_type=get_three_state_flag(), + help="Whether user credentials are supported on cross-site requests.") + c.argument('exposed_headers', arg_group='Cross-origin Resource Sharing (CORS)', help="Comma-separated list of HTTP response headers to expose for cross-site requests.") + + for scope in ['spring-cloud gateway custom-domain', + 'spring-cloud api-portal custom-domain']: + with self.argument_context(scope) as c: + c.argument('domain_name', help='Name of custom domain.') + + for scope in ['spring-cloud gateway custom-domain bind', + 'spring-cloud gateway custom-domain update', + 'spring-cloud api-portal custom-domain bind', + 'spring-cloud api-portal custom-domain update']: + with self.argument_context(scope) as c: + c.argument('certificate', type=str, help='Certificate name in Azure Spring Cloud.') + + with self.argument_context('spring-cloud gateway route-config') as c: + c.argument('name', help='Name of route config.') + + for scope in ['spring-cloud gateway route-config create', + 'spring-cloud gateway route-config update']: + with self.argument_context(scope) as c: + c.argument('app_name', type=str, help="The Azure Spring Cloud app name to configure the route.") + c.argument('routes_json', type=str, help="The JSON array of API routes.", validator=validate_routes) + c.argument('routes_file', type=str, help="The file path of JSON array of API routes.", validator=validate_routes) + for scope in ['spring-cloud build-service buildpacks-binding create', 'spring-cloud build-service buildpacks-binding set']: with self.argument_context(scope) as c: diff --git a/src/spring-cloud/azext_spring_cloud/_validators.py b/src/spring-cloud/azext_spring_cloud/_validators.py index 31a338de54..e87552ec02 100644 --- a/src/spring-cloud/azext_spring_cloud/_validators.py +++ b/src/spring-cloud/azext_spring_cloud/_validators.py @@ -5,6 +5,7 @@ # pylint: disable=too-few-public-methods, unused-argument, redefined-builtin +from os import name from re import match from re import search from ipaddress import ip_network diff --git a/src/spring-cloud/azext_spring_cloud/_validators_enterprise.py b/src/spring-cloud/azext_spring_cloud/_validators_enterprise.py index 87b9af91d5..0673249158 100644 --- a/src/spring-cloud/azext_spring_cloud/_validators_enterprise.py +++ b/src/spring-cloud/azext_spring_cloud/_validators_enterprise.py @@ -17,8 +17,8 @@ from ._util_enterprise import ( is_enterprise_tier, get_client ) +from ._validators import (validate_instance_count, _parse_sku_name) from .vendored_sdks.appplatform.v2022_01_01_preview.models import _app_platform_management_client_enums as AppPlatformEnums -from ._validators import _parse_sku_name logger = get_logger(__name__) @@ -125,6 +125,32 @@ def validate_buildpacks_binding_exist(cmd, namespace): namespace.name) +def validate_gateway_update(namespace): + _validate_sso(namespace) + validate_cpu(namespace) + validate_memory(namespace) + validate_instance_count(namespace) + + +def validate_api_portal_update(namespace): + _validate_sso(namespace) + validate_instance_count(namespace) + + +def _validate_sso(namespace): + all_provided = namespace.scope and namespace.client_id and namespace.client_secret and namespace.issuer_uri + none_provided = namespace.scope is None and namespace.client_id is None and namespace.client_secret is None and namespace.issuer_uri is None + if not all_provided and not none_provided : + raise CLIError("Single Sign On configurations '--scope --client-id --client-secret --issuer-uri' should be all provided or none provided.") + if namespace.scope: + namespace.scope = namespace.scope.split(",") + + +def validate_routes(namespace): + if namespace.routes_json is not None and namespace.routes_file is not None: + raise CLIError("You can only specify either --routes-json or --routes-file.") + + def validate_builder(cmd, namespace): client = get_client(cmd) builder = client.build_service_builder.get(namespace.resource_group, @@ -135,6 +161,7 @@ def validate_builder(cmd, namespace): raise CLIError('The provision state of builder {} is not succeeded, please choose a succeeded builder.' .format(namespace.builder)) + def validate_build_pool_size(namespace): if _parse_sku_name(namespace.sku) != 'enterprise': namespace.build_pool_size = None diff --git a/src/spring-cloud/azext_spring_cloud/api_portal.py b/src/spring-cloud/azext_spring_cloud/api_portal.py new file mode 100644 index 0000000000..1b4d2b09cc --- /dev/null +++ b/src/spring-cloud/azext_spring_cloud/api_portal.py @@ -0,0 +1,88 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from .vendored_sdks.appplatform.v2022_01_01_preview import models as models + +DEFAULT_NAME = "default" + + +def api_portal_show(cmd, client, resource_group, service): + return client.api_portals.get(resource_group, service, DEFAULT_NAME) + + +def api_portal_update(cmd, client, resource_group, service, + instance_count=None, + assign_endpoint=None, + https_only=None, + scope=None, + client_id=None, + client_secret=None, + issuer_uri=None): + api_portal = client.api_portals.get(resource_group, service, DEFAULT_NAME) + + sso_properties = api_portal.properties.sso_properties + if scope and client_id and client_secret and issuer_uri: + sso_properties = models.SsoProperties( + scope=scope, + client_id=client_id, + client_secret=client_secret, + issuer_uri=issuer_uri, + ) + + properties = models.ApiPortalProperties( + public=assign_endpoint if assign_endpoint is not None else api_portal.properties.public, + https_only=https_only if https_only is not None else api_portal.properties.https_only, + gateway_ids=api_portal.properties.gateway_ids, + sso_properties=sso_properties + ) + + sku = models.Sku(name=api_portal.sku.name, tier=api_portal.sku.tier, + capacity=instance_count or api_portal.sku.capacity) + + api_portal_resource = models.ApiPortalResource( + properties=properties, sku=sku) + return client.api_portals.begin_create_or_update(resource_group, service, DEFAULT_NAME, api_portal_resource) + + +def api_portal_clear(cmd, client, resource_group, service): + api_portal = client.api_portals.get(resource_group, service, DEFAULT_NAME) + properties = models.GatewayProperties( + gateway_ids=api_portal.properties.gateway_ids + ) + + sku = models.Sku(name=api_portal.sku.name, tier=api_portal.sku.tier) + api_portal_resource = models.ApiPortalResource(properties=properties, sku=sku) + return client.api_portals.begin_create_or_update(resource_group, service, DEFAULT_NAME, api_portal_resource) + + +def api_portal_custom_domain_show(cmd, client, resource_group, service, domain_name): + return client.api_portal_custom_domains.get(resource_group, service, DEFAULT_NAME, domain_name) + + +def api_portal_custom_domain_list(cmd, client, resource_group, service): + return client.api_portal_custom_domains.list(resource_group, service, DEFAULT_NAME) + + +def api_portal_custom_domain_update(cmd, client, resource_group, service, + domain_name, + certificate=None): + properties = models.ApiPortalCustomDomainProperties() + if certificate is not None: + certificate_response = client.api_portals.certificates.get( + resource_group, service, certificate) + properties = models.ApiPortalCustomDomainProperties( + thumbprint=certificate_response.properties.thumbprint + ) + + custom_domain_resource = models.ApiPortalCustomDomainResource( + properties=properties) + return client.api_portal_custom_domains.begin_create_or_update(resource_group, service, DEFAULT_NAME, + domain_name, custom_domain_resource) + + +def api_portal_custom_domain_unbind(cmd, client, resource_group, service, domain_name): + client.api_portal_custom_domains.get(resource_group, service, + DEFAULT_NAME, domain_name) + return client.api_portal_custom_domains.begin_delete(resource_group, service, DEFAULT_NAME, domain_name) diff --git a/src/spring-cloud/azext_spring_cloud/commands.py b/src/spring-cloud/azext_spring_cloud/commands.py index 0a2e974db2..22a1be3d6e 100644 --- a/src/spring-cloud/azext_spring_cloud/commands.py +++ b/src/spring-cloud/azext_spring_cloud/commands.py @@ -20,6 +20,7 @@ transform_spring_cloud_deployment_output, transform_spring_cloud_certificate_output, transform_spring_cloud_custom_domain_output) +from ._validators_enterprise import (validate_gateway_update, validate_api_portal_update) # pylint: disable=too-many-statements @@ -44,6 +45,31 @@ def load_command_table(self, _): client_factory=cf_spring_cloud_enterprise ) + gateway_cmd_group = CliCommandType( + operations_tmpl='azext_spring_cloud.gateway#{}', + client_factory=cf_spring_cloud_enterprise + ) + + gateway_custom_domain_cmd_group = CliCommandType( + operations_tmpl='azext_spring_cloud.gateway#{}', + client_factory=cf_spring_cloud_enterprise + ) + + gateway_route_config_cmd_group = CliCommandType( + operations_tmpl='azext_spring_cloud.gateway#{}', + client_factory=cf_spring_cloud_enterprise + ) + + api_portal_cmd_group = CliCommandType( + operations_tmpl='azext_spring_cloud.api_portal#{}', + client_factory=cf_spring_cloud_enterprise + ) + + api_portal_custom_domain_cmd_group = CliCommandType( + operations_tmpl='azext_spring_cloud.api_portal#{}', + client_factory=cf_spring_cloud_enterprise + ) + buildpacks_binding_cmd_group = CliCommandType( operations_tmpl="azext_spring_cloud.buildpacks_binding#{}", client_factory=cf_spring_cloud_enterprise @@ -187,7 +213,8 @@ def load_command_table(self, _): with self.command_group('spring-cloud application-configuration-service', custom_command_type=application_configuration_service_cmd_group, - exception_handler=handle_asc_exception) as g: + exception_handler=handle_asc_exception, + is_preview=True) as g: g.custom_command('clear', 'application_configuration_service_clear') g.custom_command('show', 'application_configuration_service_show') g.custom_command('bind', 'application_configuration_service_bind') @@ -201,6 +228,53 @@ def load_command_table(self, _): g.custom_command('remove', 'application_configuration_service_git_remove') g.custom_command('list', 'application_configuration_service_git_list') + with self.command_group('spring-cloud gateway', + custom_command_type=gateway_cmd_group, + exception_handler=handle_asc_exception, + is_preview=True) as g: + g.custom_command('show', 'gateway_show') + g.custom_command('update', 'gateway_update', validator=validate_gateway_update) + g.custom_command('clear', 'gateway_clear') + + with self.command_group('spring-cloud gateway custom-domain', + custom_command_type=gateway_custom_domain_cmd_group, + exception_handler=handle_asc_exception) as g: + g.custom_show_command('show', 'gateway_custom_domain_show', + table_transformer=transform_spring_cloud_custom_domain_output) + g.custom_command('list', 'gateway_custom_domain_list', + table_transformer=transform_spring_cloud_custom_domain_output) + g.custom_command('bind', 'gateway_custom_domain_update') + g.custom_command('unbind', 'gateway_custom_domain_unbind') + g.custom_command('update', 'gateway_custom_domain_update') + + with self.command_group('spring-cloud gateway route-config', + custom_command_type=gateway_route_config_cmd_group, + exception_handler=handle_asc_exception) as g: + g.custom_command('show', 'gateway_route_config_show') + g.custom_command('list', 'gateway_route_config_list') + g.custom_command('create', 'gateway_route_config_create') + g.custom_command('update', 'gateway_route_config_update') + g.custom_command('remove', 'gateway_route_config_remove') + + with self.command_group('spring-cloud api-portal', + custom_command_type=api_portal_cmd_group, + exception_handler=handle_asc_exception, + is_preview=True) as g: + g.custom_command('show', 'api_portal_show') + g.custom_command('update', 'api_portal_update', validator=validate_api_portal_update) + g.custom_command('clear', 'api_portal_clear') + + with self.command_group('spring-cloud api-portal custom-domain', + custom_command_type=api_portal_custom_domain_cmd_group, + exception_handler=handle_asc_exception) as g: + g.custom_show_command('show', 'api_portal_custom_domain_show', + table_transformer=transform_spring_cloud_custom_domain_output) + g.custom_command('list', 'api_portal_custom_domain_list', + table_transformer=transform_spring_cloud_custom_domain_output) + g.custom_command('bind', 'api_portal_custom_domain_update') + g.custom_command('unbind', 'api_portal_custom_domain_unbind') + g.custom_command('update', 'api_portal_custom_domain_update') + with self.command_group('spring-cloud build-service buildpacks-binding', custom_command_type=buildpacks_binding_cmd_group, exception_handler=handle_asc_exception) as g: diff --git a/src/spring-cloud/azext_spring_cloud/gateway.py b/src/spring-cloud/azext_spring_cloud/gateway.py new file mode 100644 index 0000000000..9c801bbb8f --- /dev/null +++ b/src/spring-cloud/azext_spring_cloud/gateway.py @@ -0,0 +1,215 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import json +from .vendored_sdks.appplatform.v2022_01_01_preview import models +from ._resource_quantity import validate_cpu, validate_memory +from knack.util import CLIError + +DEFAULT_NAME = "default" + +def gateway_update(cmd, client, resource_group, service, + cpu=None, + memory=None, + instance_count=None, + assign_endpoint=None, + https_only=None, + scope=None, + client_id=None, + client_secret=None, + issuer_uri=None, + api_title=None, + api_description=None, + api_documentation_location=None, + api_version=None, + server_url=None, + allowed_origins=None, + allowed_methods=None, + allowed_headers=None, + max_age=None, + allow_credentials=None, + exposed_headers=None + ): + gateway = client.gateways.get(resource_group, service, DEFAULT_NAME) + + sso_properties = gateway.properties.sso_properties + if scope and client_id and client_secret and issuer_uri: + sso_properties = models.SsoProperties( + scope=scope, + client_id=client_id, + client_secret=client_secret, + issuer_uri=issuer_uri, + ) + + api_metadata_properties = _update_api_metadata( + gateway.properties.api_metadata_properties, api_title, api_description, api_documentation_location, api_version, server_url) + + cors_properties = _update_cors( + gateway.properties.cors_properties, allowed_origins, allowed_methods, allowed_headers, max_age, allow_credentials, exposed_headers) + + resource_requests = models.GatewayResourceRequests( + cpu=cpu or gateway.properties.resource_requests.cpu, + memory=memory or gateway.properties.resource_requests.memory + ) + + properties = models.GatewayProperties( + public=assign_endpoint if assign_endpoint is not None else gateway.properties.public, + https_only=https_only if https_only is not None else gateway.properties.https_only, + sso_properties=sso_properties, + api_metadata_properties=api_metadata_properties, + cors_properties=cors_properties, + resource_requests=resource_requests) + + sku = models.Sku(name=gateway.sku.name, tier=gateway.sku.tier, + capacity=instance_count or gateway.sku.capacity) + + gateway_resource = models.GatewayResource(properties=properties, sku=sku) + return client.gateways.begin_create_or_update(resource_group, service, DEFAULT_NAME, gateway_resource) + + +def gateway_show(cmd, client, resource_group, service): + return client.gateways.get(resource_group, service, DEFAULT_NAME) + + +def gateway_clear(cmd, client, resource_group, service): + gateway = client.gateways.get(resource_group, service, DEFAULT_NAME) + properties = models.GatewayProperties() + sku = models.Sku(name=gateway.sku.name, tier=gateway.sku.tier) + gateway_resource = models.GatewayResource(properties=properties, sku=sku) + return client.gateways.begin_create_or_update(resource_group, service, DEFAULT_NAME, gateway_resource) + + +def gateway_custom_domain_show(cmd, client, resource_group, service, domain_name): + return client.gateway_custom_domains.get(resource_group, service, DEFAULT_NAME, domain_name) + + +def gateway_custom_domain_list(cmd, client, resource_group, service): + return client.gateway_custom_domains.list(resource_group, service, DEFAULT_NAME) + + +def gateway_custom_domain_update(cmd, client, resource_group, service, + domain_name, + certificate=None): + properties = models.GatewayCustomDomainProperties() + if certificate is not None: + certificate_response = client.gateways.certificates.get( + resource_group, service, certificate) + properties.thumbprint = certificate_response.properties.thumbprint + + custom_domain_resource = models.GatewayCustomDomainResource( + properties=properties) + return client.gateway_custom_domains.begin_create_or_update(resource_group, service, DEFAULT_NAME, + domain_name, custom_domain_resource) + + +def gateway_custom_domain_unbind(cmd, client, resource_group, service, domain_name): + client.gateway_custom_domains.get(resource_group, service, + DEFAULT_NAME, domain_name) + return client.gateway_custom_domains.begin_delete(resource_group, service, DEFAULT_NAME, domain_name) + + +def gateway_route_config_show(cmd, client, resource_group, service, name): + return client.gateway_route_configs.get(resource_group, service, DEFAULT_NAME, name) + + +def gateway_route_config_list(cmd, client, resource_group, service): + return client.gateway_route_configs.list(resource_group, service, DEFAULT_NAME) + + +def gateway_route_config_create(cmd, client, resource_group, service, name, + app_name=None, + routes_json=None, + routes_file=None): + _validate_route_config_exist(client, resource_group, service, name) + + app_resource_id = _update_app_resource_id(client, resource_group, service, app_name, None) + routes = _update_routes(routes_file, routes_json, []) + + return _create_or_update_gateway_route_configs(client, resource_group, service, name, app_resource_id, routes) + + +def gateway_route_config_update(cmd, client, resource_group, service, name, + app_name=None, + routes_json=None, + routes_file=None): + gateway_route_config = client.gateway_route_configs.get( + resource_group, service, DEFAULT_NAME, name) + + app_resource_id = _update_app_resource_id(client, resource_group, service, app_name, gateway_route_config.properties.app_resource_id) + routes = _update_routes(routes_file, routes_json, gateway_route_config.properties.routes) + + return _create_or_update_gateway_route_configs(client, resource_group, service, name, app_resource_id, routes) + + +def gateway_route_config_remove(cmd, client, resource_group, service, name): + return client.gateway_route_configs.begin_delete(resource_group, service, DEFAULT_NAME, name) + + +def _update_api_metadata(existing, api_title, api_description, api_documentation_location, version, server_url): + if api_title is None and api_description is None and api_documentation_location is None and version is None and server_url is None: + return None + api_metadata = models.GatewayApiMetadataProperties() if existing is None else existing + if api_title: + api_metadata.title = api_title + if api_description: + api_metadata.description = api_description + if api_documentation_location: + api_metadata.documentation = api_documentation_location + if version: + api_metadata.version = version + if server_url: + api_metadata.server_url = server_url + return api_metadata + + +def _update_cors(existing, allowed_origins, allowed_methods, allowed_headers, max_age, allow_credentials, exposed_headers): + if allowed_origins is None and allowed_methods is None and allowed_headers is None and max_age is None and allow_credentials is None and exposed_headers is None: + return None + cors = existing if existing is not None else models.GatewayCorsProperties() + if allowed_origins: + cors.allowed_origins = allowed_origins.split(",") + if allowed_methods: + cors.allowed_methods = allowed_methods.split(",") + if allowed_headers: + cors.allowed_headers = allowed_headers.split(",") + if max_age: + cors.max_age = max_age + if allow_credentials is not None: + cors.allow_credentials = allow_credentials + if exposed_headers: + cors.exposed_headers = exposed_headers.split(",") + return cors + + +def _validate_route_config_exist(client, resource_group, service, name): + route_configs = client.gateway_route_configs.list( + resource_group, service, DEFAULT_NAME) + if name in (route_config.name for route_config in list(route_configs)): + raise CLIError("Route config " + name + " already exists") + + +def _update_app_resource_id(client, resource_group, service, app_name, app_resource_id): + if app_name is not None: + app_resource = client.apps.get(resource_group, service, app_name) + app_resource_id = app_resource.id + return app_resource_id + + +def _update_routes(routes_file, routes_json, rotues): + if routes_file is not None: + with open(routes_file, 'r') as json_file: + routes = json.load(json_file) + + if routes_json is not None: + routes = json.loads(routes_json) + return routes + + +def _create_or_update_gateway_route_configs(client, resource_group, service, name, app_resource_id, routes): + properties = models.GatewayRouteConfigProperties( + app_resource_id=app_resource_id, routes=routes) + route_config_resource = models.GatewayRouteConfigResource( + properties=properties) + return client.gateway_route_configs.begin_create_or_update(resource_group, service, DEFAULT_NAME, name, route_config_resource)