Skip to content

Commit

Permalink
Merge pull request #20 from dwc0011/add-cli-option
Browse files Browse the repository at this point in the history
Add cli option
  • Loading branch information
dwc0011 authored Feb 24, 2023
2 parents 2119e87 + b1e430e commit fd9119e
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 1.0.0
current_version = 1.1.0
commit = True
message = Bumps version to {new_version}
tag = False
Expand Down
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).

### 1.1.0

**Commit Delta**: [Change from 1.0.0 release](https://github.com/plus3it/terraform-aws-org-new-account-delete-default-vpcs/compare/1.1.0...1.0.0)

**Released**: 2023.02.23

**Summary**:

* Add CLI option to run delete_default_vpc.py script

### 1.0.0

**Commit Delta**: N/A
Expand All @@ -12,4 +22,4 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

**Summary**:

* Initial release of capability
* Initial release of capability
246 changes: 171 additions & 75 deletions src/delete_default_vpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@
MAX_WORKERS: (optional) # of workers to process resources, default 20
"""
from argparse import ArgumentParser, RawDescriptionHelpFormatter
import collections
import concurrent.futures
import logging
import os
import sys

import boto3
from aws_assume_role_lib import ( # type: ignore
Expand Down Expand Up @@ -83,88 +85,23 @@ class DeleteVPCResourcesError(Exception):
"""Delete VPC Resource Error."""


class DeleteDefaultVPCInvalidArgsError(Exception):
"""Invalid arguments were used to delete VPCs."""


def lambda_handler(event, context): # pylint: disable=unused-argument, too-many-locals
"""Delete Default VPC in all regions.
Assumes role to account and deletes default VPC resources in all regions
Entrypoint if triggered via lambda
"""
log.debug("AWS Event:%s", event)

account_id = get_account_id(event)

# do stuff with the Lambda role using SESSION
log.debug(
"Main identity is %s",
SESSION.client("sts").get_caller_identity()["Arn"],
)

assumed_role_session = get_assumed_role_session(account_id)

regions = get_regions(assumed_role_session)

exception_list = []
futures = []
with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
for region in regions:
try:
ec2 = assumed_role_session.resource("ec2", region_name=region)
vpc_ids = get_default_vpc_ids(assumed_role_session, account_id, region)
except BaseException as exc: # pylint: disable=broad-except
# Allow threads to continue on exception, but capture the error
vpc_ids = []
msg = "Error: Error getting vpc resource"
exception_list.append(
convert_exception_to_string(
account_id,
region,
lambda_handler.__name__,
msg,
exc,
)
)
log.exception(exc)

for vpc_id in vpc_ids:
log.info(
"Processing Account: %s Region: %s and VPC Id: %s",
account_id,
region,
vpc_id,
)
try:
vpc_resource = ec2.Vpc(vpc_id)
futures.append(executor.submit(del_vpc_all, vpc_resource, region))
except BaseException as exc: # pylint: disable=broad-except
# Allow threads to continue on exception, but capture the error
msg = "Error: Exception submitting del_vpc_all executor"
exception_list.append(
convert_exception_to_string(
account_id,
region,
lambda_handler.__name__,
msg,
exc,
)
)
log.exception(exc)
concurrent.futures.wait(futures)
for fut in futures:
try:
fut.result()
except BaseException as exc: # pylint: disable=broad-except
# Allow threads to continue on exception, but capture the error
exception_list.append(str(exc))

if exception_list:
exception_list = "\r\r ".join(exception_list)
exception_str = f"All Exceptions encountered:\r\r{exception_list}\r\r"
log.error(exception_str)
raise DeleteVPCError(Exception(exception_str))
assume_role_arn = f"arn:{get_partition()}:iam::{account_id}:role/{ASSUME_ROLE_NAME}"

if DRY_RUN:
log.debug("Dry Run listed all resources that would be deleted")
else:
log.debug("Deleted all default VPCs and associated resources")
main(account_id, assume_role_arn)


def get_new_account_id(event):
Expand All @@ -187,10 +124,13 @@ def get_account_id(event):
return get_account_id_strategy[event_name](event)


def get_assumed_role_session(account_id):
def get_assumed_role_session(account_id, role_arn):
"""Get boto3 session."""
role_arn = f"arn:{get_partition()}:iam::{account_id}:role/{ASSUME_ROLE_NAME}"
role_session_name = generate_lambda_session_name()
function_name = os.environ.get(
"AWS_LAMBDA_FUNCTION_NAME", os.path.basename(__file__)
)

role_session_name = generate_lambda_session_name(function_name)

# Assume the session
assumed_role_session = assume_role(
Expand Down Expand Up @@ -404,3 +344,159 @@ def process_exception(vpc, method_name, exception):
log.exception(exception)

return error_str


def cli_main(target_account_id, assume_role_arn=None, assume_role_name=None):
"""Process cli assume_role_name arg and pass to main."""
log.debug(
"CLI - target_account_id=%s assume_role_arn=%s assume_role_name=%s",
target_account_id,
assume_role_arn,
assume_role_name,
)

if assume_role_name:
assume_role_arn = (
f"arn:{get_partition()}:iam::{target_account_id}:role/{assume_role_name}"
)
log.info("assume_role_arn for provided role name is '%s'", assume_role_arn)

main(target_account_id, assume_role_arn)


def main(target_account_id, assume_role_arn):
"""Assume role and concurrently delete default vpc resources."""
log.debug(
"Main identity is %s",
SESSION.client("sts").get_caller_identity()["Arn"],
)

assumed_role_session = get_assumed_role_session(target_account_id, assume_role_arn)

regions = get_regions(assumed_role_session)

exception_list = concurrently_delete_vpcs(
assumed_role_session,
target_account_id,
regions,
)

if exception_list:
exception_list = "\r\r ".join(exception_list)
exception_str = f"All Exceptions encountered:\r\r{exception_list}\r\r"
log.error(exception_str)
raise DeleteVPCError(Exception(exception_str))

if DRY_RUN:
log.debug("Dry Run listed all resources that would be deleted")
else:
log.debug("Deleted all default VPCs and associated resources")


def concurrently_delete_vpcs(
assumed_role_session,
target_account_id,
regions,
):
"""Create worker threads and deletes vpc resources."""
exception_list = []
futures = []
with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
for region in regions:
try:
ec2 = assumed_role_session.resource("ec2", region_name=region)
vpc_ids = get_default_vpc_ids(
assumed_role_session, target_account_id, region
)
except BaseException as exc: # pylint: disable=broad-except
# Allow threads to continue on exception, but capture the error
vpc_ids = []
msg = "Error: Error getting vpc resource"
exception_list.append(
convert_exception_to_string(
target_account_id,
region,
lambda_handler.__name__,
msg,
exc,
)
)
log.exception(exc)

for vpc_id in vpc_ids:
log.info(
"Processing Account: %s Region: %s and VPC Id: %s",
target_account_id,
region,
vpc_id,
)
try:
vpc_resource = ec2.Vpc(vpc_id)
futures.append(executor.submit(del_vpc_all, vpc_resource, region))
except BaseException as exc: # pylint: disable=broad-except
# Allow threads to continue on exception, but capture the error
msg = "Error: Exception submitting del_vpc_all executor"
exception_list.append(
convert_exception_to_string(
target_account_id,
region,
lambda_handler.__name__,
msg,
exc,
)
)
log.exception(exc)
concurrent.futures.wait(futures)
for fut in futures:
try:
fut.result()
except BaseException as exc: # pylint: disable=broad-except
# Allow threads to continue on exception, but capture the error
exception_list.append(str(exc))

return exception_list


if __name__ == "__main__":

def create_args():
"""Return parsed arguments."""
parser = ArgumentParser(
formatter_class=RawDescriptionHelpFormatter,
description="""
Delete Default VPC for all supported regions for provided target account.
Supported Environment Variables:
'LOG_LEVEL': defaults to 'info'
- set the desired log level ('error', 'warning', 'info' or 'debug')
'DRY_RUN': defaults to 'true'
- set whether actions should be simulated or live
- value of 'true' (case insensitive) will be simulated.
'MAX_WORKERS': defaults to '20'
-sets max number of worker threads to run simultaneously.
""",
)
required_args = parser.add_argument_group("required named arguments")
required_args.add_argument(
"--target-account-id",
required=True,
type=str,
help="Account number to delete default VPC resources in",
)
mut_x_group = parser.add_mutually_exclusive_group(required=True)
mut_x_group.add_argument(
"--assume-role-arn",
type=str,
help="ARN of IAM role to assume in the target account (case sensitive)",
)
mut_x_group.add_argument(
"--assume-role-name",
type=str,
help="Name of IAM role to assume in the target account (case sensitive)",
)

return parser.parse_args()

sys.exit(cli_main(**vars(create_args())))
1 change: 1 addition & 0 deletions src/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
aws-assume-role-lib==2.10.0
boto3==1.26.74

0 comments on commit fd9119e

Please sign in to comment.