Skip to content

Commit

Permalink
Added mce.py file for mce installation related methods and created li…
Browse files Browse the repository at this point in the history
…btest to check mce installation and hcp cluster creation without acm operator

Signed-off-by: Amrita Mahapatra <[email protected]>
  • Loading branch information
amr1ta committed Dec 12, 2024
1 parent 8293e24 commit 7205d27
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 1 deletion.
12 changes: 11 additions & 1 deletion 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 @@ -365,6 +366,7 @@ def __init__(self, name):
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 Down Expand Up @@ -450,7 +452,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 +466,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 +488,8 @@ def deploy_dependencies(
self.deploy_lb()
if download_hcp_binary:
self.update_hcp_binary()
if deploy_mce:
self.deploy_mce()

provider_ocp_version = str(
get_semantic_version(get_ocp_version(), only_major_minor=True)
Expand Down
243 changes: 243 additions & 0 deletions ocs_ci/deployment/mce.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
"""
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 import exceptions
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

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,
)

def create_mce_catalog_source(self):
"""
Creates a catalogsource for mce operator.
"""
logger.info("Adding CatalogSource for MCE")
mce_catalog_source_data = templating.load_yaml(constants.MCE_CATSRC_YAML)
mce_catalog_source_name = mce_catalog_source_data.get("metadata").get("name")
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=mce_catalog_source_name,
namespace=constants.MARKETPLACE_NAMESPACE,
)

# 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.
"""
try:
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")
except exceptions.CommandFailed as ef:
if (
f'project.project.openshift.io "{self.namespace}" already exists'
in str(ef)
):
logger.info(f"Namespace {self.namespace} already present")
raise ef

def create_multiclusterengine_operator(self):
"""
Creates multiclusterengine operator
"""
operatorgroup_yaml_file = templating.load_yaml(constants.MCE_OPERATOR_YAM)
operatorgroup_yaml = OCS(**operatorgroup_yaml_file)
try:
operatorgroup_yaml.create()
logger.info("mce OperatorGroup created successfully")
except exceptions.CommandFailed as ef:
if "multiclusterengine exists" in str(ef):
logger.info("multiclusterengine already exists")

cmd = "oc get mce multiclusterengine -o jsonpath='{.status}'"
cmd_res = exec_cmd(cmd, shell=True)
if cmd_res.returncode != 0:
logger.error(f"Failed to get multicluster engine status\n{cmd_res.stderr}")
else:
logger.info(
f"Multicluster engine version: {cmd_res.stdout.decode('utf-8')}"
)
assert (
cmd_res.stdout.decode("utf-8") == "Available"
), "multiclusterengine is not is 'Available' status"

def create_mce_subscription(self):
"""
Creates subscription for 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}")
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,
)

assert configmaps_obj.is_exist(
resource_name=constants.SUPPORTED_VERSIONS_CONFIGMAP
), 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)
assert cmd_res.returncode == 0

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

assert configmaps_obj.is_exist(
resource_name=self.hypershift_override_image_cm
), f"Configmap {self.hypershift_override_image_cm} does not exist in hypershift namespace"

# 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 = (
"oc patch mce multiclusterengine "
'-p \'{"spec":{"overrides":{"components":['
'{"enabled":true, "name":"hypershift"}'
"]}}}' --type=merge"
)
cmd_res = exec_cmd(cmd, shell=True)
assert cmd_res.returncode == 0
12 changes: 12 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 @@ -2709,6 +2710,17 @@
SUBCTL_DOWNSTREAM_URL = "registry.redhat.io/rhacm2/"

# 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_SUBSCRIPTION_YAML = os.path.join(
TEMPLATE_DEPLOYMENT_DIR_MCE, "mce_subscription.yaml"
)
MCE_OPERATOR = "multicluster-engine-operator"
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
8 changes: 8 additions & 0 deletions ocs_ci/templates/mce-deployment/image-override.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{
"image-name": "rhtap-hypershift-operator",
"image-tag": "17a958f",
"image-remote": "quay.io/acm-d",
"image-key": "hypershift_operator"
}
]
8 changes: 8 additions & 0 deletions ocs_ci/templates/mce-deployment/mce_catsrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: operators.coreos.com/v1alpha1
kind: CatalogSource
metadata:
name: mce-catalogsource
namespace: openshift-marketplace
spec:
image: PLACE_HOLDER2.13.0-DOWNSTREAM-2024-12-09-22-26-41
sourceType: grpc
6 changes: 6 additions & 0 deletions ocs_ci/templates/mce-deployment/mce_namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: multicluster-engine
labels:
openshift.io/cluster-monitoring: "true"
10 changes: 10 additions & 0 deletions ocs_ci/templates/mce-deployment/mce_operator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: multicluster.openshift.io/v1
kind: MultiClusterEngine
metadata:
name: multiclusterengine
spec:
overrides:
components:
- name: local-cluster
enabled: true
availabilityConfig: High
11 changes: 11 additions & 0 deletions ocs_ci/templates/mce-deployment/mce_subscription.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: multicluster-engine
namespace: multicluster-engine
spec:
channel: stable
installPlanApproval: Automatic
name: multicluster-engine
source: mce-catalogsource
sourceNamespace: openshift-marketplace
26 changes: 26 additions & 0 deletions tests/libtest/test_provider_create_hosted_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,3 +312,29 @@ def test_verify_native_storage(self):
assert (
storage_class in storage_class_classes
), "Storage classes ae not created as expected"

@runs_on_provider
@hci_provider_required
def test_deploy_mce(self):
"""
Test deploy mce without installting acm
"""
logger.info("Test deploy mce without deploying ACM")
HypershiftHostedOCP("dummy").deploy_dependencies(
deploy_acm_hub=False,
deploy_cnv=False,
deploy_metallb=False,
download_hcp_binary=False,
deploy_mce=True,
)
assert validate_acm_hub_install(), "ACM not installed or MCE not configured"

@hci_provider_required
def test_provider_deploy_OCP_hosted_skip_acm(self):
"""
Test deploy hosted OCP on provider platform with cnv ready beforehand
"""
logger.info("Test deploy hosted OCP on provider platform with cnv ready")
cluster_name = list(config.ENV_DATA["clusters"].keys())[-1]

HypershiftHostedOCP(cluster_name).deploy_ocp(deploy_acm_hub=False)

0 comments on commit 7205d27

Please sign in to comment.