Skip to content

Commit d86606f

Browse files
authored
[App Service] Upgrade Microsoft.Web to v2025-05-01 + New commands to set and show site update strategy for flex consumption function apps (#33341)
1 parent 725f4d8 commit d86606f

273 files changed

Lines changed: 115108 additions & 148026 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/azure-cli-core/azure/cli/core/profiles/_shared.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def default_api_version(self):
208208
ResourceType.MGMT_EVENTHUB: None,
209209
ResourceType.MGMT_MONITOR: None,
210210
ResourceType.MGMT_MSI: '2024-11-30',
211-
ResourceType.MGMT_APPSERVICE: '2024-11-01',
211+
ResourceType.MGMT_APPSERVICE: None,
212212
ResourceType.MGMT_IOTHUB: None,
213213
ResourceType.MGMT_IOTDPS: None,
214214
ResourceType.MGMT_IOTCENTRAL: None,

src/azure-cli/azure/cli/command_modules/appservice/_client_factory.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,9 @@ def cf_providers(cli_ctx, _):
6868

6969
def cf_web_client(cli_ctx, _):
7070
return web_client_factory(cli_ctx)
71+
72+
73+
def domain_registration_client_factory(cli_ctx, **_):
74+
from azure.cli.core.commands.client_factory import get_mgmt_service_client
75+
from azure.mgmt.domainregistration import DomainRegistrationMgmtClient
76+
return get_mgmt_service_client(cli_ctx, DomainRegistrationMgmtClient)

src/azure-cli/azure/cli/command_modules/appservice/_constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,6 @@ def __init__(self):
143143

144144
DEPLOYMENT_STORAGE_AUTH_TYPES = ['SystemAssignedIdentity', 'UserAssignedIdentity', 'StorageAccountConnectionString']
145145

146+
UPDATE_STRATEGY_TYPES = ['Recreate', 'RollingUpdate']
147+
146148
STORAGE_BLOB_DATA_CONTRIBUTOR_ROLE_ID = 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'

src/azure-cli/azure/cli/command_modules/appservice/_create_util.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -327,8 +327,10 @@ def set_location(cmd, sku, location):
327327

328328
def get_site_availability(cmd, name):
329329
""" This is used by az webapp up to verify if a site needs to be created or should just be deployed"""
330+
from azure.mgmt.web.models import ResourceNameAvailabilityRequest
330331
client = web_client_factory(cmd.cli_ctx)
331-
availability = client.check_name_availability(name, 'Site')
332+
request = ResourceNameAvailabilityRequest(name=name, type='Site')
333+
availability = client.check_name_availability(request)
332334

333335
# check for "." in app name. it is valid for hostnames to contain it, but not allowed for webapp names
334336
if "." in name:
@@ -339,15 +341,19 @@ def get_site_availability(cmd, name):
339341
return availability
340342

341343

342-
def get_regional_site_availability(cmd, location, name, resource_group_name, auto_generated_domain_name_label_scope):
344+
def get_regional_site_availability(cmd, location, name, resource_group_name=None, # pylint: disable=unused-argument
345+
auto_generated_domain_name_label_scope=None): # pylint: disable=unused-argument
343346
""" This is used by az webapp up to verify if a site needs to be created or should just be deployed
344347
(regional check)"""
348+
from azure.mgmt.web.models import ResourceNameAvailabilityRequest
345349
client = web_client_factory(cmd.cli_ctx)
346-
availability = client.regional_check_name_availability(location,
347-
name,
348-
"Site",
349-
resource_group_name,
350-
auto_generated_domain_name_label_scope)
350+
# Note: In azure-mgmt-web 11.0.0+, resource_group_name and auto_generated_domain_name_label_scope
351+
# are no longer supported parameters for ResourceNameAvailabilityRequest
352+
request = ResourceNameAvailabilityRequest(
353+
name=name,
354+
type="Site"
355+
)
356+
availability = client.regional_check_name_availability(location, request)
351357

352358
# check for "." in app name. it is valid for hostnames to contain it, but not allowed for webapp names
353359
if "." in name:

src/azure-cli/azure/cli/command_modules/appservice/_deployment_context_engine.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,14 @@ def _get_app_region_and_plan_sku(cmd, resource_group_name, webapp_name):
6464
try:
6565
from ._client_factory import web_client_factory
6666
from azure.mgmt.core.tools import parse_resource_id
67+
from .utils import get_site_server_farm_id
6768
client = web_client_factory(cmd.cli_ctx)
6869
app = client.web_apps.get(resource_group_name, webapp_name)
6970
region = app.location if app else "Unknown"
7071
sku = "Unknown"
71-
if app and app.server_farm_id:
72-
plan_parts = parse_resource_id(app.server_farm_id)
72+
server_farm_id = get_site_server_farm_id(app) if app else None
73+
if app and server_farm_id:
74+
plan_parts = parse_resource_id(server_farm_id)
7375
plan = client.app_service_plans.get(plan_parts['resource_group'], plan_parts['name'])
7476
if plan and plan.sku:
7577
sku = plan.sku.name

src/azure-cli/azure/cli/command_modules/appservice/_help.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,34 @@
688688
text: az functionapp scale config always-ready set --name MyFunctionApp --resource-group MyResourceGroup --settings key1=value1 key2=value2
689689
"""
690690

691+
helps['functionapp update-strategy'] = """
692+
type: group
693+
short-summary: Manage a function app's update strategy.
694+
"""
695+
696+
helps['functionapp update-strategy config'] = """
697+
type: group
698+
short-summary: Manage a function app's update strategy configuration.
699+
"""
700+
701+
helps['functionapp update-strategy config show'] = """
702+
type: command
703+
short-summary: Get the details of a function app's update strategy configuration.
704+
examples:
705+
- name: Get the details of a function app's update strategy configuration.
706+
text: az functionapp update-strategy config show --name MyFunctionApp --resource-group MyResourceGroup
707+
"""
708+
709+
helps['functionapp update-strategy config set'] = """
710+
type: command
711+
short-summary: Set or update a function app's update strategy configuration.
712+
examples:
713+
- name: Set the update strategy to Recreate.
714+
text: az functionapp update-strategy config set --name MyFunctionApp --resource-group MyResourceGroup --type Recreate
715+
- name: Set the update strategy to RollingUpdate.
716+
text: az functionapp update-strategy config set --name MyFunctionApp --resource-group MyResourceGroup --type RollingUpdate
717+
"""
718+
691719
helps['functionapp cors'] = """
692720
type: group
693721
short-summary: Manage Cross-Origin Resource Sharing (CORS)

src/azure-cli/azure/cli/command_modules/appservice/_params.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from ._completers import get_hostname_completion_list
2121
from ._constants import (FUNCTIONS_VERSIONS, LOGICAPPS_NODE_RUNTIME_VERSIONS, WINDOWS_OS_NAME, LINUX_OS_NAME,
22-
DEPLOYMENT_STORAGE_AUTH_TYPES)
22+
DEPLOYMENT_STORAGE_AUTH_TYPES, UPDATE_STRATEGY_TYPES)
2323

2424
from ._validators import (validate_timeout_value, validate_site_create, validate_asp_create,
2525
validate_ase_create, validate_ip_address,
@@ -702,6 +702,10 @@ def load_arguments(self, _):
702702
c.argument('setting_names', nargs='+', help="space-separated always-ready setting names")
703703
c.argument('settings', nargs='+', help="space-separated configuration for the number of pre-allocated instances in the format `<name>=<value>`")
704704

705+
with self.argument_context('functionapp update-strategy config') as c:
706+
c.argument('strategy_type', options_list=['--type'], arg_type=get_enum_type(UPDATE_STRATEGY_TYPES),
707+
help="The update strategy type. Allowed values: Recreate, RollingUpdate.")
708+
705709
with self.argument_context('webapp config connection-string list') as c:
706710
c.argument('name', arg_type=webapp_name_arg_type, id_part=None)
707711

src/azure-cli/azure/cli/command_modules/appservice/_validators.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from ._client_factory import web_client_factory
1919
from .utils import (_normalize_sku, get_sku_tier, get_resource_name_and_group,
2020
get_resource_if_exists, is_functionapp, is_logicapp, is_webapp, is_centauri_functionapp,
21-
_normalize_location)
21+
_normalize_location, get_site_server_farm_id)
2222

2323
from .aaz.latest.network import ListServiceTags
2424
from .aaz.latest.network.vnet import List as VNetList, Show as VNetShow
@@ -82,10 +82,12 @@ def validate_site_create(cmd, namespace):
8282

8383
def validate_ase_create(cmd, namespace):
8484
# Validate the ASE Name availability
85+
from azure.mgmt.web.models import ResourceNameAvailabilityRequest
8586
client = web_client_factory(cmd.cli_ctx)
8687
resource_type = 'Microsoft.Web/hostingEnvironments'
8788
if isinstance(namespace.name, str):
88-
name_validation = client.check_name_availability(namespace.name, resource_type)
89+
request = ResourceNameAvailabilityRequest(name=namespace.name, type=resource_type)
90+
name_validation = client.check_name_availability(request)
8991
if not name_validation.name_available:
9092
raise ValidationError(name_validation.message)
9193

@@ -175,9 +177,10 @@ def validate_functionapp_on_flex_plan(cmd, namespace):
175177
resource_group_name = namespace.resource_group_name
176178
name = _get_app_name(namespace)
177179
functionapp = _generic_site_operation(cmd.cli_ctx, resource_group_name, name, 'get')
178-
if functionapp.server_farm_id is None:
180+
server_farm_id = get_site_server_farm_id(functionapp)
181+
if server_farm_id is None:
179182
return
180-
parsed_plan_id = parse_resource_id(functionapp.server_farm_id)
183+
parsed_plan_id = parse_resource_id(server_farm_id)
181184
client = web_client_factory(cmd.cli_ctx)
182185
plan_info = client.app_service_plans.get(parsed_plan_id['resource_group'], parsed_plan_id['name'])
183186
if plan_info is None:
@@ -191,9 +194,10 @@ def validate_is_flex_functionapp(cmd, namespace):
191194
resource_group_name = namespace.resource_group_name
192195
name = namespace.name
193196
functionapp = _generic_site_operation(cmd.cli_ctx, resource_group_name, name, 'get')
194-
if functionapp.server_farm_id is None:
197+
server_farm_id = get_site_server_farm_id(functionapp)
198+
if server_farm_id is None:
195199
raise ValidationError('This command is only valid for Azure Functions on the FlexConsumption plan.')
196-
parsed_plan_id = parse_resource_id(functionapp.server_farm_id)
200+
parsed_plan_id = parse_resource_id(server_farm_id)
197201
client = web_client_factory(cmd.cli_ctx)
198202
plan_info = client.app_service_plans.get(parsed_plan_id['resource_group'], parsed_plan_id['name'])
199203
if plan_info is None:

src/azure-cli/azure/cli/command_modules/appservice/access_restrictions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323

2424
def show_webapp_access_restrictions(cmd, resource_group_name, name, slot=None):
2525
configs = get_site_configs(cmd, resource_group_name, name, slot)
26-
access_restrictions = [r.serialize() for r in (configs.ip_security_restrictions or [])]
27-
scm_access_restrictions = [r.serialize() for r in (configs.scm_ip_security_restrictions or [])]
26+
access_restrictions = [r.as_dict() for r in (configs.ip_security_restrictions or [])]
27+
scm_access_restrictions = [r.as_dict() for r in (configs.scm_ip_security_restrictions or [])]
2828
access_rules = {
2929
"scmIpSecurityRestrictionsUseMain": configs.scm_ip_security_restrictions_use_main,
3030
"ipSecurityRestrictionsDefaultAction": configs.ip_security_restrictions_default_action,

src/azure-cli/azure/cli/command_modules/appservice/appservice_domains.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
from azure.cli.core.commands.client_factory import get_mgmt_service_client
99
from azure.cli.core.profiles import ResourceType
1010
from azure.cli.core.util import sdk_no_wait, random_string
11-
from azure.mgmt.web.models import NameIdentifier
11+
from azure.mgmt.domainregistration.models import NameIdentifier, TopLevelDomainAgreementOption
1212
from knack.util import CLIError
1313
from knack.log import get_logger
1414

15-
from ._client_factory import web_client_factory
15+
from ._client_factory import domain_registration_client_factory
1616

1717
logger = get_logger(__name__)
1818

@@ -48,17 +48,16 @@ def create_domain(cmd, resource_group_name, hostname, contact_info, privacy=True
4848
except:
4949
raise CLIError("Unable to get IP address")
5050

51-
web_client = web_client_factory(cmd.cli_ctx)
52-
hostname_availability = web_client.domains.check_availability(NameIdentifier(name=hostname))
51+
domain_client = domain_registration_client_factory(cmd.cli_ctx)
52+
hostname_availability = domain_client.domains.check_availability(NameIdentifier(name=hostname))
5353

5454
if not hostname_availability.available:
5555
raise ValidationError("Custom domain name '{}' is not available. Please try again "
5656
"with a new hostname.".format(hostname))
5757

5858
tld = '.'.join(hostname.split('.')[1:])
59-
TopLevelDomainAgreementOption = cmd.get_models('TopLevelDomainAgreementOption')
6059
domain_agreement_option = TopLevelDomainAgreementOption(include_privacy=bool(privacy), for_transfer=False)
61-
agreements = web_client.top_level_domains.list_agreements(name=tld, agreement_option=domain_agreement_option)
60+
agreements = domain_client.top_level_domains.list_agreements(name=tld, agreement_option=domain_agreement_option)
6261
agreement_keys = [agreement.agreement_key for agreement in agreements]
6362

6463
if dryrun:
@@ -151,16 +150,15 @@ def create_domain(cmd, resource_group_name, hostname, contact_info, privacy=True
151150

152151

153152
def show_domain_purchase_terms(cmd, hostname):
154-
from azure.mgmt.web.models import TopLevelDomainAgreementOption
155153
domain_identifier = NameIdentifier(name=hostname)
156-
web_client = web_client_factory(cmd.cli_ctx)
157-
hostname_availability = web_client.domains.check_availability(domain_identifier)
154+
domain_client = domain_registration_client_factory(cmd.cli_ctx)
155+
hostname_availability = domain_client.domains.check_availability(domain_identifier)
158156
if not hostname_availability.available: # api returns false
159157
raise CLIError(" hostname: '{}' in not available. Please enter a valid hostname.".format(hostname))
160158

161159
tld = '.'.join(hostname.split('.')[1:])
162160
domain_agreement_option = TopLevelDomainAgreementOption(include_privacy=True, for_transfer=True)
163-
agreements = web_client.top_level_domains.list_agreements(name=tld, agreement_option=domain_agreement_option)
161+
agreements = domain_client.top_level_domains.list_agreements(name=tld, agreement_option=domain_agreement_option)
164162

165163
terms = {
166164
"hostname": hostname,

0 commit comments

Comments
 (0)