Last active
June 12, 2018 11:48
-
-
Save xianlubird/b6ee81245831027e229fe31bf2cdbcba to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Script to determine what named images and containers are dependent on the specified image (or a containers image) from stdin or in the args | |
# An unmatchable input is ignored | |
# All of the following will be found: | |
# Any image name / tag / name:tag / id that has a prefix in it that matches the input | |
# Any other image that relies on the images specified | |
# Any containers (running or not) that use any of these images | |
set -euf -o pipefail | |
debugMsg() { | |
true | |
#printf "%s\n" "$@" >&2 | |
} | |
specifiedParents="" | |
# Find all the images that need to be removed | |
if [ "$#" -ge "1" ]; then | |
# Images for removal in args | |
specifiedParents="$(printf " %s\n" "$@")" | |
else | |
# Images for removal to arrive via stdin | |
while IFS= read -r inStr; do | |
if [ -n "$inStr" ]; then | |
specifiedParents="$(printf "%s %s\n" "$specifiedParents" "$inStr")" | |
fi | |
done | |
fi | |
debugMsg "DBG:1 specifiedParents = '$specifiedParents'" | |
# Check there is some input | |
if [ -z "$specifiedParents" ]; then | |
printf "%s" "Nothing specified to search for; images/containers must be specified as either args or on the stdin" >&2 | |
exit 1 | |
fi | |
# Collect the container and image info | |
containersData="$(docker ps -a --format 'Container {{.ID}} {{.Image}} {{.Names}} {{.Labels}}' --no-trunc)" | |
allImagesData="$(docker images -a --format 'Image {{.ID}} {{.Repository}}:{{.Tag}} {{.Repository}} {{.Tag}}' --no-trunc | sed 's/ [^:]*:/ /')" | |
namedImagesData="$(docker images --format 'Image {{.ID}} {{.Repository}}:{{.Tag}}' --no-trunc | sed 's/ [^:]*:/ /')" | |
debugMsg "DBG:2 containersData = '$containersData'" | |
debugMsg "DBG:3 allImagesData = '$allImagesData'" | |
debugMsg "DBG:4 namedImagesData = '$namedImagesData'" | |
# Check to see if you can find a matching container | |
parents="" | |
while IFS= read -r aParent; do | |
if [ -z "$aParent" ]; then | |
continue | |
fi | |
# Use space to ensure matching starts at the beginning of a field | |
anImageId=" $(printf "%s" "$containersData" | grep -F " $aParent" | awk '{print $3}' || true)" | |
if [ "$anImageId" != " " ]; then | |
# A container matched so use the image ID | |
parents="$(printf "%s%s\n" "$parents" " $anImageId")" | |
else | |
# Not a container, so presumably an image | |
parents="$(printf "%s%s\n" "$parents" " $aParent")" | |
fi | |
done <<< $(printf "%s\n" "$specifiedParents") # Performing while inside this shell | |
#debugMsg "DBG:5 parents = '$parents'" | |
# Get the full parent image ID's | |
parentImageIds="" | |
while IFS= read -r aParent; do | |
debugMsg "DBG:6 aParent = '$aParent'" | |
# Find anything matching the parent and get it's full ID | |
while IFS= read -r parentImageId; do | |
if [ -z "$parentImageId" ]; then | |
continue | |
fi | |
debugMsg "DBG:7 parentImageId = '$parentImageId'" | |
# Add the full ID to the parentImageIds, including a space to assist matching later | |
parentImageIds="$(printf "%s%s\n" "$parentImageIds" " $parentImageId")" | |
done <<< $(printf "%s" "$allImagesData" | grep -F " $aParent" | awk '{print $2}') | |
done <<< $(printf "%s" "$parents") # Performing while inside this shell | |
debugMsg "DBG:8 parentImageIds = '$parentImageIds'" | |
# Stop if there are no parents | |
if [ -z "$parentImageIds" ]; then | |
exit 0 | |
fi | |
# Deduplicate | |
parentImageIds="$(printf "%s" "$parentImageIds" | LC_ALL=C sort -u)" | |
debugMsg "DBG:9 parentImageIds = '$parentImageIds'" | |
# Find descendent images | |
descendentImages="" | |
while IFS= read -r imageData; do | |
anImageId="$(printf "%s" "$imageData" | awk '{print $2}')" | |
# Check to see if this ID is a descendent of parentImageIds by imageInfo by moving through it's lineage | |
areDescendents="" | |
imageIdsChecked="" | |
while true; do | |
# Record that anImageId is being checked; including the space at the start to assist matching later | |
imageIdsChecked="$(printf "%s%s\n" "$imageIdsChecked" " $anImageId")" | |
if printf "%s" "$descendentImages" | grep -q -F "$anImageId"; then | |
# Already determined that anImageId is a descendent of parentImageIds so TheImage is too | |
areDescendents="true" | |
break; | |
else | |
if printf "%s" "$parentImageIds" | grep -q -F " $anImageId"; then | |
# TheImage is a descendent of parentImageIds | |
areDescendents="true" | |
break; | |
fi | |
# Move onto the parent of anImageId | |
anImageId="$(docker inspect --format '{{.Parent}}' "$anImageId" | sed 's/.*://')" | |
if [ -z "$anImageId" ]; then | |
# Reached the end of the line; abandon all hope ye who enter here | |
break; | |
fi | |
fi | |
done | |
# Add descendents to the descendentImages | |
if [ -n "$areDescendents" ]; then | |
descendentImages="$(printf "%s%s\n" "$descendentImages" "$imageIdsChecked")" | |
fi | |
done <<< $(printf "%s" "$allImagesData") # Performing while inside this shell | |
debugMsg "DBG:10 descendentImages = '$descendentImages'" | |
checkIfDescendentImageFound() { | |
# Check to see if this is a descendent from any parent | |
# $1 is thisImageId | |
# $2 is the display text | |
# Using the space to ensure matching form the start of an ID | |
if printf "%s" "$descendentImages" | grep -q -F " $1"; then | |
# We've found a descendent; display it quick before it gets away | |
debugMsg "DBG: Found " | |
printf "%s\n" "$2" | |
fi | |
} | |
# Identify any named images that are descendents of the parentImageIds | |
debugMsg "DBG:11 namedImagesData = '$namedImagesData'" | |
printf "%s\n" "$namedImagesData" | while IFS= read -r imageData; do | |
thisImageId="$(printf "%s" "$imageData" | awk '{print $2}')" | |
checkIfDescendentImageFound "$thisImageId" "$imageData" | |
done | |
# Identify containers that rely on images that are descendents of the parentImageIds | |
debugMsg "DBG:12 containersData = '$containersData'" | |
printf "%s\n" "$containersData" | while IFS= read -r containerData; do | |
thisImageId="$(printf "%s" "$containerData" | awk '{print $3}')" | |
checkIfDescendentImageFound "$thisImageId" "$containerData" | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment