diff --git a/conf/ocsci/submariner_downstream_unreleased.yaml b/conf/ocsci/submariner_downstream_unreleased.yaml new file mode 100644 index 000000000000..a26c53b153f3 --- /dev/null +++ b/conf/ocsci/submariner_downstream_unreleased.yaml @@ -0,0 +1,4 @@ +ENV_DATA: + submariner_source: "downstream" + submariner_release_type: "unreleased" + submariner_version: "0.16.0" diff --git a/ocs_ci/deployment/acm.py b/ocs_ci/deployment/acm.py index 3268842de612..b02b49aa0b71 100644 --- a/ocs_ci/deployment/acm.py +++ b/ocs_ci/deployment/acm.py @@ -16,6 +16,7 @@ CommandFailed, DRPrimaryNotFoundException, ) +from ocs_ci.utility import templating from ocs_ci.ocs.utils import get_non_acm_cluster_config from ocs_ci.utility.utils import run_cmd, run_cmd_interactive from ocs_ci.ocs.node import get_typed_worker_nodes, label_nodes @@ -62,6 +63,8 @@ class Submariner(object): def __init__(self): # whether upstream OR downstream self.source = config.ENV_DATA["submariner_source"] + # released/unreleased + self.submariner_release_type = config.ENV_DATA.get("submariner_release_type") # Deployment type: self.deployment_type = config.ENV_DATA.get("submariner_deployment") # Designated broker cluster index where broker will be deployed @@ -94,9 +97,27 @@ def deploy_downstream(self): login_to_acm() acm_obj = AcmAddClusters() + if self.submariner_release_type == "unreleased": + old_ctx = config.cur_index + for cluster in get_non_acm_cluster_config(): + config.switch_ctx(cluster.MULTICLUSTER["multicluster_index"]) + self.create_acm_brew_icsp() + config.switch_ctx(old_ctx) acm_obj.install_submariner_ui() acm_obj.submariner_validation_ui() + def create_acm_brew_icsp(self): + """ + This is a prereq for downstream unreleased submariner + + """ + icsp_data = templating.load_yaml(constants.ACM_DOWNSTREAM_BREW_ICSP) + icsp_data_yaml = tempfile.NamedTemporaryFile( + mode="w+", prefix="acm_icsp", delete=False + ) + templating.dump_data_to_temp_yaml(icsp_data, icsp_data_yaml.name) + run_cmd(f"oc create -f {icsp_data_yaml.name}", timeout=300) + def download_binary(self): if self.source == "upstream": # This script puts the platform specific binary in ~/.local/bin diff --git a/ocs_ci/ocs/acm/acm.py b/ocs_ci/ocs/acm/acm.py index e46a6b22c25a..a7f907b2a9df 100644 --- a/ocs_ci/ocs/acm/acm.py +++ b/ocs_ci/ocs/acm/acm.py @@ -1,6 +1,7 @@ import logging import time import os +import tempfile from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as ec @@ -24,6 +25,8 @@ TimeoutSampler, get_running_acm_version, string_chunkify, + chained_subprocess_pipes, + run_cmd, ) from ocs_ci.ocs.ui.acm_ui import AcmPageNavigator from ocs_ci.ocs.ui.base_ui import login_ui, SeleniumDriver @@ -152,6 +155,46 @@ def install_submariner_ui(self, globalnet=True): for s in get_non_acm_cluster_config() if s.MULTICLUSTER["multicluster_index"] != primary_index ][0] + # submariner catalogsource creation + if config.ENV_DATA["submariner_release_type"] == "unreleased": + submariner_downstream_unreleased = templating.load_yaml( + constants.SUBMARINER_DOWNSTREAM_UNRELEASED + ) + # Update catalog source + submariner_full_url = "".join( + [ + constants.SUBMARINER_DOWNSTREAM_UNRELEASED_BUILD_URL, + config.ENV_DATA["submariner_version"], + ] + ) + curl_cmd = f"curl --retry 3 --retry-delay 5 -Ls {submariner_full_url}" + jq_cmd1 = ( + 'jq -r \'[.raw_messages[].msg | select(.pipeline.status=="complete") |' + "{{nvr: .artifact.nvr, index_image: .pipeline.index_image}}] | .[0]'" + ) + + jq_cmd2 = "jq -r '.index_image.\"v4.14\"'" + cut_cmd1 = "cut -d'/' -f3-" + cut_cmd2 = "cut -d':' -f2-" + cmd_exec = chained_subprocess_pipes( + [curl_cmd, jq_cmd1, jq_cmd2, cut_cmd1, cut_cmd2] + ) + version_tag = cmd_exec.communicate()[0].decode() + + image_url = submariner_downstream_unreleased["spec"]["image"] + image_url = image_url.replace("PLACE_HOLDER", version_tag) + submariner_downstream_unreleased["spec"]["image"] = image_url + submariner_data_yaml = tempfile.NamedTemporaryFile( + mode="w+", prefix="submariner_downstream_unreleased", delete=False + ) + templating.dump_data_to_temp_yaml( + submariner_downstream_unreleased, submariner_data_yaml + ) + old_ctx = config.cur_index + for cluster in get_non_acm_cluster_config(): + config.switch_ctx(cluster.MULTICLUSTER["multicluster_index"]) + run_cmd(f"oc create -f {submariner_data_yaml.name}", timeout=300) + config.switch_ctx(old_ctx) cluster_name_a = cluster_env.get(f"cluster_name_{primary_index}") cluster_name_b = cluster_env.get(f"cluster_name_{secondary_index}") @@ -239,6 +282,8 @@ def install_submariner_ui(self, globalnet=True): check_globalnet == constants.GLOBALNET_STATUS ), "Globalnet was not enabled" log.info("Globalnet is enabled") + # TODO: Use custom submariner sucscription from UI in case of downstream unreleased submariner + self.take_screenshot() log.info("Click on 'Install'") self.do_click(self.page_nav["install-btn"]) diff --git a/ocs_ci/ocs/constants.py b/ocs_ci/ocs/constants.py index 1d0240768881..52eadbf5cdaa 100644 --- a/ocs_ci/ocs/constants.py +++ b/ocs_ci/ocs/constants.py @@ -848,6 +848,7 @@ ) MDR_BACKUP_SCHEDULE_RESOURCE = "schedule-acm" + # DR constants SUBMARINER_DOWNLOAD_URL = "https://get.submariner.io" DR_DEFAULT_NAMESPACE = "openshift-dr-systems" @@ -2067,6 +2068,15 @@ SUBMARINER_GATEWAY_ACTIVE_LABEL = "gateway.submariner.io/status=active" SUBMARINER_GATEWAY_NODE_LABEL = "submariner.io/gateway=true" GLOBALNET_STATUS = "True" +SUBMARINER_DOWNSTREAM_UNRELEASED = os.path.join( + TEMPLATE_MULTICLUSTER_DIR, "submariner_downstream_unreleased_catsrc.yaml" +) +# We need to append version string at the end of this url +SUBMARINER_DOWNSTREAM_UNRELEASED_BUILD_URL = ( + "https://datagrepper.engineering.redhat.com/raw?topic=/topic/" + "VirtualTopic.eng.ci.redhat-container-image.pipeline.complete" + "&rows_per_page=25&delta=1296000&contains=submariner-operator-bundle-container-v" +) # Multicluster related @@ -2100,6 +2110,9 @@ ACM_HUB_UNRELEASED_ICSP_YAML = os.path.join( TEMPLATE_DIR, "acm-deployment", "imagecontentsourcepolicy.yaml" ) +ACM_DOWNSTREAM_BREW_ICSP = os.path.join( + TEMPLATE_DIR, "acm-deployment", "acm_downstream_brew_icsp.yaml" +) ACM_HUB_UNRELEASED_PULL_SECRET_TEMPLATE = "pull-secret.yaml.j2" ACM_ODF_MULTICLUSTER_ORCHESTRATOR_RESOURCE = "odf-multicluster-orchestrator" ACM_ODR_HUB_OPERATOR_RESOURCE = "odr-hub-operator" diff --git a/ocs_ci/templates/acm-deployment/acm_downstream_brew_icsp.yaml b/ocs_ci/templates/acm-deployment/acm_downstream_brew_icsp.yaml new file mode 100644 index 000000000000..4a4c76e8aa06 --- /dev/null +++ b/ocs_ci/templates/acm-deployment/acm_downstream_brew_icsp.yaml @@ -0,0 +1,18 @@ +apiVersion: operator.openshift.io/v1alpha1 +kind: ImageContentSourcePolicy +metadata: + name: brew-registry +spec: + repositoryDigestMirrors: + - mirrors: + - brew.registry.redhat.io + source: registry.redhat.io + - mirrors: + - brew.registry.redhat.io/rhacm2 + source: registry.redhat.io/rhacm2 + - mirrors: + - brew.registry.redhat.io + source: registry.stage.redhat.io + - mirrors: + - brew.registry.redhat.io + source: registry-proxy.engineering.redhat.com diff --git a/ocs_ci/templates/ocs-deployment/multicluster/submariner_downstream_unreleased_catsrc.yaml b/ocs_ci/templates/ocs-deployment/multicluster/submariner_downstream_unreleased_catsrc.yaml new file mode 100644 index 000000000000..bab28efe1df8 --- /dev/null +++ b/ocs_ci/templates/ocs-deployment/multicluster/submariner_downstream_unreleased_catsrc.yaml @@ -0,0 +1,16 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: CatalogSource +metadata: + name: submariner-catalogsource + namespace: openshift-marketplace +spec: + icon: + base64data: "" + mediatype: "" + image: brew.registry.redhat.io/rh-osbs/iib:PLACE_HOLDER + publisher: Red Hat + sourceType: grpc + priority: 100 + updateStrategy: + registryPoll: + interval: 15m diff --git a/ocs_ci/utility/utils.py b/ocs_ci/utility/utils.py index 02c72a3d1e84..888eff9cf476 100644 --- a/ocs_ci/utility/utils.py +++ b/ocs_ci/utility/utils.py @@ -4524,3 +4524,30 @@ def get_oadp_version(): if "oadp-operator" in csv["metadata"]["name"]: # extract version string return csv["spec"]["version"] + + +def chained_subprocess_pipes(cmd_list): + """ + We can use this function wherever we have chain of commands which + need to be piped. Direct shell piping has some parsing issues hence implementing + this using subprocess output redirections which mimics shell pipes. + Commands will be run as per the command ordering inside the list and output of + each command will be fed as input to the next command in the list + + + Args: + cmd_list (list): list of commands to be run whose output need to be piped + + Returns: + Popen object of the last command executed + + """ + pipe_buf = None + for cmd in cmd_list: + if not pipe_buf: + pipe_buf = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE) + else: + pipe_buf = subprocess.Popen( + shlex.split(cmd), stdin=pipe_buf.stdout, stdout=subprocess.PIPE + ) + return pipe_buf