Skip to content

Commit 7d59f5e

Browse files
authored
[Service Connector] az spring connection: Enable new auth types for Spring Boot and Cosmos SQL connection (#26719)
* add Spring Cloud Azure migration warning * update warning message * delete whitespace * delete redundant whitespaces * fix typo * fix line-too-long error * improve warning messages * add check and test results * fix not-in-list ValueError * fix CLI style * add logs * fix style
1 parent 63f2271 commit 7d59f5e

File tree

10 files changed

+3072
-15
lines changed

10 files changed

+3072
-15
lines changed

src/azure-cli/azure/cli/command_modules/serviceconnector/_addon_factory.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
parse_resource_id,
1010
is_valid_resource_id
1111
)
12+
from azure.cli.core import telemetry
1213
from azure.cli.core.commands.client_factory import get_subscription_id
1314
from azure.cli.core.azclierror import (
1415
CLIInternalError,
@@ -174,7 +175,9 @@ def _retrive_source_rg(self):
174175
'''Retrieve the resource group name in source resource id
175176
'''
176177
if not is_valid_resource_id(self._source_id):
177-
raise InvalidArgumentValueError('The source resource id is invalid: {}'.format(self._source_id))
178+
e = InvalidArgumentValueError('The source resource id is invalid: {}'.format(self._source_id))
179+
telemetry.set_exception(e, "source-id-invalid")
180+
raise e
178181

179182
segments = parse_resource_id(self._source_id)
180183
return segments.get('resource_group')
@@ -195,7 +198,9 @@ def _get_source_type(self):
195198
matched = re.match(get_resource_regex(resource), self._source_id)
196199
if matched:
197200
return _type
198-
raise InvalidArgumentValueError('The source resource id is invalid: {}'.format(self._source_id))
201+
e = InvalidArgumentValueError('The source resource id is invalid: {}'.format(self._source_id))
202+
telemetry.set_exception(e, "source-id-invalid")
203+
raise e
199204

200205
def _get_target_type(self):
201206
'''Get target resource type

src/azure-cli/azure/cli/command_modules/serviceconnector/_resource_config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,7 @@ class CLIENT_TYPE(Enum):
966966
CLIENT_TYPE.Java,
967967
CLIENT_TYPE.Python,
968968
CLIENT_TYPE.Nodejs,
969+
CLIENT_TYPE.SpringBoot,
969970
CLIENT_TYPE.Blank
970971
],
971972
RESOURCE.StorageBlob: [

src/azure-cli/azure/cli/command_modules/serviceconnector/_utils.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,3 +435,45 @@ def _install_extension(cmd, extension_name):
435435
except Exception: # nopa pylint: disable=broad-except
436436
return False
437437
return True
438+
439+
440+
def springboot_migration_warning(require_update=False, check_version=False, both_version=False):
441+
warning_message = "It is recommended to use Spring Cloud Azure version 4.0 and above. \
442+
The configurations in the format of \"azure.cosmos.*\" from Spring Cloud Azure 3.x will no longer be supported after 1st July, 2024. \
443+
Please refer to https://microsoft.github.io/spring-cloud-azure/current/reference/html/appendix.html\
444+
#configuration-spring-cloud-azure-starter-data-cosmos for more details."
445+
446+
update_message = "\nPlease update your connection to include the configurations for the newer version."
447+
448+
check_version_message = "\nManaged identity and service principal are only supported \
449+
in Spring Cloud Azure version 4.0 and above. Please check your Spring Cloud Azure version. \
450+
Learn more at https://spring.io/projects/spring-cloud-azure#overview"
451+
both_version_message = "\nTwo sets of configuration properties will be configured \
452+
according to Spring Cloud Azure version 3.x and 4.x. \
453+
Learn more at https://spring.io/projects/spring-cloud-azure#overview"
454+
455+
if require_update:
456+
warning_message += update_message
457+
if check_version:
458+
warning_message += check_version_message
459+
if both_version:
460+
warning_message += both_version_message
461+
462+
return warning_message
463+
464+
465+
def decorate_springboot_cosmossql_config(configs):
466+
is_springboot_cosmossql = False
467+
require_update = True
468+
469+
for config in configs.configurations:
470+
if config.name.startswith("azure.cosmos."):
471+
is_springboot_cosmossql = True
472+
config.note = "This configuration property is used in Spring Cloud Azure version 3.x and below."
473+
elif config.name.startswith("spring.cloud.azure.cosmos."):
474+
is_springboot_cosmossql = True
475+
require_update = False
476+
config.note = "This configuration property is used in Spring Cloud Azure version 4.0 and above."
477+
478+
if is_springboot_cosmossql:
479+
logger.warning(springboot_migration_warning(require_update=require_update))

src/azure-cli/azure/cli/command_modules/serviceconnector/_validators.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
parse_resource_id,
1717
is_valid_resource_id
1818
)
19+
from azure.cli.core import telemetry
1920
from azure.cli.core.commands.client_factory import get_subscription_id
2021
from azure.cli.core.azclierror import (
2122
ValidationError,
@@ -345,15 +346,19 @@ def validate_source_resource_id(namespace):
345346
'''
346347
if getattr(namespace, 'source_id', None):
347348
if not is_valid_resource_id(namespace.source_id):
348-
raise InvalidArgumentValueError('Resource id is invalid: {}'.format(namespace.source_id))
349+
e = InvalidArgumentValueError('Resource id is invalid: {}'.format(namespace.source_id))
350+
telemetry.set_exception(e, 'source-id-invalid')
351+
raise e
349352
matched = False
350353
for resource in SOURCE_RESOURCES.values():
351354
matched = re.match(get_resource_regex(resource), namespace.source_id)
352355
if matched:
353356
namespace.source_id = matched.group()
354357
return True
355358
if not matched:
356-
raise InvalidArgumentValueError('Unsupported source resource id: {}'.format(namespace.source_id))
359+
e = InvalidArgumentValueError('Unsupported source resource id: {}'.format(namespace.source_id))
360+
telemetry.set_exception(e, 'source-id-unsupported')
361+
raise e
357362

358363
return False
359364

@@ -371,7 +376,9 @@ def validate_connection_id(namespace):
371376
namespace.connection_name = matched.group(2)
372377
return True
373378
if not matched:
374-
raise InvalidArgumentValueError('Connection id is invalid: {}'.format(namespace.indentifier))
379+
e = InvalidArgumentValueError('Connection id is invalid: {}'.format(namespace.indentifier))
380+
telemetry.set_exception(e, 'connection-id-invalid')
381+
raise e
375382

376383
return False
377384

@@ -381,15 +388,19 @@ def validate_target_resource_id(namespace):
381388
'''
382389
if getattr(namespace, 'target_id', None):
383390
if not is_valid_resource_id(namespace.target_id):
384-
raise InvalidArgumentValueError('Resource id is invalid: {}'.format(namespace.target_id))
391+
e = InvalidArgumentValueError('Resource id is invalid: {}'.format(namespace.target_id))
392+
telemetry.set_exception(e, 'target-id-invalid')
393+
raise e
385394
matched = False
386395
for resource in TARGET_RESOURCES.values():
387396
matched = re.match(get_resource_regex(resource), namespace.target_id, re.IGNORECASE)
388397
if matched:
389398
namespace.target_id = matched.group()
390399
return True
391400
if not matched:
392-
raise InvalidArgumentValueError('Unsupported target resource id is invalid: {}'.format(namespace.target_id))
401+
e = InvalidArgumentValueError('Unsupported target resource id is invalid: {}'.format(namespace.target_id))
402+
telemetry.set_exception(e, 'target-id-unsupported')
403+
raise e
393404

394405
return False
395406

@@ -607,8 +618,10 @@ def validate_default_params(cmd, namespace):
607618

608619
def validate_connection_name(name):
609620
if not re.match(r'^[A-Za-z0-9\._]+$', name):
610-
raise InvalidArgumentValueError("Resource name can only contain letters (A-Z, a-z), "
611-
"numbers (0-9), periods ('.'), and underscores ('_')")
621+
e = InvalidArgumentValueError("Resource name can only contain letters (A-Z, a-z), "
622+
"numbers (0-9), periods ('.'), and underscores ('_')")
623+
telemetry.set_exception('connection-name-invalid')
624+
raise e
612625
return True
613626

614627

src/azure-cli/azure/cli/command_modules/serviceconnector/commands.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# --------------------------------------------------------------------------------------------
55

66
from azure.cli.core.commands import CliCommandType
7+
from knack.log import get_logger
78
from ._transformers import (
89
transform_support_types,
910
transform_linker_properties,
@@ -19,6 +20,9 @@
1920
from ._utils import should_load_source
2021

2122

23+
logger = get_logger(__name__)
24+
25+
2226
def load_command_table(self, _): # pylint: disable=too-many-statements
2327

2428
from azure.cli.command_modules.serviceconnector._client_factory import (
@@ -52,7 +56,10 @@ def load_command_table(self, _): # pylint: disable=too-many-statements
5256
# use SUPPORTED_AUTH_TYPE to decide target resource, as some
5357
# target resources are not avialable for certain source resource
5458
supported_target_resources = list(SUPPORTED_AUTH_TYPE.get(source).keys())
55-
supported_target_resources.remove(RESOURCE.ConfluentKafka)
59+
if RESOURCE.ConfluentKafka in supported_target_resources:
60+
supported_target_resources.remove(RESOURCE.ConfluentKafka)
61+
else:
62+
logger.warning("ConfluentKafka is not in supported target resources for %s", source.value)
5663
for target in supported_target_resources:
5764
with self.command_group('{} connection create'.format(source.value),
5865
connection_type, client_factory=cf_linker) as ig:
@@ -98,7 +105,10 @@ def load_command_table(self, _): # pylint: disable=too-many-statements
98105

99106
supported_target_resources = list(
100107
SUPPORTED_AUTH_TYPE.get(RESOURCE.Local).keys())
101-
supported_target_resources.remove(RESOURCE.ConfluentKafka)
108+
if RESOURCE.ConfluentKafka in supported_target_resources:
109+
supported_target_resources.remove(RESOURCE.ConfluentKafka)
110+
else:
111+
logger.warning("ConfluentKafka is not in supported target resources for %s", RESOURCE.Local.value)
102112
for target in supported_target_resources:
103113
with self.command_group('connection preview-configuration', client_factory=cf_configuration_names) as ig:
104114
ig.custom_command(target.value, 'connection_preview_configuration')

src/azure-cli/azure/cli/command_modules/serviceconnector/custom.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
SUPPORTED_AUTH_TYPE,
2020
SUPPORTED_CLIENT_TYPE,
2121
TARGET_RESOURCES,
22+
AUTH_TYPE,
2223
RESOURCE
2324
)
2425
from ._validators import (
@@ -35,7 +36,9 @@
3536
get_cloud_conn_auth_info,
3637
get_local_conn_auth_info,
3738
_get_azext_module,
38-
_get_or_add_extension
39+
_get_or_add_extension,
40+
springboot_migration_warning,
41+
decorate_springboot_cosmossql_config
3942
)
4043
from ._credential_free import is_passwordless_command
4144
# pylint: disable=unused-argument,unsubscriptable-object,unsupported-membership-test,too-many-statements,too-many-locals
@@ -175,9 +178,13 @@ def connection_list_configuration(client,
175178
spring=None, app=None, deployment='default'):
176179
if not source_id or not connection_name:
177180
raise RequiredArgumentMissingError(err_msg.format('--source-id, --connection'))
178-
return auto_register(client.list_configurations,
179-
resource_uri=source_id,
180-
linker_name=connection_name)
181+
configurations = auto_register(client.list_configurations,
182+
resource_uri=source_id,
183+
linker_name=connection_name)
184+
185+
decorate_springboot_cosmossql_config(configurations)
186+
187+
return configurations
181188

182189

183190
def local_connection_generate_configuration(cmd, client,
@@ -459,6 +466,15 @@ def connection_create_func(cmd, client, # pylint: disable=too-many-locals,too-m
459466
new_auth_info = enable_mi_for_db_linker(
460467
cmd, source_id, target_id, auth_info, client_type, connection_name)
461468
parameters['auth_info'] = new_auth_info or parameters['auth_info']
469+
470+
# migration warning for Spring Azure Cloud
471+
if client_type == CLIENT_TYPE.SpringBoot.value and target_type == RESOURCE.CosmosSql:
472+
isSecretType = (auth_info['auth_type'] == AUTH_TYPE.SecretAuto.value or
473+
auth_info['auth_type'] == AUTH_TYPE.Secret.value)
474+
logger.warning(springboot_migration_warning(require_update=False,
475+
check_version=(not isSecretType),
476+
both_version=isSecretType))
477+
462478
return auto_register(sdk_no_wait, no_wait,
463479
client.begin_create_or_update,
464480
resource_uri=source_id,
@@ -684,6 +700,14 @@ def connection_update(cmd, client, # pylint: disable=too-many-locals, too-many-
684700
elif private_endpoint is False and linker.get('vNetSolution').get('type') == 'privateLink':
685701
parameters['v_net_solution'] = None
686702

703+
# migration warning for Spring Azure Cloud
704+
if client_type == CLIENT_TYPE.SpringBoot.value and target_type == RESOURCE.CosmosSql:
705+
isSecretType = (auth_info['auth_type'] == AUTH_TYPE.SecretAuto.value or
706+
auth_info['auth_type'] == AUTH_TYPE.Secret.value)
707+
logger.warning(springboot_migration_warning(require_update=False,
708+
check_version=(not isSecretType),
709+
both_version=isSecretType))
710+
687711
return auto_register(sdk_no_wait, no_wait,
688712
client.begin_create_or_update,
689713
resource_uri=source_id,

0 commit comments

Comments
 (0)