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
|