diff --git a/src/containerapp/HISTORY.rst b/src/containerapp/HISTORY.rst index 9223bb8b08a..80531e61c2b 100644 --- a/src/containerapp/HISTORY.rst +++ b/src/containerapp/HISTORY.rst @@ -8,6 +8,8 @@ upcoming * 'az containerapp function keys': Update minimum replica check * 'az containerapp list': Add `--kind` parameter to filter container apps by kind * 'az containerapp function invocations': Fix issue when cloud role name is set +* 'az containerapp sessionpool update': Fix --no-wait issue and extend timeout to 7200s +* 'az containerapp sessionpool update': Fix clean identity issue when not providing identity parameters 1.3.0b1 ++++++ diff --git a/src/containerapp/azext_containerapp/_clients.py b/src/containerapp/azext_containerapp/_clients.py index 957c8f24aa0..27b890e5f5f 100644 --- a/src/containerapp/azext_containerapp/_clients.py +++ b/src/containerapp/azext_containerapp/_clients.py @@ -5,22 +5,25 @@ # pylint: disable=line-too-long, no-else-return, useless-return, broad-except, no-else-raise import json +import time import os import requests -from azure.cli.core.azclierror import ResourceNotFoundError, CLIError +from azure.cli.core.azclierror import CLIError, AzureResponseError from azure.cli.core.util import send_raw_request from azure.cli.core.commands.client_factory import get_subscription_id from azure.cli.command_modules.containerapp._clients import ( poll_status, poll_results, + _extract_delay, AuthClient, GitHubActionClient, ContainerAppClient, ContainerAppsJobClient, DaprComponentClient, ManagedEnvironmentClient, - StorageClient) + StorageClient, + PollingAnimation) from knack.log import get_logger @@ -29,6 +32,7 @@ PREVIEW_API_VERSION = "2025-10-02-preview" POLLING_TIMEOUT = 1500 # how many seconds before exiting POLLING_SECONDS = 2 # how many seconds between requests +POLLING_TIMEOUT_FOR_SESSION_POOL = 7200 # 2 hours for timeout POLLING_TIMEOUT_FOR_MANAGED_CERTIFICATE = 1500 # how many seconds before exiting POLLING_INTERVAL_FOR_MANAGED_CERTIFICATE = 4 # how many seconds between requests HEADER_AZURE_ASYNC_OPERATION = "azure-asyncoperation" @@ -37,6 +41,28 @@ MAINTENANCE_CONFIG_DEFAULT_NAME = "default" +def poll_results_with_timeout(cmd, request_url, polling_timeout_in_sec=POLLING_TIMEOUT): # pylint: disable=inconsistent-return-statements + if not request_url: + raise AzureResponseError(f"Http response lack of necessary header: '{HEADER_LOCATION}'") + + start = time.time() + end = time.time() + polling_timeout_in_sec + animation = PollingAnimation() + + animation.tick() + r = send_raw_request(cmd.cli_ctx, "GET", request_url) + + while r.status_code in [202] and start < end: + time.sleep(_extract_delay(r)) + animation.tick() + r = send_raw_request(cmd.cli_ctx, "GET", request_url) + start = time.time() + + animation.flush() + if r.text: + return json.loads(r.text) + + class GitHubActionPreviewClient(GitHubActionClient): api_version = PREVIEW_API_VERSION @@ -235,9 +261,10 @@ def update(cls, cmd, resource_group_name, name, container_app_name, container_ap operation_url = r.headers.get(HEADER_LOCATION) response = poll_results(cmd, operation_url) if response is None: - raise ResourceNotFoundError("Could not find the app resiliency policy") - else: - return response + logger.debug("poll_results returned empty body. operation_url=%s", operation_url) + raise CLIError("Timed out waiting for the app resiliency policy update operation to complete. Please try again or use --no-wait.") + + return response return r.json() @@ -588,9 +615,10 @@ def update(cls, cmd, resource_group_name, name, managed_environment_envelope, no operation_url = r.headers.get(HEADER_LOCATION) response = poll_results(cmd, operation_url) if response is None: - raise ResourceNotFoundError("Could not find a container app") - else: - return response + logger.debug("poll_results returned empty body. operation_url=%s", operation_url) + raise CLIError("Timed out waiting for the managed environment update operation to complete. Please try again or use --no-wait.") + + return response return r.json() @@ -748,9 +776,10 @@ def update(cls, cmd, resource_group_name, name, managed_environment_envelope, no operation_url = r.headers.get(HEADER_LOCATION) response = poll_results(cmd, operation_url) if response is None: - raise ResourceNotFoundError("Could not find a connected environment") - else: - return response + logger.debug("poll_results returned empty body. operation_url=%s", operation_url) + raise CLIError("Timed out waiting for the connected environment update operation to complete. Please try again or use --no-wait.") + + return response return r.json() @@ -1317,9 +1346,10 @@ def update(cls, cmd, resource_group_name, environment_name, name, java_component operation_url = r.headers.get(HEADER_LOCATION) response = poll_results(cmd, operation_url) if response is None: - raise ResourceNotFoundError("Could not find the Java component") - else: - return response + logger.debug("poll_results returned empty body. operation_url=%s", operation_url) + raise CLIError("Timed out waiting for the Java component update operation to complete. Please try again or use --no-wait.") + + return response return r.json() @@ -1430,11 +1460,12 @@ def update(cls, cmd, resource_group_name, name, session_pool_envelope, no_wait=F return elif r.status_code == 202: operation_url = r.headers.get(HEADER_LOCATION) - response = poll_results(cmd, operation_url) + response = poll_results_with_timeout(cmd, operation_url, POLLING_TIMEOUT_FOR_SESSION_POOL) if response is None: - raise ResourceNotFoundError("Could not find the Session Pool") - else: - return response + logger.debug("poll_results returned empty body. operation_url=%s", operation_url) + raise CLIError("Timed out waiting for the session pool update operation to complete. Please try again or use --no-wait.") + + return response return r.json() @@ -1733,9 +1764,10 @@ def update(cls, cmd, resource_group_name, environment_name, name, dotnet_compone operation_url = r.headers.get(HEADER_LOCATION) response = poll_results(cmd, operation_url) if response is None: - raise ResourceNotFoundError("Could not find the DotNet component") - else: - return response + logger.debug("poll_results returned empty body. operation_url=%s", operation_url) + raise CLIError("Timed out waiting for the .NET component update operation to complete. Please try again or use --no-wait.") + + return response return r.json() @@ -1845,9 +1877,10 @@ def create_or_update(cls, cmd, resource_group_name, environment_name, maintenanc operation_url = r.headers.get(HEADER_LOCATION) response = poll_results(cmd, operation_url) if response is None: - raise ResourceNotFoundError("Could not find the maintenance config") - else: - return response + logger.debug("poll_results returned empty body. operation_url=%s", operation_url) + raise CLIError("Timed out waiting for the maintenance configuration operation to complete. Please try again or use --no-wait.") + + return response return r.json() diff --git a/src/containerapp/azext_containerapp/custom.py b/src/containerapp/azext_containerapp/custom.py index a2b2077e304..a5ad655f894 100644 --- a/src/containerapp/azext_containerapp/custom.py +++ b/src/containerapp/azext_containerapp/custom.py @@ -3173,8 +3173,9 @@ def update_session_pool(cmd, registry_user=None, mi_user_assigned=None, registry_identity=None, - mi_system_assigned=False, - probe_yaml=None): + mi_system_assigned=None, + probe_yaml=None, + no_wait=False): raw_parameters = locals() session_pool_decorator = SessionPoolUpdateDecorator( cmd=cmd,