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
3 changes: 3 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 @@ -2615,6 +2615,9 @@
- name: Create a web app and deploy as a static HTML app.
text: >
az webapp up --html
- name: Create a web app with a specified domain name scope for unique hostname generation
text: >
az webapp up -n MyUniqueAppName --domain-name-scope TenantReuse
"""

helps['webapp update'] = """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@ def load_arguments(self, _):
arg_type=get_three_state_flag())
c.argument('enable_kudu_warmup', help="If true, kudu will be warmed up before performing deployment for a linux webapp.",
arg_type=get_three_state_flag())
c.argument('auto_generated_domain_name_label_scope', options_list=['--domain-name-scope'], help="Specify the scope of uniqueness for the default hostname during resource creation.", arg_type=get_enum_type(AutoGeneratedDomainNameLabelScope))

with self.argument_context('webapp ssh') as c:
c.argument('port', options_list=['--port', '-p'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9082,7 +9082,8 @@ def get_history_triggered_webjob(cmd, resource_group_name, name, webjob_name, sl

def webapp_up(cmd, name=None, resource_group_name=None, plan=None, location=None, sku=None, # pylint: disable=too-many-statements,too-many-branches
os_type=None, runtime=None, dryrun=False, logs=False, launch_browser=False, html=False,
app_service_environment=None, track_status=True, enable_kudu_warmup=True, basic_auth=""):
app_service_environment=None, track_status=True, enable_kudu_warmup=True, basic_auth="",
auto_generated_domain_name_label_scope=None):
if not name:
name = generate_default_app_name(cmd)

Expand Down Expand Up @@ -9228,7 +9229,8 @@ def webapp_up(cmd, name=None, resource_group_name=None, plan=None, location=None
if _create_new_app:
logger.warning("Creating webapp '%s' ...", name)
create_webapp(cmd, rg_name, name, plan, runtime_version if not html else None,
using_webapp_up=True, language=language)
using_webapp_up=True, language=language,
auto_generated_domain_name_label_scope=auto_generated_domain_name_label_scope)
_configure_default_logging(cmd, rg_name, name)
else: # for existing app if we might need to update the stack runtime settings
helper = _StackRuntimeHelper(cmd, linux=_is_linux, windows=not _is_linux)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import unittest
import os
import re
from pytest import skip
import requests
from knack.util import CLIError
Expand Down Expand Up @@ -1369,6 +1370,58 @@ def test_webapp_up_track_runtimestatus_runtimefailed(self, resource_group):
import shutil
shutil.rmtree(temp_dir)

@live_only()
@AllowLargeResponse(8192)
@ResourceGroupPreparer(random_name_length=24, name_prefix='clitest', location=LINUX_ASP_LOCATION_WEBAPP)
def test_webapp_up_with_domain_name_scope(self, resource_group):
plan = self.create_random_name('up-dnlplan', 24)
webapp_name = self.create_random_name('up-dnl-app', 24)
zip_file_name = os.path.join(TEST_DIR, 'node-Express-up.zip')

import zipfile
import tempfile
temp_dir = tempfile.mkdtemp()
zip_ref = zipfile.ZipFile(zip_file_name, 'r')
zip_ref.extractall(temp_dir)
current_working_dir = os.getcwd()

up_working_dir = os.path.join(temp_dir, 'myExpressApp')
os.chdir(up_working_dir)

# test dryrun with --domain-name-scope
result = self.cmd('webapp up -n {} --dryrun --domain-name-scope TenantReuse'.format(
webapp_name)).get_output_in_json()
self.assertTrue(result['name'].startswith(webapp_name))
self.assertIn("node|", result['runtime_version'].lower())
self.assertEqual(result['os'].lower(), 'linux')

# test the full E2E operation works
self.cmd('webapp up -n {} -g {} --plan {} --domain-name-scope TenantReuse'.format(
webapp_name, resource_group, plan)).get_output_in_json()

# Verify app is created with domain name scope
result = self.cmd('webapp show -n {} -g {}'.format(webapp_name, resource_group), checks=[
JMESPathCheck('name', webapp_name),
JMESPathCheck('state', 'Running'),
JMESPathCheck('resourceGroup', resource_group),
JMESPathCheck('autoGeneratedDomainNameLabelScope', 'TenantReuse')
]).get_output_in_json()

# Verify the default hostname matches the regional pattern with hash
default_hostname = result.get('defaultHostName')
pattern = r'^([a-zA-Z0-9\-]+)-([a-z0-9]{16})\.([a-z]+-\d{2})\.azurewebsites\.net$'
match = re.match(pattern, default_hostname)
self.assertIsNotNone(match, "defaultHostName '{}' does not match expected pattern".format(default_hostname))
app_name, hash_part, region = match.groups()
self.assertTrue(len(hash_part) == 16 and hash_part.islower(), "Hash is not 16 chars or not lowercase.")
self.assertIn('-', region, "Region part does not have '-' separator.")
self.assertEqual(app_name, webapp_name, "App name and defaultHostName app name do not match.")

# cleanup
os.chdir(current_working_dir)
import shutil
shutil.rmtree(temp_dir)


if __name__ == '__main__':
unittest.main()