#!/bin/bash
K8S_CLI_BIN=oc

# eBPF agent image to use
agentImg="registry.redhat.io/network-observability/network-observability-ebpf-agent-rhel9:v1.7.0"

if [ -n "$NETOBSERV_AGENT_IMAGE" ]; then
  echo "using custom agent image $NETOBSERV_AGENT_IMAGE"
  agentImg="$NETOBSERV_AGENT_IMAGE"
fi

function loadYAMLs() {
  namespaceYAML='
kind: Namespace
apiVersion: v1
metadata:
  name: netobserv-cli
  labels:
    app: netobserv
    pod-security.kubernetes.io/enforce: privileged
    pod-security.kubernetes.io/audit: privileged
  '
  if [ -f ./res/namespace.yml ]; then
    namespaceYAML="$(cat ./res/namespace.yml)"
  fi

  saYAML='
apiVersion: v1
kind: ServiceAccount
metadata:
  name: netobserv-cli
  namespace: netobserv-cli
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: netobserv-cli
  namespace: netobserv-cli
rules:
  - apiGroups:
     - security.openshift.io
    resourceNames:
     - privileged
    resources:
     - securitycontextconstraints
    verbs:
     - use
  - verbs:
     - list
     - get
     - watch
    apiGroups:
     - ''
    resources:
     - pods
     - services
     - nodes
  - verbs:
     - list
     - get
     - watch
    apiGroups:
     - apps
    resources:
     - replicasets
  - verbs:
     - create
     - delete
     - patch
     - update
     - get
     - watch
     - list
    apiGroups:
     - autoscaling
    resources:
     - horizontalpodautoscalers
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: netobserv-cli
  namespace: netobserv-cli
subjects:
  - kind: ServiceAccount
    name: netobserv-cli
    namespace: netobserv-cli
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: netobserv-cli
  '
  if [ -f ./res/service-account.yml ]; then
    saYAML="$(cat ./res/service-account.yml)"
  fi

  flowAgentYAML='
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: netobserv-cli
  namespace: netobserv-cli
  labels:
    app: netobserv-cli
spec:
  selector:
    matchLabels:
      app: netobserv-cli
  template:
    metadata:
      labels:
        app: netobserv-cli
    spec:
      serviceAccountName: netobserv-cli
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      containers:
      - name: netobserv-cli
        image: "{{AGENT_IMAGE_URL}}"
        imagePullPolicy: Always
        securityContext:
          privileged: true
          runAsUser: 0
        env:
          - name: METRICS_ENABLE
            value: "false"
          - name: LOG_LEVEL
            value: info
          - name: INTERFACES
            value: ""
          - name: EXCLUDE_INTERFACES
            value: "lo"
          - name: SAMPLING
            value: "1"
          - name: ENABLE_RTT
            value: "false"
          - name: ENABLE_PKT_DROPS
            value: "false"
          - name: ENABLE_DNS_TRACKING
            value: "false"
          - name: ENABLE_NETWORK_EVENTS_MONITORING
            value: "false"
          - name: ENABLE_FLOW_FILTER
            value: "false"
          - name: FILTER_DIRECTION
            value: ""
          - name: FILTER_IP_CIDR
            value: "0.0.0.0/0"
          - name: FILTER_PROTOCOL
            value: ""
          - name: FILTER_SOURCE_PORT
            value: ""
          - name: FILTER_DESTINATION_PORT
            value: ""
          - name: FILTER_PORT
            value: ""
          - name:  FILTER_SOURCE_PORT_RANGE
            value: ""
          - name: FILTER_DESTINATION_PORT_RANGE
            value: ""
          - name: FILTER_PORT_RANGE
            value: ""
          - name:  FILTER_SOURCE_PORTS
            value: ""
          - name: FILTER_DESTINATION_PORTS
            value: ""
          - name: FILTER_PORTS
            value: ""
          - name: FILTER_ICMP_TYPE
            value: ""
          - name: FILTER_ICMP_CODE
            value: ""
          - name: FILTER_PEER_IP
            value: ""
          - name: FILTER_TCP_FLAGS
            value: ""
          - name: FILTER_ACTION
            value: "Accept"
          - name: EXPORT
            value: "direct-flp"
          - name: FLP_CONFIG
            value: >
              {
                "log-level": "trace",
                "metricsSettings":{
                    "disableGlobalServer": true
                },
                "parameters":[
                    {
                      "name":"enrich",
                      "transform":{
                          "type":"network",
                          "network":{
                            "rules":[
                                {
                                  "type":"add_kubernetes",
                                  "kubernetes":{
                                      "add_zone": true,
                                      "ipField":"SrcAddr",
                                      "output":"SrcK8S"
                                  }
                                },
                                {
                                  "type":"add_kubernetes",
                                  "kubernetes":{
                                      "add_zone": true,
                                      "ipField":"DstAddr",
                                      "output":"DstK8S"
                                  }
                                },
                                {
                                  "type":"reinterpret_direction"
                                }
                            ],
                            "directionInfo":{
                                "reporterIPField":"AgentIP",
                                "srcHostField":"SrcK8S_HostIP",
                                "dstHostField":"DstK8S_HostIP",
                                "flowDirectionField":"FlowDirection"
                            }
                          }
                      }
                    },
                    {
                      "name":"send",
                      "write":{
                          "type":"grpc",
                          "grpc":{
                            "targetHost":"collector.netobserv-cli.svc.cluster.local",
                            "targetPort":9999
                          }
                      }
                    }
                ],
                "pipeline":[
                    {
                      "name":"enrich",
                      "follows":"preset-ingester"
                    },
                    {
                      "name":"send",
                      "follows":"enrich"
                    }
                ],
              }
        volumeMounts:
            - name: bpf-kernel-debug
              mountPath: /sys/kernel/debug
              mountPropagation: Bidirectional
            - name: var-run-ovn
              mountPath: /var/run/ovn
              mountPropagation: Bidirectional
            - name: var-run-ovs
              mountPath: /var/run/openvswitch
              mountPropagation: Bidirectional

      volumes:
        - name: bpf-kernel-debug
          hostPath:
            path: /sys/kernel/debug
            type: Directory
        - name: var-run-ovn
          hostPath:
            path: /var/run/ovn-ic
            type: DirectoryOrCreate
        - name: var-run-ovs
          hostPath:
            path: /var/run/openvswitch
            type: DirectoryOrCreate
  '
  if [ -f ./res/flow-capture.yml ]; then
    flowAgentYAML="$(cat ./res/flow-capture.yml)"
  fi
  flowAgentYAML="${flowAgentYAML/"{{AGENT_IMAGE_URL}}"/${agentImg}}"

  packetAgentYAML='
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: netobserv-cli
  namespace: netobserv-cli
  labels:
    app: netobserv-cli
spec:
  selector:
    matchLabels:
      app: netobserv-cli
  template:
    metadata:
      labels:
        app: netobserv-cli
    spec:
      serviceAccountName: netobserv-cli
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      containers:
      - name: netobserv-cli
        image: "{{AGENT_IMAGE_URL}}"
        imagePullPolicy: Always
        securityContext:
          privileged: true
          runAsUser: 0
        env:
          - name: ENABLE_PCA
            value: "true"
          - name: METRICS_ENABLE
            value: "false"
          - name: LOG_LEVEL
            value: info
          - name: FILTER_DIRECTION
            value: ""
          - name: FILTER_IP_CIDR
            value: "0.0.0.0/0"
          - name: FILTER_PROTOCOL
            value: ""
          - name: FILTER_SOURCE_PORT
            value: ""
          - name: FILTER_DESTINATION_PORT
            value: ""
          - name: FILTER_PORT
            value: ""
          - name:  FILTER_SOURCE_PORT_RANGE
            value: ""
          - name: FILTER_DESTINATION_PORT_RANGE
            value: ""
          - name: FILTER_PORT_RANGE
            value: ""
          - name:  FILTER_SOURCE_PORTS
            value: ""
          - name: FILTER_DESTINATION_PORTS
            value: ""
          - name: FILTER_PORTS
            value: ""
          - name: FILTER_ICMP_TYPE
            value: ""
          - name: FILTER_ICMP_CODE
            value: ""
          - name: FILTER_PEER_IP
            value: ""
          - name: FILTER_ACTION
            value: "Accept"
          - name: EXPORT
            value: "direct-flp"
          - name: FLP_CONFIG
            value: >
              {
                "log-level": "trace",
                "metricsSettings":{
                    "disableGlobalServer": true
                },
                "parameters":[
                    {
                      "name":"enrich",
                      "transform":{
                          "type":"network",
                          "network":{
                            "rules":[
                                {
                                  "type":"add_kubernetes",
                                  "kubernetes":{
                                      "add_zone": true,
                                      "ipField":"SrcAddr",
                                      "output":"SrcK8S"
                                  }
                                },
                                {
                                  "type":"add_kubernetes",
                                  "kubernetes":{
                                      "add_zone": true,
                                      "ipField":"DstAddr",
                                      "output":"DstK8S"
                                  }
                                },
                                {
                                  "type":"reinterpret_direction"
                                }
                            ],
                            "directionInfo":{
                                "reporterIPField":"AgentIP",
                                "srcHostField":"SrcK8S_HostIP",
                                "dstHostField":"DstK8S_HostIP",
                                "flowDirectionField":"FlowDirection"
                            }
                          }
                      }
                    },
                    {
                      "name":"send",
                      "write":{
                          "type":"grpc",
                          "grpc":{
                            "targetHost":"collector.netobserv-cli.svc.cluster.local",
                            "targetPort":9999
                          }
                      }
                    }
                ],
                "pipeline":[
                    {
                      "name":"enrich",
                      "follows":"preset-ingester"
                    },
                    {
                      "name":"send",
                      "follows":"enrich"
                    }
                ],
              }
        volumeMounts:
            - name: bpf-kernel-debug
              mountPath: /sys/kernel/debug
              mountPropagation: Bidirectional

      volumes:
        - name: bpf-kernel-debug
          hostPath:
            path: /sys/kernel/debug
            type: Directory
  '
  if [ -f ./res/packet-capture.yml ]; then
    packetAgentYAML="$(cat ./res/packet-capture.yml)"
  fi
  packetAgentYAML="${packetAgentYAML/"{{AGENT_IMAGE_URL}}"/${agentImg}}"

  collectorServiceYAML='
apiVersion: v1
kind: Service
metadata:
  name: collector
  namespace: netobserv-cli
spec:
  selector:
    run: collector
  ports:
  - name: collector
    protocol: TCP
    port: 9999
    targetPort: 9999  '
  if [ -f ./res/collector-service.yml ]; then
    collectorServiceYAML="$(cat ./res/collector-service.yml)"
  fi
}

function clusterIsReady() {
    # use oc whoami as connectivity check by default and fallback to kubectl get all if needed
    K8S_CLI_CONNECTIVITY="${K8S_CLI_BIN} whoami"
    if [ "${K8S_CLI_BIN}" = "kubectl" ]; then
      K8S_CLI_CONNECTIVITY="${K8S_CLI_BIN} get all"
    fi
    if ${K8S_CLI_CONNECTIVITY} 2>&1 || ${K8S_CLI_BIN} cluster-info | grep -q "Kubernetes control plane"; then
      return 0
    else
      return 1
    fi
}

FLOWS_MANIFEST_FILE="flow-capture.yml"
PACKETS_MANIFEST_FILE="packet-capture.yml"
MANIFEST_OUTPUT_PATH="tmp"

function setup {
  echo "Setting up... "

  # check for mandatory arguments
  if ! [[ $1 =~ flows|packets ]]; then
    echo "invalid setup argument"
    return
  fi

  if ! clusterIsReady; then
    printf 'You must be connected to cluster\n' >&2
    exit 1
  fi

  # load yaml files
  loadYAMLs

  # apply yamls
  echo "creating netobserv-cli namespace"
  echo "$namespaceYAML" | ${K8S_CLI_BIN} apply -f -

  echo "creating service account"
  echo "$saYAML" | ${K8S_CLI_BIN} apply -f -

  echo "creating collector service"
  echo "$collectorServiceYAML" | ${K8S_CLI_BIN} apply -f -

  if [ "$1" = "flows" ]; then
    shift
    echo "creating flow-capture agents:"
    if [[ ! -d ${MANIFEST_OUTPUT_PATH} ]]; then
      mkdir -p ${MANIFEST_OUTPUT_PATH} > /dev/null
    fi
    manifest="${MANIFEST_OUTPUT_PATH}/${FLOWS_MANIFEST_FILE}"
    echo "${flowAgentYAML}" > ${manifest}
    options="$*"
    check_args_and_apply "$options" "$manifest" "flows"
  elif [ "$1" = "packets" ]; then
    shift
    echo "creating packet-capture agents"
    if [[ ! -d ${MANIFEST_OUTPUT_PATH} ]]; then
      mkdir -p ${MANIFEST_OUTPUT_PATH} > /dev/null
    fi
    manifest="${MANIFEST_OUTPUT_PATH}/${PACKETS_MANIFEST_FILE}"
    echo "${packetAgentYAML}" > ${manifest}
    options="$*"
    check_args_and_apply "$options" "$manifest" "packets"
  fi
}

function copyOutput {
  echo "Copying collector output files..."
  mkdir -p ./output
  ${K8S_CLI_BIN} cp -n netobserv-cli collector:output ./output
}

function cleanup {
  # shellcheck disable=SC2034
  if clusterIsReady; then
    if [ "$captureStarted" = false ]; then
      echo "Can't copy since capture didn't start"
    elif [[ "$isE2E" = true || "$copy" = true ]]; then
      copyOutput
    elif [ "$copy" = "prompt" ]; then
      while true; do
          read -rp "Copy the capture output locally ?" yn
          case $yn in
              [Yy]* ) copyOutput; break;;
              [Nn]* ) echo "copy skipped"; break;;
              * ) echo "Please answer yes or no.";;
          esac
      done
    fi

    printf "\nCleaning up... "
    ${K8S_CLI_BIN} delete namespace netobserv-cli
  else
    echo "Cleanup namespace skipped"
    return
  fi
}

function common_usage {
  # general options
  echo "          --log-level:              components logs                            (default: info)"
  echo "          --max-time:               maximum capture time                       (default: 5m)"
  echo "          --max-bytes:              maximum capture bytes                      (default: 50000000 = 50MB)"
  echo "          --copy:                   copy the output files locally              (default: prompt)"
  # filters
  echo "          --direction:              filter direction                           (default: n/a)"
  echo "          --cidr:                   filter CIDR                                (default: 0.0.0.0/0)"
  echo "          --protocol:               filter protocol                            (default: n/a)"
  echo "          --sport:                  filter source port                         (default: n/a)"
  echo "          --dport:                  filter destination port                    (default: n/a)"
  echo "          --port:                   filter port                                (default: n/a)"
  echo "          --sport_range:            filter source port range                   (default: n/a)"
  echo "          --dport_range:            filter destination port range              (default: n/a)"
  echo "          --port_range:             filter port range                          (default: n/a)"
  echo "          --sports:                 filter on either of two source ports       (default: n/a)"
  echo "          --dports:                 filter on either of two destination ports  (default: n/a)"
  echo "          --ports:                  filter on either of two ports              (default: n/a)"
  echo "          --tcp_flags:              filter TCP flags                           (default: n/a)"
  echo "          --action:                 filter action                              (default: Accept)"
  echo "          --icmp_type:              filter ICMP type                           (default: n/a)"
  echo "          --icmp_code:              filter ICMP code                           (default: n/a)"
  echo "          --peer_ip:                filter peer IP                             (default: n/a)"
}

function flows_usage {
  # features
  echo "          --enable_pktdrop:         enable packet drop                         (default: false)"
  echo "          --enable_dns:             enable DNS tracking                        (default: false)"
  echo "          --enable_rtt:             enable RTT tracking                        (default: false)"
  echo "          --enable_network_events:  enable Network events monitoring           (default: false)"
  echo "          --enable_filter:          enable flow filter                         (default: false)"
  # common
  common_usage
  # specific filters
  echo "          --interfaces:             interfaces to monitor                      (default: n/a)"

}

function packets_usage {
  # common
  common_usage
}

function edit_manifest() {
  ## replace the env variable in the manifest file
  echo "env: $1, env_value: $2"
  case "$1" in
  "interfaces")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"INTERFACES\").value|=\"$2\"" "$3"
    ;;
  "pktdrop_enable")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"ENABLE_PKT_DROPS\").value|=\"$2\"" "$3"
    ;;
  "dns_enable")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"ENABLE_DNS_TRACKING\").value|=\"$2\"" "$3"
    ;;
  "rtt_enable")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"ENABLE_RTT\").value|=\"$2\"" "$3"
    ;;
  "network_events_enable")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"ENABLE_NETWORK_EVENTS_MONITORING\").value|=\"$2\"" "$3"
    ;;
  "filter_enable")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"ENABLE_FLOW_FILTER\").value|=\"$2\"" "$3"
    ;;
  "filter_direction")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_DIRECTION\").value|=\"$2\"" "$3"
    ;;
  "filter_cidr")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_IP_CIDR\").value|=\"$2\"" "$3"
    ;;
  "filter_protocol")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_PROTOCOL\").value|=\"$2\"" "$3"
    ;;
  "filter_sport")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_SOURCE_PORT\").value|=\"$2\"" "$3"
    ;;
  "filter_dport")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_DESTINATION_PORT\").value|=\"$2\"" "$3"
    ;;
  "filter_port")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_PORT\").value|=\"$2\"" "$3"
    ;;
  "filter_sport_range")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_SOURCE_PORT_RANGE\").value|=\"$2\"" "$3"
    ;;
  "filter_dport_range")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_DESTINATION_PORT_RANGE\").value|=\"$2\"" "$3"
    ;;
  "filter_port_range")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_PORT_RANGE\").value|=\"$2\"" "$3"
    ;;
  "filter_sports")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_SOURCE_PORTS\").value|=\"$2\"" "$3"
    ;;
  "filter_dportS")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_DESTINATION_PORTS\").value|=\"$2\"" "$3"
    ;;
  "filter_ports")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_PORTS\").value|=\"$2\"" "$3"
    ;;
  "filter_icmp_type")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_ICMP_TYPE\").value|=\"$2\"" "$3"
    ;;
  "filter_icmp_code")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_ICMP_CODE\").value|=\"$2\"" "$3"
    ;;
  "filter_peer_ip")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_PEER_IP\").value|=\"$2\"" "$3"
    ;;
  "filter_action")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_ACTION\").value|=\"$2\"" "$3"
    ;;
  "filter_tcp_flags")
  yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"FILTER_TCP_FLAGS\").value|=\"$2\"" "$3"
  ;;
  "log_level")
    yq e --inplace ".spec.template.spec.containers[0].env[] |= select(.name==\"LOG_LEVEL\").value|=\"$2\"" "$3"
    ;;
  esac
}

# Check if the arguments are valid
#$1: options
#$2: manifest
#$3: either flows or packets
function check_args_and_apply() {
    # Iterate through the command-line arguments
    for option in $1; do
        key="${option%%=*}"
        value="${option#*=}"
        case "$key" in
            --copy) # Copy or skip without prompt
                if [[ "$value" == "true" || "$value" == "false" || "$value" == "prompt" ]]; then
                  echo "param: $key, param_value: $value"
                  copy="$value"
                else
                  echo "invalid value for --copy"
                fi
                ;;
            --interfaces) # Interfaces
                edit_manifest "interfaces" "$value" "$2"
                ;;
            --enable_pktdrop) # Enable packet drop
                if [[ "$3" == "flows" ]]; then
                  if [[ "$value" == "true" || "$value" == "false" ]]; then
                    edit_manifest "pktdrop_enable" "$value" "$2"
                  else
                    echo "invalid value for --enable_pktdrop"
                  fi
                else
                  echo "--enable_pktdrop is invalid option for packets"
                  exit 1
                fi
                ;;
            --enable_dns) # Enable DNS
                if [[ "$3" == "flows" ]]; then
                  if [[ "$value" == "true" || "$value" == "false" ]]; then
                    edit_manifest "dns_enable" "$value" "$2"
                  else
                    echo "invalid value for --enable_dns"
                  fi
                else
                  echo "--enable_dns is invalid option for packets"
                  exit 1
                fi
                ;;
            --enable_rtt) # Enable RTT
                if [[ "$3" == "flows" ]]; then
                  if [[ "$value" == "true" || "$value" == "false" ]]; then
                    edit_manifest "rtt_enable" "$value" "$2"
                  else
                    echo "invalid value for --enable_rtt"
                  fi
                else
                  echo "--enable_rtt is invalid option for packets"
                  exit 1
                fi
                ;;
            --enable_network_events) # Enable Network events monitoring
                if [[ "$3" == "flows" ]]; then
                  if [[ "$value" == "true" || "$value" == "false" ]]; then
                    edit_manifest "network_events_enable" "$value" "$2"
                  else
                    echo "invalid value for --enable_network_events"
                  fi
                else
                  echo "--enable_network_events is invalid option for packets"
                  exit 1
                fi
                ;;
            --enable_filter) # Enable flow filter
                if [[ "$3" == "flows" ]]; then
                  if [[ "$value" == "true" || "$value" == "false" ]]; then
                    edit_manifest "filter_enable" "$value" "$2"
                  else
                    echo "invalid value for --enable_filter"
                  fi
                else
                  echo "--enable_filter is invalid option for packets"
                  exit 1
                fi
                ;;
            --direction) # Configure filter direction
                if [[ "$value" == "Ingress" || "$value" == "Egress" ]]; then
                  edit_manifest "filter_direction" "$value" "$2"
                else
                  echo "invalid value for --direction"
                fi
                ;;
            --cidr) # Configure flow CIDR
                edit_manifest "filter_cidr" "$value" "$2"
                ;;
            --protocol) # Configure filter protocol
                if [[ "$value" == "TCP" || "$value" == "UDP" || "$value" == "SCTP" || "$value" == "ICMP" || "$value" == "ICMPv6" ]]; then
                  edit_manifest "filter_protocol" "$value" "$2"
                else
                  echo "invalid value for --protocol"
                fi
                ;;
            --sport) # Configure filter source port
                edit_manifest "filter_sport" "$value" "$2"
                ;;
            --dport) # Configure filter destination port
                edit_manifest "filter_dport" "$value" "$2"
                ;;
            --port) # Configure filter port
                edit_manifest "filter_port" "$value" "$2"
                ;;
            --sport_range) # Configure filter source port range
                edit_manifest "filter_sport_range" "$value" "$2"
                ;;
            --dport_range) # Configure filter destination port range
                edit_manifest "filter_dport_range" "$value" "$2"
                ;;
            --port_range) # Configure filter port range
                edit_manifest "filter_port_range" "$value" "$2"
                ;;
            --sports) # Configure filter source two ports using ","
                edit_manifest "filter_sports" "$value" "$2"
                ;;
            --dports) # Configure filter destination two ports using ","
                edit_manifest "filter_dports" "$value" "$2"
                ;;
            --ports) # Configure filter on two ports usig "," can either be srcport or dstport
                edit_manifest "filter_ports" "$value" "$2"
                ;;
            --tcp_flags) # Configure filter TCP flags
              if [[ "$value" == "SYN" || "$value" == "SYN-ACK" || "$value" == "ACK" || "$value" == "FIN" || "$value" == "RST" || "$value" == "FIN-ACK" || "$value" == "RST-ACK" || "$value" == "PSH" || "$value" == "URG" || "$value" == "ECE" || "$value" == "CWR" ]]; then
                edit_manifest "filter_tcp_flags" "$value" "$2"
              else
                echo "invalid value for --tcp_flags"
              fi
              ;;
            --icmp_type) # ICMP type
                edit_manifest "filter_icmp_type" "$value" "$2"
                ;;
            --icmp_code) # ICMP code
                edit_manifest "filter_icmp_code" "$value" "$2"
                ;;
            --peer_ip) # Peer IP
                edit_manifest "filter_peer_ip" "$value" "$2"
                ;;
            --action) # Filter action
                if [[ "$value" == "Accept" || "$value" == "Reject" ]]; then
                  edit_manifest "filter_action" "$value" "$2"
                else
                  echo "invalid value for --action"
                fi
                ;;
            --log-level) # Log level
                if [[ "$value" == "trace" || "$value" == "debug" || "$value" == "info" || "$value" == "warn" || "$value" == "error" || "$value" == "fatal" || "$value" == "panic" ]]; then
                  edit_manifest "log_level" "$value" "$2"
                  logLevel=$value
                  filter=${filter/$key=$logLevel/}
                else
                  echo "invalid value for --action"
                fi
                ;;
            --max-time) # Max time
                echo "param: $key, param_value: $value"
                maxTime=$value
                filter=${filter/$key=$maxTime/}
                ;;
            --max-bytes) # Max bytes
                echo "param: $key, param_value: $value"
                maxBytes=$value
                filter=${filter/$key=$maxBytes/}
                ;;
            *) # Invalid option
                echo "Invalid option: $key" >&2
                exit 1
                ;;
        esac
    done

    ${K8S_CLI_BIN} apply -f "$2"
    ${K8S_CLI_BIN} rollout status daemonset netobserv-cli -n netobserv-cli --timeout 60s
    rm -rf ${MANIFEST_OUTPUT_PATH}
}
set +u

# e2e skips inputs
if [ -z "${isE2E+x}" ]; then isE2E=false; fi
# keep capture state
if [ -z "${captureStarted+x}" ]; then captureStarted=false; fi
# prompt copy by default
if [ -z "${copy+x}" ]; then copy="prompt"; fi

# interface filter such as 'br-ex' or pcap filter such as 'tcp,80'
filter=""

# CLI image to use
img="registry.redhat.io/network-observability/network-observability-cli-rhel9:v1.7.0"

if [ -n "$NETOBSERV_COLLECTOR_IMAGE" ]; then
  echo "using custom collector image $NETOBSERV_COLLECTOR_IMAGE"
  img="$NETOBSERV_COLLECTOR_IMAGE"
fi

# version to display
version="1.6.1-community-65-g1f8b565a"

# command to run
command=""

# log level (default: info)
logLevel="info"

# max time (default: 5min)
maxTime="5m" 

# max bytes (default: 50MB)
maxBytes=50000000

function flows() {
  case "$2" in
    "help")
      flows_usage
      exit 0 ;;
    *)
      shift # remove first argument
      filter="$*"
      # run flows command
      command="flows" ;;
  esac
}

function packets() {
  case "$2" in
    "help")
      packets_usage
      exit 0 ;;
    *)
      shift # remove first argument
      filter="$*"
      # run packets command
      command="packets" ;;
  esac
}

case "$1" in  
"help")
    # display Help
    echo
    echo "Netobserv allows you to capture flow and packets from your cluster."
    echo "Find more information at: https://github.com/netobserv/network-observability-cli/"
    echo
    echo "Syntax: netobserv [flows|packets|cleanup] [options]"
    echo
    echo "commands:"
    echo "  flows      Capture flows information. You can specify an optional interface name as filter such as 'netobserv flows br-ex'."
    echo "        Options:"
    flows_usage
    echo "  packets    Capture packets information in pcap format."
    echo "        Options:"
    packets_usage
    echo "  cleanup    Remove netobserv components."
    echo "  version    Print software version."
    echo
    exit 0 ;;
"version")
    # display version
    echo "Netobserv CLI version $version"
    exit 0 ;;
"flows")
    flows $* ;;
"packets")
    packets $* ;;
"cleanup")
    # run cleanup command
    cleanup
    exit 0 ;;
*)
    echo "Unknown command $1. Use 'netobserv help' to display options"
    exit 1
esac

trap cleanup EXIT

setup $command $filter

echo "Running network-observability-cli get-$command... "
${K8S_CLI_BIN} run \
  -n netobserv-cli \
  collector \
  --image=$img\
  --image-pull-policy='Always' \
  --restart='Never' \
  --command -- sleep infinity

${K8S_CLI_BIN} wait \
  -n netobserv-cli \
  --for=condition=Ready pod/collector || exit 1

captureStarted=true

${K8S_CLI_BIN} exec -i --tty \
  -n netobserv-cli \
  collector \
  -- /network-observability-cli get-$command ${filter:+"--filter" "${filter//--/}"} --loglevel $logLevel --maxtime $maxTime --maxbytes $maxBytes