Compare commits

...

4 Commits

Author SHA1 Message Date
f7a6d924d9 feature(helpers): add exit codes to update script 2021-07-27 18:28:09 -06:00
16f302c3fd struct(tools): checksum generator script 2021-07-27 17:08:55 -06:00
a6107f7e25 struct(helpers): set params file as template again
- prevents accidental overwrite of user params on updates
2021-07-27 16:17:04 -06:00
03e0631964 style(helpers): reformat update script and bump version 2021-07-27 16:09:27 -06:00
4 changed files with 417 additions and 180 deletions

View File

@ -0,0 +1,28 @@
#!/bin/sh
#
# generate checksums from provided path suitable for use by 'update.sh'
#
# check for missing path to helper files, otherwise strip trailing slash
if [ -z "$1" ]; then
printf "\nPlease supply path to helper files. Exiting.\n\n"
exit 1
fi
srcDir="${1%/}"
# verify path exists and is accessible
if ! [ -d "$srcDir" ]; then
printf "\nUnable to find or read supplied path to helper files. Exiting.\n\n"
exit 1
fi
# generate checksum file
\rm -f "${srcDir}/checksums.sha256"
find "${srcDir}/" -type f -exec sha256sum {} + >>"${srcDir}/checksums.sha256"
sed -i "s+$srcDir/++g" "${srcDir}/checksums.sha256"
# exit gracefully
exit 0
#EOF

View File

@ -0,0 +1,175 @@
###
### Parameters for use by ab-nginx helper script
###
### If you are NOT using the 'ab-nginx.sh' script file to start the container,
### then you don't have to do anything with this file.
###
#
# Container options
#
# Specify a particular tag to 'version pin' the ab-nginx container.
TAG=latest
# Specify a runtime UID and GID for the container user. This is useful to
# ensure the container can read and/or write to locations on the host or
# has access to files shared between members of a container stack.
# REQUIRED: NO
# DEFAULT: NGINX_UID=8080, NGINX_GID=8080
# VALID OPTIONS: any permissible and available UID/GID value
NGINX_UID=8080
NGINX_GID=8080
#
# Network options
#
# If you want to specify a network to which this container should bind or one
# that should be created, then use this variable. If you don't know what this
# means or if you just want to use the default, leave this variable commented.
# REQUIRED: NO
# DEFAULT: nginx_network
# VALID OPTIONS: network names acceptable to the docker engine
NETWORK=nginx_network
# If you want to specify a particular IP subnet for the network to be created
# as per the above variable, specify it here. Again, if you don't know what
# this means, just leave this variable commented.
# REQUIRED: NO
# DEFAULT: '172.31.254.0/24'
# VALID OPTIONS: subnet in CIDR format
SUBNET='172.31.254.0/24'
#
# Timezone
#
# This doesn't impact any functionality of the container, but it does make your
# logs easier to understand if they report the correct local time, right? Valid
# options can be found at
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
# REQUIRED: NO
# DEFAULT: Etc/UTC
# VALID OPTIONS: IANA time zones in TZ format
TZ=Etc/UTC
#
# NGINX options
#
# Hostnames to which this instance of NGINX should answer:
# By default, this is set to '_' meaning 'match anything'. However, that won't
# work if you're using SSL certificates! Multiple hostnames must be space
# delimited and "enclosed in quotes".
#
# This is NOT required if you are supplying your own server blocks via
# 'SERVERS_DIR'
#
# REQUIRED: YES, if using SSL and default server-blocks
# DEFAULT: "_"
# EXAMPLE: HOSTNAMES="domain.tld www.domain.tld server.domain.tld alt.domain.tld"
HOSTNAMES="_"
# Ports to listen on:
# If you need to use ports other than HTTP=80 and HTTPS=443, remember to set up
# your server blocks accordingly!
#
# If you're using the default server-blocks, they will auto-adjust to whatever
# you use here.
# REQUIRED: NO
# DEFAULTS: 80 and 443, respectively
HTTP_PORT=80
HTTPS_PORT=443
# Access logging (global preference):
# Unless overridden in a server/location block, access logging will be handled
# according to this setting. Logs are printed to the container console.
# REQUIRED: NO
# DEFAULT: OFF
# VALID OPTIONS: 'ON' or 'OFF'
ACCESS_LOG=OFF
#
# Content locations
# Whatever you specify here will replace the default files in the container with
# your content/configurations. You may comment any/all of the following lines to
# disable them use the container defaults.
#
# Specify a directory containing your NGINX configurations (if any)
# Remember that these will be all be applied in the HTTP configuration context.
# Only files with a ".conf" extension will be loaded! If you want to disable a
# file, simply change its extension (i.e. '.conf.disabled').
#
# REMEMBER: Your configuration files must be readable by the container UID/GID!
CONFIG_DIR=$(pwd)/config
# Specify a directory containing your NGINX server-block configurations (if any)
# If you are just serving static content from the 'webroot', you can use the
# container default server-blocks and comment this variable.
#
# More likely, you will have your own server blocks. Remember, files are
# processed in order so consider starting file names with numbers
# (i.e. 00-first_server.conf, 05-second_server.conf)
#
# Only files with a ".conf" extension will be loaded! If you want to disable a
# file, simply change its extension (i.e. '.conf.disabled').
#
# REMEMBER: Your server-block files must be readable by the container UID/GID!
SERVERS_DIR=$(pwd)/sites
# Specify a directory containing 'snippets' of NGINX code you want/need to
# reference in other configuration files. Pointers to other SSL certificates for
# hosted domains or commonly used headers are good examples.
#
# You can then "include /etc/nginx/snippets/yourSnippet.conf;" in your configs
# instead of having to type the same thing many times.
# This is totally optional! Comment this variable to disable it.
# REMEMBER: Your snippets must be readable by the container UID/GID!
SNIPPETS_DIR=$(pwd)/snippets
# Specify a directory with the content you want to serve.
# REMEMBER: This directory must be readable by the container UID/GID!
WEBROOT_DIR=/var/www
#
# SSL options:
#
# Enable HSTS only AFTER you've tested SSL implementation! Container sets the
# header to require SSL for 6 months! Subdomains are NOT included.
# REQUIRED: NO
# DEFAULT: FALSE
# VALID OPTIONS: 'TRUE', 'FALSE'
HSTS=FALSE
# TLS 1.3 mode:
# If 'FALSE' (default), NGINX will accept both TLS 1.2 and 1.3 connections.
# If 'TRUE', only TLS 1.3 connections will be accepted.
TLS13_ONLY=FALSE
#
# Certificate files
#
# If you are mounting symlinks you MUST specify the full path of the symlink so
# the target is resolved!
#
# REMEMBER: ALL files must be readable by container UID/GID!
# EXAMPLES:
# SSL_CERT=/path/to/your/ssl-certificate/fullchain.pem
# SSL_KEY=/path/to/your/ssl-private-key/privkey.pem
# SSL_CHAIN=/path/to/your/ssl-certificate-chain/chain.pem
SSL_CERT=""
SSL_KEY=""
SSL_CHAIN=""
#EOF

View File

@ -231,6 +231,7 @@ fi
checkExist 'file' './ab-nginx.params'
# read .params file
# shellcheck source=ab-nginx.params.template
. "./ab-nginx.params"
# fix case of TLS13_ONLY var

View File

@ -1,83 +1,87 @@
#!/bin/sh
### update script for ab-nginx container and utility scripts
# version 2.0.0
# script by Asif Bacchus
###
#
# update script for ab-nginx container and utility scripts
# version 2.1.0
# script by Asif Bacchus
#
### functions
#
# functions
errMsg() {
printf "\n%s%s%s\n\n" "$err" "$1" "$norm"
exit 1
printf "\n%s%s%s\n\n" "$err" "$1" "$norm"
[ -n "$2" ] && exit "$2" || exit 1
}
errNotify() {
printf "%s[ERROR]%s\n" "$err" "$norm"
printf "%s[ERROR]%s\n" "$err" "$norm"
}
okMsg() {
printf "%s%s%s\n\n" "$ok" "$1" "$norm"
printf "%s%s%s\n\n" "$ok" "$1" "$norm"
}
okNotify() {
printf "%s[OK]%s\n" "$ok" "$norm"
printf "%s[OK]%s\n" "$ok" "$norm"
}
scriptHelp() {
textNewline
textblock "Update ${containerName} container and helper script files"
textblock "${bold}Usage: ${localScriptName} [parameters]${norm}"
textNewline
textblock "If run with no parameters, the script will update both the container and the helper script files, including this update script."
textblockHeader " parameters "
textblockParam "-h|-?|--help" "Display this help screen."
textblockParam "-c|--container|--container-only" "Update the docker container only."
textblockParam "-s|--scripts|--scripts-only" "Update the helper scripts (including this update script) only."
textNewline
exit 0
textNewline
textBlock "Update ${containerName} container and helper script files"
textBlock "${bold}Usage: ${localScriptName} [parameters]${norm}"
textNewline
textBlock "If run with no parameters, the script will update both the container and the helper script files, including this update script."
textBlockHeader " parameters "
textBlockParam "-h|-?|--help" "Display this help screen."
textBlockParam "-c|--container|--container-only" "Update the docker container only."
textBlockParam "-s|--scripts|--scripts-only" "Update the helper scripts (including this update script) only."
textNewline
exit 0
}
textblock() {
printf "%s\n" "$1" | fold -w "$width" -s
textBlock() {
printf "%s\n" "$1" | fold -w "$width" -s
}
textblockHeader() {
printf "\n%s***%s***%s\n" "$header" "$1" "$norm"
textBlockHeader() {
printf "\n%s***%s***%s\n" "$header" "$1" "$norm"
}
textblockParam() {
printf "%s%-35s%s%s\n" "$info" "$1" "$2" "$norm"
textBlockParam() {
printf "%s%-35s%s%s\n" "$info" "$1" "$2" "$norm"
}
textNewline() {
printf "\n"
printf "\n"
}
### text formatting presets
#
# text formatting presets
if command -v tput >/dev/null 2>&1; then
bold=$(tput bold)
err=$(tput bold)$(tput setaf 1)
info=$(tput bold)$(tput setaf 6)
header=$(tput bold)$(tput setaf 5)
norm=$(tput sgr0)
ok=$(tput sgr0)$(tput setaf 2)
warn=$(tput bold)$(tput setaf 3)
width=$(tput cols)
bold=$(tput bold)
err=$(tput bold)$(tput setaf 1)
info=$(tput bold)$(tput setaf 6)
header=$(tput bold)$(tput setaf 5)
norm=$(tput sgr0)
ok=$(tput sgr0)$(tput setaf 2)
warn=$(tput bold)$(tput setaf 3)
width=$(tput cols)
else
bold=''
err=''
info=''
header=''
norm=''
ok=''
warn=''
width=80
bold=''
err=''
info=''
header=''
norm=''
ok=''
warn=''
width=80
fi
### pre-requisites
#
# pre-requisites
# check if wget is installed
if ! command -v wget >/dev/null 2>&1; then
errMsg "Sorry, this script requires that 'wget' is installed in order to download updates. Exiting."
errMsg "Sorry, this script requires that 'wget' is installed in order to download updates. Exiting."
fi
# zero counters
@ -102,149 +106,178 @@ doScriptUpdate=1
localScriptName="$(basename "$0")"
repoScriptName='update.sh'
### process startup parameters
#
# process startup parameters
while [ $# -gt 0 ]; do
case "$1" in
-h | -\? | --help)
# display inline help
scriptHelp
;;
-s | --scripts | --scripts-only)
# update scripts only, skip docker container update
doDockerUpdate=0
;;
-c | --container | --container-only)
# update docker container only, skip script update
doScriptUpdate=0
;;
*)
printf "%s\nUnknown option: %s\n" "$err" "$1"
printf "%sUse '--help' for valid options%s\n\n" "$info" "$norm"
exit 1
;;
esac
shift
case "$1" in
-h | -\? | --help)
# display inline help
scriptHelp
;;
-s | --scripts | --scripts-only)
# update scripts only, skip docker container update
doDockerUpdate=0
;;
-c | --container | --container-only)
# update docker container only, skip script update
doScriptUpdate=0
;;
*)
printf "%s\nUnknown option: %s\n" "$err" "$1"
printf "%sUse '--help' for valid options%s\n\n" "$info" "$norm"
exit 1
;;
esac
shift
done
### update container
#
# update container
if [ "$doDockerUpdate" -eq 1 ]; then
# check if docker is installed
if ! command -v docker >/dev/null 2>&1; then
errMsg "Sorry, it appears that docker is not installed on this machine! Exiting."
fi
# is user root or in the docker group?
if [ ! "$(id -u)" -eq 0 ]; then
if ! id -Gn | grep docker >/dev/null; then
errMsg "You must either be root or in the 'docker' group to pull container updates."
fi
fi
printf "%s\n*** Updating %s container ***\n\n%s" "$info" "$containerName" "$norm"
if ! docker pull "$containerUpdatePath"; then
errMsg "There was an error updating the container. Try again later."
else
okMsg "Container updated!"
fi
fi
### update scripts
if [ "$doScriptUpdate" -eq 1 ]; then
printf "%s*** Updating %s service scripts ***%s\n" "$info" "$containerName" "$norm"
## download latest checksums
printf "Getting latest checksums... "
if ! wget --quiet --tries=3 --timeout=10 -N "${server}${checksumFilename}"; then
errNotify
errMsg "Unable to download checksums. Try again later."
else
okNotify
fi
## check for updates to this script
printf "Checking for updates to this script... "
repoScriptChecksum=$(grep "$repoScriptName" "$checksumFilename" | grep -o '^\S*')
localScriptChecksum=$(sha256sum "$localScriptName" | grep -o '^\S*')
if [ "$localScriptChecksum" = "$repoScriptChecksum" ]; then
printf "[NONE]\n"
else
printf "[AVAILABLE]\n"
printf "Getting updated script... "
# download updated script
if ! wget --quiet --tries=3 --timeout=10 -O "update.sh.tmp" "${server}${repoScriptName}"; then
errNotify
# delete failed download as necessary
rm -f ./update.sh.tmp 2>/dev/null
errMsg "Unable to download script update. Try again later."
else
# verify download
dlScriptChecksum=$(sha256sum "update.sh.tmp" | grep -o '^\S*')
if ! [ "$dlScriptChecksum" = "$repoScriptChecksum" ]; then
printf "[ERROR]\n"
# delete corrupt download as necessary
rm -f ./update.sh.tmp 2>/dev/null
errMsg "Checksum mismatch! Try again later."
else
okNotify
printf "\n%s*** This script has been updated. Please re-run it to load the updated version of this file. ***%s\n\n" "$warn" "$norm"
# overwrite this script with updated script
mv -f ./update.sh.tmp "$localScriptName"
fi
fi
fi
## update files
while IFS=' ' read -r field1 field2; do
printf "\nChecking '%s' for updates... " "$field2"
updateFilename="$field2"
repoFileChecksum="$field1"
if [ -f "$updateFilename" ]; then
localFileChecksum=$(sha256sum "$updateFilename" | grep -o '^\S*')
else
localFileChecksum=0
# check if docker is installed
if ! command -v docker >/dev/null 2>&1; then
errMsg "Sorry, it appears that docker is not installed on this machine! Exiting." 2
fi
# update file if necessary
if ! [ "$localFileChecksum" = "$repoFileChecksum" ]; then
printf "[AVAILABLE]\n"
updatesAvailable=$((updatesAvailable + 1))
# download update
printf "Downloading updated '%s'... " "$updateFilename"
if ! wget --quiet --tries=3 --timeout=10 -O "$updateFilename.tmp" "${server}${updateFilename}"; then
errNotify
downloadFailed=$((downloadFailed + 1))
# delete failed download file as necessary
rm -f "$updateFilename.tmp" 2>&1
else
okNotify
downloadSuccess=$((downloadSuccess + 1))
# verify download
printf "Verifying '%s'... " "$updateFilename"
localFileChecksum=$(sha256sum "$updateFilename.tmp" | grep -o '^\S*')
if ! [ "$localFileChecksum" = "$repoFileChecksum" ]; then
errNotify
updateFailed=$((updateFailed + 1))
# delete corrupted download file as necessary
rm -f "$updateFilename.tmp" 2>&1
else
okNotify
updateSuccess=$((updateSuccess + 1))
# overwrite old version of file
mv -f "$updateFilename.tmp" "$updateFilename"
# is user root or in the docker group?
if [ ! "$(id -u)" -eq 0 ]; then
if ! id -Gn | grep docker >/dev/null; then
errMsg "You must either be root or in the 'docker' group to pull container updates." 2
fi
fi
else
printf "[NONE]\n"
fi
done <"$checksumFilename"
printf "%s\n*** Updating %s container ***\n\n%s" "$info" "$containerName" "$norm"
if ! docker pull "$containerUpdatePath"; then
errMsg "There was an error updating the container. Try again later." 31
else
okMsg "Container updated!"
fi
fi
### display results
#
# update scripts
if [ "$doScriptUpdate" -eq 1 ]; then
printf "\n%s*** Results ***%s\n" "$info" "$norm"
printf "\tUpdates: %s available\n" "$updatesAvailable"
printf "\tDownloads: %s%s successful%s, %s%s failed%s\n" "$ok" "$downloadSuccess" "$norm" "$err" "$downloadFailed" "$norm"
printf "\tUpdates: %s%s applied%s, %s%s failed%s\n" "$ok" "$updateSuccess" "$norm" "$err" "$updateFailed" "$norm"
printf "%s*** Updating %s service scripts ***%s\n" "$info" "$containerName" "$norm"
## download latest checksums
printf "Getting latest checksums... "
if ! wget --quiet --tries=3 --timeout=10 -N "${server}${checksumFilename}"; then
errNotify
errMsg "Unable to download checksums. Try again later." 41
else
okNotify
fi
## check for updates to this script
printf "Checking for updates to this script... "
repoScriptChecksum=$(grep "$repoScriptName" "$checksumFilename" | grep -o '^\S*')
localScriptChecksum=$(sha256sum "$localScriptName" | grep -o '^\S*')
if [ "$localScriptChecksum" = "$repoScriptChecksum" ]; then
printf "[NONE]\n"
else
printf "[AVAILABLE]\n"
printf "Getting updated script... "
# download updated script
if ! wget --quiet --tries=3 --timeout=10 -O "update.sh.tmp" "${server}${repoScriptName}"; then
errNotify
# delete failed download as necessary
rm -f ./update.sh.tmp 2>/dev/null
errMsg "Unable to download script update. Try again later." 42
else
# verify download
dlScriptChecksum=$(sha256sum "update.sh.tmp" | grep -o '^\S*')
if ! [ "$dlScriptChecksum" = "$repoScriptChecksum" ]; then
printf "[ERROR]\n"
# delete corrupt download as necessary
rm -f ./update.sh.tmp 2>/dev/null
errMsg "Checksum mismatch! Try again later." 42
else
okNotify
printf "\n%s*** This script has been updated. Please re-run it to load the updated version of this file. ***%s\n\n" "$warn" "$norm"
# overwrite this script with updated script
mv -f ./update.sh.tmp "$localScriptName"
fi
fi
fi
## update files
while IFS=' ' read -r field1 field2; do
printf "\nChecking '%s' for updates... " "$field2"
updateFilename="$field2"
repoFileChecksum="$field1"
if [ -f "$updateFilename" ]; then
localFileChecksum=$(sha256sum "$updateFilename" | grep -o '^\S*')
else
localFileChecksum=0
fi
# update file if necessary
if ! [ "$localFileChecksum" = "$repoFileChecksum" ]; then
printf "[AVAILABLE]\n"
updatesAvailable=$((updatesAvailable + 1))
# download update
printf "Downloading updated '%s'... " "$updateFilename"
if ! wget --quiet --tries=3 --timeout=10 -O "$updateFilename.tmp" "${server}${updateFilename}"; then
errNotify
downloadFailed=$((downloadFailed + 1))
# delete failed download file as necessary
rm -f "$updateFilename.tmp" 2>&1
else
okNotify
downloadSuccess=$((downloadSuccess + 1))
# verify download
printf "Verifying '%s'... " "$updateFilename"
localFileChecksum=$(sha256sum "$updateFilename.tmp" | grep -o '^\S*')
if ! [ "$localFileChecksum" = "$repoFileChecksum" ]; then
errNotify
updateFailed=$((updateFailed + 1))
# delete corrupted download file as necessary
rm -f "$updateFilename.tmp" 2>&1
else
okNotify
updateSuccess=$((updateSuccess + 1))
# overwrite old version of file
mv -f "$updateFilename.tmp" "$updateFilename"
fi
fi
else
printf "[NONE]\n"
fi
done <"$checksumFilename"
fi
exit 0
#
# display results
if [ "$doScriptUpdate" -eq 1 ]; then
printf "\n%s*** Results ***%s\n" "$info" "$norm"
printf "\tUpdates: %s available\n" "$updatesAvailable"
printf "\tDownloads: %s%s successful%s, %s%s failed%s\n" "$ok" "$downloadSuccess" "$norm" "$err" "$downloadFailed" "$norm"
printf "\tUpdates: %s%s applied%s, %s%s failed%s\n" "$ok" "$updateSuccess" "$norm" "$err" "$updateFailed" "$norm"
fi
#
# exit
if [ "$downloadFailed" -gt 0 ]; then
exit 43
elif [ "$updateFailed" -gt 0 ]; then
exit 44
else
exit 0
fi
# this is a trap for mis-coding... should never get an exit code 99!
exit 99
#
# exit return codes
# 0: normal exit, no errors
# 1: missing or invalid parameter
# 2: docker not found or no docker permissions
# 31: unable to update docker container
# 4x: helper files errors
# 41: unable to download checksums
# 42: update script: unable to download or bad checksum
# 43: update helpers: unable to download
# 44: update helpers: bad checksum, no update
# 99: coding mistake trap -- this return code should never happen!
#EOF