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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
|
#!/bin/bash
# vi: ts=4 noexpandtab
TMPD=""
VERBOSITY=0
error() { echo "$@" 1>&2; }
errorp() { printf "$@" 1>&2; }
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
failp() { [ $# -eq 0 ] || errorp "$@"; exit 1; }
debugp() {
[ "${1}" -gt "${VERBOSITY}" ] && return
shift;
errorp "${@}"
}
Usage() {
cat <<EOF
Usage: ${0##*/} [ options ] region image-id
privatize 'image-id' from 'region' on ec2.
This will remove public access to 'image-id' in 'region', and
create a file named "<manifest>.unpublished" that contains
the date this was done.
If image-id is kernel or ramdisk, check for other references, failing
if there are any.
-f | --follow if image-id is a machine image, remove
the associated kernel and ramdisk
-n | --dry-run only report what would be done
-s | --skip-referenced if image-id is a kernel or ramdisk and is
referenced by other images, silently continue
-v | --verbose increase verbosity
Example:
${0##*/} us-east-1 ami-abcdef
EOF
}
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; }
cleanup() {
[ -n "${TMPD}" -a -d "${TMPD}" ] && rm -Rf "${TMPD}"
return 0
}
privatize() {
local oifs=${IFS};
local region="" id="" img_info="" x=""
local id_info="" manif="" acl="" itype="" kernel="" ramdisk=""
local skip=0 dry_run=0 follow=0 followed=""
local unpub_path_fmt="" unpub_path=""
local short_opts="fhnsv"
local long_opts="help,following:,follow,dry-run,skip-referenced,unpub-path-fmt:,verbose"
local getopt_out=$(getopt --name "${0##*/}" \
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
eval set -- "${getopt_out}" ||
{ bad_Usage; return 1; }
local pt; pt=( );
while [ $# -ne 0 ]; do
cur=${1}; next=${2};
case "$cur" in
--) shift; break;;
-f|--follow) follow=1; pt[${#pt[@]}]=${cur};;
--following) followed=${next}; shift;;
-h|--help) Usage; return 0;;
-n|--dry-run) dry_run=1; pt[${#pt[@]}]=${cur};;
-s|--skip-referenced) skip=1; pt[${#pt[@]}]=${cur};;
--unpub-path-fmt)
unpub_path_fmt=${next};
pt[${#pt[@]}]="--unpub-path-fmt=${next}";
shift;;
-v|--verbose)
VERBOSITY=$((${VERBOSITY}+1));;
-*) bad_Usage "confused by ${cur}"; return 1;;
esac
shift;
done
region=${1}
id=${2}
[ $# -gt 2 ] && { bad_Usage "to many arguments given"; return 1; }
[ $# -lt 2 ] && { bad_Usage "must provide region and image-id"; return 1; }
if [ -z "${TMPD}" ]; then
TMPD=$(mktemp -d ${TMPDIR:-/tmp}/${0##*/}.XXXXXX) ||
{ error "failed to make temp dir"; return 1; }
trap cleanup EXIT
fi
export XC2_XIMAGES_CACHE_D=${XC2_XIMAGES_CACHE_D:-"$TMPD/ximgcache"}
img_info=${TMPD}/img_info.txt;
xc2 ximages describe-images --all --region "${region}" > "${img_info}" ||
{ error "failed to query images with describe-images"; return 1; }
# get manifest, public/private, type, kernel,ramdisk
id_info=$(awk '-F\t' '$2 == id { print $3,$6,$9,$10,$11 }' \
"id=${id}" "OFS=|" "${img_info}" ) &&
{ IFS="|"; set -- ${id_info}; IFS=${oifs}; } ||
fail "failed to parse images info"
manif=${1}; acl=${2}; itype=${3}; kernel=${4}; ramdisk=${5};
# if its a kernel or ramdisk, check public images
if [ "${itype}" = "kernel" -o "${itype}" = "ramdisk" ]; then
local used_by=""
# have to check two things here
# a. that the image we find isn't the one that we followed here
# b. that the images that reference it are not private
local cond='( $10 == id || $11 == id ) && $6 != "private"'
[ -z "${followed}" ] || cond="${cond} && \$2 != \"${followed}\""
used_by=$(awk '-F\t' "${cond} { printf(\"\t%s %s\n\",\$2,\$3); }" \
"id=${id}" "${img_info}" ) ||
{ error "failed to parse image info for ${id}"; return 1; }
if [ -n "${used_by}" ]; then
debugp 2 "%s used by:\n%s\n" "${id}" "${used_by}"
if [ ${skip} -eq 0 ]; then
errorp "%s referenced by public images%s\n" \
"${id}" "${followed:+ [followed from ${followed}]}"
errorp "\t%s\n" " use --skip-referenced to skip"
return 1;
fi
# skip was set, just ignore
debugp 1 "skipping %s %s\n" "${id}" "${manif}"
return 0
fi
# if its a machine and follow was given, then follow
elif [ "${itype}" = "machine" ]; then
if [ ${follow} -ne 0 ]; then
for x in "${kernel}" "${ramdisk}"; do
[ -n "${x}" ] || continue;
privatize "${pt[@]}" --following=${id} "${region}" "${x}" ||
return 1;
done
fi
else
error "bad type: ${itype} for ${id} [${manif}]"
return 1
fi
# **** Note on '.unpublished' ****
# I considered changing '.unpublished' to more generic ".info"
# and having publish-image write this file to mark when it was published
# the 2 reasons I avoided doing so are:
# a.) it uses s3cmd, which presently doesn't work with eucalyptus,
# which would mean that publish-image wouldn't work with euc
# b.) I really wanted to put more info in that .info file, such as:
# - registered image ids (which are per-region, waiting on the
# relationship of bucket -> region ... ie, maybe each image in
# s3 could be registered in multiple regions
# - pedigree (ie, "testing" or "release" or "promoted to release <name>"
# or other region info (ie that this image is also found in us-west-1
# as bucket/manifest
#
# For now, using this simple .unpublished file with a date, that will
# get us the ability to unregister daily images that have been unpublished
# for a given time
#
# privatize it now
if [ -n "${unpub_path_fmt}" ]; then
unpub_path=${unpub_path_fmt//%r/${region}}
unpub_path=${unpub_path//%i/${id}}
else
unpub_path=${manif}.unpublished
fi
local info="${id}:${manif}${followed:+ followed:${followed}}"
local modout="" upf="${TMPD}/${unpub_path##*/}"
local bucket="s3://${unpub_path%/*}/"
[ ${dry_run} -ne 0 ] &&
{ error "privatize ${info}"; return 0; }
date -R > "${upf}" ||
{ error "failed to write date to ${upf}"; return 1; }
x=$(xc2 s3cmd put "${upf}" "${bucket}" 2>&1) || {
errorp "%s\n%s\n" "${x}" "failed to write unpublished file for ${info}"
return 1;
}
modout=$(xc2 modify-image-attribute --region "${region}" \
--launch-permission --remove all "${id}" ) || {
errorp "%s\n%s\n" "${modout}" "failed to remove permission ${info}";
xc2 s3cmd del "${bucket}${upf##*/}"
return 1;
}
printf "privatized %s %s %s\n" "${region}" "${id}" "${manif}"
return 0
}
privatize "${@}"
|