Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Spring Cloud] Integrate tanzu components with service and app #4300

Merged
merged 17 commits into from
Jan 11, 2022
25 changes: 24 additions & 1 deletion src/spring-cloud/azext_spring_cloud/_deployment_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
from ._deployment_source_factory import source_selector


APPLICATION_CONFIGURATION_SERVICE_NAME = "applicationConfigurationService"
APPLICATION_CONFIGURATION_SERVICE_PROPERTY_PATTERN = "configFilePatterns"


class DefaultDeployment:
def __init__(self, **kwargs):
self.source_factory = source_selector(**kwargs)
Expand All @@ -32,7 +36,8 @@ def format_settings(self, **kwargs):
return models.DeploymentSettings(
resource_requests=self._format_resource_request(**kwargs),
container_probe_settings=self._format_container_probe(**kwargs),
environment_variables=self._get_env(**kwargs)
environment_variables=self._get_env(**kwargs),
addon_configs=self._get_addon_configs(**kwargs)
)

def _format_container_probe(self, disable_probe=None, **_):
Expand All @@ -53,6 +58,16 @@ def _format_resource_request(self, cpu=None, memory=None, **_):
def _get_env(self, env, **_):
return env

def _get_addon_configs(self, config_file_patterns=None, **_):
if config_file_patterns is not None:
addon_configs = {
APPLICATION_CONFIGURATION_SERVICE_NAME: {
APPLICATION_CONFIGURATION_SERVICE_PROPERTY_PATTERN: config_file_patterns
}
}
return addon_configs
return None

def format_source(self, **kwargs):
return self.source_factory.format_source(**kwargs)

Expand Down Expand Up @@ -113,12 +128,20 @@ def deployment_settings_options_from_resource(original):
'instance_count': original.sku.capacity,
'sku': original.sku,
'env': original.properties.deployment_settings.environment_variables,
'config_file_patterns': _get_origin_config_file_patterns(original.properties.deployment_settings.addon_configs)
}
if original.properties.deployment_settings.container_probe_settings is not None:
options['disable_probe'] = original.properties.deployment_settings.container_probe_settings.disable_probe
return options


def _get_origin_config_file_patterns(origin_addon_configs):
if origin_addon_configs:
acs_addon = origin_addon_configs.get(APPLICATION_CONFIGURATION_SERVICE_NAME)
return acs_addon.get(APPLICATION_CONFIGURATION_SERVICE_PROPERTY_PATTERN) if acs_addon is not None else None
return None


def deployment_source_options_from_resource(original):
'''
Construct the options about deployment source from original resource.
Expand Down
5 changes: 5 additions & 0 deletions src/spring-cloud/azext_spring_cloud/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
az provider register -n Microsoft.SaaS
az term accept --publisher vmware-inc --product azure-spring-cloud-vmware-tanzu-2 --plan tanzu-asc-ent-mtr
az spring-cloud create -n MyService -g MyResourceGroup --sku Enterprise
- name: Create a Azure Spring Cloud Enterprise instance with Tanzu components enabled.
text: |
az spring-cloud create -n MyService -g MyResourceGroup --sku Enterprise --enable-application-configuration-service --enable-service-registry --enable-gateway --enable-api-portal
"""

helps['spring-cloud update'] = """
Expand Down Expand Up @@ -227,6 +230,8 @@
text: az spring-cloud app deploy -n MyApp -s MyCluster -g MyResourceGroup --container-image contoso/your-app:v1
- name: Deploy a container image on a private registry to an app.
text: az spring-cloud app deploy -n MyApp -s MyCluster -g MyResourceGroup --container-image contoso/your-app:v1 --container-registry myacr.azurecr.io --registry-username <username> --registry-password <password>
- name: Deploy with Application Configuration Service config file patterns to an app.
text: az spring-cloud app deploy -n MyApp -s MyCluster -g MyResourceGroup --config-file-patterns MyPatterns --jar-path app.jar
"""

helps['spring-cloud app scale'] = """
Expand Down
45 changes: 44 additions & 1 deletion src/spring-cloud/azext_spring_cloud/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
validate_tracing_parameters_asc_create, validate_tracing_parameters_asc_update,
validate_app_insights_parameters, validate_instance_count, validate_java_agent_parameters,
validate_jar)
from ._validators_enterprise import (only_support_enterprise, validate_git_uri, validate_acs_patterns, validate_routes,
from ._validators_enterprise import (only_support_enterprise,
validate_git_uri, validate_acs_patterns, validate_config_file_patterns,
validate_routes, validate_gateway_instance_count,
validate_api_portal_instance_count,
validate_buildpack_binding_exist, validate_buildpack_binding_not_exist,
validate_buildpack_binding_properties, validate_buildpack_binding_secrets)
from ._app_validator import (fulfill_deployment_param, active_deployment_exist, active_deployment_exist_under_app,
Expand Down Expand Up @@ -96,6 +99,39 @@ def load_arguments(self, _):
help="Create your Azure Spring Cloud service in an Azure availability zone or not, "
"this could only be supported in several regions at the moment.",
default=False, is_preview=True)
c.argument('enable_application_configuration_service',
action='store_true',
is_preview=True,
options_list=['--enable-application-configuration-service', '--enable-acs'],
help='(Enterprise Tier Only) Enable Application Configuration Service.')
c.argument('enable_service_registry',
action='store_true',
is_preview=True,
options_list=['--enable-service-registry', '--enable-sr'],
help='(Enterprise Tier Only) Enable Service Registry.')
c.argument('enable_gateway',
arg_group="Spring Cloud Gateway",
action='store_true',
is_preview=True,
help='(Enterprise Tier Only) Enable Spring Cloud Gateway.')
c.argument('gateway_instance_count',
arg_group="Spring Cloud Gateway",
type=int,
validator=validate_gateway_instance_count,
is_preview=True,
help='(Enterprise Tier Only) Number of Spring Cloud Gateway instances.')
c.argument('enable_api_portal',
arg_group="API portal",
action='store_true',
is_preview=True,
help='(Enterprise Tier Only) Enable API portal.')
c.argument('api_portal_instance_count',
arg_group="API portal",
type=int,
validator=validate_api_portal_instance_count,
is_preview=True,
options_list=['--api-portal-instance-count', '--ap-instance'],
help='(Enterprise Tier Only) Number of API portal instances.')

with self.argument_context('spring-cloud update') as c:
c.argument('sku', arg_type=sku_type)
Expand Down Expand Up @@ -223,6 +259,13 @@ def prepare_logs_argument(c):
c.argument('env', env_type)
c.argument('disable_probe', arg_type=get_three_state_flag(), help='If true, disable the liveness and readiness probe.')

for scope in ['update', 'deployment create', 'deploy']:
with self.argument_context('spring-cloud app {}'.format(scope)) as c:
c.argument('config_file_patterns',
help="(Enterprise Tier Only) Config file patterns separated with \',\' to decide which patterns "
"of Application Configuration Service will be used. Use '\"\"' to clear existing configurations.",
validator=validate_config_file_patterns, is_preview=True)

with self.argument_context('spring-cloud app scale') as c:
c.argument('cpu', arg_type=cpu_type)
c.argument('memory', arg_type=memort_type)
Expand Down
63 changes: 63 additions & 0 deletions src/spring-cloud/azext_spring_cloud/_tanzu_component.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

# pylint: disable=too-few-public-methods, unused-argument, redefined-builtin

from azure.cli.core.commands.client_factory import get_subscription_id
from knack.log import get_logger
from msrestazure.tools import resource_id

from .vendored_sdks.appplatform.v2022_01_01_preview import models

GATEWAY_RESOURCE_TYPE = "gateways"
DEFAULT_NAME = "default"
logger = get_logger(__name__)


def create_application_configuration_service(cmd, client, resource_group, service, enable_application_configuration_service, **_):
if enable_application_configuration_service:
logger.warning(" - Creating Application Configuration Service ..")
acs_resource = models.ConfigurationServiceResource()
return client.configuration_services.begin_create_or_update(resource_group, service, DEFAULT_NAME, acs_resource)


def create_service_registry(cmd, client, resource_group, service, enable_service_registry, **_):
if enable_service_registry:
logger.warning(" - Creating Service Registry ..")
return client.service_registries.begin_create_or_update(resource_group, service, DEFAULT_NAME)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no service registry body, is this on purpose?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's expected



def create_gateway(cmd, client, resource_group, service, enable_gateway, gateway_instance_count=None, sku=None, **_):
if enable_gateway:
logger.warning(" - Creating Spring Cloud Gateway ..")
gateway_resource = models.GatewayResource()
if gateway_instance_count and sku:
gateway_resource.sku = models.Sku(name=sku.name, tier=sku.tier,
capacity=gateway_instance_count)
return client.gateways.begin_create_or_update(resource_group, service, DEFAULT_NAME, gateway_resource)


def create_api_portal(cmd, client, resource_group, service, enable_api_portal, api_portal_instance_count=None, sku=None, **_):
if enable_api_portal:
logger.warning(" - Creating API portal ..")
gateway_id = resource_id(
subscription=get_subscription_id(cmd.cli_ctx),
resource_group=resource_group,
namespace='Microsoft.AppPlatform',
type='Spring',
name=service,
child_type_1=GATEWAY_RESOURCE_TYPE,
child_name_1=DEFAULT_NAME
)

api_portal_resource = models.ApiPortalResource(
properties=models.ApiPortalProperties(
gateway_ids=[gateway_id]
)
)
if api_portal_instance_count and sku:
api_portal_resource.sku = models.Sku(name=sku.name, tier=sku.tier,
capacity=api_portal_instance_count)
return client.api_portals.begin_create_or_update(resource_group, service, DEFAULT_NAME, api_portal_resource)
2 changes: 1 addition & 1 deletion src/spring-cloud/azext_spring_cloud/_transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def _parse_item_resource_id(addon, key, secondary):
if not resource_id:
return None
resource_dict = parse_resource_id(resource_id)
return resource_dict.get('name', '')
return resource_dict.get('resource_name', '')


def transform_spring_cloud_deployment_output(result):
Expand Down
16 changes: 15 additions & 1 deletion src/spring-cloud/azext_spring_cloud/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from azure.cli.core import telemetry
from azure.cli.core.commands.client_factory import get_subscription_id
from azure.cli.core.commands.validators import validate_tag
from azure.cli.core.azclierror import InvalidArgumentValueError
from azure.cli.core.azclierror import ArgumentUsageError, InvalidArgumentValueError
from knack.validators import DefaultStr
from azure.mgmt.core.tools import is_valid_resource_id
from azure.mgmt.core.tools import parse_resource_id
Expand Down Expand Up @@ -46,6 +46,8 @@ def validate_sku(cmd, namespace):
if namespace.sku.lower() == 'enterprise':
_validate_saas_provider(cmd, namespace)
_validate_terms(cmd, namespace)
else:
_check_tanzu_components_not_enable(cmd, namespace)
namespace.sku = models.Sku(name=_get_sku_name(namespace.sku), tier=namespace.sku)


Expand Down Expand Up @@ -73,6 +75,18 @@ def _validate_terms(cmd, namespace):
'--plan tanzu-asc-ent-mtr" to accept the term.')


def _check_tanzu_components_not_enable(cmd, namespace):
suffix = 'can only be used for Azure Spring Cloud Enterprise. Please add --sku="Enterprise" to create Enterprise instance.'
if namespace.enable_application_configuration_service:
raise ArgumentUsageError('--enable-application-configuration-service {}'.format(suffix))
if namespace.enable_service_registry:
raise ArgumentUsageError('--enable-service-registry {}'.format(suffix))
if namespace.enable_gateway:
raise ArgumentUsageError('--enable-gateway {}'.format(suffix))
if namespace.enable_api_portal:
raise ArgumentUsageError('--enable-api-portal {}'.format(suffix))


def validate_instance_count(namespace):
if namespace.instance_count is not None:
if namespace.instance_count < 1:
Expand Down
8 changes: 6 additions & 2 deletions src/spring-cloud/azext_spring_cloud/_validators_enterprise.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,18 @@ def validate_routes(namespace):

def validate_gateway_instance_count(namespace):
if namespace.gateway_instance_count is not None:
if namespace.enable_gateway is False:
raise ArgumentUsageError("--gateway-instance-count can only be set when enable gateway.")
if namespace.gateway_instance_count < 1:
raise InvalidArgumentValueError("--gateway-instance-count must be greater than 0")
raise ArgumentUsageError("--gateway-instance-count must be greater than 0")


def validate_api_portal_instance_count(namespace):
if namespace.api_portal_instance_count is not None:
if namespace.enable_api_portal is False:
raise ArgumentUsageError("--api-portal-instance-count can only be set when enable API portal.")
if namespace.api_portal_instance_count < 1:
raise InvalidArgumentValueError("--api-portal-instance-count must be greater than 0")
raise ArgumentUsageError("--api-portal-instance-count must be greater than 0")


def validate_buildpack_binding_properties(namespace):
Expand Down
2 changes: 1 addition & 1 deletion src/spring-cloud/azext_spring_cloud/api_portal.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def api_portal_update(cmd, client, resource_group, service,

def api_portal_clear(cmd, client, resource_group, service):
api_portal = client.api_portals.get(resource_group, service, DEFAULT_NAME)
properties = models.GatewayProperties(
properties = models.ApiPortalProperties(
gateway_ids=api_portal.properties.gateway_ids
)

Expand Down
6 changes: 6 additions & 0 deletions src/spring-cloud/azext_spring_cloud/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ def app_update(cmd, client, resource_group, service, name,
# deployment.settings
env=None,
disable_probe=None,
config_file_patterns=None,
# general
no_wait=False):
'''app_update
Expand All @@ -156,6 +157,7 @@ def app_update(cmd, client, resource_group, service, name,

deployment_kwargs = {
'disable_probe': disable_probe,
'config_file_patterns': config_file_patterns,
'env': env,
'runtime_version': runtime_version,
'jvm_options': jvm_options,
Expand Down Expand Up @@ -213,6 +215,7 @@ def app_deploy(cmd, client, resource_group, service, name,
# deployment.settings
env=None,
disable_probe=None,
config_file_patterns=None,
# general
no_wait=False):
'''app_deploy
Expand All @@ -236,6 +239,7 @@ def app_deploy(cmd, client, resource_group, service, name,
'deployment_resource': deployment,
'sku': deployment.sku,
'disable_probe': disable_probe,
'config_file_patterns': config_file_patterns,
'env': env,
'runtime_version': runtime_version,
'jvm_options': jvm_options,
Expand Down Expand Up @@ -300,6 +304,7 @@ def deployment_create(cmd, client, resource_group, service, app, name,
instance_count=None,
env=None,
disable_probe=None,
config_file_patterns=None,
# general
no_wait=False):
'''deployment_create
Expand All @@ -321,6 +326,7 @@ def deployment_create(cmd, client, resource_group, service, app, name,
'app': app,
'deployment': name,
'disable_probe': disable_probe,
'config_file_patterns': config_file_patterns,
'env': env,
'runtime_version': runtime_version,
'jvm_options': jvm_options,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from azure.cli.core.azclierror import ClientRequestError, ValidationError
from azure.cli.core.commands.client_factory import get_subscription_id
from azure.cli.core.util import sdk_no_wait
from azure.core.exceptions import ResourceNotFoundError
from knack.log import get_logger
from msrestazure.tools import resource_id

Expand All @@ -29,6 +28,7 @@ def application_configuration_service_show(cmd, client, service, resource_group)


def application_configuration_service_clear(cmd, client, service, resource_group):
logger.warn("Please make sure no patterns are used in your apps.")
properties = models.ConfigurationServiceGitProperty()
acs_resource = models.ConfigurationServiceResource(properties=properties)
return client.configuration_services.begin_create_or_update(resource_group, service, DEFAULT_NAME, acs_resource)
Expand Down
2 changes: 1 addition & 1 deletion src/spring-cloud/azext_spring_cloud/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ def load_command_table(self, _):
is_preview=True) as g:
g.custom_show_command('show', 'gateway_show', table_transformer=transform_spring_cloud_gateway_output)
g.custom_command('update', 'gateway_update', validator=validate_gateway_update, supports_no_wait=True)
g.custom_command('clear', 'gateway_clear')
g.custom_command('clear', 'gateway_clear', supports_no_wait=True)

with self.command_group('spring-cloud gateway custom-domain',
custom_command_type=gateway_custom_domain_cmd_group,
Expand Down
11 changes: 7 additions & 4 deletions src/spring-cloud/azext_spring_cloud/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,15 @@ 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):
def gateway_clear(cmd, client, resource_group, service, no_wait=False):
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)

logger.warning(LOG_RUNNING_PROMPT)
return sdk_no_wait(no_wait, 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):
Expand Down Expand Up @@ -159,7 +162,7 @@ def gateway_route_config_remove(cmd, client, resource_group, service, name):

def _update_api_metadata(existing, api_title, api_description, api_documentation_location, version, server_url):
if not any([api_title, api_description, api_documentation_location, version, server_url]):
return None
return existing
api_metadata = models.GatewayApiMetadataProperties() if existing is None else existing
if api_title:
api_metadata.title = api_title
Expand All @@ -176,7 +179,7 @@ def _update_api_metadata(existing, api_title, api_description, api_documentation

def _update_cors(existing, allowed_origins, allowed_methods, allowed_headers, max_age, allow_credentials, exposed_headers):
if not any([allowed_origins, allowed_methods, allowed_headers, max_age, allow_credentials, exposed_headers]):
return None
return existing
cors = existing if existing is not None else models.GatewayCorsProperties()
if allowed_origins:
cors.allowed_origins = allowed_origins.split(",")
Expand Down
Loading