~patviafore/ubuntu-on-ec2/ec2-publishing-scripts-hirsute

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
158
159
160
161
162
#!/bin/bash

VERBOSITY=0
TEMP_D=""
TAB=$'\t'
OIFS=$IFS

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) running instances older than AGE

   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
    -m|--max-age     M    terminate instances older than M seconds
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,max-age:,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

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;;
		-m|--max-age)
			case "$next" in
				*h) max_age=$((${next%h}*60*60));;
				*m) max_age=$((${next%m}*60));;
				*d) max_age=$((${next%d}*60*60*24));;
				*) max_age=$next;;
			esac
			[ $? -eq 0 ] || fail "failed to convert $next to a number"
			[ "$(echo "${max_age}" | sed 's,[^0-9],,')" = "$max_age" ] ||
				fail "$next was not a number i understood"
         shift;;
		--) shift; break;;
	esac
	shift;
done

[ $# -eq 0 ] || bad_Usage "unexpected arguments: $*"

[ -n "$max_age" ] ||
	bad_Usage "must provide some reason to terminate. (--max-age?)"

TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
   fail "failed to make tempdir"
trap cleanup EXIT

my_start_time=$(date "+%s")

# program starts here
[ "${#regions[@]}" -eq 0 ] &&
	regions=( $(ec2-list-all-regions) )

for reg in "${regions[@]}"; do
	debug 2 "describe-instances --region=$reg"
	xc2 describe-instances "--region=$reg" \
		> "${TEMP_D}/$reg.instances.all" &
	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
sed -i -e 's,\t\t,\t.\t,g' -e 's,\t\t,\t.\t,g' "$TEMP_D/"*".instances.all"

OFMT="%-16s %-11s %-8s %s\n"

IFS="$TAB"
for reg in "${regions[@]}"; do
	#INSTANCE	i-9f351afc	ami-a7cc07ce	ec2-50-17-47-207.compute-1.amazonaws.com	ip-10-32-151-165.ec2.internal	running	brickies	0		m1.small	2011-11-30T21:05:06+0000	us-east-1c	aki-805ea7e9			monitoring-disabled	50.17.47.207	10.32.151.165			instance-store					paravirtual	xen		sg-134da77a	default
	while read label iid ami host_ext host_int state key_name launch_index \
		product_code size start az other; do
		[ "$label" = "INSTANCE" ] || continue
		# euca-describe-instances formats date as '2012-02-06T13:50:39.000Z'
		# ec2-describe-instances formats date as  '2012-02-06T20:30:19+0000'
		cleaned_start=$(echo "${start}" | sed 's,T, ,; s,Z,0,; s,[+.], +,')
		start_seconds=$(date --date "$cleaned_start" +"%s") ||
			fail "failed to convert $start to seconds since epoch"

		age=$(($my_start_time-$start_seconds))
      if [ "$state" = "terminated" ]; then
         op="dead"
		elif [ $max_age -lt $age ]; then
			op="kill"
			printf "%s " "$iid " >> "$TEMP_D/$reg.to-kill"
		else
			op="pass"
		fi
		printf "$OFMT" "$reg" "$iid" "$op" "$age" >> "$TEMP_D/$reg.summary"
	done < "$TEMP_D/$reg.instances.all"
done
IFS="$OIFS"

debugp 1 "$OFMT" "#region" "instance" "action" "age"
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