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
62 changes: 55 additions & 7 deletions src/azure-cli/azure/cli/command_modules/appservice/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,56 @@ def transform_web_output(web):
props = ['name', 'state', 'location', 'resourceGroup', 'defaultHostName', 'appServicePlanId', 'ftpPublishingUrl']
result = {k: web[k] for k in web if k in props}
# to get width under control, also the plan usually is in the same RG
result['appServicePlan'] = result.pop('appServicePlanId').split('/')[-1]
app_service_plan_id = result.pop('appServicePlanId', None)
if app_service_plan_id is not None:
result['appServicePlan'] = app_service_plan_id.split('/')[-1]
return result


def transform_web_list_output(webs):
return [transform_web_output(w) for w in webs]


def _transform_site_output(result, remove_server_farm_id):
"""Restore appServicePlanId after serializing azure-mgmt-web Site models."""
from azure.cli.core.util import todict
from azure.cli.core.commands import AzCliCommandInvoker

result = todict(result, AzCliCommandInvoker.remove_additional_prop_layer)
sites = result if isinstance(result, list) else [result]
for site in sites:
if not isinstance(site, dict):
continue

app_service_plan_id = site.get('appServicePlanId')
if app_service_plan_id is None:
app_service_plan_id = site.get('serverFarmId')

properties = site.get('properties')
if app_service_plan_id is None and isinstance(properties, dict):
app_service_plan_id = properties.get('appServicePlanId')
if app_service_plan_id is None:
app_service_plan_id = properties.get('serverFarmId')

if app_service_plan_id is not None:
site['appServicePlanId'] = app_service_plan_id

if remove_server_farm_id:
site.pop('serverFarmId', None)
if isinstance(properties, dict):
properties.pop('serverFarmId', None)

return result


def transform_webapp_site_output(result):
return _transform_site_output(result, remove_server_farm_id=True)


def transform_site_output(result):
return _transform_site_output(result, remove_server_farm_id=False)


def transform_runtime_list_output(result):
from collections import OrderedDict
return [OrderedDict([
Expand Down Expand Up @@ -278,8 +320,10 @@ def load_command_table(self, _):
deprecate_info=g.deprecate(redirect='webapp create and webapp deploy'))
g.custom_command('ssh', 'ssh_webapp', exception_handler=ex_handler_factory(), is_preview=True)
g.custom_command('exec', 'webapp_exec', custom_command_type=webapp_exec_custom, exception_handler=ex_handler_factory(), is_preview=True)
g.custom_command('list', 'list_webapp', table_transformer=transform_web_list_output)
g.custom_show_command('show', 'show_app', table_transformer=transform_web_output)
g.custom_command('list', 'list_webapp', transform=transform_webapp_site_output,
table_transformer=transform_web_list_output)
g.custom_show_command('show', 'show_app', transform=transform_webapp_site_output,
table_transformer=transform_web_output)
g.custom_command('delete', 'delete_webapp')
g.custom_command('stop', 'stop_webapp')
g.custom_command('start', 'start_webapp')
Expand Down Expand Up @@ -533,8 +577,10 @@ def load_command_table(self, _):
validator=validate_functionapp)
g.custom_command('list-runtimes', 'list_function_app_runtimes')
g.custom_command('list-flexconsumption-runtimes', 'list_flex_function_app_runtimes')
g.custom_command('list', 'list_function_app', table_transformer=transform_web_list_output)
g.custom_show_command('show', 'show_functionapp', table_transformer=transform_web_output)
g.custom_command('list', 'list_function_app', transform=transform_site_output,
table_transformer=transform_web_list_output)
g.custom_show_command('show', 'show_functionapp', transform=transform_site_output,
table_transformer=transform_web_output)
g.custom_command('delete', 'delete_function_app')
g.custom_command('stop', 'stop_webapp')
g.custom_command('start', 'start_webapp')
Expand Down Expand Up @@ -758,8 +804,10 @@ def load_command_table(self, _):

with self.command_group('logicapp', custom_command_type=logicapp_custom) as g:
g.custom_command('create', 'create_logicapp', exception_handler=ex_handler_factory())
g.custom_command('list', 'list_logicapp', table_transformer=transform_web_list_output)
g.custom_show_command('show', 'show_logicapp', table_transformer=transform_web_output)
g.custom_command('list', 'list_logicapp', transform=transform_site_output,
table_transformer=transform_web_list_output)
g.custom_show_command('show', 'show_logicapp', transform=transform_site_output,
table_transformer=transform_web_output)
g.custom_command('scale', 'scale_logicapp', exception_handler=ex_handler_factory())

with self.command_group('logicapp config appsettings', custom_command_type=logicapp_custom) as g:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ def test_webapp_e2e(self, resource_group):
webapp_name = self.create_random_name(prefix='webapp-e2e', length=24)
plan = self.create_random_name(prefix='webapp-e2e-plan', length=24)

self.cmd('appservice plan create -g {} -n {}'.format(resource_group, plan))
plan_id = self.cmd(
'appservice plan create -g {} -n {}'.format(resource_group, plan)).get_output_in_json()['id']
self.cmd('appservice plan list -g {}'.format(resource_group), checks=[
JMESPathCheck('length(@)', 1),
JMESPathCheck('[0].name', plan),
Expand Down Expand Up @@ -81,11 +82,15 @@ def test_webapp_e2e(self, resource_group):
self.cmd('webapp list -g {}'.format(resource_group), checks=[
JMESPathCheck('length(@)', 1),
JMESPathCheck('[0].name', webapp_name),
JMESPathCheck('[0].appServicePlanId', plan_id),
JMESPathCheckNotExists('[0].serverFarmId'),
JMESPathCheck('[0].hostNames[0]', webapp_name +
'.azurewebsites.net')
])
self.cmd('webapp show -g {} -n {}'.format(resource_group, webapp_name), checks=[
JMESPathCheck('name', webapp_name),
JMESPathCheck('appServicePlanId', plan_id),
JMESPathCheckNotExists('serverFarmId'),
JMESPathCheck('hostNames[0]', webapp_name + '.azurewebsites.net')
])
result = self.cmd('webapp deployment source config-local-git -g {} -n {}'.format(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from azure.core.exceptions import HttpResponseError

from azure.mgmt.web import WebSiteManagementClient
from azure.mgmt.web.models import Site
from knack.output import format_table
from knack.util import CLIError, CommandResultItem
from azure.cli.core.azclierror import (InvalidArgumentValueError,
Expand Down Expand Up @@ -56,7 +57,10 @@
create_webapp)
from azure.cli.command_modules.appservice.commands import (transform_troubleshoot_config_output,
transform_secure_build_output,
transform_troubleshoot_deployment_output)
transform_troubleshoot_deployment_output,
transform_site_output,
transform_webapp_site_output,
transform_web_output)
from azure.cli.command_modules.appservice._deployment_context_engine import EnrichedDeploymentError

# pylint: disable=line-too-long
Expand All @@ -75,6 +79,58 @@ def _get_test_cmd():
return cmd


class TestWebappOutputTransformers(unittest.TestCase):

def test_transform_webapp_site_output_renames_server_farm_id_for_sdk_model(self):
farm_id = '/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Web/serverfarms/plan'
site = Site(location='westus', server_farm_id=farm_id)

result = transform_webapp_site_output(site)

self.assertEqual(result['appServicePlanId'], farm_id)
self.assertNotIn('serverFarmId', result)

def test_transform_webapp_site_output_renames_server_farm_id_from_properties(self):
farm_id = '/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Web/serverfarms/plan'
site = {
'location': 'westus',
'properties': {
'serverFarmId': farm_id,
'name': 'myapp',
},
}

result = transform_webapp_site_output(site)

self.assertEqual(result['appServicePlanId'], farm_id)
self.assertNotIn('serverFarmId', result['properties'])

def test_transform_site_output_preserves_server_farm_id_for_other_app_types(self):
farm_id = '/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Web/serverfarms/plan'
sites = [
{'serverFarmId': farm_id, 'name': 'app1'},
{'appServicePlanId': farm_id, 'name': 'app2'},
]

result = transform_site_output(sites)

self.assertEqual([site['appServicePlanId'] for site in result], [farm_id, farm_id])
self.assertEqual(result[0]['serverFarmId'], farm_id)

def test_transform_web_output_uses_app_service_plan_name(self):
farm_id = '/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Web/serverfarms/plan'

result = transform_web_output({'name': 'app', 'appServicePlanId': farm_id})

self.assertEqual(result['appServicePlan'], 'plan')
self.assertNotIn('appServicePlanId', result)

def test_transform_web_output_tolerates_missing_app_service_plan_id(self):
result = transform_web_output({'name': 'app', 'state': 'Running'})

self.assertEqual(result, {'name': 'app', 'state': 'Running'})


class TestSecureBuildMocked(unittest.TestCase):

@mock.patch('azure.cli.core.util.should_disable_connection_verify', return_value=False)
Expand Down
Loading