diff --git a/README.md b/README.md index 08efd92..4bb3884 100644 --- a/README.md +++ b/README.md @@ -107,3 +107,6 @@ Volumes : 37 Total resources: 796 +## Patchup: + +Fixed several crashes due quick and dirty catching so tool is useable with non-all-access IDs. diff --git a/count_resources.py b/count_resources.py index c4c45eb..e242750 100644 --- a/count_resources.py +++ b/count_resources.py @@ -1,6 +1,13 @@ import click import boto3 import sys +import botocore +import json + +# added and saved not printed yet +mperm = {} + + resource_counts = {} resource_totals = {} @@ -8,8 +15,18 @@ @click.option('--access', help='AWS Access Key. Otherwise will use the standard credentials path for the AWS CLI.') @click.option('--secret', help='AWS Secret Key') @click.option('--profile', help='If you have multiple credential profiles, use this option to specify one.') -def controller(access, secret, profile): +@click.option('--region', help='Choose the region to test for (example: us-east-1, us-west-1), you can provide comma seperated list, like so: us-east-1,me-south-1,us-west-2') +@click.option('--show-regions', help='Show available regions',default=False,is_flag=True) +@click.option('--save-json','savejson', help='Save result regions as json',default=False,is_flag=True) +def controller(access, secret, profile, region,show_regions, savejson): global session + global args + cregion = region + args = {'region':None} + + # lets addup a region flag + if cregion: + args['region']=cregion if access: click.echo('Access Key specified') if not secret: @@ -47,49 +64,188 @@ def controller(access, secret, profile): # Then build out the master list of regions to then fill in the service counts # Also build a separate dictionary for cross-region totals + if show_regions: + print('Available regions:') + region_list = session.get_available_regions('ec2') + for region in region_list: + print(region) + sys.exit(0) + + if args['region'] != None: + if cregion.find(',') != -1: + res = cregion.split(',') + region_list = res + else: + region_list = [cregion] + resource_counts[cregion] = {} + # print('Region: {0}'.format(args['region'])) - region_list = session.get_available_regions('ec2') - for region in region_list: - resource_counts[region] = {} + else: + region_list = session.get_available_regions('ec2') + for region in region_list: + resource_counts[region] = {} + #print('Region: {0}'.format(region)) # iterate through the various services to build the counts click.echo('Counting resources across regions. This will take a few minutes...') click.echo(' ') - ec2_counter(account_id) - autoscaling_counter() - balancer_counter() - s3_counter() - iam_counter() - lambda_counter() - glacier_counter() - cloudwatch_rules_counter() - config_counter() - cloudtrail_counter() - sns_counter() - kms_counter() - dynamo_counter() - rds_counter() + ec2_counter(account_id,cregion) + try: + autoscaling_counter() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + try: + balancer_counter() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + try: + s3_counter() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + try: + iam_counter() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + try: + lambda_counter() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + + try: + glacier_counter() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + try: + cloudwatch_rules_counter() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + try: + config_counter() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + try: + cloudtrail_counter() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + try: + sns_counter() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + try: + kms_counter() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + try: + dynamo_counter() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + try: + rds_counter() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} # show results - click.echo('Resources by region') + #click.echo('Resources by region') click.echo(resource_counts) + for key in sorted(resource_counts.keys()): + click.echo(' ') + click.echo('Ressources in {0}'.format(key)) + click.echo('-----------------------') + for kitem, vitem in sorted(resource_counts[key].items()): + click.echo("{} : {}".format(kitem, vitem)) + click.echo(' ') click.echo('Resource totals across all regions') + click.echo('----------------------------------') for key, value in sorted(resource_totals.items()): click.echo("{} : {}".format(key, value)) total = sum(resource_totals.values()) click.echo('') click.echo('Total resources: ' + str(total)) + if savejson: + click.echo('Saving json results in rc.json') + click.echo('------------------------------') + jd = json.dumps(resource_counts) + fw = open('rc.json','w') + fw.write(jd) + fw.close() + # ec2 = boto3.client('ec2', region_name='us-west-2') # ec2 = session.client('ec2', region_name='us-west-2') -def ec2_counter(account_id): +def ec2_counter(account_id, cregion): # get list of regions supported by EC2 endpoint - region_list = session.get_available_regions('ec2') + if cregion != None: + if cregion.find(',') != -1: + res = cregion.split(',') + region_list = res + for ncregion in region_list: + resource_counts[ncregion] = {} + else: + region_list = [cregion] + resource_counts[cregion] = {} + +# print('Choosen Region: {0}'.format(args['region'])) + else: + region_list = session.get_available_regions('ec2') + + # initialize cross region totals total_instances = 0 @@ -108,6 +264,7 @@ def ec2_counter(account_id): for region in region_list: ec2 = session.resource('ec2', region_name=region) ec2client = session.client('ec2', region_name=region) + print("Checking Region: {0}".format(region)) # build the collections to count instance_iterator = ec2.instances.all() @@ -120,26 +277,156 @@ def ec2_counter(account_id): vpc_peering_connection_iterator = ec2.vpc_peering_connections.all() network_acl_iterator = ec2.network_acls.all() vpc_address_iterator = ec2.vpc_addresses.all() - nat_gateways = ec2client.get_paginator('describe_nat_gateways') - nat_gateway_iterator = nat_gateways.paginate() - endpoints = ec2client.describe_vpc_endpoints() + try: + nat_gateways = ec2client.get_paginator('describe_nat_gateways') + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + + try: + nat_gateway_iterator = nat_gateways.paginate() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + + try: + endpoints = ec2client.describe_vpc_endpoints() + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} # count resources - instance_counter = len(list(instance_iterator)) - group_counter = len(list(security_group_iterator)) - volume_counter = len(list(volume_iterator)) - snapshot_counter = len(list(snapshot_iterator)) - image_counter = len(list(image_iterator)) - vpc_counter = len(list(vpc_iterator)) - subnet_counter = len(list(subnet_iterator)) - peering_counter = len(list(vpc_peering_connection_iterator)) - acl_counter = len(list(network_acl_iterator)) - ip_counter = len(list(vpc_address_iterator)) + # try to get instances + try: + instance_counter = len(list(instance_iterator)) + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + instance_counter = 0 + + try: + group_counter = len(list(security_group_iterator)) + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + group_counter = 0 + + try: + volume_counter = len(list(volume_iterator)) + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + volume_counter = 0 + + try: + snapshot_counter = len(list(snapshot_iterator)) + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + snapshot_counter = 0 + + try: + image_counter = len(list(image_iterator)) + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + image_counter = 0 + + try: + vpc_counter = len(list(vpc_iterator)) + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + vpc_counter = 0 + + try: + subnet_counter = len(list(subnet_iterator)) + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + subnet_counter = 0 + + try: + peering_counter = len(list(vpc_peering_connection_iterator)) + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + peering_counter = 0 + + + try: + acl_counter = len(list(network_acl_iterator)) + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + acl_counter = 0 + + try: + ip_counter = len(list(vpc_address_iterator)) + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + ip_counter = 0 + gateway_counter = 0 - for gateway in nat_gateway_iterator: - gateway_counter += len(gateway['NatGateways']) - endpoint_counter = len(endpoints['VpcEndpoints']) + try: + for gateway in nat_gateway_iterator: + try: + gateway_counter += len(gateway['NatGateways']) + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + endpoint_counter = len(endpoints['VpcEndpoints']) + except botocore.exceptions.ClientError as e: + op = e.__dict__['operation_name'] + code = e.__dict__['response']['Error']['Code'] + msg = e.__dict__['response']['Error']['Message'] + print('{0} {1} Operation: {2}'.format(code,msg,op)) + mperm[op] = {'Code':code,'Message':msg} + endpoint_counter = 0 # add to the cross region totals total_instances = total_instances + instance_counter @@ -412,10 +699,12 @@ def dynamo_counter(): def rds_counter(): region_list = session.get_available_regions('rds') + #print(region_list) total_dbinstances = 0 for region in region_list: + print(region) rds = session.client('rds', region_name=region) dbinstances_counter = 0 rds_paginator = rds.get_paginator('describe_db_instances') @@ -427,4 +716,4 @@ def rds_counter(): resource_totals['RDS Instances'] = total_dbinstances if __name__ == "__main__": - controller() \ No newline at end of file + controller()