def get_lso_channel(): """ Get the channel to use for installing the local storage operator Returns: str: local storage operator channel """ ocp_version = get_ocp_version() # If OCP version is not GA, we will be using the Optional Operators CatalogSource # This means there are two PackageManifests with the name local-storage-operator # so we need to also use a selector to ensure we retrieve the correct one ocp_ga_version = get_ocp_ga_version(ocp_version) selector = constants.OPTIONAL_OPERATORS_SELECTOR if not ocp_ga_version else None # Retrieve available channels for LSO package_manifest = PackageManifest( resource_name=constants.LOCAL_STORAGE_CSV_PREFIX, selector=selector) channels = package_manifest.get_channels() channel_names = [channel["name"] for channel in channels] # Ensure channel_names is sorted versions = [ LooseVersion(name) for name in channel_names if name != "stable" ] versions.sort() sorted_versions = [v.vstring for v in versions] if ocp_version in channel_names: # Use channel corresponding to OCP version return ocp_version else: # Use latest channel return sorted_versions[-1]
def install_local_storage_operator(self): """ Install local storage operator """ if config.DEPLOYMENT.get("local_storage"): self.navigate_operatorhub_page() logger.info(f"Search {self.operator_name} Operator") self.do_send_keys(self.dep_loc["search_operators"], text="Local Storage") logger.info("Choose Local Storage Version") ocp_ga_version = get_ocp_ga_version(self.ocp_version_full) if ocp_ga_version: self.do_click(self.dep_loc["choose_local_storage_version"], enable_screenshot=True) else: self.do_click( self.dep_loc["choose_local_storage_version_non_ga"], enable_screenshot=True, ) logger.info("Click Install LSO") self.do_click(self.dep_loc["click_install_lso"], enable_screenshot=True) self.do_click(self.dep_loc["click_install_lso_page"], enable_screenshot=True) self.verify_operator_succeeded(operator="Local Storage")
def create_optional_operators_catalogsource_non_ga(force=False): """ Creating optional operators CatalogSource and ImageContentSourcePolicy for non-ga OCP. Args: force (bool): enable/disable lso catalog setup """ ocp_version = version.get_semantic_ocp_version_from_config() ocp_ga_version = get_ocp_ga_version(ocp_version) if ocp_ga_version and not force: return optional_operators_data = list( templating.load_yaml(constants.LOCAL_STORAGE_OPTIONAL_OPERATORS, multi_document=True)) optional_operators_yaml = tempfile.NamedTemporaryFile( mode="w+", prefix="optional_operators", delete=False) if config.DEPLOYMENT.get("optional_operators_image"): for _dict in optional_operators_data: if _dict.get("kind").lower() == "catalogsource": _dict["spec"]["image"] = config.DEPLOYMENT.get( "optional_operators_image") if config.DEPLOYMENT.get("disconnected"): # in case of disconnected environment, we have to mirror all the # optional_operators images icsp = None for _dict in optional_operators_data: if _dict.get("kind").lower() == "catalogsource": index_image = _dict["spec"]["image"] if _dict.get("kind").lower() == "imagecontentsourcepolicy": icsp = _dict mirrored_index_image = (f"{config.DEPLOYMENT['mirror_registry']}/" f"{index_image.split('/', 1)[-1]}") prune_and_mirror_index_image( index_image, mirrored_index_image, constants.DISCON_CL_REQUIRED_PACKAGES, icsp, ) _dict["spec"]["image"] = mirrored_index_image templating.dump_data_to_temp_yaml(optional_operators_data, optional_operators_yaml.name) with open(optional_operators_yaml.name, "r") as f: logger.info(f.read()) logger.info( "Creating optional operators CatalogSource and ImageContentSourcePolicy" ) run_cmd(f"oc create -f {optional_operators_yaml.name}") wait_for_machineconfigpool_status("all")
def setup_local_storage(storageclass): """ Setup the necessary resources for enabling local storage. Args: storageclass (string): storageClassName value to be used in LocalVolume CR based on LOCAL_VOLUME_YAML """ # Get the worker nodes workers = get_nodes(node_type="worker") worker_names = [worker.name for worker in workers] logger.debug("Workers: %s", worker_names) ocp_version = version.get_semantic_ocp_version_from_config() ocs_version = version.get_semantic_ocs_version_from_config() ocp_ga_version = get_ocp_ga_version(ocp_version) if not ocp_ga_version: optional_operators_data = list( templating.load_yaml(constants.LOCAL_STORAGE_OPTIONAL_OPERATORS, multi_document=True)) optional_operators_yaml = tempfile.NamedTemporaryFile( mode="w+", prefix="optional_operators", delete=False) if config.DEPLOYMENT.get("optional_operators_image"): for _dict in optional_operators_data: if _dict.get("kind").lower() == "catalogsource": _dict["spec"]["image"] = config.DEPLOYMENT.get( "optional_operators_image") if config.DEPLOYMENT.get("disconnected"): # in case of disconnected environment, we have to mirror all the # optional_operators images icsp = None for _dict in optional_operators_data: if _dict.get("kind").lower() == "catalogsource": index_image = _dict["spec"]["image"] if _dict.get("kind").lower() == "imagecontentsourcepolicy": icsp = _dict mirrored_index_image = (f"{config.DEPLOYMENT['mirror_registry']}/" f"{index_image.split('/', 1)[-1]}") prune_and_mirror_index_image( index_image, mirrored_index_image, constants.DISCON_CL_REQUIRED_PACKAGES, icsp, ) _dict["spec"]["image"] = mirrored_index_image templating.dump_data_to_temp_yaml(optional_operators_data, optional_operators_yaml.name) with open(optional_operators_yaml.name, "r") as f: logger.info(f.read()) logger.info( "Creating optional operators CatalogSource and ImageContentSourcePolicy" ) run_cmd(f"oc create -f {optional_operators_yaml.name}") logger.info( "Sleeping for 60 sec to start update machineconfigpool status") # sleep here to start update machineconfigpool status time.sleep(60) wait_for_machineconfigpool_status("all") logger.info("Retrieving local-storage-operator data from yaml") lso_data = list( templating.load_yaml(constants.LOCAL_STORAGE_OPERATOR, multi_document=True)) # ensure namespace is correct lso_namespace = config.ENV_DATA["local_storage_namespace"] for data in lso_data: if data["kind"] == "Namespace": data["metadata"]["name"] = lso_namespace else: data["metadata"]["namespace"] = lso_namespace if data["kind"] == "OperatorGroup": data["spec"]["targetNamespaces"] = [lso_namespace] # Update local-storage-operator subscription data with channel for data in lso_data: if data["kind"] == "Subscription": data["spec"]["channel"] = get_lso_channel() if not ocp_ga_version: if data["kind"] == "Subscription": data["spec"]["source"] = "optional-operators" # Create temp yaml file and create local storage operator logger.info( "Creating temp yaml file with local-storage-operator data:\n %s", lso_data) lso_data_yaml = tempfile.NamedTemporaryFile( mode="w+", prefix="local_storage_operator", delete=False) templating.dump_data_to_temp_yaml(lso_data, lso_data_yaml.name) with open(lso_data_yaml.name, "r") as f: logger.info(f.read()) logger.info("Creating local-storage-operator") run_cmd(f"oc create -f {lso_data_yaml.name}") local_storage_operator = ocp.OCP(kind=constants.POD, namespace=lso_namespace) assert local_storage_operator.wait_for_resource( condition=constants.STATUS_RUNNING, selector=constants.LOCAL_STORAGE_OPERATOR_LABEL, timeout=600, ), "Local storage operator did not reach running phase" # Add disks for vSphere/RHV platform platform = config.ENV_DATA.get("platform").lower() lso_type = config.DEPLOYMENT.get("type") if platform == constants.VSPHERE_PLATFORM: add_disk_for_vsphere_platform() if platform == constants.RHV_PLATFORM: add_disk_for_rhv_platform() if (ocp_version >= version.VERSION_4_6) and (ocs_version >= version.VERSION_4_6): # Pull local volume discovery yaml data logger.info("Pulling LocalVolumeDiscovery CR data from yaml") lvd_data = templating.load_yaml(constants.LOCAL_VOLUME_DISCOVERY_YAML) # Set local-volume-discovery namespace lvd_data["metadata"]["namespace"] = lso_namespace worker_nodes = get_compute_node_names(no_replace=True) # Update local volume discovery data with Worker node Names logger.info( "Updating LocalVolumeDiscovery CR data with worker nodes Name: %s", worker_nodes, ) lvd_data["spec"]["nodeSelector"]["nodeSelectorTerms"][0][ "matchExpressions"][0]["values"] = worker_nodes lvd_data_yaml = tempfile.NamedTemporaryFile( mode="w+", prefix="local_volume_discovery", delete=False) templating.dump_data_to_temp_yaml(lvd_data, lvd_data_yaml.name) logger.info("Creating LocalVolumeDiscovery CR") run_cmd(f"oc create -f {lvd_data_yaml.name}") # Pull local volume set yaml data logger.info("Pulling LocalVolumeSet CR data from yaml") lvs_data = templating.load_yaml(constants.LOCAL_VOLUME_SET_YAML) # Since we don't have datastore with SSD on our current VMware machines, localvolumeset doesn't detect # NonRotational disk. As a workaround we are setting Rotational to device MechanicalProperties to detect # HDD disk if platform == constants.VSPHERE_PLATFORM or config.ENV_DATA.get( "local_storage_allow_rotational_disks"): logger.info("Adding Rotational for deviceMechanicalProperties spec" " to detect HDD disk") lvs_data["spec"]["deviceInclusionSpec"][ "deviceMechanicalProperties"].append("Rotational") # Update local volume set data with Worker node Names logger.info( "Updating LocalVolumeSet CR data with worker nodes Name: %s", worker_nodes) lvs_data["spec"]["nodeSelector"]["nodeSelectorTerms"][0][ "matchExpressions"][0]["values"] = worker_nodes # Set storage class logger.info( "Updating LocalVolumeSet CR data with LSO storageclass: %s", storageclass) lvs_data["spec"]["storageClassName"] = storageclass # set volumeMode to Filesystem for MCG only deployment if config.ENV_DATA["mcg_only_deployment"]: lvs_data["spec"]["volumeMode"] = constants.VOLUME_MODE_FILESYSTEM lvs_data_yaml = tempfile.NamedTemporaryFile(mode="w+", prefix="local_volume_set", delete=False) templating.dump_data_to_temp_yaml(lvs_data, lvs_data_yaml.name) logger.info("Creating LocalVolumeSet CR") run_cmd(f"oc create -f {lvs_data_yaml.name}") else: # Retrieve NVME device path ID for each worker node device_paths = get_device_paths(worker_names) # Pull local volume yaml data logger.info("Pulling LocalVolume CR data from yaml") lv_data = templating.load_yaml(constants.LOCAL_VOLUME_YAML) # Set local-volume namespace lv_data["metadata"]["namespace"] = lso_namespace # Set storage class logger.info("Updating LocalVolume CR data with LSO storageclass: %s", storageclass) for scd in lv_data["spec"]["storageClassDevices"]: scd["storageClassName"] = storageclass # Update local volume data with NVME IDs logger.info("Updating LocalVolume CR data with device paths: %s", device_paths) lv_data["spec"]["storageClassDevices"][0]["devicePaths"] = device_paths # Create temp yaml file and create local volume lv_data_yaml = tempfile.NamedTemporaryFile(mode="w+", prefix="local_volume", delete=False) templating.dump_data_to_temp_yaml(lv_data, lv_data_yaml.name) logger.info("Creating LocalVolume CR") run_cmd(f"oc create -f {lv_data_yaml.name}") logger.info("Waiting 30 seconds for PVs to create") storage_class_device_count = 1 if platform == constants.AWS_PLATFORM and not lso_type == constants.AWS_EBS: storage_class_device_count = 2 elif platform == constants.IBM_POWER_PLATFORM: numberofstoragedisks = config.ENV_DATA.get("number_of_storage_disks", 1) storage_class_device_count = numberofstoragedisks elif platform == constants.VSPHERE_PLATFORM: # extra_disks is used in vSphere attach_disk() method storage_class_device_count = config.ENV_DATA.get("extra_disks", 1) expected_pvs = len(worker_names) * storage_class_device_count verify_pvs_created(expected_pvs, storageclass)
def setup_local_storage(storageclass): """ Setup the necessary resources for enabling local storage. Args: storageclass (string): storageClassName value to be used in LocalVolume CR based on LOCAL_VOLUME_YAML """ # Get the worker nodes workers = get_nodes(node_type="worker") worker_names = [worker.name for worker in workers] logger.debug("Workers: %s", worker_names) ocp_version = get_ocp_version() ocs_version = config.ENV_DATA.get("ocs_version") ocp_ga_version = get_ocp_ga_version(ocp_version) if not ocp_ga_version: optional_operators_data = templating.load_yaml( constants.LOCAL_STORAGE_OPTIONAL_OPERATORS, multi_document=True ) logger.info( "Creating temp yaml file with optional operators data:\n %s", optional_operators_data, ) optional_operators_yaml = tempfile.NamedTemporaryFile( mode="w+", prefix="optional_operators", delete=False ) templating.dump_data_to_temp_yaml( optional_operators_data, optional_operators_yaml.name ) with open(optional_operators_yaml.name, "r") as f: logger.info(f.read()) logger.info( "Creating optional operators CatalogSource and" " ImageContentSourcePolicy" ) run_cmd(f"oc create -f {optional_operators_yaml.name}") logger.info("Sleeping for 60 sec to start update machineconfigpool status") # sleep here to start update machineconfigpool status time.sleep(60) wait_for_machineconfigpool_status("all") logger.info("Retrieving local-storage-operator data from yaml") lso_data = list( templating.load_yaml(constants.LOCAL_STORAGE_OPERATOR, multi_document=True) ) # ensure namespace is correct lso_namespace = config.ENV_DATA["local_storage_namespace"] for data in lso_data: if data["kind"] == "Namespace": data["metadata"]["name"] = lso_namespace else: data["metadata"]["namespace"] = lso_namespace if data["kind"] == "OperatorGroup": data["spec"]["targetNamespaces"] = [lso_namespace] # Update local-storage-operator subscription data with channel for data in lso_data: if data["kind"] == "Subscription": data["spec"]["channel"] = get_lso_channel() if not ocp_ga_version: if data["kind"] == "Subscription": data["spec"]["source"] = "optional-operators" # Create temp yaml file and create local storage operator logger.info( "Creating temp yaml file with local-storage-operator data:\n %s", lso_data ) lso_data_yaml = tempfile.NamedTemporaryFile( mode="w+", prefix="local_storage_operator", delete=False ) templating.dump_data_to_temp_yaml(lso_data, lso_data_yaml.name) with open(lso_data_yaml.name, "r") as f: logger.info(f.read()) logger.info("Creating local-storage-operator") run_cmd(f"oc create -f {lso_data_yaml.name}") local_storage_operator = ocp.OCP(kind=constants.POD, namespace=lso_namespace) assert local_storage_operator.wait_for_resource( condition=constants.STATUS_RUNNING, selector=constants.LOCAL_STORAGE_OPERATOR_LABEL, timeout=600, ), "Local storage operator did not reach running phase" # Add RDM disk for vSphere platform platform = config.ENV_DATA.get("platform").lower() lso_type = config.DEPLOYMENT.get("type") if platform == constants.VSPHERE_PLATFORM: # Types of LSO Deployment # Importing here to avoid circular dependency from ocs_ci.deployment.vmware import VSPHEREBASE vsphere_base = VSPHEREBASE() if lso_type == constants.RDM: logger.info(f"LSO Deployment type: {constants.RDM}") vsphere_base.add_rdm_disks() if lso_type == constants.VMDK: logger.info(f"LSO Deployment type: {constants.VMDK}") vsphere_base.attach_disk( config.ENV_DATA.get("device_size", defaults.DEVICE_SIZE), config.DEPLOYMENT.get("provision_type", constants.VM_DISK_TYPE), ) if lso_type == constants.DIRECTPATH: raise NotImplementedError( "LSO Deployment for VMDirectPath is not implemented" ) if (ocp_version >= "4.6") and (ocs_version >= "4.6"): # Pull local volume discovery yaml data logger.info("Pulling LocalVolumeDiscovery CR data from yaml") lvd_data = templating.load_yaml(constants.LOCAL_VOLUME_DISCOVERY_YAML) # Set local-volume-discovery namespace lvd_data["metadata"]["namespace"] = lso_namespace worker_nodes = get_compute_node_names(no_replace=True) # Update local volume discovery data with Worker node Names logger.info( "Updating LocalVolumeDiscovery CR data with worker nodes Name: %s", worker_nodes, ) lvd_data["spec"]["nodeSelector"]["nodeSelectorTerms"][0]["matchExpressions"][0][ "values" ] = worker_nodes lvd_data_yaml = tempfile.NamedTemporaryFile( mode="w+", prefix="local_volume_discovery", delete=False ) templating.dump_data_to_temp_yaml(lvd_data, lvd_data_yaml.name) logger.info("Creating LocalVolumeDiscovery CR") run_cmd(f"oc create -f {lvd_data_yaml.name}") # Pull local volume set yaml data logger.info("Pulling LocalVolumeSet CR data from yaml") lvs_data = templating.load_yaml(constants.LOCAL_VOLUME_SET_YAML) # Since we don't have datastore with SSD on our current VMware machines, localvolumeset doesn't detect # NonRotational disk. As a workaround we are setting Rotational to device MechanicalProperties to detect # HDD disk if platform == constants.VSPHERE_PLATFORM or config.ENV_DATA.get( "local_storage_allow_rotational_disks" ): logger.info( "Adding Rotational for deviceMechanicalProperties spec" " to detect HDD disk" ) lvs_data["spec"]["deviceInclusionSpec"][ "deviceMechanicalProperties" ].append("Rotational") # Update local volume set data with Worker node Names logger.info( "Updating LocalVolumeSet CR data with worker nodes Name: %s", worker_nodes ) lvs_data["spec"]["nodeSelector"]["nodeSelectorTerms"][0]["matchExpressions"][0][ "values" ] = worker_nodes # Set storage class logger.info( "Updating LocalVolumeSet CR data with LSO storageclass: %s", storageclass ) lvs_data["spec"]["storageClassName"] = storageclass lvs_data_yaml = tempfile.NamedTemporaryFile( mode="w+", prefix="local_volume_set", delete=False ) templating.dump_data_to_temp_yaml(lvs_data, lvs_data_yaml.name) logger.info("Creating LocalVolumeSet CR") run_cmd(f"oc create -f {lvs_data_yaml.name}") else: # Retrieve NVME device path ID for each worker node device_paths = get_device_paths(worker_names) # Pull local volume yaml data logger.info("Pulling LocalVolume CR data from yaml") lv_data = templating.load_yaml(constants.LOCAL_VOLUME_YAML) # Set local-volume namespace lv_data["metadata"]["namespace"] = lso_namespace # Set storage class logger.info( "Updating LocalVolume CR data with LSO storageclass: %s", storageclass ) for scd in lv_data["spec"]["storageClassDevices"]: scd["storageClassName"] = storageclass # Update local volume data with NVME IDs logger.info("Updating LocalVolume CR data with device paths: %s", device_paths) lv_data["spec"]["storageClassDevices"][0]["devicePaths"] = device_paths # Create temp yaml file and create local volume lv_data_yaml = tempfile.NamedTemporaryFile( mode="w+", prefix="local_volume", delete=False ) templating.dump_data_to_temp_yaml(lv_data, lv_data_yaml.name) logger.info("Creating LocalVolume CR") run_cmd(f"oc create -f {lv_data_yaml.name}") logger.info("Waiting 30 seconds for PVs to create") storage_class_device_count = 1 if platform == constants.AWS_PLATFORM: storage_class_device_count = 2 verify_pvs_created(len(worker_names) * storage_class_device_count)