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 5b7b5b1da03..5db95cd26b2 100644 --- a/src/azure-cli/azure/cli/command_modules/appservice/_help.py +++ b/src/azure-cli/azure/cli/command_modules/appservice/_help.py @@ -43,12 +43,18 @@ type: command short-summary: Create an app service plan. examples: - - name: Create a basic app service plan. + - name: Create a Linux app service plan. + text: > + az appservice plan create -g MyResourceGroup -n MyPlan --is-linux + - name: Create a Windows app service plan. text: > az appservice plan create -g MyResourceGroup -n MyPlan - - name: Create a standard app service plan with four Linux workers. + - name: Create a Windows app service plan with a specific SKU. + text: > + az appservice plan create -g MyResourceGroup -n MyPlan --sku B1 + - name: Create a Linux app service plan with four Linux workers. text: > - az appservice plan create -g MyResourceGroup -n MyPlan --is-linux --number-of-workers 4 --sku S1 + az appservice plan create -g MyResourceGroup -n MyPlan --is-linux --number-of-workers 4 --sku P0V3 - name: Create a Windows container app service plan. text: > az appservice plan create -g MyResourceGroup -n MyPlan --hyper-v --sku P1V3 diff --git a/src/azure-cli/azure/cli/command_modules/appservice/_validators.py b/src/azure-cli/azure/cli/command_modules/appservice/_validators.py index 33bd2ec9add..6b1fdfd670b 100644 --- a/src/azure-cli/azure/cli/command_modules/appservice/_validators.py +++ b/src/azure-cli/azure/cli/command_modules/appservice/_validators.py @@ -109,6 +109,15 @@ def _validate_asp_sku(sku, app_service_environment, zone_redundant): def validate_asp_create(namespace): validate_tags(namespace) + if namespace.sku is None: + if namespace.is_linux: + namespace.sku = 'P0V3' + logger.warning("No --sku specified. Using default: P0V3 (Premium V3 Extra Small). " + "See all options: az appservice plan create --help. " + "For current pricing, visit: " + "https://azure.microsoft.com/pricing/details/app-service/") + else: + namespace.sku = 'B1' sku = _normalize_sku(namespace.sku) _validate_asp_sku(sku, namespace.app_service_environment, namespace.zone_redundant) if namespace.is_linux and namespace.hyper_v: diff --git a/src/azure-cli/azure/cli/command_modules/appservice/custom.py b/src/azure-cli/azure/cli/command_modules/appservice/custom.py index df80810161b..2ffe42bec89 100644 --- a/src/azure-cli/azure/cli/command_modules/appservice/custom.py +++ b/src/azure-cli/azure/cli/command_modules/appservice/custom.py @@ -2174,7 +2174,7 @@ def update_webapp(cmd, instance, client_affinity_enabled=None, https_only=None, args = ["--minimum-elastic-instance-count", "--prewarmed-instance-count"] plan = get_app_service_plan_from_webapp(cmd, instance) sku = _normalize_sku(plan.sku.name) - if get_sku_tier(sku) not in ["PREMIUMV2", "PREMIUMV3"]: + if get_sku_tier(sku) not in ["PREMIUMV2", "PREMIUM0V3", "PREMIUMV3"]: raise ValidationError("{} are only supported for elastic premium V2/V3 SKUs".format(str(args))) if not plan.elastic_scale_enabled: raise ValidationError("Elastic scale is not enabled on the App Service Plan. Please update the plan ") @@ -4212,11 +4212,14 @@ def is_async_response(poller, timeout_seconds=30): def create_app_service_plan(cmd, resource_group_name, name, is_linux, hyper_v, per_site_scaling=False, - app_service_environment=None, sku='B1', number_of_workers=None, location=None, + app_service_environment=None, sku=None, number_of_workers=None, location=None, tags=None, no_wait=False, zone_redundant=False, async_scaling_enabled=None, is_managed_instance=None, mi_system_assigned=None, mi_user_assigned=None, default_identity=None, rdp_enabled=None, vnet=None, subnet=None, registry_adapters=None, install_scripts=None, storage_mounts=None): + if sku is None: + sku = 'P0V3' if is_linux else 'B1' + HostingEnvironmentProfile, SkuDescription, AppServicePlan = cmd.get_models( 'HostingEnvironmentProfile', 'SkuDescription', 'AppServicePlan') @@ -4260,10 +4263,13 @@ def create_app_service_plan(cmd, resource_group_name, name, is_linux, hyper_v, p if sku.upper() in ['WS1', 'WS2', 'WS3']: existing_plan = get_resource_if_exists(client.app_service_plans, - resource_group_name=resource_group_name, name=name) + resource_group_name=resource_group_name, + name=name) if existing_plan and existing_plan.sku.tier != "WorkflowStandard": - raise ValidationError("Plan {} in resource group {} already exists and " - "cannot be updated to a logic app SKU (WS1, WS2, or WS3)") + raise ValidationError( + "Plan '{}' in resource group '{}' already exists and " + "cannot be updated to a logic app SKU (WS1, WS2, or WS3)" + .format(name, resource_group_name)) plan_def.type = "elastic" if zone_redundant: @@ -4397,7 +4403,7 @@ def update_app_service_plan(cmd, instance, sku=None, number_of_workers=None, ela if elastic_scale is not None or max_elastic_worker_count is not None: if sku is None: sku = instance.sku.name - if get_sku_tier(sku) not in ["PREMIUMV2", "PREMIUMV3", "WorkflowStandard"]: + if get_sku_tier(sku) not in ["PREMIUMV2", "PREMIUM0V3", "PREMIUMV3", "WorkflowStandard"]: raise ValidationError("--number-of-workers and --elastic-scale can only " "be used on premium V2/V3 or workflow SKUs. " "Use command help to see all available SKUs.") diff --git a/src/azure-cli/azure/cli/command_modules/appservice/tests/latest/test_webapp_commands_thru_mock.py b/src/azure-cli/azure/cli/command_modules/appservice/tests/latest/test_webapp_commands_thru_mock.py index 853eadc1edd..4db335740f3 100644 --- a/src/azure-cli/azure/cli/command_modules/appservice/tests/latest/test_webapp_commands_thru_mock.py +++ b/src/azure-cli/azure/cli/command_modules/appservice/tests/latest/test_webapp_commands_thru_mock.py @@ -644,5 +644,32 @@ def __init__(self, status_code): self.status_code = status_code +class TestCreateAppServicePlanDefaults(unittest.TestCase): + """Tests for create_app_service_plan default SKU behavior""" + + @mock.patch('azure.cli.command_modules.appservice.custom.web_client_factory') + @mock.patch('azure.cli.command_modules.appservice.custom._get_location_from_resource_group', return_value='eastus') + def test_default_sku_is_p0v3_when_not_specified(self, mock_location, mock_client_factory): + from azure.cli.command_modules.appservice.custom import create_app_service_plan + mock_cmd = mock.MagicMock() + mock_cmd.get_models.return_value = (mock.MagicMock(), mock.MagicMock(), mock.MagicMock()) + mock_cmd.cli_ctx = mock.MagicMock() + mock_client = mock.MagicMock() + mock_client_factory.return_value = mock_client + + # Call without sku parameter — should default to P0V3 + try: + create_app_service_plan(mock_cmd, 'rg', 'plan', is_linux=True, hyper_v=False) + except Exception: + pass # We don't care about downstream errors, just checking the SKU + + # Verify SkuDescription was called with P0V3 tier/name + sku_description_cls = mock_cmd.get_models.return_value[1] + sku_description_cls.assert_called() + call_kwargs = sku_description_cls.call_args + # The sku name should be normalized P0V3 + self.assertIn('P0V3', str(call_kwargs)) + + if __name__ == '__main__': unittest.main()