2020-06-30 16:11:12 +02:00
#!/usr/bin/env bash
parseparams( )
{
COMMANDS = ( )
SCRIPTS = ( )
ENVIRONMENTS = ( )
2021-06-01 08:54:19 +02:00
PREPROCESSING = ( )
2021-06-11 13:47:25 +02:00
while getopts "hyt:s:p:c:e:" opt; do
2020-06-30 16:11:12 +02:00
case " ${ opt } " in
y)
Y = true
; ;
2021-06-11 13:47:25 +02:00
t)
TARGET = $OPTARG
FORCE_TARGET = true
; ;
2020-06-30 16:11:12 +02:00
s)
SCRIPTS += ( " $OPTARG " )
; ;
2021-06-01 08:54:19 +02:00
p)
PREPROCESSING += ( " $OPTARG " )
; ;
2020-06-30 16:11:12 +02:00
c)
COMMANDS += ( " $OPTARG " )
; ;
e)
ENVIRONMENTS += ( " $OPTARG " )
; ;
*)
usage
; ;
esac
done
shift $(( OPTIND-1))
}
yq( ) {
2021-11-16 17:17:08 +01:00
docker run --rm -i -v " ${ PWD } :/workdir " --user " $UID " mikefarah/yq:4 " $@ "
2020-06-30 16:11:12 +02:00
}
2020-10-21 13:13:13 +02:00
jq( ) {
2022-06-06 17:23:02 +02:00
docker run --rm -i -v " ${ PWD } :/data " --user " $UID " imega/jq " $@ "
2020-10-21 13:13:13 +02:00
}
2022-05-23 16:29:10 +02:00
docker-compose( )
{
if ! docker compose version 1>/dev/null 2>/dev/null
then
2022-05-25 09:53:25 +02:00
if ! command docker-compose version 1>/dev/null 2>/dev/null
2022-05-23 16:29:10 +02:00
then
echo -e "\e[91m[ ❌ ] docker-compose was not found, exiting...\e[39m" && exit 1
else
2022-05-25 09:53:25 +02:00
command docker-compose " $@ "
2022-05-23 16:29:10 +02:00
fi
else
docker compose " $@ "
fi
}
2022-06-06 17:23:02 +02:00
has_sudo( )
{
local prompt
prompt = $( sudo -nv 2>& 1)
if [ $? -eq 0 ] ; then
echo "has_sudo__pass_set"
elif echo $prompt | grep -q '^sudo:' ; then
echo "has_sudo__needs_pass"
else
echo "no_sudo"
fi
}
elevate_cmd( )
{
local cmd = $@
HAS_SUDO = $( has_sudo)
case " $HAS_SUDO " in
has_sudo__pass_set)
sudo $cmd
; ;
has_sudo__needs_pass)
echo " Please supply sudo password for the following command: sudo $cmd "
sudo $cmd
; ;
*)
echo " Please supply root password for the following command: su -c \" $cmd \" "
su -c " $cmd "
; ;
esac
}
2021-06-11 13:47:25 +02:00
# set $SERVICE and $YES_ALL
2020-06-30 16:11:12 +02:00
config( )
{
2021-06-11 13:47:25 +02:00
echo -e "Checking user... "
2020-06-30 16:11:12 +02:00
if [ [ " $( whoami) " != "root" ] ] && ! groups | grep docker
then
echo "Please add your current user to the docker group OR run this script as root."
echo "current user is not allowed to use docker, exiting..."
exit 1
fi
2021-04-19 17:07:03 +02:00
echo -e "Checking installation..."
if [ ! -f "docker-compose.yml" ] ; then
echo -e " \e[91m[ ❌ ] docker-compose.yml was not found in ${ PWD } . Please run this script from the Fab-manager's installation folder. Exiting... \e[39m "
exit 1
fi
2022-06-27 15:19:53 +02:00
echo "Checking docker version..."
DOCKER_VERSION = $( docker -v | grep -oP "([0-9]{1,}\.)+[0-9]{1,}" )
if verlt " $DOCKER_VERSION " 20.10; then
echo -e " \e[91m[ ❌ ] The installed docker version ( $DOCKER_VERSION ) is lower than the minimum required version (20.10). Exiting...\e[39m " && exit 1
fi
2020-06-30 16:11:12 +02:00
2021-03-01 10:13:48 +01:00
SERVICE = " $( yq eval '.services.*.image | select(. == "sleede/fab-manager*") | path | .[-2]' docker-compose.yml) "
2020-06-30 16:11:12 +02:00
YES_ALL = ${ Y :- false }
# COMMANDS, SCRIPTS and ENVIRONMENTS are set by parseparams
2021-04-19 17:07:03 +02:00
if [ -z " ${ SERVICE } " ] ; then
echo -e "\e[91m[ ❌ ] The service name was not determined. Please check your docker-compose.yml file. Exiting... \e[39m"
exit 1
fi
2021-05-18 09:40:35 +02:00
echo -e "\n"
2020-06-30 16:11:12 +02:00
}
2020-10-06 14:18:35 +02:00
# compare versions utilities
# https://stackoverflow.com/a/4024263/1039377
verlte( ) {
[ " $1 " = " $( echo -e " $1 \n $2 " | sort -V | head -n1) " ]
}
verlt( ) {
[ " $1 " = " $2 " ] && return 1 || verlte " $1 " " $2 "
}
2021-06-11 13:47:25 +02:00
# set $TAG and $TARGET
target_version( )
{
TAG = $( yq eval " .services. $SERVICE .image " docker-compose.yml | grep -o ':.*' )
if [ -n " $TARGET " ] ; then return ; fi
if [ [ " $TAG " = ~ ^:release-v[ \. 0-9] +$ ] ] ; then
TARGET = $( echo " $TAG " | grep -Eo '[\.0-9]{5}' )
2021-06-15 13:05:38 +02:00
elif [ " $TAG " = ":latest" ] || [ " $TAG " = "" ] ; then
2021-10-04 16:45:54 +02:00
HTTP_CODE = $( curl -I -s -w "%{http_code}\n" -o /dev/null https://hub.fab-manager.com/api/versions/latest)
if [ " $HTTP_CODE " != 200 ] ; then
printf "\n\n\e[91m[ ❌ ] Unable to retrieve the last version of Fab-manager. Please check your internet connection or restart this script providing the \e[1m-t\e[0m\e[91m option\n\e[39m"
exit 3
fi
2021-06-11 13:47:25 +02:00
TARGET = $( \c url -sSL "https://hub.fab-manager.com/api/versions/latest" | jq -r '.semver' )
else
TARGET = 'custom'
fi
}
2020-10-06 14:18:35 +02:00
version_error( )
{
2021-04-19 17:07:03 +02:00
printf "\n\n\e[91m[ ❌ ] You are running Fab-manager version %s\n\e[39m" " ${ VERSION :- undetermined } "
2021-06-11 13:47:25 +02:00
printf "You must upgrade Fab-manager to %s.\nPlease refer to http://update.doc.fab.mn for instructions\n" " $1 " 1>& 2
2020-10-06 14:18:35 +02:00
exit 3
}
2021-06-11 13:47:25 +02:00
# set $VERSION
2020-10-06 14:18:35 +02:00
version_check( )
{
2022-06-14 16:25:36 +02:00
VERSION = $( docker-compose exec -T " $SERVICE " cat .fabmanager-version 2>/dev/null)
2020-10-06 14:18:35 +02:00
if [ [ $? = 1 ] ] ; then
2022-06-14 16:25:36 +02:00
VERSION = $( docker-compose exec -T " $SERVICE " cat package.json | jq -r '.version' )
2020-10-06 14:18:35 +02:00
fi
2021-06-11 13:47:25 +02:00
target_version
if [ " $TARGET " = 'custom' ] ; then return ; fi
2020-10-06 14:18:35 +02:00
2021-06-11 13:47:25 +02:00
if verlt " $VERSION " 2.8.3 && verlt 2.8.3 " $TARGET " ; then
version_error "v2.8.3 first"
elif verlt " $VERSION " 3.1.2 && verlt 3.1.2 " $TARGET " ; then
version_error "v3.1.2 first"
elif verlt " $VERSION " 4.0.4 && verlt 4.0.4 " $TARGET " ; then
version_error "v4.0.4 first"
elif verlt " $VERSION " 4.4.6 && verlt 4.4.6 " $TARGET " ; then
version_error "v4.4.6 first"
2021-10-04 12:09:31 +02:00
elif verlt " $VERSION " 4.7.14 && verlt 4.7.14 " $TARGET " ; then
version_error "v4.7.14 first"
2021-06-11 13:47:25 +02:00
elif verlt " $TARGET " " $VERSION " ; then
version_error " a version > $VERSION "
2020-10-06 14:18:35 +02:00
fi
}
2020-06-30 16:11:12 +02:00
add_environments( )
{
for ENV in " ${ ENVIRONMENTS [@] } " ; do
if [ [ " $ENV " = ~ ^[ A-Z0-9_] += .*$ ] ] ; then
2021-10-20 17:19:07 +02:00
local var = $( echo " $ENV " | cut -d '=' -f1)
grep " $var " ./config/env
if [ [ " $? " = 1 ] ] ; then
printf "\e[91m::\e[0m \e[1mInserting variable %s..\e[0m.\n" " $ENV "
printf "# added on %s\n%s\n" " $( date +%Y-%m-%d\ %R) " " $ENV " >> "config/env"
else
printf "\e[93m[ ⚠ ] %s is already defined in config/env, ignoring...\e[39m\n" " $var "
fi
2020-06-30 16:11:12 +02:00
else
2021-05-17 15:42:23 +02:00
printf "\e[93m[ ⚠ ] Ignoring invalid option: -e %s.\e[39m\n Given value is not valid environment variable, please see http://env.doc.fab.mn\n" " $ENV "
2020-06-30 16:11:12 +02:00
fi
done
}
2021-03-08 17:08:07 +01:00
clean_env_file( )
{
# docker run --env-file does not support whitespaces in the environment variables so we must clean the file
sed -ri 's/^([A-Z0-9_]+)\s*=\s*(.*)$/\1=\2/g' ./config/env
}
2020-10-23 12:15:25 +02:00
compile_assets( )
2020-10-21 10:44:43 +02:00
{
2021-03-01 10:13:48 +01:00
IMAGE = $( yq eval '.services.*.image | select(. == "sleede/fab-manager*")' docker-compose.yml)
mapfile -t COMPOSE_ENVS < <( yq eval " .services. $SERVICE .environment " docker-compose.yml)
2020-10-21 13:13:13 +02:00
ENV_ARGS = $( for i in " ${ COMPOSE_ENVS [@] } " ; do sed 's/: /=/g;s/^/-e /g' <<< " $i " ; done )
PG_ID = $( docker-compose ps -q postgres)
2020-10-23 12:15:25 +02:00
if [ [ " $PG_ID " = "" ] ] ; then
2021-06-11 13:47:25 +02:00
restore_tag
2021-04-19 17:07:03 +02:00
printf "\e[91m[ ❌ ] PostgreSQL container is not running, unable to compile the assets\e[39m\nExiting..."
2021-06-01 09:03:24 +02:00
exit 4
2020-10-23 12:15:25 +02:00
fi
2020-10-21 13:13:13 +02:00
PG_NET_ID = $( docker inspect " $PG_ID " -f "{{json .NetworkSettings.Networks }}" | jq -r '.[] .NetworkID' )
2021-03-08 17:08:07 +01:00
clean_env_file
2022-06-13 10:05:03 +02:00
if ! mkdir -p public/new_packs; then
# if, for any reason, the directory cannot be created, we create it with sudo privileges and changes the ownership to the current user
elevate_cmd mkdir -p public/new_packs
elevate_cmd chown " $( id -u) : $( id -g) " public/new_packs
fi
2020-10-21 13:13:13 +02:00
# shellcheck disable=SC2068
2022-06-14 16:25:36 +02:00
if ! docker run --user "0:0" --rm --env-file ./config/env ${ ENV_ARGS [@] } --link " $PG_ID " --net " $PG_NET_ID " -v " ${ PWD } /public/new_packs:/usr/src/app/public/packs " " $IMAGE " bundle exec rake assets:precompile; then
2022-06-07 16:38:46 +02:00
printf "\e[93m[ ⚠ ] Something may have went wrong while compiling the assets, please check the logs above.\e[39m\n"
[ [ " $YES_ALL " = "true" ] ] && confirm = "y" || read -rp " [91m:: [0m [1mIgnore and continue? [0m (Y/n) " confirm </dev/tty
if [ [ " $confirm " = "n" ] ] ; then restore_tag; echo "Exiting..." ; exit 4; fi
2021-05-18 16:18:44 +02:00
fi
2020-10-21 10:44:43 +02:00
docker-compose down
2022-06-06 17:23:02 +02:00
if ! rm -rf public/packs; then
# sometimes we can't delete the packs folder, because of a permission issue. In that case try with sudo
elevate_cmd rm -rf public/packs
fi
2020-10-21 10:44:43 +02:00
mv public/new_packs public/packs
}
2021-06-11 13:47:25 +02:00
force_version( )
{
if [ " $FORCE_TARGET " != "true" ] ; then return ; fi
yq -i eval " .services. $SERVICE .image = \"sleede/fab-manager:release-v $TARGET \" " docker-compose.yml
}
restore_tag( )
{
if [ " $FORCE_TARGET " != "true" ] ; then return ; fi
yq -i eval " .services. $SERVICE .image = \"sleede/fab-manager $TAG \" " docker-compose.yml
}
2020-06-30 16:11:12 +02:00
upgrade( )
{
2021-06-11 13:47:25 +02:00
[ [ " $YES_ALL " = "true" ] ] && confirm = "y" || read -rp " [91m:: [0m [1mProceed with upgrading to version $TARGET ? [0m (Y/n) " confirm </dev/tty
2021-04-14 16:18:35 +02:00
if [ [ " $confirm " = "n" ] ] ; then exit 2; fi
2020-06-30 16:11:12 +02:00
2021-04-14 16:18:35 +02:00
add_environments
2021-06-11 13:47:25 +02:00
force_version
2021-04-19 17:07:03 +02:00
if ! docker-compose pull " $SERVICE " ; then
2021-06-11 13:47:25 +02:00
restore_tag
2021-04-19 17:07:03 +02:00
printf "\e[91m[ ❌ ] An error occurred, detected service name: %s\e[39m\nExiting..." " $SERVICE "
2021-06-01 09:03:24 +02:00
exit 4
2020-06-30 16:11:12 +02:00
fi
2020-10-21 15:18:39 +02:00
BRANCH = 'master'
2021-03-01 10:13:48 +01:00
if yq eval '.services.*.image | select(. == "sleede/fab-manager*")' docker-compose.yml | grep -q ':dev' ; then BRANCH = 'dev' ; fi
2020-06-30 16:11:12 +02:00
for SCRIPT in " ${ SCRIPTS [@] } " ; do
2021-03-24 11:04:59 +01:00
printf "\e[91m::\e[0m \e[1mRunning script %s from branch %s...\e[0m\n" " $SCRIPT " " $BRANCH "
2020-07-01 10:52:43 +02:00
if [ [ " $YES_ALL " = "true" ] ] ; then
2020-10-21 15:18:39 +02:00
\c url -sSL " https://raw.githubusercontent.com/sleede/fab-manager/ $BRANCH /scripts/ $SCRIPT .sh " | bash -s -- -y
2020-07-01 10:52:43 +02:00
else
2020-10-21 15:18:39 +02:00
\c url -sSL " https://raw.githubusercontent.com/sleede/fab-manager/ $BRANCH /scripts/ $SCRIPT .sh " | bash
2020-07-01 10:52:43 +02:00
fi
2021-04-19 17:07:03 +02:00
# shellcheck disable=SC2181
if [ [ $? != 0 ] ] ; then
printf "\e[93m[ ⚠ ] Something may have went wrong while running \"%s\", please check the logs above...\e[39m\n" " $SCRIPT "
[ [ " $YES_ALL " = "true" ] ] && confirm = "y" || read -rp " [91m:: [0m [1mIgnore and continue? [0m (Y/n) " confirm </dev/tty
2021-06-11 13:47:25 +02:00
if [ [ " $confirm " = "n" ] ] ; then restore_tag; exit 4; fi
2021-04-19 17:07:03 +02:00
fi
2020-06-30 16:11:12 +02:00
done
2021-06-01 08:54:19 +02:00
for PRE in " ${ PREPROCESSING [@] } " ; do
printf "\e[91m::\e[0m \e[1mRunning preprocessing command %s...\e[0m\n" " $PRE "
2022-06-14 16:25:36 +02:00
if ! docker-compose run --rm " $SERVICE " bundle exec " $PRE " </dev/tty; then
2021-06-11 13:47:25 +02:00
restore_tag
2021-06-01 08:54:19 +02:00
printf "\e[91m[ ❌ ] Something went wrong while running \"%s\", please check the logs above.\e[39m\nExiting...\n" " $PRE "
exit 4
fi
done
2020-10-23 12:15:25 +02:00
compile_assets
2022-11-22 09:52:22 +01:00
if ! docker-compose run --rm " $SERVICE " bundle exec rake db:migrate </dev/tty; then
2021-06-11 13:47:25 +02:00
restore_tag
2021-04-19 17:07:03 +02:00
printf "\e[91m[ ❌ ] Something went wrong while migrating the database, please check the logs above.\e[39m\nExiting...\n"
exit 4
fi
2020-06-30 16:11:12 +02:00
for COMMAND in " ${ COMMANDS [@] } " ; do
2021-03-24 11:04:59 +01:00
printf "\e[91m::\e[0m \e[1mRunning command %s...\e[0m\n" " $COMMAND "
2022-06-14 16:25:36 +02:00
if ! docker-compose run --rm " $SERVICE " bundle exec " $COMMAND " </dev/tty; then
2021-06-11 13:47:25 +02:00
restore_tag
2021-04-19 17:07:03 +02:00
printf "\e[91m[ ❌ ] Something went wrong while running \"%s\", please check the logs above.\e[39m\nExiting...\n" " $COMMAND "
exit 4
fi
2020-06-30 16:11:12 +02:00
done
docker-compose up -d
2021-06-11 13:47:25 +02:00
restore_tag
2020-06-30 16:11:12 +02:00
docker ps
}
clean( )
{
2021-03-24 11:04:59 +01:00
echo -e "\e[91m::\e[0m \e[1mCurrent disk usage:\e[0m"
2020-06-30 16:11:12 +02:00
df -h /
2021-04-19 17:07:03 +02:00
[ [ " $YES_ALL " = "true" ] ] && confirm = "y" || read -rp " [91m:: [0m [1mClean previous docker images? [0m (y/N) " confirm </dev/tty
2020-06-30 16:11:12 +02:00
if [ [ " $confirm " = = "y" ] ] ; then
/usr/bin/docker image prune -f
fi
}
usage( )
{
printf " Usage: %s [OPTIONS]
Options:
-h Print this message and quit
-y Answer yes to all questions
2021-06-11 13:47:25 +02:00
-t <string> Force the upgrade to target the specified version
2021-06-01 08:54:19 +02:00
-p <string> Run the preprocessing command ( TODO DEPLOY)
2020-06-30 16:11:12 +02:00
-c <string> Provides additional upgrade command, run in the context of the app ( TODO DEPLOY)
-s <string> Executes a remote script ( TODO DEPOY)
2022-03-23 10:05:56 +01:00
-e <string> Adds the environment variable to config/env
2021-06-01 09:03:24 +02:00
Return codes:
0 Upgrade terminated successfully
1 Configuration required
2 Aborted by user
3 Version not supported
2022-03-23 10:05:56 +01:00
4 Unexpected error\n " " $( basename " $0 " ) " 1>&2
2020-06-30 16:11:12 +02:00
exit 1
}
function trap_ctrlc( )
{
echo "Ctrl^C, exiting..."
exit 2
}
proceed( )
{
trap "trap_ctrlc" 2 # SIGINT
parseparams " $@ "
config
2020-10-06 14:18:35 +02:00
version_check
2020-06-30 16:11:12 +02:00
upgrade
clean
}
proceed " $@ "