Skip to content

Commit b68cff4

Browse files
authored
[Spring] Add new params for ACS settings (#7187)
1 parent ecf778c commit b68cff4

8 files changed

Lines changed: 2144 additions & 850 deletions

src/spring/HISTORY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
Release History
22
===============
3+
1.19.3
4+
---
5+
* Add arguments `--refresh-interval` in `spring application-configuration-service create` and `spring application-configuration-service update`.
36

47
1.19.2
58
---

src/spring/azext_spring/_params.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
validate_buildpack_binding_exist, validate_buildpack_binding_not_exist,
3030
validate_buildpack_binding_properties, validate_buildpack_binding_secrets,
3131
validate_build_env, validate_target_module, validate_runtime_version,
32-
validate_acs_ssh_or_warn, validate_apm_properties, validate_apm_secrets,
32+
validate_acs_ssh_or_warn, validate_refresh_interval,
33+
validate_apm_properties, validate_apm_secrets,
3334
validate_apm_not_exist, validate_apm_update, validate_apm_reference,
3435
validate_apm_reference_and_enterprise_tier, validate_cert_reference,
3536
validate_build_cert_reference, validate_acs_create, not_support_enterprise,
@@ -864,6 +865,10 @@ def prepare_logs_argument(c):
864865
for scope in ['create', 'update']:
865866
with self.argument_context('spring application-configuration-service {}'.format(scope)) as c:
866867
c.argument('generation', arg_type=get_enum_type(ConfigurationServiceGeneration), help='Generation of Application Configuration Service.')
868+
c.argument('refresh_interval', type=int,
869+
validator=validate_refresh_interval,
870+
help='Specify the interval (in seconds) for refreshing the repository. '
871+
'Use 0 to turn off automatic refresh. An interval of at least 60 seconds is recommended.')
867872

868873
for scope in ['add', 'update']:
869874
with self.argument_context('spring application-configuration-service git repo {}'.format(scope)) as c:

src/spring/azext_spring/_validators_enterprise.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,15 @@ def validate_acs_create(namespace):
352352
raise ArgumentUsageError("--application-configuration-service-generation can only be set when enable application configuration service.")
353353

354354

355+
def validate_refresh_interval(namespace):
356+
if namespace.refresh_interval:
357+
if not isinstance(namespace.refresh_interval, int):
358+
raise InvalidArgumentValueError("--refresh-interval should be a number.")
359+
360+
if namespace.refresh_interval < 0:
361+
raise ArgumentUsageError("--refresh-interval must be greater than or equal to 0.")
362+
363+
355364
def validate_gateway_update(cmd, namespace):
356365
_validate_gateway_response_cache(namespace)
357366
_validate_sso(namespace)

src/spring/azext_spring/application_configuration_service.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,20 @@
2424

2525

2626
def application_configuration_service_create(cmd, client, service, resource_group,
27-
generation=None):
27+
generation=None, refresh_interval=None):
2828
if generation is None:
2929
generation = ConfigurationServiceGeneration.GEN1
3030

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

3638

3739
def application_configuration_service_update(cmd, client, service, resource_group,
38-
generation=None):
40+
generation=None, refresh_interval=None):
3941
acs_resource = client.configuration_services.get(resource_group, service, DEFAULT_NAME)
4042
if generation is not None:
4143
acs_resource.properties.generation = generation
@@ -44,6 +46,9 @@ def application_configuration_service_update(cmd, client, service, resource_grou
4446
acs_resource.properties.generation = ConfigurationServiceGeneration.GEN1
4547
logger.warning("Default generation will be Gen1")
4648
logger.warning(acs_resource.properties.generation)
49+
if refresh_interval is not None:
50+
acs_resource.properties.settings = acs_resource.properties.settings or models.ConfigurationServiceSettings()
51+
acs_resource.properties.settings.refresh_interval_in_seconds = refresh_interval
4752
return client.configuration_services.begin_create_or_update(resource_group, service, DEFAULT_NAME, acs_resource)
4853

4954

src/spring/azext_spring/tests/latest/recordings/test_application_configuration_service.yaml

Lines changed: 1925 additions & 755 deletions
Large diffs are not rendered by default.

src/spring/azext_spring/tests/latest/test_asa_application_configuration_service.py

Lines changed: 86 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -2,94 +2,89 @@
22
# Copyright (c) Microsoft Corporation. All rights reserved.
33
# Licensed under the MIT License. See License.txt in the project root for license information.
44
# --------------------------------------------------------------------------------------------
5-
6-
from azure.cli.testsdk import (ScenarioTest)
7-
from azure.cli.testsdk.reverse_dependency import (
8-
get_dummy_cli,
9-
)
10-
from .custom_preparers import (SpringPreparer, SpringResourceGroupPreparer, SpringAppNamePreparer,
11-
SpringSubResourceWrapper)
12-
from .custom_dev_setting_constant import SpringTestEnvironmentEnum
13-
14-
15-
# pylint: disable=line-too-long
16-
# pylint: disable=too-many-lines
17-
18-
class TearDown(SpringSubResourceWrapper):
19-
def __init__(self,
20-
resource_group_parameter_name='resource_group',
21-
spring_parameter_name='spring'):
22-
super(TearDown, self).__init__()
23-
self.cli_ctx = get_dummy_cli()
24-
self.resource_group_parameter_name = resource_group_parameter_name
25-
self.spring_parameter_name = spring_parameter_name
26-
27-
def create_resource(self, *_, **kwargs):
28-
self.resource_group = self._get_resource_group(**kwargs)
29-
self.spring = self._get_spring(**kwargs)
30-
31-
def remove_resource(self, *_, **__):
32-
self.live_only_execute(self.cli_ctx,
33-
'spring application-configuration-service delete -g {} -s {} --yes'.format(
34-
self.resource_group, self.spring))
35-
self.live_only_execute(self.cli_ctx, 'spring application-configuration-service create -g {} -s {}'.format(
36-
self.resource_group, self.spring))
37-
38-
39-
class ApplicationConfigurationServiceTest(ScenarioTest):
40-
41-
@SpringResourceGroupPreparer(
42-
dev_setting_name=SpringTestEnvironmentEnum.ENTERPRISE_WITH_TANZU['resource_group_name'])
43-
@SpringPreparer(**SpringTestEnvironmentEnum.ENTERPRISE_WITH_TANZU['spring'])
44-
@SpringAppNamePreparer()
45-
@TearDown()
46-
def test_application_configuration_service(self, resource_group, spring, app):
47-
self.kwargs.update({
48-
'serviceName': spring,
49-
'rg': resource_group,
50-
'repo': "repo1",
51-
"label": "main",
52-
"patterns": "api-gateway,customers-service",
53-
"uri": "https://github.com/spring-petclinic/spring-petclinic-microservices-config",
54-
"app": app
55-
})
56-
57-
self.cmd('spring app create -g {rg} -s {serviceName} -n {app}')
58-
59-
self.cmd('spring application-configuration-service show -g {rg} -s {serviceName}', checks=[
60-
self.check('properties.provisioningState', "Succeeded")
61-
])
62-
63-
self.cmd('spring application-configuration-service git repo add -g {rg} -s {serviceName} '
64-
'-n {repo} --label {label} --patterns {patterns} --uri {uri}',
65-
checks=[self.check('properties.provisioningState', "Succeeded")])
66-
67-
self.cmd('spring application-configuration-service git repo update -g {rg} -s {serviceName} '
68-
'-n {repo} --label {label}',
69-
checks=[self.check('properties.provisioningState', "Succeeded")])
70-
71-
result = self.cmd(
72-
'spring application-configuration-service git repo list -g {rg} -s {serviceName}').get_output_in_json()
73-
self.assertTrue(len(result) > 0)
74-
75-
self.cmd('spring application-configuration-service git repo remove --name {repo} -g {rg} -s {serviceName}')
76-
result = self.cmd(
77-
'spring application-configuration-service git repo list -g {rg} -s {serviceName}').get_output_in_json()
78-
self.assertTrue(len(result) == 0)
79-
80-
self.cmd('spring application-configuration-service bind --app {app} -g {rg} -s {serviceName}', checks=[
81-
self.check('properties.addonConfigs.applicationConfigurationService.resourceId',
82-
"/subscriptions/{}/resourceGroups/{}/providers/Microsoft.AppPlatform/Spring/{}/configurationServices/default".format(
83-
self.get_subscription_id(), resource_group, spring))
84-
])
85-
86-
self.cmd('spring app show -n {app} -g {rg} -s {serviceName}')
87-
88-
self.cmd('spring application-configuration-service unbind --app {app} -g {rg} -s {serviceName}')
89-
90-
self.cmd('spring application-configuration-service clear -g {rg} -s {serviceName}', checks=[
91-
self.check('properties.provisioningState', "Succeeded")
92-
])
93-
94-
self.cmd('spring application-configuration-service update -g {rg} -s {serviceName} --generation Gen2',
95-
checks=[self.check('properties.provisioningState', "Succeeded")])
5+
from ...application_configuration_service import (application_configuration_service_create,
6+
application_configuration_service_update)
7+
8+
import unittest
9+
from argparse import Namespace
10+
from azure.cli.core.azclierror import InvalidArgumentValueError, ArgumentUsageError
11+
from ..._validators_enterprise import validate_refresh_interval
12+
try:
13+
import unittest.mock as mock
14+
except ImportError:
15+
from unittest import mock
16+
17+
from azure.cli.core.mock import DummyCli
18+
from azure.cli.core import AzCommandsLoader
19+
from azure.cli.core.commands import AzCliCommand
20+
21+
from knack.log import get_logger
22+
23+
logger = get_logger(__name__)
24+
free_mock_client = mock.MagicMock()
25+
26+
27+
def _get_test_cmd():
28+
cli_ctx = DummyCli()
29+
cli_ctx.data['subscription_id'] = '00000000-0000-0000-0000-000000000000'
30+
loader = AzCommandsLoader(cli_ctx, resource_type='Microsoft.AppPlatform')
31+
cmd = AzCliCommand(loader, 'test', None)
32+
cmd.command_kwargs = {'resource_type': 'Microsoft.AppPlatform'}
33+
cmd.cli_ctx = cli_ctx
34+
return cmd
35+
36+
37+
def _cf_resource_group(cli_ctx, subscription_id=None):
38+
client = mock.MagicMock()
39+
rg = mock.MagicMock()
40+
rg.location = 'east us'
41+
client.resource_groups.get.return_value = rg
42+
return client
43+
44+
45+
def _get_basic_mock_client(*_):
46+
return mock.MagicMock()
47+
48+
49+
class BasicTest(unittest.TestCase):
50+
def __init__(self, methodName: str = ...):
51+
super().__init__(methodName=methodName)
52+
self.created_resource = None
53+
54+
def setUp(self):
55+
resp = super().setUp()
56+
free_mock_client.reset_mock()
57+
return resp
58+
59+
@mock.patch('azext_spring._utils.cf_resource_groups', _cf_resource_group)
60+
def _execute(self, resource_group, generation, refresh_interval, **kwargs):
61+
client = kwargs.pop('client', None) or _get_basic_mock_client()
62+
application_configuration_service_create(_get_test_cmd(), client, 'myasa',
63+
resource_group, generation, refresh_interval)
64+
call_args = client.configuration_services.begin_create_or_update.call_args_list
65+
self.assertEqual(1, len(call_args))
66+
self.assertEqual(4, len(call_args[0][0]))
67+
self.assertEqual((resource_group, generation),
68+
(call_args[0][0][0], call_args[0][0][3].properties.generation))
69+
self.created_resource = call_args[0][0][3]
70+
71+
72+
class TestApplicationConfigurationService(BasicTest):
73+
def test_acs_create(self):
74+
self._execute('rg', 'Gen1', 120)
75+
resource = self.created_resource
76+
self.assertIsNotNone(resource.properties)
77+
self.assertEqual(120, resource.properties.settings.refresh_interval_in_seconds)
78+
79+
80+
class TestApplicationConfigurationServiceValidator(unittest.TestCase):
81+
def test_validate_refresh_interval_parameter(self):
82+
ns = Namespace(refresh_interval="a")
83+
with self.assertRaises(InvalidArgumentValueError) as context:
84+
validate_refresh_interval(ns)
85+
self.assertEqual("--refresh-interval should be a number.", str(context.exception))
86+
87+
ns = Namespace(refresh_interval=-1)
88+
with self.assertRaises(ArgumentUsageError) as context:
89+
validate_refresh_interval(ns)
90+
self.assertEqual("--refresh-interval must be greater than or equal to 0.", str(context.exception))
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# --------------------------------------------------------------------------------------------
5+
6+
from azure.cli.testsdk import (ScenarioTest)
7+
from azure.cli.testsdk.reverse_dependency import (
8+
get_dummy_cli,
9+
)
10+
from .custom_preparers import (SpringPreparer, SpringResourceGroupPreparer, SpringAppNamePreparer,
11+
SpringSubResourceWrapper)
12+
from .custom_dev_setting_constant import SpringTestEnvironmentEnum
13+
14+
15+
# pylint: disable=line-too-long
16+
# pylint: disable=too-many-lines
17+
18+
class TearDown(SpringSubResourceWrapper):
19+
def __init__(self,
20+
resource_group_parameter_name='resource_group',
21+
spring_parameter_name='spring'):
22+
super(TearDown, self).__init__()
23+
self.cli_ctx = get_dummy_cli()
24+
self.resource_group_parameter_name = resource_group_parameter_name
25+
self.spring_parameter_name = spring_parameter_name
26+
27+
def create_resource(self, *_, **kwargs):
28+
self.resource_group = self._get_resource_group(**kwargs)
29+
self.spring = self._get_spring(**kwargs)
30+
31+
def remove_resource(self, *_, **__):
32+
self.live_only_execute(self.cli_ctx,
33+
'spring application-configuration-service delete -g {} -s {} --yes'.format(
34+
self.resource_group, self.spring))
35+
self.live_only_execute(self.cli_ctx, 'spring application-configuration-service create -g {} -s {}'.format(
36+
self.resource_group, self.spring))
37+
38+
39+
class ApplicationConfigurationServiceTest(ScenarioTest):
40+
41+
@SpringResourceGroupPreparer(
42+
dev_setting_name=SpringTestEnvironmentEnum.ENTERPRISE_WITH_TANZU['resource_group_name'])
43+
@SpringPreparer(**SpringTestEnvironmentEnum.ENTERPRISE_WITH_TANZU['spring'])
44+
@SpringAppNamePreparer()
45+
@TearDown()
46+
def test_application_configuration_service(self, resource_group, spring, app):
47+
self.kwargs.update({
48+
'serviceName': spring,
49+
'rg': resource_group,
50+
'repo': "repo1",
51+
"label": "main",
52+
"patterns": "api-gateway,customers-service",
53+
"uri": "https://github.com/spring-petclinic/spring-petclinic-microservices-config",
54+
"app": app
55+
})
56+
57+
self.cmd('spring app create -g {rg} -s {serviceName} -n {app}')
58+
59+
self.cmd('spring application-configuration-service show -g {rg} -s {serviceName}', checks=[
60+
self.check('properties.provisioningState', "Succeeded")
61+
])
62+
63+
self.cmd('spring application-configuration-service git repo add -g {rg} -s {serviceName} '
64+
'-n {repo} --label {label} --patterns {patterns} --uri {uri}',
65+
checks=[self.check('properties.provisioningState', "Succeeded")])
66+
67+
self.cmd('spring application-configuration-service git repo update -g {rg} -s {serviceName} '
68+
'-n {repo} --label {label}',
69+
checks=[self.check('properties.provisioningState', "Succeeded")])
70+
71+
result = self.cmd(
72+
'spring application-configuration-service git repo list -g {rg} -s {serviceName}').get_output_in_json()
73+
self.assertTrue(len(result) > 0)
74+
75+
self.cmd('spring application-configuration-service git repo remove --name {repo} -g {rg} -s {serviceName}')
76+
result = self.cmd(
77+
'spring application-configuration-service git repo list -g {rg} -s {serviceName}').get_output_in_json()
78+
self.assertTrue(len(result) == 0)
79+
80+
self.cmd('spring application-configuration-service bind --app {app} -g {rg} -s {serviceName}', checks=[
81+
self.check('properties.addonConfigs.applicationConfigurationService.resourceId',
82+
"/subscriptions/{}/resourceGroups/{}/providers/Microsoft.AppPlatform/Spring/{}/configurationServices/default".format(
83+
self.get_subscription_id(), resource_group, spring))
84+
])
85+
86+
self.cmd('spring app show -n {app} -g {rg} -s {serviceName}')
87+
88+
self.cmd('spring application-configuration-service unbind --app {app} -g {rg} -s {serviceName}')
89+
90+
self.cmd('spring application-configuration-service clear -g {rg} -s {serviceName}', checks=[
91+
self.check('properties.provisioningState', "Succeeded")
92+
])
93+
94+
self.cmd('spring application-configuration-service update -g {rg} -s {serviceName} '
95+
'--generation Gen2 --refresh-interval 10',
96+
checks=[
97+
self.check('properties.provisioningState', "Succeeded"),
98+
self.check('properties.generation', "Gen2"),
99+
self.check('properties.settings.refreshIntervalInSeconds', 10)])
100+
101+
self.cmd('spring application-configuration-service delete -g {rg} -s {serviceName} --yes')
102+
self.cmd('spring application-configuration-service create -g {rg} -s {serviceName} '
103+
'--generation Gen1 --refresh-interval 20',
104+
checks=[
105+
self.check('properties.provisioningState', "Succeeded"),
106+
self.check('properties.generation', "Gen1"),
107+
self.check('properties.settings.refreshIntervalInSeconds', 20)])

src/spring/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

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

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

0 commit comments

Comments
 (0)