diff --git a/src/azure-cli/azure/cli/command_modules/acr/_utils.py b/src/azure-cli/azure/cli/command_modules/acr/_utils.py index 3873b4a4124..71e73478d58 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/_utils.py +++ b/src/azure-cli/azure/cli/command_modules/acr/_utils.py @@ -38,6 +38,19 @@ logger = get_logger(__name__) +def get_warning_response_hook(): + """Create an SDK response hook that emits each LRO warning once.""" + displayed_warnings = set() + + def _show_warning(response): + warning = response.http_response.headers.get('x-ms-warning') + if warning and warning not in displayed_warnings: + logger.warning('%s', warning) + displayed_warnings.add(warning) + + return _show_warning + + def _arm_get_resource_by_name(cli_ctx, resource_name, resource_type): """Returns the ARM resource in the current subscription with resource_name. :param str resource_name: The name of resource diff --git a/src/azure-cli/azure/cli/command_modules/acr/scope_map.py b/src/azure-cli/azure/cli/command_modules/acr/scope_map.py index 6228989a61a..72be4a95782 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/scope_map.py +++ b/src/azure-cli/azure/cli/command_modules/acr/scope_map.py @@ -6,6 +6,7 @@ from enum import Enum from azure.cli.core.util import CLIError from ._utils import ( + get_warning_response_hook, get_resource_group_name_by_registry_name, parse_scope_map_actions ) @@ -70,7 +71,12 @@ def acr_scope_map_delete(cmd, return None resource_group_name = get_resource_group_name_by_registry_name(cmd.cli_ctx, registry_name, resource_group_name) - return client.begin_delete(resource_group_name, registry_name, scope_map_name) + return client.begin_delete( + resource_group_name, + registry_name, + scope_map_name, + raw_response_hook=get_warning_response_hook() + ) def acr_scope_map_update(cmd, diff --git a/src/azure-cli/azure/cli/command_modules/acr/tests/latest/test_acr_commands_mock.py b/src/azure-cli/azure/cli/command_modules/acr/tests/latest/test_acr_commands_mock.py index 95c8e3c34db..902ef47f6de 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/tests/latest/test_acr_commands_mock.py +++ b/src/azure-cli/azure/cli/command_modules/acr/tests/latest/test_acr_commands_mock.py @@ -39,6 +39,7 @@ acr_helm_delete, acr_helm_push ) +from azure.cli.command_modules.acr.scope_map import acr_scope_map_delete from azure.cli.command_modules.acr._docker_utils import ( get_login_credentials, get_access_credentials, @@ -64,6 +65,54 @@ class AcrMockCommandsTests(unittest.TestCase): + @mock.patch('azure.cli.command_modules.acr._utils.logger') + @mock.patch( + 'azure.cli.command_modules.acr.scope_map.' + 'get_resource_group_name_by_registry_name' + ) + def test_scope_map_delete_surfaces_warning_once( + self, mock_get_resource_group, mock_logger): + mock_get_resource_group.return_value = 'testresourcegroup' + client = mock.MagicMock() + client.begin_delete.return_value = mock.sentinel.poller + + result = acr_scope_map_delete( + self._setup_cmd(), + client, + 'testregistry', + 'testscopemap', + yes=True + ) + + self.assertIs(result, mock.sentinel.poller) + client.begin_delete.assert_called_once_with( + 'testresourcegroup', + 'testregistry', + 'testscopemap', + raw_response_hook=mock.ANY + ) + + response_hook = client.begin_delete.call_args.kwargs[ + 'raw_response_hook' + ] + response = mock.MagicMock() + response.http_response.headers = {} + response_hook(response) + mock_logger.warning.assert_not_called() + + warning = ( + "Could not find the authorization entity for token(s): " + "'testtoken'." + ) + response.http_response.headers = { + 'x-ms-warning': warning + } + + response_hook(response) + response_hook(response) + + mock_logger.warning.assert_called_once_with('%s', warning) + @mock.patch('azure.cli.command_modules.acr.repository.get_access_credentials', autospec=True) @mock.patch('requests.request', autospec=True) def test_repository_list(self, mock_requests_get, mock_get_access_credentials):