Skip to content

Commit 5950b48

Browse files
authored
[Containerapp] az containerapp env premium-ingress (#8677)
1 parent 4b34bd3 commit 5950b48

File tree

9 files changed

+55837
-2173
lines changed

9 files changed

+55837
-2173
lines changed

src/containerapp/HISTORY.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Release History
44
===============
55
upcoming
66
++++++
7+
* 'az containerapp env premium-ingress': New environment level ingress configuration.
78
* 'az containerapp sessionpool update': Support `--mi-system-assigned`, `--mi-user-assigned` and `--registry-identity`
89
* Upgrade api-version to 2025-02-02-preview
910

src/containerapp/azext_containerapp/_help.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,3 +2366,52 @@
23662366
text: |
23672367
az containerapp env http-route-config delete -g MyResourceGroup -n MyEnvironment -r configname
23682368
"""
2369+
2370+
helps['containerapp env premium-ingress show'] = """
2371+
type: command
2372+
short-summary: Show the premium ingress settings for the environment.
2373+
examples:
2374+
- name: Show the premium ingress settings for the environment.
2375+
text: |
2376+
az containerapp env premium-ingress show -g MyResourceGroup -n MyEnvironment
2377+
"""
2378+
2379+
helps['containerapp env premium-ingress'] = """
2380+
type: group
2381+
short-summary: Configure premium ingress settings for the environment.
2382+
long-summary: |
2383+
Premium ingress settings apply to all applications in the environment. They allow moving the ingress instances to a workload profile and scaling them beyond the system defaults to enable high traffic workloads. Other settings include request idle timeouts, header count limits, and the termination grace period.
2384+
examples:
2385+
- name: Enable premium ingress for the environment.
2386+
text: |
2387+
az containerapp env premium-ingress add -g MyResourceGroup -n MyEnvironment -w WorkloadProfileName --min-replicas 2 --max-replicas 10
2388+
"""
2389+
2390+
helps['containerapp env premium-ingress add'] = """
2391+
type: command
2392+
short-summary: Enable the premium ingress settings for the environment.
2393+
long-summary: |
2394+
Unspecified optional parameters will be cleared from any existing configuration.
2395+
examples:
2396+
- name: Add the premium ingress settings for the environment.
2397+
text: |
2398+
az containerapp env premium-ingress add -g MyResourceGroup -n MyEnvironment -w WorkloadProfileName --min-replicas 2 --max-replicas 10
2399+
"""
2400+
2401+
helps['containerapp env premium-ingress update'] = """
2402+
type: command
2403+
short-summary: Update the premium ingress settings for the environment.
2404+
examples:
2405+
- name: Update the workload profile used for premium ingress.
2406+
text: |
2407+
az containerapp env premium-ingress update -g MyResourceGroup -n MyEnvironment -w WorkloadProfileName
2408+
"""
2409+
2410+
helps['containerapp env premium-ingress remove'] = """
2411+
type: command
2412+
short-summary: Remove the ingress settings and restores the system to default values.
2413+
examples:
2414+
- name: Reset the ingress settings for the environment to its default values
2415+
text: |
2416+
az containerapp env premium-ingress remove -g MyResourceGroup -n MyEnvironment
2417+
"""

src/containerapp/azext_containerapp/_params.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def load_arguments(self, _):
4848
c.ignore('service_type')
4949

5050
with self.argument_context('containerapp create', arg_group='GitHub Repository', is_preview=True) as c:
51-
c.argument('repo', help='Create an app via GitHub Actions in the format: https://github.com/owner/repository-name or owner/repository-name')
51+
c.argument('repo', help='Create an app via GitHub Actions in the format: `https://github.com/owner/repository-name` or owner/repository-name')
5252
c.argument('token', help='A Personal Access Token with write access to the specified repository. For more information: https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line. If not provided or not found in the cache (and using --repo), a browser page will be opened to authenticate with Github.')
5353
c.argument('branch', options_list=['--branch', '-b'], help='Branch in the provided GitHub repository. Assumed to be the GitHub repository\'s default branch if not specified.')
5454
c.argument('context_path', help='Path in the repository to run docker build. Defaults to "./". Dockerfile is assumed to be named "Dockerfile" and in this directory.')
@@ -264,7 +264,7 @@ def load_arguments(self, _):
264264
c.argument('target_label', help="The label to apply to new revisions. Required for revisions-mode 'labels'.", is_preview=True)
265265

266266
with self.argument_context('containerapp up', arg_group='Github Repo') as c:
267-
c.argument('repo', help='Create an app via Github Actions. In the format: https://github.com/owner/repository-name or owner/repository-name')
267+
c.argument('repo', help='Create an app via Github Actions. In the format: `https://github.com/owner/repository-name` or owner/repository-name')
268268
c.argument('token', help='A Personal Access Token with write access to the specified repository. For more information: https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line. If not provided or not found in the cache (and using --repo), a browser page will be opened to authenticate with Github.')
269269
c.argument('branch', options_list=['--branch', '-b'], help='The branch of the Github repo. Assumed to be the Github repo\'s default branch if not specified.')
270270
c.argument('context_path', help='Path in the repo from which to run the docker build. Defaults to "./". Dockerfile is assumed to be named "Dockerfile" and in this directory.')
@@ -510,3 +510,13 @@ def load_arguments(self, _):
510510
with self.argument_context('containerapp revision set-mode') as c:
511511
c.argument('mode', arg_type=get_enum_type(['single', 'multiple', 'labels']), help="The active revisions mode for the container app.")
512512
c.argument('target_label', help="The label to apply to new revisions. Required for revision mode 'labels'.", is_preview=True)
513+
514+
with self.argument_context('containerapp env premium-ingress') as c:
515+
c.argument('resource_group_name', arg_type=resource_group_name_type, id_part=None)
516+
c.argument('name', options_list=['--name', '-n'], help="The name of the managed environment.")
517+
c.argument('workload_profile_name', options_list=['--workload-profile-name', '-w'], help="The workload profile to run ingress replicas on. This profile must not be shared with any container app or job.")
518+
c.argument('min_replicas', options_list=['--min-replicas'], type=int, help="Minimum number of replicas to run. Default 2, minimum 2.")
519+
c.argument('max_replicas', options_list=['--max-replicas'], type=int, help="Maximum number of replicas to run. Default 10. The upper limit is the maximum cores available in the workload profile.")
520+
c.argument('termination_grace_period', options_list=['--termination-grace-period', '-t'], type=int, help="Time in seconds to drain requests during ingress shutdown. Default 500, minimum 0, maximum 3600.")
521+
c.argument('request_idle_timeout', options_list=['--request-idle-timeout'], type=int, help="Timeout in minutes for idle requests. Default 4, minimum 1.")
522+
c.argument('header_count_limit', options_list=['--header-count-limit'], type=int, help="Limit of http headers per request. Default 100, minimum 1.")

src/containerapp/azext_containerapp/commands.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,3 +291,9 @@ def load_command_table(self, args):
291291
with self.command_group('containerapp revision label') as g:
292292
g.custom_command('add', 'add_revision_label')
293293
g.custom_command('remove', 'remove_revision_label')
294+
295+
with self.command_group('containerapp env premium-ingress', is_preview=True) as g:
296+
g.custom_show_command('show', 'show_environment_premium_ingress')
297+
g.custom_command('add', 'add_environment_premium_ingress')
298+
g.custom_command('update', 'update_environment_premium_ingress')
299+
g.custom_command('remove', 'remove_environment_premium_ingress', confirmation=True)

src/containerapp/azext_containerapp/custom.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3807,3 +3807,117 @@ def remove_revision_label(cmd, resource_group_name, name, label, no_wait=False):
38073807
return r['properties']['configuration']['ingress']['traffic']
38083808
except Exception as e:
38093809
handle_raw_exception(e)
3810+
3811+
3812+
def show_environment_premium_ingress(cmd, name, resource_group_name):
3813+
_validate_subscription_registered(cmd, CONTAINER_APPS_RP)
3814+
3815+
try:
3816+
env = ManagedEnvironmentPreviewClient.show(cmd, resource_group_name, name)
3817+
ingress_config = safe_get(env, "properties", "ingressConfiguration")
3818+
if not ingress_config:
3819+
return {"message": "No premium ingress configuration found for this environment, using default values."}
3820+
3821+
return ingress_config
3822+
except Exception as e:
3823+
handle_raw_exception(e)
3824+
3825+
3826+
def add_environment_premium_ingress(cmd, name, resource_group_name, workload_profile_name, min_replicas, max_replicas, termination_grace_period=None, request_idle_timeout=None, header_count_limit=None, no_wait=False):
3827+
_validate_subscription_registered(cmd, CONTAINER_APPS_RP)
3828+
3829+
try:
3830+
ManagedEnvironmentPreviewClient.show(cmd, resource_group_name, name)
3831+
env_patch = {}
3832+
ingress_config = {}
3833+
safe_set(env_patch, "properties", "ingressConfiguration", value=ingress_config)
3834+
scale = {}
3835+
ingress_config["scale"] = scale
3836+
3837+
# Required
3838+
ingress_config["workloadProfileName"] = workload_profile_name
3839+
scale["minReplicas"] = min_replicas
3840+
scale["maxReplicas"] = max_replicas
3841+
# Optional, remove if None
3842+
ingress_config["terminationGracePeriodSeconds"] = termination_grace_period
3843+
ingress_config["requestIdleTimeout"] = request_idle_timeout
3844+
ingress_config["headerCountLimit"] = header_count_limit
3845+
3846+
result = ManagedEnvironmentPreviewClient.update(
3847+
cmd=cmd,
3848+
resource_group_name=resource_group_name,
3849+
name=name,
3850+
managed_environment_envelope=env_patch,
3851+
no_wait=no_wait
3852+
)
3853+
3854+
return safe_get(result, "properties", "ingressConfiguration")
3855+
3856+
except Exception as e:
3857+
handle_raw_exception(e)
3858+
3859+
3860+
def update_environment_premium_ingress(cmd, name, resource_group_name, workload_profile_name=None, min_replicas=None, max_replicas=None, termination_grace_period=None, request_idle_timeout=None, header_count_limit=None, no_wait=False):
3861+
_validate_subscription_registered(cmd, CONTAINER_APPS_RP)
3862+
3863+
try:
3864+
ManagedEnvironmentPreviewClient.show(cmd, resource_group_name, name)
3865+
env_patch = {}
3866+
ingress_config = {}
3867+
scale = {}
3868+
3869+
if workload_profile_name is not None:
3870+
ingress_config["workloadProfileName"] = workload_profile_name
3871+
if min_replicas is not None:
3872+
ingress_config["scale"] = scale
3873+
scale["minReplicas"] = min_replicas
3874+
if max_replicas is not None:
3875+
ingress_config["scale"] = scale
3876+
scale["maxReplicas"] = max_replicas
3877+
if termination_grace_period is not None:
3878+
ingress_config["terminationGracePeriodSeconds"] = termination_grace_period
3879+
if request_idle_timeout is not None:
3880+
ingress_config["requestIdleTimeout"] = request_idle_timeout
3881+
if header_count_limit is not None:
3882+
ingress_config["headerCountLimit"] = header_count_limit
3883+
3884+
# Only add ingressConfiguration to the patch if any values were specified
3885+
if ingress_config:
3886+
safe_set(env_patch, "properties", "ingressConfiguration", value=ingress_config)
3887+
else:
3888+
return {"message": "No changes specified for premium ingress configuration"}
3889+
3890+
# Update the environment with the patched ingress configuration
3891+
result = ManagedEnvironmentPreviewClient.update(
3892+
cmd=cmd,
3893+
resource_group_name=resource_group_name,
3894+
name=name,
3895+
managed_environment_envelope=env_patch,
3896+
no_wait=no_wait
3897+
)
3898+
3899+
return safe_get(result, "properties", "ingressConfiguration")
3900+
3901+
except Exception as e:
3902+
handle_raw_exception(e)
3903+
3904+
3905+
def remove_environment_premium_ingress(cmd, name, resource_group_name, no_wait=False):
3906+
_validate_subscription_registered(cmd, CONTAINER_APPS_RP)
3907+
3908+
try:
3909+
ManagedEnvironmentPreviewClient.show(cmd, resource_group_name, name)
3910+
env_patch = {}
3911+
# Remove the whole section to restore defaults
3912+
safe_set(env_patch, "properties", "ingressConfiguration", value=None)
3913+
3914+
ManagedEnvironmentPreviewClient.update(
3915+
cmd=cmd,
3916+
resource_group_name=resource_group_name,
3917+
name=name,
3918+
managed_environment_envelope=env_patch,
3919+
no_wait=no_wait
3920+
)
3921+
3922+
except Exception as e:
3923+
handle_raw_exception(e)

0 commit comments

Comments
 (0)