Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
WINDOWS_OS_NAME = "windows"
STATIC_RUNTIME_NAME = "static" # not an official supported runtime but used for CLI logic
LINUX_SKU_DEFAULT = "P1V2"
ISOLATED_V4_SKUS = [
'I1V4', 'I2V4', 'I3V4', 'I4V4', 'I5V4', 'I6V4',
'I1MV4', 'I2MV4', 'I3MV4', 'I4MV4', 'I5MV4'
]
FUNCTIONS_VERSIONS = ['4']
LOGICAPPS_NODE_RUNTIME_VERSIONS = ['~14', '~16', '~18']
FUNCTIONS_LINUX_RUNTIME_VERSION_REGEX = r"^.*\|(.*)$"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from ._completers import get_hostname_completion_list
from ._constants import (FUNCTIONS_VERSIONS, LOGICAPPS_NODE_RUNTIME_VERSIONS, WINDOWS_OS_NAME, LINUX_OS_NAME,
DEPLOYMENT_STORAGE_AUTH_TYPES, UPDATE_STRATEGY_TYPES)
DEPLOYMENT_STORAGE_AUTH_TYPES, UPDATE_STRATEGY_TYPES, ISOLATED_V4_SKUS)

from ._validators import (validate_timeout_value, validate_site_create, validate_asp_create,
validate_ase_create, validate_ip_address,
Expand Down Expand Up @@ -56,9 +56,9 @@ def load_arguments(self, _):
# PARAMETER REGISTRATION
name_arg_type = CLIArgumentType(options_list=['--name', '-n'], metavar='NAME')
sku_arg_type = CLIArgumentType(
help='The pricing tiers, e.g., F1(Free), D1(Shared), B1(Basic Small), B2(Basic Medium), B3(Basic Large), S1(Standard Small), P1V2(Premium V2 Small), P2V2(Premium V2 Medium), P3V2(Premium V2 Large), P0V3(Premium V3 Extra Small), P1V3(Premium V3 Small), P2V3(Premium V3 Medium), P3V3(Premium V3 Large), P1MV3(Premium Memory Optimized V3 Small), P2MV3(Premium Memory Optimized V3 Medium), P3MV3(Premium Memory Optimized V3 Large), P4MV3(Premium Memory Optimized V3 Extra Large), P5MV3(Premium Memory Optimized V3 Extra Extra Large), P0V4(Premium V4 Extra Small), P1V4(Premium V4 Small), P2V4(Premium V4 Medium), P3V4(Premium V4 Large), P1MV4(Premium Memory Optimized V4 Small), P2MV4(Premium Memory Optimized V4 Medium), P3MV4(Premium Memory Optimized V4 Large), P4MV4(Premium Memory Optimized V4 Extra Large), P5MV4(Premium Memory Optimized V4 Extra Extra Large), I1V2 (Isolated V2 I1V2), I2V2 (Isolated V2 I2V2), I3V2 (Isolated V2 I3V2), I4V2 (Isolated V2 I4V2), I5V2 (Isolated V2 I5V2), I6V2 (Isolated V2 I6V2), I1MV2 (Isolated Memory Optimized V2 I1MV2), I2MV2 (Isolated Memory Optimized V2 I2MV2), I3MV2 (Isolated Memory Optimized V2 I3MV2), I4MV2 (Isolated Memory Optimized V2 I4MV2), I5MV2 (Isolated Memory Optimized V2 I5MV2), WS1 (Logic Apps Workflow Standard 1), WS2 (Logic Apps Workflow Standard 2), WS3 (Logic Apps Workflow Standard 3)',
help='The pricing tiers, e.g., F1(Free), D1(Shared), B1(Basic Small), B2(Basic Medium), B3(Basic Large), S1(Standard Small), P1V2(Premium V2 Small), P2V2(Premium V2 Medium), P3V2(Premium V2 Large), P0V3(Premium V3 Extra Small), P1V3(Premium V3 Small), P2V3(Premium V3 Medium), P3V3(Premium V3 Large), P1MV3(Premium Memory Optimized V3 Small), P2MV3(Premium Memory Optimized V3 Medium), P3MV3(Premium Memory Optimized V3 Large), P4MV3(Premium Memory Optimized V3 Extra Large), P5MV3(Premium Memory Optimized V3 Extra Extra Large), P0V4(Premium V4 Extra Small), P1V4(Premium V4 Small), P2V4(Premium V4 Medium), P3V4(Premium V4 Large), P1MV4(Premium Memory Optimized V4 Small), P2MV4(Premium Memory Optimized V4 Medium), P3MV4(Premium Memory Optimized V4 Large), P4MV4(Premium Memory Optimized V4 Extra Large), P5MV4(Premium Memory Optimized V4 Extra Extra Large), I1V2 (Isolated V2 I1V2), I2V2 (Isolated V2 I2V2), I3V2 (Isolated V2 I3V2), I4V2 (Isolated V2 I4V2), I5V2 (Isolated V2 I5V2), I6V2 (Isolated V2 I6V2), I1MV2 (Isolated Memory Optimized V2 I1MV2), I2MV2 (Isolated Memory Optimized V2 I2MV2), I3MV2 (Isolated Memory Optimized V2 I3MV2), I4MV2 (Isolated Memory Optimized V2 I4MV2), I5MV2 (Isolated Memory Optimized V2 I5MV2), I1V4-I6V4 (Isolated V4), I1MV4-I5MV4 (Isolated Memory Optimized V4), WS1 (Logic Apps Workflow Standard 1), WS2 (Logic Apps Workflow Standard 2), WS3 (Logic Apps Workflow Standard 3)',
arg_type=get_enum_type(
['F1', 'FREE', 'D1', 'SHARED', 'B1', 'B2', 'B3', 'S1', 'S2', 'S3', 'P1V2', 'P2V2', 'P3V2', 'P0V3', 'P1V3', 'P2V3', 'P3V3', 'P1MV3', 'P2MV3', 'P3MV3', 'P4MV3', 'P5MV3', 'P0V4', 'P1V4', 'P2V4', 'P3V4', 'P1MV4', 'P2MV4', 'P3MV4', 'P4MV4', 'P5MV4', 'I1V2', 'I2V2', 'I3V2', 'I4V2', 'I5V2', 'I6V2', 'I1MV2', 'I2MV2', 'I3MV2', 'I4MV2', 'I5MV2', 'WS1', 'WS2', 'WS3']))
['F1', 'FREE', 'D1', 'SHARED', 'B1', 'B2', 'B3', 'S1', 'S2', 'S3', 'P1V2', 'P2V2', 'P3V2', 'P0V3', 'P1V3', 'P2V3', 'P3V3', 'P1MV3', 'P2MV3', 'P3MV3', 'P4MV3', 'P5MV3', 'P0V4', 'P1V4', 'P2V4', 'P3V4', 'P1MV4', 'P2MV4', 'P3MV4', 'P4MV4', 'P5MV4', 'I1V2', 'I2V2', 'I3V2', 'I4V2', 'I5V2', 'I6V2', 'I1MV2', 'I2MV2', 'I3MV2', 'I4MV2', 'I5MV2', 'WS1', 'WS2', 'WS3'] + ISOLATED_V4_SKUS))
Comment thread
seligj95 marked this conversation as resolved.
Comment thread
seligj95 marked this conversation as resolved.
webapp_name_arg_type = CLIArgumentType(configured_default='web', options_list=['--name', '-n'], metavar='NAME',
completer=get_resource_name_completion_list('Microsoft.Web/sites'),
id_part='name',
Expand Down Expand Up @@ -1057,7 +1057,7 @@ def load_arguments(self, _):
help="Configure default logging required to enable viewing log stream immediately after launching the webapp",
default=False, action='store_true')
c.argument('html', help="Ignore app detection and deploy as an html app", default=False, action='store_true')
c.argument('app_service_environment', options_list=['--app-service-environment', '-e'], help='name or resource ID of the (pre-existing) App Service Environment to deploy to. Requires an Isolated V2 sku')
c.argument('app_service_environment', options_list=['--app-service-environment', '-e'], help='name or resource ID of the (pre-existing) App Service Environment to deploy to. Requires an Isolated V2 or Isolated V4 sku')
c.argument('basic_auth', help='Enable or disable basic auth.', arg_type=get_enum_type(BASIC_AUTH_TYPES))
c.argument('track_status', help="If true, web app startup status during deployment will be tracked for linux web apps.",
arg_type=get_three_state_flag())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

from .aaz.latest.network import ListServiceTags
from .aaz.latest.network.vnet import List as VNetList, Show as VNetShow
from ._constants import ACR_IMAGE_SUFFIX
from ._constants import ACR_IMAGE_SUFFIX, ISOLATED_V4_SKUS

logger = get_logger(__name__)

Expand Down Expand Up @@ -93,19 +93,20 @@ def validate_ase_create(cmd, namespace):


def _validate_asp_sku(sku, app_service_environment, zone_redundant):
supported_skus = ['PREMIUMV2', 'PREMIUMV3', 'PREMIUMMV3', 'PREMIUM0V3', 'PREMIUMV4', 'PREMIUMMV4', 'ISOLATEDV2', 'ISOLATEDMV2', 'ELASTICPREMIUM'] # pylint: disable=line-too-long
supported_skus = ['PREMIUMV2', 'PREMIUMV3', 'PREMIUMMV3', 'PREMIUM0V3', 'PREMIUMV4', 'PREMIUMMV4', 'ISOLATEDV2', 'ISOLATEDMV2', 'ISOLATEDV4', 'ELASTICPREMIUM'] # pylint: disable=line-too-long
if zone_redundant and get_sku_tier(sku).upper() not in supported_skus:
raise ValidationError("Zone redundancy cannot be enabled for sku {}".format(sku))
# Isolated SKU is supported only for ASE
if sku.upper() in ['I1V2', 'I2V2', 'I3V2', 'I4V2', 'I5V2', 'I6V2', 'I1MV2', 'I2MV2', 'I3MV2', 'I4MV2', 'I5MV2']:
if sku.upper() in ['I1V2', 'I2V2', 'I3V2', 'I4V2', 'I5V2', 'I6V2',
'I1MV2', 'I2MV2', 'I3MV2', 'I4MV2', 'I5MV2'] + ISOLATED_V4_SKUS:
if not app_service_environment:
raise ValidationError("The pricing tier 'Isolated' is not allowed for this app service plan. "
"Use this link to learn more: "
"https://learn.microsoft.com/azure/app-service/overview-hosting-plans")
else:
if app_service_environment:
raise ValidationError("Only pricing tier 'IsolatedV2' and 'IsolatedMV2' is allowed in this "
"app service plan. Use this link to "
raise ValidationError("Only pricing tiers 'IsolatedV2', 'IsolatedMV2', and 'IsolatedV4' are allowed "
"in this app service plan. Use this link to "
"learn more: https://learn.microsoft.com/azure/app-service/overview-hosting-plans")


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
RUNTIME_STATUS_TEXT_MAP, LANGUAGE_EOL_DEPRECATION_NOTICES,
STORAGE_BLOB_DATA_CONTRIBUTOR_ROLE_ID)
from ._github_oauth import (get_github_access_token, cache_github_token)
from ._validators import validate_and_convert_to_int, validate_range_of_int_flag
from ._validators import validate_and_convert_to_int, validate_range_of_int_flag, _validate_asp_sku

from .aaz.latest.network.vnet import List as VNetList, Show as VNetShow
from .aaz.latest.network.vnet.subnet import Show as SubnetShow, Update as SubnetUpdate
Expand Down Expand Up @@ -5257,6 +5257,9 @@ def update_app_service_plan(cmd, instance, sku=None, number_of_workers=None, ela
sku_def = instance.sku
if sku is not None:
sku = _normalize_sku(sku)
_validate_asp_sku(sku,
getattr(instance, 'hosting_environment_profile', None),
getattr(instance, 'zone_redundant', False))
sku_def.tier = get_sku_tier(sku)
sku_def.name = sku

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,36 @@
import unittest
from unittest import mock

from azure.cli.core.azclierror import ArgumentUsageError
from azure.cli.core.azclierror import ArgumentUsageError, ValidationError

from azure.cli.command_modules.appservice._constants import ISOLATED_V4_SKUS
from azure.cli.command_modules.appservice._validators import (
_normalize_http_headers,
_normalize_ip_address_list,
_validate_asp_sku,
_validate_ip_address_existence,
_validate_service_tag_existence,
)
from azure.cli.command_modules.appservice.utils import get_sku_tier


class ValidateAppServicePlanSkuTest(unittest.TestCase):
def test_isolated_v4_skus_are_supported_for_ase_plans(self):
for sku in ISOLATED_V4_SKUS:
with self.subTest(sku=sku):
self.assertEqual(get_sku_tier(sku), 'IsolatedV4')
_validate_asp_sku(sku, app_service_environment='ase', zone_redundant=False)

def test_isolated_v4_skus_support_zone_redundancy(self):
for sku in ISOLATED_V4_SKUS:
with self.subTest(sku=sku):
_validate_asp_sku(sku, app_service_environment='ase', zone_redundant=True)

def test_isolated_v4_skus_require_ase(self):
for sku in ISOLATED_V4_SKUS:
with self.subTest(sku=sku):
with self.assertRaises(ValidationError):
_validate_asp_sku(sku, app_service_environment=None, zone_redundant=False)


class _StubRule:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
MutuallyExclusiveArgumentError,
ArgumentUsageError,
AzureResponseError,
ResourceNotFoundError)
ResourceNotFoundError,
ValidationError)
from azure.cli.command_modules.appservice.custom import (set_deployment_user,
update_git_token, add_hostname,
update_site_configs,
Expand Down Expand Up @@ -1438,6 +1439,28 @@ def test_default_sku_is_p0v3_when_not_specified(self, mock_location, mock_client
# The sku name should be normalized P0V3
self.assertIn('P0V3', str(call_kwargs))

def test_update_to_isolated_v4_sku_requires_ase(self):
from azure.cli.command_modules.appservice.custom import update_app_service_plan
instance = mock.MagicMock()
instance.hosting_environment_profile = None
instance.zone_redundant = False

with self.assertRaises(ValidationError):
update_app_service_plan(mock.MagicMock(), instance, sku='I1V4')

@mock.patch('azure.cli.command_modules.appservice.custom._enable_managed_instance_properties')
def test_update_to_isolated_v4_sku_on_ase(self, _):
from azure.cli.command_modules.appservice.custom import update_app_service_plan
instance = mock.MagicMock()
instance.hosting_environment_profile = mock.MagicMock()
instance.zone_redundant = False
instance.sku.capacity = 1

result = update_app_service_plan(mock.MagicMock(), instance, sku='I1MV4')

self.assertEqual(result.sku.name, 'I1MV4')
self.assertEqual(result.sku.tier, 'IsolatedV4')


class TestOneDeployScmCache(unittest.TestCase):
"""Tests for the per-invocation SCM URL / SCM headers cache on OneDeployParams.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from azure.mgmt.core.tools import parse_resource_id, is_valid_resource_id, resource_id

from ._client_factory import web_client_factory, providers_client_factory
from ._constants import LOGICAPP_KIND, FUNCTIONAPP_KIND, LINUXAPP_KIND
from ._constants import LOGICAPP_KIND, FUNCTIONAPP_KIND, LINUXAPP_KIND, ISOLATED_V4_SKUS

logger = get_logger(__name__)

Expand Down Expand Up @@ -113,6 +113,8 @@ def get_sku_tier(name): # pylint: disable=too-many-return-statements
return 'IsolatedV2'
if name in ['I1MV2', 'I2MV2', 'I3MV2', 'I4MV2', 'I5MV2']:
return 'IsolatedMV2'
if name in ISOLATED_V4_SKUS:
return 'IsolatedV4'
if name in ['WS1', 'WS2', 'WS3']:
return 'WorkflowStandard'
raise ValidationError("Invalid sku(pricing tier), please refer to command help for valid values")
Expand Down
Loading