diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..04b74b8 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,11 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-yaml + - id: check-added-large-files + - id: trailing-whitespace + args: [--markdown-linebreak-ext=md] + - id: end-of-file-fixer + - id: mixed-line-ending + args: ['--fix=lf'] diff --git a/README.md b/README.md index 02b87b5..fb62329 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

-

+

bash GPLv3 release @@ -72,16 +72,16 @@ Containers with updates available: Choose what containers to update: Enter number(s) separated by comma, [a] for all - [q] to quit: ``` -Then it proceedes to run `pull` and `up -d` on every container with updates. +Then it proceedes to run `pull` and `up -d` on every container with updates. After the updates are complete, you'll get prompted if you'd like to prune dangling images. ___ ## :nut_and_bolt: Dependencies -- Running docker (duh) and compose, either standalone or plugin. +- Running docker (duh) and compose, either standalone or plugin. - Bash shell or compatible shell of at least v4.3 -- [regclient/regctl](https://github.com/regclient/regclient) (Licensed under [Apache-2.0 License](http://www.apache.org/licenses/LICENSE-2.0)) - - User will be prompted to download `regctl` if not in `PATH` or `PWD`. +- [regclient/regctl](https://github.com/regclient/regclient) (Licensed under [Apache-2.0 License](http://www.apache.org/licenses/LICENSE-2.0)) + - User will be prompted to download `regctl` if not in `PATH` or `PWD`. - regctl requires `amd64/arm64` - see [workaround](#roller_coaster-workaround-for-non-amd64--arm64) if other architecture is used. ## :tent: Install Instructions @@ -99,10 +99,10 @@ Add preferred `notify.sh`-template to the same directory - this will not be touc ## :loudspeaker: Notifications -Trigger with the `-i` flag. +Trigger with the `-i` flag. Run it scheduled with `-ni` to only get notified when there's updates available! -Use a `notify_X.sh` template file, copy it to `notify.sh`, modify it to your needs! (notify.sh is added to .gitignore) +Use a `notify_X.sh` template file, copy it to `notify.sh`, modify it to your needs! (notify.sh is added to .gitignore) **Current templates:** - Synology [DSM](https://www.synology.com/en-global/dsm) - Email with [mSMTP](https://wiki.debian.org/msmtp) (or deprecated alternative [sSMTP](https://wiki.debian.org/sSMTP)) @@ -115,7 +115,7 @@ Use a `notify_X.sh` template file, copy it to `notify.sh`, modify it to your nee - [Telegram](https://telegram.org/) - Telegram chat API. - [Matrix-Synapse](https://github.com/element-hq/synapse) - [Matrix](https://matrix.org/), open, secure, decentralised communication. -Further additions are welcome - suggestions or PR! +Further additions are welcome - suggestions or PR! Initiated and first contributed by [yoyoma2](https://github.com/yoyoma2). ## :bookmark: Labels @@ -163,7 +163,7 @@ function dchk { - Not working well with containers created by Portainer. ## :warning: `-r flag` disclaimer and warning -**Wont auto-update the containers, only their images. (compose is recommended)** +**Wont auto-update the containers, only their images. (compose is recommended)** `docker run` dont support using new images just by restarting a container. Containers need to be manually stopped, removed and created again to run on the new image. @@ -176,5 +176,5 @@ ___ ## Special Thanks -- :bison: [t0rnis](https://github.com/t0rnis) +- :bison: [t0rnis](https://github.com/t0rnis) - :leopard: [Palleri](https://github.com/Palleri) diff --git a/dockcheck.sh b/dockcheck.sh index 3a00518..0ea7c73 100755 --- a/dockcheck.sh +++ b/dockcheck.sh @@ -16,7 +16,7 @@ LatestChanges="$(curl -s -r 0-200 $RawUrl | sed -n "/ChangeNotes/s/### ChangeNot ### Help Function: Help() { - echo "Syntax: dockcheck.sh [OPTION] [part of name to filter]" + echo "Syntax: dockcheck.sh [OPTION] [part of name to filter]" echo "Example: dockcheck.sh -y -d 10 -e nextcloud,heimdall" echo echo "Options:" @@ -58,7 +58,7 @@ while getopts "aynpfrhlisvme:d:t:" options; do e) Exclude=${OPTARG} ;; m) declare c_{red,green,yellow,blue,teal,reset}="" ;; s) Stopped="-a" ;; - t) Timeout="${OPTARG}" ;; + t) Timeout="${OPTARG}" ;; v) printf "%s\n" "$VERSION" ; exit 0 ;; d) DaysOld=${OPTARG} if ! [[ $DaysOld =~ ^[0-9]+$ ]] ; then { printf "Days -d argument given (%s) is not a number.\n" "${DaysOld}" ; exit 2 ; } ; fi ;; @@ -69,12 +69,12 @@ shift "$((OPTIND-1))" self_update_curl() { cp "$ScriptPath" "$ScriptPath".bak - if [[ $(builtin type -P curl) ]]; then - curl -L $RawUrl > "$ScriptPath" ; chmod +x "$ScriptPath" + if [[ $(builtin type -P curl) ]]; then + curl -L $RawUrl > "$ScriptPath" ; chmod +x "$ScriptPath" printf "\n%s\n" "--- starting over with the updated version ---" exec "$ScriptPath" "${ScriptArgs[@]}" # run the new script with old arguments exit 1 # exit the old instance - elif [[ $(builtin type -P wget) ]]; then + elif [[ $(builtin type -P wget) ]]; then wget $RawUrl -O "$ScriptPath" ; chmod +x "$ScriptPath" printf "\n%s\n" "--- starting over with the updated version ---" exec "$ScriptPath" "${ScriptArgs[@]}" # run the new script with old arguments @@ -103,7 +103,7 @@ self_update() { choosecontainers() { while [[ -z "$ChoiceClean" ]]; do read -r -p "Enter number(s) separated by comma, [a] for all - [q] to quit: " Choice - if [[ "$Choice" =~ [qQnN] ]] ; then + if [[ "$Choice" =~ [qQnN] ]] ; then exit 0 elif [[ "$Choice" =~ [aAyY] ]] ; then SelectedUpdates=( "${GotUpdates[@]}" ) @@ -147,9 +147,9 @@ progress_bar() { } ### Version check & initiate self update -if [[ "$VERSION" != "$LatestRelease" ]] ; then +if [[ "$VERSION" != "$LatestRelease" ]] ; then printf "New version available! %b%s%b ⇒ %b%s%b \n Change Notes: %s \n" "$c_yellow" "$VERSION" "$c_reset" "$c_green" "$LatestRelease" "$c_reset" "$LatestChanges" - if [[ -z "$AutoUp" ]] ; then + if [[ -z "$AutoUp" ]] ; then read -r -p "Would you like to update? y/[n]: " SelfUpdate [[ "$SelfUpdate" =~ [yY] ]] && self_update fi @@ -218,7 +218,7 @@ DocCount=$(docker ps $Stopped --filter "name=$SearchName" --format '{{.Names}}' RegCheckQue=0 ### Testing and setting timeout binary -t_out=$(type -P "timeout") +t_out=$(type -P "timeout") if [[ $t_out ]]; then t_out=$(realpath $t_out 2>/dev/null || readlink -f $t_out) if [[ $t_out =~ "busybox" ]]; then @@ -233,17 +233,17 @@ for i in $(docker ps $Stopped --filter "name=$SearchName" --format '{{.Names}}') ((RegCheckQue+=1)) progress_bar "$RegCheckQue" "$DocCount" ### Looping every item over the list of excluded names and skipping: - for e in "${Excludes[@]}" ; do [[ "$i" == "$e" ]] && continue 2 ; done + for e in "${Excludes[@]}" ; do [[ "$i" == "$e" ]] && continue 2 ; done RepoUrl=$(docker inspect "$i" --format='{{.Config.Image}}') LocalHash=$(docker image inspect "$RepoUrl" --format '{{.RepoDigests}}') # Checking for errors while setting the variable: if RegHash=$(${t_out} $regbin image digest --list "$RepoUrl" 2>&1) ; then - if [[ "$LocalHash" = *"$RegHash"* ]] ; then - NoUpdates+=("$i") - else + if [[ "$LocalHash" = *"$RegHash"* ]] ; then + NoUpdates+=("$i") + else if [[ -n "$DaysOld" ]] && ! datecheck ; then - NoUpdates+=("+$i ${ImageAge}d") - else + NoUpdates+=("+$i ${ImageAge}d") + else GotUpdates+=("$i") fi fi @@ -273,13 +273,13 @@ if [[ -n ${GotErrors[*]} ]] ; then printf "%s\n" "${GotErrors[@]}" printf "%binfo:%b 'unauthorized' often means not found in a public registry.\n" "$c_blue" "$c_reset" fi -if [[ -n ${GotUpdates[*]} ]] ; then +if [[ -n ${GotUpdates[*]} ]] ; then printf "\n%bContainers with updates available:%b\n" "$c_yellow" "$c_reset" [[ -z "$AutoUp" ]] && options || printf "%s\n" "${GotUpdates[@]}" [[ -n "$Notify" ]] && { [[ $(type -t send_notification) == function ]] && send_notification "${GotUpdates[@]}" || printf "Could not source notification function.\n" ; } fi -### Optionally get updates if there's any +### Optionally get updates if there's any if [ -n "$GotUpdates" ] ; then if [ -z "$AutoUp" ] ; then printf "\n%bChoose what containers to update.%b\n" "$c_teal" "$c_reset" @@ -302,14 +302,14 @@ if [ -n "$GotUpdates" ] ; then ContUpdateLabel=$(docker inspect "$i" --format '{{ index .Config.Labels "mag37.dockcheck.update" }}') ContRestartStack=$(docker inspect "$i" --format '{{ index .Config.Labels "mag37.dockcheck.restart-stack" }}') ### Checking if compose-values are empty - hence started with docker run: - if [ -z "$ContPath" ] ; then + if [ -z "$ContPath" ] ; then if [ "$DRunUp" == "yes" ] ; then docker pull "$ContImage" printf "%s\n" "$i got a new image downloaded, rebuild manually with preferred 'docker run'-parameters" else printf "\n%b%s%b has no compose labels, probably started with docker run - %bskipping%b\n\n" "$c_yellow" "$i" "$c_reset" "$c_yellow" "$c_reset" fi - continue + continue fi ### cd to the compose-file directory to account for people who use relative volumes, eg - ${PWD}/data:data cd "$ContPath" || { echo "Path error - skipping $i" ; continue ; } @@ -326,15 +326,15 @@ if [ -n "$GotUpdates" ] ; then ### Check if the container got an environment file set and reformat it if [ -n "$ContEnv" ]; then ContEnvs=$(for env in ${ContEnv//,/ } ; do printf -- "--env-file %s " "$env"; done) ; fi ### Check if the whole stack should be restarted - if [[ "$ContRestartStack" == true ]] || [[ "$ForceRestartStacks" == true ]] ; then - $DockerBin ${CompleteConfs} stop ; $DockerBin ${CompleteConfs} ${ContEnvs} up -d + if [[ "$ContRestartStack" == true ]] || [[ "$ForceRestartStacks" == true ]] ; then + $DockerBin ${CompleteConfs} stop ; $DockerBin ${CompleteConfs} ${ContEnvs} up -d else - $DockerBin ${CompleteConfs} ${ContEnvs} up -d ${ContName} + $DockerBin ${CompleteConfs} ${ContEnvs} up -d ${ContName} fi done printf "\n%bAll done!%b\n" "$c_green" "$c_reset" [[ -z "$AutoPrune" ]] && read -r -p "Would you like to prune dangling images? y/[n]: " AutoPrune - [[ "$AutoPrune" =~ [yY] ]] && docker image prune -f + [[ "$AutoPrune" =~ [yY] ]] && docker image prune -f else printf "\nNo updates installed, exiting.\n" fi @@ -343,4 +343,3 @@ else fi exit 0 - diff --git a/extras/apprise_quickstart.md b/extras/apprise_quickstart.md index 4ed8bfe..2d1ddd6 100644 --- a/extras/apprise_quickstart.md +++ b/extras/apprise_quickstart.md @@ -25,13 +25,13 @@ services: Then browse to the webui. ![](apprise-ex1.png) Here you'll click **Configuration Manager**, read the overview and then click on **Configuration**. -Under **Configuration** you'll craft/paste your notification config. +Under **Configuration** you'll craft/paste your notification config. ![](apprise-ex2.png) -The simplest way is just paste the url's as is (like in the example above). -There are many ways to customize with tags, groups, json and more. Read [caronc/apprise-api](https://github.com/caronc/apprise-api) for more info! +The simplest way is just paste the url's as is (like in the example above). +There are many ways to customize with tags, groups, json and more. Read [caronc/apprise-api](https://github.com/caronc/apprise-api) for more info! -Look at the [apprise wiki: Notification Services](https://github.com/caronc/apprise/wiki) for more info about how the url syntax for different services works. +Look at the [apprise wiki: Notification Services](https://github.com/caronc/apprise/wiki) for more info about how the url syntax for different services works. You can also use the [caronc/apprise-api](https://github.com/caronc/apprise-api) to host the api as a frontend to an already existing **Apprise**-setup on the host. @@ -40,7 +40,7 @@ You can also use the [caronc/apprise-api](https://github.com/caronc/apprise-api) ### Customize the **notify.sh** file. After you're done with the setup of the container and tried your notifications, you can copy the `notify_apprise.sh` file to `notify.sh` and start editing it. -Comment out/remove the bare metal apprise-command (starting with `apprise -vv -t...`). +Comment out/remove the bare metal apprise-command (starting with `apprise -vv -t...`). Uncomment and edit the `AppriseURL` variable and *curl* line It should look something like this when curling the API: ```bash @@ -72,11 +72,11 @@ ___ ## On host installed **Apprise** -Follow the official guide on [caronc/apprise](https://github.com/caronc/apprise)! +Follow the official guide on [caronc/apprise](https://github.com/caronc/apprise)! ### A brief, basic "get started" -- Install **apprise** +- Install **apprise** - python package `pip install apprise` - packaged in EPEL/Fedora `dnf install apprise` - packaged in AUR `[yay/pikaur/paru/other] apprise` @@ -92,7 +92,7 @@ Then either source the notifications with `-c=/path/to/config/apprise` or store - Test apprise with a single notification: - `apprise -vv -t 'test title' -b 'test notification body' 'mailto://myemail:mypass@gmail.com'` - Set up your notification URL's and test them. - - Look at the [apprise wiki: Notification Services](https://github.com/caronc/apprise/wiki) for more info about how the url syntax for different services works. + - Look at the [apprise wiki: Notification Services](https://github.com/caronc/apprise/wiki) for more info about how the url syntax for different services works. ### When done, customize the **notify.sh** file. After you're done with the setup of the container and tried your notifications, you can copy the `notify_apprise.sh` file to `notify.sh` and start editing it. diff --git a/extras/dc_brief.sh b/extras/dc_brief.sh index c188ae0..d496d06 100755 --- a/extras/dc_brief.sh +++ b/extras/dc_brief.sh @@ -29,7 +29,7 @@ for i in $(docker ps --filter "name=$SearchName" --format '{{.Names}}') ; do done ### Sort arrays alphabetically -IFS=$'\n' +IFS=$'\n' NoUpdates=($(sort <<<"${NoUpdates[*]}")) GotUpdates=($(sort <<<"${GotUpdates[*]}")) GotErrors=($(sort <<<"${GotErrors[*]}")) @@ -44,7 +44,7 @@ if [[ -n ${GotErrors[*]} ]] ; then printf "\n\033[0;31mContainers with errors, wont get updated:\033[0m\n" printf "%s\n" "${GotErrors[@]}" fi -if [[ -n ${GotUpdates[*]} ]] ; then +if [[ -n ${GotUpdates[*]} ]] ; then printf "\n\033[0;33mContainers with updates available:\033[0m\n" printf "%s\n" "${GotUpdates[@]}" fi diff --git a/extras/errorCheck.sh b/extras/errorCheck.sh index 30ebe52..327f454 100755 --- a/extras/errorCheck.sh +++ b/extras/errorCheck.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash SearchName="$1" -for i in $(docker ps --filter "name=$SearchName" --format '{{.Names}}') ; do +for i in $(docker ps --filter "name=$SearchName" --format '{{.Names}}') ; do echo "------------ $i ------------" ContPath=$(docker inspect "$i" --format '{{ index .Config.Labels "com.docker.compose.project.working_dir" }}') [ -z "$ContPath" ] && { "$i has no compose labels - skipping" ; continue ; } @@ -8,7 +8,7 @@ for i in $(docker ps --filter "name=$SearchName" --format '{{.Names}}') ; do ContName=$(docker inspect "$i" --format '{{ index .Config.Labels "com.docker.compose.service" }}') ContEnv=$(docker inspect "$i" --format '{{index .Config.Labels "com.docker.compose.project.environment_file" }}') ContImage=$(docker inspect "$i" --format='{{.Config.Image}}') - + if [[ $ContConfigFile = '/'* ]] ; then ComposeFile="$ContConfigFile" else diff --git a/notify_DSM.sh b/notify_DSM.sh index b6e4df0..2affe30 100644 --- a/notify_DSM.sh +++ b/notify_DSM.sh @@ -9,7 +9,7 @@ MSMTP=$(which msmtp) SSMTP=$(which ssmtp) -if [ -n $MSMPT ] ; then +if [ -n $MSMPT ] ; then MAIL=$MSMTP elif [ -n $SSMTP ] && [ -z $MAIL ] ; then MAIL=$SSMTP diff --git a/notify_apprise.sh b/notify_apprise.sh index 9945524..9080cd8 100644 --- a/notify_apprise.sh +++ b/notify_apprise.sh @@ -33,5 +33,3 @@ apprise -vv -t "$MessageTitle" -b "$MessageBody" \ # curl -X POST -F "title=$MessageTitle" -F "body=$MessageBody" -F "tags=all" $AppriseURL } - - diff --git a/notify_gotify.sh b/notify_gotify.sh index 7a41a77..832b387 100644 --- a/notify_gotify.sh +++ b/notify_gotify.sh @@ -8,18 +8,18 @@ send_notification() { Updates=("$@") UpdToString=$( printf "%s\n" "${Updates[@]}" ) FromHost=$(hostname) - + # platform specific notification code would go here printf "\nSending Gotify notification\n" - + # Setting the MessageTitle and MessageBody variable here. MessageTitle="${FromHost} - updates available." MessageBody="Containers on ${FromHost} with updates available: ${UpdToString}" - + # Modify to fit your setup: GotifyToken="Your Gotify token here" - GotifyUrl="https://api.gotify/message?token=${GotifyToken}" - + GotifyUrl="https://api.gotify/message?token=${GotifyToken}" + curl \ -F "title=${MessageTitle}" \ -F "message=${MessageBody}" \ diff --git a/notify_matrix.sh b/notify_matrix.sh index 4c98456..998592a 100644 --- a/notify_matrix.sh +++ b/notify_matrix.sh @@ -8,13 +8,13 @@ send_notification() { Updates=("$@") UpdToString=$( printf "%s\n" "${Updates[@]}" ) FromHost=$(hostname) - + # platform specific notification code would go here printf "\nSending Matrix notification\n" - + # Setting the MessageBody variable here. MessageBody="🐋 Containers on $FromHost with updates available: \n$UpdToString" - + # Modify to fit your setup: AccessToken="Your Matrix token here" Room_id="Enter Room_id here" @@ -24,5 +24,5 @@ send_notification() { # URL Example: https://matrix.org/_matrix/client/r0/rooms/!xxxxxx:example.com/send/m.room.message?access_token=xxxxxxxx curl -sS -o /dev/null --fail -X POST "$MatrixServer/_matrix/client/r0/rooms/$Room_id/send/m.room.message?access_token=$AccessToken" -H 'Content-Type: application/json' -d "$MsgBody" - + } diff --git a/notify_smtp.sh b/notify_smtp.sh index c62d3ed..9c81aa9 100644 --- a/notify_smtp.sh +++ b/notify_smtp.sh @@ -8,7 +8,7 @@ MSMTP=$(which msmtp) SSMTP=$(which ssmtp) -if [ -n $MSMPT ] ; then +if [ -n $MSMPT ] ; then MAIL=$MSMTP elif [ -n $SSMTP ] && [ -z $MAIL ] ; then MAIL=$SSMTP diff --git a/notify_telegram.sh b/notify_telegram.sh index e6da963..45584e6 100644 --- a/notify_telegram.sh +++ b/notify_telegram.sh @@ -8,20 +8,20 @@ send_notification() { Updates=("$@") UpdToString=$( printf "%s\n" "${Updates[@]}" ) FromHost=$(hostname) - + # platform specific notification code would go here printf "\nSending Telegram notification\n" - + # Setting the MessageBody variable here. MessageBody="🐋 Containers on $FromHost with updates available: \n$UpdToString" - + # Modify to fit your setup: TelegramToken="Your Telegram token here" TelegramChatId="Your Telegram ChatId here" TelegramUrl="https://api.telegram.org/bot$TelegramToken" TelegramTopicID=12345678 ## Set to 0 if not using specific topic within chat TelegramData="{\"chat_id\":\"$TelegramChatId\",\"text\":\"$MessageBody\",\"message_thread_id\":\"$TelegramTopicID\",\"disable_notification\": false}" - + curl -sS -o /dev/null --fail -X POST "$TelegramUrl/sendMessage" -H 'Content-Type: application/json' -d "$TelegramData" - + }