Skip to content

Commit

Permalink
Static Webapp Azure Frontdoor Integration (enterprise edge) (#3959)
Browse files Browse the repository at this point in the history
* add enterprise-edge extension

* add SKU validation

* remove 'az staticwebapp enterprise-edge wait'

* fix style/linter issues

* add provider validation

* update summary

* fix package data

* fix CODEOWNERS

* add static webapps to service_name

* add swa docs URL notification and help text

* remove out of date TODO

* fix typo

* handle lack of JSON response from server when enabling/disabling the CDN

* Fix style
  • Loading branch information
StrawnSC committed Jan 11, 2022
1 parent f549964 commit 5b0c34b
Show file tree
Hide file tree
Showing 15 changed files with 289 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@

/src/purview/ @kairu-ms @jsntcy

/src/enterprise-edge/ @StrawnSC

/src/functionapp/ @gzuber

/src/elastic/ @kairu-ms @jsntcy
Expand Down
8 changes: 8 additions & 0 deletions src/enterprise-edge/HISTORY.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.. :changelog:
Release History
===============

0.1.0
++++++
* Initial release.
5 changes: 5 additions & 0 deletions src/enterprise-edge/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Microsoft Azure CLI 'enterprise-edge' Extension
==========================================

This package is for the 'enterprise-edge' extension.
i.e. 'az staticwebapp enterprise-edge'
29 changes: 29 additions & 0 deletions src/enterprise-edge/azext_enterprise_edge/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from azure.cli.core import AzCommandsLoader

from azext_enterprise_edge._help import helps # pylint: disable=unused-import


class EnterpriseEdgeCommandsLoader(AzCommandsLoader):

def __init__(self, cli_ctx=None):
from azure.cli.core.commands import CliCommandType
enterprise_edge_custom = CliCommandType(
operations_tmpl='azext_enterprise_edge.custom#{}')
super().__init__(cli_ctx=cli_ctx, custom_command_type=enterprise_edge_custom)

def load_command_table(self, args):
from azext_enterprise_edge.commands import load_command_table
load_command_table(self, args)
return self.command_table

def load_arguments(self, command):
from azext_enterprise_edge._params import load_arguments
load_arguments(self, command)


COMMAND_LOADER_CLS = EnterpriseEdgeCommandsLoader
28 changes: 28 additions & 0 deletions src/enterprise-edge/azext_enterprise_edge/_help.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# coding=utf-8
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from knack.help_files import helps # pylint: disable=unused-import


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. 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
"""
19 changes: 19 additions & 0 deletions src/enterprise-edge/azext_enterprise_edge/_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
# pylint: disable=line-too-long

from knack.arguments import CLIArgumentType

from azure.cli.core.commands.parameters import resource_group_name_type


def load_arguments(self, _):
staticsite_name_arg_type = CLIArgumentType(options_list=['--name', '-n'],
metavar='NAME',
help="name of the staticwebapp")

with self.argument_context('staticwebapp enterprise-edge') as c:
c.argument("name", arg_type=staticsite_name_arg_type)
c.argument("resource_group_name", arg_type=resource_group_name_type)
4 changes: 4 additions & 0 deletions src/enterprise-edge/azext_enterprise_edge/azext_metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"azext.isPreview": true,
"azext.minCliCoreVersion": "2.29.0"
}
13 changes: 13 additions & 0 deletions src/enterprise-edge/azext_enterprise_edge/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

# pylint: disable=line-too-long


def load_command_table(self, _):
with self.command_group('staticwebapp enterprise-edge', is_preview=True) 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')
94 changes: 94 additions & 0 deletions src/enterprise-edge/azext_enterprise_edge/custom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import json

from knack.util import CLIError
from knack.log import get_logger

from azure.cli.core.util import send_raw_request
from azure.cli.core.commands.client_factory import get_subscription_id


logger = get_logger(__name__)


class StaticWebAppFrontDoorClient:
@classmethod
def _request(cls, cmd, resource_group, name, http_method="GET", body=None):
management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
api_version = "2021-02-01"
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Web/staticSites/{}?api-version={}"
request_url = url_fmt.format(
management_hostname.strip('/'),
sub_id,
resource_group,
name,
api_version)

if body is not None:
r = send_raw_request(cmd.cli_ctx, http_method, request_url, body=json.dumps(body))
else:
r = send_raw_request(cmd.cli_ctx, http_method, request_url)

return r

@classmethod
def set(cls, cmd, resource_group, name, enable):
params = cls.get(cmd, resource_group, name).json()

if enable:
cls._validate_cdn_provider_registered(cmd)
cls._validate_sku(params["sku"].get("name"))

params["properties"]["enterpriseGradeCdnStatus"] = "enabled" if enable else "disabled"
return cls._request(cmd, resource_group, name, "PUT", params)

@classmethod
def get(cls, cmd, resource_group, name):
return cls._request(cmd, resource_group, name)

@classmethod
def _validate_cdn_provider_registered(cls, cmd):
management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
api_version = "2021-04-01"
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/providers/Microsoft.CDN?api-version={}"

request_url = url_fmt.format(management_hostname.strip('/'), sub_id, api_version)

registration = send_raw_request(cmd.cli_ctx, "GET", request_url).json().get("registrationState").lower()
if registration != "registered":
raise CLIError("Provider Microsoft.CDN is not registered. "
"Please run 'az provider register --wait --namespace Microsoft.CDN'")

@classmethod
def _validate_sku(cls, sku_name):
if sku_name.lower() != "standard":
raise CLIError("Invalid SKU: '{}'. Staticwebapp must have 'Standard' SKU to use "
"enterprise edge CDN".format(sku_name))


def _format_show_response(cmd, name, resource_group_name):
staticsite_data = StaticWebAppFrontDoorClient.get(cmd, name=name, resource_group=resource_group_name).json()
return {"enterpriseGradeCdnStatus": staticsite_data["properties"]["enterpriseGradeCdnStatus"]}


def enable_staticwebapp_enterprise_edge(cmd, name, resource_group_name):
logger.warn("For optimal experience and availability please check our documentation https://aka.ms/swaedge")
StaticWebAppFrontDoorClient.set(cmd, name=name, resource_group=resource_group_name, enable=True)
return _format_show_response(cmd, name, resource_group_name)


def disable_staticwebapp_enterprise_edge(cmd, name, resource_group_name):
logger.warn("For optimal experience and availability please check our documentation https://aka.ms/swaedge")
StaticWebAppFrontDoorClient.set(cmd, name=name, resource_group=resource_group_name, enable=False)
return _format_show_response(cmd, name, resource_group_name)


def show_staticwebapp_enterprise_edge_status(cmd, name, resource_group_name):
logger.warn("For optimal experience and availability please check our documentation https://aka.ms/swaedge")
return _format_show_response(cmd, name, resource_group_name)
5 changes: 5 additions & 0 deletions src/enterprise-edge/azext_enterprise_edge/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -----------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# -----------------------------------------------------------------------------
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -----------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# -----------------------------------------------------------------------------
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import os
import unittest

from azure_devtools.scenario_tests import AllowLargeResponse
from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer)


TEST_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), '..'))


# TODO
Empty file added src/enterprise-edge/setup.cfg
Empty file.
56 changes: 56 additions & 0 deletions src/enterprise-edge/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env python

# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------


from codecs import open
from setuptools import setup, find_packages
try:
from azure_bdist_wheel import cmdclass
except ImportError:
from distutils import log as logger
logger.warn("Wheel is not available, disabling bdist_wheel hook")

# TODO: Confirm this is the right version number you want and it matches your
# HISTORY.rst entry.
VERSION = '0.1.0'

# The full list of classifiers is available at
# https://pypi.python.org/pypi?%3Aaction=list_classifiers
CLASSIFIERS = [
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Intended Audience :: System Administrators',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'License :: OSI Approved :: MIT License',
]

DEPENDENCIES = []

with open('README.rst', 'r', encoding='utf-8') as f:
README = f.read()
with open('HISTORY.rst', 'r', encoding='utf-8') as f:
HISTORY = f.read()

setup(
name='enterprise-edge',
version=VERSION,
description='Support for Static Webapp-Azure Front Door Integration (aka Static Webapp Enterprise Edge)',
# TODO: Update author and email, if applicable
author='Microsoft Corporation',
author_email='azpycli@microsoft.com',
url='https://github.com/Azure/azure-cli-extensions/tree/master/src/enterprise-edge',
long_description=README + '\n\n' + HISTORY,
license='MIT',
classifiers=CLASSIFIERS,
packages=find_packages(),
install_requires=DEPENDENCIES,
package_data={'azext_enterprise_edge': ['azext_metadata.json']},
)
5 changes: 5 additions & 0 deletions src/service_name.json
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,11 @@
"AzureServiceName": "Azure Stack",
"URL": "https://docs.microsoft.com/azure-stack/hci/"
},
{
"Command": "az staticwebapp",
"AzureServiceName": "Azure Static Web Apps",
"URL": "https://azure.microsoft.com/en-us/services/app-service/static/"
},
{
"Command": "az storage",
"AzureServiceName": "Azure Storage",
Expand Down

0 comments on commit 5b0c34b

Please sign in to comment.