aboutsummaryrefslogtreecommitdiff
path: root/contrib/imgprune/entrypoint.sh
blob: fd80d9b2652eea343f2a93b64001ca88cf4db27b (plain)
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
#!/usr/bin/env bash

set -e

source /usr/local/bin/lib_entrypoint.sh

req_env_var GCPJSON GCPNAME GCPPROJECT IMGNAMES

unset BASE_IMAGES
# When executing under Cirrus-CI, script have access to current source
LIB="$CIRRUS_WORKING_DIR/$SCRIPT_BASE/lib.sh"
if [[ "$CI" == "true" ]] && [[ -r "$LIB" ]]
then
    # Avoid importing anything that might conflict
    for env in $(sed -ne 's/^[^#]\+_BASE_IMAGE=/img=/p' "$LIB")
    do
        eval $env
        BASE_IMAGES="$BASE_IMAGES $img"
    done
else
    # metadata labeling may have broken for some reason in the future
    echo "Warning: Running outside of Cirrus-CI, very minor-risk of base-image deletion."
fi

gcloud_init

# For safety's sake + limit nr background processes
PRUNE_LIMIT=5
THEFUTURE=$(date --date='+1 hour' +%s)
TOO_OLD='30 days ago'
THRESHOLD=$(date --date="$TOO_OLD" +%s)
# Format Ref: https://cloud.google.com/sdk/gcloud/reference/topic/formats
FORMAT='value[quote](name,selfLink,creationTimestamp,labels)'
PROJRE="/v1/projects/$GCPPROJECT/global/"
RECENTLY=$(date --date='3 days ago' --iso-8601=date)
# Filter Ref: https://cloud.google.com/sdk/gcloud/reference/topic/filters
FILTER="selfLink~$PROJRE AND creationTimestamp<$RECENTLY AND NOT name=($IMGNAMES $BASE_IMAGES)"
TODELETE=$(mktemp -p '' todelete.XXXXXX)
IMGCOUNT=$(mktemp -p '' imgcount.XXXXXX)

# Search-loop runs in a sub-process, must store count in file
echo "0" > "$IMGCOUNT"
count_image() {
    local count
    count=$(<"$IMGCOUNT")
    let 'count+=1'
    echo "$count" > "$IMGCOUNT"
}

echo "Using filter: $FILTER"
echo "Searching images for pruning candidates older than $TOO_OLD ($(date --date="$TOO_OLD" --iso-8601=date)):"
$GCLOUD compute images list --format="$FORMAT" --filter="$FILTER" | \
    while read name selfLink creationTimestamp labels
    do
        count_image
        created_ymd=$(date --date=$creationTimestamp --iso-8601=date)
        last_used=$(egrep --only-matching --max-count=1 'last-used=[[:digit:]]+' <<< $labels || true)
        markmsgpfx="Marking $name (created $created_ymd) for deletion"
        if [[ -z "$last_used" ]]
        then # image pre-dates addition of tracking labels
            echo "$markmsgpfx: Missing 'last-used' metadata, labels: '$labels'"
            echo "$name" >> $TODELETE
            continue
        fi

        last_used_timestamp=$(date --date=@$(cut -d= -f2 <<< $last_used || true) +%s || true)
        last_used_ymd=$(date --date=@$last_used_timestamp --iso-8601=date)
        if [[ -z "$last_used_timestamp" ]] || [[ "$last_used_timestamp" -ge "$THEFUTURE" ]]
        then
            echo "$markmsgpfx: Missing or invalid last-used timestamp: '$last_used_timestamp'"
            echo "$name" >> $TODELETE
            continue
        fi

        if [[ "$last_used_timestamp" -le "$THRESHOLD" ]]
        then
            echo "$markmsgpfx: Used over $TOO_OLD on $last_used_ymd"
            echo "$name" >> $TODELETE
            continue
        fi
    done

COUNT=$(<"$IMGCOUNT")
echo "########################################################################"
echo "Deleting up to $PRUNE_LIMIT images marked ($(wc -l < $TODELETE)) of all searched ($COUNT):"

# Require a minimum number of images to exist
NEED="$[$PRUNE_LIMIT*2]"
if [[ "$COUNT" -lt "$NEED" ]]
then
    die 0 Safety-net Insufficient images \($COUNT\) to process deletions \($NEED\)
    exit 0
fi

for image_name in $(sort --random-sort $TODELETE | tail -$PRUNE_LIMIT)
do
    if echo "$IMGNAMES $BASE_IMAGES" | grep -q "$image_name"
    then
        # double-verify in-use images were filtered out in search loop above
        die 8 FATAL ATTEMPT TO DELETE IN-USE IMAGE \'$image_name\' - THIS SHOULD NEVER HAPPEN
    fi
    echo "Deleting $image_name in parallel..."
    $GCLOUD compute images delete $image_name &
done

wait || true  # Nothing to delete: No background jobs