Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added mce.py file for mce installation related methods #11038

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
4 changes: 3 additions & 1 deletion conf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ anywhere else.
* `mirror_registry` - Hostname of the mirror registry
* `mirror_registry_user` - Username for disconnected cluster mirror registry
* `mirror_registry_password` - Password for disconnected cluster mirror registry
* `opm_index_prune_binary_image` - Required only for IBM Power Systems and IBM Z images: Operator Registry base image with the tag that matches the target OpenShift Container Platform cluster major and minor version.
* `opm_index_prune_binary_image` - Required only for IBM Power Systems and IBM Z images: Operator Registry base image with the tag that matches the target OpenShift Container Platform cluster major and minor
* `deploy_mce`- Boolean, Deploy mce if True
version.
(for example: `registry.redhat.io/openshift4/ose-operator-registry:v4.9`)
[doc](https://access.redhat.com/documentation/en-us/openshift_container_platform/4.9/html/operators/administrator-tasks#olm-pruning-index-image_olm-managing-custom-catalogs)
* `min_noobaa_endpoints` - Sets minimum noobaa endpoints (Workaround for https://github.com/red-hat-storage/ocs-ci/issues/2861)
Expand Down
20 changes: 17 additions & 3 deletions ocs_ci/deployment/hosted_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import time
from concurrent.futures import ThreadPoolExecutor
from ocs_ci.deployment.cnv import CNVInstaller
from ocs_ci.deployment.mce import MCEInstaller
from ocs_ci.deployment.deployment import Deployment
from ocs_ci.deployment.helpers.hypershift_base import (
HyperShiftBase,
Expand Down Expand Up @@ -359,12 +360,15 @@ def deploy_multiple_odf_clients(self):
hosted_odf.do_deploy()


class HypershiftHostedOCP(HyperShiftBase, MetalLBInstaller, CNVInstaller, Deployment):
class HypershiftHostedOCP(
HyperShiftBase, MetalLBInstaller, CNVInstaller, Deployment, MCEInstaller
):
def __init__(self, name):
Deployment.__init__(self)
HyperShiftBase.__init__(self)
MetalLBInstaller.__init__(self)
CNVInstaller.__init__(self)
MCEInstaller.__init__(self)
self.name = name
if config.ENV_DATA.get("clusters", {}).get(self.name):
cluster_path = (
Expand All @@ -386,6 +390,7 @@ def deploy_ocp(
deploy_acm_hub=True,
deploy_metallb=True,
download_hcp_binary=True,
deploy_mce=True,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we will need introduce this new parameter in configurations and .md file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in latest commit.

):
"""
Deploy hosted OCP cluster on provisioned Provider platform
Expand All @@ -406,7 +411,7 @@ def deploy_ocp(
deploy_acm_hub = False

self.deploy_dependencies(
deploy_acm_hub, deploy_cnv, deploy_metallb, download_hcp_binary
deploy_acm_hub, deploy_cnv, deploy_metallb, download_hcp_binary, deploy_mce
)

ocp_version = str(config.ENV_DATA["clusters"][self.name].get("ocp_version"))
Expand Down Expand Up @@ -450,7 +455,12 @@ def deploy_ocp(
)

def deploy_dependencies(
self, deploy_acm_hub, deploy_cnv, deploy_metallb, download_hcp_binary
self,
deploy_acm_hub,
deploy_cnv,
deploy_metallb,
download_hcp_binary,
deploy_mce,
):
"""
Deploy dependencies for hosted OCP cluster
Expand All @@ -459,6 +469,7 @@ def deploy_dependencies(
deploy_cnv: bool Deploy CNV
deploy_metallb: bool Deploy MetalLB
download_hcp_binary: bool Download HCP binary
deploy_mce: bool Deploy mce

"""
initial_default_sc = helpers.get_default_storage_class()
Expand All @@ -480,6 +491,9 @@ def deploy_dependencies(
self.deploy_lb()
if download_hcp_binary:
self.update_hcp_binary()
if deploy_mce and not deploy_acm_hub:
self.deploy_mce()
self.validate_mce_deployment()

provider_ocp_version = str(
get_semantic_version(get_ocp_version(), only_major_minor=True)
Expand Down
244 changes: 244 additions & 0 deletions ocs_ci/deployment/mce.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
"""
This module contains functionality required for mce installation.
"""

import logging
import tempfile

from ocs_ci.framework import config
from ocs_ci.ocs.resources.ocs import OCS
from ocs_ci.ocs.ocp import OCP
from ocs_ci.utility import templating
from ocs_ci.ocs import constants
from ocs_ci.utility.utils import (
run_cmd,
exec_cmd,
)
from ocs_ci.ocs.resources.catalog_source import CatalogSource
from ocs_ci.ocs import ocp
from ocs_ci.utility.utils import get_running_ocp_version
from ocs_ci.ocs.exceptions import CommandFailed, UnavailableResourceException

logger = logging.getLogger(__name__)


class MCEInstaller(object):
"""
mce Installer class for mce deployment
"""

def __init__(self):
self.namespace = constants.MCE_NAMESPACE
self.ns_obj = ocp.OCP(kind=constants.NAMESPACES)
self.hypershift_override_image_cm = "hypershift-override-images-new"
self.multicluster_engine = ocp.OCP(
kind="MultiClusterEngine",
resource_name=constants.MULTICLUSTER_ENGINE,
)
self.catsrc = ocp.OCP(
kind=constants.CATSRC, namespace=constants.MARKETPLACE_NAMESPACE
)
self.subs = ocp.OCP(kind=constants.PROVIDER_SUBSCRIPTION)

def create_mce_catalog_source(self):
"""
Creates a catalogsource for mce operator.

"""
if not self.catsrc.is_exist(
resource_name=constants.MCE_CATSRC_NAME,
):
logger.info("Adding CatalogSource for MCE")
mce_catalog_source_data = templating.load_yaml(constants.MCE_CATSRC_YAML)
if config.ENV_DATA.get("mce_image"):
mce_image_tag = config.ENV_DATA.get("mce_image")
mce_catalog_source_data["spec"]["image"] = (
"quay.io:443/acm-d/mce-custom-registry:" + mce_image_tag
)
mce_catalog_source_manifest = tempfile.NamedTemporaryFile(
mode="w+", prefix="mce_catalog_source_manifest", delete=False
)
templating.dump_data_to_temp_yaml(
mce_catalog_source_data, mce_catalog_source_manifest.name
)
run_cmd(f"oc apply -f {mce_catalog_source_manifest.name}", timeout=2400)
mce_catalog_source = CatalogSource(
resource_name=constants.MCE_CATSRC_NAME,
namespace=constants.MARKETPLACE_NAMESPACE,
)
# Wait for catalog source is ready
mce_catalog_source.wait_for_state("READY")
else:
logger.info("catalogsource exists")

def create_mce_namespace(self):
"""
Creates the namespace for mce resources

Raises:
CommandFailed: If the 'oc create' command fails.
"""
if not self.ns_obj.is_exist(
resource_name=self.namespace,
):
logger.info(f"Creating namespace {self.namespace} for mce resources")
namespace_yaml_file = templating.load_yaml(constants.MCE_NAMESPACE_YAML)
namespace_yaml = OCS(**namespace_yaml_file)
namespace_yaml.create()
logger.info(f"MCE namespace {self.namespace} was created successfully")
else:
logger.info(f"{self.namespace} already exists")

def create_multiclusterengine_operator(self):
"""
Creates multiclusterengine operator

"""
logger.info("Check if mce operator already exist")
if not self.multicluster_engine.is_exist(
resource_name=constants.MULTICLUSTER_ENGINE
):

operatorgroup_yaml_file = templating.load_yaml(constants.MCE_OPERATOR_YAML)
operatorgroup_yaml = OCS(**operatorgroup_yaml_file)
operatorgroup_yaml.create()
logger.info("mce OperatorGroup created successfully")
self.multicluster_engine.wait_for_phase("Available")

def create_mce_subscription(self):
"""
Creates subscription for mce operator

"""
logger.info("Check if mce subscription already exist")
if not self.subs.is_exist(resource_name=constants.MCE_OPERATOR):
mce_subscription_yaml_data = templating.load_yaml(
constants.MCE_SUBSCRIPTION_YAML
)

if config.DEPLOYMENT.get("mce_latest_stable"):
mce_subscription_yaml_data["spec"][
"source"
] = constants.OPERATOR_CATALOG_SOURCE_NAME
mce_channel = "stable"
else:
mce_channel = config.DEPLOYMENT.get("mce_channel")

mce_subscription_yaml_data["spec"]["channel"] = mce_channel
mce_subscription_manifest = tempfile.NamedTemporaryFile(
mode="w+", prefix="mce_subscription_manifest", delete=False
)
templating.dump_data_to_temp_yaml(
mce_subscription_yaml_data, mce_subscription_manifest.name
)
logger.info("Creating subscription for mce operator")
run_cmd(f"oc create -f {mce_subscription_manifest.name}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please check if subscription exists in the beginning of the method; if exists skip execution of the method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in latest commit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Amrita. In case if subscription exists we will need to return True or something but not execute creation of the subscription second time.
I see you checked it here, but there is no else in this block, so it will be executed in any way

 if not self.subs.is_exist(resource_name=constants.MCE_OPERATOR):
            mce_subscription_yaml_data = templating.load_yaml(
                constants.MCE_SUBSCRIPTION_YAML
            )

OCP(
kind=constants.SUBSCRIPTION_COREOS,
namespace=self.namespace,
resource_name=constants.MCE_OPERATOR,
).check_resource_existence(
should_exist=True, resource_name=constants.MCE_OPERATOR
)

def check_hypershift_namespace(self):
"""
Check hypershift namespace created

"""
logger.info(f"hypershift namespace {self.namespace} was created successfully")
is_hypershift_ns_available = self.ns_obj.is_exist(
resource_name=constants.HYPERSHIFT_NAMESPACE,
)
return is_hypershift_ns_available

def check_supported_versions(self):
"""
Check supported ocp versions for hcp cluster creation

"""
configmaps_obj = OCP(
kind=constants.CONFIGMAP,
namespace=constants.HYPERSHIFT_NAMESPACE,
)

if not configmaps_obj.is_exist(
resource_name=constants.SUPPORTED_VERSIONS_CONFIGMAP
):
raise UnavailableResourceException(
f"Configmap {constants.SUPPORTED_VERSIONS_CONFIGMAP} does not exist in hypershift namespace"
)

cmd = "oc get cm -n hypershift supported-versions -o jsonpath='{.data.supported-versions}'"
cmd_res = exec_cmd(cmd, shell=True)
if cmd_res.returncode == 0:
supported_versions = cmd_res.stdout.decode("utf-8")
logger.info(f"Supported versions: {supported_versions}")

if not get_running_ocp_version() in supported_versions:
self.create_image_override()

def create_image_override(self):
"""
Create hypershift image override cm
"""
# Create image override configmap using the image override json
cmd = (
f"oc create cm {self.hypershift_override_image_cm} --from-file={constants.IMAGE_OVERRIDE_JSON}"
"-n {self.namespace}"
)
cmd_res = exec_cmd(cmd, shell=True)
if cmd_res.returncode:
raise CommandFailed("override configmap not created successfully")

# annotate multicluster engine operator with the override cm
self.multicluster_engine.annotate(
annotation=f"imageOverridesCM={self.hypershift_override_image_cm}"
)
self.multicluster_engine.wait_until_running()

def deploy_mce(self, check_mce_deployed=False, check_mce_ready=False):
"""
Installs mce enabling software emulation.

Args:
check_mce_deployed (bool): If True, check if mce is already deployed. If so, skip the deployment.
check_mce_ready (bool): If True, check if mce is ready. If so, skip the deployment.
"""
if check_mce_deployed:
if self.mce_hyperconverged_installed():
logger.info("mce operator is already deployed, skipping the deployment")
return

if check_mce_ready:
if self.post_install_verification(raise_exception=False):
logger.info("mce operator ready, skipping the deployment")
return

logger.info("Installing mce")
# we create catsrc with nightly builds only if config.DEPLOYMENT does not have mce_latest_stable
if not config.DEPLOYMENT.get("mce_latest_stable"):
# Create mce catalog source
self.create_mce_catalog_source()
# Create multicluster-engine namespace
self.create_mce_namespace()
# create mce subscription
self.create_mce_subscription()
# Deploy the multiclusterengine CR
self.create_multiclusterengine_operator()
# Check hypershift ns created
if not self.check_hypershift_namespace():
cmd = f"oc create namespace {constants.HYPERSHIFT_NAMESPACE}"
cmd_res = exec_cmd(cmd, shell=True)
if cmd_res.returncode:
raise CommandFailed("Failed to create hypershift namespace")
# Check supported versions in supported-versions configmap
self.check_supported_versions()

def validate_mce_deployment(self):
"""
Validate mce operator installation
"""
if self.mce_hyperconverged_installed():
logger.info("mce operator is already deployed")
return
18 changes: 18 additions & 0 deletions ocs_ci/deployment/provider_client/storage_client_deployment.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import logging
import time
import tempfile


from ocs_ci.framework import config
Expand Down Expand Up @@ -41,6 +42,7 @@
verify_block_pool_exists,
)
from ocs_ci.ocs.exceptions import CommandFailed
from ocs_ci.ocs.resources.catalog_source import CatalogSource


log = logging.getLogger(__name__)
Expand Down Expand Up @@ -322,6 +324,22 @@ def odf_subscription_on_provider(self):
live_deployment = config.DEPLOYMENT.get("live_deployment")
if not live_deployment:
create_catalog_source()
catalog_data = templating.load_yaml(constants.PROVIDER_MODE_CATALOGSOURCE)
catalog_data["spec"]["image"] = config.DEPLOYMENT.get(
"ocs_registry_image", ""
)
catalog_data_yaml = tempfile.NamedTemporaryFile(
mode="w+", prefix="catalog_data", delete=False
)
templating.dump_data_to_temp_yaml(catalog_data, catalog_data_yaml.name)
self.ocp_obj.exec_oc_cmd(f"apply -f {catalog_data_yaml.name}")

catalog_source = CatalogSource(
resource_name=constants.OCS_CATALOG_SOURCE_NAME,
namespace=constants.MARKETPLACE_NAMESPACE,
)
# Wait for catalog source is ready
catalog_source.wait_for_state("READY")
Comment on lines 326 to +342
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amr1ta I'm not sure, if I didn't miss anything, but why there is the new code for creating CatalogSource, when there is one already created just above that via the create_catalog_source() function?

The problem is, tat the deployment is failing like this: https://url.corp.redhat.com/35f799a and the reason is, that there are two catalog sources with label ocs-operator-internal=true and both created from the same image:

$ oc get catalogsources.operators.coreos.com -n openshift-marketplace --selector=ocs-operator-internal=true
NAME                DISPLAY                       TYPE   PUBLISHER   AGE
ocs-catalogsource   Openshift Container Storage   grpc   Red Hat     161m
redhat-operators    Openshift Container Storage   grpc   Red Hat     161m

$ oc get catalogsources.operators.coreos.com -n openshift-marketplace --selector=ocs-operator-internal=true -o yaml | grep image:
    image: quay.io/rhceph-dev/ocs-registry:4.18.0-109
    image: quay.io/rhceph-dev/ocs-registry:4.18.0-109

Which then causes the AttributeError: 'list' object has no attribute 'get' failure in the above linked job.


log.info("Creating namespace and operator group.")
olm_data = templating.load_yaml(constants.OLM_YAML, multi_document=True)
Expand Down
Loading
Loading