From 2346f9f6d6ad99c3ebb802b6a7055146b81387ab Mon Sep 17 00:00:00 2001 From: Daniel Osypenko Date: Sun, 20 Oct 2024 18:43:03 +0300 Subject: [PATCH 1/5] add ocp install log, delete cluster Signed-off-by: Daniel Osypenko --- ocs_ci/deployment/assisted_installer.py | 17 +--- ocs_ci/deployment/rosa.py | 21 +++- ocs_ci/ocs/constants.py | 3 + ocs_ci/utility/deployment.py | 28 ++++++ ocs_ci/utility/rosa.py | 124 ++++++++++++++++++++---- 5 files changed, 155 insertions(+), 38 deletions(-) diff --git a/ocs_ci/deployment/assisted_installer.py b/ocs_ci/deployment/assisted_installer.py index 2e8a52c0e03..b41b0819197 100644 --- a/ocs_ci/deployment/assisted_installer.py +++ b/ocs_ci/deployment/assisted_installer.py @@ -4,7 +4,6 @@ """ from copy import deepcopy -from datetime import datetime import json import logging import os @@ -15,6 +14,7 @@ SameNameClusterAlreadyExistsException, ) from ocs_ci.utility import assisted_installer as ai +from ocs_ci.utility.deployment import create_openshift_install_log_file from ocs_ci.utility.utils import download_file, TimeoutSampler from ocs_ci.utility.retry import retry @@ -435,21 +435,8 @@ def create_openshift_install_log_file(self): Create .openshift_install.log file containing URL to OpenShift console. It is used by our CI jobs to show the console URL in build description. """ - # Create metadata file to store the cluster name - installer_log_file = os.path.join(self.cluster_path, ".openshift_install.log") - formatted_time = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") cluster_address = self.api.get_cluster_admin_credentials(self.id)["console_url"] - logger.info(f"Cluster URL: {cluster_address}") - with open(installer_log_file, "a") as fd: - fd.writelines( - [ - "W/A for our CI to get URL to the cluster in jenkins job. " - "Cluster is deployed via Assisted Installer API!\n" - f'time="{formatted_time}" level=info msg="Access the OpenShift web-console here: ' - f"{cluster_address}\"\n'", - ] - ) - logger.info("Created .openshift_install.log file") + create_openshift_install_log_file(self.cluster_path, cluster_address) def create_kubeconfig_file(self): """ diff --git a/ocs_ci/deployment/rosa.py b/ocs_ci/deployment/rosa.py index 0075ec9ebb1..d1b03d24114 100644 --- a/ocs_ci/deployment/rosa.py +++ b/ocs_ci/deployment/rosa.py @@ -18,7 +18,13 @@ from ocs_ci.framework import config from ocs_ci.ocs.resources.pod import get_operator_pods from ocs_ci.utility import openshift_dedicated as ocm, rosa -from ocs_ci.utility.aws import AWS as AWSUtil +from ocs_ci.utility.aws import AWS as AWSUtil, delete_sts_iam_roles +from ocs_ci.utility.deployment import create_openshift_install_log_file +from ocs_ci.utility.rosa import ( + get_console_url, + get_associated_oidc_config_id, + delete_account_roles, +) from ocs_ci.utility.utils import ( ceph_health_check, get_ocp_version, @@ -95,8 +101,9 @@ def deploy(self, log_level=""): logger.info("generate kubeconfig and kubeadmin-password files") if config.ENV_DATA["ms_env_type"] == "staging": + cluster_path = config.ENV_DATA["cluster_path"] kubeconfig_path = os.path.join( - config.ENV_DATA["cluster_path"], config.RUN["kubeconfig_location"] + cluster_path, config.RUN["kubeconfig_location"] ) ocm.get_kubeconfig(self.cluster_name, kubeconfig_path) # this default admin password from secret doesn't work for ROSA HCP staging in the management-console @@ -104,6 +111,8 @@ def deploy(self, log_level=""): rosa_stage_cluster = ROSAStageEnvCluster(self.cluster_name) rosa_stage_cluster.create_admin_and_login() rosa_stage_cluster.generate_kubeadmin_password_file() + console_url = get_console_url(self.cluster_name) + create_openshift_install_log_file(cluster_path, console_url) if config.ENV_DATA["ms_env_type"] == "production": if config.ENV_DATA.get("appliance_mode"): logger.info( @@ -128,6 +137,7 @@ def destroy(self, log_level="DEBUG"): """ try: + rosa_hcp = config.ENV_DATA.get("platform") == constants.ROSA_HCP_PLATFORM cluster_details = ocm.get_cluster_details(self.cluster_name) cluster_id = cluster_details.get("id") delete_status = rosa.destroy_appliance_mode_cluster(self.cluster_name) @@ -145,7 +155,14 @@ def destroy(self, log_level="DEBUG"): logger.error(err_msg) raise TimeoutExpiredError(err_msg) rosa.delete_operator_roles(cluster_id) + if rosa_hcp: + oidc_config_id = get_associated_oidc_config_id(cluster_id) + if oidc_config_id: + rosa.delete_oidc_config(oidc_config_id) + # use sts IAM roles for ROSA HCP is mandatory + delete_sts_iam_roles() rosa.delete_oidc_provider(cluster_id) + delete_account_roles(constants.ACCOUNT_ROLE_PREFIX_ROSA_HCP) except CommandFailed as err: if "There are no subscriptions or clusters with identifier or name" in str( err diff --git a/ocs_ci/ocs/constants.py b/ocs_ci/ocs/constants.py index c9a80db0a9d..d4902e58daa 100644 --- a/ocs_ci/ocs/constants.py +++ b/ocs_ci/ocs/constants.py @@ -2291,6 +2291,9 @@ # aws tags AWS_CLOUDFORMATION_TAG = "aws:cloudformation:stack-name" +# aws prefixes +ACCOUNT_ROLE_PREFIX_ROSA_HCP = "accroleshcp" + # aws volume constants AWS_VOL_PVC_NAME_TAG = "kubernetes.io/created-for/pvc/name" AWS_VOL_PV_NAME_TAG = "kubernetes.io/created-for/pv/name" diff --git a/ocs_ci/utility/deployment.py b/ocs_ci/utility/deployment.py index 67bc5500dbd..d01d5373244 100644 --- a/ocs_ci/utility/deployment.py +++ b/ocs_ci/utility/deployment.py @@ -6,6 +6,8 @@ import os import re import tempfile +from datetime import datetime + import yaml import requests @@ -228,3 +230,29 @@ def workaround_mark_disks_as_ssd(): logger.info("Workaround already applied.") else: raise err + + +def create_openshift_install_log_file(cluster_path, console_url): + """ + Workaround. + Create .openshift_install.log file containing URL to OpenShift console. + It is used by our CI jobs to show the console URL in build description. + + Args: + cluster_path (str): The path to the cluster directory. + console_url (str): The address of the OpenShift cluster management-console + """ + installer_log_file = os.path.join(cluster_path, ".openshift_install.log") + formatted_time = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") + + logger.info(f"Cluster URL: {console_url}") + with open(installer_log_file, "a") as fd: + fd.writelines( + [ + "W/A for our CI to get URL to the cluster in jenkins job. " + "Cluster is deployed via Assisted Installer API!\n" + f'time="{formatted_time}" level=info msg="Access the OpenShift web-console here: ' + f"{console_url}\"\n'", + ] + ) + logger.info("Created '.openshift_install.log' file") diff --git a/ocs_ci/utility/rosa.py b/ocs_ci/utility/rosa.py index e31e93eff4c..c986cbc72cb 100644 --- a/ocs_ci/utility/rosa.py +++ b/ocs_ci/utility/rosa.py @@ -78,7 +78,7 @@ def create_cluster(cluster_name, version, region): logger.info(f"Using OCP version {rosa_ocp_version}") if rosa_hcp: - account_roles_prefix = f"accroleshcp-{date_in_minimal_format}{random_letters}" + account_roles_prefix = constants.ACCOUNT_ROLE_PREFIX_ROSA_HCP else: account_roles_prefix = "ManagedOpenShift" log_step("Creating account roles") @@ -584,9 +584,11 @@ def create_oidc_config(): TimeoutExpiredError: If OIDC config is not created in time """ cmd = "rosa create oidc-config --managed --mode=auto --yes" - proc = utils.exec_cmd(cmd, timeout=1200) + proc = exec_cmd(cmd, timeout=1200) if proc.returncode != 0: - raise CommandFailed(f"Failed to create oidc config: {proc.stderr}") + raise CommandFailed( + f"Failed to create oidc config: {proc.stderr.decode().strip()}" + ) for sample in TimeoutSampler( timeout=300, @@ -594,9 +596,9 @@ def create_oidc_config(): func=get_oidc_config_ids, latest=True, ): - if len(sample) and sample[0] in proc.stdout: + if len(sample) and sample[0] in proc.stdout.decode().strip(): logger.info("OIDC config created successfully") - return sample[0].strip().decode() + return sample[0] def get_oidc_endpoint_url(oidc_config_id): @@ -610,10 +612,12 @@ def get_oidc_endpoint_url(oidc_config_id): str: OIDC provider id """ cmd = f"rosa list oidc-config -o json | jq -r '.[] | select(.id == \"{oidc_config_id}\") | .issuer_url'" - cmd_res = exec_cmd(cmd, shell=True) - if cmd_res.returncode != 0: - raise CommandFailed(f"Failed to get oidc provider id: {cmd_res.stderr}") - issuer_url = cmd_res.stdout.strip().decode() + proc = exec_cmd(cmd, shell=True) + if proc.returncode != 0: + raise CommandFailed( + f"Failed to get oidc provider id: {proc.stderr.decode().strip()}" + ) + issuer_url = proc.stdout.decode().strip() logger.info(f"OIDC issuer url: {issuer_url}") return issuer_url @@ -648,11 +652,14 @@ def delete_oidc_config(oidc_config_id): def get_latest_oidc_config_id(): cmd = "rosa list oidc-config -o json | jq -r 'max_by(.creation_timestamp) | .id'" - cmd_res = exec_cmd(cmd, shell=True) - if cmd_res.returncode != 0: - raise CommandFailed(f"Failed to get latest oidc config id: {cmd_res.stderr}") - logger.info(f"Latest OIDC config id: {cmd_res.stdout}") - return cmd_res.stdout.strip() + proc = exec_cmd(cmd, shell=True) + if proc.returncode != 0: + raise CommandFailed( + f"Failed to get latest oidc config id: {proc.stderr.decode().strip()}" + ) + oidc_config_latest = proc.stdout.decode().strip() + logger.info(f"Latest OIDC config id: {oidc_config_latest}") + return oidc_config_latest def get_oidc_config_ids(latest=False): @@ -674,12 +681,15 @@ def get_oidc_config_ids(latest=False): "rosa list oidc-config -o json | jq -r 'map(select(has(\"id\"))) | .[].id'" ) - cmd_res = exec_cmd(cmd, shell=True) - if cmd_res.returncode != 0: - raise CommandFailed(f"Failed to get OIDC config ids: {cmd_res.stderr}") + proc = exec_cmd(cmd, shell=True) + if proc.returncode != 0: + raise CommandFailed( + f"Failed to get OIDC config ids: {proc.stderr.decode().strip()}" + ) - logger.info(f"OIDC config id(s), latest='{latest}': {cmd_res.stdout}") - return cmd_res.stdout.strip().splitlines() + oidc_configs = proc.stdout.decode().strip() + logger.info(f"OIDC config id(s), latest='{latest}': {oidc_configs}") + return oidc_configs.splitlines() def download_rosa_cli(): @@ -834,7 +844,29 @@ def delete_operator_roles(cluster_id): cluster_id (str): the id of the cluster """ cmd = f"rosa delete operator-roles -c {cluster_id} --mode auto --yes" - utils.run_cmd(cmd, timeout=1200) + proc = exec_cmd(cmd, timeout=1200) + if proc.returncode != 0: + raise CommandFailed( + f"Failed to delete operator roles: {proc.stderr.decode().strip()}" + ) + logger.info(f"{proc.stdout.decode().strip()}") + + +def delete_account_roles(prefix): + """ + Delete account roles + + Args: + prefix (str): role prefix + + """ + cmd = f"rosa delete account-roles -p {prefix} --mode auto --yes" + proc = exec_cmd(cmd, timeout=1200) + if proc.returncode != 0: + raise CommandFailed( + f"Failed to delete account roles: {proc.stderr.decode().strip()}" + ) + logger.info(f"{proc.stdout.decode().strip()}") def get_rosa_cluster_service_id(cluster): @@ -928,7 +960,12 @@ def delete_oidc_provider(cluster_id): cluster_id (str): the id of the cluster """ cmd = f"rosa delete oidc-provider -c {cluster_id} --mode auto --yes" - utils.run_cmd(cmd, timeout=1200) + proc = exec_cmd(cmd, timeout=1200) + if proc.returncode != 0: + raise CommandFailed( + f"Failed to delete oidc provider: {proc.stderr.decode().strip()}" + ) + logger.info(f"{proc.stdout.decode().strip()}") def is_odf_addon_installed(cluster_name=None): @@ -1061,3 +1098,48 @@ def edit_addon_installation( utils.run_cmd(cmd) if wait: wait_for_addon_to_be_ready(cluster_name, addon_name) + + +def get_console_url(cluster_name): + """ + Get the console URL of the given cluster + + Args: + cluster_name (str): The cluster name + + Returns: + str: The console URL + + """ + cmd = ( + f"rosa describe cluster --cluster {cluster_name} -o json | jq -r '.console.url'" + ) + proc = exec_cmd(cmd, shell=True) + if proc.returncode != 0: + raise CommandFailed( + f"Failed to get console URL: {proc.stderr.decode().strip()}" + ) + return proc.stdout.decode().strip() + + +def get_associated_oidc_config_id(cluster_name): + """ + Get the associated OIDC config id of the given cluster + + Args: + cluster_name (str): The cluster name + + Returns: + str: The OIDC config id + + """ + cmd = ( + f"rosa describe cluster --cluster {cluster_name} -o json " + "| jq -r '.aws.sts.oidc_endpoint_url? " + '| split("/") | .[-1] // ""\'' + ) + proc = exec_cmd(cmd, shell=True) + if proc.returncode != 0: + logger.warning(f"Failed to get OIDC config id: {proc.stderr.decode().strip()}") + return "" + return proc.stdout.decode().strip() From 7c9977c102882fb25efb2deb66b03c0eb29d91d6 Mon Sep 17 00:00:00 2001 From: Daniel Osypenko Date: Mon, 21 Oct 2024 12:21:26 +0300 Subject: [PATCH 2/5] add username file for rosa, for jenkins console Signed-off-by: Daniel Osypenko --- ocs_ci/deployment/helpers/rosa_cluster_helpers.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ocs_ci/deployment/helpers/rosa_cluster_helpers.py b/ocs_ci/deployment/helpers/rosa_cluster_helpers.py index 16b7bbf4069..fa4462ad1ea 100644 --- a/ocs_ci/deployment/helpers/rosa_cluster_helpers.py +++ b/ocs_ci/deployment/helpers/rosa_cluster_helpers.py @@ -38,6 +38,7 @@ def __init__(self, cluster, env_prefix): self.kubeadmin_password_path = os.path.join( config.ENV_DATA["cluster_path"], config.RUN["password_location"] ) + self.username_path = os.path.join(config.ENV_DATA["cluster_path"], "auth") # Create "auth" folder if it doesn't exist. abs_path = os.path.expanduser(self.kubeconfig_path) @@ -130,6 +131,16 @@ def create_admin_and_login(self): logger.info("It may take up to a minute for the account to become active") time.sleep(10) self.wait_for_cluster_admin_login_successful() + self.create_username_file() + + def create_username_file(self): + """ + Creates a file with the username for the cluster. + + """ + + with open(self.username_path, "w+") as fd: + fd.write(config.ENV_DATA[self.username_key]) def get_admin_password(self): """ From 7f262fda67549f0ec83a02bfc6139d985bcfbd50 Mon Sep 17 00:00:00 2001 From: Daniel Osypenko Date: Mon, 21 Oct 2024 14:16:10 +0300 Subject: [PATCH 3/5] delete resources. old issues with clsuter_id were fixed Signed-off-by: Daniel Osypenko --- .../helpers/rosa_cluster_helpers.py | 4 +- ocs_ci/deployment/rosa.py | 26 +++++++--- ocs_ci/ocs/constants.py | 1 + ocs_ci/utility/rosa.py | 47 +++++++++++++------ 4 files changed, 55 insertions(+), 23 deletions(-) diff --git a/ocs_ci/deployment/helpers/rosa_cluster_helpers.py b/ocs_ci/deployment/helpers/rosa_cluster_helpers.py index fa4462ad1ea..78de303f712 100644 --- a/ocs_ci/deployment/helpers/rosa_cluster_helpers.py +++ b/ocs_ci/deployment/helpers/rosa_cluster_helpers.py @@ -38,7 +38,9 @@ def __init__(self, cluster, env_prefix): self.kubeadmin_password_path = os.path.join( config.ENV_DATA["cluster_path"], config.RUN["password_location"] ) - self.username_path = os.path.join(config.ENV_DATA["cluster_path"], "auth") + self.username_path = os.path.join( + config.ENV_DATA["cluster_path"], "auth", "admin-user" + ) # Create "auth" folder if it doesn't exist. abs_path = os.path.expanduser(self.kubeconfig_path) diff --git a/ocs_ci/deployment/rosa.py b/ocs_ci/deployment/rosa.py index d1b03d24114..b65aecf41e0 100644 --- a/ocs_ci/deployment/rosa.py +++ b/ocs_ci/deployment/rosa.py @@ -16,6 +16,7 @@ ) from ocs_ci.deployment.ocp import OCPDeployment as BaseOCPDeployment from ocs_ci.framework import config +from ocs_ci.framework.logger_helper import log_step from ocs_ci.ocs.resources.pod import get_operator_pods from ocs_ci.utility import openshift_dedicated as ocm, rosa from ocs_ci.utility.aws import AWS as AWSUtil, delete_sts_iam_roles @@ -138,12 +139,14 @@ def destroy(self, log_level="DEBUG"): """ try: rosa_hcp = config.ENV_DATA.get("platform") == constants.ROSA_HCP_PLATFORM - cluster_details = ocm.get_cluster_details(self.cluster_name) - cluster_id = cluster_details.get("id") + oidc_config_id = ( + get_associated_oidc_config_id(self.cluster_name) if rosa_hcp else None + ) + log_step(f"Destroying ROSA cluster. Hosted CP: {rosa_hcp}") delete_status = rosa.destroy_appliance_mode_cluster(self.cluster_name) if not delete_status: ocm.destroy_cluster(self.cluster_name) - logger.info("Waiting for ROSA cluster to be uninstalled") + log_step("Waiting for ROSA cluster to be uninstalled") sample = TimeoutSampler( timeout=14400, sleep=300, @@ -154,15 +157,24 @@ def destroy(self, log_level="DEBUG"): err_msg = f"Failed to delete {self.cluster_name}" logger.error(err_msg) raise TimeoutExpiredError(err_msg) - rosa.delete_operator_roles(cluster_id) + log_step("Deleting ROSA/aws associated resources") + oproles_prefix = ( + f"{constants.OPERATOR_ROLE_PREFIX_ROSA_HCP}-{self.cluster_name}" + ) + rosa.delete_operator_roles(prefix=oproles_prefix) if rosa_hcp: - oidc_config_id = get_associated_oidc_config_id(cluster_id) if oidc_config_id: rosa.delete_oidc_config(oidc_config_id) # use sts IAM roles for ROSA HCP is mandatory delete_sts_iam_roles() - rosa.delete_oidc_provider(cluster_id) - delete_account_roles(constants.ACCOUNT_ROLE_PREFIX_ROSA_HCP) + rosa.delete_oidc_provider(self.cluster_name) + account_roles_prefix = ( + f"{constants.ACCOUNT_ROLE_PREFIX_ROSA_HCP}-{self.cluster_name}" + ) + delete_account_roles(account_roles_prefix) + logger.info( + f"Cluster {self.cluster_name} and associated resources deleted successfully" + ) except CommandFailed as err: if "There are no subscriptions or clusters with identifier or name" in str( err diff --git a/ocs_ci/ocs/constants.py b/ocs_ci/ocs/constants.py index d4902e58daa..58a6a8fb893 100644 --- a/ocs_ci/ocs/constants.py +++ b/ocs_ci/ocs/constants.py @@ -2293,6 +2293,7 @@ # aws prefixes ACCOUNT_ROLE_PREFIX_ROSA_HCP = "accroleshcp" +OPERATOR_ROLE_PREFIX_ROSA_HCP = "oproleshcp" # aws volume constants AWS_VOL_PVC_NAME_TAG = "kubernetes.io/created-for/pvc/name" diff --git a/ocs_ci/utility/rosa.py b/ocs_ci/utility/rosa.py index c986cbc72cb..3dceaff10f7 100644 --- a/ocs_ci/utility/rosa.py +++ b/ocs_ci/utility/rosa.py @@ -78,7 +78,9 @@ def create_cluster(cluster_name, version, region): logger.info(f"Using OCP version {rosa_ocp_version}") if rosa_hcp: - account_roles_prefix = constants.ACCOUNT_ROLE_PREFIX_ROSA_HCP + account_roles_prefix = ( + f"{constants.ACCOUNT_ROLE_PREFIX_ROSA_HCP}-{cluster_name}" + ) else: account_roles_prefix = "ManagedOpenShift" log_step("Creating account roles") @@ -151,7 +153,7 @@ def create_cluster(cluster_name, version, region): if rosa_hcp: # with rosa hcp we need operator roles to be created before cluster creation - prefix = f"oproles-{date_in_minimal_format}{random_letters}" + prefix = f"{constants.OPERATOR_ROLE_PREFIX_ROSA_HCP}-{cluster_name}" aws_account_id = aws.get_caller_identity() log_step("Creating operator roles and waiting them to be created") create_operator_roles( @@ -475,19 +477,29 @@ def validate_ocp_version(version): def create_account_roles(prefix="ManagedOpenShift"): """ - Create the required account-wide roles and policies, including Operator policies. + Create the necessary account-wide roles and policies, including operator-specific policies. + + **Important:** + - Each cluster should have a unique prefix for its account roles, rather than using a common prefix across the + entire account. + - If multiple clusters are deployed with the same role prefix, deleting account roles during the cluster + destruction stage could lead to: + - Loss of Red Hat (RH) support. + - Disruption of communication with worker nodes. + + Ensure that role prefixes are uniquely assigned per cluster to maintain cluster integrity and supportability. Args: prefix (str): role prefix """ - if config.ENV_DATA.get("platform") == constants.ROSA_HCP_PLATFORM: + if rosa_hcp: hosted_cp_param = "--hosted-cp" else: hosted_cp_param = "" cmd = f"rosa create account-roles {hosted_cp_param} --mode auto --prefix {prefix} --yes" - utils.run_cmd(cmd, timeout=1200) + exec_cmd(cmd, timeout=1200) def create_operator_roles( @@ -498,17 +510,21 @@ def create_operator_roles( relevant prefix for the cluster name Args: - cluster (str): cluster name or cluster id + cluster (str): cluster name prefix (str): role prefix oidc_config_id (str): OIDC config id aws_account_id (str): AWS account id account_roles_prefix (str): account roles prefix """ - + prefix = ( + f"{constants.OPERATOR_ROLE_PREFIX_ROSA_HCP}-{cluster}" + if prefix == "" + else prefix + ) cmd = f"rosa create operator-roles --cluster {cluster} --mode auto --yes" # command with prefix should look another way, to avoid error: # ERR: A cluster key for STS cluster and an operator roles prefix cannot be specified alongside each other - if prefix: + if rosa_hcp: cmd = ( "rosa create operator-roles " "--hosted-cp " @@ -836,14 +852,14 @@ def delete_odf_addon(cluster): ) -def delete_operator_roles(cluster_id): +def delete_operator_roles(prefix): """ - Delete operator roles of the given cluster + Delete operator roles with prefix Args: - cluster_id (str): the id of the cluster + prefix (str): prefix. Usually it is cluster name set during 'rosa create operator-roles' command """ - cmd = f"rosa delete operator-roles -c {cluster_id} --mode auto --yes" + cmd = f"rosa delete operator-roles --prefix {prefix} --mode auto --yes" proc = exec_cmd(cmd, timeout=1200) if proc.returncode != 0: raise CommandFailed( @@ -855,6 +871,7 @@ def delete_operator_roles(cluster_id): def delete_account_roles(prefix): """ Delete account roles + ! Important to not delete account roles if there are any clusters in the account using this prefix Args: prefix (str): role prefix @@ -952,14 +969,14 @@ def destroy_appliance_mode_cluster(cluster): return True -def delete_oidc_provider(cluster_id): +def delete_oidc_provider(cluster_name): """ Delete oidc provider of the given cluster Args: - cluster_id (str): the id of the cluster + cluster_name (str): the cluster name """ - cmd = f"rosa delete oidc-provider -c {cluster_id} --mode auto --yes" + cmd = f"rosa delete oidc-provider -c {cluster_name} --mode auto --yes" proc = exec_cmd(cmd, timeout=1200) if proc.returncode != 0: raise CommandFailed( From b86e840388cc62ac790cda54bb0bbc73badfe24f Mon Sep 17 00:00:00 2001 From: Daniel Osypenko Date: Mon, 21 Oct 2024 17:31:15 +0300 Subject: [PATCH 4/5] extended timeout to create clsuter Signed-off-by: Daniel Osypenko --- ocs_ci/deployment/rosa.py | 4 ++-- ocs_ci/utility/rosa.py | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/ocs_ci/deployment/rosa.py b/ocs_ci/deployment/rosa.py index b65aecf41e0..cbc1836af8b 100644 --- a/ocs_ci/deployment/rosa.py +++ b/ocs_ci/deployment/rosa.py @@ -22,9 +22,9 @@ from ocs_ci.utility.aws import AWS as AWSUtil, delete_sts_iam_roles from ocs_ci.utility.deployment import create_openshift_install_log_file from ocs_ci.utility.rosa import ( - get_console_url, get_associated_oidc_config_id, delete_account_roles, + wait_console_url, ) from ocs_ci.utility.utils import ( ceph_health_check, @@ -112,7 +112,7 @@ def deploy(self, log_level=""): rosa_stage_cluster = ROSAStageEnvCluster(self.cluster_name) rosa_stage_cluster.create_admin_and_login() rosa_stage_cluster.generate_kubeadmin_password_file() - console_url = get_console_url(self.cluster_name) + console_url = wait_console_url(self.cluster_name) create_openshift_install_log_file(cluster_path, console_url) if config.ENV_DATA["ms_env_type"] == "production": if config.ENV_DATA.get("appliance_mode"): diff --git a/ocs_ci/utility/rosa.py b/ocs_ci/utility/rosa.py index 3dceaff10f7..82a16dd1584 100644 --- a/ocs_ci/utility/rosa.py +++ b/ocs_ci/utility/rosa.py @@ -17,6 +17,7 @@ UnsupportedPlatformVersionError, ConfigurationError, ResourceWrongStatusException, + TimeoutExpiredError, ) from ocs_ci.utility import openshift_dedicated as ocm from ocs_ci.utility import utils @@ -27,6 +28,7 @@ generate_onboarding_token, get_storage_provider_endpoint, ) +from ocs_ci.utility.retry import catch_exceptions from ocs_ci.utility.utils import exec_cmd, TimeoutSampler logger = logging.getLogger(name=__file__) @@ -63,6 +65,7 @@ def create_cluster(cluster_name, version, region): region (str): Cluster region """ + create_timeout = 2400 aws = AWSUtil() rosa_ocp_version = config.DEPLOYMENT["installer_version"] # Validate ocp version with rosa ocp supported version @@ -167,7 +170,7 @@ def create_cluster(cluster_name, version, region): cmd += " --hosted-cp " log_step("Running create rosa cluster command") - utils.run_cmd(cmd, timeout=1200) + utils.run_cmd(cmd, timeout=create_timeout) if rosa_mode != "auto" and not rosa_hcp: logger.info( "Waiting for ROSA cluster status changed to waiting or pending state" @@ -484,8 +487,8 @@ def create_account_roles(prefix="ManagedOpenShift"): entire account. - If multiple clusters are deployed with the same role prefix, deleting account roles during the cluster destruction stage could lead to: - - Loss of Red Hat (RH) support. - - Disruption of communication with worker nodes. + - Loss of Red Hat (RH) support. + - Disruption of communication with worker nodes. Ensure that role prefixes are uniquely assigned per cluster to maintain cluster integrity and supportability. @@ -653,7 +656,7 @@ def delete_oidc_config(oidc_config_id): ) return - cmd = f"rosa delete oidc-config {oidc_config_id} --mode auto --yes" + cmd = f"rosa delete oidc-config --oidc-config-id {oidc_config_id} --mode auto --yes" utils.exec_cmd(cmd, timeout=1200) for sample in TimeoutSampler( timeout=300, @@ -1139,6 +1142,34 @@ def get_console_url(cluster_name): return proc.stdout.decode().strip() +@catch_exceptions((CommandFailed, TimeoutExpiredError)) +def wait_console_url(cluster_name, timeout=600, sleep=10): + """ + Wait for the console URL of the cluster to be ready + + Args: + cluster_name (str): The cluster name + timeout (int): Timeout to wait for the console URL to be ready + sleep (int): Time in seconds to sleep between attempts + + Returns: + str: The console URL + + Raises: + TimeoutExpiredError: In case the console URL is not ready in the given timeout + + """ + for console_url in TimeoutSampler( + timeout=timeout, + sleep=sleep, + func=get_console_url, + cluster_name=cluster_name, + ): + if console_url and "https" in console_url: + logger.info(f"Console URL: {console_url}") + return console_url + + def get_associated_oidc_config_id(cluster_name): """ Get the associated OIDC config id of the given cluster From 7872cb8d54014cb1be23eaed768434437d1ebd22 Mon Sep 17 00:00:00 2001 From: Daniel Osypenko Date: Wed, 23 Oct 2024 12:05:17 +0300 Subject: [PATCH 5/5] logmessage changed Signed-off-by: Daniel Osypenko --- ocs_ci/utility/deployment.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ocs_ci/utility/deployment.py b/ocs_ci/utility/deployment.py index d01d5373244..2b009be7407 100644 --- a/ocs_ci/utility/deployment.py +++ b/ocs_ci/utility/deployment.py @@ -250,7 +250,8 @@ def create_openshift_install_log_file(cluster_path, console_url): fd.writelines( [ "W/A for our CI to get URL to the cluster in jenkins job. " - "Cluster is deployed via Assisted Installer API!\n" + "Cluster is deployed via some kind of managed deployment (Assisted Installer API or ROSA). " + "OpenShift Installer (IPI or UPI deployment) were not used!\n" f'time="{formatted_time}" level=info msg="Access the OpenShift web-console here: ' f"{console_url}\"\n'", ]