#!/bin/bash

# moovIT GmbH - B. Dimmel
# Linux hc worker for Helmut4
# Version: 4.0

# Changelog: Dec 5th 2024

# adopted commands for Debian 11/Buster
# updated docker keyring & apt commands (Debian+Ubuntu+Streams8)
# CentOS Streams 8 installer
# Check if Docker is available
# Linux render compsoe file
# ffmpeg static download
# unzip added
# rclone binary download
# 7-zip binary download
# repository check
# check for add-on URLs
# Changed portainer tag :latest to :lts
# updated linux binary to v2408
# Adopted additional repository check for U24.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 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

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
addons=true

# Function to find repository URL and source file
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"
        "johnvansickle.com"
        "rclone.org"
        "7-zip.org"
    )

    for hostname in "${hostnames[@]}"; do
        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"
            if [[ $hostname == "johnvansickle.com" || $hostname == "rclone.org" || $hostname == "7-zip.org" ]]; then
                addons=false  # Set addons to false if specifically those hostnames are unreachable
            else
                all_reachable=false  # Set all_reachable to false for other unreachable hostnames
            fi

            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"
                if [[ $hostname == "johnvansickle.com" || $hostname == "rclone.org" || $hostname == "7-zip.org" ]]; then
                    addons=false  # Set addons to false if specifically those hostnames are unreachable
                else
                    all_reachable=false  # Set all_reachable to false for other unreachable hostnames
                fi
            fi
        fi
    done

# Check for CentOS or CentOS Stream
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"
        "johnvansickle.com"
        "rclone.org"
        "7-zip.org"
    )

    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"
            if [[ $hostname == "johnvansickle.com" || $hostname == "rclone.org" || $hostname == "7-zip.org" ]]; then
                addons=false  # Set addons to false if specifically those hostnames are unreachable
            else
                all_reachable=false  # Set all_reachable to false for other unreachable hostnames
            fi

            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"
                if [[ $hostname == "johnvansickle.com" || $hostname == "rclone.org" || $hostname == "7-zip.org" ]]; then
                    addons=false  # Set addons to false if specifically those hostnames are unreachable
                else
                    all_reachable=false  # Set all_reachable to false for other unreachable hostnames
                fi
            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: Linux client + Docker/Portainer installation ...\n"
sleep 2

echo -e "             _                 _     _  _        __ _                         _ _            _  "
echo -e "   /\  /\___| |_ __ ___  _   _| |_  | || | _    / /(_)_ __  _   ___  __   ___| (_) ___ _ __ | |_"
echo -e "  / /_/ / _ \ | '_   _ \| | | | __| | || |(_)  / / | | '_ \| | | \ \/ /  / __| | |/ _ \ '_ \| __|"
echo -e " / __  /  __/ | | | | | | |_| | |_  |__   _|  / /__| | | | | |_| |>  <  | (__| | |  __/ | | | |_ "
echo -e " \/ /_/ \___|_|_| |_| |_|\__,_|\__|    |_|(_) \____/_|_| |_|\__,_/_/\_\  \___|_|_|\___|_| |_|\__|"

echo -e "\n"


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 ###
echo -e "\nStarting the Helmut4: Linux-client 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
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get install docker-ce docker-ce-cli containerd.io -y
sudo apt-get install docker-compose -y
sudo apt-get install httpie jq unzip -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-Linux client installation on OS $NAME version $VERSION ...\n"
sleep 2

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
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) 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 -y
sudo apt-get install docker-compose -y
sudo apt-get install httpie jq unzip -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-Linux client 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 --nobest --allowerasing

sudo yum -y install httpie jq unzip
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-Linux client 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
sudo yum install -y httpie docker-compose
fi
sudo yum -y install jq unzip
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 Linux-client \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:lts --admin-password='$2y$05$WbcqfTqVa2T58lGrLO7Tp.30DMjKFo.6O4.XAmfBFg4a0jrVSbdW.' -H unix:///var/run/docker.sock
sleep 10
docker swarm init
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 Helmut4: Linux-client stack ...\n"

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 Helmut4: Linux-client stack, this might take some time.. (Timeout is set to 10 minutes)\n"
STACK=$(curl -s https://repo.moovit24.de/install/config/linux-render-compose.yml)
http --ignore-stdin --timeout=1200 POST ":9000/api/stacks?method=string&type=1&endpointId=1" "Authorization:Bearer ${JWT}" Name="helmut4-linux-client" SwarmID="${SWARM_ID}" StackFileContent="${STACK}"


echo -e "Helmut4: Linux-client setup done - you might want to change the portainer password from admin:admin to something more secure...\n\n\n"

echo -e "\nContinuing with additional binary download ...\n"

echo -e "     ___       __    __                 _      "
echo -e "    /   | ____/ /___/ /     ____  ____ ( )_____"
echo -e "   / /| |/ __  / __  /_____/ __ \/ __ \|// ___/"
echo -e "  / ___ / /_/ / /_/ /_____/ /_/ / / / / (__  ) "
echo -e " /_/  |_\__,_/\__,_/      \____/_/ /_/ /____/  "
echo -e "\n"

# Check if URLs are reachable, skip installation if false
if [[ $addons = false ]]; then
   echo -e "\nAdd-on URLS are not fully reachable. Please check your internet connection or try again."
   
   echo -e "\n\n\nYour Helmut4: Linux-client stack has been configured.\n\nPlease go to Portainer and start to configure it towards your environment"
   
   exit 1  # Exit with a non-zero status code to indicate failure
fi

#Confirming Eula / license
while true; do

read -p "Do you accept the EULA/license conditions for ffmpeg, rclone & 7-zip? (y/n) " yn

case $yn in 
	#If input is yes we leave the loop
	[yY] ) echo Ok, we will continue with the binaries installation  ...;
		break;;
	
	#No - abport binary installaton
	[nN] ) 
        		echo -e "\nSkipping binary installation!";
		exit 1;;
	
	#If input is neither y nor n
	* ) echo Invalid response for question;
	echo -e "\nSkipping binary installation!";
	echo -e "\n\n\nYour Helmut4: Linux-client stack has been configured.\n\nPlease go to Portainer and start to configure it towards your environment";
	exit 1;;
esac
done

#Define binaries destination folder
echo -e "\nType in the name of the directory which should be used for all binaries (eg /usr/share)\n"

#Fetch user input
read -p 'Binary destination path: ' binarypath

echo -e "\n\n$binarypath has been recognized.\n"

#Check if folder name is correct - possibility to change it again
while true; do

read -p "Is the binary directory path correct? (y/n) " yn

case $yn in 
	#If input is yes we leace the loop
	[yY] ) echo Ok, we will continue with the binaries configuration  ...;
		break;;
	
	#If input is no we ask for the mnt input again
	[nN] ) 
        echo -e "Type in the name of the directory which should be used for all binaries (eg /usr/share)\n";
		read -p 'Binary destination directory: ' binarypath
		echo -e "\n/mnt/$binarypath has been recognized.";;
	
	#If input is neither y nor n
	* ) echo Invalid response for question;
	echo -e "\n$binarypath has been recognized.";;
esac
done

#Create folder if it doesn't exist
[ ! -d "$binarypath" ] && mkdir -p "$binarypath"


#Download latest ffmpeg static binary for Helmut4-hc

#Download official ffmpeg static binary from johnvansickle.com
echo -e "\n\nDownloading latest static ffmpeg version ... \n\n"
wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz

#create temp folder if it doesn't exist
[ ! -d "/tmp/staticffmpeg" ] && mkdir -p "/tmp/staticffmpeg"

#uncompress archive
#--strip-components=1 - skipping version root folder
tar -xf ffmpeg-release-amd64-static.tar.xz --strip-components=1 -C /tmp/staticffmpeg

#Delete archive
rm -r ffmpeg-release-amd64-static.tar.xz

#Copy ffmpeg binary
echo -e "\n\nMoving latest ffmpeg binary into destintion directory $binarypath \n"
cp /tmp/staticffmpeg/ffmpeg $binarypath

#Delete temp folder
rm -r /tmp/staticffmpeg

#Set right level
chmod 755 $binarypath/ffmpeg

echo -e "\nffmpeg instance downloaded\n\n"


#Download latest rclone static binary for Helmut4-hc

#Download official rclone static binary from rclone.org
echo -e "\n\nDownloading latest rclone version ... \n\n"
wget https://downloads.rclone.org/rclone-current-linux-amd64.zip

#create temp folder if it doesn't exist
[ ! -d "/tmp/staticrclone" ] && mkdir -p "/tmp/staticrclone"

#unzip rlone into temp folder
unzip -j rclone-current-linux-amd64.zip -d /tmp/staticrclone

#Delete archive
rm -r rclone-current-linux-amd64.zip

#Copy rclone binary
echo -e "\n\nMoving latest rclone binary into destintion directory $binarypath \n"
cp /tmp/staticrclone/rclone $binarypath

#Set right level
chmod 755 $binarypath/rclone

#Delete temp folder
rm -r /tmp/staticrclone

echo -e "\nrclone instance downloaded\n\n"


#Download latest 7zip static binary for Helmut4-hc

#Download official 7zip static binary from 7-zip.org
echo -e "\n\nDownloading latest 7zip version ... \n\n"
wget https://7-zip.org/a/7z2408-linux-x64.tar.xz

#create temp folder if it doesn't exist
[ ! -d "/tmp/static7zip" ] && mkdir -p "/tmp/static7zip"

#unzip 7zip into temp folder
tar -xf 7z2408-linux-x64.tar.xz --strip-components=0 -C /tmp/static7zip

#Delete archive
rm -r 7z2408-linux-x64.tar.xz

#Copy 7-zip binary
echo -e "\n\nMoving latest 7-zip binary into destintion directory $binarypath \n"
#Rename binary 7zzs to 7zz to match normal linux enviornment
cp /tmp/static7zip/7zzs "$binarypath"/7zz

#Set right level
chmod 755 $binarypath/7zz

#Delete temp folder
rm -r /tmp/static7zip

echo -e "\n7-zip instance downloaded\n\n"


echo -e "\n\n\nYour Helmut4: Linux-client stack has been configured.\n\nPlease go to Portainer and start to configure it towards your environment"
