diff --git a/ec2-create-ce b/ec2-create-ce index 6f47497..aa1616f 100755 --- a/ec2-create-ce +++ b/ec2-create-ce @@ -1,22 +1,14 @@ #!/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" +[ -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() { @@ -67,19 +59,19 @@ Mandatory options for VPC usage: # generate report for usage in other scripts/jenkins jobs generate_ec2_report() { 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 +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 +testhost=${TESTHOST} +vmversion=${VMVERSION} EOF } @@ -91,13 +83,14 @@ bailout() { # to Jenkins downstream job ec2-ami-stop generate_ec2_report - exit "$EXIT" + exit "${EXIT}" } -trap bailout 1 2 3 3 6 9 14 15 +trap bailout 1 2 3 3 6 14 15 # NOTE: this is non-blocking currently, so we're not waiting until everything is finished here copy_ami() { - local logfile=$(mktemp) + local logfile + logfile=$(mktemp) local source_region="$1" local ami_id="$2" @@ -105,33 +98,55 @@ copy_ami() { local ami_description="$4" local target_region - for target_region in us-east-1 us-west-2 us-west-1 eu-central-1 eu-west-1 ap-southeast-1 ap-southeast-2 ap-northeast-1 sa-east-1 ; do - case "$target_region" in - "$source_region") - echo "*** Skipping region $target_region as source and destination region are the same ones. ***" - echo "AMI ID for region ${target_region}: ${ami_id}" >> ec2_report_amis.txt - ;; + for target_region in \ + ap-northeast-1 \ + ap-southeast-1 \ + ap-southeast-2 \ + eu-central-1 \ + eu-west-1 \ + sa-east-1 \ + us-east-1 \ + us-west-1 \ + us-west-2 + ## currently unused ones: + # ap-east-1 \ + # ap-northeast-2 \ + # ap-south-1 \ + # ca-central-1 \ + # eu-north-1 \ + # eu-west-2 \ + # eu-west-3 \ + # me-south-1 \ + # us-east-2 \ + do + case "${target_region}" in + "${source_region}") + echo "*** Skipping region ${target_region} as source and destination region are the same ones. ***" + echo "AMI ID for region ${target_region}: ${ami_id}" >> ec2_report_amis.txt + ;; *) - remove_ami "$target_region" "$ami_name" - - echo "*** Copying AMI ID $ami_id from $source_region to $target_region (note: we are NOT blocking/waiting until this is fully finished!) ***" - ec2-copy-image --source-region "${source_region}" --region "${target_region}" --source-ami-id "$ami_id" -n "$ami_name" -d "$ami_description" > "$logfile" - if [ $? -ne 0 ]; then - echo "Error copying AMI ID $ami_id from $source_region to $target_region" >&2 - return 1 - fi + remove_ami "${target_region}" "${ami_name}" - local ami_id_copy="$(awk '/^IMAGE/ {print $2}' "$logfile")" + echo "*** Copying AMI ID ${ami_id} from ${source_region} to ${target_region} (note: we are NOT blocking/waiting until this is fully finished!) ***" + aws ec2 copy-image --source-image-id "${ami_id}" --source-region "${source_region}" --region "${target_region}" --name "${ami_name}" --description "${ami_description}" > "${logfile}" - if [ -z "$ami_id_copy" ] ; then - echo "Error retrieving AMI ID $ami_id for region ${target_region}:" - cat "$logfile" >&2 - return 1 - fi - - # for usage as global report - echo "AMI ID for region ${target_region}: $ami_id_copy" >> ec2_report_amis.txt - ;; + if [ $? -ne 0 ]; then + echo "Error copying AMI ID ${ami_id} from ${source_region} to ${target_region}" >&2 + return 1 + fi + + local ami_id_copy + ami_id_copy="$(jq -r '.ImageId' "${logfile}")" + + if [ -z "${ami_id_copy}" ] ; then + echo "Error retrieving AMI ID ${ami_id} for region ${target_region}:" + cat "${logfile}" >&2 + return 1 + fi + + # for usage as global report + echo "AMI ID for region ${target_region}: ${ami_id_copy}" >> ec2_report_amis.txt + ;; esac done } @@ -140,40 +155,43 @@ remove_ami() { local aws_region="$1" local ami_name="$2" - if ! ec2-describe-images --region "$aws_region" --filter "name=${ami_name}" | grep -q . ; then + if ! aws ec2 describe-images --region "${aws_region}" --filter "Name=name,Values=${ami_name}" | jq -r '.Images[].ImageId' | grep -q . ; then return 0 # no AMIs with given name present fi echo "*** Warning, AMI with name ${ami_name} exists already." - if ! $_opt_remove_existing_ami ; then + if ! ${_opt_remove_existing_ami} ; then return 0 fi - local existing_ami_id=$(ec2-describe-images --region "$aws_region" --filter "name=${ami_name}" | awk '/IMAGE/ {print $2}') + local existing_ami_id + existing_ami_id=$(aws ec2 describe-images --region "${aws_region}" --filter "Name=name,Values=${ami_name}" | jq -r '.Images[].ImageId') - if [ -z "$existing_ami_id" ] ; then + if [ -z "${existing_ami_id}" ] ; then echo "Problem retrieving AMI ID for AMI with name ${ami_name}." >&2 return 1 fi # we need to identify which snapshot is used by the AMI so we can remove it after "deregister"-ing the AMI - local ami_snapshot=$(ec2-describe-images --region "$aws_region" --filter "name=${ami_name}" | awk '/^BLOCKDEVICEMAPPING.*EBS/ {print $4}') - if [ -z "$ami_snapshot" ] ; then + local ami_snapshot + ami_snapshot=$(aws ec2 describe-images --region "${aws_region}" --filter "Name=name,Values=${ami_name}" | jq -r '.Images[].BlockDeviceMappings[].Ebs.SnapshotId') + + if [ -z "${ami_snapshot}" ] ; then echo "Problem retrieving snapshot ID for AMI with name ${ami_name}." >&2 return 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}" + aws ec2 deregister-image --region "${aws_region}" --image-id "${existing_ami_id}" if [ $? -ne 0 ] ; then echo "Noticed problem when trying to delete AMI with name ${ami_name}." >&2 return 1 fi - if $_opt_keep_ami_snapshot ; then + 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}" + aws ec2 delete-snapshot --region "${aws_region}" --snapshot-id "${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 return 1 @@ -183,12 +201,12 @@ remove_ami() { CMDLINE_OPTS=allocation-id:,ami-name:,base-ami:,copy-to-all-regions,elastic-ip:,help,installer-url:,instance-type:,keep-ami-snapshot,ngcp-release:,public,region:,remove-existing-ami,subnet:,skip-reboot -_opt_temp=$(getopt --name "$0" -o +bch --long $CMDLINE_OPTS -- "$@") +_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" +eval set -- "${_opt_temp}" _opt_keep_ami_snapshot=false _opt_public=false @@ -199,7 +217,7 @@ _opt_copy_to_all_regions=false while :; do case "$1" in --allocation-id) - shift; ALLOCATION_ID="$1" # TODO eipalloc-0a96e07d4355e12fb + shift; ALLOCATION_ID="$1" ;; --ami-name) shift; AMI_NAME="$1" @@ -255,21 +273,16 @@ while :; do done # if unset set sane defaults -[ -n "$AWS_REGION" ] || AWS_REGION="eu-west-1" -[ -n "$BASE_AMI" ] || BASE_AMI="ami-8a745cf3" -[ -n "$INSTANCE_TYPE" ] || INSTANCE_TYPE="t2.medium" - -if [ -z "$AWS_ACCESS_KEY" ] ; then - echo "AWS_ACCESS_KEY is unset, can not continue." >&2 - exit 1 -fi +[ -n "${AWS_REGION}" ] || AWS_REGION="eu-west-1" +[ -n "${BASE_AMI}" ] || BASE_AMI="ami-0e9cc061cd3259f22" +[ -n "${INSTANCE_TYPE}" ] || INSTANCE_TYPE="m5.large" -if [ -z "$AWS_SECRET_KEY" ] ; then - echo "AWS_SECRET_KEY is unset, can not continue." >&2 +if ! [ -r "${HOME}"/.aws/config ] ; then + echo "awscli seems to be unconfigured, ensure ${HOME}/.aws/config exists." >&2 exit 1 fi -if ! [ -r "$KEY_FILE" ] ; then +if ! [ -r "${KEY_FILE}" ] ; then echo "Could not read key file ${KEY_FILE}, can not continue." >&2 exit 1 fi @@ -277,20 +290,25 @@ fi check4progs(){ local RC='' for arg in "$@" ; do - which "$arg" >/dev/null 2>&1 || RC="$arg" + which "${arg}" >/dev/null 2>&1 || RC="${arg}" done - if [ -n "$RC" ] ; then - echo "$RC not found/executable" >&2 + 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 +if ! check4progs jq ; then + echo "Required tool jq not found, forgot to install jq?" >&2 + exit 1 +fi + +if ! check4progs aws ; then + echo "Required tool aws not found, forgot to install awscli?" >&2 exit 1 fi -if [ -z "$NGCP_RELEASE" ] ; then +if [ -z "${NGCP_RELEASE}" ] ; then NGCP_RELEASE="latest" echo "No ngcp release set, defaulting to ${NGCP_RELEASE}" fi @@ -307,23 +325,24 @@ 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" + 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 +if [ -z "${NGCP_VERSION}" ] ; then echo "Couldn't identify ngcp version, exiting." >&2 bailout 1 fi # ensure we don't have any builds running already, see TT#30565 -NUM_RUNNING_INSTANCES=$(ec2-describe-instances --region "${AWS_REGION}" \ - --filter "instance-state-name=running" \ - --filter "tag:Purpose=${TAG_PURPOSE}" 2>/dev/null | \ - grep -c '^INSTANCE') -if [ "$NUM_RUNNING_INSTANCES" -gt 0 ] ; then - echo "Error: there are running instances with tag $TAG_PURPOSE in region $AWS_REGION" >&2 +NUM_RUNNING_INSTANCES=$(aws ec2 describe-instances --region "${AWS_REGION}" \ + --filter "Name=instance-state-name,Values=running" \ + "Name=tag:Purpose,Values=${TAG_PURPOSE}" | \ + jq '.Reservations[].Instances[].InstanceId' | \ + wc -l) +if [ "${NUM_RUNNING_INSTANCES}" -gt 0 ] ; then + echo "Error: there are running instances with tag ${TAG_PURPOSE} in region ${AWS_REGION}" >&2 echo "Exiting to ensure we don't have instances running due to Jenkins job failures." >&2 echo "Please ensure that those instances are stopped before trying to build new ones." >&2 echo "In case of questions contact someone with according AWS permissions." >&2 @@ -332,16 +351,16 @@ 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 ***" +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" + echo "*** AMI_NAME is unset yet, defaulting to ${AMI_NAME}" - case "$AMI_NAME" in + case "${AMI_NAME}" in ngcp-ce-mr*.*.*.*) echo "*** Identified hotfix version string in AMI name [${AMI_NAME}]... ***" AMI_NAME="${AMI_NAME%.*}" @@ -353,19 +372,19 @@ fi AMI_DESCRIPTION="Official sip:provider CE AMI for release ${NGCP_VERSION} [${DATE_STRING}]" -case "$NGCP_RELEASE" in +case "${NGCP_RELEASE}" in 2.*|3.*|mr3.*|mr4.*|mr5.*|mr6.0*|mr6.1*) - echo "*** ngcp release $NGCP_RELEASE doesn't support systemd" + echo "*** ngcp release ${NGCP_RELEASE} doesn't support systemd" SYSTEMD_SUPPORT=false ;; *) - echo "*** ngcp release $NGCP_RELEASE supports systemd" + echo "*** ngcp release ${NGCP_RELEASE} supports systemd" SYSTEMD_SUPPORT=true ;; esac USER_DATA_FILE="$(mktemp)" -cat > "$USER_DATA_FILE" << EOF +cat > "${USER_DATA_FILE}" << EOF #!/bin/bash wget -O /tmp/ngcp-installer.deb ${INSTALLER_URL} dpkg -i /tmp/ngcp-installer.deb @@ -376,7 +395,7 @@ if [ -f /etc/apt/sources.list.d/backports.list ] && grep -q 'jessie-backports' / rm -f /etc/apt/sources.list.d/backports.list fi -if [ "$SYSTEMD_SUPPORT" = "false" ] && [ -d /run/systemd/system ] ; then +if [ "${SYSTEMD_SUPPORT}" = "false" ] && [ -d /run/systemd/system ] ; then echo "Switching from systemd to sysvinit (pre-reboot)" apt update apt install --yes sysvinit-core @@ -431,66 +450,73 @@ FORCE=yes ngcp-installer 2>&1 | tee -a /var/log/ngcp-installer-debug.log EOF fi +echo "*** Generated the following user-data file:" +cat "${USER_DATA_FILE}" +echo "*** end of user-data-file ***" + LOGFILE_RUN="$(mktemp)" -if [ -n "$SUBNET" ] ; then - echo "Starting EC2 instance in region $AWS_REGION, using VPC with subnet $SUBNET, instance-type $INSTANCE_TYPE + AMI $BASE_AMI" - ec2-run-instances --region "$AWS_REGION" \ - --user-data-file "$USER_DATA_FILE" \ - --subnet "$SUBNET" \ - --key "$KEY_NAME" \ - --instance-type "$INSTANCE_TYPE" \ - "$BASE_AMI" >"$LOGFILE_RUN" +if [ -n "${SUBNET}" ] ; then + echo "Starting EC2 instance in region ${AWS_REGION}, using VPC with subnet ${SUBNET}, instance-type ${INSTANCE_TYPE} + AMI ${BASE_AMI}" + aws ec2 run-instances --region "${AWS_REGION}" \ + --user-data "file://${USER_DATA_FILE}" \ + --subnet "${SUBNET}" \ + --key "${KEY_NAME}" \ + --instance-type "${INSTANCE_TYPE}" \ + --image-id "${BASE_AMI}" >"${LOGFILE_RUN}" else - echo "Starting EC2 instance in region $AWS_REGION, using EC2-Classic with security-group $SECURITY_GROUP, instance-type $INSTANCE_TYPE + AMI $BASE_AMI" - 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" + echo "Starting EC2 instance in region ${AWS_REGION}, using EC2-Classic with security-group ${SECURITY_GROUP}, instance-type ${INSTANCE_TYPE} + AMI ${BASE_AMI}" + aws ec2 run-instances --region "${AWS_REGION}" \ + --user-data "file://${USER_DATA_FILE}" \ + --group "${SECURITY_GROUP}" \ + --key "${KEY_NAME}" \ + --instance-type "${INSTANCE_TYPE}" \ + --image-id "${BASE_AMI}" >"${LOGFILE_RUN}" fi -INSTANCE_ID="$(awk '/INSTANCE/ {print $2}' "$LOGFILE_RUN")" -if [ -z "$INSTANCE_ID" ] ; then - echo "Could not identify instance ID, exiting." >&2 +INSTANCE_ID="$(jq -r '.Instances[].InstanceId' "${LOGFILE_RUN}")" +if [ -z "${INSTANCE_ID}" ] ; then + echo "Error: 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" +aws ec2 create-tags --region "${AWS_REGION}" --resources "${INSTANCE_ID}" --tag "Key=Purpose,Value=${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}" +[ -z "${JOB_NAME:-}" ] && JOB_NAME="unset" # running outside of Jenkins +[ -z "${BUILD_NUMBER:-}" ] && BUILD_NUMBER="executed-by-$(whoami)" # running outside of Jenkins +aws ec2 create-tags --region "${AWS_REGION}" --resources "${INSTANCE_ID}" --tag "Key=Name,Value=${AMI_NAME}/${DATE_STRING}/${JOB_NAME}/build_${BUILD_NUMBER}" + +echo "Starting instance ID ${INSTANCE_ID} for ngcp version ${NGCP_VERSION}" -STATUS="$(ec2-describe-instances --region ${AWS_REGION} --filter instance-id="$INSTANCE_ID" | awk '/INSTANCE/ {print $5}')" -echo "Starting instance ID $INSTANCE_ID for ngcp version $NGCP_VERSION" +STATUS="$(aws ec2 describe-instances --region ${AWS_REGION} --filter "Name=instance-id,Values=${INSTANCE_ID}" | jq -r '.Reservations[].Instances[].State.Name')" retry=120 # up to 10 minutes -while [ "$STATUS" != "running" ] && [ $retry -ne 0 ] ; do - # NOTE: it's '$5' here, becoming '$6' later iff elastic IP is attached, this ugly parsing will stay until we switch to e.g. awscli - STATUS="$(ec2-describe-instances --region ${AWS_REGION} --filter instance-id="$INSTANCE_ID" | awk '/INSTANCE/ {print $5}')" +while [ "${STATUS}" != "running" ] && [ ${retry} -ne 0 ] ; do + STATUS="$(aws ec2 describe-instances --region ${AWS_REGION} --filter "Name=instance-id,Values=${INSTANCE_ID}" | jq -r '.Reservations[].Instances[].State.Name')" + retry=$((retry - 1)) - echo "Instance ID $INSTANCE_ID not running yet, checking again in 5 seconds ($retry retries left)." + echo "Instance ID ${INSTANCE_ID} not running yet, checking again in 5 seconds (${retry} retries left)." sleep 5 done -if [ "$STATUS" != "running" ] ; then - echo "No further retries left and couldn't bring up system for AMI $BASE_AMI, giving up." >&2 +if [ "${STATUS}" != "running" ] ; then + echo "No further retries left and couldn't bring up system for AMI ${BASE_AMI}, giving up." >&2 bailout 1 fi # assign elastic IP address to instance, # enabling us to enable access to restricted # webserver areas -if [ -n "$ALLOCATION_ID" ] ; then - echo "Associating elastic IP $ELASTIC_IP allocation ID ${ALLOCATION_ID} with instance ID $INSTANCE_ID" - ec2-associate-address --region "${AWS_REGION}" --allocation-id "${ALLOCATION_ID}" --instance "${INSTANCE_ID}" --allow-reassociation -elif [ -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}" --allow-reassociation +if [ -n "${ALLOCATION_ID}" ] ; then + echo "Associating elastic IP ${ELASTIC_IP} allocation ID ${ALLOCATION_ID} with instance ID ${INSTANCE_ID}" + aws ec2 associate-address --region "${AWS_REGION}" --allocation-id "${ALLOCATION_ID}" --instance "${INSTANCE_ID}" --allow-reassociation +elif [ -n "${ELASTIC_IP}" ] ; then + echo "Associating elastic IP ${ELASTIC_IP} with instance ID ${INSTANCE_ID}" + aws ec2 associate-address --region "${AWS_REGION}" "${ELASTIC_IP}" -i "${INSTANCE_ID}" --allow-reassociation fi -HOSTNAME="$(ec2-describe-instances --region ${AWS_REGION} --filter instance-id="$INSTANCE_ID" | awk '/INSTANCE/ {print $4}')" +HOSTNAME="$(aws ec2 describe-instances --region ${AWS_REGION} --filter "Name=instance-id,Values=${INSTANCE_ID}" | jq -r '.Reservations[].Instances[] | {PublicDnsName} | [.[]] | .[0]')" retry=360 # up to 30 minutes FINISHED_NGCP_CE_INSTALLATION=false @@ -498,24 +524,24 @@ grep_cmd="grep -q 'Installation finished. Thanks for choosing NGCP' /var/log/ngc if "${init_configuration}" ; then grep_cmd="grep -q 'System was successfully configured, now you have the best VoIP software.' /var/log/ngcp-installer.log" fi -while [ "$FINISHED_NGCP_CE_INSTALLATION" != "true" ] && [ $retry -ne 0 ] ; do +while [ "${FINISHED_NGCP_CE_INSTALLATION}" != "true" ] && [ ${retry} -ne 0 ] ; do # shellcheck disable=SC2029 - ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -i "${KEY_FILE}" "admin@$HOSTNAME" \ + ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -i "${KEY_FILE}" "admin@${HOSTNAME}" \ "${grep_cmd}" RC=$? - if [ $RC -eq 0 ] ; then + 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)." + 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 +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 +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 @@ -523,126 +549,130 @@ else fi #Remove temporary crontab -ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -i "${KEY_FILE}" "admin@$HOSTNAME" "sudo crontab -l || sudo crontab -r" +ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -i "${KEY_FILE}" "admin@${HOSTNAME}" "sudo crontab -l || sudo crontab -r" # reboot CE system -if $_opt_skip_reboot ; then +if ${_opt_skip_reboot} ; then echo "*** Skipping system reboot of instance ID ${INSTANCE_ID} as requested via --skip-reboot ***" else - ssh -o "ServerAliveInterval=10" -o "ServerAliveCountMax=1" -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -i "${KEY_FILE}" "admin@$HOSTNAME" "sudo reboot" + ssh -o "ServerAliveInterval=10" -o "ServerAliveCountMax=1" -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}')" + while [ "${STATUS}" != "running" ] && [ ${retry} -ne 0 ] ; do + STATUS="$(aws ec2 describe-instances --region ${AWS_REGION} --filter "Name=instance-id,Values=${INSTANCE_ID}" | jq -r '.Reservations[].Instances[].State.Name')" retry=$((retry - 1)) - echo "Instance ID not yet running (status: ${STATUS}), checking again in 5 seconds ($retry retries left)." + echo "Instance ID not yet running (status: ${STATUS}), checking again in 5 seconds (${retry} retries left)." sleep 5 done - if [ "$STATUS" != "running" ] ; then + if [ "${STATUS}" != "running" ] ; then echo "No further retries left and couldn't finish reboot of instance ID ${INSTANCE_ID}, giving up." >&2 bailout 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}')" + HOSTNAME="$(aws ec2 describe-instances --region ${AWS_REGION} --filter "Name=instance-id,Values=${INSTANCE_ID}" | jq -r '.Reservations[].Instances[] | {PublicDnsName} | [.[]] | .[0]')" # 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 (LISTEN)'" + 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 (LISTEN)'" if [ $? -eq 0 ] ; then STATUS=ok else retry=$((retry - 1)) - echo "Host $HOSTNAME can't be reached via ssh login yet or nginx not listening on port 1443." - echo "Retrying ssh access and checking port 1443 LISTEN state in 5 seconds ($retry retries left)." + echo "Host ${HOSTNAME} can't be reached via ssh login yet or nginx not listening on port 1443." + echo "Retrying ssh access and checking port 1443 LISTEN state in 5 seconds (${retry} retries left)." sleep 5 fi done - if [ "$STATUS" != "ok" ] ; then - echo "Host $HOSTNAME can't be reached via ssh or port 1443 not in state LISTEN, giving up." >&2 + if [ "${STATUS}" != "ok" ] ; then + echo "Host ${HOSTNAME} can't be reached via ssh or port 1443 not in state LISTEN, giving up." >&2 bailout 1 fi fi -remove_ami "$AWS_REGION" "$AMI_NAME" || bailout 1 +remove_ami "${AWS_REGION}" "${AMI_NAME}" || bailout 1 echo "*** Getting rid of all authorized_keys files. ***" -ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -i "${KEY_FILE}" "admin@$HOSTNAME" \ +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" +aws ec2 create-image \ + --region "${AWS_REGION}" \ + --name "${AMI_NAME}" \ + --description "${AMI_DESCRIPTION}" \ + --instance-id "${INSTANCE_ID}" \ + > "${LOGFILE_AMI}" + +AMI_ID=$(jq -r '.ImageId' "${LOGFILE_AMI}") -AMI_ID="$(awk '/^IMAGE/ {print $2}' "$LOGFILE_AMI")" +if [ -n "${AMI_ID}" ] ; then + echo "Received AMI ID ${AMI_ID}, now waiting until AMI is available." +else + echo "Error creating AMI :(" >&2 + cat "${LOGFILE_AMI}" >&2 + bailout 1 +fi 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}')" +while [ "${STATUS}" != "available" ] && [ ${retry} -ne 0 ] ; do + STATUS="$(aws ec2 describe-images --region "${AWS_REGION}" --image-ids "${AMI_ID}" | jq -r '.Images[].State')" - if [ "$STATUS" = "failed" ] ; then - echo "Fatal error while creating AMI ID $AMI_ID (status: ${STATUS}), exiting." >&2 + if [ "${STATUS}" = "failed" ] ; then + echo "Fatal error while creating AMI ID ${AMI_ID} (status: ${STATUS}), exiting." >&2 bailout 1 fi retry=$((retry - 1)) - echo "AMI ID $AMI_ID not yet finished (status: ${STATUS}), checking again in 5 seconds ($retry retries left)." + echo "AMI ID ${AMI_ID} not yet finished (status: ${STATUS}), checking again in 5 seconds (${retry} retries left)." sleep 5 done -if [ "$STATUS" != "available" ] ; then +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 bailout 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 - bailout 1 -fi - -if $_opt_copy_to_all_regions ; then - copy_ami "$AWS_REGION" "$AMI_ID" "$AMI_NAME" "$AMI_DESCRIPTION" || bailout 1 -fi +echo "Successfully created AMI with ID ${AMI_ID}" -if $_opt_public ; then +if ${_opt_public} ; then echo "Marking AMI as public" - ec2-modify-image-attribute --region "$AWS_REGION" "$AMI_ID" --launch-permission -a all + aws ec2 modify-image-attribute --region "${AWS_REGION}" --image-id "${AMI_ID}" --launch-permission "Add=[{Group=all}]" if [ $? -ne 0 ] ; then - echo "Noticed problem when trying to mark AMI with ID $AMI_ID as public." >&2 + echo "Noticed problem when trying to mark AMI with ID ${AMI_ID} as public." >&2 bailout 1 fi fi +if ${_opt_copy_to_all_regions} ; then + copy_ami "${AWS_REGION}" "${AMI_ID}" "${AMI_NAME}" "${AMI_DESCRIPTION}" || bailout 1 +fi + echo "*** Debugging information ***" echo "--- user-data-file ---" -cat "$USER_DATA_FILE" +cat "${USER_DATA_FILE}" echo "--- log file for instance run ---" -cat "$LOGFILE_RUN" +cat "${LOGFILE_RUN}" echo "--- log file for AMI creation ---" -cat "$LOGFILE_AMI" +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 +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 ***" if [ -r ec2_report_amis.txt ] ; then @@ -651,8 +681,8 @@ if [ -r ec2_report_amis.txt ] ; then fi # Jenkins setup specific -TESTHOST="$HOSTNAME" -case "$NGCP_RELEASE" in +TESTHOST="${HOSTNAME}" +case "${NGCP_RELEASE}" in latest) VMVERSION="trunk" ;; @@ -664,4 +694,4 @@ esac generate_ec2_report -rm -f "$USER_DATA_FILE" "$LOGFILE_RUN" "$LOGFILE_AMI" +rm -f "${USER_DATA_FILE}" "${LOGFILE_RUN}" "${LOGFILE_AMI}" diff --git a/ec2-publish-ami b/ec2-publish-ami index 6c884c3..9b37b70 100755 --- a/ec2-publish-ami +++ b/ec2-publish-ami @@ -1,15 +1,7 @@ #!/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" -# retrieve AWS_* environment variables -if [ -r "$HOME/.ec2-create-ngcp" ] ; then - source "$HOME/.ec2-create-ngcp" -fi - usage() { echo "$0 - script to mark a specified EC2 AMI as public @@ -28,14 +20,12 @@ Supported OPTIONS: CMDLINE_OPTS=ami:,help,region: -_opt_temp=$(getopt --name $0 -o +bch --long $CMDLINE_OPTS -- "$@") +_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_public=false +eval set -- "${_opt_temp}" while :; do case "$1" in @@ -60,42 +50,32 @@ while :; do done # if unset set sane defaults -[ -n "$AWS_REGION" ] || AWS_REGION="eu-west-1" - -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 +[ -n "${AWS_REGION}" ] || AWS_REGION="eu-west-1" check4progs(){ local RC='' - for arg in $* ; do - which $arg >/dev/null 2>&1 || RC="$arg" + for arg in "$@" ; do + which "${arg}" >/dev/null 2>&1 || RC="${arg}" done - if [ -n "$RC" ] ; then - echo "$RC not found/executable" >&2 + if [ -n "${RC}" ] ; then + echo "${RC} not found/executable" >&2 return 1 fi } -if ! check4progs ec2-modify-image-attribute ; then - echo "Required tools not found, forgot to install ec2-api-tools?" >&2 +if ! check4progs aws ; then + echo "Required tool aws not found, forgot to install awscli?" >&2 exit 1 fi -if [ -z "$AMI_ID" ] ; then +if [ -z "${AMI_ID}" ] ; then usage >&2 exit 1 fi -echo "Marking AMI $AMI_ID as public" -ec2-modify-image-attribute --region "$AWS_REGION" "$AMI_ID" --launch-permission -a all +echo "Marking AMI ${AMI_ID} as public" +aws ec2 modify-image-attribute --region "${AWS_REGION}" --image-id "${AMI_ID}" --launch-permission "Add=[{Group=all}]" if [ $? -ne 0 ] ; then - echo "Noticed problem when trying to mark AMI with ID $AMI_ID as public." >&2 + echo "Noticed problem when trying to mark AMI with ID ${AMI_ID} as public." >&2 exit 1 fi diff --git a/ec2-stop-instance b/ec2-stop-instance index d35b363..abaa6be 100755 --- a/ec2-stop-instance +++ b/ec2-stop-instance @@ -1,15 +1,7 @@ #!/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" -# retrieve AWS_* environment variables -if [ -r "$HOME/.ec2-create-ngcp" ] ; then - source "$HOME/.ec2-create-ngcp" -fi - usage() { echo "$0 - script to stop the specified EC2 instance ID @@ -29,14 +21,13 @@ Supported OPTIONS: CMDLINE_OPTS=help,instance-id:,region:,terminate -_opt_temp=$(getopt --name $0 -o +bch --long $CMDLINE_OPTS -- "$@") +_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" +eval set -- "${_opt_temp}" -_opt_public=false _opt_terminate=false while :; do @@ -65,51 +56,41 @@ while :; do done # if unset set sane defaults -[ -n "$AWS_REGION" ] || AWS_REGION="eu-west-1" - -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 +[ -n "${AWS_REGION}" ] || AWS_REGION="eu-west-1" check4progs(){ local RC='' - for arg in $* ; do - which $arg >/dev/null 2>&1 || RC="$arg" + for arg in "$@" ; do + which "${arg}" >/dev/null 2>&1 || RC="${arg}" done - if [ -n "$RC" ] ; then - echo "$RC not found/executable" >&2 + if [ -n "${RC}" ] ; then + echo "${RC} not found/executable" >&2 return 1 fi } -if ! check4progs ec2-stop-instances ; then - echo "Required tools not found, forgot to install ec2-api-tools?" >&2 +if ! check4progs aws ; then + echo "Required tool aws not found, forgot to install awscli?" >&2 exit 1 fi -if [ -z "$INSTANCE_ID" ] ; then +if [ -z "${INSTANCE_ID}" ] ; then usage >&2 exit 1 fi -if $_opt_terminate ; then - echo "Terminating instance ID $INSTANCE_ID (as requested via --terminate)" - ec2-terminate-instances --region "$AWS_REGION" "$INSTANCE_ID" +if ${_opt_terminate} ; then + echo "Terminating instance ID ${INSTANCE_ID} (as requested via --terminate)" + aws ec2 terminate-instances --region "${AWS_REGION}" --instance-ids "${INSTANCE_ID}" if [ $? -ne 0 ] ; then - echo "Noticed problem when trying to terminate instance with ID $INSTANCE_ID" >&2 + echo "Noticed problem when trying to terminate instance with ID ${INSTANCE_ID}" >&2 exit 1 fi else - echo "Stopping Instance ID $INSTANCE_ID" - ec2-stop-instances --region "$AWS_REGION" "$INSTANCE_ID" + echo "Stopping Instance ID ${INSTANCE_ID}" + aws ec2 stop-instances --region "${AWS_REGION}" --instance-ids "${INSTANCE_ID}" if [ $? -ne 0 ] ; then - echo "Noticed problem when trying to stop instance with ID $INSTANCE_ID" >&2 + echo "Noticed problem when trying to stop instance with ID ${INSTANCE_ID}" >&2 exit 1 fi fi