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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
#!/bin/bash
VERBOSITY=0
TEMP_D=""
TAB=$'\t'
OIFS=$IFS
TAG_NAME="reap-by"
set -f
error() { echo "$@" 1>&2; }
errorp() { printf "$@" 1>&2; }
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
failp() { [ $# -eq 0 ] || errorp "$@"; exit 1; }
Usage() {
cat <<EOF
Usage: ${0##*/} [ options ]
Reap (terminate) instances that have opted in to lifetime control
by presense of a given tag.
After launching an instance, tag it with:
$TAG_NAME=DATE
where DATE is anything valid for gnu date. Then, running this
program will reap instances that have lived past their reap-by
options:
--regions R operate only in listed regions
default (all regions in ec2-list-all-regions)
-v|--verbose increase verbosity
--dry-run only list what would be done
-t|--tag T name of tag to look for. default: ${TAG_NAME}
EOF
}
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; exit 1; }
cleanup() {
local pids
pids=$(jobs -pr)
if [ -n "$pids" ]; then
pids=$(echo $pids)
error "killing and waiting on child pids: $pids"
kill -SIGTERM $pids
wait $pids
fi
[ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
}
debugp() {
local level=${1}; shift;
[ "${level}" -gt "${VERBOSITY}" ] && return
printf "$@" 1>&2;
}
debug() {
local level=${1}; shift;
[ "${level}" -gt "${VERBOSITY}" ] && return
echo "$(date): ${@}" 1>&2
}
short_opts="hmrv"
long_opts="help,dry-run,tag-name:,regions:,verbose"
getopt_out=$(getopt --name "${0##*/}" \
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
eval set -- "${getopt_out}" ||
bad_Usage
## <<insert default variables here>>
regions=( )
max_age=""
dry_run=0
tagname=${TAG_NAME}
while [ $# -ne 0 ]; do
cur=${1}; next=${2};
case "$cur" in
-h|--help) Usage ; exit 0;;
-r|--regions) regions=( "${regions[@]}" ${next//,/ } ); shift;;
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
--dry-run) dry_run=1;;
-t|--tag-name) tagname=$next; shift;;
--) shift; break;;
esac
shift;
done
[ $# -eq 0 ] || bad_Usage "unexpected arguments: $*"
TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
fail "failed to make tempdir"
trap cleanup EXIT
my_start_time=$(date "+%s")
# program starts here
if [ "${#regions[@]}" -eq 0 ]; then
out=$(ec2-list-all-regions) || fail "failed to get list of regions"
regions=( $out )
fi
for reg in "${regions[@]}"; do
debug 2 "describe-tags --region=$reg --filter key=$tagname"
xc2 describe-tags "--region=$reg" --filter "key=$tagname" \
> "${TEMP_D}/$reg.tags" &
pids[${#pids[@]}]=$!
done
for((i=0;i<${#pids[@]};i++)); do
wait "${pids[$i]}" ||
fail "describe-instances in $reg failed"
done
# just make sure there are no empty fields (set -- doesn't respect them)
# now instead, a '.' indicates empty
for r in "${regions[@]}"; do
sed -i -e 's,\t\t,\t.\t,g' -e 's,\t\t,\t.\t,g' "$TEMP_D/$r.tags" ||
fail "failed to fix empty fields in tags from $r"
done
OFMT="%-16s %-11s %-8s %s\n"
IFS="$TAB"
for reg in "${regions[@]}"; do
#TAG i-aa7744cd instance reap-by Fri, 27 Apr 2012 13:17:14 -0400
while read label iid rtype tagname reapdate; do
[ "$rtype" = "instance" ] || continue
reap_seconds=$(date "+%s" "--date=${reapdate}") ||
fail "failed to convert $reapdate to unix seconds"
if [ "${my_start_time}" -ge "${reap_seconds}" ]; then
op="kill"
printf "%s " "$iid " >> "$TEMP_D/$reg.to-kill"
else
op="pass"
fi
printf "$OFMT" "$reg" "$iid" "$op" "$reapdate" >> "$TEMP_D/$reg.summary"
done < "$TEMP_D/$reg.tags"
done
IFS="$OIFS"
debugp 1 "$OFMT" "#region" "instance" "action" "reapdate"
for reg in "${regions[@]}"; do
if [ ! -f "$TEMP_D/$reg.summary" ]; then
debugp 2 "$OFMT" "$reg" "i-0000000" "" ""
iids=""
else
cat "$TEMP_D/$reg.summary"
printf "\n" >> "${TEMP_D}/$reg.to-kill" && read iids < "${TEMP_D}/$reg.to-kill" ||
fail "failed to read iids from file for $reg (iids=$iids)"
fi
[ -n "$iids" ] || continue
[ $dry_run -eq 0 ] || continue
xc2 terminate-instances $iids >> "${TEMP_D}/term.out" ||
fail "failed to terminate instances $iids in $region"
done
exit 0
# vi: ts=4 noexpandtab
|