### logging related step definitions
# for 4.x we default logging installation is via OLM only

### none configurable, just use default parameters
Given /^logging service has been installed successfully$/ do
  ensure_admin_tagged
  if env.version_cmp('4.5', user: user) < 0
    example_cr = "<%= BushSlicer::HOME %>/testdata/logging/clusterlogging/example.yaml"
  else
    step %Q/the correct directory name of clusterlogging file is stored in the :cl_dir clipboard/
    example_cr = "<%= BushSlicer::HOME %>/testdata/logging/clusterlogging/<%= cb.cl_dir %>/example_indexmanagement.yaml"
  end
  step %Q/logging operators are installed successfully/
  step %Q/I create clusterlogging instance with:/, table(%{
    | remove_logging_pods | false         |
    | crd_yaml            | #{example_cr} |
  })
end

### configurable installation of logging
# available parameters are:
# :keep_installation: true/false   -- keep installation if true
# :crd_yaml  -- http url for logging crd yaml
# operator_group_yaml -- http url for operator group yaml
# :catsrc_logging_yaml] -- http url for catalogsourceconfig for logging
# :catsrc_elasticsearch_yaml] -- http url for catalogsourceconfig for ES
# :sub_logging_yaml  -- http url for logging subscription yaml
# :sub_elasticsearch_yaml -- http url for elastic search yaml
#
Given /^logging operators are installed successfully$/ do
  ensure_admin_tagged
  step %Q/I switch to cluster admin pseudo user/
  step %Q/evaluation of `cluster_version('version').version` is stored in the :ocp_cluster_version clipboard/

  if project('openshift-operators-redhat').exists?
    @result = admin.cli_exec(:label, resource: "namespace", name: "openshift-operators-redhat", key_val: 'openshift.io/cluster-monitoring=true', overwrite: true)
    raise "Can't add label openshift.io/cluster-monitoring=true to namespace openshift-operators-redhat" unless @result[:success]
  else
    eo_namespace_yaml = "#{BushSlicer::HOME}/testdata/logging/eleasticsearch/deploy_via_olm/01_eo-project.yaml"
    @result = admin.cli_exec(:create, f: eo_namespace_yaml)
    raise "Error creating namespace" unless @result[:success]
  end

  #check clusternetwork plugin name
  #if it's redhat/openshift-ovs-multitenant, then execute `oc adm pod-network make-projects-global openshift-operators-redhat`
  if cluster_network("default").exists? && cluster_network('default').plugin_name == "redhat/openshift-ovs-multitenant"
    @result = admin.cli_exec(:oadm_pod_network_make_projects_global, project: "openshift-operators-redhat")
    raise "Error making project/openshift-operators-redhat network global" unless @result[:success]
  end

  step %Q/I use the "openshift-operators-redhat" project/
  unless deployment('elasticsearch-operator').exists?
    unless operator_group('openshift-operators-redhat').exists?
      # Create operator group in `openshift-operators-redhat` namespace
      eo_operator_group_yaml ||= "#{BushSlicer::HOME}/testdata/logging/eleasticsearch/deploy_via_olm/02_eo-og.yaml"
      @result = admin.cli_exec(:create, f: eo_operator_group_yaml)
      raise "Error creating operatorgroup" unless @result[:success]
    end

    unless role_binding('prometheus-k8s').exists? || env.version_gt('4.6', user: user)
      # create RBAC object in `openshift-operators-redhat` namespace
      rbac_yaml ||= "#{BushSlicer::HOME}/testdata/logging/eleasticsearch/deploy_via_olm/03_eo-rbac.yaml"
      @result = admin.cli_exec(:create, f: rbac_yaml)
      raise "Error creating rolebinding" unless @result[:success]
    end

    unless subscription('elasticsearch-operator').exists?
      step %Q/I use the "openshift-marketplace" project/
      # first check packagemanifest exists for elasticsearch-operator
      raise "Required packagemanifest 'elasticsearch-operator' no found!" unless package_manifest('elasticsearch-operator').exists?
      step %Q/elasticsearch-operator catalog source name is stored in the :eo_catsrc clipboard/
      step %Q/elasticsearch-operator channel name is stored in the :eo_channel clipboard/
      step %Q/I use the "openshift-operators-redhat" project/
      if cb.ocp_cluster_version.include? "4.1."
        # create catalogsourceconfig and subscription for elasticsearch-operator
        catsrc_elasticsearch_yaml ||= "#{BushSlicer::HOME}/testdata/logging/eleasticsearch/deploy_via_olm/4.1/04_eo-csc.yaml"
        @result = admin.cli_exec(:create, f: catsrc_elasticsearch_yaml)
        raise "Error creating catalogsourceconfig for elasticsearch" unless @result[:success]
        sub_elasticsearch_yaml ||= "#{BushSlicer::HOME}/testdata/logging/eleasticsearch/deploy_via_olm/4.1/05_eo-sub.yaml"
        @result = admin.cli_exec(:create, f: sub_elasticsearch_yaml)
        raise "Error creating subscription for elasticsearch" unless @result[:success]
      else
        # create subscription in "openshift-operators-redhat" namespace:
        sub_elasticsearch_yaml ||= "#{BushSlicer::HOME}/testdata/logging/eleasticsearch/deploy_via_olm/04_eo-sub-template.yaml"
        step %Q/I process and create:/, table(%{
          | f | #{sub_elasticsearch_yaml} |
          | p | SOURCE=#{cb.eo_catsrc}    |
          | p | CHANNEL=#{cb.eo_channel}  |
        })
        raise "Error creating subscription for elasticsearch" unless @result[:success]
      end
    end
  end
  # check csv existense
  success = wait_for(300, interval: 10) {
    csv = subscription('elasticsearch-operator').current_csv
    !(csv.nil?) && cluster_service_version(csv).exists?
  }
  raise "CSV #{csv} isn't created" unless success
  step %Q/elasticsearch operator is ready/

  # Create namespace
  if project('openshift-logging').exists?
    @result = admin.cli_exec(:label, resource: "namespace", name: "openshift-logging", key_val: 'openshift.io/cluster-monitoring=true', overwrite: true)
    raise "Can't add label openshift.io/cluster-monitoring=true to namespace openshift-logging" unless @result[:success]
  else
    namespace_yaml = "#{BushSlicer::HOME}/testdata/logging/clusterlogging/deploy_clo_via_olm/01_clo_ns.yaml"
    @result = admin.cli_exec(:create, f: namespace_yaml)
    raise "Error creating namespace" unless @result[:success]
  end

  step %Q/I use the "openshift-logging" project/
  unless deployment('cluster-logging-operator').exists?
    step %Q/I use the "openshift-marketplace" project/
    # first check packagemanifest exists for cluster-logging
    raise "Required packagemanifest 'cluster-logging' no found!" unless package_manifest('cluster-logging').exists?
    step %Q/cluster-logging catalog source name is stored in the :clo_catsrc clipboard/
    step %Q/cluster-logging channel name is stored in the :clo_channel clipboard/

    step %Q/I use the "openshift-logging" project/
    unless operator_group('openshift-logging').exists?
      # start from logging 5.8, deploy CLO to watch all namespaces
      if cb.clo_channel == "stable" || ((cb.clo_channel.include? "-") && (cb.clo_channel.split('-')[1].split('.')[0].to_i >= 5) && (cb.clo_channel.split('-')[1].split('.')[1].to_i >=8))
        clo_operator_group_yaml = "#{BushSlicer::HOME}/testdata/logging/clusterlogging/deploy_clo_via_olm/02_clo_og_all_namespaces.yaml"
      else
        clo_operator_group_yaml = "#{BushSlicer::HOME}/testdata/logging/clusterlogging/deploy_clo_via_olm/02_clo_og.yaml"
      end
      @result = admin.cli_exec(:create, f: clo_operator_group_yaml)
      raise "Error creating operatorgroup" unless @result[:success]
    end

    unless subscription('cluster-logging').exists?
      step %Q/I use the "openshift-logging" project/
      if cb.ocp_cluster_version.include? "4.1."
        # create catalogsourceconfig and subscription for cluster-logging-operator
        catsrc_logging_yaml ||= "#{BushSlicer::HOME}/testdata/logging/clusterlogging/deploy_clo_via_olm/4.1/03_clo_csc.yaml"
        @result = admin.cli_exec(:create, f: catsrc_logging_yaml)
        raise "Error creating catalogsourceconfig for cluster_logging" unless @result[:success]
        sub_logging_yaml ||= "#{BushSlicer::HOME}/testdata/logging/clusterlogging/deploy_clo_via_olm/4.1/04_clo_sub.yaml"
        @result = admin.cli_exec(:create, f: sub_logging_yaml)
        raise "Error creating subscription for cluster_logging" unless @result[:success]
      else
        # create subscription in `openshift-logging` namespace:
        sub_logging_yaml ||= "#{BushSlicer::HOME}/testdata/logging/clusterlogging/deploy_clo_via_olm/03_clo_sub.yaml"
        step %Q/I process and create:/, table(%{
          | f | #{sub_logging_yaml}       |
          | p | SOURCE=#{cb.clo_catsrc}   |
          | p | CHANNEL=#{cb.clo_channel} |
        })
        raise "Error creating subscription for cluster_logging" unless @result[:success]
      end
    end
  end
  # check csv existense
  success = wait_for(300, interval: 10) {
    csv = subscription('cluster-logging').current_csv
    !(csv.nil?) && cluster_service_version(csv).exists?
  }
  raise "CSV #{csv} isn't created" unless success
  step %Q/cluster logging operator is ready/
end

## To check cluserlogging is working correctly, we check all of the subcomponents' status
#  The list of components currently are: ["collection", "curation", "logStore",  "visualization"]
Given /^I wait for clusterlogging(?: named "(.+)")? to be functional in the#{OPT_QUOTED} project$/ do | logging_name, proj_name |
  ensure_admin_tagged
  cb.target_proj ||= 'openshift-logging'
  proj_name = cb.target_proj if proj_name.nil?
  org_proj_name = project.name
  logging_name ||= 'instance'

  step %Q/I switch to cluster admin pseudo user/
  step %Q/I use the "#{proj_name}" project/

  # log the clusterlogging and elasticsearch status before checking logging pods' status.
  raise "Can't find clusterlogging/instance or elasticsearch/elasticsearch, please check if logging stack is deployed or not" unless cluster_logging("instance").exists? && elasticsearch("elasticsearch").exists?

  cb.cluster_logging ||= cluster_logging(logging_name)
  cl = cb.cluster_logging
  logger.info("### checking logging subcomponent status")

  # check elasticsearch subcomponent is ready
  logger.info("### checking logging subcomponent status: elasticsearch")
  step %Q/a pod becomes ready with labels:/, table(%{
    | component=elasticsearch |
  })
  cl.wait_until_es_is_ready

  # check log collector is ready.
  logger.info("### checking logging subcomponent status: log collector")
  step %Q/logging collector name is stored in the :collector_name clipboard/
  step %Q/a pod becomes ready with labels:/, table(%{
    | component=#{cb.collector_name} |
  })
  cl.wait_until_fluentd_is_ready

  logger.info("### checking logging subcomponent status: kibana")
  step %Q/a pod becomes ready with labels:/, table(%{
    | component=kibana |
  })
  cl.wait_until_kibana_is_ready
  # check the cronjob curator.
  if env.version_lt('4.5', user: user)
    raise "Failed to find cronjob for curator" unless cron_job('curator').exists?
  end

  # check the cronjob index management
  if env.version_gt('4.4', user: user)
    cj_names = ["elasticsearch-im-app", "elasticsearch-im-audit", "elasticsearch-im-infra"]
    for cj_name in cj_names do
      raise "Failed to find cronjob for #{cj_name}" unless cron_job(cj_name).exists?
    end
  end
end

# to cleanup OLM installed clusterlogging
Given /^logging service is removed successfully$/ do
  ensure_admin_tagged
  # remove namespace
  clo_proj_name = "openshift-logging"
  step %Q/I switch to cluster admin pseudo user/
  if project(clo_proj_name).exists?
    @result = admin.cli_exec(:delete, object_type: 'project', object_name_or_id: clo_proj_name, n: clo_proj_name)
    raise "Unable to delete #{clo_proj_name}" unless @result[:success]
    step %Q/I wait for the resource "project" named "#{clo_proj_name}" to disappear/
  end
  eo_proj_name = "openshift-operators-redhat"
  if project(eo_proj_name).exists?
    @result = admin.cli_exec(:delete, object_type: 'project', object_name_or_id: eo_proj_name, n: eo_proj_name)
    raise "Unable to delete #{eo_proj_name}" unless @result[:success]
    step %Q/I wait for the resource "project" named "#{eo_proj_name}" to disappear/
  end

  # remove catalogsourceconfigs if ocp cluster version is 4.1
  step %Q/evaluation of `cluster_version('version').version` is stored in the :ocp_cluster_version clipboard/
  if cb.ocp_cluster_version.include? "4.1."
    csc_logging_name = "cluster-logging-operator"
    csc_elasticsearch_name = "elasticsearch"
    @result = admin.cli_exec(:delete, object_type: 'csc', object_name_or_id: csc_logging_name, n: 'openshift-marketplace')
    @result = admin.cli_exec(:delete, object_type: 'csc', object_name_or_id: csc_elasticsearch_name, n: 'openshift-marketplace')
    step %Q/I use the "openshift-marketplace" project/
    step %Q/I wait for the resource "csc" named "#{csc_logging_name}" to disappear/
    step %Q/I wait for the resource "csc" named "#{csc_elasticsearch_name}" to disappear/
  end
end

Given /^I wait until fluentd is ready$/ do
  step %Q/logging collector name is stored in the :collector_name clipboard/
  step %Q/I wait for the "<%= cb.collector_name %>" daemon_set to appear up to 300 seconds/
  success = wait_for(180, interval: 10) {
    daemon_set(cb.collector_name).replica_counters(cached:false)[:desired]>0 && daemon_set(cb.collector_name).replica_counters[:desired]==daemon_set(cb.collector_name).replica_counters[:ready] && daemon_set(cb.collector_name).replica_counters[:desired]==daemon_set(cb.collector_name).replica_counters[:updated_scheduled]
  }
  raise "the collector pods are not ready" unless success

  step %Q/#{daemon_set("#{cb.collector_name}").replica_counters[:desired]} pods become ready with labels:/, table(%{
    | logging-infra=#{cb.collector_name} |
  })
end

Given /^I wait until ES cluster is ready$/ do
  step %Q/#{cluster_logging('instance').logstore_node_count.to_i} pods become ready with labels:/, table(%{
    | cluster-name=elasticsearch,component=elasticsearch |
  })
end

Given /^I wait until kibana is ready$/ do
  step %Q/#{deployment('kibana').replica_counters[:desired]} pods become ready with labels:/, table(%{
    | component=kibana |
  })
end

Given /^cluster logging operator is ready$/ do
  ensure_admin_tagged
  step %Q/I use the "openshift-logging" project/
  step %Q/a pod becomes ready with labels:/, table(%{
    | name=cluster-logging-operator |
  })
end

Given /^elasticsearch operator is ready(?: in the "(.+)" namespace)?$/ do | proj_name |
  ensure_admin_tagged
  if proj_name
    target_namespace = proj_name
  else
    target_namespace = "openshift-operators-redhat"
  end
  step %Q/I use the "#{target_namespace}" project/
  step %Q/a pod becomes ready with labels:/, table(%{
    | name=elasticsearch-operator |
  })
end

Given /^I create clusterlogging instance with:$/ do | table |
  opts = opts_array_to_hash(table.raw)
  ensure_admin_tagged
  step %Q/I switch to cluster admin pseudo user/
  step %Q/I use the "openshift-logging" project/
  crd_yaml = opts[:crd_yaml]
  storage_class = opts[:storage_class]
  storage_size = opts[:storage_size]
  es_node_count = opts[:es_node_count]
  redundancy_policy = opts[:redundancy_policy]
  if opts[:check_status].nil?
    check_status = 'true'
  else
    check_status = opts[:check_status]
  end

  if cluster_logging("instance").exists?
    step %Q/I delete the clusterlogging instance/
  end

  if !(storage_size.nil? && storage_class.nil?)
    process_opts=[
      ["f", "#{crd_yaml}"],
      ["n", "openshift-logging"]
    ]
    if !(storage_class.nil?)
      process_opts << ["p", "STORAGE_CLASS=#{storage_class}"]
    end
    if !(storage_size.nil?)
      process_opts << ["p", "PVC_SIZE=#{storage_size}"]
    end
    if !(es_node_count.nil?)
      process_opts << ["p", "ES_NODE_COUNT=#{es_node_count}"]
    end
    if !(redundancy_policy.nil?)
      process_opts << ["p", "REDUNDANCY_POLICY=#{redundancy_policy}"]
    end

    p_opts = opts_array_process(process_opts)
    p_opts << [:_stderr, :stderr]
    @result = admin.cli_exec(:process, p_opts)
    if @result[:success]
      @result = admin.cli_exec(:create, {f: "-", _stdin: @result[:stdout]})
    end
  else
    @result = admin.cli_exec(:create, f: crd_yaml, n: "openshift-logging")
  end

  raise "Unable to create clusterlogging instance" unless @result[:success]
  if opts[:remove_logging_pods] == 'true'
    teardown_add {
      step %Q/I delete the clusterlogging instance/
    }
  end
  step %Q/I wait for the "instance" clusterloggings to appear up to 300 seconds/
  if check_status == 'true'
    unless cluster_logging("instance").log_store_spec.nil?
      step %Q/I wait for the "elasticsearch" elasticsearches to appear up to 300 seconds/
      step %Q/I wait until ES cluster is ready/
    end
    unless  cluster_logging("instance").visualization_spec.nil?
      step %Q/I wait for the "kibana" deployment to appear up to 300 seconds/
      step %Q/I wait until kibana is ready/
    end
    unless cluster_logging('instance').collection_spec.nil?
      step %Q/I wait until fluentd is ready/
    end
  end
end

Given /^I delete the clusterlogging instance$/ do
  ensure_admin_tagged
  step %Q/I switch to cluster admin pseudo user/
  step %Q/I use the "openshift-logging" project/

  if cluster_logging("instance").exists?
    @result = admin.cli_exec(:delete, object_type: 'clusterlogging', object_name_or_id: 'instance', n: 'openshift-logging')
    raise "Unable to delete instance" unless @result[:success]
    unless cluster_logging("instance").log_store_spec(cached: true).nil?
      step %Q/I wait for the resource "elasticsearch" named "elasticsearch" to disappear/
      success = wait_for(180, interval: 10) {
        res = admin.cli_exec(:get, resource: "deploy", l: "cluster-name=elasticsearch", n: "openshift-logging")
        case res[:response]
        # the resource has terminated which means we are done waiting.
        when /No resources found/
          break true
        end
      }
      raise "the ES deployment did not terminate" unless success
      if BushSlicer::PersistentVolumeClaim.list(user: user, project: project).count > 0
        admin.cli_exec(:delete, object_type: 'pvc', l: 'logging-cluster=elasticsearch', n: 'openshift-logging')
      end
    end
    unless  cluster_logging("instance").visualization_spec(cached: true).nil?
      step %Q/I wait for the resource "deployment" named "kibana" to disappear/
    end
      step %Q/logging collector name is stored in the :collector_name clipboard/
    unless cluster_logging('instance').collection_spec(cached: true).nil?
      step %Q/admin ensures "#{cb.collector_name}" ds is deleted/
    end
  end
end

Given /^(cluster-logging|elasticsearch-operator) channel name is stored in the#{OPT_SYM} clipboard$/ do | packagemanifest, cb_name |
  cb_name = 'channel' unless cb_name
  logging_envs = env.logging_envs
  unless logging_envs.empty?
    case packagemanifest
    when "cluster-logging"
      envs = logging_envs[:clo]
    when "elasticsearch-operator"
      envs = logging_envs[:eo]
    end
  end
  step %Q/I use the "openshift-marketplace" project/
  # check if the packagemanifest exist
  raise "Packagemanifest #{packagemanifest} doesn't exist" unless package_manifest(packagemanifest).exists?

  if (logging_envs.empty?) || (envs.nil?) || (envs[:channel].nil?)
    version = cluster_version('version').version.split('-')[0].split('.').take(2).join('.')
    case version
    when '4.15'
      cb[cb_name] = "stable"
    when '4.14'
      cb[cb_name] = "stable-5.8"
    when '4.13'
      cb[cb_name] = "stable-5.7"
    when '4.12'
      cb[cb_name] = "stable-5.6"
    when '4.11'
      cb[cb_name] = "stable-5.5"
    when '4.10'
      cb[cb_name] = "stable-5.4"
    when '4.9'
      cb[cb_name] = "stable-5.3"
    when '4.8'
      cb[cb_name] = "stable-5.2"
    when '4.7'
      cb[cb_name] = "stable-5.1"
    when '4.2','4.3','4.4','4.5','4.6'
      cb[cb_name] = version
    when '4.1'
      cb[cb_name] = "preview"
    else
      cb[cb_name] = "stable"
    end
  else
    cb[cb_name] = envs[:channel]
  end
end

Given /^(cluster-logging|elasticsearch-operator) catalog source name is stored in the#{OPT_SYM} clipboard$/ do | packagemanifest, cb_name |
  cb_name = 'source' unless cb_name
  logging_envs = env.logging_envs
  unless logging_envs.empty?
    case packagemanifest
    when "cluster-logging"
      envs = logging_envs[:clo]
    when "elasticsearch-operator"
      envs = logging_envs[:eo]
    end
  end
  step %Q/I use the "openshift-marketplace" project/
  # check if the packagemanifest exist
  raise "Packagemanifest #{packagemanifest} doesn't exist" unless package_manifest(packagemanifest).exists?

  # get source name, if it's not set, use default source
  if (logging_envs.empty?) || (envs.nil?) || (envs[:catsrc].nil?)
    if catalog_source("qe-app-registry").exists?
      cb[cb_name] = "qe-app-registry"
    elsif catalog_source("redhat-operators").exists?
      cb[cb_name] = "redhat-operators"
    else
      cb[cb_name] = package_manifest(packagemanifest).catalog_source
    end
  else
    #raise "The specified catalog source doesn't exist" unless catalog_source(envs[:catsrc]).exists?
    cb[cb_name] = envs[:catsrc]
  end
end

Given /^the logging operators are redeployed after scenario$/ do
  _admin = admin
  teardown_add {
    step %Q/logging operators are installed successfully/
  }
end

# from logging 4.5, we don't have index project.$project-name.xxxxx, so we need other ways to check the project logs
# es_util --query=*/_count -d '{"query": {"match": {"kubernetes.namespace_name": "project-name"}}}'
# if count > 0, then the project logs are received
When /^I wait(?: (\d+) seconds)? for the project #{QUOTED} logs to appear in the ES pod(?: with labels #{QUOTED})?$/ do |seconds, project_name, pod_labels|
  if pod_labels
    labels = pod_labels
  else
    labels = "es-node-master=true"
  end
  step %Q/a pod becomes ready with labels:/, table(%{
    | #{labels} |
  })

  seconds = Integer(seconds) unless seconds.nil?
  seconds ||= 10 * 60
  success = wait_for(seconds) {
    step %Q/I perform the HTTP request on the ES pod with labels "#{labels}":/, table(%{
      | relative_url | */_count?format=JSON' -d '{"query": {"match": {"kubernetes.namespace_name": "#{project_name}"}}} |
      | op           | GET                                                                                              |
    })
    res = @result[:parsed]
    if res
      res['count'] > 0
    end
  }
  cb.doc_count = @result[:parsed]['count']
  raise "Can't find logs from project '#{project_name}' in #{seconds} seconds" unless success
end

Given /^logging eventrouter is installed in the cluster$/ do
  step %Q/admin ensures "event-reader" cluster_role is deleted after scenario/
  step %Q/admin ensures "event-reader-binding" cluster_role_binding is deleted after scenario/
  step %Q/admin ensures "eventrouter" service_account is deleted from the "openshift-logging" project after scenario/
  step %Q/admin ensures "eventrouter" config_map is deleted from the "openshift-logging" project after scenario/
  step %Q/admin ensures "eventrouter" deployment is deleted from the "openshift-logging" project after scenario/
  clo_csv_version = subscription("cluster-logging").current_csv(cached: false)
  clo_version = clo_csv_version.split(".", 2).last.split(/[A-Za-z]/).last
  if clo_version.start_with?("5")
    # from logging 5.0, the image name is changed to eventrouter-rhel8
    image_name = "eventrouter-rhel8"
  else
    image_name = "logging-eventrouter"
  end

  image_version = ""
  # for logging 5.2 and later, use image tag v0.3.0/v0.4.0
  if (clo_version.include? "5.7") || (clo_version.include? "5.6") || (clo_version.include? "5.5") || (clo_version.include? "5.4")
    image_version = "0.4.0"
  elsif (clo_version.include? "5.3") || (clo_version.include? "5.2")
    image_version = "0.3.0"
  else
    image_version = clo_version
  end

  # get image registry from CLO
  clo_image = deployment('cluster-logging-operator').container_spec(name: 'cluster-logging-operator').image
  registry = clo_image.split(/cluster-logging(.*)/)[0]
  image = "#{registry}#{image_name}:v#{image_version}"

  step %Q/I process and create:/, table(%{
    | f | #{BushSlicer::HOME}/testdata/logging/eventrouter/internal_eventrouter.yaml |
    | p | IMAGE=#{image} |
  })
  step %Q/the step should succeed/
  step %Q/a pod becomes ready with labels:/, table(%{
    | component=eventrouter |
  })
end

Given /^I generate certs for the#{OPT_QUOTED} receiver(?: in the#{OPT_QUOTED} project)?$/ do | receiver_name, project_name |
  script_file = "#{BushSlicer::HOME}/testdata/logging/logforwarding/cert_generation.sh"
  project_name ||= "openshift-logging"
  #step %Q/I download a file from "#{script_file}"/
  shell_cmd = "sh #{script_file} $(pwd) #{project_name} #{receiver_name}"
  system(shell_cmd)
end

Given /^I create a pipeline secret with:$/ do | table |
  opts = opts_array_to_hash(table.raw)
  secret_name = opts[:secret_name]
  username = opts[:username]
  password = opts[:password]
  client_auth = opts[:client_auth]
  user_auth_enabled = opts[:user_auth_enabled]
  http_ssl_enabled = opts[:http_ssl_enabled]
  shared_key = opts[:shared_key]
  auth_type = opts[:auth_type]
  #require 'pry'
  #binding.pry
  unless tagged_upgrade? || secret_name.empty? || secret_name.nil?
    step %Q/admin ensures "#{secret_name}" secret is deleted from the "openshift-logging" project after scenario/
  end

  secret_keys = [
    ["name", "#{secret_name}"],
    ["secret_type", "generic"],
    ["n", "openshift-logging"]
  ]

  if client_auth == "true" || auth_type == "mTLS" || auth_type == "mTLS_share"
    secret_keys << ["from_file", "tls.key=logging-es.key"] << ["from_file", "tls.crt=logging-es.crt"] << ["from_file", "ca-bundle.crt=ca.crt"]
  end

  if user_auth_enabled == "true"
    secret_keys << ["from_literal", "username=#{username}"] << ["from_literal", "password=#{password}"]
  end

  if http_ssl_enabled == "true" || auth_type == "server_auth" || auth_type == "server_auth_share"
    secret_keys << ["from_file", "ca-bundle.crt=ca.crt"]
  end

  if auth_type == "mTLS_share" || auth_type == "server_auth_share"
    raise "No shared_key specified" unless !(shared_key.empty? || shared_key.nil?)
    secret_keys << ["from_literal", "shared_key=#{shared_key}"]
  end

  @result = admin.cli_exec(:create_secret, opts_array_process(secret_keys.uniq))
  raise "Unable to create secret #{secret_name}" unless @result[:success]
end

Given /^I create the resources for the receiver with:$/ do | table |
  org_user = user
  opts = opts_array_to_hash(table.raw)
  namespace = opts[:namespace]
  receiver_name = opts[:receiver_name]
  configmap_file = opts[:configmap_file]
  deployment_file = opts[:deployment_file]
  pod_label = opts[:pod_label]
  step %Q/I use the "#{namespace}" project/

  unless tagged_upgrade?
    step %Q/I ensure "#{receiver_name}" config_map is deleted from the "#{namespace}" project after scenario/
    step %Q/I ensure "#{receiver_name}" deployment is deleted from the "#{namespace}" project after scenario/
    step %Q/I ensure "#{receiver_name}" service is deleted from the "#{namespace}" project after scenario/
  end

  files = [configmap_file, deployment_file]
  for file in files do
    @result = user.cli_exec(:create, f: file, n: namespace)
    raise "Unable to create resoure with #{file}" unless @result[:success]
  end

  if receiver_name == "rsyslogserver"
    svc_file = "#{BushSlicer::HOME}/testdata/logging/logforwarding/rsyslog/rsyslogserver_svc.yaml"
    @result = user.cli_exec(:create, f: svc_file, n: namespace)
    raise "Unable to expose the service for rsyslog server" unless @result[:success]
  else
    @result = user.cli_exec(:expose, name: receiver_name, resource: 'deployment', resource_name: receiver_name, namespace: namespace)
    raise "Unable to expose the service for #{receiver_name}" unless @result[:success]
  end

  step %Q/a pod becomes ready with labels:/, table(%{
    | #{pod_label} |
  })

  step %Q/evaluation of `pod` is stored in the :log_receiver clipboard/
end

Given /^(fluentd|rsyslog) receiver is deployed as (secure|insecure)(?: with (mTLS|mTLS_share|server_auth|server_auth_share) enabled)?(?: in the#{OPT_QUOTED} project)?$/ do | server, security, auth_type, project_name |
  project_name ||= "openshift-logging"
  step %Q/I use the "#{project_name}" project/
  if env.version_lt('4.6', user: user)
    file_dir = "#{BushSlicer::HOME}/testdata/logging/logforwarding"
  else
    file_dir = "#{BushSlicer::HOME}/testdata/logging/clusterlogforwarder"
  end
  case server
  when "fluentd"
    receiver_name = "fluentdserver"
    pod_label = "logging-infra=fluentdserver"
    if security == "secure"
      step %Q/I generate certs for the "fluentdserver" receiver in the "<%= project.name %>" project/
      unless tagged_upgrade?
        step %Q/I ensure "fluentdserver" secret is deleted from the "<%= project.name %>" project after scenario/
      end
      # create secret/fluentdserver for fluentd server pod
      step %Q/I run the :create_secret client command with:/, table(%{
        | name         | fluentdserver            |
        | secret_type  | generic                  |
        | from_file    | tls.key=logging-es.key   |
        | from_file    | tls.crt=logging-es.crt   |
        | from_file    | ca-bundle.crt=ca.crt     |
        | from_file    | ca.key=ca.key            |
        | from_literal | shared_key=fluentdserver |
        | n            | #{project_name}          |
      })
      step %Q/I create a pipeline secret with:/, table(%{
        | secret_name | pipelinesecret |
        | auth_type   | #{auth_type}   |
        | shared_key  | fluentdserver  |
      })
      step %Q/the step should succeed/
      # set configmap and create pipeline secret in openshift-logging project
      case auth_type
      when "mTLS_share"
        configmap_file = "#{file_dir}/fluentd/secure/cm-mtls-share.yaml"
      when "mTLS"
        configmap_file = "#{file_dir}/fluentd/secure/cm-mtls.yaml"
      when "server_auth"
        configmap_file = "#{file_dir}/fluentd/secure/cm-serverauth.yaml"
      when "server_auth_share"
        configmap_file = "#{file_dir}/fluentd/secure/cm-serverauth-share.yaml"
      else
        raise "Unrecognized auth type: #{auth_type}"
      end
      deployment_file = "#{file_dir}/fluentd/secure/deployment.yaml"
    else
      configmap_file = "#{file_dir}/fluentd/insecure/configmap.yaml"
      deployment_file = "#{file_dir}/fluentd/insecure/deployment.yaml"
    end

  when "rsyslog"
    receiver_name = "rsyslogserver"
    pod_label = "component=rsyslogserver"
    configmap_file = "#{file_dir}/rsyslog/insecure/rsyslogserver_configmap.yaml"
    deployment_file = "#{file_dir}/rsyslog/insecure/rsyslogserver_deployment.yaml"
  else
    raise "Unrecognized server: #{server}"
  end

  step %Q/I create the resources for the receiver with:/, table(%{
    | namespace       | #{project_name}    |
    | receiver_name   | #{receiver_name}   |
    | configmap_file  | #{configmap_file}  |
    | deployment_file | #{deployment_file} |
    | pod_label       | #{pod_label}       |
  })
end

# upgrade operator and check the EFK pods status
Given /^I upgrade the operator with:$/ do | table |
  opts = opts_array_to_hash(table.raw)
  subscription = opts[:subscription]
  channel = opts[:channel]
  catsrc = opts[:catsrc]
  namespace = opts[:namespace]
  step %Q/I use the "#{namespace}" project/

  pre_csv = subscription(subscription).current_csv
  # upgrade operator
  patch_json = {"spec": {"channel": "#{channel}", "source": "#{catsrc}"}}
  patch_opts = {resource: "subscription", resource_name: subscription, p: patch_json.to_json, n: namespace, type: "merge"}
  @result = admin.cli_exec(:patch, **patch_opts)
  raise "Patch failed with #{@result[:response]}" unless @result[:success]
  # wait till new csv to be installed
  success = wait_for(180, interval: 10) {
    if channel != "stable"
      (subscription(subscription).installplan_csv.include? channel) || (subscription(subscription).installplan_csv.include? (channel.split('-')[1]))
    else
      subscription(subscription).installplan_csv != pre_csv
    end
  }
  raise "the new CSV can't be installed" unless success
  # wait till new csv is ready
  success = wait_for(600, interval: 10) {
    new_csv = subscription(subscription).current_csv(cached: false)
    cluster_service_version(new_csv).ready?[:success]
  }
  raise "can't upgrade operator #{subscription}" unless success

  #check if the EFK pods could be upgraded successfully
  step %Q/I use the "openshift-logging" project/
  if cluster_logging('instance').log_store_spec != nil
    if elasticsearch('elasticsearch').exists?
      if subscription == "elasticsearch-operator"
        # check if the ES cluster could be upgraded
        success = wait_for(300, interval: 10) {
          elasticsearch('elasticsearch').nodes_status[0]["upgradeStatus"]["scheduledUpgrade"]
        }
        raise "Can't upgrade the ES cluster" unless success
      end
      # wait for the ES cluster to be ready
      success = wait_for(600, interval: 10) {
        esPods = BushSlicer::Pod.get_labeled("component=elasticsearch", project: project, user: user, quiet: true).map(&:name)
        unless (elasticsearch('elasticsearch').es_master_ready_pod_names.nil?) || (elasticsearch('elasticsearch').es_client_ready_pod_names.nil?) || (elasticsearch('elasticsearch').es_data_ready_pod_names.nil?)
          readyPods = (elasticsearch('elasticsearch').es_master_ready_pod_names + elasticsearch('elasticsearch').es_client_ready_pod_names(cached: true) + elasticsearch('elasticsearch').es_data_ready_pod_names(cached:true)).uniq
          elasticsearch('elasticsearch').cluster_health == "green" && (esPods - readyPods).blank? && (readyPods - esPods).blank?
        end
      }
      raise "ES cluster isn't in a good status" unless success
      # check pvc count
      unless BushSlicer::PersistentVolumeClaim.list(user: user, project: project).count == cluster_logging('instance').logstore_node_count
        raise "The PVC count doesn't match the ES node count"
      end
    else
      raise "The elasticsearch/elasticsearch is not created"
    end
  end

  # check the kibana status
  if cluster_logging('instance').visualization_spec != nil
    if deployment('kibana').exists?
      success = wait_for(300, interval: 10) {
        (deployment('kibana').replica_counters(cached: false)[:desired] == deployment('kibana').replica_counters(cached: false)[:updated]) &&
        (deployment('kibana').replica_counters(cached: false)[:desired] == deployment('kibana').replica_counters(cached: false)[:available])
      }
      raise "Kibana isn't in a good status" unless success
    else
      raise "Deployment/kibana does not exist"
    end
  end


  step %Q/logging collector name is stored in the :collector_name clipboard/
  # check fluentd status
  if cluster_logging('instance').collection_spec != nil
    if daemon_set("#{cb.collector_name}").exists?
      success = wait_for(300, interval: 10) {
        (daemon_set("#{cb.collector_name}").replica_counters(cached: false)[:desired] == daemon_set("#{cb.collector_name}").replica_counters(cached: false)[:updated_scheduled]) &&
        (daemon_set("#{cb.collector_name}").replica_counters(cached: false)[:desired] == daemon_set("#{cb.collector_name}").replica_counters(cached: false)[:available])
      }
      raise "the collector fluentd isn't in a good status" unless success
    else
      raise "Daemonset/#{cb.collector_name} doesn't exist"
    end
  end
end

# only check the major version, such as 4.4, 4.5, 4.6, don't care about versions like 4.6.0-2020xxxxxxxx
Given /^I make sure the logging operators match the cluster version$/ do
  step %Q/I switch to cluster admin pseudo user/
  # check if channel name in subscription is same to the target channel
  step %Q/cluster-logging channel name is stored in the :clo_channel clipboard/
  step %Q/elasticsearch-operator channel name is stored in the :eo_channel clipboard/
  step %Q/elasticsearch-operator catalog source name is stored in the :eo_catsrc clipboard/
  step %Q/cluster-logging catalog source name is stored in the :clo_catsrc clipboard/
  # check EO
  step %Q/I use the "openshift-operators-redhat" project/
  eo_current_channel = subscription("elasticsearch-operator").channel(cached: false)
  eo_current_catsrc = subscription("elasticsearch-operator").source
  # in https://gitlab.cee.redhat.com/aosqe/jenkins-jcasc-n/-/blob/master/scripts/OCPQE-11466/upgrade_cluster_logging.sh#L9-10
  # the channel is set to stable-5.6 when testing on OCP 4.12
  # to avoid hitting issues like https://issues.redhat.com//browse/OCPQE-8932
  # skip upgrade when current channel is stable-5.6
  if eo_current_channel != "stable-5.6" && (cb.eo_channel != eo_current_channel || cb.eo_catsrc != eo_current_catsrc)
    upgrade_eo = true
    step %Q/I upgrade the operator with:/, table(%{
      | namespace    | openshift-operators-redhat |
      | subscription | elasticsearch-operator     |
      | channel      | #{cb.eo_channel}           |
      | catsrc       | #{cb.eo_catsrc}            |
    })
    step %Q/the step should succeed/
  else
    upgrade_eo = false
  end
  # check CLO
  step %Q/I use the "openshift-logging" project/
  clo_current_channel = subscription("cluster-logging").channel(cached: false)
  clo_current_catsrc = subscription("cluster-logging").source
  # skip upgrade when current channel is stable-5.6
  if clo_current_channel != "stable-5.6" && (clo_current_channel != cb.clo_channel || cb.clo_catsrc != clo_current_catsrc)
    upgrade_clo = true
    step %Q/I upgrade the operator with:/, table(%{
      | namespace    | openshift-logging |
      | subscription | cluster-logging   |
      | channel      | #{cb.clo_channel} |
      | catsrc       | #{cb.clo_catsrc}  |
    })
    step %Q/the step should succeed/
  else
    upgrade_clo = false
  end
  # check cronjobs if the CLO or/and EO is upgraded
  if (upgrade_eo || upgrade_clo) && (BushSlicer::CronJob.list(user: user, project: project).count != 0)
    step %Q/I check the cronjob status/
    step %Q/the step should succeed/
  end
end

# check cronjob status
# delete all the jobs, and wait up to 15min to check the jobs status
Given /^I check the cronjob status$/ do
  # check logging version
  step %Q/I use the "openshift-operators-redhat" project/
  eo_version = subscription("elasticsearch-operator").current_csv(cached: false).split(".", 2).last.split(/[A-Za-z]/).last
  step %Q/I use the "openshift-logging" project/
  clo_version = subscription("cluster-logging").current_csv(cached: false).split(".", 2).last.split(/[A-Za-z]/).last
  #csv version >= 4.5, check rollover/delete cronjobs, csv < 4.5, only check curator cronjob
  if ["4.0", "4.1", "4.2", "4.3", "4.4"].include? clo_version.split('.').take(2).join('.')
    if cron_job('curator').exists?
      # remove all the old jobs
      @result = admin.cli_exec(:delete, object_type: 'job', l: 'component=curator', n: 'openshift-logging')
      # wait up to 6 minutes for the cronjob to be recreated
      success = wait_for(360, interval: 10) {
        BushSlicer::Job.list(user: user, project: project).count >= 1
      }
      raise "can't recreate cronjobs" unless success
    else
      raise "cronjob curator doesn't exist"
    end
  else
    cj_names = ["elasticsearch-im-app", "elasticsearch-im-audit", "elasticsearch-im-infra"]
    for cj_name in cj_names do
      raise "cronjob #{cj_name} doesn't exist" unless cron_job(cj_name).exists?
    end
    # remove all the old jobs
    @result = admin.cli_exec(:delete, object_type: 'job', l: 'component=indexManagement', n: 'openshift-logging')
    # wait up to 16 minutes for the cronjob to be recreated
    success = wait_for(960, interval: 10) {
      BushSlicer::Job.list(user: user, project: project).count >= 3
    }
    raise "can't recreate cronjobs" unless success
  end

  # check the new jobs could be successfully
  # wait up to 1 minute for the jobs to complete
  jobs = BushSlicer::Job.list(user: user, project: project)
  job_names = jobs.map(&:name)
  for job_name in job_names
    success = wait_for(60, interval: 5) {
      job(job_name).succeeded == 1
    }
    raise "#{job_name} failed to complete" unless success
  end
end

# This step will deploy one kafka cluster and create 4 topics(topic-logging-all,topic-logging-infra,topic-logging-app,topic-logging-audit) in this kafka
Given /^I deploy kafka in the #{QUOTED} project via amqstream operator$/ do | project_name|
  ensure_admin_tagged
  step %Q/I switch to cluster admin pseudo user/
  kafka_catsrc = package_manifest("amq-streams").catalog_source

  step %Q/I use the "#{project_name}" project/
  step %Q/I process and create:/, table(%{
    | f | #{BushSlicer::HOME}/testdata/logging/clusterlogforwarder/kafka/amq/02_og_amqstreams_template.yaml |
    | p | AMQ_NAMESPACE=#{project_name} |
  })
  raise "Error create operatorgroup" unless @result[:success]

  step %Q/I process and create:/, table(%{
    | f | #{BushSlicer::HOME}/testdata/logging/clusterlogforwarder/kafka/amq/03_sub_amqstreams_template.yaml |
    | p | AMQ_NAMESPACE=#{project_name}     |
    | p | AMQ_CATALOGSOURCE=#{kafka_catsrc} |
  })
  raise "Error subscript amqstreams" unless @result[:success]

  @result = admin.cli_exec(:get, resource: "machineconfig", resource_name: "99-worker-fips")
  unless @result[:response].include? "NotFound"
    patch_json = {"spec": {"config": {"env": [{"name": "FIPS_MODE", "value": "disabled"}]}}}
    patch_opts = {resource: "subscription", resource_name: "amq-streams", p: patch_json.to_json, n: project_name, type: "merge"}
    @result = admin.cli_exec(:patch, **patch_opts)
    raise "Patch failed with #{@result[:response]}" unless @result[:success]
  end

  step %Q/a pod becomes ready with labels:/, table(%{
    | name=amq-streams-cluster-operator |
  })

  step %Q/I process and create:/, table(%{
    | f | #{BushSlicer::HOME}/testdata/logging/clusterlogforwarder/kafka/amq/04_kafka_my-cluster_amqstreams_template.yaml |
    | p | AMQ_NAMESPACE=#{project_name} |
  })
  raise "Error create kafka" unless @result[:success]

  @result = admin.cli_exec(:create, f: "#{BushSlicer::HOME}/testdata/logging/clusterlogforwarder/kafka/amq/05_kafkatopics_amqstreams.yaml")
  raise "Error create kafka topics" unless @result[:success]

  step %Q/1 pod becomes ready with labels:/, table(%{
    | strimzi.io/name=my-cluster-kafka |
  })
  raise "Error kafka cluster not ready" unless @result[:success]
end

# Get some records from a kafka topic
# https://datacadamia.com/dit/kafka/kafka-console-consumer
Given /^I get(?: (\d+))? records from the #{QUOTED} kafka topic in the #{QUOTED} project$/ do | record_num, topic_name, project_name|
  record_num = record_num ? record_num.to_str : "10"
  job_name=rand_str(8, :dns)
  step %Q/I use the "#{project_name}" project/
  kafka_image=pod('my-cluster-kafka-0').container_specs(user: user)[0].image
  teardown_add {
    admin.cli_exec(:delete, object_type: 'job', object_name_or_id: job_name, n: project_name)
  }
  step %Q/I process and create:/,table(%{
    | f | #{BushSlicer::HOME}/testdata/logging/clusterlogforwarder/kafka/amq/21_job_topic_consumer_from_beginning_template.yaml |
    | p | KAFKA_IMAGE=#{kafka_image} |
    | p | KAFKA_TOPIC=#{topic_name}  |
    | p | MAX_MESSAGES=#{record_num} |
    | p | JOB_NAME=#{job_name} |
  })
  step %Q/a pod becomes ready with labels:/, table(%{
    | job-name=#{job_name}|
  })

  # wait up to 1 minutes for the kafka message
  success = wait_for(60, interval: 15) {
    @result = user.cli_exec(:logs, {resource_name: "#{pod.name}"})
    @result[:response].match("pipeline_metadata")
  }
  raise "Couldn't received logs from the kafka topic #{topic_name}" unless success
end

# Register an topic consumer which listen the topic continuously. we can verify the logging records by the next step 'I get N logs from the X kafka consumer job'
Given /^I create the #{QUOTED} consumer job to the #{QUOTED} kafka topic in the #{QUOTED} project$/ do | job_name, topic_name, project_name |
  step %Q/I use the "#{project_name}" project/
  kafka_image=stateful_set('my-cluster-kafka').containers_spec(user: user)[0].image
  teardown_add {
    admin.cli_exec(:delete, object_type: 'job', object_name_or_id: job_name, n: project_name)
  }
  step %Q/I process and create:/,table(%{
    | f | #{BushSlicer::HOME}/testdata/logging/clusterlogforwarder/kafka/amq/21_job_topic_consumer_from_latest_template.yaml |
    | p | KAFKA_IMAGE=#{kafka_image} |
    | p | KAFKA_TOPIC=#{topic_name} |
    | p | JOB_NAME=#{job_name} |
  })
  raise "Unable to create consumer job" unless @result[:success]
end

# Get logs from the kafka comsumer job which created by upper job
Given /^I get(?: (\d+))? logs from the #{QUOTED} kafka consumer job in the #{QUOTED} project$/ do | record_num, job_name, project_name |
  record_num = record_num ? record_num.to_i : 0
  step %Q/I use the "#{project_name}" project/
  step %Q/a pod becomes ready with labels:/, table(%{
    | job-name=#{job_name}|
  })

  # wait up to 1 minutes for the kafka message
  success = wait_for(60, interval: 10) {
    if record_num >0
      @result = user.cli_exec(:logs, {resource_name: "#{pod.name}", tail: "#{ record_num }"})
    else
      @result = user.cli_exec(:logs, {resource_name: "#{pod.name}"})
    end
    @result[:response].match("pipeline_metadata")
  }
  raise "Couldn't retrieve kafka records #{pod.name}" unless success
end

# deploy external elasticsearch server
# version: 6.8 or 7.17
# project_name: where the external ES deployed
# scheme: http or https
# client_auth: true or false, if `true`, must provide client crendentials
# user_auth_enabled: true or false, if `true`, must provide username and password
# secret_name: the name of the pipeline secret for the fluentd to use
Given /^external elasticsearch server is deployed with:$/ do | table |
  opts = opts_array_to_hash(table.raw)
  version = opts[:version] # 6.8 or 7.17
  project_name = opts[:project_name]
  scheme = opts[:scheme]
  client_auth = opts[:client_auth]
  user_auth_enabled = opts[:user_auth_enabled]
  username = opts[:username]
  password = opts[:password]
  secret_name = opts[:secret_name]
  step %Q/I use the "#{project_name}" project/

  unless ["6.8", "7.17"].include? version
    raise "Unsupported ES version: #{version}, we only support ES 6.8 and 7.17!"
  end

  if scheme == "https"
    http_ssl_enabled = "true"
  else
    http_ssl_enabled = "false"
  end

  if user_auth_enabled == "true"
    raise "username or password is not specified" unless !(username.nil? || username.empty?) && !(password.nil? || password.empty?)
  end

  file_dir = "#{BushSlicer::HOME}/testdata/logging/clusterlogforwarder/elasticsearch/#{version}/#{scheme}"
  receiver_name = "elasticsearch-server"
  pod_label = "app=elasticsearch-server"

  # create secret/elasticsearch-server for ES if needed
  if http_ssl_enabled == "true"
    step %Q/I generate certs for the "elasticsearch-server" receiver in the "<%= project.name %>" project/
    unless tagged_upgrade?
      step %Q/I ensure "elasticsearch-server" secret is deleted from the "<%= project.name %>" project after scenario/
    end
    step %Q/I run the :create_secret client command with:/, table(%{
      | name        | elasticsearch-server                |
      | secret_type | generic                             |
      | from_file   | elasticsearch.key=elasticsearch.key |
      | from_file   | elasticsearch.crt=elasticsearch.crt |
      | from_file   | admin-ca=ca.crt                     |
      | n           | #{project_name}                     |
    })
    step %Q/the step should succeed/
  end

  if user_auth_enabled == "true" || http_ssl_enabled == "true"
    raise "secret_name is not specified or is empty" unless !(secret_name.nil? || secret_name.empty?)
    step %Q/I create a pipeline secret with:/, table(%{
      | secret_name       | #{secret_name}       |
      | username          | #{username}          |
      | password          | #{password}          |
      | client_auth       | #{client_auth}       |
      | user_auth_enabled | #{user_auth_enabled} |
      | http_ssl_enabled  | #{http_ssl_enabled}  |
    })
  end

  # get file per configurations
  if user_auth_enabled == "true"
    cm_file = "#{file_dir}/user_auth/configmap.yaml"
    deploy_file = "#{file_dir}/user_auth/deployment.yaml"
  else
    cm_file = "#{file_dir}/no_user/configmap.yaml"
    deploy_file = "#{file_dir}/no_user/deployment.yaml"
  end

  # process configmap
  cm_patch = [
    ["f", "#{cm_file}"],
    ["n", "#{project_name}"],
    ["p", "NAMESPACE=#{project_name}"]
  ]
  if client_auth == "true" && http_ssl_enabled == "true"
    cm_patch << ["p", "CLIENT_AUTH=required"]
  end

  if client_auth != "true" && http_ssl_enabled == "true"
    cm_patch << ["p", "CLIENT_AUTH=none"]
  end

  if user_auth_enabled == "true"
    cm_patch << ["p", "USERNAME=#{username}"] << ["p", "PASSWORD=#{password}"]
  end

  # get the arch of node
  @result = admin.cli_exec(:get, resource: "nodes", l: "kubernetes.io/os=linux", output: "jsonpath={.items[0].status.nodeInfo.architecture}")
  # set xpack.ml.enable to false when the architecture is not amd64
  if @result[:response] != "amd64"
    cm_patch << ["p", "MACHINE_LEARNING=false"]
  end

  @result = admin.cli_exec(:process, opts_array_process(cm_patch.uniq))
  File.write(File.expand_path("cm.yaml".strip), @result[:stdout])
  cm = "cm.yaml"

  deploy_patch = [
    ["f", "#{deploy_file}"],
    ["n", "#{project_name}"],
    ["p", "NAMESPACE=#{project_name}"]
  ]

  @result = admin.cli_exec(:process, opts_array_process(deploy_patch.uniq))
  File.write(File.expand_path("deploy.yaml".strip), @result[:stdout])
  deploy = "deploy.yaml"

  step %Q/I create the resources for the receiver with:/, table(%{
    | namespace       | #{project_name}  |
    | receiver_name   | #{receiver_name} |
    | configmap_file  | #{cm}            |
    | deployment_file | #{deploy}        |
    | pod_label       | #{pod_label}     |
  })
end

Given /^I check in the external ES pod with:$/ do | table |
  opts = opts_array_to_hash(table.raw)
  project_name = opts[:project_name]
  pod_label = opts[:pod_label]
  scheme = opts[:scheme]
  client_auth = opts[:client_auth]
  user_auth_enabled = opts[:user_auth_enabled]
  username = opts[:username]
  password = opts[:password]
  url_path = opts[:url_path]
  query = opts[:query]
  step %Q/I use the "#{project_name}" project/

  curlString = "curl -H \"Content-Type: application/json\""
  if user_auth_enabled == "true"
    raise "please provide username/password" unless (username != "" && password != "")
    curlString += " -u #{username}:#{password}"
  end

  if scheme == "https"
    if client_auth == "true"
      curlString += " --cert /usr/share/elasticsearch/config/secret/elasticsearch.crt --key /usr/share/elasticsearch/config/secret/elasticsearch.key"
    end
    curlString += " --cacert /usr/share/elasticsearch/config/secret/admin-ca -s https://localhost:9200/"
  else
    curlString += " -s http://localhost:9200/"
  end

  if url_path != ""
    curlString += url_path
  end

  if query != ""
    curlString += " -d '#{query}'"
  end

  step %Q/a pod becomes ready with labels:/, table(%{
    | #{pod_label} |
  })
  @result = pod.exec("bash", "-c", curlString, as: admin, container: 'elasticsearch-server')
  if @result[:success]
    @result[:parsed] = YAML.load(@result[:response])
    # curl returns 0 even with a http code of 403, we force it to match.
    if @result[:parsed].is_a? Hash and @result[:parsed].has_key? 'status'
      @result[:exitstatus] = @result[:parsed]['status']
    end
  else
    raise "HTTP operation failed with error, #{@result[:response]}"
  end

end

Given /^I have(?: "(\w+)")? log pod in project #{QUOTED}$/ do | log_type, project_name |
    file_dir = "#{BushSlicer::HOME}/testdata/logging/loggen"
    deploy_pod = true
    log_type ||= "any"

    template_file = "#{file_dir}/container_json_log_template.json"
    if log_type == "unicode" || log_type == "flat"
      template_file = "#{file_dir}/container_json_unicode_log_template.json"
    end

    unless project(project_name).exists?
      step %Q/I run the :new_project client command with:/,table(%{
        | project_name | #{project_name} |
      })
      raise "Error creating namespace" unless @result[:success]
    end

    step %Q/I use the "#{project_name}" project/

    if log_type == "any"
      pods = project.pods(by:user)
      pods.each do | current_pod |
        cache_pods(current_pod)
        @result = user.cli_exec(:logs, {resource_name: "#{current_pod.name}", n: "#{project_name}", since: "15s"})
        if @result[:success]
           deploy_pod = false
        end
      end
    end

    if deploy_pod
      step %Q/I run the :delete client command with:/, table(%{
        | object_type | configmap |
        | object_name_or_id | logtest-config |
      })
      step %Q/I run the :delete client command with:/, table(%{
        | object_type | ReplicationController |
        | object_name_or_id | centos-logtest |
      })
      step %Q/I run the :new_app client command with:/,table(%{
        | file | #{template_file} |
      })
      step %Q/a pod becomes ready with labels:/, table(%{
        | run=centos-logtest|
      })
    end
end

Given /^I have index pattern #{QUOTED}$/ do | pattern_name |
    step %Q/I perform the :kibana_index_pattern_exist web action with:/,table(%{
      | index_pattern_name | #{pattern_name} |
    })
    unless @result[:success]
      step %Q/I run the :go_to_kibana_management_page web action/
      step %Q/I perform the :create_index_pattern_in_kibana web action with:/, table(%{
        | index_pattern_name | #{pattern_name} |
      })
      raise "Failed to create index pattern #{pattern_name}" unless @result[:success]
    end
end

Given /^cluster-admin create the #{QUOTED} pattern for the #{WORD} user$/ do | pattern_name, who |
    user(word_to_num(who))
    user_name=user.name
    user_token=user.cached_tokens.first
    step %Q/I switch to cluster admin pseudo user/
    step %Q/I use the "openshift-logging" project/

    rest_cmd="curl -s --connect-timeout 10  -XPOST \"http://localhost:5601/api/saved_objects/index-pattern/#{pattern_name}\" -H \"kbn-xsrf: true\" -H \"x-forwarded-user: #{user_name}\" -H \"securitytenant: __user__\" -H \"Authorization: Bearer #{user_token}\" -H \"Content-Type: application/json\" -d \'{\"attributes\": {\"title\": \"#{pattern_name}\", \"timeFieldName\": \"@timestamp\"}}\'"

    step %Q/a pod becomes ready with labels:/, table(%{
      | component= kibana|
    })
    @result = pod.exec("bash", "-c", rest_cmd, as: admin, container: 'kibana')
    raise "Failed to create index pattern via rest api" unless @result[:success]
end

Given /^I can display the#{OPT_QUOTED} pod logs of the#{OPT_QUOTED} project under the#{OPT_QUOTED} pattern in kibana$/ do | pod_name, project_name, pattern_name |
    # I switch to cluster admin pseudo user
    pod_name ||= "*"
    project_name ||= "*"
    pattern_name ||= "app"
    #lucene_query_string = "kubernetes.namespace_name: #{project_name} and kubernetes.pod_name: #{pod_name} and @timestamp:[now-15m TO now]"
    lucene_query_string = "kubernetes.namespace_name: #{project_name} and kubernetes.pod_name: #{pod_name}"
    step %Q/I perform the :select_index_pattern_in_kibana web action with:/,table(%{
      | index_pattern_name | #{pattern_name} |
    })
    raise("Can not select to pattern #{ pattern_name}!") unless @result[:success]

    step %Q/I perform the :search_doc_in_kibana web action with:/,table(%{
      | search_string | #{lucene_query_string} |
    })
    raise("Can not refresh the search #{lucene_query_string}!") unless @result[:success]

    retries = 3
    succeed=false
    while retries > 0
      retries -= 1
      step %Q/I run the :check_log_count web action/
      if @result[:success]
        succeed=true
        break
      else
        log("Can not find documents using clause #{lucene_query_string} under pattern  #{ pattern_name}! retry.....")
      end
    end
    raise("Can not find documents using clause #{lucene_query_string} under pattern  #{ pattern_name}! after 3 retry,  abort") unless succeed
end

Given /^I have clusterlogging with(?: (\d+))? persistent storage ES$/ do |es_num|
    # I switch to cluster admin pseudo user
    ensure_admin_tagged
    es_num ||= 3
    redundancy_policy="SingleRedundancy"
    deploy_cluster_logging=true

    if project('openshift-logging').exists?
        step %Q/I use the "openshift-logging" project/
        if cluster_logging('instance').exists? && cluster_logging('instance').logstore_storage.has_key?("storageClassName")
            deploy_cluster_logging=false
        end
    end

    if deploy_cluster_logging
      if(es_num==1)
        redundancy_policy="ZeroRedundancy"
      end
      step %Q/I get storageclass from cluster and store it in the :default_sc clipboard/
      step %Q/the correct directory name of clusterlogging file is stored in the :cl_dir clipboard/
      cr = "<%= BushSlicer::HOME %>/testdata/logging/clusterlogging/<%= cb.cl_dir %>/clusterlogging-storage-template.yaml"
      step %Q/I create clusterlogging instance with:/, table(%{
        | crd_yaml          | #{cr}                     |
        | storage_class     | <%= cb.default_sc.name %> |
        | storage_size      | 20Gi                      |
        | es_node_count     | #{ es_num }               |
        | redundancy_policy | #{ redundancy_policy }    |
      })
    end
end

Given /^logging collector name is stored in the#{OPT_SYM} clipboard$/ do | collector_name |
  collector_name ||= "collector_name"
  fluentd_component_label ||= "collector"

  clo_csv_version = subscription("cluster-logging").current_csv(cached: false).split(".", 2).last.split(/[A-Za-z]/).last

  if Integer(clo_csv_version.split('.')[0]) < 5 || (Integer(clo_csv_version.split('.')[0]) ==5 &&  Integer(clo_csv_version.split('.')[1]) < 3 )
     fluentd_component_label="fluentd"
  end
  cb[collector_name] = fluentd_component_label
end

Given /^I check if the remaining_resources in woker nodes meet the requirements for logging stack$/ do
  ensure_admin_tagged
  linux_nodes = BushSlicer::Node.get_labeled("kubernetes.io/os=linux", user: admin)
  worker_nodes = linux_nodes.select { |n| n.is_worker? && n.ready? && n.schedulable? }
  total_remaning_cpu = 0
  total_remaning_memory = 0

  # calculate node.remaining_resources
  worker_nodes.each do |n|
    total_remaning_cpu += n.remaining_resources[:cpu]
    total_remaning_memory += n.remaining_resources[:memory]
  end
  # we need 3 ES pods, memory: (1Gi+256Mi)*3, cpu: 200m*3
  # for kibana, memory: (256+736)Mi, cpu: 200m
  # for collector, memory: 736Mi*worker_nodes_count, cpu: 100m*worker_nodes_count
  if total_remaning_cpu < 800+100*worker_nodes.count || total_remaning_memory < 5066719232+771751936*worker_nodes.count
    raise "Cluster doesn't have sufficient cpu or memory for logging pods to deploy, skip the logging case"
  end
end

Given /^I (check|record) all pods logs in the#{OPT_QUOTED} project(?: in last (\d+) seconds)?$/ do | action, namespace, seconds |
  ensure_admin_tagged
  def check_log(logs, errors, exceptions)
    error_logs = []
    unless logs.empty? || logs.nil?
      logs.split("\n").each do | log |
        if !(exceptions.nil?)
          ignore = false
          exceptions.each do | exception |
            if log.include? exception
              ignore = true
              break
            end
          end
          if ignore
            next
          end
        else
          errors.each do | error_string |
            if log.include? error_string
              error_logs.append(log)
            end
            #raise "found error/failure logs: #{log}" unless !(log.include? error_string)
          end
        end
      end
    end
    return error_logs
  end

  error_strings = ["error", "Error"]
  pods = BushSlicer::Pod.list(user: admin, project: project(namespace))
  pods.each do | pod |
    # skip index management jobs and not ready pods
    if (pod.name.include? "elasticsearch-im-") || !(pod.ready?[:success])
      next
    end
    pod.containers.each do | container |
      if seconds.nil?
        @result = admin.cli_exec(:logs, n: namespace,resource_name: pod.name, c: container.name)
      else
        @result = admin.cli_exec(:logs, n: namespace,resource_name: pod.name, c: container.name, since: seconds+"s")
      end
      if action == "check"
        # read logs line by line
        # ignore errors in https://issues.redhat.com/browse/LOG-2702
        ignored_messages = []
        case container.name
        when "cluster-logging-operator"
          ignored_messages = ["the object has been modified"]
        when "kibana"
          ignored_messages = ["java.lang.UnsupportedOperationException"]
        when "elasticsearch"
          ignored_messages = ["INFO", "WARN", "DEBUG"]
        when "proxy"
          ignored_messages = ["proxy error"]
        when "collector"
          ignored_messages = ["Timeout flush: kubernetes.var.log"]
        when "logfilesmetricexporter"
          ignored_messages = ["unsupported cipher suite"]
        when "elasticsearch-operator"
          ignored_messages = ["failed decoding raw response body into `map[string]estypes.GetIndexTemplate`", "failed to get list of index templates"]
        end
        log = check_log(@result[:response], error_strings, ignored_messages)
        raise "find error/failure log in #{pod.name}/#{container.name}: #{log}" unless log.empty?
      end
    end
  end
end

Given /^I get storageclass from cluster and store it in the#{OPT_SYM} clipboard$/ do | sc |
  sc = 'sc' unless sc
  has_default_sc = false
  _sc = ''
  storage_classes = BushSlicer::StorageClass.list(user: user)
  raise "Unable to get storage class " unless storage_classes.count > 0
  storage_classes.each do | storage_class |
    if storage_class.default?
      has_default_sc = true
      _sc = storage_class
      break
    end
  end

  if !has_default_sc
    _sc = storage_classes.first
  end

  cb[sc] = _sc
  cache_resources _sc
end

Given /^the correct directory name of clusterlogging file is stored in the#{OPT_SYM} clipboard$/ do | directory |
  ensure_admin_tagged
  step %Q/I switch to cluster admin pseudo user/
  step %Q/I use the "openshift-logging" project/
  directory ||= "directory"
  clo_csv_version = subscription("cluster-logging").current_csv(cached: false).split(".", 2).last.split(/[A-Za-z]/).last

  directory_name=""
  if Integer(clo_csv_version.split('.')[0]) >= 5 && Integer(clo_csv_version.split('.')[1]) >= 7
    directory_name="5.7"
  end

  cb[directory] = directory_name
end
