Skip to content

Commit aa7431b

Browse files
[connectedk8s] Update extension CLI to v1.10.5 (#8454)
1 parent df75dba commit aa7431b

File tree

14 files changed

+752
-336
lines changed

14 files changed

+752
-336
lines changed

src/connectedk8s/HISTORY.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
Release History
44
===============
55

6+
1.10.5
7+
++++++
8+
* Fixed bug impacting long-running operations of the az connectedk8s proxy command.
9+
* Refactored code to reduce proxy command startup time.
10+
* Added support for downloading proxy binaries from MCR, including more architecture-specific versions.
11+
* Enhanced telemetry to capture detailed error information during Helm installation failures.
12+
613
1.10.4
714
++++++
815
* Fixed the issue where the 'connectedk8s proxy' command would fail if the kubeconfig file was empty.

src/connectedk8s/azext_connectedk8s/_constants.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@
163163
Create_Directory_Fault_Type = (
164164
"Error while creating directory for placing the executable"
165165
)
166+
Remove_File_Fault_Type = "Error while deleting the specified file"
166167
Run_Clientproxy_Fault_Type = "Error while starting client proxy process."
167168
Post_Hybridconn_Fault_Type = (
168169
"Error while posting hybrid connection details to proxy process"
@@ -460,23 +461,20 @@
460461
)
461462
DNS_Check_Result_String = "DNS Result:"
462463
AZ_CLI_ADAL_TO_MSAL_MIGRATE_VERSION = "2.30.0"
463-
CLIENT_PROXY_VERSION = "1.3.022011"
464+
CLIENT_PROXY_VERSION = "1.3.029301"
465+
CLIENT_PROXY_FOLDER = ".clientproxy"
464466
API_SERVER_PORT = 47011
465467
CLIENT_PROXY_PORT = 47010
466468
CLIENTPROXY_CLIENT_ID = "04b07795-8ddb-461a-bbee-02f9e1bf7b46"
467469
API_CALL_RETRIES = 12
468470
DEFAULT_REQUEST_TIMEOUT = 10 # seconds
469-
RELEASE_DATE_WINDOWS = "release12-01-23"
470-
RELEASE_DATE_LINUX = "release12-01-23"
471471
CSP_REFRESH_TIME = 300
472472

473473
# Default timeout in seconds for Onboarding Helm Install
474474
DEFAULT_MAX_ONBOARDING_TIMEOUT_HELMVALUE_SECONDS = "1200"
475475

476476
# URL constants
477-
CSP_Storage_Url = "https://k8sconnectcsp.azureedge.net"
478-
CSP_Storage_Url_Mooncake = "https://k8sconnectcsp.blob.core.chinacloudapi.cn"
479-
CSP_Storage_Url_Fairfax = "https://k8sconnectcsp.azureedge.us"
477+
CLIENT_PROXY_MCR_TARGET = "mcr.microsoft.com/azureconnectivity/proxy"
480478
HELM_STORAGE_URL = "https://k8connecthelm.azureedge.net"
481479
HELM_VERSION = "v3.12.2"
482480
Download_And_Install_Kubectl_Fault_Type = "Failed to download and install kubectl"
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# --------------------------------------------------------------------------------------------
5+
6+
import os
7+
8+
from azure.cli.core import azclierror, telemetry
9+
from knack import log
10+
11+
import azext_connectedk8s._constants as consts
12+
13+
logger = log.get_logger(__name__)
14+
15+
16+
def delete_file(file_path: str, message: str, warning: bool = False) -> None:
17+
# pylint: disable=broad-except
18+
if os.path.isfile(file_path):
19+
try:
20+
os.remove(file_path)
21+
except Exception as e:
22+
telemetry.set_exception(
23+
exception=e,
24+
fault_type=consts.Remove_File_Fault_Type,
25+
summary=f"Unable to delete file at {file_path}",
26+
)
27+
if warning:
28+
logger.warning(message)
29+
else:
30+
raise azclierror.FileOperationError(message + "Error: " + str(e)) from e
31+
32+
33+
def create_directory(file_path: str, error_message: str) -> None:
34+
try:
35+
os.makedirs(file_path)
36+
except Exception as e:
37+
telemetry.set_exception(
38+
exception=e,
39+
fault_type=consts.Create_Directory_Fault_Type,
40+
summary="Unable to create installation directory",
41+
)
42+
raise azclierror.FileOperationError(error_message + "Error: " + str(e)) from e

src/connectedk8s/azext_connectedk8s/_troubleshootutils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,8 +1769,7 @@ def check_msi_expiry(connected_cluster: ConnectedCluster) -> str:
17691769
# To handle any exception that may occur during the execution
17701770
except Exception as e:
17711771
logger.exception(
1772-
"An exception has occured while performing msi expiry check on the "
1773-
"cluster."
1772+
"An exception has occured while performing msi expiry check on the cluster."
17741773
)
17751774
telemetry.set_exception(
17761775
exception=e,

src/connectedk8s/azext_connectedk8s/_utils.py

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import contextlib
88
import json
99
import os
10+
import re
1011
import shutil
1112
import subprocess
1213
import sys
@@ -1307,6 +1308,16 @@ def helm_install_release(
13071308
_, error_helm_install = response_helm_install.communicate()
13081309
if response_helm_install.returncode != 0:
13091310
helm_install_error_message = error_helm_install.decode("ascii")
1311+
helm_install_error_message = process_helm_error_detail(
1312+
helm_install_error_message
1313+
)
1314+
helm_error_detail = {
1315+
"Context.Default.AzureCLI.onboardingErrorType": consts.Install_HelmRelease_Fault_Type,
1316+
"Context.Default.AzureCLI.onboardingErrorMessage": helm_install_error_message,
1317+
}
1318+
# Replace the existing calls with the new function
1319+
1320+
telemetry.add_extension_event("connectedk8s", helm_error_detail)
13101321
if any(
13111322
message in helm_install_error_message
13121323
for message in consts.Helm_Install_Release_Userfault_Messages
@@ -1328,6 +1339,55 @@ def helm_install_release(
13281339
)
13291340

13301341

1342+
def process_helm_error_detail(helm_error_detail: str) -> str:
1343+
helm_error_detail = remove_rsa_private_key(helm_error_detail)
1344+
helm_error_detail = scrub_proxy_url(helm_error_detail)
1345+
helm_error_detail = redact_base64_strings(helm_error_detail)
1346+
helm_error_detail = redact_sensitive_fields_from_string(helm_error_detail)
1347+
1348+
return helm_error_detail
1349+
1350+
1351+
def remove_rsa_private_key(input_text: str) -> str:
1352+
# Regex to identify RSA private key
1353+
rsa_key_pattern = re.compile(
1354+
r"-----BEGIN RSA PRIVATE KEY-----.*?-----END RSA PRIVATE KEY-----", re.DOTALL
1355+
)
1356+
# Search for the key in the input text
1357+
if rsa_key_pattern.search(input_text):
1358+
# Remove the RSA private key
1359+
return rsa_key_pattern.sub("[RSA PRIVATE KEY REMOVED]", input_text)
1360+
return input_text
1361+
1362+
1363+
def scrub_proxy_url(proxy_url_str: str) -> str:
1364+
regex = re.compile(r"://.*?:.*?@")
1365+
# Replace matches with "://[REDACTED]:[REDACTED]@"
1366+
proxy_url_str = regex.sub("://[REDACTED]:[REDACTED]@", proxy_url_str)
1367+
return proxy_url_str
1368+
1369+
1370+
def redact_base64_strings(content: str) -> str:
1371+
base64_pattern = r"\b[A-Za-z0-9+/=]{40,}\b"
1372+
return re.sub(base64_pattern, "[REDACTED]", content)
1373+
1374+
1375+
def redact_sensitive_fields_from_string(input_text: str) -> str:
1376+
# Define regex patterns for keys
1377+
patterns = {
1378+
r"(username:\s*).*": r"\1[REDACTED]",
1379+
r"(password:\s*).*": r"\1[REDACTED]",
1380+
r"(token:\s*).*": r"\1[REDACTED]",
1381+
}
1382+
1383+
# Apply regex to redact sensitive fields
1384+
for pattern, replacement in patterns.items():
1385+
input_text = re.sub(pattern, replacement, input_text)
1386+
1387+
# Return the redacted text
1388+
return input_text
1389+
1390+
13311391
def get_release_namespace(
13321392
kube_config: str | None,
13331393
kube_context: str | None,
@@ -1542,18 +1602,6 @@ def az_cli(args_str: str) -> Any:
15421602
return True
15431603

15441604

1545-
# def is_cli_using_msal_auth():
1546-
# response_cli_version = az_cli("version --output json")
1547-
# try:
1548-
# cli_version = response_cli_version['azure-cli']
1549-
# except Exception as ex:
1550-
# raise CLIInternalError(f"Unable to decode the az cli version installed: {ex}")
1551-
# if version.parse(cli_version) >= version.parse(consts.AZ_CLI_ADAL_TO_MSAL_MIGRATE_VERSION):
1552-
# return True
1553-
# else:
1554-
# return False
1555-
1556-
15571605
def is_cli_using_msal_auth() -> bool:
15581606
response_cli_version = az_cli("version --output json")
15591607
try:
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# --------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)