#!/bin/bash
. gather_service_logs_util
BASE_COLLECTION_PATH="must-gather"
NETWORK_LOG_PATH=${OUT:-"${BASE_COLLECTION_PATH}/network_logs"}
SERVICE_LOG_PATH="${BASE_COLLECTION_PATH}/host_service_logs/"

mkdir -p "${NETWORK_LOG_PATH}"/

function gather_multus_data { 
  echo "INFO: Gathering Multus data"
  #Should we store this on a per namespace basis? 
  oc get net-attach-def -o yaml --all-namespaces > "${NETWORK_LOG_PATH}"/net_attach_def 2>&1 & PIDS=($!)

  oc describe ippools.whereabouts.cni.cncf.io -A > "${NETWORK_LOG_PATH}"/ippools  2>&1 & PIDS=($!)

  oc describe overlappingrangeipreservations.whereabouts.cni.cncf.io -A > "${NETWORK_LOG_PATH}"/overlappingrangeipreservations  2>&1 & PIDS=($!)
}

function gather_ovn_ipsec_data { 
  echo "INFO: Gathering ovn-ipsec data"
  for IPSEC_POD in ${IPSEC_PODS[@]}; do 
    oc -n openshift-ovn-kubernetes exec "${IPSEC_POD}" -- bash -c "ovs-appctl -t ovs-monitor-ipsec tunnels/show" \
    > "${NETWORK_LOG_PATH}"/"${IPSEC_POD}"_ovs-monitor-ipsec_tunnels-show & 
    PIDS+=($!)

    oc -n openshift-ovn-kubernetes exec "${IPSEC_POD}" -- bash -c "ipsec status" \
    > "${NETWORK_LOG_PATH}"/"${IPSEC_POD}"_ipsec_status & 
    PIDS+=($!)

    oc -n openshift-ovn-kubernetes exec "${IPSEC_POD}" -- bash -c "certutil -L -d sql:/etc/ipsec.d" \
    > "${NETWORK_LOG_PATH}"/"${IPSEC_POD}"_active_libreswan_certs & 
    PIDS+=($!)

    oc -n openshift-ovn-kubernetes exec "${IPSEC_POD}" -- bash -c "ovs-vsctl list Open_vSwitch" \
    > "${NETWORK_LOG_PATH}"/"${IPSEC_POD}"_list_Open_vSwitch & 
    PIDS+=($!)

    oc -n openshift-ovn-kubernetes exec "${IPSEC_POD}" -- bash -c "ovn-nbctl list nb_global" \
    > "${NETWORK_LOG_PATH}"/"${IPSEC_POD}"_list_nb_global & 
    PIDS+=($!)

    oc cp openshift-ovn-kubernetes/"${IPSEC_POD}":/etc/openvswitch/keys "${NETWORK_LOG_PATH}"/"${IPSEC_POD}"_keys/ &
    PIDS+=($!) 

    oc cp openshift-ovn-kubernetes/"${IPSEC_POD}":/var/log/openvswitch/libreswan.log "${NETWORK_LOG_PATH}"/"${IPSEC_POD}"_libreswan_log &
    PIDS+=($!) 

    oc cp openshift-ovn-kubernetes/"${IPSEC_POD}":/var/log/openvswitch/ovs-monitor-ipsec.log "${NETWORK_LOG_PATH}"/"${IPSEC_POD}"_ovs_monitor_ipsec &
    PIDS+=($!)
  done
}

function gather_openshiftsdn_nodes_data {
  echo "INFO: Gathering Openshift-SDN data"
  for NODE in ${NODES}; do
      SDN_POD=$(oc -n openshift-sdn get pods --no-headers -o custom-columns=":metadata.name" --field-selector spec.nodeName="${NODE}" -l app=sdn)
      oc -n openshift-sdn exec "${SDN_POD}" -c sdn -- bash -c "iptables-save -c" > "${NETWORK_LOG_PATH}"/"${NODE}"_iptables &
      PIDS+=($!)
      oc -n openshift-sdn exec "${SDN_POD}" -c sdn -- bash -c "ovs-vsctl show" > "${NETWORK_LOG_PATH}"/"${NODE}"_ovs_dump &
      PIDS+=($!)
      collect_service_logs "${NODE}" openvswitch ovs-vswitchd ovsdb-server ovs-configuration
  done
}

function gather_ovn_kubernetes_nodes_data {
  echo "INFO: Gathering ovn-kubernetes node data"
  for NODE in ${NODES}; do
      OVNKUBE_NODE_POD=$(oc -n openshift-ovn-kubernetes get pods --no-headers -o custom-columns=":metadata.name" --field-selector spec.nodeName="${NODE}" -l app=ovnkube-node)
      oc -n openshift-ovn-kubernetes exec -c ovnkube-node "${OVNKUBE_NODE_POD}" -- bash -c "iptables-save -c" > "${NETWORK_LOG_PATH}"/"${NODE}"_"${OVNKUBE_NODE_POD}"_iptables &
      PIDS+=($!)
      oc -n openshift-ovn-kubernetes exec -c ovnkube-node "${OVNKUBE_NODE_POD}" -- bash -c "ip addr" > "${NETWORK_LOG_PATH}"/"${NODE}"_"${OVNKUBE_NODE_POD}"_ip_addr &
      PIDS+=($!)
      oc -n openshift-ovn-kubernetes exec -c ovnkube-node "${OVNKUBE_NODE_POD}" -- bash -c "ip route" > "${NETWORK_LOG_PATH}"/"${NODE}"_"${OVNKUBE_NODE_POD}"_ip_route &
      PIDS+=($!)
      oc -n openshift-ovn-kubernetes exec -c ovnkube-node "${OVNKUBE_NODE_POD}" -- bash -c "ip -6 route" > "${NETWORK_LOG_PATH}"/"${NODE}"_"${OVNKUBE_NODE_POD}"_ip_6_route &
      PIDS+=($!)
      oc -n openshift-ovn-kubernetes exec -c ovnkube-node "${OVNKUBE_NODE_POD}" -- bash -c "ip -s -d link" > "${NETWORK_LOG_PATH}"/"${NODE}"_"${OVNKUBE_NODE_POD}"_ip_-s_-d_link &
      PIDS+=($!)

      #Dump flows and ports 
      oc -n openshift-ovn-kubernetes exec -c ovnkube-node "${OVNKUBE_NODE_POD}" -- bash -c \
      "ovs-ofctl dump-ports-desc br-int" > "${NETWORK_LOG_PATH}"/"${NODE}"_ovs_ofctl_dump_ports_br_int &
      PIDS+=($!)
      oc -n openshift-ovn-kubernetes exec -c ovnkube-node "${OVNKUBE_NODE_POD}" -- bash -c \
      "ovs-ofctl dump-flows br-int" > "${NETWORK_LOG_PATH}"/"${NODE}"_ovs_ofctl_dump_flows_br_int &
      PIDS+=($!)
      oc -n openshift-ovn-kubernetes exec -c ovnkube-node "${OVNKUBE_NODE_POD}" -- bash -c \
      "ovs-ofctl dump-ports-desc br-local" > "${NETWORK_LOG_PATH}"/"${NODE}"_ovs_ofctl_dump_ports_br_local &
      PIDS+=($!)
      oc -n openshift-ovn-kubernetes exec -c ovnkube-node "${OVNKUBE_NODE_POD}" -- bash -c \
      "ovs-ofctl dump-flows br-local" > "${NETWORK_LOG_PATH}"/"${NODE}"_ovs_ofctl_dump_flows_br_local &
      PIDS+=($!)
       oc -n openshift-ovn-kubernetes exec -c ovnkube-node "${OVNKUBE_NODE_POD}" -- bash -c \
      "ovs-ofctl dump-ports-desc br-ex" > "${NETWORK_LOG_PATH}"/"${NODE}"_ovs_ofctl_dump_ports_br_ex &
      PIDS+=($!)
      oc -n openshift-ovn-kubernetes exec -c ovnkube-node "${OVNKUBE_NODE_POD}" -- bash -c \
      "ovs-ofctl dump-flows br-ex" > "${NETWORK_LOG_PATH}"/"${NODE}"_ovs_ofctl_dump_flows_br_ex &
      PIDS+=($!)

      oc -n openshift-ovn-kubernetes exec -c ovnkube-node "${OVNKUBE_NODE_POD}" -- bash -c \
      "ovs-vsctl show" > "${NETWORK_LOG_PATH}"/"${NODE}"_ovs_dump &
      PIDS+=($!)

      collect_service_logs "${NODE}" openvswitch ovs-vswitchd ovsdb-server ovs-configuration
  done
}

function gather_ovn_kubernetes_master_data {
  echo "INFO: Gathering ovn-kubernetes master data"
  OVNKUBE_MASTER_IPS=($(oc -n openshift-ovn-kubernetes get pods -l app=ovnkube-master -o=jsonpath='{.items[*].status.podIP}'))
  OVNKUBE_MASTER_PODS=($(oc -n openshift-ovn-kubernetes get pods -l app=ovnkube-master -o=jsonpath='{.items[*].metadata.name}'))

  oc -n openshift-ovn-kubernetes exec -c ovnkube-master "${OVNKUBE_MASTER_PODS[0]}" -- bash -c \
  "ovn-nbctl --db=ssl:${OVNKUBE_MASTER_IPS[0]}:9641,ssl:${OVNKUBE_MASTER_IPS[1]}:9641,ssl:${OVNKUBE_MASTER_IPS[2]}:9641 \
  -p /ovn-cert/tls.key -c /ovn-cert/tls.crt -C /ovn-ca/ca-bundle.crt show" > \
  "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_PODS[0]}"_ovn_nbctl_show &
  PIDS+=($!)
  oc -n openshift-ovn-kubernetes exec -c ovnkube-master "${OVNKUBE_MASTER_PODS[0]}" -- bash -c \
  "ovn-nbctl --db=ssl:${OVNKUBE_MASTER_IPS[0]}:9641,ssl:${OVNKUBE_MASTER_IPS[1]}:9641,ssl:${OVNKUBE_MASTER_IPS[2]}:9641 \
  -p /ovn-cert/tls.key -c /ovn-cert/tls.crt -C /ovn-ca/ca-bundle.crt list Logical_Switch_Port" > \
  "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_PODS[0]}"_ovn_nbctl_list_lsp &
  PIDS+=($!)
  oc -n openshift-ovn-kubernetes exec -c ovnkube-master "${OVNKUBE_MASTER_PODS[0]}" -- bash -c \
  "ovn-nbctl --db=ssl:${OVNKUBE_MASTER_IPS[0]}:9641,ssl:${OVNKUBE_MASTER_IPS[1]}:9641,ssl:${OVNKUBE_MASTER_IPS[2]}:9641 \
  -p /ovn-cert/tls.key -c /ovn-cert/tls.crt -C /ovn-ca/ca-bundle.crt list Load_Balancer" > \
  "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_PODS[0]}"_ovn_nbctl_list_lb &
  PIDS+=($!)
  oc -n openshift-ovn-kubernetes exec -c ovnkube-master "${OVNKUBE_MASTER_PODS[0]}" -- bash -c \
  "ovn-nbctl --db=ssl:${OVNKUBE_MASTER_IPS[0]}:9641,ssl:${OVNKUBE_MASTER_IPS[1]}:9641,ssl:${OVNKUBE_MASTER_IPS[2]}:9641 \
  -p /ovn-cert/tls.key -c /ovn-cert/tls.crt -C /ovn-ca/ca-bundle.crt list Port_Group" > \
  "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_PODS[0]}"_ovn_nbctl_list_pg &
  PIDS+=($!)
  oc -n openshift-ovn-kubernetes exec -c ovnkube-master "${OVNKUBE_MASTER_PODS[0]}" -- bash -c \
  "ovn-nbctl --db=ssl:${OVNKUBE_MASTER_IPS[0]}:9641,ssl:${OVNKUBE_MASTER_IPS[1]}:9641,ssl:${OVNKUBE_MASTER_IPS[2]}:9641 \
  -p /ovn-cert/tls.key -c /ovn-cert/tls.crt -C /ovn-ca/ca-bundle.crt list ACL" > \
  "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_PODS[0]}"_ovn_nbctl_list_acl &
  PIDS+=($!)
  oc -n openshift-ovn-kubernetes exec -c ovnkube-master "${OVNKUBE_MASTER_PODS[0]}" -- bash -c \
  "ovn-sbctl --db=ssl:${OVNKUBE_MASTER_IPS[0]}:9642,ssl:${OVNKUBE_MASTER_IPS[1]}:9642,ssl:${OVNKUBE_MASTER_IPS[2]}:9642 \
  -p /ovn-cert/tls.key -c /ovn-cert/tls.crt -C /ovn-ca/ca-bundle.crt show" > \
  "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_PODS[0]}"_ovn_sbctl_show &
  PIDS+=($!)

  for OVNKUBE_MASTER_POD in ${OVNKUBE_MASTER_PODS[@]}; do
    #get nbdb and sbdb sizes before and after db compaction, run serially to ensure event timeline 
    oc exec -n openshift-ovn-kubernetes "${OVNKUBE_MASTER_POD}"  -c nbdb -- ls -lht /etc/ovn/ \
    > "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_POD}"_nbdb_size_pre_compact

    oc exec -n openshift-ovn-kubernetes "${OVNKUBE_MASTER_POD}"  -c sbdb -- ls -lht /etc/ovn/ \
    > "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_POD}"_sbdb_size_pre_compact
 
    oc exec -n openshift-ovn-kubernetes "${OVNKUBE_MASTER_POD}" -c sbdb -- ovs-appctl -t /var/run/ovn/ovnsb_db.ctl ovsdb-server/compact 

    oc exec -n openshift-ovn-kubernetes "${OVNKUBE_MASTER_POD}" -c nbdb -- ovs-appctl -t /var/run/ovn/ovnnb_db.ctl ovsdb-server/compact 

    oc exec -n openshift-ovn-kubernetes "${OVNKUBE_MASTER_POD}"  -c nbdb -- ls -lht /etc/ovn/ \
    > "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_POD}"_nbdb_size_post_compact

    oc exec -n openshift-ovn-kubernetes "${OVNKUBE_MASTER_POD}"  -c sbdb -- ls -lht /etc/ovn/ \
    > "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_POD}"_sbdb_size_post_compact

    oc cp openshift-ovn-kubernetes/"${OVNKUBE_MASTER_POD}":/etc/ovn/ovnsb_db.db -c sbdb \
    "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_POD}"_sbdb 2>&1 
    gzip "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_POD}"_sbdb 2>&1 & PIDS+=($!)
    
    oc cp openshift-ovn-kubernetes/"${OVNKUBE_MASTER_POD}":/etc/ovn/ovnnb_db.db -c nbdb \
    "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_POD}"_nbdb 2>&1
    
    gzip "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_POD}"_nbdb 2>&1 & PIDS+=($!)
    
    oc exec -n openshift-ovn-kubernetes "${OVNKUBE_MASTER_POD}"  -c nbdb --  bash -c "ovn-appctl -t /var/run/ovn/ovnnb_db.ctl cluster/status \
    OVN_Northbound" > "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_POD}"_ovnnb_status_log & PIDS+=($!)

    oc exec -n openshift-ovn-kubernetes "${OVNKUBE_MASTER_POD}"  -c sbdb -- bash -c "ovn-appctl -t /var/run/ovn/ovnsb_db.ctl cluster/status \
    OVN_Southbound" > "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_POD}"_ovnsb_status_log & PIDS+=($!)

    oc exec -n openshift-ovn-kubernetes "${OVNKUBE_MASTER_POD}"  -c sbdb -- bash -c "cat /proc/sys/kernel/threads-max" \
    > "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_POD}"_sbdb_threads & PIDS+=($!)

    oc exec -n openshift-ovn-kubernetes "${OVNKUBE_MASTER_POD}"  -c sbdb -- bash -c  "ps -eo nlwp" \
    >  "${NETWORK_LOG_PATH}"/"${OVNKUBE_MASTER_POD}"_sbdb_thresd_nlwp & PIDS+=($!)

  done

  oc adm top pods -n openshift-ovn-kubernetes --containers > "${NETWORK_LOG_PATH}"/openshift_ovn_kubernetes_top_output & PIDS+=($!)
}

function gather_kuryr_data {
  echo "INFO: Gathering kuryr data"
  CONTROLLER_POD=$(oc -n openshift-kuryr get pods --no-headers -o custom-columns=":metadata.name" -l app=kuryr-controller)
  oc -n openshift-kuryr exec "${CONTROLLER_POD}" -- bash -c \
  'kuryr-gather-openstack-data --config-dir /etc/kuryr' > "${NETWORK_LOG_PATH}"/get_openstack_data &
  PIDS+=($!)
  oc get pods -A -o wide --show-labels > "${NETWORK_LOG_PATH}"/get_pods & PIDS+=($!)
  oc get kuryrnetworks -A -o yaml > "${NETWORK_LOG_PATH}"/get_kuryrnetworks & PIDS+=($!)
  oc get kuryrnetworkpolicy -A -o yaml > "${NETWORK_LOG_PATH}"/get_kuryrnetworkpolicy & PIDS+=($!)
  oc get kuryrport -A -o yaml > "${NETWORK_LOG_PATH}"/get_kuryrport & PIDS+=($!)
  oc get kuryrloadbalancer -A -o yaml > "${NETWORK_LOG_PATH}"/get_kuryrloadbalancer & PIDS+=($!)
  oc get svc -A > "${NETWORK_LOG_PATH}"/get_svc & PIDS+=($!)
}

function gather_kuryr_nodes_data {
  echo "INFO: Gathering kuryr nodes data"
  for NODE in ${NODES}; do
      CNI_POD=$(oc -n openshift-kuryr get pods --no-headers -o custom-columns=":metadata.name" --field-selector spec.nodeName="${NODE}" -l app=kuryr-cni)
      oc exec -n openshift-kuryr "${CNI_POD}" -- bash -c "for pid in $(find /host_proc/[1-9]*/ns/net | cut -d/ -f3); do \
          echo 'Namespace: \$pid'; \
          nsenter --net=/host_proc/\$pid/ns/net ip -d addr; \
          done" > "${NETWORK_LOG_PATH}"/"${CNI_POD}"_interfaces & PIDS+=($!)
  done
}

if [ $# -eq 0 ]; then
    echo "WARNING: Collecting network logs on ALL linux nodes in your cluster. This could take a long time." >&2
fi

PIDS=()
NODES="${@:-$(oc get nodes -o jsonpath='{range .items[*]}{@.metadata.name} {.status.nodeInfo.operatingSystem==linux}')}"
NETWORK_TYPE=$(oc get network.config.openshift.io -o=jsonpath='{.items[0].spec.networkType}' | tr '[:upper:]' '[:lower:]')
IPSEC_PODS=($(oc -n openshift-ovn-kubernetes get pods -l app=ovn-ipsec -o=jsonpath='{.items[*].metadata.name}'))

if [[ "${NETWORK_TYPE}" == "openshiftsdn" ]]; then
    gather_multus_data
    gather_openshiftsdn_nodes_data
elif [[ "${NETWORK_TYPE}" == "kuryr" ]]; then
    gather_kuryr_nodes_data
    gather_kuryr_data
elif [[ "${NETWORK_TYPE}" == "ovnkubernetes" ]]; then
    if [-z "$IPSEC_PODS"]; then
        echo "INFO: No ovn-ipsec pods exist, tunnel traffic will be unencrypted"
    else 
        echo "INFO: ovn-ipsec is enabled, tunnel traffic should be encryted"  
        gather_ovn_ipsec_data
    fi 
    gather_multus_data
    gather_ovn_kubernetes_nodes_data
    gather_ovn_kubernetes_master_data
fi

echo "INFO: Waiting for node network log collection to complete ..."
wait "${PIDS[@]}"
echo "INFO: Node network log collection complete."

# force disk flush to ensure that all data gathered is accessible in the copy container
sync
