#!/bin/bash

# moovIT GmbH - B. Dimmel

# Version 5.2
# Changelog: May 15th 2025

# Updated commands for Debian 11/Buster support.
# Refined Docker keyring and apt commands for Debian, Ubuntu, and CentOS Stream 8.
# Changed stack name from Helmut4 to helmut4.
# Added installer support for CentOS Stream 8.
# Prompt added for /mnt/ folder input.
# Implemented Docker availability check.
# Added functionality to download companion assets.
# Introduced a repository and URL checker.
# Added a 3-second timeout for repository requests.
# Included support for both HTTP and HTTPS in repository URLs.
# Added an option to download and extract companion files.
# Updated Portainer tag from :latest to :lts.
# Fixed issue with companion download verification.
# Removed input prompts for companion download and mountpoint.
# Enhanced repository check for Ubuntu 24.04.1+ LTS.
# Included a check to ensure the script is run with sudo permissions.
# Added validation for the target OS and improved user interaction.
# Check for existing docker installation
# Replaced stack deployment method with Portainer API.

# Check if the script is run with sudo permissions
if [ "$EUID" -ne 0 ]; then
    echo "Please run this script via sudo bash install.sh"
    exit 1
fi

# Check if Docker is already installed by verifying via docker version command
if command -v docker >/dev/null 2>&1; then
    # Retrieve Docker version information.
    docker_version=$(docker --version 2>&1)
    echo -e "\nError: ${docker_version} is already installed on this system." >&2
    echo -e "\nInstallation aborted: The helmut4 installer is designed for a fresh, vanilla OS environment only.\n"
    exit 1
fi

echo -e "\nDocker is not installed. Proceeding with helmut4 installation..."

echo -e "Checking necessary repository ports for availability ..."
sleep 2

# Source the OS release information and redirect errors to output
. /etc/os-release 2>&1

# Check if all necessary ports are available
all_reachable=true

# Function to find repository URL in sources
find_repo_url() {
    local response
    local source_file

    # First, check /etc/apt/sources.list.d/ubuntu.sources
    response=$(grep -rhE '^URIs: ' /etc/apt/sources.list.d/ubuntu.sources 2>/dev/null | awk '{print $2}' | sed -E 's#https?://([^/]+).*#\1#')
    
    # If a URL was found, set source file
    if [[ -n "$response" ]]; then
        source_file="/etc/apt/sources.list.d/ubuntu.sources"
    else
        # If no URL was found, check /etc/apt/sources.list
        response=$(grep -rhE '^deb ' /etc/apt/sources.list 2>/dev/null | awk '{print $2}' | sed -E 's#https?://([^/]+).*#\1#')
        
        # Set source file if found in sources.list
        if [[ -n "$response" ]]; then
            source_file="/etc/apt/sources.list"
        fi
    fi

    # Extract the first hostname, if it exists
    first_url=$(echo "$response" | head -n 1)
    repo_url="$first_url"

    if [[ -n "$repo_url" ]]; then
        echo "Repository server found: $repo_url in $source_file"
    else
        echo "No repository server found in sources list files."
    fi
}

# Check for Debian or Ubuntu
if [[ $NAME == *"Debian"* ]] || [[ $NAME == *"Ubuntu"* ]]; then

    # Check if OS is Ubuntu Server or another distro
    dpkg -l ubuntu-desktop > /dev/null 2>&1
    if [[ $? -eq 0 ]]; then
        LOCATION="desktop or unknown"
        # Confirm installation on unsupported OS 
        while true; do

        echo -e "You are executing this script on a unsupported & suggested Ubuntu Server LTS machine: $NAME";
        read -p "Do you want to proceed with the installation on an unsupported Linux distribution? (y/n)" yn

        case $yn in 
            #If input is yes we leave the loop
            [yY] ) echo "Ok, we will continue with installation  ...";
                mkdir -p /etc/helmut4
                file_path="/etc/helmut4/unsupportedOS"
                current_date_time=$(date)
                echo "Installation on unsupported OS - $current_date_time" > "$file_path"
                break;;
            
            #No - abport binary installaton
            [nN] ) 
                        echo -e "\nSkipping installation!";
                exit 1;;
            
            #If input is neither y nor n
            * ) echo "Invalid response for question";
            echo -e "\nManual abortion of installation!";
            exit 1;;
        esac
        done

    else
        LOCATION="server"
    fi

    # Check if app repo urls are accessible
    find_repo_url

    # List of hostnames to check
    hostnames=(
        "repo.moovit24.de"
        "download.docker.com"
        "docker.com"
        "docker.io"
        "python.org"
        "$repo_url"
        "canonical.com"
        "snapcraft.io"
    )

    for hostname in "${hostnames[@]}"; do
        if [[ -z "$hostname" ]]; then
            continue
        fi

        echo "Checking $hostname (3 sec timeout) ..."

        if nc -zv -w 3 "$hostname" 443 >/dev/null 2>&1; then
            echo -e "  OK - $hostname reachable via port 443\n"
        else
            echo -e "  FAIL - $hostname is not reachable via port 443"
            echo -e "<--------------------------------------------------->\n\n"
            all_reachable=false

            if nc -zv -w 3 "$hostname" 80 >/dev/null 2>&1; then
                echo -e "    -> OK - $hostname reachable via port 80\n"
                all_reachable=true
            else
                echo -e "    FAIL - $hostname is not reachable via port 80 as well\n"
            fi
        fi
    done

# Check for CentOS / CentOS Streams
elif [[ $NAME == *"CentOS"* ]]; then
    # Confirm installation on unsupported OS 
    while true; do

    echo -e "You are running this script on an unsupported machine: $NAME. It is recommended to use an Ubuntu Server LTS";
    read -p "Do you want to proceed with the installation on an unsupported Linux distribution? (y/n)" yn

    case $yn in 
        #If input is yes we leave the loop
        [yY] ) echo "Ok, we will continue with installation  ...";
            mkdir -p /etc/helmut4
            file_path="/etc/helmut4/unsupportedOS"
            current_date_time=$(date)
            echo "Installation on unsupported OS - $current_date_time" > "$file_path"
            break;;
        
        #No - abport binary installaton
        [nN] ) 
            echo -e "\nSkipping installation!";
            exit 1;;
        
        #If input is neither y nor n
        * ) echo "Invalid response for question";
        echo -e "\nManual abortion of installation!";
        exit 1;;
    esac
    done

    # Path to the file containing the data
    file_path="/etc/yum.repos.d/centos.repo"

    # Extract the first metalink value using sed
    first_metalink=$(sed -n '/\[baseos\]/,/\[/ s/^metalink=\(.*\)$/\\1/p' "$file_path")

    # Extract the domain part from the metalink URL
    repo_url=$(echo "$first_metalink" | awk -F/ '{print $3}')

    echo -e "Repository server: $repo_url"

    # List of hostnames to check
    hostnames=(
        "repo.moovit24.de"
        "download.docker.com"
        "docker.com"
        "docker.io"
        "python.org"
        "$repo_url"
    )

    for hostname in "${hostnames[@]}"; do
        echo -e "Checking $hostname (3 sec timeout) ..."

        if curl --head --silent --output /dev/null --fail --max-time 3 "https://$hostname"; then
            echo -e "  OK - $hostname reachable via port 443\n"
        else
            echo -e "  FAIL - $hostname is not reachable via port 443"
            echo -e "<--------------------------------------------------->\n\n"
            all_reachable=false

            if curl --head --silent --output /dev/null --fail --max-time 3 "http://$hostname"; then
                echo -e "    -> OK - $hostname reachable via port 80\n"
                all_reachable=true
            else
                echo -e "    FAIL - $hostname is not reachable via port 80 as well\n"
            fi
        fi
    done
fi

# Display final message
if $all_reachable; then
    echo -e "All repositories are reachable - continue with Helmut4 installation.\n"
else
    echo -e "Some repositories are not reachable - please adjust firewall access before you continue!\n"
    exit 1
fi


echo -e "\nStarting Helmut4 installation ...\n"

echo -e "  _   _      _                 _     _  _   "
echo -e " | | | | ___| |_ __ ___  _   _| |_  | || |  "
echo -e " | |_| |/ _ \ | '_   _ \| | | | __| | || |_ "
echo -e " |  _  |  __/ | | | | | | |_| | |_  |__   _|"
echo -e " |_| |_|\___|_|_| |_| |_|\__,_|\__|    |_|  "

echo -e "\n"
sleep 2

mkdir -p /etc/docker
echo -e "{\"log-driver\": \"json-file\",\"log-opts\": {\"max-size\": \"10m\",\"max-file\": \"3\"}}" > /etc/docker/daemon.json

if [[ $NAME == *"Debian"* ]]; then
### DEBIAN 9, 10, 11, 12 ###
echo -e "\nStarting the Helmut4 installation on OS $NAME version $VERSION ...\n"
sleep 2

#Install sudo commands
apt-get install sudo -y
sudo apt-get update -y
if [ $? != 0 ]; 
then
echo -e "aptitude is in use by someone else (maybe the system itself) - please retry later - exiting.."
exit 1
fi

sudo apt-get install ca-certificates curl gnupg lsb-release -y
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg


echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
sudo apt-get install httpie jq -y

sudo systemctl restart docker.service
echo -e "\nOS installation part finished - switching over to Docker sub-process ...\n"
sleep 10
### /DEBIAN ###

elif [[ $NAME == *"Ubuntu"* ]]; then
### UBUNTU ###
echo -e "\nStarting the Helmut4 installation on OS $NAME version $VERSION ...\n"
sleep 2

sudo apt-get update -y
if [ $? != 0 ]; 
then
echo "aptitude is in use by someone else (maybe the system itself) - please retry later - exiting.."
exit 1
fi
sudo apt-get install ca-certificates curl gnupg lsb-release -y
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update -y
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
sudo apt-get install httpie jq -y
sudo service docker start
echo -e "\nOS installation part finished - switching over to Docker sub-process ...\n"
sleep 10
### /UBUNTU ###

elif [[ $NAME == *"CentOS Stream"* ]] && [[ $VERSION == *"8"* ]]; then
### CENTOS Streams ###
echo -e "\nStarting the Helmut4 installation on OS $NAME version $VERSION ...\n"
sleep 2

sudo yum update -y
sudo yum install -y yum-utils device-mapper-persistent-data lvm2 nano
sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm

sudo yum update -y

sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum update -y --nobest --allowerasing
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin


sudo yum -y install httpie jq
sudo systemctl start docker
sudo systemctl enable /usr/lib/systemd/system/docker.service

echo -e "\nOS installation part finished - switching over to Docker sub-process ...\n"
sleep 10
### /CENTOS Streams###

elif [[ $NAME == *"CentOS"* ]] && [[ $NAME != *"CentOS Stream"* ]]; then
### CENTOS 7 ###
echo -e "\nStarting the Helmut4 installation on OS $NAME version $VERSION ...\n"
sleep 2

sudo yum update -y
sudo yum --enablerepo=extras install epel-release -y
sudo yum update -y
sudo yum install -y yum-utils device-mapper-persistent-data lvm2 nano
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 
sudo yum update -y
if [[ $(rpm --eval '%{centos_ver}') == "8" ]]; then
sudo yum install -y docker-ce docker-ce-cli containerd.io --nobest
pip3 install httpie
pip3 install docker-compose
else
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo yum install -y httpie docker-compose
fi
sudo yum -y install jq
sudo systemctl start docker
sudo systemctl enable /usr/lib/systemd/system/docker.service

echo -e "\nOS installation part finished - switching over to Docker sub-process ...\n"
sleep 10
### /CENTOS ###

else
echo -e "Unknown or unsupported operating system - only Ubuntu, Debian and CentOS 7/8/Streams 8 is supported - exiting.."
exit 1
fi

echo -e "\nStarting configuring Docker, Portainer & the helmut4 stack ...\n"

echo -e "     ____             __                __    __       __  ____ __"
echo -e "    / __ \____  _____/ /_____  _____   / /    \ \     / / / / // /"
echo -e "   / / / / __ \/ ___/ //_/ _ \/ ___/  / / _____\ \   / /_/ / // /_"
echo -e "  / /_/ / /_/ / /__/ ,< /  __/ /      \ \/_____/ /  / __  /__  __/"
echo -e " /_____/\____/\___/_/|_|\___/_/        \_\    /_/  /_/ /_/  /_/   "
echo -e "\n "
sleep 2

### GENERAL ###
touch /etc/localtime
touch /etc/timezone

# -> Portainer CE latest v2.x.x
docker run -it -d --restart=always -p 9000:9000 --name=portainer -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:2.26.1 --admin-password='$2y$05$WbcqfTqVa2T58lGrLO7Tp.30DMjKFo.6O4.XAmfBFg4a0jrVSbdW.' -H unix:///var/run/docker.sock
sleep 10
docker swarm init --advertise-addr 127.0.0.1
docker swarm ca --cert-expiry 175200h --rotate

#Create folder for certificates
mkdir /root/certs

echo -e "\nDeploying default helmut4 stack ...\n"

mkdir -p /etc/helmut4 && chmod a+w /etc/helmut4
JWT=$(http --ignore-stdin POST :9000/api/auth Username="admin" Password="admin" | jq -r ".jwt")
SWARM_ID=$(http --ignore-stdin GET :9000/api/endpoints/1/docker/swarm "Authorization:Bearer ${JWT}" | jq -r ".ID")
http --ignore-stdin POST ":9000/api/registries" "Authorization:Bearer ${JWT}" Name="MoovIT GmbH" URL="repo.moovit24.de:443" Type:=3 Authentication:=true Username="moovit" Password="public"
echo -e "\nDeploying the Helmut Stack, this might take some time.. (Timeout is set to 10 minutes)\n"
STACK=$(curl -s https://repo.moovit24.de/install/config/docker-compose.yml)
http --ignore-stdin --timeout=1200 POST :9000/api/stacks/create/swarm/string?endpointId=1 Authorization:"Bearer ${JWT}" name="helmut4" stackFileContent="${STACK}" swarmID="${SWARM_ID}" fromAppTemplate:=false

echo -e "\nStack configuration sucessfull"
sleep 2

#DEBIAN - set update commands to /usr/local/bin
if [[ $NAME == *"Debian"* ]]; then
echo -e "\nSetting helmut update commands for $NAME ...\n"

echo -e "#/bin/bash\\ncurl -s https://repo.moovit24.de/install/update.sh | bash" > /usr/local/bin/helmut-update && chmod  a+x /usr/local/bin/helmut-update
echo -e "#/bin/bash\\ncurl -s https://repo.moovit24.de/install/snapshot.sh | bash -s \${1}" > /usr/local/bin/helmut-snapshot && chmod  a+x /usr/local/bin/helmut-snapshot
sleep 2

#UBUNTU/CentOS set update commands to /usr/sbin
else
echo -e "\nSetting helmut update commands for $NAME ...\n"
echo -e "#/bin/bash\\ncurl -s https://repo.moovit24.de/install/update.sh | bash" > /usr/sbin/helmut-update && chmod  a+x /usr/sbin/helmut-update
echo -e "#/bin/bash\\ncurl -s https://repo.moovit24.de/install/snapshot.sh | bash -s \${1}" > /usr/sbin/helmut-snapshot && chmod  a+x /usr/sbin/helmut-snapshot

sleep 2
fi

echo -e "Helmut4 setup done.\n\nYou might want to change the portainer password from admin:admin to something more secure...\n\n\n"
### /GENERAL ###
