3 # Copyright (c) 2021 Cisco and/or its affiliates.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
19 # Log all output to stdout & stderr to a log file
20 logname="/tmp/$(basename $0).$(date -u +%Y_%m_%d_%H%M%S).log"
21 echo -e "\n*** Logging output to $logname ***\n"
22 exec > >(tee -a $logname) 2>&1
24 export CIMAN_DOCKER_SCRIPTS=${CIMAN_DOCKER_SCRIPTS:-"$(dirname $BASH_SOURCE)"}
25 . "$CIMAN_DOCKER_SCRIPTS/lib_common.sh"
28 long_bar="################################################################"
39 image_realname_prod=""
40 image_realname_prev=""
54 local script="$(basename $0)"
56 echo "Usage: $script r[evert] <prod image>"
57 echo " $script p[romote] <new image> [<new image>]"
58 echo " $script i[nspect] <prod image>"
60 echo " revert: swaps 'prod-<arch>' and 'prod-prev-<arch>' images"
61 echo " <prod image>: e.g. fdiotools/builder-ubuntu1804:prod-x86_64"
63 echo " promote: moves 'prod-<arch>' image to 'prod-prev-<arch>' tag and"
64 echo " tags <new image> with 'prod-<arch>'"
65 echo " <new image>: e.g. fdiotools/builder-ubuntu1804:2020_09_23_151655-x86_64"
66 echo " inspect: prints out all tags for prod-<arch> and prod-prev-<arch>"
72 echo -e "\n$long_bar\n"
73 echo "To restore tags to original state, issue the following command:"
74 echo -e "\n$restore_cmd\n\n$long_bar\n"
79 for image in "$@" ; do
81 echo "Pushing '$image' to docker hub..."
82 if ! docker push "$image" ; then
83 echo "ERROR: 'docker push $image' failed!"
90 image_user="$(echo $1 | cut -d'/' -f1)"
91 image_repo="$(echo $1 | cut -d'/' -f2 | cut -d':' -f1)"
92 local tag="$(echo $1 | cut -d':' -f2)"
93 image_version="$(echo $tag | cut -d'-' -f1)"
94 image_arch="$(echo $tag | sed -e s/$image_version-//)"
95 image_name_new="${image_user}/${image_repo}:${image_version}-${image_arch}"
96 if [ "$1" != "$image_name_new" ] ; then
97 echo "ERROR: Image name parsing failed: $1 != '$image_name_new'"
100 if [[ "$image_version" =~ "prod" ]] ; then
103 image_name_prod="${image_user}/${image_repo}:prod-${image_arch}"
104 image_name_prev="${image_user}/${image_repo}:prod-prev-${image_arch}"
107 format_image_tags() {
108 # Note: 'grep $image_arch' & grep -v 'prod-curr' is required due to a
109 # bug in docker hub which returns old tags which were deleted via
110 # the webUI, but are still retrieved by 'docker pull -a'
111 image_tags="$(docker images | grep $1 | grep $image_arch | grep -v prod-curr | sort -r | mawk '{print $1":"$2}' | tr '\n' ' ')"
112 image_realname="$(docker images | grep $1 | grep $image_arch | sort -r | grep -v prod | mawk '{print $1":"$2}' || true)"
113 if [ -z "${image_realname:-}" ] ; then
114 image_realname="$image_tags"
118 get_image_id_tags() {
119 for image in "$image_name_new" "$image_name_prod" "$image_name_prev" ; do
120 if [ -z "$image" ] ; then
123 # ensure image exists
125 local image_found="$(docker images | mawk '{print $1":"$2}' | grep $image)"
127 if [ -z "$image_found" ] ; then
128 if [ "$image" = "$image_name_prev" ] ; then
129 if [ "$action" = "revert" ] ; then
130 echo "ERROR: Image '$image' not found!"
131 echo "Unable to revert production image '$image_name_prod'!"
137 echo "ERROR: Image '$image' not found!"
142 local id="$(docker image inspect $image | mawk -F':' '/Id/{print $3}')"
143 local digest="$(docker image inspect $image | grep -A1 RepoDigests | grep -v RepoDigests | mawk -F':' '{print $2}')"
146 if [ "$retval" -ne "0" ] ; then
147 echo "ERROR: Docker ID not found for '$image'!"
150 if [ "$image" = "$image_name_prod" ] ; then
151 docker_id_prod="${id::12}"
152 digest_prod="${digest::12}"
153 format_image_tags "$docker_id_prod"
154 image_tags_prod="$image_tags"
155 if [ -z "$image_realname_prod" ] ; then
156 image_realname_prod="$image_realname"
158 elif [ "$image" = "$image_name_prev" ] ; then
159 docker_id_prev="${id::12}"
160 digest_prev="${digest::12}"
161 format_image_tags "$docker_id_prev"
162 image_tags_prev="$image_tags"
163 if [ -z "$image_realname_prev" ] ; then
164 image_realname_prev="$image_realname"
167 docker_id_new="${id::12}"
168 digest_new="${digest::12}"
169 format_image_tags "$docker_id_new" "NEW"
170 image_tags_new="$image_tags"
173 if [ -z "$restore_cmd" ] ; then
174 restore_cmd="sudo $0 p $image_realname_prev $image_realname_prod"
178 get_all_tags_from_dockerhub() {
179 local dh_repo="$image_user/$image_repo"
180 echo -e "Pulling all tags from docker hub repo '$dh_repo':\n$long_bar"
181 if ! docker pull -a "$dh_repo" ; then
182 echo "ERROR: Repository '$dh_repo' not found on docker hub!"
188 verify_image_version_date_format() {
190 # TODO: Remove regex1 when legacy nomenclature is no longer on docker hub.
191 local regex1="^[0-9]{4}_[0-1][0-9]_[0-3][0-9]_[0-2][0-9][0-5][0-9][0-5][0-9]$"
192 local regex2="^[0-9]{4}_[0-1][0-9]_[0-3][0-9]_[0-2][0-9][0-5][0-9][0-5][0-9]_UTC$"
193 if [[ "$version" =~ $regex1 ]] || [[ "$version" =~ $regex2 ]]; then
199 verify_image_name() {
202 if [ "$image_user" != "fdiotools" ] ; then
203 image_not_found="true"
204 echo "ERROR: invalid user '$image_user' in '$image_name_new'!"
207 if [ -z "$image_not_found" ] \
208 && [ "$image_version" != "prod" ] \
209 && ! verify_image_version_date_format "$image_version" ]] ; then
210 image_not_found="true"
211 echo "ERROR: invalid version '$image_version' in '$image_name_new'!"
214 if [ -z "$image_not_found" ] \
215 && ! [[ "$EXECUTOR_ARCHS" =~ .*"$image_arch".* ]] ; then
216 image_not_found="true"
217 echo "ERROR: invalid arch '$image_arch' in '$image_name_new'!"
219 if [ -n "$image_not_found" ] ; then
220 echo "ERROR: Invalid image '$image_name_new'!"
226 echo ">>> docker tag $1 $2"
231 if [ "$retval" -ne "0" ] ; then
232 echo "WARNING: 'docker tag $1 $2' failed!"
238 echo ">>> docker rmi $1"
242 if [ "$retval" -ne "0" ] ; then
243 echo "WARNING: 'docker rmi $1' failed!"
248 if [ -z "$2" ] ; then
249 echo "$1 Image Not Found"
252 echo "$1 (Id $2, Digest $3):"
259 echo -e "\n${1}Production Docker Images:"
261 if [ -n "$image_tags_new" ] ; then
262 print_image_list "NEW" "$docker_id_new" "$digest_new" "$image_tags_new"
265 print_image_list "prod-$image_arch" "$docker_id_prod" "$digest_prod" \
268 print_image_list "prod-prev-$image_arch" "$docker_id_prev" "$digest_prev" \
270 echo -e "$short_bar\n"
273 revert_prod_image() {
274 inspect_images "EXISTING "
275 docker_tag_image "$docker_id_prod" "$image_name_prev"
276 docker_tag_image "$docker_id_prev" "$image_name_prod"
278 inspect_images "REVERTED "
282 read -p "Push Reverted tags to '$image_user/$image_repo' (yes/no)? " yn
287 echo -e "\nABORTING REVERT!\n"
288 docker_tag_image $docker_id_prev $image_name_prod
289 docker_tag_image $docker_id_prod $image_name_prev
291 inspect_images "RESTORED LOCAL "
294 echo "Please answer yes or no." ;;
298 push_to_dockerhub $image_name_prev $image_name_prod
303 promote_new_image() {
304 inspect_images "EXISTING "
305 docker_tag_image "$docker_id_prod" "$image_name_prev"
306 docker_tag_image "$docker_id_new" "$image_name_prod"
308 inspect_images "PROMOTED "
312 read -p "Push promoted tags to '$image_user/$image_repo' (yes/no)? " yn
317 echo -e "\nABORTING PROMOTION!\n"
318 docker_tag_image "$docker_id_prev" "$image_name_prod"
319 local restore_both="$(echo $restore_cmd | mawk '{print $5}')"
320 if [[ -n "$restore_both" ]] ; then
321 docker_tag_image "$image_realname_prev" "$image_name_prev"
323 docker_rmi_tag "$image_name_prev"
328 inspect_images "RESTORED "
331 echo "Please answer yes or no." ;;
335 push_to_dockerhub "$image_name_new" "$image_name_prev" "$image_name_prod"
340 must_be_run_as_root_or_docker_group
344 if [ "$num_args" -lt "1" ] ; then
351 if [ "$num_args" -ne "2" ] ; then
352 echo "ERROR: Invalid number of arguments: $#"
356 if [ "$num_args" -eq "2" ] || [ "$num_args" -eq "3" ] ; then
359 echo "ERROR: Invalid number of arguments: $#"
364 if [ "$num_args" -ne "2" ] ; then
365 echo "ERROR: Invalid number of arguments: $#"
369 echo "ERROR: Invalid option '$1'!"
373 docker login >& /dev/null
377 for image in "$@" ; do
378 parse_image_name "$image"
379 verify_image_name "$image"
380 get_all_tags_from_dockerhub
382 if [ "$action" = "promote" ] ; then
383 if [ -n "$image_name_new" ] ; then
386 echo "ERROR: No new image specified to promote!"
389 elif [ "$action" = "revert" ] ; then
390 if [ "$image_version" = "prod" ] ; then
393 echo "ERROR: Non-production image '$image' specified!"
397 if [ "$image_version" = "prod" ] ; then
400 echo "ERROR: Non-production image '$image' specified!"