2025-07-03 01:13:07 -05:00
#!/usr/bin/env bash
2025-07-04 22:45:05 -05:00
# ╭────────────────────────────────────────────────────╮
# │ _ _ _ _ owo │
# │ | |__ ___| |_ __ ___ _ __| |__ ___ | |_ │
# │ | '_ \ / _ \ | '_ \ / _ \ '__| '_ \ / _ \| __| │
# │ | | | | __/ | |_) | __/ | | |_) | (_) | |_ │
# │ |_| |_|\___|_| .__/ \___|_| |_.__/ \___/ \__| │
# │ |_| │
# ╰────────────────────────────────────────────────────╯
# helperbot - synth.download's all in one script for managing everything. beep!
# =============================================================================
# ╭─────────────────────────╮
# │ functions and variables │
# ╰─────────────────────────╯
# unset everything - ensure we're working with a clean state
unset synth_help && unset synth_upgrade && unset synth_backup && unset synth_vacuum && unset synth_invalid && unset synth_current_system
# exit immediately if an error occurs somewhere to prevent Fucked Up Shit
set -e
# defining colors for text output
if [[ -t 1 ]]; then
red=$( tput setaf 1 );
green=$( tput setaf 2 );
yellow=$( tput setaf 3 );
blue=$( tput setaf 4 );
pink=$( tput setaf 5 );
cyan=$( tput setaf 6 );
gray=$( tput setaf 8 );
normal=$( tput sgr 0 );
fi
# attempt to detect the system based on hostname
function detect_system {
if [ "$(hostname)" = "phosphorus" ]; then
synth_current_system=phosphorus
echo "Detected ${blue}phosphorus${normal}."
elif [ "$(hostname)" = "neptunium" ]; then
synth_current_system=neptunium
echo "Detected ${blue}neptunium${normal}."
elif [ "$(hostname)" = "cerium" ]; then
synth_current_system=cerium
echo "Detected ${blue}cerium${normal}."
elif [ "$(hostname)" = "synthnix" ]; then
synth_current_system=synthnix
echo "Detected ${blue}synthnix${normal}."
else
echo "${red}Failed to detect system.${normal}"
echo "We're most likely being run in an environment we don't know of."
echo "Exiting..."
exit 1
fi
}
# base system upgrade - generic steps for debian/ubuntu based systems
function base_system_upgrade {
echo "${cyan}Upgrading base system.${normal}"
echo "${blue}Doing standard apt upgrade...${normal}"
2025-07-05 00:46:35 -05:00
apt update
apt upgrade -y
2025-07-04 22:45:05 -05:00
echo "${blue}Try upgrading distro base...${normal}"
2025-07-05 00:46:35 -05:00
apt dist-upgrade -y
2025-07-04 22:45:05 -05:00
echo "${blue}Apt cleanup...${normal}"
2025-07-05 00:46:35 -05:00
apt clean
2025-07-04 22:45:05 -05:00
echo "${green}Base system upgraded!.${normal}"
}
# docker container updates
2025-07-05 00:46:35 -05:00
# reusable steps to update containers - upgrade_docker_container [/srv/docker] [name_of_service_or_folder] [compose.yaml]
2025-07-04 22:45:05 -05:00
function upgrade_docker_container {
if [ -d "$1/$2" ]; then
2025-07-05 00:46:35 -05:00
# pull the container
cd "$1"/"$2" && docker compose -f "$1/$2/$3" pull
2025-07-04 22:45:05 -05:00
docker compose -f "$1/$2/$3" down && docker compose -f "$1/$2/$3" up -d
else
echo "${red}docker:${normal} Folder $1/$2 does not exist."
fi
}
# psql vacuuming
2025-07-05 00:46:35 -05:00
# reusable step to vacuum databases - postgres_vacuum [postgres-db-1] [user_and_db_name] [password]
2025-07-04 22:45:05 -05:00
function postgres_vacuum {
2025-07-05 00:46:35 -05:00
docker exec -it "$1" /bin/bash -c "POSTGRES_PASSWORD="$3" psql -U "$2" -d "$2" -c 'VACUUM ANALYZE;'"
}
# postgres_vacuum_self [postgres-db-1]
function postgres_vacuum_self {
docker exec -it "$1" /bin/bash -c "psql -U postgres -c 'VACUUM ANALYZE;'"
}
# psql backup
# reusable step to backup databases - postgres_backup [postgres-db-1] [user_and_db_name] [output_name] [$backup_working_directory]
function postgres_backup {
docker exec "$1" /bin/bash -c "pg_dump "$2" --username "$2" > "$3".sql"
docker cp "$1":/$3.sql $4/$3/$3.sql
docker exec "$1" /bin/bash -c "rm "$3".sql"
}
# redis snapshot
# tells redis to make a snapshot - redis_snapshot [whatever-redis-1]
function redis_snapshot {
docker exec $1 redis-cli SAVE
}
# backup - create folder and copy
# step that combines the process of making folders and copying files for backup
# backup_create_copy ["source files"] [subpath/to/folder] [$backup_working_directory]
function backup_create_copy {
mkdir -p $3/$2
cp -r $1 $3/$2
2025-07-04 22:45:05 -05:00
}
# ╭───────────────────╮
# │ defining messages │
# ╰───────────────────╯
# header
function header {
echo "╭────────────────╮"
echo "│ helperbot! owo │"
echo "╰────────────────╯"
echo
sleep 1 # grace period
}
# help info
function info_help {
echo "${blue}Usage:${normal} helperbot [-h|-u|-b|-v]"
echo
echo "${green}Options:${normal}"
echo "-h, --help Print this help page."
echo "-u, --upgrade Update the system."
echo "-b, --backup Backup the system."
echo "-v, --vacuum Vacuum the postgresql databases."
echo
echo "helperbot automatically knows what to do based on this system's hostname! Beep!"
echo
echo "${yellow}This script is still generally a work-in-progress.${normal}"
echo "Report breakage or suggestions or improvments or whatever to here:"
echo "https://forged.synth.download/synth.download/synth.download"
echo
}
# =============================================================================
# ╭──────────────╮
# │ main program │
# ╰──────────────╯
# check to see if we're running as root
#if [[ ${UID} != 0 ]]; then
# echo "${red}helperbot must be run as root or with sudo permissions!${normal} thanks!"
# exit 1
#fi
# display the header
header
# evaluate arguments and set environment variables to enable each command and see what should be executed
while [ -n "$1" ]; do
case "$1" in
-h | --help) # display help info
synth_help=1;;
-u | --upgrade) # upgrade system
synth_upgrade=1
if [ ! -v synth_current_system ]; then
detect_system
fi;;
-b | --backup) # backup system
synth_backup=1
if [ ! -v synth_current_system ]; then
detect_system
fi;;
-v | --vacuum) # vacuum database
synth_vacuum=1
if [ ! -v synth_current_system ]; then
detect_system
fi;;
*) # invalid option was given
synth_invalid=1;;
esac
shift 1
done
# say invalid option if we get an invalid option (duh)
if [ -v synth_invalid ]; then
echo "${red}Error:${normal} Invalid option."
echo "\"helperbot is very confused... >~<\""
echo
echo "Run with --help to see all options."
exit 1
fi
# runs if no option was specified; throw up the help menu
# otherwise: also run if specified
if [[ ! -v synth_args_exist || -v synth_help ]]; then
info_help
exit 0
fi
# ╭──────────────╮
# │ upgrade step │
# ╰──────────────╯
if [ -v synth_upgrade ]; then
2025-07-05 00:46:35 -05:00
#timestamp=$(date +'%Y%m%d%H%M%S')
#synth_upgrade_log=/tmp/upgrade-output-${timestamp}.txt
echo "${blue}upgrade:${normal} Running full system upgrade for ${green}${synth_current_system}${normal}."
#echo "Upgrade will be logged into ${yellow}${synth_upgrade_log}${normal} if needed." # logging doesn't work properly - check on later
if [ "$synth_current_system" = "phosphorus" ]; then # phosphorus
2025-07-04 22:45:05 -05:00
# apt/system related upgrade
base_system_upgrade
# docker
upgrade_docker_container "/srv/docker" "sharkey" "compose.yaml"
upgrade_docker_container "/srv/docker" "iceshrimp" "compose.yaml"
upgrade_docker_container "/srv/docker" "mastodon" "compose.yaml"
upgrade_docker_container "/srv/docker" "pds" "compose.yaml"
# done
echo "${green}System upgrade finished! beep!~${normal}"
2025-07-05 00:46:35 -05:00
elif [ "$synth_current_system" = "neptunium" ]; then # neptunium
# apt/system related upgrade
base_system_upgrade
# docker
upgrade_docker_container "/srv/docker" "mailserver" "compose.yaml"
upgrade_docker_container "/srv/docker" "ejabberd" "compose.yaml"
upgrade_docker_container "/srv/docker" "zitadel" "compose.yaml"
upgrade_docker_container "/srv/docker" "forgejo" "compose.yaml"
upgrade_docker_container "/srv/docker" "forgejo" "compose-runner.yaml"
upgrade_docker_container "/srv/docker" "freshrss" "compose.yaml"
upgrade_docker_container "/srv/docker" "vaultwarden" "compose-runner.yaml"
upgrade_docker_container "/srv/docker" "ask-js" "compose.yaml"
# done
echo "${green}System upgrade finished! beep!~${normal}"
elif [ "$synth_current_system" = "cerium" ]; then # cerium
# apt/system related upgrade
base_system_upgrade
# docker
upgrade_docker_container "/srv/docker" "redlib" "compose.yaml"
upgrade_docker_container "/srv/docker" "safetwitch" "compose.yaml"
# done
echo "${green}System upgrade finished! beep!~${normal}"
echo "${red}Rebooting system.${normal}"
sleep 1 && systemctl reboot
elif [ "$synth_current_system" = "synthnix" ]; then # synthnix
# apt/system related upgrade
base_system_upgrade
# done
echo "${green}System upgrade finished! beep!~${normal}"
fi
fi
# ╭─────────────╮
# │ backup step │
# ╰─────────────╯
if [ -v synth_backup ]; then
if [ -v synth_vacuum ]; then
echo "${yellow}NOTICE:${normal} You've also passed in the --vacuum command. Note that upgrading also automatically vacuums the databases beforehand."
sleep 1
fi
echo "${blue}backup:${normal} Running full system backup for ${green}${synth_current_system}${normal}."
if [ "$synth_current_system" = "phosphorus" ]; then # phosphorus
# variables
backup_local_folder=/srv/docker
backup_working_directory=/var/backups/phosphorus
backup_output_tar=phosphorus.tar
backup_media_output_tar=media_backups.tar # refers to the old local fedi media before s3 migration
# external files containing secrets
export $(grep -v '^#' /etc/secrets/b2.env | xargs)
export $(grep -v '^#' /etc/secrets/postgres.env | xargs)
# initial
mkdir -p $backup_working_directory
# database vacuuming
echo "${blue}Vacuuming postgres databases...${normal}"
postgres_vacuum_self postgres-db-1
postgres_vacuum postgres-db-1 misskey ${SHARKEY_POSTGRES_PASSWORD}
postgres_vacuum postgres-db-1 iceshrimp ${ICESHRIMP_POSTGRES_PASSWORD}
postgres_vacuum postgres-db-1 mastodon ${MASTODON_POSTGRES_PASSWORD}
# =============================================================================
# backup files - sharkey
echo "${blue}Pulling in Sharkey...${normal}"
mkdir -p $backup_working_directory/sharkey/.config
# database
postgres_backup postgres-db-1 misskey sharkey $backup_working_directory
# redis
redis_snapshot sharkey-redis-1
cp -r $backup_local_folder/sharkey/redis $backup_working_directory/sharkey
# configs, extra
cp -r $backup_local_folder/sharkey/compose.yaml $backup_working_directory/sharkey
cp -r $backup_local_folder/sharkey/.config $backup_working_directory/sharkey
# =============================================================================
# iceshrimp
echo "${blue}Pulling in Iceshrimp...${normal}"
mkdir -p $backup_working_directory/iceshrimp/config
# database
postgres_backup postgres-db-1 iceshrimp iceshrimp $backup_working_directory
# configs, extra
cp -r $backup_local_folder/iceshrimp/compose.yaml $backup_working_directory/iceshrimp
cp -r $backup_local_folder/iceshrimp/config $backup_working_directory/iceshrimp
# =============================================================================
# mastodon
echo "${blue}Pulling in Mastodon...${normal}"
mkdir -p $backup_working_directory/mastodon/.config
# database
postgres_backup postgres-db-1 mastodon mastodon $backup_working_directory
# redis
redis_snapshot mastodon-redis-1
cp -r $backup_local_folder/mastodon/redis $backup_working_directory/mastodon
# configs, extra
cp -r $backup_local_folder/mastodon/compose.yaml $backup_working_directory/mastodon
cp -r $backup_local_folder/mastodon/.config $backup_working_directory/mastodon
# =============================================================================
# pds
echo "${blue}Pulling in PDS...${normal}"
mkdir -p $backup_working_directory/pds
# there isn't a native way to "backup" the pds, so we shut it off and copy it
docker compose -f $backup_local_folder/pds/compose.yaml down
cp -r $backup_local_folder/pds/pds $backup_working_directory/pds
docker compose -f $backup_local_folder/pds/compose.yaml up -d
# configs, extra
cp -r $backup_local_folder/pds/compose.yaml $backup_working_directory/pds
# =============================================================================
# unset secrets
unset $(grep -v '^#' /etc/secrets/b2.env | sed -E 's/(.*)=.*/\1/' | xargs)
unset $(grep -v '^#' /etc/secrets/postgres.env | sed -E 's/(.*)=.*/\1/' | xargs)
elif [ "$synth_current_system" = "neptunium" ]; then # neptunium
postgres_vacuum_self postgres-db-1
elif [ "$synth_current_system" = "cerium" ]; then # cerium
postgres_vacuum_self postgres-db-1
elif [ "$synth_current_system" = "synthnix" ]; then # synthnix
# as synthnix doesn't really include much and serves as a place for members
# we just need to back up the home directory here
#
# WIP
2025-07-04 22:45:05 -05:00
fi
2025-07-05 00:46:35 -05:00
echo "${green}System backup finished! beep!~${normal}"
2025-07-04 22:45:05 -05:00
fi
#if [[ -v system_vacuum ]]; then
# echo "${yellow}NOTICE:${normal} You've also passed in the --vacuum command. Note that upgrading also automatically vacuums the databases beforehand."
# sleep 1
#fi
# unset everything
unset synth_help && unset synth_upgrade && unset synth_backup && unset synth_vacuum && unset synth_invalid && unset synth_current_system