From 7debdfeb81853da73bff29c92a37c917bb2b5179 Mon Sep 17 00:00:00 2001 From: Feng Zhou Date: Sat, 29 Feb 2020 23:33:04 +0800 Subject: [PATCH 1/5] disable telemetry for some clouds --- src/azure-cli-core/azure/cli/core/cloud.py | 3 +++ src/azure-cli-core/azure/cli/core/telemetry.py | 10 +++++++++- .../cli/command_modules/configure/_consts.py | 3 +++ .../azure/cli/command_modules/configure/custom.py | 15 ++++++++++++--- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/azure-cli-core/azure/cli/core/cloud.py b/src/azure-cli-core/azure/cli/core/cloud.py index b03c6f96544..bc5e597a720 100644 --- a/src/azure-cli-core/azure/cli/core/cloud.py +++ b/src/azure-cli-core/azure/cli/core/cloud.py @@ -20,6 +20,9 @@ CLOUD_CONFIG_FILE = os.path.join(GLOBAL_CONFIG_DIR, 'clouds.config') +# Add names of clouds that don't allow telemetry data collection here such as JEDI. +CLOUDS_FORBIDDING_TELEMETRY = [] + class CloudNotRegisteredException(Exception): def __init__(self, cloud_name): diff --git a/src/azure-cli-core/azure/cli/core/telemetry.py b/src/azure-cli-core/azure/cli/core/telemetry.py index 39ceb516e45..2122200b085 100644 --- a/src/azure-cli-core/azure/cli/core/telemetry.py +++ b/src/azure-cli-core/azure/cli/core/telemetry.py @@ -204,7 +204,7 @@ def product_version(self): def _user_agrees_to_telemetry(func): @wraps(func) def _wrapper(*args, **kwargs): - if not _get_config().getboolean('core', 'collect_telemetry', fallback=True): + if not is_telemetry_enabled(): return None return func(*args, **kwargs) @@ -358,6 +358,14 @@ def _add_event(event_name, properties, instrumentation_key=DEFAULT_INSTRUMENTATI }) +@decorators.suppress_all_exceptions() +def is_telemetry_enabled(): + from azure.cli.core.cloud import AZURE_PUBLIC_CLOUD, CLOUDS_FORBIDDING_TELEMETRY + if _get_config().get('cloud', 'name', fallback=AZURE_PUBLIC_CLOUD.name) in CLOUDS_FORBIDDING_TELEMETRY: + return False + return _get_config().getboolean('core', 'collect_telemetry', fallback=True) + + # definitions @decorators.call_once diff --git a/src/azure-cli/azure/cli/command_modules/configure/_consts.py b/src/azure-cli/azure/cli/command_modules/configure/_consts.py index 1fe76a394b9..a90a99e86ec 100644 --- a/src/azure-cli/azure/cli/command_modules/configure/_consts.py +++ b/src/azure-cli/azure/cli/command_modules/configure/_consts.py @@ -30,6 +30,9 @@ ' $ az vm create --help\n' \ ' $ az feedback\n' +MSG_CLOUD_FORBID_TELEMETRY = '\nYour current cloud: {} does not allow data collection.' \ + ' Telemetry is disabled regardless of the configuration.' + MSG_GLOBAL_SETTINGS_LOCATION = 'Your settings can be found at {}' MSG_HEADING_CURRENT_CONFIG_INFO = 'Your current configuration is as follows:' diff --git a/src/azure-cli/azure/cli/command_modules/configure/custom.py b/src/azure-cli/azure/cli/command_modules/configure/custom.py index b11195eb5b1..736cd05e51b 100644 --- a/src/azure-cli/azure/cli/command_modules/configure/custom.py +++ b/src/azure-cli/azure/cli/command_modules/configure/custom.py @@ -26,6 +26,7 @@ MSG_PROMPT_TELEMETRY, MSG_PROMPT_FILE_LOGGING, MSG_PROMPT_CACHE_TTL, + MSG_CLOUD_FORBID_TELEMETRY, DEFAULT_CACHE_TTL) from azure.cli.command_modules.configure._utils import get_default_from_config @@ -96,7 +97,7 @@ def _config_env_public_azure(cli_ctx, _): logger.error(err) -def _handle_global_configuration(config): +def _handle_global_configuration(config, cloud_forbid_telemetry): # print location of global configuration print(MSG_GLOBAL_SETTINGS_LOCATION.format(config.config_path)) # set up the config parsers @@ -118,7 +119,10 @@ def _handle_global_configuration(config): answers['output_type_prompt'] = output_index answers['output_type_options'] = str(OUTPUT_LIST) enable_file_logging = prompt_y_n(MSG_PROMPT_FILE_LOGGING, default='n') - allow_telemetry = prompt_y_n(MSG_PROMPT_TELEMETRY, default='y') + if cloud_forbid_telemetry: + allow_telemetry = False + else: + allow_telemetry = prompt_y_n(MSG_PROMPT_TELEMETRY, default='y') answers['telemetry_prompt'] = allow_telemetry cache_ttl = None while not cache_ttl: @@ -140,6 +144,7 @@ def _handle_global_configuration(config): # pylint: disable=inconsistent-return-statements def handle_configure(cmd, defaults=None, list_defaults=None, scope=None): + from azure.cli.core.cloud import AZURE_PUBLIC_CLOUD, CLOUDS_FORBIDDING_TELEMETRY if defaults: defaults_section = cmd.cli_ctx.config.defaults_section_name with ConfiguredDefaultSetter(cmd.cli_ctx.config, scope.lower() == 'local'): @@ -157,8 +162,12 @@ def handle_configure(cmd, defaults=None, list_defaults=None, scope=None): # if nothing supplied, we go interactively try: print(MSG_INTRO) - _handle_global_configuration(cmd.cli_ctx.config) + current_cloud = cmd.cli_ctx.config.get('cloud', 'name', fallback=AZURE_PUBLIC_CLOUD.name) + cloud_forbid_telemetry = current_cloud in CLOUDS_FORBIDDING_TELEMETRY + _handle_global_configuration(cmd.cli_ctx.config, cloud_forbid_telemetry) print(MSG_CLOSING) + if cloud_forbid_telemetry: + logger.warning(MSG_CLOUD_FORBID_TELEMETRY.format(current_cloud)) # TODO: log_telemetry('configure', **answers) except NoTTYException: raise CLIError('This command is interactive and no tty available.') From b24494c54da6d3129c95fa78eb3ca36e69b7718a Mon Sep 17 00:00:00 2001 From: Feng Zhou Date: Mon, 2 Mar 2020 10:38:14 +0800 Subject: [PATCH 2/5] fix style --- src/azure-cli/azure/cli/command_modules/configure/_consts.py | 4 ++-- src/azure-cli/azure/cli/command_modules/configure/custom.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/configure/_consts.py b/src/azure-cli/azure/cli/command_modules/configure/_consts.py index a90a99e86ec..04ca4af91bc 100644 --- a/src/azure-cli/azure/cli/command_modules/configure/_consts.py +++ b/src/azure-cli/azure/cli/command_modules/configure/_consts.py @@ -30,8 +30,8 @@ ' $ az vm create --help\n' \ ' $ az feedback\n' -MSG_CLOUD_FORBID_TELEMETRY = '\nYour current cloud: {} does not allow data collection.' \ - ' Telemetry is disabled regardless of the configuration.' +WARNING_CLOUD_FORBID_TELEMETRY = '\nYour current cloud: %s does not allow data collection.' \ + ' Telemetry is disabled regardless of the configuration.' MSG_GLOBAL_SETTINGS_LOCATION = 'Your settings can be found at {}' diff --git a/src/azure-cli/azure/cli/command_modules/configure/custom.py b/src/azure-cli/azure/cli/command_modules/configure/custom.py index 736cd05e51b..2d29e1fc12d 100644 --- a/src/azure-cli/azure/cli/command_modules/configure/custom.py +++ b/src/azure-cli/azure/cli/command_modules/configure/custom.py @@ -26,7 +26,7 @@ MSG_PROMPT_TELEMETRY, MSG_PROMPT_FILE_LOGGING, MSG_PROMPT_CACHE_TTL, - MSG_CLOUD_FORBID_TELEMETRY, + WARNING_CLOUD_FORBID_TELEMETRY, DEFAULT_CACHE_TTL) from azure.cli.command_modules.configure._utils import get_default_from_config @@ -167,7 +167,7 @@ def handle_configure(cmd, defaults=None, list_defaults=None, scope=None): _handle_global_configuration(cmd.cli_ctx.config, cloud_forbid_telemetry) print(MSG_CLOSING) if cloud_forbid_telemetry: - logger.warning(MSG_CLOUD_FORBID_TELEMETRY.format(current_cloud)) + logger.warning(WARNING_CLOUD_FORBID_TELEMETRY, current_cloud) # TODO: log_telemetry('configure', **answers) except NoTTYException: raise CLIError('This command is interactive and no tty available.') From 8fb5c214d8e5bf95bd3d7df89750bfaf2b690926 Mon Sep 17 00:00:00 2001 From: Feng Zhou Date: Mon, 2 Mar 2020 11:50:18 +0800 Subject: [PATCH 3/5] refactor --- src/azure-cli-core/azure/cli/core/cloud.py | 3 +++ src/azure-cli-core/azure/cli/core/telemetry.py | 4 ++-- .../azure/cli/command_modules/configure/custom.py | 7 +++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/azure-cli-core/azure/cli/core/cloud.py b/src/azure-cli-core/azure/cli/core/cloud.py index bc5e597a720..a5edd3e534a 100644 --- a/src/azure-cli-core/azure/cli/core/cloud.py +++ b/src/azure-cli-core/azure/cli/core/cloud.py @@ -529,3 +529,6 @@ def remove_cloud(cli_ctx, cloud_name): config.remove_section(cloud_name) with open(CLOUD_CONFIG_FILE, 'w') as configfile: config.write(configfile) + +def cloud_forbid_telemetry(cli_ctx): + return get_active_cloud_name(cli_ctx) in CLOUDS_FORBIDDING_TELEMETRY diff --git a/src/azure-cli-core/azure/cli/core/telemetry.py b/src/azure-cli-core/azure/cli/core/telemetry.py index 2122200b085..f59c5b98d63 100644 --- a/src/azure-cli-core/azure/cli/core/telemetry.py +++ b/src/azure-cli-core/azure/cli/core/telemetry.py @@ -360,8 +360,8 @@ def _add_event(event_name, properties, instrumentation_key=DEFAULT_INSTRUMENTATI @decorators.suppress_all_exceptions() def is_telemetry_enabled(): - from azure.cli.core.cloud import AZURE_PUBLIC_CLOUD, CLOUDS_FORBIDDING_TELEMETRY - if _get_config().get('cloud', 'name', fallback=AZURE_PUBLIC_CLOUD.name) in CLOUDS_FORBIDDING_TELEMETRY: + from azure.cli.core.cloud import cloud_forbid_telemetry + if cloud_forbid_telemetry(_session.application): return False return _get_config().getboolean('core', 'collect_telemetry', fallback=True) diff --git a/src/azure-cli/azure/cli/command_modules/configure/custom.py b/src/azure-cli/azure/cli/command_modules/configure/custom.py index 2d29e1fc12d..62e4cd520cb 100644 --- a/src/azure-cli/azure/cli/command_modules/configure/custom.py +++ b/src/azure-cli/azure/cli/command_modules/configure/custom.py @@ -144,7 +144,7 @@ def _handle_global_configuration(config, cloud_forbid_telemetry): # pylint: disable=inconsistent-return-statements def handle_configure(cmd, defaults=None, list_defaults=None, scope=None): - from azure.cli.core.cloud import AZURE_PUBLIC_CLOUD, CLOUDS_FORBIDDING_TELEMETRY + from azure.cli.core.cloud import cloud_forbid_telemetry, get_active_cloud_name if defaults: defaults_section = cmd.cli_ctx.config.defaults_section_name with ConfiguredDefaultSetter(cmd.cli_ctx.config, scope.lower() == 'local'): @@ -162,12 +162,11 @@ def handle_configure(cmd, defaults=None, list_defaults=None, scope=None): # if nothing supplied, we go interactively try: print(MSG_INTRO) - current_cloud = cmd.cli_ctx.config.get('cloud', 'name', fallback=AZURE_PUBLIC_CLOUD.name) - cloud_forbid_telemetry = current_cloud in CLOUDS_FORBIDDING_TELEMETRY + cloud_forbid_telemetry = cloud_forbid_telemetry(cmd.cli_ctx) _handle_global_configuration(cmd.cli_ctx.config, cloud_forbid_telemetry) print(MSG_CLOSING) if cloud_forbid_telemetry: - logger.warning(WARNING_CLOUD_FORBID_TELEMETRY, current_cloud) + logger.warning(WARNING_CLOUD_FORBID_TELEMETRY, get_active_cloud_name(cmd.cli_ctx)) # TODO: log_telemetry('configure', **answers) except NoTTYException: raise CLIError('This command is interactive and no tty available.') From 158ac283e65e61567b0e7e56883a42fba418c8e5 Mon Sep 17 00:00:00 2001 From: Feng Zhou Date: Mon, 2 Mar 2020 22:52:00 +0800 Subject: [PATCH 4/5] add tests --- src/azure-cli-core/azure/cli/core/cloud.py | 1 + .../azure/cli/core/tests/test_telemetry.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/azure-cli-core/azure/cli/core/cloud.py b/src/azure-cli-core/azure/cli/core/cloud.py index a5edd3e534a..c00d924485f 100644 --- a/src/azure-cli-core/azure/cli/core/cloud.py +++ b/src/azure-cli-core/azure/cli/core/cloud.py @@ -530,5 +530,6 @@ def remove_cloud(cli_ctx, cloud_name): with open(CLOUD_CONFIG_FILE, 'w') as configfile: config.write(configfile) + def cloud_forbid_telemetry(cli_ctx): return get_active_cloud_name(cli_ctx) in CLOUDS_FORBIDDING_TELEMETRY diff --git a/src/azure-cli-core/azure/cli/core/tests/test_telemetry.py b/src/azure-cli-core/azure/cli/core/tests/test_telemetry.py index a897be455d8..5e8ef205666 100644 --- a/src/azure-cli-core/azure/cli/core/tests/test_telemetry.py +++ b/src/azure-cli-core/azure/cli/core/tests/test_telemetry.py @@ -39,3 +39,22 @@ def test_extract_parameters_correctly(self): args = ['vm', 'show', '-g', 'rg', '--name', 'vm1', '-d', '--debug'] self.assertEqual(['-g', '--name', '-d', '--debug'], AzCliCommandInvoker._extract_parameter_names(args)) + + + def test_cloud_forbid_telemetry(self): + import mock + import azure.cli.core.telemetry as telemetry + from azure.cli.core.mock import DummyCli + from knack.completion import ARGCOMPLETE_ENV_NAME + + az_cli = DummyCli() + telemetry.set_application(az_cli, ARGCOMPLETE_ENV_NAME) + # mock user turns off telemetry + with mock.patch('knack.config.CLIConfig.getboolean', return_value=False): + self.assertFalse(telemetry.is_telemetry_enabled()) + # mock user turns on telemetry + with mock.patch('knack.config.CLIConfig.getboolean', return_value=True): + self.assertTrue(telemetry.is_telemetry_enabled()) + # mock to add current cloud name in CLOUDS_FORBIDDING_TELEMETRY + with mock.patch('azure.cli.core.cloud.CLOUDS_FORBIDDING_TELEMETRY', [az_cli.cloud.name]): + self.assertFalse(telemetry.is_telemetry_enabled()) From 1cb75c7af49dcf79dec0b6291de180489a8ca7d9 Mon Sep 17 00:00:00 2001 From: Feng Zhou Date: Tue, 3 Mar 2020 10:40:35 +0800 Subject: [PATCH 5/5] fix style --- src/azure-cli-core/azure/cli/core/tests/test_telemetry.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/azure-cli-core/azure/cli/core/tests/test_telemetry.py b/src/azure-cli-core/azure/cli/core/tests/test_telemetry.py index 5e8ef205666..fc1204da304 100644 --- a/src/azure-cli-core/azure/cli/core/tests/test_telemetry.py +++ b/src/azure-cli-core/azure/cli/core/tests/test_telemetry.py @@ -40,13 +40,12 @@ def test_extract_parameters_correctly(self): args = ['vm', 'show', '-g', 'rg', '--name', 'vm1', '-d', '--debug'] self.assertEqual(['-g', '--name', '-d', '--debug'], AzCliCommandInvoker._extract_parameter_names(args)) - def test_cloud_forbid_telemetry(self): import mock import azure.cli.core.telemetry as telemetry from azure.cli.core.mock import DummyCli from knack.completion import ARGCOMPLETE_ENV_NAME - + az_cli = DummyCli() telemetry.set_application(az_cli, ARGCOMPLETE_ENV_NAME) # mock user turns off telemetry