You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

454 lines
15 KiB

#!/bin/bash
export EC2_HOME="/usr/share/ec2/ec2-api-tools"
export JAVA_HOME="$(dirname $(dirname $(readlink /etc/alternatives/java)))"
export PATH="$PATH:${EC2_HOME}/bin"
export TZ="UTC"
# defaults
[ -n "$KEY_NAME" ] || KEY_NAME="jenkins-ngcp-create-ami"
[ -n "$KEY_FILE" ] || KEY_FILE="${HOME}/.ssh/${KEY_NAME}.pem"
[ -n "$SECURITY_GROUP" ] || SECURITY_GROUP="sipwise-only"
[ -n "$TAG_PURPOSE" ] || TAG_PURPOSE="ngcp-create-ce-ami"
DATE_STRING=$(date +%Y-%m-%d_%H:%M)
# retrieve AWS_* environment variables
if [ -r "$HOME/.ec2-create-ngcp" ] ; then
source "$HOME/.ec2-create-ngcp"
fi
rm -f ec2_report.txt
usage() {
echo "$0 - script to generate EC2 AMI for sip:provider ngcp CE
Usage:
$0 [OPTIONS]
Supported OPTIONS:
--ami-name <STRING> set AMI name to specified string
(if unset defaults to ngcp-ce-\$release)
--base-ami <AMI-ID> AMI ID that should be used as base for running
ngcp installation process (recommended: Debian 64bit)
(if unset defaults to ami-9ef001e9)
--elastic-ip <IP> associate started instance ID with provided Elastic IP address
--help display this help text
--instance-type <TYPE> EC2 instance type that should be used for launching
(if unset defaults to m1.medium)
--keep-ami-snapshot do not remove snapshot used by a possibly existing AMI
which gets removed during the run (because of identical names)
(only considered in combination with --remove-existing-ami)
--ngcp-release <VERSION> sip:provider release version
(if unset defaults to <latest>)
--public Make AMI available to the public
(if unset defaults to private)
--remove-existing-ami If an AMI with the according name already exists get
rid of it before trying to creating the AMI
--region <REGION> specify region that should be used
(if unset defaults to the eu-west-1 zone)
--skip-reboot do not reboot ngcp system after installation finished
"
}
CMDLINE_OPTS=ami-name:,base-ami:,elastic-ip:,help,instance-type:,keep-ami-snapshot,ngcp-release:,public,region:,remove-existing-ami,skip-reboot
_opt_temp=$(getopt --name $0 -o +bch --long $CMDLINE_OPTS -- "$@")
if [ $? -ne 0 ]; then
echo "Try '$0 --help' for more information." >& 2
exit 1
fi
eval set -- "$_opt_temp"
_opt_keep_ami_snapshot=false
_opt_public=false
_opt_remove_existing_ami=false
_opt_skip_reboot=false
while :; do
case "$1" in
--ami-name)
shift; AMI_NAME="$1"
;;
--base-ami)
shift; BASE_AMI="$1"
;;
--elastic-ip)
shift; ELASTIC_IP="$1"
;;
--help)
usage ; exit 0;
;;
--instance-type)
shift; INSTANCE_TYPE="$1"
;;
--keep-ami-snapshot)
_opt_keep_ami_snapshot=true
;;
--ngcp-release)
shift; NGCP_RELEASE="$1"
;;
--public)
_opt_public=true
;;
--region)
shift; AWS_REGION="$1"
;;
--remove-existing-ami)
_opt_remove_existing_ami=true
;;
--skip-reboot)
_opt_skip_reboot=true
;;
--)
shift; break
;;
*)
echo "Internal getopt error! $1" >&2
exit 1
;;
esac
shift
done
# if unset set sane defaults
[ -n "$AWS_REGION" ] || AWS_REGION="eu-west-1"
[ -n "$BASE_AMI" ] || BASE_AMI="ami-9ef001e9"
[ -n "$INSTANCE_TYPE" ] || INSTANCE_TYPE="m1.medium"
if [ -z "$AWS_ACCESS_KEY" ] ; then
echo "AWS_ACCESS_KEY is unset, can not continue." >&2
exit 1
fi
if [ -z "$AWS_SECRET_KEY" ] ; then
echo "AWS_SECRET_KEY is unset, can not continue." >&2
exit 1
fi
if ! [ -r "$KEY_FILE" ] ; then
echo "Could not read key file ${KEY_FILE}, can not continue." >&2
exit 1
fi
check4progs(){
local RC=''
for arg in $* ; do
which $arg >/dev/null 2>&1 || RC="$arg"
done
if [ -n "$RC" ] ; then
echo "$RC not found/executable" >&2
return 1
fi
}
if ! check4progs ec2-run-instances || ! check4progs ec2-create-image || ! check4progs ec2-describe-instances ; then
echo "Required tools not found, forgot to install ec2-api-tools?" >&2
exit 1
fi
if [ -z "$NGCP_RELEASE" ] ; then
NGCP_RELEASE="latest"
echo "No ngcp release set, defaulting to ${NGCP_RELEASE}"
fi
if ! wget --quiet -O /tmp/ngcp-installer.deb "http://deb.sipwise.com/spce/ngcp-installer-${NGCP_RELEASE}.deb" ; then
echo "Couldn't retrieve http://deb.sipwise.com/spce/ngcp-installer-${NGCP_RELEASE}.deb - exiting" >&2
exit 1
fi
if dpkg --info /tmp/ngcp-installer.deb | grep -q 'mr' ; then
NGCP_VERSION=$(dpkg --info /tmp/ngcp-installer.deb | awk '/^ Version: / {print $2}' | sed 's/.*mr/mr/')
else # older versions don't have the mr string in the version information, so let's reuse provided ngcp release
NGCP_VERSION="$NGCP_RELEASE"
echo "*** No 'mr' string inside version information of installer found... ***"
echo "*** ... falling back to ngcp release version information [${NGCP_VERSION}] ***"
fi
if [ -z "$NGCP_VERSION" ] ; then
echo "Couldn't identify ngcp version, exiting." >&2
exit 1
fi
# if AMI_NAME is set to "none" then we get defaults from Jenkins, if
# so then use the ngcp-ce-... naming schema
if [ -n "$AMI_NAME" ] && [ "$AMI_NAME" != "none" ] ; then
echo "*** AMI_NAME is set to $AMI_NAME ***"
else
# use just "ngcp-ce-mr3.3.1.0" if we get something like
# "ngcp-ce-mr3.3.1.0+0~20140528091259.443+wheezy~1.gbpf74599"
# as NGCP_VERSION
AMI_NAME="ngcp-ce-${NGCP_VERSION%%\+*}"
echo "*** AMI_NAME is unset yet, defaulting to $AMI_NAME"
case "$AMI_NAME" in
ngcp-ce-mr*.*.*.*)
echo "*** Identified hotfix version string in AMI name [${AMI_NAME}]... ***"
AMI_NAME="${AMI_NAME%.*}"
echo "*** ... stripping AMI name to use ${AMI_NAME} instead ***"
;;
esac
fi
AMI_DESCRIPTION="Official sip:provider CE AMI for release ${NGCP_VERSION} [${DATE_STRING}]"
USER_DATA_FILE="$(mktemp)"
cat > "$USER_DATA_FILE" << EOF
#!/bin/bash
wget -O /tmp/ngcp-installer.deb http://deb.sipwise.com/spce/ngcp-installer-${NGCP_RELEASE}.deb
dpkg -i /tmp/ngcp-installer.deb
echo y | ngcp-installer 2>&1 | tee -a /var/log/ngcp-installer-debug.log
cp /tmp/ngcp-installer.log /var/log/ngcp-installer.log
EOF
LOGFILE_RUN="$(mktemp)"
ec2-run-instances --region "$AWS_REGION" \
--user-data-file "$USER_DATA_FILE" \
--group "$SECURITY_GROUP" \
--key "$KEY_NAME" \
--instance-type "$INSTANCE_TYPE" \
"$BASE_AMI" >"$LOGFILE_RUN"
INSTANCE_ID="$(awk '/INSTANCE/ {print $2}' "$LOGFILE_RUN")"
if [ -z "$INSTANCE_ID" ] ; then
echo "Could not identify instance ID, exiting." >&2
exit 1
fi
# assign tag so we de-register again the AMI if needed
ec2-create-tags --region "$AWS_REGION" "$INSTANCE_ID" --tag Purpose="$TAG_PURPOSE"
# assign name (useful for web management console browsing)
ec2-create-tags --region "$AWS_REGION" "$INSTANCE_ID" --tag Name="${AMI_NAME}/${DATE_STRING}/${JOB_NAME}/build_${BUILD_NUMBER}"
# assign elastic IP address to instance,
# enabling us to enable access to restricted
# webserver areas
if [ -n "$ELASTIC_IP" ] ; then
echo "Associating elastic IP $ELASTIC_IP with instance ID $INSTANCE_ID"
ec2-associate-address --region "${AWS_REGION}" "${ELASTIC_IP}" -i "${INSTANCE_ID}"
fi
STATUS="$(ec2-describe-instances --region ${AWS_REGION} --filter instance-id=$INSTANCE_ID | awk '/INSTANCE/ {print $6}')"
echo "Starting instance ID $INSTANCE_ID for ngcp version $NGCP_VERSION"
retry=120 # up to 10 minutes
while [ "$STATUS" != "running" ] && [ $retry -ne 0 ] ; do
STATUS="$(ec2-describe-instances --region ${AWS_REGION} --filter instance-id=$INSTANCE_ID | awk '/INSTANCE/ {print $6}')"
echo "Instance ID $INSTANCE_ID not running yet, checking again in 5 seconds ($retry retries left)."
sleep 5
retry=$(($retry - 1))
done
if [ "$STATUS" != "running" ] ; then
echo "No further retries left and couldn't bring up system for AMI $BASE_AMI, giving up." >&2
exit 1
fi
HOSTNAME="$(ec2-describe-instances --region ${AWS_REGION} --filter instance-id=$INSTANCE_ID | awk '/INSTANCE/ {print $4}')"
retry=360 # up to 30 minutes
FINISHED_NGCP_CE_INSTALLATION=false
while [ "$FINISHED_NGCP_CE_INSTALLATION" != "true" ] && [ $retry -ne 0 ] ; do
ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -i "${KEY_FILE}" "admin@$HOSTNAME" \
"grep -q 'Installation finished. Thanks for choosing NGCP' /var/log/ngcp-installer-debug.log"
RC=$?
if [ $RC -eq 0 ] ; then
FINISHED_NGCP_CE_INSTALLATION=true
else
echo "ngcp installation not yet finished, checking again in 5 seconds ($retry retries left)."
sleep 5
retry=$(($retry - 1))
fi
done
echo "Trying to retrieve ngcp-installer log files"
scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -i "${KEY_FILE}" "admin@$HOSTNAME":/var/log/ngcp-installer\*log ./ || true
if [ "$FINISHED_NGCP_CE_INSTALLATION" = "true" ] ; then
echo "Successfully finished ngcp CE installation (version ${NGCP_VERSION})."
else
echo "No further retries left and couldn't finish ngcp CE installation (version ${NGCP_VERSION}), giving up." >&2
exit 1
fi
# reboot CE system
if $_opt_skip_reboot ; then
echo "*** Skipping system reboot of instance ID ${INSTANCE_ID} as requested via --skip-reboot ***"
else
ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -i "${KEY_FILE}" "admin@$HOSTNAME" "sudo reboot"
retry=120 # up to 10 minutes
STATUS=""
while [ "$STATUS" != "running" ] && [ $retry -ne 0 ] ; do
STATUS="$(ec2-describe-instances --region ${AWS_REGION} --filter instance-id=$INSTANCE_ID | awk '/^INSTANCE/ {print $6}')"
echo "Instance ID not yet running (status: ${STATUS}), checking again in 5 seconds ($retry retries left)."
sleep 5
retry=$(($retry - 1))
done
if [ "$STATUS" != "running" ] ; then
echo "No further retries left and couldn't finish reboot of instance ID ${INSTANCE_ID}, giving up." >&2
exit 1
fi
# we probably have a new hostname after reboot
HOSTNAME="$(ec2-describe-instances --region ${AWS_REGION} --filter instance-id=$INSTANCE_ID | awk '/INSTANCE/ {print $4}')"
# now check for available ssh connection and nginx listening on port 1443
retry=120 # up to 10 minutes
STATUS=""
while [ "$STATUS" != "ok" ] && [ $retry -ne 0 ] ; do
ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -i "${KEY_FILE}" "admin@$HOSTNAME" "sudo lsof -i -n -P | grep -q '*:1443 '"
if [ $? -eq 0 ] ; then
STATUS=ok
else
echo "Host $HOSTNAME can't be reached via ssh login yet, checking again in 5 seconds ($retry retries left)."
sleep 5
retry=$(($retry - 1))
fi
done
fi
if ec2-describe-images --region "$AWS_REGION" --filter "name=${AMI_NAME}" | grep -q . ; then
echo "*** Warning, AMI with name ${AMI_NAME} exists already."
if $_opt_remove_existing_ami ; then
EXISTING_AMI_ID=$(ec2-describe-images --region "$AWS_REGION" --filter "name=${AMI_NAME}" | awk '/IMAGE/ {print $2}')
if [ -z "$EXISTING_AMI_ID" ] ; then
echo "Problem retrieving AMI ID for AMI with name ${AMI_NAME}, exiting." >&2
exit 1
fi
# we need to identify which snapshot is used by the AMI so we can remove it after "deregister"-ing the AMI
AMI_SNAPSHOT=$(ec2-describe-images --region "$AWS_REGION" --filter "name=${AMI_NAME}" | awk '/^BLOCKDEVICEMAPPING.*EBS/ {print $4}')
if [ -z "$AMI_SNAPSHOT" ] ; then
echo "Problem retrieving snapshot ID for AMI with name ${AMI_NAME}, exiting." >&2
exit 1
fi
echo "*** Option --remove-existing-ami is set, removing existing AMI with ID ${EXISTING_AMI_ID} ***"
ec2-deregister --region "$AWS_REGION" "${EXISTING_AMI_ID}"
if [ $? -ne 0 ] ; then
echo "Noticed problem when trying to delete AMI with name ${AMI_NAME}." >&2
exit 1
fi
if $_opt_keep_ami_snapshot ; then
echo "*** Option --keep-ami-snapshot is set, not removing AMI snapshot ${AMI_SNAPSHOT}. ***"
else
ec2-delete-snapshot --region "$AWS_REGION" "${AMI_SNAPSHOT}"
if [ $? -ne 0 ] ; then
echo "Noticed problem when trying to delete snapshot ${AMI_SNAPSHOT} for 'deregister'-ed AMI with name ${AMI_NAME}." >&2
exit 1
fi
fi
fi
fi
echo "*** Getting rid of all authorized_keys files. ***"
ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -i "${KEY_FILE}" "admin@$HOSTNAME" \
'sudo find / -name authorized_keys -exec rm -f {} \;'
LOGFILE_AMI=$(mktemp)
ec2-create-image --region "$AWS_REGION" \
--name "$AMI_NAME" \
--description "$AMI_DESCRIPTION" \
"$INSTANCE_ID" >"$LOGFILE_AMI"
AMI_ID="$(awk '/^IMAGE/ {print $2}' $LOGFILE_AMI)"
retry=120 # up to 10 minutes
STATUS=""
while [ "$STATUS" != "available" ] && [ $retry -ne 0 ] ; do
STATUS="$(ec2-describe-images --region ${AWS_REGION} "$AMI_ID" | awk '/^IMAGE/ {print $5}')"
if [ "$STATUS" = "failed" ] ; then
echo "Fatal error while creating AMI ID $AMI_ID (status: ${STATUS}), exiting." >&2
exit 1
fi
echo "AMI ID $AMI_ID not yet finished (status: ${STATUS}), checking again in 5 seconds ($retry retries left)."
sleep 5
retry=$(($retry - 1))
done
if [ "$STATUS" != "available" ] ; then
echo "No further retries left and couldn't finish creation of AMI ID ${AMI_ID} for instance ID ${INSTANCE_ID}, giving up." >&2
exit 1
fi
if [ -n "$AMI_ID" ] ; then
echo "Successfully created AMI with ID $AMI_ID"
else
echo "Error creating AMI :(" >&2
cat "$LOGFILE_AMI" >&2
exit 1
fi
if $_opt_public ; then
echo "Marking AMI as public"
ec2-modify-image-attribute --region "$AWS_REGION" "$AMI_ID" --launch-permission -a all
if [ $? -ne 0 ] ; then
echo "Noticed problem when trying to mark AMI with ID $AMI_ID as public." >&2
exit 1
fi
fi
echo "*** Debugging information ***"
echo "--- user-data-file ---"
cat "$USER_DATA_FILE"
echo "--- log file for instance run ---"
cat "$LOGFILE_RUN"
echo "--- log file for AMI creation ---"
cat "$LOGFILE_AMI"
echo "*** End of Debugging information ***"
echo
echo "*** Status report for AMI ***
AWS region: $AWS_REGION
AMI ID: $AMI_ID
AMI name: $AMI_NAME
AMI description: $AMI_DESCRIPTION
AMI public: $_opt_public
Instance type: $INSTANCE_TYPE
NGCP version: $NGCP_VERSION
*** End of Status report ***"
# Jenkins setup specific
TESTHOST="$HOSTNAME"
case "$NGCP_RELEASE" in
latest)
VMVERSION="trunk"
;;
*)
VMVERSION="${NGCP_RELEASE}"
;;
esac
# generate report for usage in other scripts
cat > ec2_report.txt << EOF
instance_hostname=$HOSTNAME
instance_id=$INSTANCE_ID
aws_region=$AWS_REGION
ami_id=$AMI_ID
ami_name=$AMI_NAME
ami_description=$AMI_DESCRIPTION
ami_public=$_opt_public
ami_instance_type=$INSTANCE_TYPE
ngcp_version=$NGCP_VERSION
# for usage in Jenkins
testhost=$TESTHOST
vmversion=$VMVERSION
EOF
rm -f "$USER_DATA_FILE" "$LOGFILE_RUN" "$LOGFILE_AMI"