# Federated Computer functions # Define all services SERVICES=("dns" "postgresql" "ldap" "mail" "collabora" "proxy" "nextcloud" "matrix" "element" "listmonk" "vaultwarden" "panel" "wireguard" "jitsi" "baserow" "gitea" "caddy") fail() { echo -ne "FAILED\n\n$1\n\n" kill -9 $SPINPID &> /dev/null # [ -d "apps/dns" ] && rm -rf apps/dns # docker network rm fstack &> /dev/null exit 2; } failcheck() { echo -ne "\n\nFAILED - $1\n\n" exit 2; } cleanup() { kill -9 $SPINPID &> /dev/null exit 2 } spin() { spinner="/|\\-/|\\-" while : do for i in `seq 0 7` do echo -n "${spinner:$i:1}" echo -en "\010" sleep 1 done done } add_cron() { (crontab -l 2>/dev/null; echo "30 23 * * * /federated/bin/backuptool -b all >> /federated/logs/backup.log 2>&1") | sort -u | crontab - (crontab -l 2>/dev/null; echo "0 2 * * * /federated/bin/upgrade >> /federated/logs/upgrade.log 2>&1") | sort -u | crontab - } install_federated() { [ -d "/federated" ] && fail "Directory /federated already exists. Already installed?" API_TOKEN="92d97f5aa371d420ebce7bc9a008ea8c6ec5d334" git clone https://derek:$API_TOKEN@code.federated.company/federatedcomputer/Core /federated } upgrade_federated() { echo -ne "\n* Updating federated install.." [ ! -d "/federated" ] && fail "Directory /federated doesn't exist." echo -ne "\n* Grabbing the latest version from Gitea.." API_TOKEN="92d97f5aa371d420ebce7bc9a008ea8c6ec5d334" cd /federated && git pull https://derek:$API_TOKEN@code.federated.company/federatedcomputer/Core &> /dev/null [ $? -ne 0 ] && fail "Git pull not working on update of federated." echo -ne "\n* Checking installed app versions with the latest.." [ ! -f "/federated/lib/latest-versions" ] && fail "File /federated/lib/latest-version doesn't exist." for i in `cat /federated/lib/latest-versions`; do SERVICE=(${i//=/ }); APP="${SERVICE[0]}" VERSION="${SERVICE[1]}" echo -ne "\n** Checking $APP.." [ ! -f "/federated/apps/$APP/.env" ] && fail "File /federated/apps/$APP/.env doesn't exist." APP_VERSION_RAW=`grep IMAGE_VERSION /federated/apps/$APP/.env | awk -F= '{ print $2 }'` APP_VERSION="${APP_VERSION_RAW//\"}" if [ "$APP_VERSION" = "$VERSION" ]; then echo -ne "\n $APP is already at the latest version." else NC_COMMAND=`grep start_service /federated/lib/$APP.sh | awk -F\" '{ print $4 }'` echo -ne "\n Upgrading $APP.." echo -ne "\n Shutting Down $APP.." cd /federated/apps/$APP && docker-compose -f docker-compose.yml -p $APP down sed -i "s#VERSION=.*#VERSION=$VERSION#g" /federated/apps/$APP/.env echo -ne "\n Starting Up $APP.." start_service_upgrade "$APP" "$NC_COMMAND" echo -ne "\n Done Updating $APP to $VERSION." fi done echo -ne "\n\n" } create_password() { # eval $1_var=$1 # echo "$postgres_var" SECRET=`tr -cd '[:alnum:]' < /dev/urandom | fold -w32 | head -n1` echo "$SECRET"; } start_service_upgrade() { SERVICE="$1" COMMAND="$2" # Start /federated/apps/SERVICE with output to /dev/null echo -ne "\n* Starting /federated/apps/$SERVICE service.." if [ $DEBUG ]; then # Start /federated/apps/SERVICE with output to console for debug docker-compose -f /federated/apps/$SERVICE/docker-compose.yml -p $SERVICE up [ $? -eq 0 ] && echo -ne "done.\n" || fail "There was a problem starting service /federated/apps/$SERVICE" else docker-compose -f /federated/apps/$SERVICE/docker-compose.yml -p $SERVICE up -d &> /dev/null # Keep trying service port to make sure it's up before # we proceed RETRY="30" while [ $RETRY -gt 0 ]; do bash -c "$COMMAND" &> /dev/null if [ $? -eq 0 ]; then break else if [ "$RETRY" == 1 ]; then docker-compose -f /federated/apps/$SERVICE/docker-compose.yml -p $SERVICE down &> /dev/null fail "There was a problem starting service /federated/apps/$SERVICE\nCheck the output of 'docker logs $SERVICE' or turn on\ndebug with -d" fi ((RETRY--)) sleep 7 fi done fi } start_service() { SERVICE="$1" COMMAND="$2" # Start /federated/apps/SERVICE with output to /dev/null echo -ne "\n* Starting /federated/apps/$SERVICE service.." spin & SPINPID=$! if [ $DEBUG ]; then # Start /federated/apps/SERVICE with output to console for debug docker-compose -f /federated/apps/$SERVICE/docker-compose.yml -p $SERVICE up [ $? -eq 0 ] && echo -ne "done.\n" || fail "There was a problem starting service /federated/apps/$SERVICE" else docker-compose -f /federated/apps/$SERVICE/docker-compose.yml -p $SERVICE up -d &> /dev/null # Keep trying service port to make sure it's up before # we proceed RETRY="30" while [ $RETRY -gt 0 ]; do bash -c "$COMMAND" &> /dev/null if [ $? -eq 0 ]; then break else if [ "$RETRY" == 1 ]; then docker-compose -f /federated/apps/$SERVICE/docker-compose.yml -p $SERVICE down &> /dev/null kill -9 $SPINPID &> /dev/null fail "There was a problem starting service /federated/apps/$SERVICE\nCheck the output of 'docker logs $SERVICE' or turn on\ndebug with -d" fi ((RETRY--)) sleep 7 fi done fi } print_details() { cat > /federated/apps/mail/data/root/certs/mailfile <> /federated/apps/mail/data/root/certs/mailfile cat >> /federated/apps/mail/data/root/certs/mailfile </dev/null | grep ID | awk -F: '{ print $2 }' | xargs` if ! command -v docker &> /dev/null; then echo -ne "\n* Couldn't find docker, installing.." spin & SPINPID=$! # Install Docker on Ubuntu if [ $OSRELEASE == "Ubuntu" ]; then # Update list of packages sudo apt-get update -y &> /dev/null [ $? -ne 0 ] && failcheck "Couldn't run sudo apt-get update" # Install packages which let apt use packages over HTTPS sudo apt install apt-transport-https ca-certificates curl software-properties-common -y &> /dev/null [ $? -ne 0 ] && failcheck "Couldn't run sudo apt install for https packages" # Add GPG key for the official Docker repository to this system curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - &> /dev/null [ $? -ne 0 ] && failcheck "Couldn't run curl to add Docker GPG key" # Add the docker repository to our APT sources list sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu jammy stable" -y &> /dev/null [ $? -ne 0 ] && failcheck "Couldn't run sudo add-apt-repository" # Install docker packages sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin docker-compose -y &> /dev/null [ $? -ne 0 ] && failcheck "Couldn't run sudo apt install docker packages" # Install extra packages sudo apt-get install duplicity python3-b2sdk uuid -y &> /dev/null [ $? -ne 0 ] && failcheck "Couldn't run sudo apt install extra packages" fi kill -9 $SPINPID &> /dev/null echo -ne "done." fi if ! command -v docker-compose &> /dev/null; then echo -ne "\n* Couldn't find docker-compose, installing.." spin & SPINPID=$! # Install Docker compose on Ubuntu if [ $OSRELEASE == "Ubuntu" ]; then sudo apt-get install docker-compose -y &> /dev/null fi kill -9 $SPINPID &> /dev/null echo -ne "done." fi } check_ports() { EXTERNALIP=`dig @resolver4.opendns.com myip.opendns.com +short 2> /dev/null` [ $? -ne 0 ] && failcheck "Couldn't run dig, dns is not working" # Check if ss command exists if command -v ss &> /dev/null; then # Check every port we need if it's in use (only if we have never run before) if [ $(ls /federated/apps | wc -l) -eq "0" ]; then for i in 25 53 80 143 389 587 993 8000; do SS=`ss -tulwn | grep LISTEN | awk '{ print $5 }' | awk -F: '{ print $NF }' | grep "^$i$" | head -1` # If port 53 (dns) in use by system-resolvd (Ubuntu) then auto fix if [ "$SS" == 53 ]; then if [ $OSRELEASE == "Ubuntu" ]; then if [ `pgrep -x systemd-resolve` ]; then echo -ne "\n* Port 53 in use by systemd-resolved, fixing.." spin & SPINPID=$! # Install resolvconf to fix sudo apt install resolvconf -y &> /dev/null [ $? -eq 0 ] && echo -ne "." || failcheck "Failed running sudo apt install resolvconf" # Shut down systemd-resolved systemctl stop systemd-resolved &> /dev/null [ $? -ne 0 ] && failcheck "Failed running systemctl stop systemd-resolved" systemctl disable systemd-resolved &> /dev/null [ $? -ne 0 ] && failcheck "Failed running systemctl stop systemd-resolved" # Put nameserver entries so will exist on reboot echo "nameserver 8.8.8.8" > /etc/resolvconf/resolv.conf.d/tail echo "nameserver 8.8.8.8" > /run/resolvconf/resolv.conf kill -9 $SPINPID &> /dev/null echo -ne "done." else echo -ne "\nFAILED - Port 53 (dns) is already in use\n\n" && exit 2 fi fi elif [ "$SS" == "$i" ]; then failcheck "FAILED - Port $i is already in use" fi done fi fi } check_os() { VERSIONID=`grep "VERSION_ID=" /etc/os-release | awk -F\" '{ print $2 }'` if [ "$VERSIONID" != "22.04" ]; then echo -ne "\nFederated requires a minimum of 4G of RAM and 25G of storage\n \ running Ubuntu 22.04 LTS. Your system is not supported. Please contact\n \ Federated @ support@federated.computer for assistance or choose our\n \ cloud offerings at https://cloud.federated.computer.\n\n" exit 2; fi } check_memory() { MEMTOTAL=`awk '/MemTotal/ { printf "%.3d \n", $2/1024 }' /proc/meminfo` if [ "$MEMTOTAL" -lt "3700" ]; then echo -ne "\nFederated requires a minimum of 4G of RAM and 25G of storage\n \ running Ubuntu 22.04 LTS. Your system is not supported. Please contact\n \ Federated @ support@federated.computer for assistance or choose our\n \ cloud offerings at https://cloud.federated.computer.\n\n" exit 2; fi }