Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -1458,3 +1458,91 @@ def list_usages(cls, cmd, location):

r = send_raw_request(cmd.cli_ctx, "GET", request_url)
return r.json()


class HttpRouteConfigClient:
api_version = CURRENT_API_VERSION

@classmethod
def create(cls, cmd, resource_group_name, name, http_route_config_name, http_route_config_envelope):
management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/resourceGroups/{}/providers/Microsoft.App/managedEnvironments/{}/httpRouteConfigs/{}?api-version={}"
request_url = url_fmt.format(
management_hostname.strip('/'),
sub_id,
resource_group_name,
name,
http_route_config_name,
cls.api_version)

r = send_raw_request(cmd.cli_ctx, "PUT", request_url, body=json.dumps(http_route_config_envelope))
return r.json()

@classmethod
def update(cls, cmd, resource_group_name, name, http_route_config_name, http_route_config_envelope):
management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/resourceGroups/{}/providers/Microsoft.App/managedEnvironments/{}/httpRouteConfigs/{}?api-version={}"
request_url = url_fmt.format(
management_hostname.strip('/'),
sub_id,
resource_group_name,
name,
http_route_config_name,
cls.api_version)

r = send_raw_request(cmd.cli_ctx, "PATCH", request_url, body=json.dumps(http_route_config_envelope))
return r.json()

@classmethod
def list(cls, cmd, resource_group_name, name):
route_list = []
management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/resourceGroups/{}/providers/Microsoft.App/managedEnvironments/{}/httpRouteConfigs?api-version={}"
request_url = url_fmt.format(
management_hostname.strip('/'),
sub_id,
resource_group_name,
name,
cls.api_version)

r = send_raw_request(cmd.cli_ctx, "GET", request_url, body=None)
j = r.json()
for route in j["value"]:
route_list.append(route)
return route_list

@classmethod
def show(cls, cmd, resource_group_name, name, http_route_config_name):
management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/resourceGroups/{}/providers/Microsoft.App/managedEnvironments/{}/httpRouteConfigs/{}?api-version={}"
request_url = url_fmt.format(
management_hostname.strip('/'),
sub_id,
resource_group_name,
name,
http_route_config_name,
cls.api_version)

r = send_raw_request(cmd.cli_ctx, "GET", request_url, body=None)
return r.json()

@classmethod
def delete(cls, cmd, resource_group_name, name, http_route_config_name):
management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/resourceGroups/{}/providers/Microsoft.App/managedEnvironments/{}/httpRouteConfigs/{}?api-version={}"
request_url = url_fmt.format(
management_hostname.strip('/'),
sub_id,
resource_group_name,
name,
http_route_config_name,
cls.api_version)

send_raw_request(cmd.cli_ctx, "DELETE", request_url, body=None)
# API doesn't return JSON (it returns no content)
return
101 changes: 101 additions & 0 deletions src/azure-cli/azure/cli/command_modules/containerapp/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -1641,3 +1641,104 @@
--environment MyContainerappEnv \\
--compose-file-path "path/to/docker-compose.yml"
"""

# Routing
helps['containerapp env http-route-config'] = """
type: group
short-summary: Commands to manage environment level http routing.
"""

helps['containerapp env http-route-config list'] = """
type: command
short-summary: List the http route configs in the environment.
Comment on lines +1651 to +1653
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

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

The help message should start with an active voice verb. Change 'List the http route configs' to 'List http route configs'.

Copilot uses AI. Check for mistakes.
examples:
- name: List the http route configs in the environment.
text: |
az containerapp env http-route-config list -g MyResourceGroup -n MyEnvironment
"""

helps['containerapp env http-route-config create'] = """
type: command
short-summary: Create a new http route config.
Comment on lines +1660 to +1662
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

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

The help message should start with an active voice verb. Change 'Create a new http route config' to 'Create http route config'.

Copilot uses AI. Check for mistakes.
examples:
- name: Create a new route from a yaml file.
text: |
az containerapp env http-route-config create -g MyResourceGroup -n MyEnvironment -r configname --yaml config.yaml
"""

helps['containerapp env http-route-config update'] = """
type: command
short-summary: Update a http route config.
Comment on lines +1669 to +1671
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

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

The help message should start with an active voice verb. Change 'Update a http route config' to 'Update http route config'.

Copilot uses AI. Check for mistakes.
examples:
- name: Update a route in the environment from a yaml file.
text: |
az containerapp env http-route-config update -g MyResourceGroup -n MyEnvironment -r configname --yaml config.yaml
"""

helps['containerapp env http-route-config show'] = """
type: command
short-summary: Show a http route config.
Comment on lines +1678 to +1680
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

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

The help message should start with an active voice verb. Change 'Show a http route config' to 'Show http route config'.

Copilot uses AI. Check for mistakes.
examples:
- name: Show a route in the environment.
text: |
az containerapp env http-route-config show -g MyResourceGroup -n MyEnvironment -r configname
"""

helps['containerapp env http-route-config delete'] = """
type: command
short-summary: Delete a http route config.
Comment on lines +1687 to +1689
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

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

The help message should start with an active voice verb. Change 'Delete a http route config' to 'Delete http route config'.

Copilot uses AI. Check for mistakes.
examples:
- name: Delete a route from the environment.
text: |
az containerapp env http-route-config delete -g MyResourceGroup -n MyEnvironment -r configname
"""

# Ingress
helps['containerapp env premium-ingress show'] = """
type: command
short-summary: Show the premium ingress settings for the environment.
Comment on lines +1697 to +1699
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

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

The help message should start with an active voice verb. Change 'Show the premium ingress settings' to 'Show premium ingress settings'.

Copilot uses AI. Check for mistakes.
examples:
- name: Show the premium ingress settings for the environment.
text: |
az containerapp env premium-ingress show -g MyResourceGroup -n MyEnvironment
"""

helps['containerapp env premium-ingress'] = """
type: group
short-summary: Configure premium ingress settings for the environment.
long-summary: |
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.
examples:
- name: Enable premium ingress for the environment.
text: |
az containerapp env premium-ingress add -g MyResourceGroup -n MyEnvironment -w WorkloadProfileName
"""

helps['containerapp env premium-ingress add'] = """
type: command
short-summary: Enable the premium ingress settings for the environment.
Comment on lines +1717 to +1719
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

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

The help message should start with an active voice verb. Change 'Enable the premium ingress settings' to 'Enable premium ingress settings'.

Copilot uses AI. Check for mistakes.
long-summary: |
Unspecified optional parameters will be cleared from any existing configuration.
examples:
- name: Add the premium ingress settings for the environment.
text: |
az containerapp env premium-ingress add -g MyResourceGroup -n MyEnvironment -w WorkloadProfileName
"""

helps['containerapp env premium-ingress update'] = """
type: command
short-summary: Update the premium ingress settings for the environment.
Comment on lines +1728 to +1730
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

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

The help message should start with an active voice verb. Change 'Update the premium ingress settings' to 'Update premium ingress settings'.

Copilot uses AI. Check for mistakes.
examples:
- name: Update the workload profile used for premium ingress.
text: |
az containerapp env premium-ingress update -g MyResourceGroup -n MyEnvironment -w WorkloadProfileName
"""

helps['containerapp env premium-ingress remove'] = """
type: command
short-summary: Remove the ingress settings and restores the system to default values.
Comment on lines +1737 to +1739
Copy link

Copilot AI Oct 10, 2025

Choose a reason for hiding this comment

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

The help message should start with an active voice verb. Change 'Remove the ingress settings and restores' to 'Remove ingress settings and restore'.

Copilot uses AI. Check for mistakes.
examples:
- name: Reset the ingress settings for the environment to its default values
text: |
az containerapp env premium-ingress remove -g MyResourceGroup -n MyEnvironment
"""
13 changes: 13 additions & 0 deletions src/azure-cli/azure/cli/command_modules/containerapp/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,3 +500,16 @@ def load_arguments(self, _):

with self.argument_context('containerapp job registry list') as c:
c.argument('name', id_part=None)

with self.argument_context('containerapp env http-route-config') as c:
c.argument('http_route_config_name', options_list=['--http-route-config-name', '-r'], help="The name of the http route configuration.")
c.argument('yaml', help="The path to the YAML input file.")
c.argument('name', id_part=None)

with self.argument_context('containerapp env premium-ingress') as c:
c.argument('resource_group_name', arg_type=resource_group_name_type, id_part=None)
c.argument('name', options_list=['--name', '-n'], help="The name of the managed environment.")
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.")
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.")
c.argument('request_idle_timeout', type=int, help="Timeout in minutes for idle requests. Default 4, minimum 4, maximum 30.")
c.argument('header_count_limit', type=int, help="Limit of http headers per request. Default 100, minimum 1.")
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,16 @@ def load_command_table(self, _):
g.custom_command('add', 'add_workload_profile')
g.custom_command('update', 'update_workload_profile')
g.custom_command('delete', 'delete_workload_profile')

with self.command_group('containerapp env http-route-config') as g:
g.custom_show_command('show', 'show_http_route_config')
g.custom_command('list', 'list_http_route_configs')
g.custom_command('create', 'create_http_route_config', exception_handler=ex_handler_factory())
g.custom_command('update', 'update_http_route_config', exception_handler=ex_handler_factory())
g.custom_command('delete', 'delete_http_route_config', confirmation=True, exception_handler=ex_handler_factory())

with self.command_group('containerapp env premium-ingress') as g:
g.custom_show_command('show', 'show_environment_premium_ingress')
g.custom_command('add', 'add_environment_premium_ingress')
g.custom_command('update', 'update_environment_premium_ingress')
g.custom_command('remove', 'remove_environment_premium_ingress', confirmation=True)
158 changes: 158 additions & 0 deletions src/azure-cli/azure/cli/command_modules/containerapp/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
AuthClient,
WorkloadProfileClient,
ContainerAppsJobClient,
HttpRouteConfigClient,
SubscriptionClient
)
from ._github_oauth import get_github_access_token
Expand Down Expand Up @@ -5088,3 +5089,160 @@ def delete_workload_profile(cmd, resource_group_name, env_name, workload_profile
return r
except Exception as e:
handle_raw_exception(e)


def create_http_route_config(cmd, resource_group_name, name, http_route_config_name, yaml):
_validate_subscription_registered(cmd, CONTAINER_APPS_RP)
yaml_http_route_config = load_yaml_file(yaml)
# check if the type is dict
if not isinstance(yaml_http_route_config, dict):
raise ValidationError('Invalid YAML provided. Please see https://aka.ms/azure-container-apps-yaml for a valid YAML spec.')

http_route_config_envelope = {"properties": yaml_http_route_config}

try:
return HttpRouteConfigClient.create(cmd, resource_group_name, name, http_route_config_name, http_route_config_envelope)
except Exception as e:
handle_raw_exception(e)


def update_http_route_config(cmd, resource_group_name, name, http_route_config_name, yaml):
_validate_subscription_registered(cmd, CONTAINER_APPS_RP)
yaml_http_route_config = load_yaml_file(yaml)
# check if the type is dict
if not isinstance(yaml_http_route_config, dict):
raise ValidationError('Invalid YAML provided. Please see https://aka.ms/azure-container-apps-yaml for a valid YAML spec.')

http_route_config_envelope = {"properties": yaml_http_route_config}

try:
return HttpRouteConfigClient.update(cmd, resource_group_name, name, http_route_config_name, http_route_config_envelope)
except Exception as e:
handle_raw_exception(e)


def list_http_route_configs(cmd, resource_group_name, name):
_validate_subscription_registered(cmd, CONTAINER_APPS_RP)
try:
return HttpRouteConfigClient.list(cmd, resource_group_name, name)
except Exception as e:
handle_raw_exception(e)


def show_http_route_config(cmd, resource_group_name, name, http_route_config_name):
_validate_subscription_registered(cmd, CONTAINER_APPS_RP)
try:
return HttpRouteConfigClient.show(cmd, resource_group_name, name, http_route_config_name)
except Exception as e:
handle_raw_exception(e)


def delete_http_route_config(cmd, resource_group_name, name, http_route_config_name):
_validate_subscription_registered(cmd, CONTAINER_APPS_RP)
try:
return HttpRouteConfigClient.delete(cmd, resource_group_name, name, http_route_config_name)
except Exception as e:
handle_raw_exception(e)


def show_environment_premium_ingress(cmd, name, resource_group_name):
_validate_subscription_registered(cmd, CONTAINER_APPS_RP)

try:
env = ManagedEnvironmentClient.show(cmd, resource_group_name, name)
ingress_config = safe_get(env, "properties", "ingressConfiguration")
if not ingress_config:
return {"message": "No premium ingress configuration found for this environment, using default values."}

return ingress_config
except Exception as e:
handle_raw_exception(e)


def add_environment_premium_ingress(cmd, name, resource_group_name, workload_profile_name, min_replicas=None, max_replicas=None, termination_grace_period=None, request_idle_timeout=None, header_count_limit=None, no_wait=False):
_validate_subscription_registered(cmd, CONTAINER_APPS_RP)

try:
ManagedEnvironmentClient.show(cmd, resource_group_name, name)
env_patch = {}
ingress_config = {}
safe_set(env_patch, "properties", "ingressConfiguration", value=ingress_config)

# Required
ingress_config["workloadProfileName"] = workload_profile_name
# Optional, remove if None
ingress_config["terminationGracePeriodSeconds"] = termination_grace_period
ingress_config["requestIdleTimeout"] = request_idle_timeout
ingress_config["headerCountLimit"] = header_count_limit

result = ManagedEnvironmentClient.update(
cmd=cmd,
resource_group_name=resource_group_name,
name=name,
managed_environment_envelope=env_patch,
no_wait=no_wait
)

return safe_get(result, "properties", "ingressConfiguration")

except Exception as e:
handle_raw_exception(e)


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):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @Tratcher
You didn't remove not needed params min_replicas=None, max_replicas=None

image image

_validate_subscription_registered(cmd, CONTAINER_APPS_RP)

try:
ManagedEnvironmentClient.show(cmd, resource_group_name, name)
env_patch = {}
ingress_config = {}

if workload_profile_name is not None:
ingress_config["workloadProfileName"] = workload_profile_name
if termination_grace_period is not None:
ingress_config["terminationGracePeriodSeconds"] = termination_grace_period
if request_idle_timeout is not None:
ingress_config["requestIdleTimeout"] = request_idle_timeout
if header_count_limit is not None:
ingress_config["headerCountLimit"] = header_count_limit

# Only add ingressConfiguration to the patch if any values were specified
if ingress_config:
safe_set(env_patch, "properties", "ingressConfiguration", value=ingress_config)
else:
return {"message": "No changes specified for premium ingress configuration"}

# Update the environment with the patched ingress configuration
result = ManagedEnvironmentClient.update(
cmd=cmd,
resource_group_name=resource_group_name,
name=name,
managed_environment_envelope=env_patch,
no_wait=no_wait
)

return safe_get(result, "properties", "ingressConfiguration")

except Exception as e:
handle_raw_exception(e)


def remove_environment_premium_ingress(cmd, name, resource_group_name, no_wait=False):
_validate_subscription_registered(cmd, CONTAINER_APPS_RP)

try:
ManagedEnvironmentClient.show(cmd, resource_group_name, name)
env_patch = {}
# Remove the whole section to restore defaults
safe_set(env_patch, "properties", "ingressConfiguration", value=None)

ManagedEnvironmentClient.update(
cmd=cmd,
resource_group_name=resource_group_name,
name=name,
managed_environment_envelope=env_patch,
no_wait=no_wait
)

except Exception as e:
handle_raw_exception(e)
Loading