Skip to content

Instantly share code, notes, and snippets.

@smoser

smoser/mini-ec2-init

Created Sep 24, 2014
Embed
What would you like to do?
mini ec2 init
#!/bin/bash
set -f
NAME="mini-ec2-init"
OIFS="$IFS"
CONSOLE="/dev/console"
LOG="/var/log/${NAME}.log"
MD_URL="http://169.254.169.254/2009-04-04/"
VERBOSITY=${VERBOSITY:-0}
HAS_USERDATA=""
USER="ubuntu"
MARKER_D="/var/lib/$NAME"
MARKER=""
ERRORS=""
RERUN=${RERUN:-false}
TIMEOUT=10
CR="
"
as_def_user() {
sudo -Hu "$USER" -- "$@"
}
log() {
local now=$(date -R)
set -- "$now:" "$@"
if [ -w "$CONSOLE" ] && ! [ "$CONSOLE" -ef /dev/stdout ]; then
echo "$@" >> "$CONSOLE"
fi
[ -w "$LOG" ] && echo "$@" >> "$LOG"
echo "$@" 1>&2
}
debug() {
[ "${VERBOSITY:-0}" -ge "$1" ] || return 0;
local v="$1"
shift
log "debug[$v]:" "$@"
}
error() { log "ERROR:" "$@"; ERRORS=$(($ERRORS+1)); }
fail() { [ $# -eq 0 ] || log "FAIL:" "$@"; exit 1; }
warn() { log "WARN:" "$@"; }
caturl() {
debug 2 "getting ${1#${MD_URL}}"
curl --fail --silent --max-time "${TIMEOUT}" "$1"
}
mdget() {
local u="$1" t1="" t2="" out="" outf="$2"
case "$u" in
user-data)
has_userdata || { _RET=""; return; }
;;
public-keys|public-keys/)
out=$(caturl "$MD_URL/meta-data/${u%/}/") ||
fail "failed to get $MD_URL/meta-data/$u";
# output of public-keys is lines of 'X=keyname'
# so we return a carriage return list of the tokens before =
_RET=""
IFS="$CR"
for t1 in $out; do
t1="${t1%%=*}"
_RET="${_RET:+${_RET}${CR}}${t1%/}"
done
IFS="$OIFS"
return
;;
public-keys/*)
t1=${u#public-keys/[0-9]}
# t2 will now have 'public-keys/[0-9]'
t2=${u%${t1}}
# if t1 has a / (ie, u=public-keys/0=brickies/openssh-keys)
# then set t1 to just "/openssh-keys". if not, set it to ""
[ "${t1#*/}" = "${t1}" ] && t1="" || t1="/${t1#*/}"
u="meta-data/${t2}${t1}"
;;
_top) u="";;
*) u="meta-data/$u";;
esac
if [ -z "$outf" ]; then
_RET=$(caturl "$MD_URL/$u")
elif [ "$outf" = "-" ]; then
caturl "$MD_URL/$u"
else
caturl "$MD_URL/$u" > "$outf"
fi
[ $? -eq 0 ] ||
fail "failed to get ${MD_URL}/$u"
}
has_userdata() {
local out=""
if [ -z "$HAS_USERDATA" ]; then
mdget "_top" || return 2
HAS_USERDATA=false
case "${CR}$_RET${CR}" in
*"${CR}user-data${CR}"*) HAS_USERDATA=true;;
esac
fi
${HAS_USERDATA}
return
}
get_field_list() {
local under="$1" x="" out="" found=""
mdget "$under"
out="$_RET"
for x in $out; do
case "$x" in
*/) get_field_list "${under:+${under}/}${x}"
found="${found:+${found} }$_RET";;
*) found="${found:+${found} }${under:+$under}$x";;
esac
done
_RET="${found# }"
}
inargs() {
# inargs needle haystack
local needle="$1" hay=""
shift;
for hay in "$@"; do
[ "$needle" = "$hay" ] && return 0
done
return 1
}
cleanup() {
if [ "${ERRORS:-0}" != "0" ]; then
[ -n "$MARKER" -a -e "$MARKER" ] && {
error "cleaning $MARKER"
rm -Rf "$MARKER"
}
fi
}
errors=0
get_field_list "" || fail "failed to get fields under $MD_URL"
available=${_RET}
has_userdata && available="${available} user-data"
mdget instance-id || fail "failed to get instance-id"
instance_id="$_RET"
[ -n "$instance_id" ] || fail "instance-id is empty!"
MARKER="${MARKER_D}/${instance_id}"
if [ -e "$MARKER" ]; then
if $RERUN; then
debug 1 "re-running for $instance_id"
else
debug 1 "already ran for $instance_id"
exit 0
fi
else
debug 1 "running for $instance_id"
fi
if [ -d "$MARKER_D" ] || mkdir -p "$MARKER_D" >/dev/null 2>&1; then
MARKER="$MARKER_D/$instance_id"
msg=$(date --utc -R 2>/dev/null) || msg="sometime"
{ echo "$msg" > "$MARKER"; } >/dev/null 2>&1 || {
warn "unable to create marker $MARKER."
MARKER=""
}
else
warn "unable to create marker dir $MARKER_D"
fi
for ktype in rsa ecdsa dsa; do
f="/etc/ssh/ssh_host_${ktype}_key"
rm -f "$f" && out=$(ssh-keygen -t "$ktype" -N "" -f "$f" 2>&1) &&
log "generated ssh host key '$ktype' in $f" ||
error "Failed to generate ssh key $ktype: $out"
done
if inargs public-keys/0 ${available}; then
if mdget public-keys/0/openssh-key; then
pubkeys="$_RET"
as_def_user sh -ec '
[ -d "$HOME/.ssh" ] || mkdir "$HOME/.ssh"
umask 044
printf "%s\n" "$1" >> "$HOME/.ssh/authorized_keys"' -- \
"$pubkeys" &&
log "imported for $USER: $pubkeys" ||
error "failed to write public-keys"
else
errors=$(($errors+1));
error "failed to get public-keys"
fi
else
debug 1 "no public keys available"
fi
if has_userdata; then
if tmpf=$(mktemp 2>/dev/null); then
if ! mdget user-data "$tmpf"; then
error "failed to get user-data to temp file"
else
read line < "$tmpf"
shebang='#!'
case "$line" in
"${shebang}"*)
chmod 755 "$tmpf" && "$tmpf" &&
log "executed user-data." ||
error "executing user-data failed."
esac
fi
rm -f "$tmpf"
else
error "could not create temp file for user-data"
fi
fi
exit ${ERRORS}
# vi: ts=4 noexpandtab
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment