-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathimage-check-update.sh
executable file
·130 lines (113 loc) · 4.81 KB
/
image-check-update.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env sh
###########################################################################
# PROGRAM:
# Check if a local image tag differs from a remote tag, printing
# possible newer tags and optionally sending a notification.
###########################################################################
# Copyright (C) 2023 stendler
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
###########################################################################
#set -x
# podman or docker if not explicitly specified
if command -v podman 1>/dev/null; then
CONTAINER_CMD="${CONTAINER_CMD:=podman}"
elif command -v docker 1>/dev/null; then
CONTAINER_CMD="${CONTAINER_CMD:=docker}"
fi
OPTS=$(getopt --options qt:g: --longoptions quiet,docker,podman,grep:,ntfy-topic:,ntfy-email:,ntfy-url: -- "$@")
eval set -- "$OPTS"
while true; do
case "$1" in
-t|--ntfy-topic) NTFY_TOPIC="$2"; shift 2;;
-g|--grep) regex="$2"; shift 2;;
--ntfy-email) NTFY_EMAIL="$2"; shift 2;;
--ntfy-url) NTFY_URL="$2"; shift 2;;
--podman) command -v podman 1>/dev/null && CONTAINER_CMD="podman" || exit 1; shift;;
--docker) command -v docker 1>/dev/null && CONTAINER_CMD="docker" || exit 1; shift;;
-q|--quiet) quiet=true; shift;; # still printing to stderr, but not to stdout
--) shift; break;;
*) echo "Unknown argument: $1"; exit 1;;
esac
done
if [ -z "${CONTAINER_CMD}" ]; then
echo 1>&2 "Neither podman nor docker present and no CONTAINER_CMD set."
exit 1
fi
# optional socket url, in case this script is running in a container
if [ -n "$SOCKET_URL" ]; then
if [ "$CONTAINER_CMD" = "podman" ]; then
CONTAINER_CMD="podman --url=$SOCKET_URL"
fi
fi
if [ -z "$1" ]; then
echo >&2 "Image repository url (including e.g. \"docker.io/\") must be specified."
exit 1
fi
repo="$1"
image_tag='latest'
if [ -n "$2" ]; then
image_tag="$2"
fi
remote_tag="$image_tag"
if [ -n "$3" ]; then
remote_tag="$3"
fi
local_digest=$($CONTAINER_CMD image ls --all --digests --format '{{ .Digest }}' --no-trunc --filter "reference=$repo:$image_tag" | head -n 1)
if [ -z "$local_digest" ]; then
echo >&2 "No local image exists with this tag. Check $CONTAINER_CMD image ls"
exit 1
fi
remote_inspect=$(skopeo inspect "docker://$repo:$remote_tag")
remote_layers=$(echo "$remote_inspect" | jq --raw-output '.Layers')
if [ -z "$remote_layers" ]; then
exit 1 # no error message needed, was probably already printed to stderr
fi
# this may throw an error if the manifest does not exist on the remote anymore - but that means, an update is probably available
local_inspect=$(skopeo inspect "docker://$repo@$local_digest")
local_layers=$(echo "$local_inspect" | jq --raw-output '.Layers')
if [ "$remote_layers" = "$local_layers" ]; then
if [ "$remote_tag" = "$image_tag" ]; then
echo >&2 "$1:$image_tag is up-to-date"
else
echo >&2 "$1:$image_tag is up-to-date with tag $remote_tag"
fi
exit 0
fi
# declare locally used variables
message=""
ntfy_mail_header=""
if [ "$remote_tag" = "$image_tag" ]; then
echo >&2 "$1:$image_tag can be updated."
else
echo >&2 "$1:$image_tag is not up-to-date with tag $remote_tag."
if [ -z "$quiet" ]; then
echo >&2 "These tags could be newer:"
# get the list of tags starting from the image_tag
tag_list=$(echo "$remote_inspect" | jq --raw-output ".RepoTags as \$tags | \$tags | index(\"${image_tag}\") as \$start | \$tags[\$start+1:] | map(select(test(\"${regex}\"))) | join(\"\\n\")")
echo "$tag_list"
# limit to less than 4096 to prevent turning the message into an attachment: https://docs.ntfy.sh/publish/#limitations
message=$(printf "Possible update candidates:\n%s" "$tag_list" | head -c 4095)
fi
fi
if [ -n "$NTFY_TOPIC" ]; then
if [ -n "$NTFY_EMAIL" ]; then
NTFY_EMAIL="Email: $NTFY_EMAIL"
ntfy_mail_header="--header"
fi
curl >/dev/null 2>&1 --header "Tags: whale" --header "Firebase: no" "$ntfy_mail_header" "$NTFY_EMAIL" \
--header "Title: ${NTFY_USER:=$(whoami)}@${NTFY_HOSTNAME:=$(hostname)}: $repo:$image_tag is outdated compared to remote tag '$remote_tag'" \
--data "$message" "${NTFY_URL:=https://ntfy.sh}/$NTFY_TOPIC"
fi
exit 2