Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/spring/HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
Release History
===============
1.19.3
---
* Add arguments `--refresh-interval` in `spring application-configuration-service create` and `spring application-configuration-service update`.

1.19.2
---
Expand Down
7 changes: 6 additions & 1 deletion src/spring/azext_spring/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
validate_buildpack_binding_exist, validate_buildpack_binding_not_exist,
validate_buildpack_binding_properties, validate_buildpack_binding_secrets,
validate_build_env, validate_target_module, validate_runtime_version,
validate_acs_ssh_or_warn, validate_apm_properties, validate_apm_secrets,
validate_acs_ssh_or_warn, validate_refresh_interval,
validate_apm_properties, validate_apm_secrets,
validate_apm_not_exist, validate_apm_update, validate_apm_reference,
validate_apm_reference_and_enterprise_tier, validate_cert_reference,
validate_build_cert_reference, validate_acs_create, not_support_enterprise,
Expand Down Expand Up @@ -864,6 +865,10 @@ def prepare_logs_argument(c):
for scope in ['create', 'update']:
with self.argument_context('spring application-configuration-service {}'.format(scope)) as c:
c.argument('generation', arg_type=get_enum_type(ConfigurationServiceGeneration), help='Generation of Application Configuration Service.')
c.argument('refresh_interval', type=int,
validator=validate_refresh_interval,
help='Specify the interval (in seconds) for refreshing the repository. '
'Use 0 to turn off automatic refresh. An interval of at least 60 seconds is recommended.')

for scope in ['add', 'update']:
with self.argument_context('spring application-configuration-service git repo {}'.format(scope)) as c:
Expand Down
9 changes: 9 additions & 0 deletions src/spring/azext_spring/_validators_enterprise.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,15 @@ def validate_acs_create(namespace):
raise ArgumentUsageError("--application-configuration-service-generation can only be set when enable application configuration service.")


def validate_refresh_interval(namespace):
if namespace.refresh_interval:
if not isinstance(namespace.refresh_interval, int):
raise InvalidArgumentValueError("--refresh-interval should be a number.")

if namespace.refresh_interval < 0:
raise ArgumentUsageError("--refresh-interval must be greater than or equal to 0.")


def validate_gateway_update(cmd, namespace):
_validate_gateway_response_cache(namespace)
_validate_sso(namespace)
Expand Down
9 changes: 7 additions & 2 deletions src/spring/azext_spring/application_configuration_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,20 @@


def application_configuration_service_create(cmd, client, service, resource_group,
generation=None):
generation=None, refresh_interval=None):
if generation is None:
generation = ConfigurationServiceGeneration.GEN1

properties = models.ConfigurationServiceProperties(generation=generation)
if refresh_interval is not None:
properties.settings = models.ConfigurationServiceSettings(refresh_interval_in_seconds=refresh_interval)
acs_resource = models.ConfigurationServiceResource(properties=properties)
logger.warning("Create with generation {}".format(acs_resource.properties.generation))
return client.configuration_services.begin_create_or_update(resource_group, service, DEFAULT_NAME, acs_resource)


def application_configuration_service_update(cmd, client, service, resource_group,
generation=None):
generation=None, refresh_interval=None):
acs_resource = client.configuration_services.get(resource_group, service, DEFAULT_NAME)
if generation is not None:
acs_resource.properties.generation = generation
Expand All @@ -44,6 +46,9 @@ def application_configuration_service_update(cmd, client, service, resource_grou
acs_resource.properties.generation = ConfigurationServiceGeneration.GEN1
logger.warning("Default generation will be Gen1")
logger.warning(acs_resource.properties.generation)
if refresh_interval is not None:
acs_resource.properties.settings = acs_resource.properties.settings or models.ConfigurationServiceSettings()
acs_resource.properties.settings.refresh_interval_in_seconds = refresh_interval
return client.configuration_services.begin_create_or_update(resource_group, service, DEFAULT_NAME, acs_resource)


Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,94 +2,89 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from azure.cli.testsdk import (ScenarioTest)
from azure.cli.testsdk.reverse_dependency import (
get_dummy_cli,
)
from .custom_preparers import (SpringPreparer, SpringResourceGroupPreparer, SpringAppNamePreparer,
SpringSubResourceWrapper)
from .custom_dev_setting_constant import SpringTestEnvironmentEnum


# pylint: disable=line-too-long
# pylint: disable=too-many-lines

class TearDown(SpringSubResourceWrapper):
def __init__(self,
resource_group_parameter_name='resource_group',
spring_parameter_name='spring'):
super(TearDown, self).__init__()
self.cli_ctx = get_dummy_cli()
self.resource_group_parameter_name = resource_group_parameter_name
self.spring_parameter_name = spring_parameter_name

def create_resource(self, *_, **kwargs):
self.resource_group = self._get_resource_group(**kwargs)
self.spring = self._get_spring(**kwargs)

def remove_resource(self, *_, **__):
self.live_only_execute(self.cli_ctx,
'spring application-configuration-service delete -g {} -s {} --yes'.format(
self.resource_group, self.spring))
self.live_only_execute(self.cli_ctx, 'spring application-configuration-service create -g {} -s {}'.format(
self.resource_group, self.spring))


class ApplicationConfigurationServiceTest(ScenarioTest):

@SpringResourceGroupPreparer(
dev_setting_name=SpringTestEnvironmentEnum.ENTERPRISE_WITH_TANZU['resource_group_name'])
@SpringPreparer(**SpringTestEnvironmentEnum.ENTERPRISE_WITH_TANZU['spring'])
@SpringAppNamePreparer()
@TearDown()
def test_application_configuration_service(self, resource_group, spring, app):
self.kwargs.update({
'serviceName': spring,
'rg': resource_group,
'repo': "repo1",
"label": "main",
"patterns": "api-gateway,customers-service",
"uri": "https://github.com/spring-petclinic/spring-petclinic-microservices-config",
"app": app
})

self.cmd('spring app create -g {rg} -s {serviceName} -n {app}')

self.cmd('spring application-configuration-service show -g {rg} -s {serviceName}', checks=[
self.check('properties.provisioningState', "Succeeded")
])

self.cmd('spring application-configuration-service git repo add -g {rg} -s {serviceName} '
'-n {repo} --label {label} --patterns {patterns} --uri {uri}',
checks=[self.check('properties.provisioningState', "Succeeded")])

self.cmd('spring application-configuration-service git repo update -g {rg} -s {serviceName} '
'-n {repo} --label {label}',
checks=[self.check('properties.provisioningState', "Succeeded")])

result = self.cmd(
'spring application-configuration-service git repo list -g {rg} -s {serviceName}').get_output_in_json()
self.assertTrue(len(result) > 0)

self.cmd('spring application-configuration-service git repo remove --name {repo} -g {rg} -s {serviceName}')
result = self.cmd(
'spring application-configuration-service git repo list -g {rg} -s {serviceName}').get_output_in_json()
self.assertTrue(len(result) == 0)

self.cmd('spring application-configuration-service bind --app {app} -g {rg} -s {serviceName}', checks=[
self.check('properties.addonConfigs.applicationConfigurationService.resourceId',
"/subscriptions/{}/resourceGroups/{}/providers/Microsoft.AppPlatform/Spring/{}/configurationServices/default".format(
self.get_subscription_id(), resource_group, spring))
])

self.cmd('spring app show -n {app} -g {rg} -s {serviceName}')

self.cmd('spring application-configuration-service unbind --app {app} -g {rg} -s {serviceName}')

self.cmd('spring application-configuration-service clear -g {rg} -s {serviceName}', checks=[
self.check('properties.provisioningState', "Succeeded")
])

self.cmd('spring application-configuration-service update -g {rg} -s {serviceName} --generation Gen2',
checks=[self.check('properties.provisioningState', "Succeeded")])
from ...application_configuration_service import (application_configuration_service_create,
application_configuration_service_update)

import unittest
from argparse import Namespace
from azure.cli.core.azclierror import InvalidArgumentValueError, ArgumentUsageError
from ..._validators_enterprise import validate_refresh_interval
try:
import unittest.mock as mock
except ImportError:
from unittest import mock

from azure.cli.core.mock import DummyCli
from azure.cli.core import AzCommandsLoader
from azure.cli.core.commands import AzCliCommand

from knack.log import get_logger

logger = get_logger(__name__)
free_mock_client = mock.MagicMock()


def _get_test_cmd():
cli_ctx = DummyCli()
cli_ctx.data['subscription_id'] = '00000000-0000-0000-0000-000000000000'
loader = AzCommandsLoader(cli_ctx, resource_type='Microsoft.AppPlatform')
cmd = AzCliCommand(loader, 'test', None)
cmd.command_kwargs = {'resource_type': 'Microsoft.AppPlatform'}
cmd.cli_ctx = cli_ctx
return cmd


def _cf_resource_group(cli_ctx, subscription_id=None):
client = mock.MagicMock()
rg = mock.MagicMock()
rg.location = 'east us'
client.resource_groups.get.return_value = rg
return client


def _get_basic_mock_client(*_):
return mock.MagicMock()


class BasicTest(unittest.TestCase):
def __init__(self, methodName: str = ...):
super().__init__(methodName=methodName)
self.created_resource = None

def setUp(self):
resp = super().setUp()
free_mock_client.reset_mock()
return resp

@mock.patch('azext_spring._utils.cf_resource_groups', _cf_resource_group)
def _execute(self, resource_group, generation, refresh_interval, **kwargs):
client = kwargs.pop('client', None) or _get_basic_mock_client()
application_configuration_service_create(_get_test_cmd(), client, 'myasa',
resource_group, generation, refresh_interval)
call_args = client.configuration_services.begin_create_or_update.call_args_list
self.assertEqual(1, len(call_args))
self.assertEqual(4, len(call_args[0][0]))
self.assertEqual((resource_group, generation),
(call_args[0][0][0], call_args[0][0][3].properties.generation))
self.created_resource = call_args[0][0][3]


class TestApplicationConfigurationService(BasicTest):
def test_acs_create(self):
self._execute('rg', 'Gen1', 120)
resource = self.created_resource
self.assertIsNotNone(resource.properties)
self.assertEqual(120, resource.properties.settings.refresh_interval_in_seconds)


class TestApplicationConfigurationServiceValidator(unittest.TestCase):
def test_validate_refresh_interval_parameter(self):
ns = Namespace(refresh_interval="a")
with self.assertRaises(InvalidArgumentValueError) as context:
validate_refresh_interval(ns)
self.assertEqual("--refresh-interval should be a number.", str(context.exception))

ns = Namespace(refresh_interval=-1)
with self.assertRaises(ArgumentUsageError) as context:
validate_refresh_interval(ns)
self.assertEqual("--refresh-interval must be greater than or equal to 0.", str(context.exception))
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from azure.cli.testsdk import (ScenarioTest)
from azure.cli.testsdk.reverse_dependency import (
get_dummy_cli,
)
from .custom_preparers import (SpringPreparer, SpringResourceGroupPreparer, SpringAppNamePreparer,
SpringSubResourceWrapper)
from .custom_dev_setting_constant import SpringTestEnvironmentEnum


# pylint: disable=line-too-long
# pylint: disable=too-many-lines

class TearDown(SpringSubResourceWrapper):
def __init__(self,
resource_group_parameter_name='resource_group',
spring_parameter_name='spring'):
super(TearDown, self).__init__()
self.cli_ctx = get_dummy_cli()
self.resource_group_parameter_name = resource_group_parameter_name
self.spring_parameter_name = spring_parameter_name

def create_resource(self, *_, **kwargs):
self.resource_group = self._get_resource_group(**kwargs)
self.spring = self._get_spring(**kwargs)

def remove_resource(self, *_, **__):
self.live_only_execute(self.cli_ctx,
'spring application-configuration-service delete -g {} -s {} --yes'.format(
self.resource_group, self.spring))
self.live_only_execute(self.cli_ctx, 'spring application-configuration-service create -g {} -s {}'.format(
self.resource_group, self.spring))


class ApplicationConfigurationServiceTest(ScenarioTest):

@SpringResourceGroupPreparer(
dev_setting_name=SpringTestEnvironmentEnum.ENTERPRISE_WITH_TANZU['resource_group_name'])
@SpringPreparer(**SpringTestEnvironmentEnum.ENTERPRISE_WITH_TANZU['spring'])
@SpringAppNamePreparer()
@TearDown()
def test_application_configuration_service(self, resource_group, spring, app):
self.kwargs.update({
'serviceName': spring,
'rg': resource_group,
'repo': "repo1",
"label": "main",
"patterns": "api-gateway,customers-service",
"uri": "https://github.com/spring-petclinic/spring-petclinic-microservices-config",
"app": app
})

self.cmd('spring app create -g {rg} -s {serviceName} -n {app}')

self.cmd('spring application-configuration-service show -g {rg} -s {serviceName}', checks=[
self.check('properties.provisioningState', "Succeeded")
])

self.cmd('spring application-configuration-service git repo add -g {rg} -s {serviceName} '
'-n {repo} --label {label} --patterns {patterns} --uri {uri}',
checks=[self.check('properties.provisioningState', "Succeeded")])

self.cmd('spring application-configuration-service git repo update -g {rg} -s {serviceName} '
'-n {repo} --label {label}',
checks=[self.check('properties.provisioningState', "Succeeded")])

result = self.cmd(
'spring application-configuration-service git repo list -g {rg} -s {serviceName}').get_output_in_json()
self.assertTrue(len(result) > 0)

self.cmd('spring application-configuration-service git repo remove --name {repo} -g {rg} -s {serviceName}')
result = self.cmd(
'spring application-configuration-service git repo list -g {rg} -s {serviceName}').get_output_in_json()
self.assertTrue(len(result) == 0)

self.cmd('spring application-configuration-service bind --app {app} -g {rg} -s {serviceName}', checks=[
self.check('properties.addonConfigs.applicationConfigurationService.resourceId',
"/subscriptions/{}/resourceGroups/{}/providers/Microsoft.AppPlatform/Spring/{}/configurationServices/default".format(
self.get_subscription_id(), resource_group, spring))
])

self.cmd('spring app show -n {app} -g {rg} -s {serviceName}')

self.cmd('spring application-configuration-service unbind --app {app} -g {rg} -s {serviceName}')

self.cmd('spring application-configuration-service clear -g {rg} -s {serviceName}', checks=[
self.check('properties.provisioningState', "Succeeded")
])

self.cmd('spring application-configuration-service update -g {rg} -s {serviceName} '
'--generation Gen2 --refresh-interval 10',
checks=[
self.check('properties.provisioningState', "Succeeded"),
self.check('properties.generation', "Gen2"),
self.check('properties.settings.refreshIntervalInSeconds', 10)])

self.cmd('spring application-configuration-service delete -g {rg} -s {serviceName} --yes')
self.cmd('spring application-configuration-service create -g {rg} -s {serviceName} '
'--generation Gen1 --refresh-interval 20',
checks=[
self.check('properties.provisioningState', "Succeeded"),
self.check('properties.generation', "Gen1"),
self.check('properties.settings.refreshIntervalInSeconds', 20)])
2 changes: 1 addition & 1 deletion src/spring/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

# TODO: Confirm this is the right version number you want and it matches your
# HISTORY.rst entry.
VERSION = '1.19.2'
VERSION = '1.19.3'

# The full list of classifiers is available at
# https://pypi.python.org/pypi?%3Aaction=list_classifiers
Expand Down