~josvaz/ubuntu-on-ec2/ec2-publishing-scripts-lp1613470-udev-cdrom

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 "${@}"