Skip to content
Closed
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
2 changes: 1 addition & 1 deletion src/azure-cli-core/azure/cli/core/profiles/_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def default_api_version(self):
ResourceType.MGMT_EVENTHUB: None,
ResourceType.MGMT_MONITOR: None,
ResourceType.MGMT_MSI: '2024-11-30',
ResourceType.MGMT_APPSERVICE: '2024-11-01',
ResourceType.MGMT_APPSERVICE: None,
ResourceType.MGMT_IOTHUB: None,
ResourceType.MGMT_IOTDPS: None,
ResourceType.MGMT_IOTCENTRAL: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,9 @@ def cf_providers(cli_ctx, _):

def cf_web_client(cli_ctx, _):
return web_client_factory(cli_ctx)


def domain_registration_client_factory(cli_ctx, **_):
from azure.cli.core.commands.client_factory import get_mgmt_service_client
from azure.mgmt.domainregistration import DomainRegistrationMgmtClient
return get_mgmt_service_client(cli_ctx, DomainRegistrationMgmtClient)
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,6 @@ def __init__(self):

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

UPDATE_STRATEGY_TYPES = ['Recreate', 'RollingUpdate']

STORAGE_BLOB_DATA_CONTRIBUTOR_ROLE_ID = 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,10 @@ def set_location(cmd, sku, location):

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

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


def get_regional_site_availability(cmd, location, name, resource_group_name, auto_generated_domain_name_label_scope):
def get_regional_site_availability(cmd, location, name, resource_group_name=None, # pylint: disable=unused-argument
auto_generated_domain_name_label_scope=None): # pylint: disable=unused-argument
""" This is used by az webapp up to verify if a site needs to be created or should just be deployed
(regional check)"""
from azure.mgmt.web.models import ResourceNameAvailabilityRequest
client = web_client_factory(cmd.cli_ctx)
availability = client.regional_check_name_availability(location,
name,
"Site",
resource_group_name,
auto_generated_domain_name_label_scope)
# Note: In azure-mgmt-web 11.0.0+, resource_group_name and auto_generated_domain_name_label_scope
# are no longer supported parameters for ResourceNameAvailabilityRequest
request = ResourceNameAvailabilityRequest(
name=name,
type="Site"
)
availability = client.regional_check_name_availability(location, request)

# check for "." in app name. it is valid for hostnames to contain it, but not allowed for webapp names
if "." in name:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,14 @@ def _get_app_region_and_plan_sku(cmd, resource_group_name, webapp_name):
try:
from ._client_factory import web_client_factory
from azure.mgmt.core.tools import parse_resource_id
from .utils import get_site_server_farm_id
client = web_client_factory(cmd.cli_ctx)
app = client.web_apps.get(resource_group_name, webapp_name)
region = app.location if app else "Unknown"
sku = "Unknown"
if app and app.server_farm_id:
plan_parts = parse_resource_id(app.server_farm_id)
server_farm_id = get_site_server_farm_id(app) if app else None
if app and server_farm_id:
plan_parts = parse_resource_id(server_farm_id)
plan = client.app_service_plans.get(plan_parts['resource_group'], plan_parts['name'])
if plan and plan.sku:
sku = plan.sku.name
Expand Down
28 changes: 28 additions & 0 deletions src/azure-cli/azure/cli/command_modules/appservice/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,34 @@
text: az functionapp scale config always-ready set --name MyFunctionApp --resource-group MyResourceGroup --settings key1=value1 key2=value2
"""

helps['functionapp update-strategy'] = """
type: group
short-summary: Manage a function app's update strategy.
"""

helps['functionapp update-strategy config'] = """
type: group
short-summary: Manage a function app's update strategy configuration.
"""

helps['functionapp update-strategy config show'] = """
type: command
short-summary: Get the details of a function app's update strategy configuration.
examples:
- name: Get the details of a function app's update strategy configuration.
text: az functionapp update-strategy config show --name MyFunctionApp --resource-group MyResourceGroup
"""

helps['functionapp update-strategy config set'] = """
type: command
short-summary: Set or update a function app's update strategy configuration.
examples:
- name: Set the update strategy to Recreate.
text: az functionapp update-strategy config set --name MyFunctionApp --resource-group MyResourceGroup --type Recreate
- name: Set the update strategy to RollingUpdate.
text: az functionapp update-strategy config set --name MyFunctionApp --resource-group MyResourceGroup --type RollingUpdate
"""

helps['functionapp cors'] = """
type: group
short-summary: Manage Cross-Origin Resource Sharing (CORS)
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)
DEPLOYMENT_STORAGE_AUTH_TYPES, UPDATE_STRATEGY_TYPES)

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

with self.argument_context('functionapp update-strategy config') as c:
c.argument('strategy_type', options_list=['--type'], arg_type=get_enum_type(UPDATE_STRATEGY_TYPES),
help="The update strategy type. Allowed values: Recreate, RollingUpdate.")

with self.argument_context('webapp config connection-string list') as c:
c.argument('name', arg_type=webapp_name_arg_type, id_part=None)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from ._client_factory import web_client_factory
from .utils import (_normalize_sku, get_sku_tier, get_resource_name_and_group,
get_resource_if_exists, is_functionapp, is_logicapp, is_webapp, is_centauri_functionapp,
_normalize_location)
_normalize_location, get_site_server_farm_id)

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

def validate_ase_create(cmd, namespace):
# Validate the ASE Name availability
from azure.mgmt.web.models import ResourceNameAvailabilityRequest
client = web_client_factory(cmd.cli_ctx)
resource_type = 'Microsoft.Web/hostingEnvironments'
if isinstance(namespace.name, str):
name_validation = client.check_name_availability(namespace.name, resource_type)
request = ResourceNameAvailabilityRequest(name=namespace.name, type=resource_type)
name_validation = client.check_name_availability(request)
if not name_validation.name_available:
raise ValidationError(name_validation.message)

Expand Down Expand Up @@ -175,9 +177,10 @@ def validate_functionapp_on_flex_plan(cmd, namespace):
resource_group_name = namespace.resource_group_name
name = _get_app_name(namespace)
functionapp = _generic_site_operation(cmd.cli_ctx, resource_group_name, name, 'get')
if functionapp.server_farm_id is None:
server_farm_id = get_site_server_farm_id(functionapp)
if server_farm_id is None:
return
parsed_plan_id = parse_resource_id(functionapp.server_farm_id)
parsed_plan_id = parse_resource_id(server_farm_id)
client = web_client_factory(cmd.cli_ctx)
plan_info = client.app_service_plans.get(parsed_plan_id['resource_group'], parsed_plan_id['name'])
if plan_info is None:
Expand All @@ -191,9 +194,10 @@ def validate_is_flex_functionapp(cmd, namespace):
resource_group_name = namespace.resource_group_name
name = namespace.name
functionapp = _generic_site_operation(cmd.cli_ctx, resource_group_name, name, 'get')
if functionapp.server_farm_id is None:
server_farm_id = get_site_server_farm_id(functionapp)
if server_farm_id is None:
raise ValidationError('This command is only valid for Azure Functions on the FlexConsumption plan.')
parsed_plan_id = parse_resource_id(functionapp.server_farm_id)
parsed_plan_id = parse_resource_id(server_farm_id)
client = web_client_factory(cmd.cli_ctx)
plan_info = client.app_service_plans.get(parsed_plan_id['resource_group'], parsed_plan_id['name'])
if plan_info is None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@

def show_webapp_access_restrictions(cmd, resource_group_name, name, slot=None):
configs = get_site_configs(cmd, resource_group_name, name, slot)
access_restrictions = [r.serialize() for r in (configs.ip_security_restrictions or [])]
scm_access_restrictions = [r.serialize() for r in (configs.scm_ip_security_restrictions or [])]
access_restrictions = [r.as_dict() for r in (configs.ip_security_restrictions or [])]
scm_access_restrictions = [r.as_dict() for r in (configs.scm_ip_security_restrictions or [])]
access_rules = {
"scmIpSecurityRestrictionsUseMain": configs.scm_ip_security_restrictions_use_main,
"ipSecurityRestrictionsDefaultAction": configs.ip_security_restrictions_default_action,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
from azure.cli.core.commands.client_factory import get_mgmt_service_client
from azure.cli.core.profiles import ResourceType
from azure.cli.core.util import sdk_no_wait, random_string
from azure.mgmt.web.models import NameIdentifier
from azure.mgmt.domainregistration.models import NameIdentifier, TopLevelDomainAgreementOption
from knack.util import CLIError
from knack.log import get_logger

from ._client_factory import web_client_factory
from ._client_factory import domain_registration_client_factory

logger = get_logger(__name__)

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

web_client = web_client_factory(cmd.cli_ctx)
hostname_availability = web_client.domains.check_availability(NameIdentifier(name=hostname))
domain_client = domain_registration_client_factory(cmd.cli_ctx)
hostname_availability = domain_client.domains.check_availability(NameIdentifier(name=hostname))

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

tld = '.'.join(hostname.split('.')[1:])
TopLevelDomainAgreementOption = cmd.get_models('TopLevelDomainAgreementOption')
domain_agreement_option = TopLevelDomainAgreementOption(include_privacy=bool(privacy), for_transfer=False)
agreements = web_client.top_level_domains.list_agreements(name=tld, agreement_option=domain_agreement_option)
agreements = domain_client.top_level_domains.list_agreements(name=tld, agreement_option=domain_agreement_option)
agreement_keys = [agreement.agreement_key for agreement in agreements]

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


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

tld = '.'.join(hostname.split('.')[1:])
domain_agreement_option = TopLevelDomainAgreementOption(include_privacy=True, for_transfer=True)
agreements = web_client.top_level_domains.list_agreements(name=tld, agreement_option=domain_agreement_option)
agreements = domain_client.top_level_domains.list_agreements(name=tld, agreement_option=domain_agreement_option)

terms = {
"hostname": hostname,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,10 @@ def load_command_table(self, _):
g.custom_command('delete', 'delete_always_ready_settings', exception_handler=ex_handler_factory(), validator=validate_is_flex_functionapp)
g.custom_command('set', 'update_always_ready_settings', exception_handler=ex_handler_factory(), validator=validate_is_flex_functionapp)

with self.command_group('functionapp update-strategy config') as g:
g.custom_show_command('show', 'get_update_strategy_config', exception_handler=ex_handler_factory(), validator=validate_is_flex_functionapp)
g.custom_command('set', 'set_update_strategy_config', exception_handler=ex_handler_factory(), validator=validate_is_flex_functionapp)

with self.command_group('functionapp config hostname') as g:
g.custom_command('add', 'add_hostname', exception_handler=ex_handler_factory())
g.custom_command('list', 'list_hostnames')
Expand Down
Loading
Loading