From 5c2b959f78c4f8b1ded5d78800b3c7c36c36ba11 Mon Sep 17 00:00:00 2001 From: "Mason(Jie) Chen" Date: Tue, 8 Jun 2021 11:28:37 +0800 Subject: [PATCH 1/3] For extension: Spring-Cloud Application-Insights, migration instrumentation key to connection string, fall back to instrumentation key when connection string is not available --- src/spring-cloud/azext_spring_cloud/_help.py | 2 +- src/spring-cloud/azext_spring_cloud/custom.py | 43 ++++++++++++------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/spring-cloud/azext_spring_cloud/_help.py b/src/spring-cloud/azext_spring_cloud/_help.py index 4d5ac6f90de..5a7748d74de 100644 --- a/src/spring-cloud/azext_spring_cloud/_help.py +++ b/src/spring-cloud/azext_spring_cloud/_help.py @@ -462,7 +462,7 @@ short-summary: Update Application Insights settings. examples: - name: Enable Application Insights and Java In-process Agent. - text: az spring-cloud app-insights update -n MyService -g MyResourceGroup --app-insights-key MyInstrumentationKey --sampling-rate 100 + text: az spring-cloud app-insights update -n MyService -g MyResourceGroup --app-insights-key \"MyConnectionString\" --sampling-rate 100 - name: Disable Application Insights. text: az spring-cloud app-insights update -n MyService -g MyResourceGroup --disable """ diff --git a/src/spring-cloud/azext_spring_cloud/custom.py b/src/spring-cloud/azext_spring_cloud/custom.py index 974f5af3dda..056a5948d16 100644 --- a/src/spring-cloud/azext_spring_cloud/custom.py +++ b/src/spring-cloud/azext_spring_cloud/custom.py @@ -1560,12 +1560,26 @@ def domain_unbind(cmd, client, resource_group, service, app, domain_name): return client.custom_domains.delete(resource_group, service, app, domain_name) -def get_app_insights_key(cli_ctx, resource_group, name): +def get_conenction_string_or_instrumentation_key(appinsights): + credential = None + if appinsights: + if appinsights.conenction_string: + credential = appinsights.connection_string + elif appinsights.instrumentation_key: + credential = appinsights.instrumentation_key + return credential + + +def get_app_insights_credential(cli_ctx, resource_group, name): + """ + Application Insights is migrating from instrumentation_key to connection_key. + Get connection_string first, if not exist, fall back to instrumentation_key. + """ appinsights_client = get_mgmt_service_client(cli_ctx, ApplicationInsightsManagementClient) appinsights = appinsights_client.components.get(resource_group, name) - if appinsights is None or appinsights.instrumentation_key is None: + if appinsights is None or (appinsights.connection_string is None and appinsights.instrumentation_key is None): raise CLIError("App Insights {} under resource group {} was not found.".format(name, resource_group)) - return appinsights.instrumentation_key + return get_conenction_string_or_instrumentation_key(appinsights) def update_tracing_config(cmd, resource_group, service_name, location, app_insights_key, @@ -1578,12 +1592,12 @@ def update_tracing_config(cmd, resource_group, service_name, location, app_insig elif app_insights: if is_valid_resource_id(app_insights): resource_id_dict = parse_resource_id(app_insights) - instrumentation_key = get_app_insights_key(cmd.cli_ctx, resource_id_dict['resource_group'], - resource_id_dict['resource_name']) + instrumentation_key = get_app_insights_credential(cmd.cli_ctx, resource_id_dict['resource_group'], + resource_id_dict['resource_name']) trace_properties = models.MonitoringSettingProperties( trace_enabled=True, app_insights_instrumentation_key=instrumentation_key) else: - instrumentation_key = get_app_insights_key(cmd.cli_ctx, resource_group, app_insights) + instrumentation_key = get_app_insights_credential(cmd.cli_ctx, resource_group, app_insights) trace_properties = models.MonitoringSettingProperties( trace_enabled=True, app_insights_instrumentation_key=instrumentation_key) elif disable_app_insights is not True: @@ -1614,12 +1628,12 @@ def update_java_agent_config(cmd, resource_group, service_name, location, app_in elif app_insights: if is_valid_resource_id(app_insights): resource_id_dict = parse_resource_id(app_insights) - instrumentation_key = get_app_insights_key(cmd.cli_ctx, resource_id_dict['resource_group'], - resource_id_dict['resource_name']) + instrumentation_key = get_app_insights_credential(cmd.cli_ctx, resource_id_dict['resource_group'], + resource_id_dict['resource_name']) trace_properties = models_20201101preview.MonitoringSettingProperties( trace_enabled=True, app_insights_instrumentation_key=instrumentation_key) else: - instrumentation_key = get_app_insights_key(cmd.cli_ctx, resource_group, app_insights) + instrumentation_key = get_app_insights_credential(cmd.cli_ctx, resource_group, app_insights) trace_properties = models_20201101preview.MonitoringSettingProperties( trace_enabled=True, app_insights_instrumentation_key=instrumentation_key) elif enable_java_agent is True: @@ -1658,7 +1672,7 @@ def try_create_application_insights(cmd, resource_group, name, location): } } appinsights = app_insights_client.components.create_or_update(ai_resource_group_name, ai_name, ai_properties) - if appinsights is None or appinsights.instrumentation_key is None: + if appinsights is None or (appinsights.connection_string is None and appinsights.instrumentation_key is None): logger.warning(creation_failed_warn) return None @@ -1667,8 +1681,7 @@ def try_create_application_insights(cmd, resource_group, name, location): logger.warning('Application Insights \"%s\" was created for this Azure Spring Cloud. ' 'You can visit %s/#resource%s/overview to view your ' 'Application Insights component', appinsights.name, portal_url, appinsights.id) - - return appinsights.instrumentation_key + return get_conenction_string_or_instrumentation_key(appinsights) def app_insights_update(cmd, client, resource_group, name, app_insights_key=None, app_insights=None, sampling_rate=None, disable=None, no_wait=False): @@ -1683,10 +1696,10 @@ def app_insights_update(cmd, client, resource_group, name, app_insights_key=None elif app_insights: if is_valid_resource_id(app_insights): resource_id_dict = parse_resource_id(app_insights) - instrumentation_key = get_app_insights_key(cmd.cli_ctx, resource_id_dict['resource_group'], - resource_id_dict['resource_name']) + instrumentation_key = get_app_insights_credential(cmd.cli_ctx, resource_id_dict['resource_group'], + resource_id_dict['resource_name']) else: - instrumentation_key = get_app_insights_key(cmd.cli_ctx, resource_group, app_insights) + instrumentation_key = get_app_insights_credential(cmd.cli_ctx, resource_group, app_insights) else: instrumentation_key = trace_properties.app_insights_instrumentation_key if sampling_rate: From 89c81df366852e578184af02582c80e150e83dd1 Mon Sep 17 00:00:00 2001 From: "Mason(Jie) Chen" Date: Thu, 17 Jun 2021 11:54:13 +0800 Subject: [PATCH 2/3] 1. Update azext.minCliCoreVersion to latest version; 2. Update help info by transforming 'intrumentation key' to 'connection string'; 3. Use concret type of exception to replace general CLIError; 4. fix typo for connection; 5. Add unit test; --- src/spring-cloud/azext_spring_cloud/_help.py | 4 +- .../azext_spring_cloud/_params.py | 4 +- .../azext_spring_cloud/azext_metadata.json | 2 +- src/spring-cloud/azext_spring_cloud/custom.py | 13 +++--- .../tests/latest/test_asc_ut.py | 43 +++++++++++++++++++ 5 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 src/spring-cloud/azext_spring_cloud/tests/latest/test_asc_ut.py diff --git a/src/spring-cloud/azext_spring_cloud/_help.py b/src/spring-cloud/azext_spring_cloud/_help.py index 5a7748d74de..a4bebf8ac4a 100644 --- a/src/spring-cloud/azext_spring_cloud/_help.py +++ b/src/spring-cloud/azext_spring_cloud/_help.py @@ -17,8 +17,8 @@ examples: - name: Create a new Azure Spring Cloud in westus. text: az spring-cloud create -n MyService -g MyResourceGroup -l westus - - name: Create a new Azure Spring Cloud in westus with an existing Application Insights by using the instrumentation key. - text: az spring-cloud create -n MyService -g MyResourceGroup -l westus --app-insights-key MyInstrumentationKey + - name: Create a new Azure Spring Cloud in westus with an existing Application Insights by using the connection string. + text: az spring-cloud create -n MyService -g MyResourceGroup -l westus --app-insights-key \"MyConnectionString\" - name: Create a new Azure Spring Cloud in westus with an existing Application Insights and enable Java In-Process Agent. text: az spring-cloud create -n MyService -g MyResourceGroup -l westus --enable-java-agent true --app-insights MyInstrumentationName - name: Create a new Azure Spring Cloud with distributed tracing disabled. diff --git a/src/spring-cloud/azext_spring_cloud/_params.py b/src/spring-cloud/azext_spring_cloud/_params.py index 6e441130fb1..0a2db5ff26c 100644 --- a/src/spring-cloud/azext_spring_cloud/_params.py +++ b/src/spring-cloud/azext_spring_cloud/_params.py @@ -49,7 +49,7 @@ def load_arguments(self, _): for scope in ['spring-cloud create', 'spring-cloud update']: with self.argument_context(scope) as c: c.argument('app_insights_key', - help="Instrumentation key of the existing Application Insights.", + help="Connection string of the existing Application Insights.", validator=validate_tracing_parameters) c.argument('app_insights', help="Name of the existing Application Insights in the same Resource Group. Or Resource ID of the existing Application Insights in a different Resource Group.", @@ -260,7 +260,7 @@ def prepare_logs_argument(c): with self.argument_context('spring-cloud app-insights update') as c: c.argument('app_insights_key', - help="Instrumentation key of the existing Application Insights", + help="Connection string of the existing Application Insights", validator=validate_app_insights_parameters) c.argument('app_insights', help="Name of the existing Application Insights in the same Resource Group. Or Resource ID of the existing Application Insights in a different Resource Group.", diff --git a/src/spring-cloud/azext_spring_cloud/azext_metadata.json b/src/spring-cloud/azext_spring_cloud/azext_metadata.json index aa15278925a..619f41e5c75 100644 --- a/src/spring-cloud/azext_spring_cloud/azext_metadata.json +++ b/src/spring-cloud/azext_spring_cloud/azext_metadata.json @@ -1,4 +1,4 @@ { "azext.isPreview": false, - "azext.minCliCoreVersion": "2.0.67" + "azext.minCliCoreVersion": "2.25.0" } \ No newline at end of file diff --git a/src/spring-cloud/azext_spring_cloud/custom.py b/src/spring-cloud/azext_spring_cloud/custom.py index 056a5948d16..9f23883d754 100644 --- a/src/spring-cloud/azext_spring_cloud/custom.py +++ b/src/spring-cloud/azext_spring_cloud/custom.py @@ -11,6 +11,7 @@ from time import sleep from ._stream_utils import stream_logs from msrestazure.azure_exceptions import CloudError +from azure.core.exceptions import ResourceNotFoundError from msrestazure.tools import parse_resource_id, is_valid_resource_id from ._utils import _get_upload_local_file, _get_persistent_disk_size, get_portal_uri, get_azure_files_info from knack.util import CLIError @@ -1560,12 +1561,12 @@ def domain_unbind(cmd, client, resource_group, service, app, domain_name): return client.custom_domains.delete(resource_group, service, app, domain_name) -def get_conenction_string_or_instrumentation_key(appinsights): +def get_connection_string_or_instrumentation_key(appinsights): credential = None if appinsights: - if appinsights.conenction_string: + if hasattr(appinsights, "connection_string") and appinsights.connection_string: credential = appinsights.connection_string - elif appinsights.instrumentation_key: + elif hasattr(appinsights, "instrumentation_key") and appinsights.instrumentation_key: credential = appinsights.instrumentation_key return credential @@ -1578,8 +1579,8 @@ def get_app_insights_credential(cli_ctx, resource_group, name): appinsights_client = get_mgmt_service_client(cli_ctx, ApplicationInsightsManagementClient) appinsights = appinsights_client.components.get(resource_group, name) if appinsights is None or (appinsights.connection_string is None and appinsights.instrumentation_key is None): - raise CLIError("App Insights {} under resource group {} was not found.".format(name, resource_group)) - return get_conenction_string_or_instrumentation_key(appinsights) + raise ResourceNotFoundError("App Insights {} under resource group {} was not found.".format(name, resource_group)) + return get_connection_string_or_instrumentation_key(appinsights) def update_tracing_config(cmd, resource_group, service_name, location, app_insights_key, @@ -1681,7 +1682,7 @@ def try_create_application_insights(cmd, resource_group, name, location): logger.warning('Application Insights \"%s\" was created for this Azure Spring Cloud. ' 'You can visit %s/#resource%s/overview to view your ' 'Application Insights component', appinsights.name, portal_url, appinsights.id) - return get_conenction_string_or_instrumentation_key(appinsights) + return get_connection_string_or_instrumentation_key(appinsights) def app_insights_update(cmd, client, resource_group, name, app_insights_key=None, app_insights=None, sampling_rate=None, disable=None, no_wait=False): diff --git a/src/spring-cloud/azext_spring_cloud/tests/latest/test_asc_ut.py b/src/spring-cloud/azext_spring_cloud/tests/latest/test_asc_ut.py new file mode 100644 index 00000000000..d45dde164aa --- /dev/null +++ b/src/spring-cloud/azext_spring_cloud/tests/latest/test_asc_ut.py @@ -0,0 +1,43 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import unittest +from azext_spring_cloud.custom import get_connection_string_or_instrumentation_key + +class SimplifiedApplicationInsightsCompoent: + def __init__(self): + self.connection_string = None + self.instrumentation_key = None + + +class AzureSpringCloudTestCase(unittest.TestCase): + def setUp(self): + self._connection_string = "InstrumentationKey=11111111-0000-0000-0000-000000000000;IngestionEndpoint=https://11111111.00.0000000000000000000.00000.000/" + self._instrumentation_key = "11111111-0000-0000-0000-000000000000" + + + def test_get_conenction_string_or_instrumentation_key_case_1_connection_string_exists(self): + appinsights = SimplifiedApplicationInsightsCompoent() + appinsights.connection_string = self._connection_string + appinsights.instrumentation_key = self._instrumentation_key + self.assertEqual(self._connection_string, get_connection_string_or_instrumentation_key(appinsights)) + + + def test_get_conenction_string_or_instrumentation_key_case_2_connection_string_not_exist(self): + appinsights = SimplifiedApplicationInsightsCompoent() + appinsights.connection_string = None + appinsights.instrumentation_key = self._instrumentation_key + self.assertEqual(self._instrumentation_key, get_connection_string_or_instrumentation_key(appinsights)) + + + def test_get_conenction_string_or_instrumentation_key_case_3_no_credential(self): + appinsights = SimplifiedApplicationInsightsCompoent() + appinsights.connection_string = None + appinsights.instrumentation_key = None + self.assertIsNone(get_connection_string_or_instrumentation_key(appinsights)) + + +if __name__ == '__main__': + unittest.main() From cd75dd3b503a3397f9cc44b7a525bbbe9bff3692 Mon Sep 17 00:00:00 2001 From: "Mason(Jie) Chen" Date: Fri, 18 Jun 2021 10:09:30 +0800 Subject: [PATCH 3/3] Update version number and add release notes --- src/spring-cloud/HISTORY.md | 3 +++ src/spring-cloud/setup.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/spring-cloud/HISTORY.md b/src/spring-cloud/HISTORY.md index d00ea50bf4a..3aa5901cd00 100644 --- a/src/spring-cloud/HISTORY.md +++ b/src/spring-cloud/HISTORY.md @@ -1,5 +1,8 @@ Release History =============== +2.5.0 +----- +* Migration from `instrumentation_key` to `connection_string` when update java agent configurations. 2.4.0 ----- diff --git a/src/spring-cloud/setup.py b/src/spring-cloud/setup.py index 70158d028a6..937d3667156 100644 --- a/src/spring-cloud/setup.py +++ b/src/spring-cloud/setup.py @@ -16,7 +16,7 @@ # TODO: Confirm this is the right version number you want and it matches your # HISTORY.rst entry. -VERSION = '2.4.0' +VERSION = '2.5.0' # The full list of classifiers is available at # https://pypi.python.org/pypi?%3Aaction=list_classifiers