#!/bin/bash
#
#    cloud-sandbox - put and get binary files to/from pastebin.com
#    Copyright (C) 2011 Dustin Kirkland <dustin.kirkland@gmail.com>
#
#    Authors: Dustin Kirkland <dustin.kirkland@gmail.com>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, version 3 of the License.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

PKG=cloud-sandbox
mkdir -p "$HOME/.${PKG}"
[ -r "$HOME/.${PKG}/conf" ] && . "$HOME/.${PKG}/conf"

if [ -z "$EC2_KEYPAIR" ] || ! ec2-describe-keypairs "$EC2_KEYPAIR" >/dev/null 2>&1; then
	echo "ERROR: You must define EC2_KEYPAIR to the path to your EC2 keypair pem file" 1>&2
	echo "ERROR: You can do so in your environment or in [$HOME/.${PKG}/conf]" 1>&2
	ec2-describe-keypairs
	exit 1
fi

if [ -z "$LAUNCHPAD_ID" ]; then
	echo "ERROR: You must define LAUNCHPAD_ID to your Launchpad.net user id" 1>&2
	echo "ERROR: You can do so in your environment or in [$HOME/.${PKG}/conf]" 1>&2
	exit 1
fi

if [ -z "$BOOTMAIL" ]; then
	echo "ERROR: You must define BOOTMAIL to an email address" 1>&2
	echo "ERROR: You can do so in your environment or in [$HOME/.${PKG}/conf]" 1>&2
	exit 1
fi

if [ -z "$EC2_KEYPAIR_FILE" ]; then
	#backsupport for default keypair file
	EC2_KEYPAIR_FILE=$HOME/.ssh/ec2-keypair.pem
fi

EC2_KNOWN_HOSTS="$HOME/.ssh/known_hosts.cloud"
SSH_CMD="ssh -o UserKnownHostsFile=$EC2_KNOWN_HOSTS -i $EC2_KEYPAIR_FILE"

generate_ssh_host_keys() {
	local d="$1"
	local f=$(mktemp /tmp/cloud-user-data.XXXXXXXXXX)
	printf "#cloud-config\nssh_keys:\n" >> "$f"
	for i in rsa dsa; do
		ssh-keygen -q -f "${d}/ssh_host_${i}_key" -t ${i} -N ""
		printf "  ${i}_private: |\n" >> "$f"
		sed "s/^/      /" "${d}/ssh_host_${i}_key" >> "$f"
		echo >> "$f"
		printf "  ${i}_public: " >> "$f"
		cat "${d}/ssh_host_${i}_key.pub" >> "$f"
		echo >> "$f"
	done
	_RET="$f"
}

add_known_hosts_entries() {
	local i
	local h="$1"
	local ip="$2"
	local d="$3"
	for i in rsa dsa; do
		printf "%s,%s %s %s\n" "$h" "$ip" $(awk '{print $1 " " $2}' "$d/ssh_host_${i}_key.pub") >> "$EC2_KNOWN_HOSTS"
	done
	#ssh-keygen -q -H -f "$EC2_KNOWN_HOSTS"
}

# Debugging, if I want to see what's going on
#set -x

# Optionally support release/size parameters
size="$1"
release="$2"

# Default to t1.micro/latest
[ -z "$size" ] && size="t1.micro"
if [ -z "$release" ]; then
	command -v ubuntu-distro-info >/dev/null 2>&1 || { echo "FAIL: no ubuntu-distro-info."; exit 1; }
	release=$(ubuntu-distro-info --devel 2>/dev/null)
	if [ $? -ne 0 ]; then
		echo "WARN: 'ubuntu-distro-info --devel' failed."
		release=$(ubuntu-distro-info --all | tail -n 1) ||
		{ echo "FAIL: failed to get latest distro"; exit 1; }
	fi
fi
echo "release=$release"

# Generate the user-data file, and a first set of keys
d=$(mktemp -d /tmp/cloud.XXXXXXXXXX)
generate_ssh_host_keys "$d"
f="$_RET"

echo "
output: {all: '| tee -a /var/log/cloud-init-output.log'}
" >> $f

# Add Byobu
echo "
byobu_by_default: system
" >> $f

# SSH Import ID
if [ -n "$LAUNCHPAD_ID" ]; then
	echo "
ssh_import_id: [$LAUNCHPAD_ID]
" >> $f
fi

# Add bootmail
if [ -n "$BOOTMAIL" ]; then
	echo "
debconf_selections: |
    debconf bootmail/recipients string $BOOTMAIL

packages:
    bootmail

runcmd:
    - sudo bootmail
" >> $f
fi

# Write random seed
SEED="$(head -c 512 /dev/urandom | base64 -w 0)"
echo "
write_files:
-   encoding: b64
    content: $SEED
    owner: root:root
    path: /dev/urandom
    perms: '0666'
" >> $f

# Get the run command from the uec-images page
cmd="ubuntu-ec2-run -t $size --key $EC2_KEYPAIR --user-data-file $f $release"
id=$($cmd | grep "^INSTANCE" | awk '{print $2}')
rm -f "$f"

if [ -z "$id" ]; then
	echo "ERROR: No instance id" 1>&2
	exit 53
fi

# Loop until this instance is running
while ! (ec2-describe-instances $id | grep -qs running); do
	sleep 5
done

# Now that it's running, get the hostname and ip
str=$(ec2-describe-instances $id | grep "^INSTANCE.*running")
h=$(echo "$str" | awk '{print $4}')
ip=$(echo "$str" | awk '{print $14}')
privip=$(echo "$str" | awk '{print $15}')

# Create --tag Name, sets the instance name
# Create --tag Created, sets a timestamp in a tag
created=$(date)
ec2-create-tags "$id" --tag Name="$LAUNCHPAD_ID" --tag Created="$created" --tag LaunchedBy="$PKG"

# Add the known_hosts entry
add_known_hosts_entries "$h" "$ip" "$d"
add_known_hosts_entries "$h" "$privip" "$d"

# Generate a second (secure) set of keys, since the first set was stored in EC2 metadata.
# Not a big deal, but local users would have had access to the private key.
d=$(mktemp -d /tmp/cloud.XXXXXXXXXX)
generate_ssh_host_keys "$d"
f="$_RET"

# Wait for SSH to come up
while ! $SSH_CMD ubuntu@$h true; do
	sleep 1
	true
done

# Securely install second set of keys to /etc/ssh
#tar -C "$d" -cf - . | $SSH_CMD ubuntu@$h "sudo tar -C /etc/ssh -xf -; sudo service ssh restart"
tar -C "$d" -cf - . | $SSH_CMD ubuntu@$h "sudo tar -C /etc/ssh -xf -"
ssh-keygen -q -f "$EC2_KNOWN_HOSTS" -R "$h"
ssh-keygen -q -f "$EC2_KNOWN_HOSTS" -R "$ip"
ssh-keygen -q -f "$EC2_KNOWN_HOSTS" -R "$privip"
add_known_hosts_entries "$h" "$ip" "$d"
add_known_hosts_entries "$h" "$privip" "$d"
rm -rf $d

# Now ssh in!
while ! $SSH_CMD ubuntu@$h; do
	true
done

# Clean up?
echo -n "Do you want to terminate this instance now? [y/N]: "
answer=$(head -n1)
case "$answer" in
	y|Y)
		ec2-terminate-instances $id
		ssh-keygen -f $EC2_KNOWN_HOSTS -R $h
		ssh-keygen -f $EC2_KNOWN_HOSTS -R $ip
		ssh-keygen -f $EC2_KNOWN_HOSTS -R $privip
		rm -f "$EC2_KNOWN_HOSTS".old
	;;
	*)
		echo "# Remember to clean up!"
		echo "    ec2-terminate-instances $id"
		echo "    ssh-keygen -f $EC2_KNOWN_HOSTS -R $h"
		echo "    ssh-keygen -f $EC2_KNOWN_HOSTS -R $ip"
		echo "    ssh-keygen -f $EC2_KNOWN_HOSTS -R $privip"
	;;
esac
