From 82bdd9fe3a3dc41196c8b05d9783980fc19aa9ae Mon Sep 17 00:00:00 2001 From: Eric Stroczynski Date: Wed, 28 Jun 2017 17:55:42 -0700 Subject: [PATCH] installer/scripts: AWS tag and delete scripts scripts/maintenance: scripts that tag and delete AWS resources using the `grafiti` Docker container (see https://github.com/coreos/grafiti), and a script that only tags Route53 hosted zones using the AWS CLI. --- installer/scripts/delete.sh | 46 ---- installer/scripts/maintenance/clean-aws.sh | 168 +++++++++++++++ installer/scripts/maintenance/tag-aws.sh | 196 ++++++++++++++++++ .../maintenance/tag-route53-hosted-zones.sh | 100 +++++++++ 4 files changed, 464 insertions(+), 46 deletions(-) delete mode 100755 installer/scripts/delete.sh create mode 100755 installer/scripts/maintenance/clean-aws.sh create mode 100755 installer/scripts/maintenance/tag-aws.sh create mode 100755 installer/scripts/maintenance/tag-route53-hosted-zones.sh diff --git a/installer/scripts/delete.sh b/installer/scripts/delete.sh deleted file mode 100755 index ce5d6fca0c..0000000000 --- a/installer/scripts/delete.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -# TODO: Use jq instead of sed everywhere -# TODO: Make xargs ignore all errors (might be pre-empted): use xargs -I{} sh -c 'aws ec2 ... {} || true' -# TODO: Delete all other kind of resources - -echo Deleting all private zones -aws route53 list-hosted-zones | jq ".HostedZones[] | select(.Config.PrivateZone == true) | .Id" | xargs -L 1 aws route53 delete-hosted-zone --id -aws route53 list-resource-record-sets --hosted-zone-id - - -echo Deleting all ASGs -aws autoscaling describe-auto-scaling-groups | jq ".AutoScalingGroups[] .AutoScalingGroupName" | xargs -L 1 aws autoscaling delete-auto-scaling-group --force-delete --auto-scaling-group-name - -echo Deleting all ELBs -aws elb describe-load-balancers | jq ".LoadBalancerDescriptions[] .LoadBalancerName" | xargs -L 1 aws elb delete-load-balancer --load-balancer-name - -echo Deleting all NAT gateways -aws ec2 describe-nat-gateways | jq '.NatGateways[] | select(.State == "available") | .NatGatewayId' | xargs -L 1 -I {} aws ec2 delete-nat-gateway --nat-gateway-id {} 1> /dev/null - -echo "Waiting for the Elastic Network Interfaces from the ELBs, and for the NAT gateways, to be detached/deleted" -sleep 30 - -echo Disassociating/Releasing all EIPs -aws ec2 describe-addresses | grep AssociationId | sed -E 's/^.*(eipassoc-[a-z0-9]+).*$/\1/' | xargs -L 1 aws ec2 disassociate-address --association-id -aws ec2 describe-addresses | grep AllocationId | sed -E 's/^.*(eipalloc-[a-z0-9]+).*$/\1/' | xargs -L 1 aws ec2 release-address --allocation-id - -echo Detaching/Deleting all Internet Gateways -aws ec2 describe-internet-gateways | jq '.InternetGateways[] | "--internet-gateway-id=" + .InternetGatewayId + " --vpc-id=" + .Attachments?[].VpcId' -r | xargs -L 1 aws ec2 detach-internet-gateway -aws ec2 describe-internet-gateways | jq '.InternetGateways[] .InternetGatewayId' | xargs -L 1 aws ec2 delete-internet-gateway --internet-gateway-id - -echo Deleting all subnets -aws ec2 describe-subnets | jq ".Subnets[] .SubnetId" | xargs -L 1 aws ec2 delete-subnet --subnet-id - -echo "Deleting all route tables (except the main ones)" -#aws ec2 describe-route-tables | jq '.RouteTables[] | select(.Routes?[] | select(.DestinationCidrBlock == "0.0.0.0/0")) | .RouteTableId' | xargs -L 1 aws ec2 delete-route --destination-cidr-block 0.0.0.0/0 --route-table-id # First, delete the default route, as they might be pointed at a non-existing gateway. -# shellcheck disable=SC2016 -aws ec2 describe-route-tables --query 'RouteTables[?Associations[0].Main != `true`]' | jq ".[] .RouteTableId" | xargs -L 1 aws ec2 delete-route-table --route-table-id - -echo Deleting security groups -aws ec2 describe-security-groups | jq ".SecurityGroups[] | select(.GroupName != \"default\" and (.IpPermissions|length > 0)) | \"--group-id \" + .GroupId + \" --ip-permissions '\" + (.IpPermissions|tostring) + \"'\"" -r | xargs -L 1 aws ec2 revoke-security-group-ingress -aws ec2 describe-security-groups | jq ".SecurityGroups[] | select(.GroupName != \"default\" and (.IpPermissionsEgress|length > 0)) | \"--group-id \" + .GroupId + \" --ip-permissions '\" + (.IpPermissionsEgress|tostring) + \"'\"" -r | xargs -L 1 aws ec2 revoke-security-group-egress -aws ec2 describe-security-groups | jq '.SecurityGroups[] | select(.GroupName != "default") | .GroupId' | xargs -L 1 -I {} sh -c 'aws ec2 delete-security-group --group-id {} || true' - -echo Deleting VPCs -aws ec2 describe-vpcs | jq ".Vpcs[] .VpcId" | xargs -L 1 -I {} sh -c 'aws ec2 delete-vpc --vpc-id {} || true' diff --git a/installer/scripts/maintenance/clean-aws.sh b/installer/scripts/maintenance/clean-aws.sh new file mode 100755 index 0000000000..5be4de723f --- /dev/null +++ b/installer/scripts/maintenance/clean-aws.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env bash + +usage() { + cat < "$config_file" +fi + +if [ -z "$tag_file" ]; then + tag_file="$(mktemp -p "$tmp_dir")" + + date_string="$(date "+%Y-%m-%d" -d "-1 day")\",\"$(date "+%Y-%-m-%-d" -d "-1 day")\",\"$(date +%Y-%m-%d)\",\"$(date +%Y-%-m-%-d)" + if [ -n "$date_override" ]; then + date_string="$date_override" + fi + + cat < "$tag_file" +{"TagFilters":[{"Key":"expirationDate","Values":["${date_string}"]}]} +EOF +fi + +echo "Deleting resources with the following tags:" +jq '.' "$tag_file" + +if [ -n "$dry_run" ]; then + echo "Dry run flag set. Not deleting any resources." +fi + +if [ ! $force ]; then + read -rp "Proceed deleting these resources? [y/N]: " yn + if [ "$yn" != "y" ]; then + echo "Aborting deletion and cleaning up." + exit 1 + fi +fi + +trap 'docker stop grafiti-deleter && docker rm grafiti-deleter; exit' EXIT + +docker run -t --rm --name grafiti-deleter \ + -v "$tmp_dir":/tmp/config:z \ + -e AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" \ + -e AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" \ + -e AWS_REGION="$region" \ + -e CONFIG_FILE="/tmp/config/$(basename "$config_file")" \ + -e TAG_FILE="/tmp/config/$(basename "$tag_file")" \ + quay.io/coreos/grafiti:"${version}" \ + ash -c "grafiti $dry_run --config \"\$CONFIG_FILE\" --ignore-errors delete --all-deps --delete-file \"\$TAG_FILE\"" + +set +e diff --git a/installer/scripts/maintenance/tag-aws.sh b/installer/scripts/maintenance/tag-aws.sh new file mode 100755 index 0000000000..1b76258396 --- /dev/null +++ b/installer/scripts/maintenance/tag-aws.sh @@ -0,0 +1,196 @@ +#!/usr/bin/env bash + +usage() { + cat < "$config_file" +endHour = -${end_hour} +startHour = -${start_hour} +includeEvent = false +tagPatterns = [ + "{expirationDate: ${date_string}}" +] +EOF +fi + +# Exclusion file prevents tagging of resources that already have tags with the key +# "expirationDate" +if [ -z "$exclude_file" ]; then + exclude_file="$(mktemp -p "$tmp_dir")" + echo '{"TagFilters":[{"Key":"expirationDate","Values":[]}]}' > "$exclude_file" +fi + +echo "Tagging resources with the following configuration:" +cat "$config_file" + +if [ -n "$dry_run" ]; then + echo "Dry run flag set. Not tagging any resources." +fi + +if [ ! $force ]; then + read -rp "Proceed tagging these resources? [y/N]: " yn + if [ "$yn" != "y" ]; then + echo "Aborting tagging and cleaning up." + exit 1 + fi +fi + +trap 'docker stop grafiti-tagger && docker rm grafiti-tagger; exit' EXIT + +docker run -t --rm --name grafiti-tagger \ + -v "$tmp_dir":/tmp/config:z \ + -e AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" \ + -e AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" \ + -e AWS_REGION="$region" \ + -e CONFIG_FILE="/tmp/config/$(basename "$config_file")" \ + -e TAG_FILE="/tmp/config/$(basename "$exclude_file")" \ + quay.io/coreos/grafiti:"${version}" \ + bash -c "grafiti --config \"\$CONFIG_FILE\" parse | \ + grafiti --config \"\$CONFIG_FILE\" filter --ignore-file \"\$TAG_FILE\" | \ + grafiti $dry_run --config \"\$CONFIG_FILE\" tag" + +set +e diff --git a/installer/scripts/maintenance/tag-route53-hosted-zones.sh b/installer/scripts/maintenance/tag-route53-hosted-zones.sh new file mode 100755 index 0000000000..74480b68b6 --- /dev/null +++ b/installer/scripts/maintenance/tag-route53-hosted-zones.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash + +usage() { + cat < /dev/null || ! command -v aws > /dev/null; then + "Dependencies not installed." + exit 1 +fi + +set -e + +# Tag all Route53 hosted zones that do not already have a tag with the same keys, +# in this case 'expirationDate', with today's date as default, or +# with the DATE_VALUE_OVERRIDE value. Format YYYY-MM-DD. +date_string="$(date "+%Y-%m-%d")" +if [ -n "$date_override" ]; then + date_string="${date_override}" +fi + +tags="[{\"Key\":\"expirationDate\",\"Value\":\"$date_string\"}]" + +echo "Tagging hosted zones with the following tags:" +echo "$tags" + +if [ ! $force ]; then + read -rp "Proceed tagging these resources? [y/N]: " yn + if [ "$yn" != "y" ]; then + echo "Aborting tagging and cleaning up." + exit 1 + fi +fi + +private_zones=$(aws route53 list-hosted-zones | \ + jq ".HostedZones[] | select(.Config.PrivateZone == true) | .Id" | \ + sed "s@\"@@g") + +for key in $(echo -e "$tags" | jq ".[].Key"); do + for zone in $private_zones; do + zone="${zone##*/}" + is_not_tagged=$(aws route53 list-tags-for-resource \ + --resource-type hostedzone \ + --resource-id "$zone" | \ + jq ".ResourceTagSet | select(.Tags[]? | .Key == $key) | .ResourceId") + if [ -z "$is_not_tagged" ]; then + if aws route53 change-tags-for-resource \ + --resource-type hostedzone \ + --add-tags "$(echo -e "$tags")" \ + --resource-id "${zone##*/}"; then + echo "Tagged hosted zone ${zone##*/}" + else + echo "Error tagging hosted zone ${zone##*/}" + fi + fi + done +done + +set +e