text: """
  This is plugin for all the plugins/hooks related to OCS-CI and its
  configuration.
  
  The basic configuration is done in run_ocsci.py module casue we need to load
  all the config before pytest run. This run_ocsci.py is just a wrapper for
  pytest which proccess config and passes all params to pytest.
  """
  import logging
  import os
  
  import pytest
  
  from ocs_ci.framework import config as ocsci_config
  from ocs_ci.framework.exceptions import ClusterPathNotProvidedError, ClusterNameNotProvidedError, ClusterNameLengthError
  from ocs_ci.ocs.exceptions import CommandFailed, ResourceNotFoundError
  from ocs_ci.utility.utils import (
      dump_config_to_file,
      get_cluster_version,
      get_ceph_version,
      get_csi_versions,
      get_testrun_name,
      get_ocs_build_number,
      load_config_file,
  )
  from ocs_ci.ocs.utils import collect_ocs_logs, collect_prometheus_metrics
  from ocs_ci.ocs.resources.ocs import get_version_info
  from ocs_ci.ocs.constants import (
      CLUSTER_NAME_MAX_CHARACTERS,
      CLUSTER_NAME_MIN_CHARACTERS,
      OCP_VERSION_CONF_DIR,
  )
  
  __all__ = [
      "pytest_addoption",
  ]
  
  log = logging.getLogger(__name__)
  
  
  def pytest_addoption(parser):
      """
      Add necessary options to initialize OCS CI library.
      """
      parser.addoption(
          '--ocsci-conf',
          dest='ocsci_conf',
          action="append",
          help="Path to config file of OCS CI",
      )
      parser.addoption(
          '--cluster-path',
          dest='cluster_path',
          help="Path to cluster directory",
      )
      parser.addoption(
          '--cluster-name',
          dest='cluster_name',
          help="Name of cluster",
      )
      parser.addoption(
          '--teardown',
          dest='teardown',
          action="store_true",
          default=False,
          help="If provided the test cluster will be destroyed after tests complete",
      )
      parser.addoption(
          '--deploy',
          dest='deploy',
          action="store_true",
          default=False,
          help="If provided a test cluster will be deployed on AWS to use for testing",
      )
      parser.addoption(
          '--live-deploy',
          dest='live_deploy',
          action="store_true",
          default=False,
          help="Deploy OCS from live registry like a customer",
      )
      parser.addoption(
          '--email',
          dest='email',
          help="Email ID to send results",
      )
      parser.addoption(
          '--collect-logs',
          dest='collect-logs',
          action="store_true",
          default=False,
          help="Collect OCS logs when test case failed",
      )
      parser.addoption(
          '--io_in_bg',
          dest='io_in_bg',
          action="store_true",
          default=False,
          help="Run IO in the background",
      )
      parser.addoption(
          '--ocs-version',
          dest='ocs_version',
          help="ocs version for which ocs-ci to be run"
      )
      parser.addoption(
          '--upgrade-ocs-version',
          dest='upgrade_ocs_version',
          help="ocs version to upgrade (e.g. 4.3)"
      )
      parser.addoption(
          '--ocp-version',
          dest='ocp_version',
          help="""
          OCP version to be used for deployment. This version will be used for
          load file from conf/ocp_version/ocp-VERSION-config.yaml. You can use
          for example those values:
          4.2: for nightly 4.2 OCP build
          4.2-ga: for latest GAed 4.2 OCP build
          4.2-ga-minus1: for latest GAed 4.2 build - 1
          """
      )
      parser.addoption(
          '--ocs-registry-image',
          dest='ocs_registry_image',
          help=(
              "ocs registry image to be used for deployment "
              "(e.g. quay.io/rhceph-dev/ocs-olm-operator:latest-4.2)"
          )
      )
      parser.addoption(
          '--upgrade-ocs-registry-image',
          dest='upgrade_ocs_registry_image',
          help=(
              "ocs registry image to be used for upgrade "
              "(e.g. quay.io/rhceph-dev/ocs-olm-operator:latest-4.3)"
          )
      )
      parser.addoption(
          '--osd-size',
          dest='osd_size',
          type=int,
          help="OSD size in GB - for 2TB pass 2048, for 0.5TB pass 512 and so on."
      )
  
  
  def pytest_configure(config):
      """
      Load config files, and initialize ocs-ci library.
  
      Args:
          config (pytest.config): Pytest config object
  
      """
      if not (config.getoption("--help") or config.getoption("collectonly")):
          process_cluster_cli_params(config)
          config_file = os.path.expanduser(
              os.path.join(
                  ocsci_config.RUN['log_dir'],
                  f"run-{ocsci_config.RUN['run_id']}-config.yaml",
              )
          )
          dump_config_to_file(config_file)
          log.info(
              f"Dump of the consolidated config file is located here: "
              f"{config_file}"
          )
          # Add OCS related versions to the html report and remove
          # extraneous metadata
          markers_arg = config.getoption('-m')
          if ocsci_config.RUN['cli_params'].get('teardown') or (
              "deployment" in markers_arg
              and ocsci_config.RUN['cli_params'].get('deploy')
          ):
              log.info(
                  "Skipping versions collecting because: Deploy or destroy of "
                  "cluster is performed."
              )
              return
          elif ocsci_config.ENV_DATA['skip_ocs_deployment']:
              log.info(
                  "Skipping version collection because we skipped "
                  "the OCS deployment"
              )
              return
          print("Collecting Cluster versions")
          # remove extraneous metadata
          del config._metadata['Python']
          del config._metadata['Packages']
          del config._metadata['Plugins']
          del config._metadata['Platform']
  
          config._metadata['Test Run Name'] = get_testrun_name()
          gather_version_info_for_report(config)
  
  
  def gather_version_info_for_report(config):
      """
      This function gather all version related info used for report.
  
      Args:
          config (pytest.config): Pytest config object
      """
      gather_version_completed = False
      try:
          # add cluster version
          clusterversion = get_cluster_version()
          config._metadata['Cluster Version'] = clusterversion
  
          # add ceph version
          ceph_version = get_ceph_version()
          config._metadata['Ceph Version'] = ceph_version
  
          # add csi versions
          csi_versions = get_csi_versions()
          config._metadata['cephfsplugin'] = csi_versions.get('csi-cephfsplugin')
          config._metadata['rbdplugin'] = csi_versions.get('csi-rbdplugin')
  
          # add ocs operator version
          if ocsci_config.REPORTING['us_ds'] == 'DS':
              config._metadata['OCS operator'] = (
                  get_ocs_build_number()
              )
          mods = {}
          mods = get_version_info(
              namespace=ocsci_config.ENV_DATA['cluster_namespace']
          )
          skip_list = ['ocs-operator']
          for key, val in mods.items():
              if key not in skip_list:
                  config._metadata[key] = val.rsplit('/')[-1]
          gather_version_completed = True
      except ResourceNotFoundError as ex:
          log.error(
              "Problem ocurred when looking for some resource! Error: %s",
              ex
          )
      except FileNotFoundError as ex:
          log.error("File not found! Error: %s", ex)
      except CommandFailed as ex:
          log.error("Failed to execute command! Error: %s", ex)
      except Exception as ex:
          log.error("Failed to gather version info! Error: %s", ex)
      finally:
          if not gather_version_completed:
              log.warning(
                  "Failed to gather version details! The report of version might"
                  "not be complete!"
              )
  
  
  def get_cli_param(config, name_of_param, default=None):
      """
      This is helper function which store cli parameter in RUN section in
      cli_params
  
      Args:
          config (pytest.config): Pytest config object
          name_of_param (str): cli parameter name
          default (any): default value of parameter (default: None)
  
      Returns:
          any: value of cli parameter or default value
  
      """
      cli_param = config.getoption(name_of_param, default=default)
      ocsci_config.RUN['cli_params'][name_of_param] = cli_param
      return cli_param
  
  
  def process_cluster_cli_params(config):
      """
      Process cluster related cli parameters
  
      Args:
          config (pytest.config): Pytest config object
  
      Raises:
          ClusterPathNotProvidedError: If a cluster path is missing
          ClusterNameNotProvidedError: If a cluster name is missing
          ClusterNameLengthError: If a cluster name is too short or too long
      """
      cluster_path = get_cli_param(config, 'cluster_path')
      if not cluster_path:
          raise ClusterPathNotProvidedError()
      cluster_path = os.path.expanduser(cluster_path)
      if not os.path.exists(cluster_path):
          os.makedirs(cluster_path)
      # Importing here cause once the function is invoked we have already config
      # loaded, so this is OK to import once you sure that config is loaded.
      from ocs_ci.ocs.openshift_ops import OCP
      OCP.set_kubeconfig(
          os.path.join(cluster_path, ocsci_config.RUN['kubeconfig_location'])
      )
      cluster_name = get_cli_param(config, 'cluster_name')
      ocsci_config.RUN['cli_params']['teardown'] = get_cli_param(config, "teardown", default=False)
      ocsci_config.RUN['cli_params']['deploy'] = get_cli_param(config, "deploy", default=False)
      live_deployment = get_cli_param(config, "live_deploy", default=False)
      ocsci_config.DEPLOYMENT['live_deployment'] = live_deployment or (
          ocsci_config.DEPLOYMENT.get('live_deployment', False)
      )
      ocsci_config.RUN['cli_params']['io_in_bg'] = get_cli_param(config, "io_in_bg", default=False)
      upgrade_ocs_version = get_cli_param(config, "upgrade_ocs_version")
      if upgrade_ocs_version:
          ocsci_config.UPGRADE['upgrade_ocs_version'] = upgrade_ocs_version
      ocs_registry_image = get_cli_param(config, "ocs_registry_image")
      if ocs_registry_image:
          ocsci_config.DEPLOYMENT['ocs_registry_image'] = ocs_registry_image
      upgrade_ocs_registry_image = get_cli_param(config, "upgrade_ocs_registry_image")
      if upgrade_ocs_registry_image:
          ocsci_config.UPGRADE['upgrade_ocs_registry_image'] = upgrade_ocs_registry_image
      ocsci_config.ENV_DATA['cluster_name'] = cluster_name
      ocsci_config.ENV_DATA['cluster_path'] = cluster_path
      get_cli_param(config, 'collect-logs')
      if ocsci_config.RUN.get("cli_params").get("deploy"):
          if not cluster_name:
              raise ClusterNameNotProvidedError()
          if (
              len(cluster_name) < CLUSTER_NAME_MIN_CHARACTERS
              or len(cluster_name) > CLUSTER_NAME_MAX_CHARACTERS
          ):
              raise ClusterNameLengthError(cluster_name)
      if get_cli_param(config, 'email') and not get_cli_param(config, '--html'):
          pytest.exit("--html option must be provided to send email reports")
      get_cli_param(config, '-m')
      osd_size = get_cli_param(config, '--osd-size')
      if osd_size:
          ocsci_config.ENV_DATA['device_size'] = osd_size
      ocp_version = get_cli_param(config, '--ocp-version')
      if ocp_version:
          version_config_file = f"ocp-{ocp_version}-config.yaml"
          version_config_file_path = os.path.join(
              OCP_VERSION_CONF_DIR, version_config_file
          )
          load_config_file(version_config_file_path)
  
  
  def pytest_collection_modifyitems(session, config, items):
      """
      Add Polarion ID property to test cases that are marked with one.
      """
      for item in items:
          try:
              marker = item.get_closest_marker(name="polarion_id")
              if marker:
                  polarion_id = marker.args[0]
                  if polarion_id:
                      item.user_properties.append(
                          ("polarion-testcase-id", polarion_id)
                      )
          except IndexError:
              log.warning(
                  f"polarion_id marker found with no value for "
                  f"{item.name} in {item.fspath}",
                  exc_info=True
              )
  
  
  @pytest.hookimpl(tryfirst=True, hookwrapper=True)
  def pytest_runtest_makereport(item, call):
      outcome = yield
      rep = outcome.get_result()
      # we only look at actual failing test calls, not setup/teardown
      if (
          rep.when == "call"
          and rep.failed
          and ocsci_config.RUN.get('cli_params').get('collect-logs')
      ):
          test_case_name = item.name
          collect_ocs_logs(test_case_name)
  
      # Collect Prometheus metrics if specified in gather_metrics_on_fail marker
      if (
          (rep.when == "setup" or rep.when == "call")
          and rep.failed
          and item.get_closest_marker('gather_metrics_on_fail')
      ):
          metrics = item.get_closest_marker('gather_metrics_on_fail').args
          collect_prometheus_metrics(
              metrics,
              f'{item.name}-{call.when}',
              call.start,
              call.stop
          )
  