#!/usr/bin/env bash

# SPDX-FileCopyrightText: (C) 2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

# Script Name: agents_deploy.sh
# Description: This script is meant to run as systemd service
# and is used to install/configure enic agents.

set -xeo pipefail

DEPLOY_TYPE=ENIC

# load functions from other files
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
# shellcheck disable=SC1091
source "$SCRIPT_DIR/_utils.sh"

function configure-certs() {
  set +e
  # FIXME improve this check - using for example nc for reachability
  INTEL_NETWORK=$(env | grep -i proxy | grep -i intel)
  if [ -n "${INTEL_NETWORK}" ]; then
    if [ ! -f /usr/local/share/ca-certificates/IntelSHA256RootCA-base64.crt ]; then
      set -e
      ca_bundle_list="Intel%20Root%20Certificate%20Chain%20Base64.zip \
        Public%20Root%20Certificate%20Chain%20Base64.zip \
        IntelSHA2RootChain-Base64.zip \
        PublicSHA2RootChain-Base64.zip"

      for bundle in $ca_bundle_list; do
        wget -O- -O /usr/local/share/ca-certificates/tmp.zip "http://certificates.intel.com/repository/certificates/${bundle}"
        unzip /usr/local/share/ca-certificates/tmp.zip -d /usr/local/share/ca-certificates
        rm /usr/local/share/ca-certificates/tmp.zip
      done
    fi
  fi
  set -e
  update-ca-certificates -f
}

function configure-logrotate() {
  echo "Configure log-rotate job"
  if ! grep -q "cron.emt" "/etc/crontab"; then
    sed -i '$ d' /etc/crontab
    echo "*/5 *   * * *   root    cd / && run-parts --report /etc/cron.emt" | tee -a /etc/crontab
    echo "#" | tee -a /etc/crontab
  fi
  rm -rf /etc/cron.emt
  mkdir -p /etc/cron.emt
  tee /etc/cron.emt/logrotate << END
#!/bin/sh

/usr/sbin/logrotate /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
    /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit $EXITVALUE
END

chmod +x /etc/cron.emt/logrotate

tee /etc/logrotate.d/rsyslog << END
/var/log/syslog
/var/log/mail.info
/var/log/mail.warn
/var/log/mail.err
/var/log/mail.log
/var/log/daemon.log
/var/log/kern.log
/var/log/auth.log
/var/log/user.log
/var/log/lpr.log
/var/log/cron.log
/var/log/debug
/var/log/messages
{
        rotate 4
        weekly
        missingok
        size 1G
        notifempty
        compress
        delaycompress
        sharedscripts
        postrotate
                /usr/lib/rsyslog/rsyslog-rotate
        endscript
}
END

  systemctl restart rsyslog.service
  systemctl restart cron.service
  /usr/sbin/logrotate /etc/logrotate.conf
}

function configure-token-folder() {
  echo "Configure token folder"
  # Create folders to store tokens generated by the node-agent
  chmod -R 700 /etc/intel_edge_node/client-credentials
  chown -R node-agent:bm-agents /etc/intel_edge_node
}

function configure-users-group() {
  echo "Configure users and groups"
  # Setup user and groups needed for the agents
  groupadd -f bm-agents -g 500 --system
  id -u prometheus &>/dev/null || useradd prometheus -u 501 --system -g bm-agents
  id -u fluent-bit &>/dev/null || useradd fluent-bit -u 502 --system -g bm-agents -G adm
  id -u node-agent &>/dev/null || useradd node-agent --system -g bm-agents
  id -u platform-update-agent &>/dev/null || useradd platform-update-agent --system -g bm-agents

  if id "etcd" &>/dev/null; then
    echo "User 'etcd' already exists."
  else
    # Add the etcd if it doesn't exist
    useradd -r -c "etcd user" -s /sbin/nologin -M "etcd" -U
    echo "User 'etcd' added successfully."
  fi
}

function configure-misc() {
  echo "Configure misc. settings"
  echo "LANG=en_US.UTF-8" > /etc/default/locale
  {
    echo "net.ipv6.conf.eth0.proxy_ndp=1"
    echo "net.ipv6.conf.all.forwarding=1"
    echo "net.ipv6.conf.default.forwarding=1"
  } >> /etc/sysctl.conf
  sed -i 's@\(MACAddressPolicy=\).*@\1none@g' /usr/lib/systemd/network/99-default.link
  update-rc.d -f nginx disable
}

function configure-security-fs() {
  echo "Configure security-fs"
  set +e
  securityfs=$(mount|grep securityfs)
  if [ -z "$securityfs" ]; then
    set -e
    mount -t securityfs securityfs /sys/kernel/security
  fi
  set -e
}

function configure-environment() {
  set +e
  # NOTE that the service will restart indefinetely until it finishes the config
  if [ ! -f /opt/enic/bin/agents_env.sh ]; then
    set -e
    # Proxy configuration
    proxy=$(envsubst < /etc/proxy.tpl)
    echo "${proxy}" > /etc/environment
    echo "${proxy}" > /etc/systemd/system/containerd.service.d/proxy.conf
    echo "${proxy}" > /etc/systemd/system/docker.service.d/proxy.conf

    # Keep proxy settings for root user
    tee /etc/sudoers.d/proxy-fix < /etc/sudoers.txt
    chown root:root /etc/sudoers.d/proxy-fix
    
    # cluster dns configuration
    clusterdns=$(envsubst < /etc/cluster-dns/env.tpl)
    echo "${clusterdns}" > /etc/cluster-dns/env
    # environment configuration
    configureEnvironment
    exit 1
  fi
  set -e
  # shellcheck disable=SC1091
  source /opt/enic/bin/agents_env.sh
}

function pre-agents-configure() {
  configure-environment
  configure-security-fs
  if [ $DEPLOY_TYPE == "ENIC" ]; then
    configure-misc
  fi
  configure-users-group
  # configure-token-folder
  configure-logrotate
  configure-certs
}

function install-node-agent() {
  echo "Install node-agent"
  # Caddy is a node-agent dependency
  apt-get install -y -o Dpkg::Options::="--force-confnew" "/opt/bma_packages/caddy_${CADDY_VERSION}_linux_amd64.deb"
  echo "node-agent node-agent/onboarding.serviceURL string ${ORCH_I_URL}" | debconf-set-selections
  echo "node-agent node-agent/auth.accessTokenURL string ${ORCH_TOKEN_URL}" | debconf-set-selections
  echo "node-agent node-agent/auth.rsTokenURL string ${RS_TOKEN_URL}" | debconf-set-selections
  echo "node-agent node-agent/auth.RSType string ${RS_TYPE}" | debconf-set-selections
  echo "node-agent node-agent/proxy.aptSourceURL string ${APT_SOURCE_URL}" | debconf-set-selections
  echo "node-agent node-agent/proxy.aptSourceProxyPort string ${APT_SOURCE_PROXY_PORT}" | debconf-set-selections
  echo "node-agent node-agent/proxy.aptSourceFilesRSRoot string ${APT_SOURCE_REPO_ROOT}" | debconf-set-selections
  apt-get install -y -o Dpkg::Options::="--force-confnew" "/opt/bma_packages/node-agent_${NODE_AGENT_VERSION}_amd64.deb"
}

function install-cluster-agent() {
  echo "Install cluster-agent"
  echo "cluster-agent cluster-agent/cluster-orchestrator-url string ${ORCH_C_URL}" | debconf-set-selections
  apt-get install -y -o Dpkg::Options::="--force-confnew" "/opt/bma_packages/cluster-agent_${CLUSTER_AGENT_VERSION}_amd64.deb" cluster-agent="${CLUSTER_AGENT_VERSION}"
}

function install-hda-agent() {
  echo "Install hardware-discovery-agent"
  echo "hardware-discovery-agent hardware-discovery-agent/onboarding.serviceURL string ${ORCH_I_URL}" | debconf-set-selections
  apt-get install -y -o Dpkg::Options::="--force-confnew" "/opt/bma_packages/hardware-discovery-agent_${HDA_AGENT_VERSION}_amd64.deb" hardware-discovery-agent="${HDA_AGENT_VERSION}"
}

function install-poa-agent() {
  echo "Install platform-observability-agent"
  echo "platform-observability-agent platform-observability-agent/host string $ORCH_N_L_OBS" | debconf-set-selections
  echo "platform-observability-agent platform-observability-agent/port string $ORCH_N_L_OBS_PORT" | debconf-set-selections
  echo "platform-observability-agent platform-observability-agent/metrics-host string $ORCH_N_M_OBS" | debconf-set-selections
  echo "platform-observability-agent platform-observability-agent/metrics-port string $ORCH_N_M_OBS_PORT" | debconf-set-selections
  apt-get install -y -o Dpkg::Options::="--force-confnew" "/opt/bma_packages/platform-observability-agent_${POA_AGENT_VERSION}_amd64.deb" platform-observability-agent="${POA_AGENT_VERSION}"
  # disable telegraf plugins which won't work in a container
  # sed '/inputs.ras/d' /etc/telegraf/telegraf.conf -i
}

function install-trtl() {
  echo "Install trtl"
  apt-get install -y "/opt/bma_packages/trtl-${TRTL_VERSION}.EVAL.deb" trtl="${TRTL_VERSION}"
}

function install-inbm-cloudadapter-agent() {
  echo "Install inbm-cloudadapter-agent"
  apt-get install -y "/opt/bma_packages/inbm-cloudadapter-agent-${INBM_CLOUDADAPTER_AGENT_VERSION}.EVAL.deb" inbm-cloudadapter-agent="${INBM_CLOUDADAPTER_AGENT_VERSION}"
}

function install-inbm-dispatcher-agent() {
  echo "Install inbm-dispatcher-agent"
  apt-get install -y "/opt/bma_packages/inbm-dispatcher-agent-${INBM_DISPATCHER_AGENT_VERSION}.EVAL.deb" inbm-dispatcher-agent="${INBM_DISPATCHER_AGENT_VERSION}"
}

function install-inbm-configuration-agent() {
  echo "Install inbm-configuration-agent"
  apt-get install -y "/opt/bma_packages/inbm-configuration-agent-${INBM_CONFIGURATION_AGENT_VERSION}.EVAL.deb" inbm-configuration-agent="${INBM_CONFIGURATION_AGENT_VERSION}"
}

function install-inbm-telemetry-agent() {
  echo "Install inbm-telemetry-agent"
  apt-get install -y "/opt/bma_packages/inbm-telemetry-agent-${INBM_TELEMETRY_AGENT_VERSION}.EVAL.deb" inbm-telemetry-agent="${INBM_TELEMETRY_AGENT_VERSION}"
}

function install-inbm-diagnostic-agent() {
  echo "Install inbm-diagnostic-agent"
  apt-get install -y "/opt/bma_packages/inbm-diagnostic-agent-${INBM_DIAGNOSTIC_AGENT_VERSION}.EVAL.deb" inbm-diagnostic-agent="${INBM_DIAGNOSTIC_AGENT_VERSION}"
}

function install-inbm-components() {
  echo "Install inbm components"
  install-inbm-cloudadapter-agent
  install-inbm-dispatcher-agent
  install-inbm-configuration-agent
  install-inbm-telemetry-agent
  install-inbm-diagnostic-agent
}

function install-inbc-program() {
  echo "Install inbc-program"
  apt-get install -y "/opt/bma_packages/inbc-program-${INBC_PROGRAM_VERSION}.EVAL.deb" inbc-program="${INBC_PROGRAM_VERSION}"
}

function install-mqtt() {
  echo "Install mqtt"
  apt-get install -y "/opt/bma_packages/mqtt-${MQTT_VERSION}.deb" mqtt="${MQTT_VERSION}"
}

function install-tpm-provision() {
  echo "Install tpm-provision"
  apt-get install -y "/opt/bma_packages/tpm-provision-${TPM_PROVISION_VERSION}.deb" tpm-provision="${TPM_PROVISION_VERSION}"
}

function install-platform-update-agent() {
  echo "Install platform-update-agent"
  echo "platform-update-agent platform-update-agent/bmaDebURL string ${APT_SOURCE_URL}" | debconf-set-selections
  echo "platform-update-agent platform-update-agent/updateServiceURL string ${ORCH_I_MM_URL}" | debconf-set-selections
  apt-get install -y "/opt/bma_packages/platform-update-agent_${PLATFORM_UPDATE_AGENT_VERSION}_amd64.deb" platform-update-agent="${PLATFORM_UPDATE_AGENT_VERSION}"
}

function install-platform-telemetry-agent() {
  echo "Install platform-telemetry-agent"
  echo "telemetry-agent telemetry-agent/telemetrymanager.serviceURL string ${ORCH_I_TM_URL}" | debconf-set-selections
  apt install -y -o Dpkg::Options::="--force-confnew" "/opt/bma_packages/platform-telemetry-agent_${PLATFORM_TELEMETRY_AGENT_VERSION}_amd64.deb" platform-telemetry-agent="${PLATFORM_TELEMETRY_AGENT_VERSION}"
}

function configure-platform-update-agent() {
  echo "Configure platform-update-agent"

  DEVICE_GUID=$(dmidecode -s system-uuid)
  sed -i "s|GUID: '.*'|GUID: '$DEVICE_GUID'|" /etc/edge-node/node/confs/platform-update-agent.yaml
  systemctl restart platform-update-agent
}

function configure-platform-telemetry-agent() {
  echo "Configure platform-telemetry-agent"

  DEVICE_GUID=$(dmidecode -s system-uuid)
  sed -i "s|nodeid: .*|nodeid: $GUID|" /etc/edge-node/node/confs/platform-telemetry-agent.yaml
  systemctl restart platform-telemetry-agent
}

function configure-platform-observability-agent() {
  echo "Configure platform-observability-agent"

  GUID=$(dmidecode -s system-uuid)
  export GUID
  yq -i '.processors.attributes.actions[] |= select(.key == "hostGuid").value = strenv(GUID)' /etc/otelcol/otelcol.yaml
  sed -i "s|EdgeNodeID .*|EdgeNodeID $GUID|" /etc/fluent-bit/fluent-bit.conf

  systemctl restart platform-observability-logging
  systemctl restart platform-observability-metrics
  systemctl restart platform-observability-collector
  systemctl restart platform-observability-health-check
}

function configure-cluster-agent() {
  echo "Configure cluster-agent"

  DEVICE_GUID=$(dmidecode -s system-uuid)
  sed -i "s|GUID: '.*'|GUID: '$DEVICE_GUID'|" /etc/edge-node/node/confs/cluster-agent.yaml
  systemctl restart cluster-agent
}

function configure-node-agent() {
  echo "Configure node-agent"
  # this is a hack to work around the fact that in kubernetes
  # - cat /sys/class/dmi/id/product_uuid
  # - dmidecode -s system-uuid
  # return different values

  DEVICE_GUID=$(dmidecode -s system-uuid)
  sed -i "s|GUID: '.*'|GUID: '$DEVICE_GUID'|" /etc/edge-node/node/confs/node-agent.yaml
  systemctl restart node-agent

  echo "Wait for node agent and pua proxy to start"
  while true; do
  http_status=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${APT_SOURCE_PROXY_PORT}/${APT_SOURCE_REPO_ROOT}/edge-node.asc")
  if [ "$http_status" -eq 200 ]; then
    echo "PUA client proxy is active"
    break
  else
    echo "HTTP status code is $http_status. Retrying in 5 seconds..."
    sleep 5
  fi
  done
}

function configure-credentials-permissions() {
  echo "Configure client-credentials permissions"
  chown -R node-agent:bm-agents /etc/intel_edge_node/client-credentials
}

function configure-systemd-policy() {
  echo "Configure policy-rc.d"
  # From this point all our agents are out of the "jail"
  tee /usr/sbin/policy-rc.d << END
#!/bin/sh
exit 0
END
}

# Allows shared mounts. This is needed for the cni installation.
# Make sure to fix the cni installation error:
# spec: failed to generate spec: path "/opt/cni/bin" is mounted on "/" but it is not a shared mount  
function configure-mount {
  mount --make-rshared /
}

function post-agents-configure() {
  configure-systemd-policy
  configure-credentials-permissions
  configure-node-agent
  configure-cluster-agent
  systemctl restart hardware-discovery-agent
  configure-platform-observability-agent
  configure-platform-update-agent
  configure-platform-telemetry-agent
  configure-mount
}

echo "Pre-agents configure"
pre-agents-configure

echo "Install edge node agents"
# FIXME simplify process by downloading the en deb repo
mkdir -p /etc/intel_edge_node/client-credentials

install-node-agent
install-cluster-agent
install-hda-agent
install-poa-agent
install-trtl
install-inbm-components
install-inbc-program
install-mqtt
install-tpm-provision
install-platform-update-agent
install-platform-telemetry-agent

# once the client secret exists in the shared volume, restart the agents
until [ -f /etc/intel_edge_node/client-credentials/client_secret ]
do
  sleep 5
done

echo "Post-agents configure"
post-agents-configure

touch /var/edge_node/edge_node_provisioned
