diff --git a/src/connectedk8s/HISTORY.rst b/src/connectedk8s/HISTORY.rst index 4bc923d4045..d9a5cacf9ac 100644 --- a/src/connectedk8s/HISTORY.rst +++ b/src/connectedk8s/HISTORY.rst @@ -2,6 +2,10 @@ Release History =============== +1.6.0 +++++++ + +* Updated Helm from 3.6.3 to 3.12.2 1.5.6 ++++++ diff --git a/src/connectedk8s/azext_connectedk8s/_constants.py b/src/connectedk8s/azext_connectedk8s/_constants.py index 62ed0fdca41..586704576d4 100644 --- a/src/connectedk8s/azext_connectedk8s/_constants.py +++ b/src/connectedk8s/azext_connectedk8s/_constants.py @@ -163,6 +163,7 @@ Kubectl_Cluster_Info_Failed_Fault_Type = "Error while doing kubectl cluster-info" Fetch_Kubectl_Cluster_Info_Fault_Type = "Error occured while fetching cluster-info" Fetch_Kubectl_Cluster_Info = "kubectl_cluster_info" +Operation_Not_Supported_Fault_Type = "This CLI version does not support this operation for Agents older than v1.14" Failed_To_Change_Telemetry_Push_Interval = "Failed to change the telemetry push interval to 1 hr" Diagnostic_Check_Passed = "Passed" Diagnostic_Check_Failed = "Failed" @@ -232,5 +233,5 @@ CSP_Storage_Url_Mooncake = "https://k8sconnectcsp.blob.core.chinacloudapi.cn" CSP_Storage_Url_Fairfax = "https://k8sconnectcsp.azureedge.us" HELM_STORAGE_URL = "https://k8connecthelm.azureedge.net" -HELM_VERSION = 'v3.6.3' +HELM_VERSION = 'v3.12.2' Download_And_Install_Kubectl_Fault_Type = "Failed to download and install kubectl" diff --git a/src/connectedk8s/azext_connectedk8s/_precheckutils.py b/src/connectedk8s/azext_connectedk8s/_precheckutils.py index 689c5810e13..a90a6199dcb 100644 --- a/src/connectedk8s/azext_connectedk8s/_precheckutils.py +++ b/src/connectedk8s/azext_connectedk8s/_precheckutils.py @@ -136,7 +136,7 @@ def executing_cluster_diagnostic_checks_job(corev1_api_instance, batchv1_api_ins telemetry.set_exception(exception=error_kubectl_delete_helm.decode("ascii"), fault_type=consts.Cluster_Diagnostic_Checks_Release_Cleanup_Failed, summary="Error while executing cluster diagnostic checks Job") return - chart_path = azext_utils.get_chart_path(consts.Cluster_Diagnostic_Checks_Job_Registry_Path, kube_config, kube_context, helm_client_location, consts.Pre_Onboarding_Helm_Charts_Folder_Name, consts.Pre_Onboarding_Helm_Charts_Release_Name) + chart_path = azext_utils.get_chart_path(consts.Cluster_Diagnostic_Checks_Job_Registry_Path, kube_config, kube_context, helm_client_location, consts.Pre_Onboarding_Helm_Charts_Folder_Name, consts.Pre_Onboarding_Helm_Charts_Release_Name, False) helm_install_release_cluster_diagnostic_checks(chart_path, location, http_proxy, https_proxy, no_proxy, proxy_cert, azure_cloud, kube_config, kube_context, helm_client_location) diff --git a/src/connectedk8s/azext_connectedk8s/_utils.py b/src/connectedk8s/azext_connectedk8s/_utils.py index c2a29be5e24..97106cb772b 100644 --- a/src/connectedk8s/azext_connectedk8s/_utils.py +++ b/src/connectedk8s/azext_connectedk8s/_utils.py @@ -6,10 +6,10 @@ import sys import os import shutil +from packaging import version import subprocess from subprocess import Popen, PIPE import time -import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry import json @@ -92,12 +92,8 @@ def validate_custom_token(cmd, resource_group_name, location): return False, location -def get_chart_path(registry_path, kube_config, kube_context, helm_client_location, chart_folder_name='AzureArcCharts', chart_name='azure-arc-k8sagents'): - # Pulling helm chart from registry - os.environ['HELM_EXPERIMENTAL_OCI'] = '1' - pull_helm_chart(registry_path, kube_config, kube_context, helm_client_location, chart_name) - - # Exporting helm chart after cleanup +def get_chart_path(registry_path, kube_config, kube_context, helm_client_location, chart_folder_name='AzureArcCharts', chart_name='azure-arc-k8sagents', new_path=True): + # Exporting Helm chart chart_export_path = os.path.join(os.path.expanduser('~'), '.azure', chart_folder_name) try: if os.path.isdir(chart_export_path): @@ -105,7 +101,7 @@ def get_chart_path(registry_path, kube_config, kube_context, helm_client_locatio except: logger.warning("Unable to cleanup the {} already present on the machine. In case of failure, please cleanup the directory '{}' and try again.".format(chart_folder_name, chart_export_path)) - export_helm_chart(registry_path, chart_export_path, kube_config, kube_context, helm_client_location, chart_name) + pull_helm_chart(registry_path, chart_export_path, kube_config, kube_context, helm_client_location, new_path, chart_name) # Returning helm chart path helm_chart_path = os.path.join(chart_export_path, chart_name) @@ -117,8 +113,21 @@ def get_chart_path(registry_path, kube_config, kube_context, helm_client_locatio return chart_path -def pull_helm_chart(registry_path, kube_config, kube_context, helm_client_location, chart_name='azure-arc-k8sagents', retry_count=5, retry_delay=3): - cmd_helm_chart_pull = [helm_client_location, "chart", "pull", registry_path] +def pull_helm_chart(registry_path, chart_export_path, kube_config, kube_context, helm_client_location, new_path, chart_name='azure-arc-k8sagents', retry_count=5, retry_delay=3): + chart_url = registry_path.split(':')[0] + chart_version = registry_path.split(':')[1] + + if new_path: + if (version.parse(chart_version) < version.parse("1.14.0")): + error_summary = "This CLI version does not support upgrading to Agents versions older than v1.14" + telemetry.set_exception(exception='Operation not supported on older Agents', fault_type=consts.Operation_Not_Supported_Fault_Type, summary=error_summary) + raise ClientRequestError(error_summary, recommendation="Please select an agent-version >= v1.14 to upgrade to using 'az connectedk8s upgrade -g -n --agent-version '.") + + base_path = os.path.dirname(chart_url) + image_name = os.path.basename(chart_url) + chart_url = base_path + '/v2/' + image_name + + cmd_helm_chart_pull = [helm_client_location, "pull", "oci://" + chart_url, "--untar", "--untardir", chart_export_path, "--version", chart_version] if kube_config: cmd_helm_chart_pull.extend(["--kubeconfig", kube_config]) if kube_context: @@ -136,20 +145,6 @@ def pull_helm_chart(registry_path, kube_config, kube_context, helm_client_locati break -def export_helm_chart(registry_path, chart_export_path, kube_config, kube_context, helm_client_location, chart_name='azure-arc-k8sagents'): - cmd_helm_chart_export = [helm_client_location, "chart", "export", registry_path, "--destination", chart_export_path] - if kube_config: - cmd_helm_chart_export.extend(["--kubeconfig", kube_config]) - if kube_context: - cmd_helm_chart_export.extend(["--kube-context", kube_context]) - response_helm_chart_export = subprocess.Popen(cmd_helm_chart_export, stdout=PIPE, stderr=PIPE) - _, error_helm_chart_export = response_helm_chart_export.communicate() - if response_helm_chart_export.returncode != 0: - telemetry.set_exception(exception=error_helm_chart_export.decode("ascii"), fault_type=consts.Export_HelmChart_Fault_Type, - summary='Unable to export {} helm chart from the registry'.format(chart_name)) - raise CLIInternalError("Unable to export {} helm chart from the registry '{}': ".format(chart_name, registry_path) + error_helm_chart_export.decode("ascii")) - - def save_cluster_diagnostic_checks_pod_description(corev1_api_instance, batchv1_api_instance, helm_client_location, kubectl_client_location, kube_config, kube_context, filepath_with_timestamp, storage_space_available): try: job_name = "cluster-diagnostic-checks-job" diff --git a/src/connectedk8s/azext_connectedk8s/custom.py b/src/connectedk8s/azext_connectedk8s/custom.py index 6637e538762..e9c6c796a07 100644 --- a/src/connectedk8s/azext_connectedk8s/custom.py +++ b/src/connectedk8s/azext_connectedk8s/custom.py @@ -11,6 +11,7 @@ import json import tempfile import time +from packaging import version import subprocess from subprocess import Popen, PIPE, run, STDOUT, call, DEVNULL from base64 import b64encode, b64decode @@ -498,14 +499,17 @@ def install_helm_client(): telemetry.add_extension_event('connectedk8s', {'Context.Default.AzureCLI.MachineType': machine_type}) # Set helm binary download & install locations + # TODO: [Kit] Move helm binaries to internal endpoints if(operating_system == 'windows'): download_location_string = f'.azure\\helm\\{consts.HELM_VERSION}\\helm-{consts.HELM_VERSION}-{operating_system}-amd64.zip' install_location_string = f'.azure\\helm\\{consts.HELM_VERSION}\\{operating_system}-amd64\\helm.exe' - requestUri = f'{consts.HELM_STORAGE_URL}/helm/helm-{consts.HELM_VERSION}-{operating_system}-amd64.zip' + # requestUri = f'{consts.HELM_STORAGE_URL}/helm/helm-{consts.HELM_VERSION}-{operating_system}-amd64.zip' + requestUri = f'https://get.helm.sh/helm-{consts.HELM_VERSION}-{operating_system}-amd64.zip' elif(operating_system == 'linux' or operating_system == 'darwin'): download_location_string = f'.azure/helm/{consts.HELM_VERSION}/helm-{consts.HELM_VERSION}-{operating_system}-amd64.tar.gz' install_location_string = f'.azure/helm/{consts.HELM_VERSION}/{operating_system}-amd64/helm' - requestUri = f'{consts.HELM_STORAGE_URL}/helm/helm-{consts.HELM_VERSION}-{operating_system}-amd64.tar.gz' + # requestUri = f'{consts.HELM_STORAGE_URL}/helm/helm-{consts.HELM_VERSION}-{operating_system}-amd64.tar.gz' + requestUri = f'https://get.helm.sh/helm-{consts.HELM_VERSION}-{operating_system}-amd64.tar.gz' else: telemetry.set_exception(exception='Unsupported OS for installing helm client', fault_type=consts.Helm_Unsupported_OS_Fault_Type, summary=f'{operating_system} is not supported for installing helm client') @@ -1073,6 +1077,8 @@ def update_connected_cluster(cmd, client, resource_group_name, cluster_name, htt agent_version = connected_cluster.agent_version registry_path = reg_path_array[0] + ":" + agent_version + check_operation_support("update (properties)", agent_version) + telemetry.add_extension_event('connectedk8s', {'Context.Default.AzureCLI.AgentVersion': agent_version}) # Get Helm chart path @@ -1168,7 +1174,7 @@ def upgrade_agents(cmd, client, resource_group_name, cluster_name, kube_config=N # Install helm client helm_client_location = install_helm_client() - # Check Release Existance + # Check Release Existence release_namespace = utils.get_release_namespace(kube_config, kube_context, helm_client_location) if release_namespace: # Loading config map @@ -1467,6 +1473,8 @@ def enable_features(cmd, client, resource_group_name, cluster_name, features, ku agent_version = connected_cluster.agent_version registry_path = reg_path_array[0] + ":" + agent_version + check_operation_support("enable-features", agent_version) + telemetry.add_extension_event('connectedk8s', {'Context.Default.AzureCLI.AgentVersion': agent_version}) # Get Helm chart path @@ -1596,6 +1604,8 @@ def get_chart_and_disable_features(cmd, connected_cluster, kube_config, kube_con agent_version = connected_cluster.agent_version registry_path = reg_path_array[0] + ":" + agent_version + check_operation_support("disable-features", agent_version) + telemetry.add_extension_event('connectedk8s', {'Context.Default.AzureCLI.AgentVersion': agent_version}) # Get Helm chart path @@ -2466,3 +2476,10 @@ def crd_cleanup_force_delete(kubectl_client_location, kube_config, kube_context) patch_cmd.extend(["--context", kube_context]) output_patch_cmd = Popen(patch_cmd, stdout=PIPE, stderr=PIPE) _, error_helm_delete = output_patch_cmd.communicate() + + +def check_operation_support(operation_name, agent_version): + error_summary = 'This CLI version does not support {} for Agents older than v1.14'.format(operation_name) + if (version.parse(agent_version) < version.parse("1.14.0")): + telemetry.set_exception(exception='Operation not supported on older Agents', fault_type=consts.Operation_Not_Supported_Fault_Type, summary=error_summary) + raise ClientRequestError(error_summary, recommendation="Please upgrade to the latest version of the Agents using 'az connectedk8s upgrade -g -n '.") diff --git a/src/connectedk8s/azext_connectedk8s/tests/latest/test_connectedk8s_scenario.py b/src/connectedk8s/azext_connectedk8s/tests/latest/test_connectedk8s_scenario.py index 4cd16f7f77f..69fde71f044 100644 --- a/src/connectedk8s/azext_connectedk8s/tests/latest/test_connectedk8s_scenario.py +++ b/src/connectedk8s/azext_connectedk8s/tests/latest/test_connectedk8s_scenario.py @@ -150,6 +150,8 @@ class Connectedk8sScenarioTest(LiveScenarioTest): @live_only() @ResourceGroupPreparer(name_prefix='conk8stest', location=CONFIG['location'], random_name_length=16) def test_connect(self,resource_group): + # os.environ.setdefault('HELMREGISTRY', 'mcr.microsoft.com/azurearck8s/batch1/preview/azure-arc-k8sagents:1.1.59-preview') + managed_cluster_name = self.create_random_name(prefix='test-connect', length=24) kubeconfig="%s" % (_get_test_data_file(managed_cluster_name + '-config.yaml')) self.kwargs.update({ @@ -178,7 +180,6 @@ def test_connect(self,resource_group): @live_only() @ResourceGroupPreparer(name_prefix='conk8stest', location=CONFIG['location'], random_name_length=16) def test_forcedelete(self,resource_group): - managed_cluster_name = self.create_random_name(prefix='test-force-delete', length=24) kubeconfig="%s" % (_get_test_data_file(managed_cluster_name + '-config.yaml')) self.kwargs.update({ @@ -218,6 +219,7 @@ def test_forcedelete(self,resource_group): @live_only() @ResourceGroupPreparer(name_prefix='conk8stest', location=CONFIG['location'], random_name_length=16) def test_enable_disable_features(self,resource_group): + # os.environ.setdefault('HELMREGISTRY', 'mcr.microsoft.com/azurearck8s/batch1/preview/azure-arc-k8sagents:1.1.59-preview') managed_cluster_name = self.create_random_name(prefix='test-enable-disable', length=24) kubeconfig="%s" % (_get_test_data_file(managed_cluster_name + '-config.yaml')) @@ -319,7 +321,6 @@ def test_enable_disable_features(self,resource_group): @live_only() @ResourceGroupPreparer(name_prefix='conk8stest', location=CONFIG['location'], random_name_length=16) def test_connectedk8s_list(self,resource_group): - managed_cluster_name = self.create_random_name(prefix='first', length=24) managed_cluster_name_second = self.create_random_name(prefix='second', length=24) kubeconfig="%s" % (_get_test_data_file(managed_cluster_name + '-config.yaml')) @@ -393,6 +394,7 @@ def test_connectedk8s_list(self,resource_group): @live_only() @ResourceGroupPreparer(name_prefix='conk8stest', location=CONFIG['location'], random_name_length=16) def test_upgrade(self,resource_group): + # os.environ.setdefault('HELMREGISTRY', 'mcr.microsoft.com/azurearck8s/batch1/preview/azure-arc-k8sagents:1.1.59-preview') managed_cluster_name = self.create_random_name(prefix='test-upgrade', length=24) kubeconfig="%s" % (_get_test_data_file(managed_cluster_name + '-config.yaml')) @@ -459,6 +461,8 @@ def test_upgrade(self,resource_group): @live_only() @ResourceGroupPreparer(name_prefix='conk8stest', location=CONFIG['location'], random_name_length=16) def test_update(self,resource_group): + # os.environ.setdefault('HELMREGISTRY', 'mcr.microsoft.com/azurearck8s/batch1/preview/azure-arc-k8sagents:1.1.59-preview') + managed_cluster_name = self.create_random_name(prefix='test-update', length=24) kubeconfig="%s" % (_get_test_data_file(managed_cluster_name + '-config.yaml')) self.kwargs.update({ diff --git a/src/connectedk8s/setup.py b/src/connectedk8s/setup.py index 41ccef94fcc..ee4658251ff 100644 --- a/src/connectedk8s/setup.py +++ b/src/connectedk8s/setup.py @@ -17,7 +17,7 @@ # TODO: Confirm this is the right version number you want and it matches your # HISTORY.rst entry. -VERSION = '1.5.6' +VERSION = '1.6.0' # The full list of classifiers is available at # https://pypi.python.org/pypi?%3Aaction=list_classifiers