diff --git a/src/azure-cli/azure/cli/command_modules/appservice/_help.py b/src/azure-cli/azure/cli/command_modules/appservice/_help.py index ad0aca195ec..d056005a434 100644 --- a/src/azure-cli/azure/cli/command_modules/appservice/_help.py +++ b/src/azure-cli/azure/cli/command_modules/appservice/_help.py @@ -2605,6 +2605,26 @@ text: az staticwebapp functions show -n MyStaticAppName -g MyResourceGroup """ +helps['staticwebapp enterprise-edge'] = """ + type: group + short-summary: Manage the Azure Front Door CDN for static webapps. For optimal experience and availability please check our documentation https://aka.ms/swaedge +""" + +helps['staticwebapp enterprise-edge enable'] = """ + type: command + short-summary: Enable the Azure Front Door CDN for a static webapp. Enabling enterprise-grade edge requires re-registration for the Azure Front Door Microsoft.CDN resource provider. For optimal experience and availability please check our documentation https://aka.ms/swaedge +""" + +helps['staticwebapp enterprise-edge disable'] = """ + type: command + short-summary: Disable the Azure Front Door CDN for a static webapp. For optimal experience and availability please check our documentation https://aka.ms/swaedge +""" + +helps['staticwebapp enterprise-edge show'] = """ + type: command + short-summary: Show the status (Enabled, Disabled, Enabling, Disabling) of the Azure Front Door CDN for a webapp. For optimal experience and availability please check our documentation https://aka.ms/swaedge +""" + helps['webapp deploy'] = """ type: command short-summary: Deploys a provided artifact to Azure Web Apps. diff --git a/src/azure-cli/azure/cli/command_modules/appservice/_params.py b/src/azure-cli/azure/cli/command_modules/appservice/_params.py index 2409a138564..cad84f91140 100644 --- a/src/azure-cli/azure/cli/command_modules/appservice/_params.py +++ b/src/azure-cli/azure/cli/command_modules/appservice/_params.py @@ -1061,3 +1061,6 @@ def load_arguments(self, _): with self.argument_context('staticwebapp functions link') as c: c.argument('function_resource_id', help="Resource ID of the functionapp to link. Can be retrieved with 'az functionapp --query id'") c.argument('force', help="Force the function link even if the function is already linked to a static webapp. May be needed if the function was previously linked to a static webapp.") + + with self.argument_context('staticwebapp enterprise-edge') as c: + c.argument("no_register", help="Don't try to register the Microsoft.CDN provider. Registration can be done manually with: az provider register --wait --namespace Microsoft.CDN. For more details, please review the documentation available at https://go.microsoft.com/fwlink/?linkid=2184995 .", default=False) diff --git a/src/azure-cli/azure/cli/command_modules/appservice/commands.py b/src/azure-cli/azure/cli/command_modules/appservice/commands.py index 20ce07e0467..038040ef33e 100644 --- a/src/azure-cli/azure/cli/command_modules/appservice/commands.py +++ b/src/azure-cli/azure/cli/command_modules/appservice/commands.py @@ -483,6 +483,11 @@ def load_command_table(self, _): g.custom_command('unlink', 'unlink_user_function', validator=validate_staticsite_sku) g.custom_show_command('show', 'get_user_function', validator=validate_staticsite_sku) + with self.command_group('staticwebapp enterprise-edge', custom_command_type=staticsite_sdk) as g: + g.custom_command('enable', 'enable_staticwebapp_enterprise_edge') + g.custom_command('disable', 'disable_staticwebapp_enterprise_edge') + g.custom_show_command('show', 'show_staticwebapp_enterprise_edge_status') + with self.command_group('logicapp') as g: g.custom_command('delete', 'delete_function_app', confirmation=True) g.custom_command('stop', 'stop_webapp') diff --git a/src/azure-cli/azure/cli/command_modules/appservice/static_sites.py b/src/azure-cli/azure/cli/command_modules/appservice/static_sites.py index 36e638fe5ef..f37a2dc9cb0 100644 --- a/src/azure-cli/azure/cli/command_modules/appservice/static_sites.py +++ b/src/azure-cli/azure/cli/command_modules/appservice/static_sites.py @@ -8,12 +8,13 @@ from azure.cli.core.commands import LongRunningOperation from azure.cli.core.azclierror import (ResourceNotFoundError, ValidationError, RequiredArgumentMissingError, - InvalidArgumentValueError) + InvalidArgumentValueError, UnauthorizedError) from knack.log import get_logger from msrestazure.tools import parse_resource_id from .utils import normalize_sku_for_staticapp, raise_missing_token_suggestion from .custom import show_app, _build_identities_info +from ._client_factory import providers_client_factory logger = get_logger(__name__) @@ -596,3 +597,59 @@ def unlink_user_function(cmd, name, resource_group_name): def get_user_function(cmd, name, resource_group_name): client = _get_staticsites_client_factory(cmd.cli_ctx) return client.get_user_provided_function_apps_for_static_site(name=name, resource_group_name=resource_group_name) + + +def _enterprise_edge_warning(): + logger.warning("For optimal experience and availability please check our documentation https://aka.ms/swaedge") + + +def _update_enterprise_edge(cmd, name, resource_group_name, enable: bool): + client = _get_staticsites_client_factory(cmd.cli_ctx) + site = client.get_static_site(resource_group_name, name) + site.enterprise_grade_cdn_status = "enabled" if enable else "disabled" + return client.update_static_site(resource_group_name=resource_group_name, name=name, static_site_envelope=site) + + +def _register_cdn_provider(cmd): + from azure.mgmt.resource.resources.models import ProviderRegistrationRequest, ProviderConsentDefinition + + namespace = "Microsoft.CDN" + properties = ProviderRegistrationRequest(third_party_provider_consent=ProviderConsentDefinition( + consent_to_authorization=True)) + + client = providers_client_factory(cmd.cli_ctx) + try: + client.register(namespace, properties=properties) + except Exception as e: + msg = "Server responded with error message : {} \n"\ + "Enabling enterprise-grade edge requires reregistration for the Azure Front "\ + "Door Microsoft.CDN resource provider. We were unable to perform that reregistration on your "\ + "behalf. Please check with your admin on permissions and review the documentation available at "\ + "https://go.microsoft.com/fwlink/?linkid=2185350. "\ + "Or try running registration manually with: az provider register --wait --namespace Microsoft.CDN" + raise UnauthorizedError(msg.format(e.args)) from e + + +def enable_staticwebapp_enterprise_edge(cmd, name, resource_group_name, no_register=False): + _enterprise_edge_warning() + if not no_register: + _register_cdn_provider(cmd) + _update_enterprise_edge(cmd, name, resource_group_name, enable=True) + return _get_enterprise_edge_status(cmd, name, resource_group_name) + + +def disable_staticwebapp_enterprise_edge(cmd, name, resource_group_name): + _enterprise_edge_warning() + _update_enterprise_edge(cmd, name, resource_group_name, enable=False) + return _get_enterprise_edge_status(cmd, name, resource_group_name) + + +def _get_enterprise_edge_status(cmd, name, resource_group_name): + client = _get_staticsites_client_factory(cmd.cli_ctx) + site = client.get_static_site(resource_group_name, name) + return {"enterpriseGradeCdnStatus": site.enterprise_grade_cdn_status} + + +def show_staticwebapp_enterprise_edge_status(cmd, name, resource_group_name): + _enterprise_edge_warning() + return _get_enterprise_edge_status(cmd, name, resource_group_name) diff --git a/src/azure-cli/azure/cli/command_modules/appservice/tests/latest/test_staticapp_commands_thru_mock.py b/src/azure-cli/azure/cli/command_modules/appservice/tests/latest/test_staticapp_commands_thru_mock.py index c2ccc900988..203c7d9d8d4 100644 --- a/src/azure-cli/azure/cli/command_modules/appservice/tests/latest/test_staticapp_commands_thru_mock.py +++ b/src/azure-cli/azure/cli/command_modules/appservice/tests/latest/test_staticapp_commands_thru_mock.py @@ -13,7 +13,7 @@ set_staticsite_app_settings, delete_staticsite_app_settings, list_staticsite_users, \ invite_staticsite_users, update_staticsite_users, update_staticsite, list_staticsite_secrets, \ reset_staticsite_api_key, delete_staticsite_environment, link_user_function, unlink_user_function, get_user_function, \ - assign_identity, remove_identity, show_identity + assign_identity, remove_identity, show_identity, enable_staticwebapp_enterprise_edge, disable_staticwebapp_enterprise_edge, show_staticwebapp_enterprise_edge_status from azure.core.exceptions import ResourceNotFoundError @@ -612,6 +612,26 @@ def test_functions_show(self, *args, **kwargs): self.staticapp_client.get_user_provided_function_apps_for_static_site.assert_called_once() + def test_enterprise_edge(self): + self.staticapp_client.get_static_site.return_value = self.app1 + + enable_staticwebapp_enterprise_edge(self.mock_cmd, self.name1, self.rg1, no_register=True) + self.staticapp_client.update_static_site.assert_called_once() + arg_list = self.staticapp_client.update_static_site.call_args[1] + self.assertEqual(self.name1, arg_list["name"]) + self.assertEqual("enabled", arg_list["static_site_envelope"].enterprise_grade_cdn_status) + + disable_staticwebapp_enterprise_edge(self.mock_cmd, self.name1, self.rg1) + self.assertEqual(self.staticapp_client.update_static_site.call_count, 2) + arg_list = self.staticapp_client.update_static_site.call_args[1] + self.assertEqual(self.name1, arg_list["name"]) + self.assertEqual("disabled", arg_list["static_site_envelope"].enterprise_grade_cdn_status) + + self.app1.enterprise_grade_cdn_status = "disabling" + status = show_staticwebapp_enterprise_edge_status(self.mock_cmd, self.name1, self.rg1) + self.assertEqual(status.get("enterpriseGradeCdnStatus"), "disabling") + + def _set_up_client_mock(self): self.mock_cmd = mock.MagicMock() self.mock_cmd.cli_ctx = mock.MagicMock()