Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
9f2ec16
workload changes
khkh-ms Oct 19, 2023
b31bc4f
small fix
khkh-ms Oct 20, 2023
3e5598c
Added tests.
khkh-ms Oct 23, 2023
5471848
Addressing the comments.
khkh-ms Nov 1, 2023
98f8c64
Updates after changes.
khkh-ms Nov 16, 2023
1217182
Updated messages
khkh-ms Nov 16, 2023
1817fa7
test update.
khkh-ms Nov 16, 2023
a8807e3
updated unit tests
khkh-ms Nov 17, 2023
5274f1e
Removed the test SDK version
khkh-ms Dec 11, 2023
32593cb
One more change
khkh-ms Dec 11, 2023
124ecdd
Few more changes in test.
khkh-ms Dec 12, 2023
d917421
pylint fixes.
khkh-ms Dec 12, 2023
8fcb219
Merge branch 'dev' of https://github.com/Azure/azure-cli into khkh/wo…
khkh-ms Dec 12, 2023
df7a6f9
Changes after merge.
khkh-ms Dec 12, 2023
67aedd3
Merge branch 'dev' of https://github.com/Azure/azure-cli into khkh/wo…
khkh-ms Dec 14, 2023
9773941
Changed regions in the tests.
khkh-ms Dec 14, 2023
172afbe
cred-tests
khkh-ms Dec 14, 2023
a5e5622
typo
khkh-ms Dec 14, 2023
d722680
addressed the comments
khkh-ms Dec 14, 2023
935e9fc
Update the recording after some change.
khkh-ms Dec 14, 2023
6faabbf
review changes
khkh-ms Dec 14, 2023
df8e402
Test Update and Moved once condition.
khkh-ms Dec 15, 2023
b5f8817
lint
khkh-ms Dec 15, 2023
8d35cda
pylint again
khkh-ms Dec 15, 2023
880d1c2
Merge branch 'dev' into khkh/workload-profiles
khkh-ms Dec 15, 2023
556d844
Addressed the review comments
khkh-ms Dec 18, 2023
2db671e
Merge branch 'dev' into khkh/workload-profiles
khkh-ms Dec 18, 2023
8ba89ef
Updated the recording.
khkh-ms Dec 18, 2023
0b1d96d
Changed the function name.
khkh-ms Dec 18, 2023
e7ef0bf
Flake8 fix
khkh-ms Dec 18, 2023
9ddc886
Updated the recording.
khkh-ms Dec 18, 2023
5b4686d
Updated the recording.
khkh-ms Dec 18, 2023
02738e1
Update polling logic for PATCH function app
kamperiadis Dec 18, 2023
0127d39
Rerun workload profile unit test
kamperiadis Dec 18, 2023
3b32b79
Consolidate dapr config and workload config updates
kamperiadis Dec 18, 2023
332cdb4
Use fake value in recording
kamperiadis Dec 19, 2023
7a7f376
Fetch cpu and memory only if resource config is not null
kamperiadis Dec 19, 2023
fdbbb6a
Revert resource config null check, add GET for all centauri apps crea…
kamperiadis Dec 19, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,9 @@ def load_arguments(self, _):
c.argument('dapr_http_read_buffer_size', type=int, options_list=['--dapr-http-read-buffer-size', '--dhrbs'], help="Max size of http header read buffer in KB to handle when sending multi-KB headers.")
c.argument('dapr_log_level', help="The log level for the Dapr sidecar", arg_type=get_enum_type(DAPR_LOG_LEVELS))
c.argument('dapr_enable_api_logging', options_list=['--dapr-enable-api-logging', '--dal'], help="Enable/Disable API logging for the Dapr sidecar.", arg_type=get_three_state_flag(return_label=True))
c.argument('workload_profile_name', help="The name of the workload profile to run the app on.", is_preview=True)
c.argument('cpu', type=float, help="Required CPU in cores from 0.5 to 2.0.", is_preview=True)
c.argument('memory', help="Required momory from 1.0 to 4.0 ending with ""Gi"" e.g. 1.0Gi, ", is_preview=True)

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 Expand Up @@ -755,6 +758,9 @@ def load_arguments(self, _):
c.argument('dapr_log_level', help="The log level for the Dapr sidecar", arg_type=get_enum_type(DAPR_LOG_LEVELS))
c.argument('dapr_enable_api_logging', options_list=['--dapr-enable-api-logging', '--dal'], help="Enable/Disable API logging for the Dapr sidecar.", arg_type=get_three_state_flag(return_label=True))
c.argument('workspace', help="Name of an existing log analytics workspace to be used for the application insights component")
c.argument('workload_profile_name', help="The workload profile name to run the container app on.", is_preview=True)
c.argument('cpu', type=float, help="The CPU in cores of the container app. e.g 0.75", is_preview=True)
c.argument('memory', help="The memory size of the container app. e.g. 1.0Gi, ", is_preview=True)

with self.argument_context('functionapp cors credentials') as c:
c.argument('enable', help='enable/disable access-control-allow-credentials', arg_type=get_three_state_flag())
Expand Down
131 changes: 108 additions & 23 deletions src/azure-cli/azure/cli/command_modules/appservice/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -1783,13 +1783,15 @@ def update_container_settings_functionapp(cmd, resource_group_name, name, regist
registry_password=None, slot=None, min_replicas=None, max_replicas=None,
enable_dapr=None, dapr_app_id=None, dapr_app_port=None,
dapr_http_max_request_size=None, dapr_http_read_buffer_size=None,
dapr_log_level=None, dapr_enable_api_logging=None):
dapr_log_level=None, dapr_enable_api_logging=None,
workload_profile_name=None, cpu=None, memory=None):
if is_centauri_functionapp(cmd, resource_group_name, name):
_validate_cpu_momory_functionapp(cpu, memory)
if any([enable_dapr, dapr_app_id, dapr_app_port, dapr_http_max_request_size, dapr_http_read_buffer_size,
dapr_log_level, dapr_enable_api_logging]):
update_dapr_config(cmd, resource_group_name, name, enable_dapr, dapr_app_id, dapr_app_port,
dapr_http_max_request_size, dapr_http_read_buffer_size, dapr_log_level,
dapr_enable_api_logging)
dapr_log_level, dapr_enable_api_logging, cpu, memory, workload_profile_name]):
update_dapr_and_workload_config(cmd, resource_group_name, name, enable_dapr, dapr_app_id, dapr_app_port,
dapr_http_max_request_size, dapr_http_read_buffer_size, dapr_log_level,
dapr_enable_api_logging, workload_profile_name, cpu, memory)
return update_container_settings(cmd, resource_group_name, name, registry_server,
image, registry_username, None,
registry_password, multicontainer_config_type=None,
Expand Down Expand Up @@ -3766,35 +3768,75 @@ def should_enable_distributed_tracing(consumption_plan_location, matched_runtime


def update_functionapp_polling(cmd, resource_group_name, name, functionapp):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied this function from @kamperiadis's PR at #27589. We both are doing a similar change.

try:
_generic_site_operation(cmd.cli_ctx, resource_group_name, name, 'update', None, functionapp)
except Exception as ex: # pylint: disable=broad-except
poll_url = ex.response.headers['Location'] if 'Location' in ex.response.headers else None
if ex.response.status_code == 202 and poll_url:
r = send_raw_request(cmd.cli_ctx, method='get', url=poll_url)
poll_timeout = time.time() + 60 * 2 # 2 minute timeout
from azure.cli.core.commands.client_factory import get_subscription_id
client = web_client_factory(cmd.cli_ctx)
sub_id = get_subscription_id(cmd.cli_ctx)
base_url = '/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Web/sites/{}?api-version={}'.format(
sub_id,
resource_group_name,
name,
client.DEFAULT_API_VERSION
)
url = cmd.cli_ctx.cloud.endpoints.resource_manager + base_url

while r.status_code != 200 and time.time() < poll_timeout:
time.sleep(5)
r = send_raw_request(cmd.cli_ctx, method='get', url=poll_url)
else:
raise CLIError(ex)
updated_functionapp = json.dumps(
{
"properties": {
"daprConfig": {
"enabled": functionapp.dapr_config.enabled,
"appId": functionapp.dapr_config.app_id,
"appPort": functionapp.dapr_config.app_port,
"httpReadBufferSize": functionapp.dapr_config.http_read_buffer_size,
"httpMaxRequestSize": functionapp.dapr_config.http_max_request_size,
"logLevel": functionapp.dapr_config.log_level,
"enableApiLogging": functionapp.dapr_config.enable_api_logging
},
"workloadProfileName": functionapp.workload_profile_name,
"resourceConfig": {
"cpu": functionapp.resource_config.cpu,
"memory": functionapp.resource_config.memory
}
}
}
)
response = send_raw_request(cmd.cli_ctx, method='PATCH', url=url, body=updated_functionapp)
poll_url = response.headers.get('location', "")
if response.status_code == 202 and poll_url:
response = send_raw_request(cmd.cli_ctx, method='get', url=poll_url)

while response.status_code != 200:
time.sleep(5)
response = send_raw_request(cmd.cli_ctx, method='get', url=poll_url)

def update_dapr_config(cmd, resource_group_name, name, enabled=None, app_id=None, app_port=None,
http_max_request_size=None, http_read_buffer_size=None, log_level=None,
enable_api_logging=None):
if response.status_code == 200:
return response

else:
return response


def update_dapr_and_workload_config(cmd, resource_group_name, name, enabled=None, app_id=None, app_port=None,
http_max_request_size=None, http_read_buffer_size=None, log_level=None,
enable_api_logging=None, workload_profile_name=None, cpu=None, memory=None):
site = _generic_site_operation(cmd.cli_ctx, resource_group_name, name, 'get')
import inspect
frame = inspect.currentframe()
bool_flags = ['enabled', 'enable_api_logging']
int_flags = ['app_port', 'http_max_request_size', 'http_read_buffer_size']
args, _, _, values = inspect.getargvalues(frame) # pylint: disable=deprecated-method
for arg in args[3:]:
for arg in args[3:10]:
if arg in int_flags and values[arg] is not None:
values[arg] = validate_and_convert_to_int(arg, values[arg])
if values.get(arg, None):
setattr(site.dapr_config, arg, values[arg] if arg not in bool_flags else values[arg] == 'true')

if cpu is not None and memory is not None:
setattr(site.resource_config, 'cpu', cpu)
setattr(site.resource_config, 'memory', memory)

if workload_profile_name is not None:
setattr(site, 'workload_profile_name', workload_profile_name)

update_functionapp_polling(cmd, resource_group_name, name, site)


Expand All @@ -3808,14 +3850,19 @@ def create_functionapp(cmd, resource_group_name, name, storage_account, plan=Non
role='Contributor', scope=None, vnet=None, subnet=None, https_only=False,
environment=None, min_replicas=None, max_replicas=None, workspace=None,
enable_dapr=False, dapr_app_id=None, dapr_app_port=None, dapr_http_max_request_size=None,
dapr_http_read_buffer_size=None, dapr_log_level=None, dapr_enable_api_logging=False):
dapr_http_read_buffer_size=None, dapr_log_level=None, dapr_enable_api_logging=False,
workload_profile_name=None, cpu=None, memory=None):
# pylint: disable=too-many-statements, too-many-branches
if functions_version is None:
logger.warning("No functions version specified so defaulting to 3. In the future, specifying a version will "
"be required. To create a 3.x function you would pass in the flag `--functions-version 3`")
functions_version = '3'
if deployment_source_url and deployment_local_git:
raise MutuallyExclusiveArgumentError('usage error: --deployment-source-url <url> | --deployment-local-git')
if any([cpu, memory, workload_profile_name]) and environment is None:
raise RequiredArgumentMissingError("usage error: parameters --cpu, -memory, --workload-profile-name "
"must be used with parameter --environment, please provide the "
"name of the container app environment using --environment.")
if environment is None and bool(plan) == bool(consumption_plan_location):
raise MutuallyExclusiveArgumentError("usage error: You must specify one of these parameter "
"--plan NAME_OR_ID | --consumption-plan-location LOCATION")
Expand All @@ -3832,7 +3879,8 @@ def create_functionapp(cmd, resource_group_name, name, storage_account, plan=Non
"please provide the name of the container app environment using "
"--environment.")
from azure.mgmt.web.models import Site
SiteConfig, NameValuePair, DaprConfig = cmd.get_models('SiteConfig', 'NameValuePair', 'DaprConfig')
SiteConfig, NameValuePair, DaprConfig, ResourceConfig = cmd.get_models('SiteConfig', 'NameValuePair',
'DaprConfig', 'ResourceConfig')
disable_app_insights = (disable_app_insights == "true")

site_config = SiteConfig(app_settings=[])
Expand Down Expand Up @@ -4016,6 +4064,17 @@ def create_functionapp(cmd, resource_group_name, name, storage_account, plan=Non
functionapp_def.is_xenon = None
functionapp_def.type = 'Microsoft.Web/sites'

# validate cpu and memory parameters.
_validate_cpu_momory_functionapp(cpu, memory)

if (workload_profile_name is not None):
functionapp_def.workload_profile_name = workload_profile_name

if (cpu is not None and memory is not None):
functionapp_def.resource_config = ResourceConfig()
functionapp_def.resource_config.cpu = cpu
functionapp_def.resource_config.memory = memory

site_config.net_framework_version = None
site_config.java_version = None
site_config.use32_bit_worker_process = None
Expand Down Expand Up @@ -4085,6 +4144,9 @@ def create_functionapp(cmd, resource_group_name, name, storage_account, plan=Non
poller = client.web_apps.begin_create_or_update(resource_group_name, name, functionapp_def)
functionapp = LongRunningOperation(cmd.cli_ctx)(poller)

if environment is not None:
functionapp = client.web_apps.get(resource_group_name, name)

if consumption_plan_location and is_linux:
logger.warning("Your Linux function app '%s', that uses a consumption plan has been successfully "
"created but is not active until content is published using "
Expand Down Expand Up @@ -4119,6 +4181,29 @@ def create_functionapp(cmd, resource_group_name, name, storage_account, plan=Non
return functionapp


def _validate_cpu_momory_functionapp(cpu=None, memory=None):
# validate either both cpu and memory are provided or none is provided. throw error otherwise
if cpu is None and memory is None:
return

if cpu is not None and memory is None:
raise ArgumentUsageError("The --memory argument is required with --cpu. Please provide both or none.")

if cpu is None and memory is not None:
raise ArgumentUsageError("The --cpu argument is required with --memory. Please provide both or none.")

# validate that memory is number and ends with Gi
if not memory.lower().endswith("gi"):
raise ValidationError("The --memory argument should end with Gi. Please provide a correct value. e.g. 4.0Gi.")

try:
float(memory[:-2])
except ValueError:
raise ValidationError("The --memory argument is not valid. Please provide a correct value. e.g. 4.0Gi.")

return


def _get_extension_version_functionapp(functions_version):
if functions_version is not None:
return '~{}'.format(functions_version)
Expand Down
Loading