~ubuntu-branches/ubuntu/raring/cloud-utils/raring-201302042112

70.1.2 by Scott Moser
Import upstream version 0.24
1
#!/bin/sh
2
3
VERBOSITY=0
4
TEMP_D=""
5
NAME="ubuntu-cloudimg-query"
6
DOT_D="$HOME/.$NAME"
7
CACHE_D="$HOME/.cache/$NAME"
8
cachelife=86400
9
10
error() { echo "$@" 1>&2; }
11
errorp() { printf "$@" 1>&2; }
12
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
13
failp() { [ $# -eq 0 ] || errorp "$@"; exit 1; }
14
15
Usage() {
16
	cat <<EOF
17
Usage: ${0##*/} [ options ] criteria
18
19
   Get the latest Ubuntu ami meeting certain criteria
20
21
   options:
22
      -o | --output FILE    output to file rather than stdout
23
      -f | --format format  change output to 'format'.
24
                            default: '%{ami}\n'
25
26
   Examples:
27
   - get the latest ami matching default criteria for release 'n'
28
     $ ${0##*/} -v n
29
     us-east-1/ebs/ubuntu-natty-11.04-amd64-server-20110426
30
     ami-1aad5273
31
   - get an instance-store image in i386 image in us-west-1
32
     $ ${0##*/} lucid i386 instance us-west-1
33
     ami-73c69436
34
   - get the latest daily build of the devel release in eu-west-1
35
     $ EC2_REGION=eu-west-1 ${0##*/} daily amd64 ebs o
36
37
EOF
38
}
39
40
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; exit 1; }
41
cleanup() {
42
	[ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
43
}
44
45
cache_valid() {
46
	local file="$1" date="$2"
47
	[ -n "$file" -a -e "$file" ] || return 1
48
	touch --date "${date}" "${TEMP_D}/ts"
49
	[ "$file" -nt "$TEMP_D/ts" ]
50
}
51
52
dlcache() {
53
	local url="$1" out="$2" cfilename="$3" age="$4"
54
	local cachef="${CACHE_D}/$cfilename"
55
	local timeout="now - $age seconds"
56
	[ -n "$cfilename" ] || cachef=""
57
	if cache_valid "$cachef" "$timeout"; then
58
		cp -a "$cachef" "$out"
59
		return
60
	fi
61
	wget -q "${url}" -O "${out}" || return 1
62
	{ [ -z "$cachef" ] || cp "${out}" "${cachef}"; } ||
63
		return 1
64
}
65
66
debug() {
67
	local level=${1}; shift;
68
	[ "${level}" -gt "${VERBOSITY}" ] && return
69
	error "${@}"
70
}
71
72
isrel() {
73
	local cand="$1" url="$2" out="$3" cache="$4" age="$5"
74
	local o="" f=""
75
	for f in "$out" "$CACHE_D/$cache"; do
76
		[ -f "${f}" ] &&
77
			o=$(awk '-F\t' '$1 ~ r { print $1; exit(0); }' "r=^$cand" "$f") &&
78
			[ -n "$o" ] && _RET="$o" && return 0
79
	done
80
	dlcache "$url" "$out" "$cache" "$age" &&
81
		o=$(awk '-F\t' '$1 ~ r { print $1; exit(0); }' "r=^$cand" "$out")  &&
82
		[ -n "$o" ] && _RET="$o" && return 0
83
	return 1
84
}
85
subst() {
86
	local cur="$1"; shift;
87
	while [ $# -ne 0 ]; do
89 by Scott Moser
* Sync to upstream trunk at revision 188
88
		while [ "${cur#*${1}}" != "${cur}" ]; do
89
			cur="${cur%%${1}*}${2}${cur#*${1}}"
90
		done
70.1.2 by Scott Moser
Import upstream version 0.24
91
		shift 2
92
	done
93
	_RET=${cur}
94
}
95
in_args() {
96
	# is $1 in $2....
97
	local needle="$1" hay=""
98
	shift;
99
	for hay in "$@"; do
100
		[ "$hay" = "$needle" ] && return 0
101
	done
102
	return 1
103
}
104
105
getreleases() {
106
	# get the list of releases, return it in _RET
107
	local releases="" r=""
108
	releases="hardy karmic lucid maverick natty oneiric precise";
109
	if command -v "ubuntu-distro-info" >/dev/null; then
110
		local all_rels="" seen_lucid=false
111
		all_rels=$(ubuntu-distro-info --all) ||
112
			{ error "'ubuntu-distro-info --all' failed"; return 1; }
113
		releases="hardy"
114
		for r in $all_rels; do
115
			if $seen_lucid || [ "$r" = "lucid" ]; then
116
				seen_lucid=true;
117
				releases="${releases} $r"
118
			fi
119
		done
120
	fi
121
	_RET="$releases"
122
}
123
124
short_opts="f:ho:v"
125
long_opts="format:,help,no-cache,output:,verbose"
126
getopt_out=$(getopt --name "${0##*/}" \
127
	--options "${short_opts}" --long "${long_opts}" -- "$@") &&
128
	eval set -- "${getopt_out}" ||
129
	bad_Usage
130
131
## <<insert default variables here>>
132
output="-"
133
format='%{ami}\n'
70.1.4 by Scott Moser
Import upstream version 0.25
134
burl="${UBUNTU_CLOUDIMG_QUERY_BASEURL:-https://cloud-images.ubuntu.com/query}"
70.1.2 by Scott Moser
Import upstream version 0.24
135
store="ebs"
136
region_default="${EC2_REGION:-us-east-1}"
137
release="lucid"
138
arch="amd64"
139
stream="released"
140
bname="server"
141
itype=""
142
ptype="paravirtual"
143
poss_release=""
144
itypes=""
89 by Scott Moser
* Sync to upstream trunk at revision 188
145
itypes_i386="m1.small c1.medium m1.medium"
146
itypes_amd64="${itypes_i386} m1.large m1.xlarge m2.xlarge m2.2xlarge m2.4xlarge c1.xlarge"
70.1.2 by Scott Moser
Import upstream version 0.24
147
148
while [ $# -ne 0 ]; do
149
	cur=${1}; next=${2};
150
	case "$cur" in
151
		-h|--help) Usage ; exit 0;;
152
		-f|--format) format=${2}; shift;;
153
		-o|--output) output=${2}; shift;;
154
		-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
155
		   --no-cache) cachelife=0;;
156
		--) shift; break;;
157
	esac
158
	shift;
159
done
160
161
getreleases || fail "failed to get releases"
162
releases="${_RET}"
163
164
for i in "$@"; do
165
	in_args "$i" $releases && r_rel=$i && continue
166
	case $i in
167
		rel*) stream="released";;
168
		daily) stream=${i};;
169
		server|desktop) bname=${i};;
170
		i386|amd64|x86_64) arch=${i}; [ "${i}" = "x86_64" ] && arch="amd64";;
171
		*-*-[0-9]) region=${i};;
172
		ebs) store="$i";;
173
		instance|instance-store) store="instance-store";;
174
		hvm) ptype="hvm";;
175
		para|paravirtual) ptype="paravirtual";;
176
		c[cg][1-9].*)
177
			ptype="hvm";
178
			itype="$i";
179
			arch=amd64;;
180
		[a-z][1-9].[0-9a-z]*|c[cg][1-9].*)
181
			itype="$i";
182
			case "${i}" in
88 by Scott Moser
* cloud-publish-tarball, cloud-publish-image: be more quiet
183
				t1.micro) store=ebs;; # t1.micro only supports ebs
70.1.2 by Scott Moser
Import upstream version 0.24
184
			esac
185
			;;
186
		http://*|https://*) burl=${i};;
187
		[hklmnopqrstuvwxyz])
188
			[ -z "$p_rel" ] || fail "found 2 unknown args: $p_rel, $i";
189
			p_rel=$i;;
190
		*) fail "confused by argument: ${i}";;
191
	esac
192
done
193
194
TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
195
	fail "failed to make tempdir"
196
trap cleanup EXIT
197
198
{ [ -d "${CACHE_D}" ] || mkdir -p "${CACHE_D}"; } ||
199
	fail "failed to create ${CACHE_D}"
200
201
daily_latest="${TEMP_D}/daily.latest.txt"
202
release_latest="${TEMP_D}/released.latest.txt"
203
204
if [ -n "$p_rel" ]; then
205
	[ -z "$r_rel" ] || fail "unknown arg ${p_rel}"
206
	url="${burl}/daily.latest.txt"
207
	isrel "$p_rel" "$url" "${daily_latest}" "daily.latest.txt" $cachelife &&
208
		r_rel="${_RET}" || fail "bad input $p_rel"
209
fi
210
[ -n "$r_rel" ] && release=$r_rel
211
212
if [ -z "${region}" ]; then
213
	if [ -n "${EC2_URL}" ]; then
214
		case "${EC2_URL#*://}" in
215
			*-*-[0-9].ec2.amazonaws.com*)
216
				region=${EC2_URL#*://};
217
				region=${region%%.*};;
218
			ec2.amazonaws.com/*) region=us-east-1;;
70.1.4 by Scott Moser
Import upstream version 0.25
219
			*) region=${region_default};;
70.1.2 by Scott Moser
Import upstream version 0.24
220
		esac
221
	else
222
		region="${region_default}"
223
	fi
224
fi
225
226
ec2_curf="${TEMP_D}/${release}.${bname}.${stream}.current.txt"
227
ec2_url="${burl}/${release}/${bname}/${stream}.current.txt"
228
dl_curf="${TEMP_D}/${release}.${bname}.${stream}-dl.current.txt"
229
dl_url="${burl}/${release}/${bname}/${stream}-dl.current.txt"
230
231
dlcache "${dl_url}" "${dl_curf}" "${dl_curf##*/}" $cachelife ||
232
	fail "failed to get ${dl_url}"
233
234
out=$(awk '-F\t' \
235
	'$1 == release && $2 == bname && $5 == arch { print $4, $6, $7 }' \
236
	"release=$release" "bname=$bname" "arch=$arch" "${dl_curf}") &&
237
	[ -n "$out" ] || fail "failed find entry in ${dl_url}"
238
set -- ${out}; serial=$1; dlpath=$2; pubname=$3
239
url="${burl%/query}/${dlpath}"
240
241
prefix="${store}"
242
[ "${ptype}" = "hvm" ] && prefix="hvm"
243
dlcache "${ec2_url}" "${ec2_curf}" "${ec2_curf##*/}" $cachelife ||
244
	fail "failed to get ${ec2_url}"
245
ami=$(awk '-F\t' \
246
	'$1 == release && $2 == bname && $5 == store &&
247
	$6 == arch && $7 == region && $11 == ptype { print $8 }' \
248
	"release=$release" "bname=${bname}" \
249
	"store=$store" "arch=$arch" "region=$region" "ptype=$ptype" \
250
	"${ec2_curf}") && [ -n "$ami" ] || fail "failed to find ami"
251
252
case "$arch:$store:$ptype" in
70.1.4 by Scott Moser
Import upstream version 0.25
253
	*:hvm) itypes_all="cc1.4xlarge cg1.4xlarge cc2.8xlarge";;
89 by Scott Moser
* Sync to upstream trunk at revision 188
254
	i386:*) itypes_all="${itypes_i386}";;
255
	amd64:*) itypes_all="${itypes_amd64}";;
70.1.2 by Scott Moser
Import upstream version 0.24
256
esac
257
[ "$store" = "ebs" -a "$ptype" != "hvm" ] && itypes_all="t1.micro $itypes_all"
258
itypes=""
259
for x in ${itype} ${itypes_all}; do
260
	case ",$itypes," in
261
		*,$x,*) continue;;
262
	esac
263
	itypes="${itypes},${x}"
264
done
265
itypes=${itypes#,}
266
itype=${itypes%%,*}
267
268
xarch=${arch}
269
[ "$xarch" = "amd64" ] && xarch="x86_64"
270
271
CR="
272
"
273
TAB="	"
274
subst "$format" \
275
  '\\n' "$CR" '\\t' "$TAB" \
276
  '%{ami}' "$ami" \
277
  '%{arch}' "$arch" '%{bname}' "$bname" '%{dlpath}' "$dlpath" \
278
  '%{ptype}' "$ptype" '%{pubname}' "$pubname" '%{region}' "$region" \
279
  '%{release}' "$release" '%{store}' "$store" '%{stream}' "$stream" \
280
  '%{url}' "$url" \
281
  '%{xarch}' "$xarch" '%{itype}' "${itype}" '%{itypes}' "$itypes" \
282
  '%{summary}' "${region}/${prefix}/${pubname}"
283
284
out=${_RET}
285
[ -n "${out}" ] || fail "no ami found matching criteria"
286
287
debug 1 "${region}/${prefix}/${pubname}"
288
if [ -n "${output}" -a "${output}" != "-" ]; then
289
	echo -n "$out" > "$output"
290
else
291
	echo -n "$out"
292
fi
293
exit
294
# vi: ts=4 noexpandtab