Python Forum
Python function executes twice when region loop is present - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Python function executes twice when region loop is present (/thread-23581.html)



Python function executes twice when region loop is present - bluethundr - Jan-06-2020

This function lists all the instances in an AWS account. It does that for each region.
For some reason I end up with the total number of instances reported by the function is doubled when the region loop is there. It is duplicating instance IDs when it shouldn't do that. Each region should have it's own unique set of servers.
For example in one account there is 95 servers but when the region loop is there, it reports that there are 190 servers. And the resulting list shows duplicate instance IDs.

def list_instances(aws_account,aws_account_number, interactive, regions, fieldnames, show_details):
    today, aws_env_list, output_file, output_file_name, fieldnames = initialize(interactive, aws_account)
    options = arguments()
    instance_list = ''
    session = ''
    ec2 = ''
    account_found = ''
    PrivateDNS = None
    block_device_list = None
    instance_count = 0
    account_type_message = ''
    profile_missing_message = ''
    region = ''
    # Set the ec2 dictionary
    ec2info = {}
    if 'gov' in aws_account and not 'admin' in aws_account:
		session = boto3.Session(profile_name=aws_account,region_name=region)
		account_found = 'yes'
    else:
		session = boto3.Session(profile_name=aws_account,region_name=region)
		account_found = 'yes'
		
    for region in regions:
        if 'gov' in aws_account and not 'admin' in aws_account:

            session = boto3.Session(profile_name=aws_account,region_name=region)
        else:

			session = boto3.Session(profile_name=aws_account,region_name=region)

            ec2 = session.client("ec2")
        # Loop through the instances
        try:
            instance_list = ec2.describe_instances()
        except Exception as e:
                pass
        for reservation in instance_list["Reservations"]:
            for instance in reservation.get("Instances", []):
                instance_count = instance_count + 1
                launch_time = instance["LaunchTime"]
                launch_time_friendly = launch_time.strftime("%B %d %Y")
                tree = objectpath.Tree(instance)
                block_devices = set(tree.execute('$..BlockDeviceMappings[\'Ebs\'][\'VolumeId\']'))
                if block_devices:
                    block_devices = list(block_devices)
                    block_devices = str(block_devices).replace('[','').replace(']','').replace('\'','')
                else:
                    block_devices = None
                private_ips =  set(tree.execute('$..PrivateIpAddress'))
                if private_ips:
                    private_ips_list = list(private_ips)
                    private_ips_list = str(private_ips_list).replace('[','').replace(']','').replace('\'','')
                else:
                    private_ips_list = None
                type(private_ips_list)
                public_ips =  set(tree.execute('$..PublicIp'))
                if len(public_ips) == 0:
                    public_ips = None
                if public_ips:
                    public_ips_list = list(public_ips)
                    public_ips_list = str(public_ips_list).replace('[','').replace(']','').replace('\'','')
                else:
                    public_ips_list = None
                if 'KeyName' in instance:
                    key_name = instance['KeyName']
                else:
                    key_name = None
                name = None
                if 'Tags' in instance:
                    try:
                        tags = instance['Tags']
                        name = None
                        for tag in tags:
                            if tag["Key"] == "Name":
                                name = tag["Value"]
                            if tag["Key"] == "Engagement" or tag["Key"] == "Engagement Code":
                                engagement = tag["Value"]
                    except ValueError:
                        # print("Instance: %s has no tags" % instance_id)
                        pass
                if 'VpcId' in instance:
                    vpc_id = instance['VpcId']
                else:
                    vpc_id = None
                if 'PrivateDnsName' in instance:
                    private_dns = instance['PrivateDnsName']
                else:
                    private_dns = None
                if 'Platform' in instance:
                    platform = instance['Platform']
                else:
                    platform = None
                ec2info[instance['InstanceId']] = {
                    'AWS Account': aws_account,
                    'Account Number': aws_account_number,
                    'Name': name,
                    'Instance ID': instance['InstanceId'],
                    'Volumes': block_devices,
                    'Private IP': private_ips_list,
                    'Public IP': public_ips_list,
                    'Private DNS': private_dns,
                    'Availability Zone': instance['Placement']['AvailabilityZone'],
                    'VPC ID': vpc_id,
                    'Type': instance['InstanceType'],
                    'Platform': platform,
                    'Key Pair Name': key_name,
                    'State': instance['State']['Name'],
                    'Launch Date': launch_time_friendly
                }
                ec2_info_items = ec2info.items
                if show_details == 'y' or show_details == 'yes':
                    for instance_id, instance in ec2_info_items():
                        if account_found == 'yes':
                            print(Fore.RESET + "-------------------------------------")
                            for key in [
                                'AWS Account',
                                'Account Number',
                                'Name',
                                'Instance ID',
                                'Volumes',
                                'Private IP',
                                'Public IP',
                                'Private DNS',
                                'Availability Zone',
                                'VPC ID',
                                'Type',
                                'Platform',
                                'Key Pair Name',
                                'State',
                                'Launch Date'
                            ]:
                                print(Fore.GREEN + f"{key}: {instance.get(key)}")
                            print(Fore.RESET + "-------------------------------------")
                    else:
                        pass
                ec2info = {}
                with open(output_file,'a') as csv_file:
                    csv_file.close()
		    report_instance_stats(instance_count, aws_account, account_found)
    return output_file
	
def report_instance_stats(instance_count, aws_account, account_found):
    if account_found == 'yes':
        print(f"There are: {instance_count} EC2 instances in AWS Account: {aws_account}.")
Why is it doing that when the regions loop is there? How do I get it to report the right number of instances in an account when the region loop is present?


RE: Python function executes twice when region loop is present - ichabod801 - Jan-06-2020

The instance count is reported in report_instance_stats. This is called on line 139, at the end of the 'for instance' loop on line 38. But that's within the 'for reservation' loop on line 37, and you don't reset the count before the next iteration of the 'for reservation' loop. Could that be causing the problem?


RE: Python function executes twice when region loop is present - bluethundr - Jan-07-2020

(Jan-06-2020, 11:06 PM)ichabod801 Wrote: The instance count is reported in report_instance_stats. This is called on line 139, at the end of the 'for instance' loop on line 38. But that's within the 'for reservation' loop on line 37, and you don't reset the count before the next iteration of the 'for reservation' loop. Could that be causing the problem?

Thanks, but I don't think so. Because the instance IDs are being duplicated in the output. So, it's not just reporting an incorrect total.