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
19 changes: 16 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,8 @@ 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()

provider_ocp_version = str(
get_semantic_version(get_ocp_version(), only_major_minor=True)
Expand Down
240 changes: 240 additions & 0 deletions ocs_ci/deployment/mce.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
"""
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"] = 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,
)
else:
logger.info("catalogsource exists")
logger.info("Check the image for MCE")
if not mce_catalog_source_data["spec"]["image"] == config.ENV_DATA.get(
"mce_image"
):
mce_catalog_source_data["spec"]["image"] = config.ENV_DATA.get(
"mce_image"
)

# Wait for catalog source is ready
mce_catalog_source.wait_for_state("READY")

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_sub_channel = "stable-2.7"

mce_subscription_yaml_data["spec"]["channel"] = f"{mce_sub_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()
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")

log.info("Creating namespace and operator group.")
olm_data = templating.load_yaml(constants.OLM_YAML, multi_document=True)
Expand Down
14 changes: 14 additions & 0 deletions ocs_ci/ocs/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
TEMPLATE_DEPLOYMENT_DIR_LVMO = os.path.join(TEMPLATE_DIR, "lvmo-deployment")
TEMPLATE_MULTICLUSTER_DIR = os.path.join(TEMPLATE_DEPLOYMENT_DIR, "multicluster")
TEMPLATE_DEPLOYMENT_DIR_CNV = os.path.join(TEMPLATE_DIR, "cnv-deployment")
TEMPLATE_DEPLOYMENT_DIR_MCE = os.path.join(TEMPLATE_DIR, "mce-deployment")
TEMPLATE_DEPLOYMENT_DIR_METALLB = os.path.join(TEMPLATE_DIR, "metallb-deployment")
TEMPLATE_DEPLOYMENT_DIR_NMSTATE = os.path.join(TEMPLATE_DIR, "nmstate-deployment")
TEMPLATE_DEPLOYMENT_DIR_INF = os.path.join(
Expand Down Expand Up @@ -400,6 +401,7 @@
"storagesystems",
"storagesystem",
]
PROVIDER_SUBSCRIPTION = "subs"

OCS_CLIENT_OPERATOR_CONTROLLER_MANAGER_PREFIX = "ocs-client-operator-controller-manager"
OCS_CLIENT_OPERATOR_CONSOLE = "ocs-client-operator-console"
Expand Down Expand Up @@ -2733,6 +2735,18 @@
ACM_BREW_REPO = SUBMARINER_BREW_REPO

# Multicluster related
MCE_NAMESPACE = "multicluster-engine"
MCE_NAMESPACE_YAML = os.path.join(TEMPLATE_DEPLOYMENT_DIR_MCE, "mce_namespace.yaml")
MCE_CATSRC_YAML = os.path.join(TEMPLATE_DEPLOYMENT_DIR_MCE, "mce_catsrc.yaml")
MCE_CATSRC_NAME = "mce-catalogsource"
MCE_SUBSCRIPTION_YAML = os.path.join(
TEMPLATE_DEPLOYMENT_DIR_MCE, "mce_subscription.yaml"
)
MCE_OPERATOR = "multicluster-engine"
MCE_OPERATOR_YAML = os.path.join(TEMPLATE_DEPLOYMENT_DIR_MCE, "mce_operator.yaml")
HYPERSHIFT_NAMESPACE = "hypershift"
SUPPORTED_VERSIONS_CONFIGMAP = "supported-versions"
IMAGE_OVERRIDE_JSON = os.path.join(TEMPLATE_DEPLOYMENT_DIR_MCE, "image-override.json")

# OpenSSL Certificate parameters
OPENSSL_KEY_SIZE = 2048
Expand Down
Loading
Loading