Skip to content

Commit

Permalink
Ocp deployment using acm UI (#5562)
Browse files Browse the repository at this point in the history
Implement OCP DR clusters deployment using ACM UI

Signed-off-by: Shylesh Kumar Mohan <[email protected]>
  • Loading branch information
shylesh authored Apr 12, 2022
1 parent 0fb116b commit 2dd59d1
Show file tree
Hide file tree
Showing 10 changed files with 783 additions and 44 deletions.
4 changes: 4 additions & 0 deletions conf/ocsci/multicluster_acm_ocp_deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ENV_DATA:
acm_ocp_deployment: True
UI_SELENIUM:
headless: False
3 changes: 3 additions & 0 deletions conf/ocsci/multicluster_mode_rdr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MULTICLUSTER:
# Other modes could be managed services
multicluster_mode: "regional-dr"
102 changes: 64 additions & 38 deletions ocs_ci/deployment/deployment.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,12 @@ class OCPDeployment(BaseOCPDeployment):

pass

def deploy_cluster(self, log_cli_level="DEBUG"):
def do_deploy_ocp(self, log_cli_level):
"""
We are handling both OCP and OCS deployment here based on flags
Deploy OCP
Args:
log_cli_level (str): log level for installer (default: DEBUG)
log_cli_level (str): log level for the installer
"""
if not config.ENV_DATA["skip_ocp_deployment"]:
if is_cluster_running(self.cluster_path):
Expand All @@ -175,46 +175,22 @@ def deploy_cluster(self, log_cli_level="DEBUG"):
collect_ocs_logs("deployment", ocs=False)
raise

# Deployment of network split scripts via machineconfig API happens
# before OCS deployment.
if config.DEPLOYMENT.get("network_split_setup"):
master_zones = config.ENV_DATA.get("master_availability_zones")
worker_zones = config.ENV_DATA.get("worker_availability_zones")
# special external zone, which is directly defined by ip addr list,
# such zone could represent external services, which we could block
# access to via ax-bx-cx network split
if config.DEPLOYMENT.get("network_split_zonex_addrs") is not None:
x_addr_list = config.DEPLOYMENT["network_split_zonex_addrs"].split(",")
else:
x_addr_list = None
if config.DEPLOYMENT.get("arbiter_deployment"):
arbiter_zone = self.get_arbiter_location()
logger.debug("detected arbiter zone: %s", arbiter_zone)
else:
arbiter_zone = None
# TODO: use temporary directory for all temporary files of
# ocs-deployment, not just here in this particular case
tmp_path = Path(tempfile.mkdtemp(prefix="ocs-ci-deployment-"))
logger.debug("created temporary directory %s", tmp_path)
setup_netsplit(
tmp_path, master_zones, worker_zones, x_addr_list, arbiter_zone
)
ocp_version = version.get_semantic_ocp_version_from_config()
if (
config.ENV_DATA.get("deploy_acm_hub_cluster")
and ocp_version >= version.VERSION_4_9
):
try:
self.deploy_acm_hub()
except Exception as e:
logger.error(e)
def do_deploy_submariner(self):
"""
Deploy Submariner operator
"""
# Multicluster operations
if config.multicluster:
# Configure submariner only on non-ACM clusters
submariner = Submariner()
submariner.deploy()

def do_deploy_ocs(self):
"""
Deploy OCS/ODF and run verification as well
"""
if not config.ENV_DATA["skip_ocs_deployment"]:
for i in range(config.nclusters):
if config.multicluster and config.get_acm_index() == i:
Expand All @@ -234,7 +210,6 @@ def deploy_cluster(self, log_cli_level="DEBUG"):
collect_ocs_logs("deployment", ocp=False)
raise
config.reset_ctx()

# Run ocs_install_verification here only in case of multicluster.
# For single cluster, test_deployment will take care.
if config.multicluster:
Expand All @@ -251,12 +226,63 @@ def deploy_cluster(self, log_cli_level="DEBUG"):
else:
logger.warning("OCS deployment will be skipped")

def do_deploy_rdr(self):
"""
Call Regional DR deploy
"""
# Multicluster: Handle all ODF multicluster DR ops
if config.multicluster:
dr_conf = self.get_rdr_conf()
deploy_dr = MultiClusterDROperatorsDeploy(dr_conf)
deploy_dr.deploy()

def deploy_cluster(self, log_cli_level="DEBUG"):
"""
We are handling both OCP and OCS deployment here based on flags
Args:
log_cli_level (str): log level for installer (default: DEBUG)
"""
self.do_deploy_ocp(log_cli_level)
# Deployment of network split scripts via machineconfig API happens
# before OCS deployment.
if config.DEPLOYMENT.get("network_split_setup"):
master_zones = config.ENV_DATA.get("master_availability_zones")
worker_zones = config.ENV_DATA.get("worker_availability_zones")
# special external zone, which is directly defined by ip addr list,
# such zone could represent external services, which we could block
# access to via ax-bx-cx network split
if config.DEPLOYMENT.get("network_split_zonex_addrs") is not None:
x_addr_list = config.DEPLOYMENT["network_split_zonex_addrs"].split(",")
else:
x_addr_list = None
if config.DEPLOYMENT.get("arbiter_deployment"):
arbiter_zone = self.get_arbiter_location()
logger.debug("detected arbiter zone: %s", arbiter_zone)
else:
arbiter_zone = None
# TODO: use temporary directory for all temporary files of
# ocs-deployment, not just here in this particular case
tmp_path = Path(tempfile.mkdtemp(prefix="ocs-ci-deployment-"))
logger.debug("created temporary directory %s", tmp_path)
setup_netsplit(
tmp_path, master_zones, worker_zones, x_addr_list, arbiter_zone
)
ocp_version = version.get_semantic_ocp_version_from_config()
if (
config.ENV_DATA.get("deploy_acm_hub_cluster")
and ocp_version >= version.VERSION_4_9
):
try:
self.deploy_acm_hub()
except Exception as e:
logger.error(e)

self.do_deploy_submariner()
self.do_deploy_ocs()
self.do_deploy_rdr()

def get_rdr_conf(self):
"""
Aggregate important Regional DR parameters in the dictionary
Expand Down
12 changes: 11 additions & 1 deletion ocs_ci/deployment/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ class DeploymentFactory(object):
"""

def __init__(self):
self.deployment_platform = config.ENV_DATA["platform"].lower()
if config.ENV_DATA.get("acm_ocp_deployment"):
self.deployment_platform = constants.ACM_OCP_DEPLOYMENT
else:
self.deployment_platform = config.ENV_DATA["platform"].lower()
self.cls_map = {}
# A map of all existing deployments and respective classes
# should be put here, but only in the condition if that platform is used.
Expand Down Expand Up @@ -76,6 +79,10 @@ def __init__(self):
from .rhv import RHVIPI

self.cls_map["rhv_ipi"] = RHVIPI
elif self.deployment_platform == constants.ACM_OCP_DEPLOYMENT:
from .multicluster_deployment import OCPDeployWithACM

self.cls_map["acm_ocp_deployment"] = OCPDeployWithACM

def get_deployment(self):
"""
Expand All @@ -84,6 +91,9 @@ def get_deployment(self):
deployment_platform may look like 'aws', 'vmware', 'baremetal'
deployment_type may be like 'ipi' or 'upi'
"""
if config.ENV_DATA.get("acm_ocp_deployment"):
logger.info("Deployment will be done through ACM platform")
return self.cls_map[constants.ACM_OCP_DEPLOYMENT]()
deployment_type = config.ENV_DATA["deployment_type"]
flexy_deployment = config.ENV_DATA["flexy_deployment"]
deployment_cls_key = (
Expand Down
108 changes: 108 additions & 0 deletions ocs_ci/deployment/multicluster_deployment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import logging

from ocs_ci.deployment.deployment import Deployment
from ocs_ci.framework import config
from ocs_ci.ocs.exceptions import ACMClusterDeployException
from ocs_ci.ocs.ui import acm_ui
from ocs_ci.ocs.utils import get_non_acm_cluster_config
from ocs_ci.ocs.acm import acm
from ocs_ci.ocs import constants


logger = logging.getLogger(__name__)


class OCPDeployWithACM(Deployment):
"""
When we instantiate this class, the assumption is we already have
an OCP cluster with ACM installed and current context is ACM
"""

def __init__(self):
"""
When we init Deployment class it will have all the
ACM cluster's context
"""
super().__init__()
self.multicluster_mode = config.MULTICLUSTER.get("multicluster_mode", None)
# Used for housekeeping during multiple OCP cluster deployments
self.deployment_cluster_list = list()
# Whether to start deployment in asynchronous mode or synchronous mode
# In async deploy mode, we will have a single wait method waiting for
# all the cluster deployments to finish
self.deploy_sync_mode = config.MULTICLUSTER.get("deploy_sync_mode", "async")
self.ui_driver = None

def do_deploy_ocp(self, log_cli_level="INFO"):
"""
This function overrides the parent's function in order accomodate
ACM based OCP cluster deployments
"""
if self.multicluster_mode == constants.RDR_MODE:
self.do_rdr_acm_ocp_deploy()

def do_rdr_acm_ocp_deploy(self):
"""
Specific to regional DR OCP cluster deployments
"""
factory = acm_ui.ACMOCPDeploymentFactory()
self.ui_driver = acm.login_to_acm()

if self.deploy_sync_mode == "async":
rdr_clusters = get_non_acm_cluster_config()
for c in rdr_clusters:
logger.info(f"{c.ENV_DATA['cluster_name']}")
logger.info(f"{c.ENV_DATA['platform']}")
logger.info(f"{c.ENV_DATA['deployment_type']}")
for cluster_conf in rdr_clusters:
deployer = factory.get_platform_instance(self.ui_driver, cluster_conf)
deployer.create_cluster_prereq()
deployer.create_cluster()
self.deployment_cluster_list.append(deployer)
# At this point deployment of all non-acm ocp clusters have been
# triggered, we need to wait for all of them to succeed
self.wait_for_all_clusters_async()
# Download kubeconfig to the respective directories
for cluster in self.deployment_cluster_list:
cluster.download_cluster_conf_files()

def wait_for_all_clusters_async(self):
# We will say done only when none of the clusters are in
# 'Creating' state. Either they have to be in 'Ready' state
# OR 'Failed' state
done_waiting = False
while not done_waiting:
done_waiting = True
for cluster in self.deployment_cluster_list:
if cluster.deployment_status not in ["ready", "failed"]:
cluster.get_deployment_status()
done_waiting = False
# We will fail even if one of the clusters failed to deploy
failed_list = list()
success_list = list()
for cluster in self.deployment_cluster_list:
if cluster.deployment_status == "failed":
failed_list.append(cluster)
else:
success_list.append(cluster)

if success_list:
logger.info("Deployment for following clusters Passed")
logger.info(f"{[c.cluster_name for c in success_list]}")
if failed_list:
logger.error("Deployment failed for following clusters")
logger.error(f"{[c.cluster_name for c in failed_list]}")
raise ACMClusterDeployException("one or more Cluster Deployment failed ")

def deploy_cluster(self, log_cli_level="INFO"):
"""
We deploy new OCP clusters using ACM
Note: Importing cluster through ACM has been implemented as part
of Jenkins pipeline
"""

super().deploy_cluster(log_cli_level=log_cli_level)
22 changes: 22 additions & 0 deletions ocs_ci/ocs/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import os


# Logging
LOG_FORMAT = "%(asctime)s - %(threadName)s - %(name)s - %(levelname)s - %(message)s"

Expand Down Expand Up @@ -654,6 +655,7 @@
DR_RAMEN_HUB_OPERATOR_CONFIG = "ramen-hub-operator-config"
DR_RAMEN_CLUSTER_OPERATOR_CONFIG = "ramen-dr-cluster-operator-config"
ODF_MULTICLUSTER_ORCHESTRATOR_CONTROLLER_MANAGER = "odfmo-controller-manager"
RDR_MODE = "regional-dr"

# DR constants
SUBMARINER_DOWNLOAD_URL = "https://get.submariner.io"
Expand Down Expand Up @@ -772,6 +774,7 @@
OPENSHIFT_DEDICATED_PLATFORM = "openshiftdedicated"
RHV_PLATFORM = "rhv"
ROSA_PLATFORM = "rosa"
ACM_OCP_DEPLOYMENT = "acm_ocp_deployment"
ON_PREM_PLATFORMS = [
VSPHERE_PLATFORM,
BAREMETAL_PLATFORM,
Expand Down Expand Up @@ -1665,3 +1668,22 @@
VAULT_TOKEN = "vaulttokens"
VAULT_TENANT_SA = "vaulttenantsa"
RBD_CSI_VAULT_TOKEN_REVIEWER_NAME = "rbd-csi-vault-token-review"
# ACM UI related constants
PLATFORM_XPATH_MAP = {
"vsphere": "cc_provider_vmware_vsphere",
"AWS": None,
"baremetal": None,
"azure": None,
}
ACM_PLATOFRM_VSPHERE_CRED_PREFIX = "vsphereacmocp-"
# example release image url : quay.io/openshift-release-dev/ocp-release:4.9.23-x86_64
ACM_OCP_RELEASE_IMG_URL_PREFIX = "registry.ci.openshift.org/ocp/release"
ACM_VSPHERE_NETWORK = "VM Network"
ACM_CLUSTER_DEPLOY_TIMEOUT = 2700 # 45 minutes
ACM_CLUSTER_DEPLOYMENT_LABEL_KEY = "hive.openshift.io/cluster-deployment-name"
ACM_CLUSTER_DEPLOYMENT_SECRET_TYPE_LABEL_KEY = "hive.openshift.io/secret-type"
# Concatenated CA file for vcenter
VSPHERE_CA_FILE_PATH = os.path.join(DATA_DIR, "vsphere_ca.crt")
SSH_PRIV_KEY = os.path.expanduser(os.path.join(".ssh", "openshift-dev.pem"))
SSH_PUB_KEY = os.path.expanduser(os.path.join(".ssh", "openshift-dev.pub"))
SPACE = " "
4 changes: 4 additions & 0 deletions ocs_ci/ocs/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,10 @@ class BenchmarkTestFailed(Exception):
pass


class ACMClusterDeployException(Exception):
pass


class WrongVersionExpression(ValueError):
pass

Expand Down
Loading

0 comments on commit 2dd59d1

Please sign in to comment.