#!/bin/bash

set -e

REPO_TYPE=testing # Тип репозитория, необходимо заменить на stable, prerelease или testing, заменяется в job-е Jenkins-а
HOST=downloads.artix.su

URL="http://${HOST}/static/downloads/install_scripts/${REPO_TYPE}/puppet_env"
URL_MAIN="http://${HOST}/static/downloads/install_scripts/${REPO_TYPE}/main"
URL_CS="http://${HOST}/static/downloads/install_scripts/${REPO_TYPE}/cs_env"

# импорт сертификата для docker
curl ${URL_MAIN}/import_docker_cert.sh -o /tmp/import_docker_cert.sh
. /tmp/import_docker_cert.sh

CHECKED_PORTS="[8140, 8072, 8073, 45873]"
DOCKER_COMPOSE_NAME=puppet_env
DOCKER_FILES_DIRECTORY=/opt/artix/docker/$DOCKER_COMPOSE_NAME

log() {
    if [[ "TRACE" = "$1" ]] || [[ `(echo "TRACEDEBUGINFOERRORWARN" |sed s/^.*"TRACE"//g )` == *"$1"* ]]; then
        echo "`date '+%Y-%m-%d %H:%M:%S'` $1: $2"
    fi;
}

trim() {
    echo -e "${1}" | tr -d '[[:space:]]'
}
isEmpty() {
    if [[ -z "$(trim "$1")" ]] || [[ -z "$1" ]]; then
        true
    else
        false
    fi;
}
askQuestion() {
    local MSG=`log INFO`

    if (isEmpty $1); then
        MSG="$MSG Do you want to continue (y/n)?"
    else
        MSG="$MSG $1"
    fi

    read -p "$MSG" choice
    case "$choice" in
      y|Y|"" ) true;;
      n|N ) exit 1;;
      * ) false;;
    esac
}
isContainersExist() {
    local NAME="$DOCKER_COMPOSE_NAME"

    docker ps -a | while read line; do
        if [[ ${line} =~ $NAME ]]; then
            echo true
            break
        fi
    done
}

check_ports() {
  if [[ $(fuser 8140/tcp 8072/tcp 8073/tcp 45873/tcp) ]]; then
      return 1
  else
      return 0
  fi
}

check_exist_certificate(){
    local CERTIFICATE_DIRECTORY="/etc/docker/certs.d"
    if [ -d "$CERTIFICATE_DIRECTORY" ] ;
        then
            log INFO "Directory $CERTIFICATE_DIRECTORY exists."
        else
            log ERROR "Error: Directory with certificate $CERTIFICATE_DIRECTORY not found. Install delivery app stopped."
            exit 1
    fi

    local CERTIFICATE_ARTIX_DIRECTORY="$CERTIFICATE_DIRECTORY/dockerregistry.artix.su:2443"

    if [ -d "$CERTIFICATE_ARTIX_DIRECTORY" ] ;
        then
            log INFO "Directory $CERTIFICATE_ARTIX_DIRECTORY exists."
        else
            log ERROR "Error: Certificate artix not added. Add certificate. Install delivery app stopped."
            exit 1
    fi
}

verify_artix_certificate(){
    local TARGET="dockerregistry.artix.su";
    log INFO "Verify expiration certificate for $TARGET";
    local expirationdate=$(date -d "$(: | openssl s_client -connect $TARGET:2443 -servername $TARGET 2>/dev/null \
                              | openssl x509 -text \
                              | grep 'Not After' \
                              |awk '{print $4,$5,$7}')" '+%s');

    local current_day=$(date +%s);
    if [ $current_day -gt $expirationdate ]; then
        log ERROR "Certificate for $TARGET expires on $(date -d @$expirationdate '+%Y-%m-%d')"
        exit 1;
    else
        log INFO "Certificate expires on $expirationdate";
    fi;
}

set_default_env_variable(){
    local VARIABLE="$1"
    local DEFAULT_VALUE="$2"
    local DESCRIPTION="$3"
    local var
    sudo touch $DOCKER_FILES_DIRECTORY/.env
    grep -q "^${VARIABLE}=" $DOCKER_FILES_DIRECTORY/.env || echo "${VARIABLE}=${DEFAULT_VALUE}"|sudo tee -a $DOCKER_FILES_DIRECTORY/.env
    read -p "Set ${DESCRIPTION}, current value: `grep \"^${VARIABLE}=\" ${DOCKER_FILES_DIRECTORY}/.env`: " var
    if [[ "$var" ]];then
        sudo sed -i "s/^${VARIABLE}=.*/${VARIABLE}=`echo $var|sed 's|/|\\\/|g'`/g" $DOCKER_FILES_DIRECTORY/.env
    fi;
}
check_exist_certificate;
verify_artix_certificate;


log INFO "Start install apt-transport-https, ca-certificates, curl, software-properties-common"

curl ${URL_CS}/extract_gpg_key.sh -o /tmp/extract_gpg_key.sh
. /tmp/extract_gpg_key.sh

apt-get update
apt-get install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common \
    gnupg \
    lsb-release

curl -fsSL "${URL_MAIN}/install_apt_key.sh" -o /tmp/install_apt_key.sh

vid=$(lsb_release -is)
vid=${vid,,}
log INFO "Add repository deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$vid $(lsb_release -cs) stable"
bash /tmp/install_apt_key.sh "https://download.docker.com/linux/${vid}/gpg" docker.gpg
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$vid \
   $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list

log INFO "apt-get update"

apt-get update

log INFO "Start install docker-ce"

apt-get install -y docker-ce

mkdir -p $DOCKER_FILES_DIRECTORY
# При повторном запуске сохраняем текущую конфигурацию до её замены.
CURRENT_COMPOSE="$DOCKER_FILES_DIRECTORY/docker-compose.yaml"
if test -f "$CURRENT_COMPOSE"; then
    # Обновляем
    COMPOSE_BACKUP="${CURRENT_COMPOSE}_$(date +%Y_%m_%d-%s)_backup"

    # Старый скрипт update не нужен. Обновление должно выполняться текущим скриптом
    rm -f -- "$DOCKER_FILES_DIRECTORY/update"

    # Стартуем контейнеры, если они были остановлены
    docker compose -f "$CURRENT_COMPOSE" start

    # Проверяем фактическую версию Puppet Server в уже запущенном контейнере.
    PUPPET_CONTAINER=$(docker compose -f "$CURRENT_COMPOSE" ps -q puppet 2>/dev/null | head -n1)
    if [[ -n "$PUPPET_CONTAINER" ]]; then
        PUPPETSERVER_VERSION=$(docker exec "$PUPPET_CONTAINER" puppetserver --version)
        PUPPETSERVER_MAJOR=$(echo "$PUPPETSERVER_VERSION" | grep -oE '[0-9]+' | head -n1)
        if [[ "$PUPPETSERVER_MAJOR" =~ ^[0-9]+$ ]] && (( PUPPETSERVER_MAJOR < 7 )); then
            log INFO "Puppet Server version $PUPPETSERVER_VERSION is older than 7; running Puppet 6 to 7 migration"
            curl -L "${URL}/migrate_from_6_to_7.sh" -o "$DOCKER_FILES_DIRECTORY/migrate_from_6_to_7.sh"
            (cd "$DOCKER_FILES_DIRECTORY" && chmod +x migrate_from_6_to_7.sh &&  ./migrate_from_6_to_7.sh)
        else
            log INFO "Puppet Server version: ${PUPPETSERVER_VERSION:-could not be determined}; migration not required"
        fi
    else
        log INFO "Puppet container is not running, break update"
        exit 2
    fi
    log INFO "Backup existing docker-compose.yaml to $COMPOSE_BACKUP"
    cp "$CURRENT_COMPOSE" "$COMPOSE_BACKUP"
else
    # Устанавливаем
    CONTINUE=true
    while ${CONTINUE}; do
        if ! check_ports ; then
            log WARN "You're have busy ports. Free up ports: $CHECKED_PORTS. Do it and we will continue!"
        else
            break
        fi
        CONTINUE=`askQuestion "Have you freed the ports? (y - continue/n - exit)"`
    done

    set_default_env_variable "CS_SERVER_HOST" "$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+')" "Artix:Cashserver host"
    log INFO "Current .env:"
    cat $DOCKER_FILES_DIRECTORY/.env
fi

# Качаем актуальный docker-compose.yaml
curl -L ${URL}/docker-compose.yaml -o $DOCKER_FILES_DIRECTORY/docker-compose.yaml

log INFO "Run ${DOCKER_COMPOSE_NAME} services"
(cd $DOCKER_FILES_DIRECTORY && docker compose up -d --pull always)
log INFO "Your's containers:"
docker ps | grep "${DOCKER_COMPOSE_NAME}"

echo -e '#!/bin/bash\nsudo docker compose stop'|sudo tee $DOCKER_FILES_DIRECTORY/stop > /dev/null && sudo chmod +x $DOCKER_FILES_DIRECTORY/stop
echo -e '#!/bin/bash\nsudo docker compose up -d --pull always'|sudo tee $DOCKER_FILES_DIRECTORY/start > /dev/null && sudo chmod +x $DOCKER_FILES_DIRECTORY/start
echo -e '#!/bin/bash\n[[ "$1" ]] && sudo docker compose up -d --force-recreate --no-deps $1 || echo "Please set service name as parameter!"'|sudo tee $DOCKER_FILES_DIRECTORY/restart_service > /dev/null \
    && sudo chmod +x $DOCKER_FILES_DIRECTORY/restart_service
echo -e '#!/bin/bash\n[[ "$1" ]] && sudo docker compose exec $@ || echo "Please set service name as parameter!"'|sudo tee $DOCKER_FILES_DIRECTORY/exec_service > /dev/null \
    && sudo chmod +x $DOCKER_FILES_DIRECTORY/exec_service
echo -e '#!/bin/bash\nsudo docker compose logs -f $@'|sudo tee $DOCKER_FILES_DIRECTORY/logs > /dev/null \
    && sudo chmod +x $DOCKER_FILES_DIRECTORY/logs
echo -e '#!/bin/bash\nsudo docker compose ps'|sudo tee $DOCKER_FILES_DIRECTORY/status > /dev/null && sudo chmod +x $DOCKER_FILES_DIRECTORY/status
