简体   繁体   English

Python 函数返回不一致的结果

[英]Python function returns inconsistent results

I wrote a script that lists EC2 instances in Amazon Web Services.我编写了一个脚本来列出 Amazon Web Services 中的 EC2 实例。 It writes the results to confluence.它将结果写入汇合。 But it's behaving oddly.但它的行为很奇怪。

I'm on windows 10. The first time I open a powershell terminal and run it it reports the correct number of servers in the AWS account.我在 Windows 10 上。第一次打开 powershell 终端并运行它时,它会报告 AWS 帐户中正确的服务器数量。

The next time I run it (without changing anything at all) it doubles the resutls.下次我运行它时(根本不改变任何东西)它会使结果翻倍。 And each time you run it again with the same arguments it reports the same incorrect (doubled) amount.每次使用相同的参数再次运行它时,它都会报告相同的错误(加倍)数量。

This is the function that lists the instances and this is where I think the trouble is, but I'm having trouble finding it:这是列出实例的函数,这是我认为问题所在,但我很难找到它:

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 = {}
    # Write the file headers
    if interactive == 1:
        with open(output_file, mode='w+') as csv_file:
            writer = csv.DictWriter(csv_file, fieldnames=fieldnames, delimiter=',', lineterminator='\n')
            writer.writeheader()
            if 'gov' in aws_account and not 'admin' in aws_account:
                try:
                    session = boto3.Session(profile_name=aws_account,region_name=region)
                    account_found = 'yes'
                except botocore.exceptions.ProfileNotFound as e:
                    message = f"An exception has occurred: {e}"
                    account_found = 'no'
                    banner(message)
            else:
                try:
                    session = boto3.Session(profile_name=aws_account,region_name=region)
                    account_found = 'yes'
                except botocore.exceptions.ProfileNotFound as e:
                    message = f"An exception has occurred: {e}"
                    account_found = 'no'
                    banner(message)
    print(Fore.CYAN)
    report_gov_or_comm(aws_account, account_found)
    print(Fore.RESET)
    for region in regions:
        if 'gov' in aws_account and not 'admin' in aws_account:
            try:
                session = boto3.Session(profile_name=aws_account,region_name=region)
            except botocore.exceptions.ProfileNotFound as e:
                profile_missing_message = f"An exception has occurred: {e}"                 account_found = 'no' pass else: try:                 session = boto3.Session(profile_name=aws_account,region_name=region)                 account_found = 'yes' except botocore.exceptions.ProfileNotFound as e:                 profile_missing_message = f"An exception has occurred: {e}" pass try:             ec2 = session.client("ec2") except Exception as e: pass
    # Loop through the instances
    try:
        instance_list = ec2.describe_instances()
    except Exception as e:
        pass
    try:
        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(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 print(f"Platform: {platform}")                     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                     } with open(output_file,'a') as csv_file:                         writer = csv.DictWriter(csv_file, fieldnames=fieldnames, delimiter=',', lineterminator='\n')                         writer.writerow({'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})
    if show_details == 'y' or show_details == 'yes': for instance_id, instance in ec2info.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() except Exception as e: pass if profile_missing_message == '*':         banner(profile_missing_message) print(Fore.GREEN)     report_instance_stats(instance_count, aws_account, account_found) print(Fore.RESET + '\n') return output_file

This is a paste of the whole code for context: aws_ec2_list_instances.py这是上下文的整个代码的粘贴: aws_ec2_list_instances.py

The first time you run it from the command line it reports the correct total of servers in EC2 (can be verified in the AWS console):第一次从命令行运行它时,它会报告 EC2 中正确的服务器总数(可以在 AWS 控制台中验证):

----------------------------------------------------------
There are: 51 EC2 instances in AWS Account: company-lab.
----------------------------------------------------------

The next time it's run with ABSOLUTELY NOTHING changed it reports this total:下一次它以绝对没有改变的情况运行时,它会报告这个总数:

----------------------------------------------------------
There are: 102 EC2 instances in AWS Account: company-lab.
----------------------------------------------------------

You literally just up arrow the command and it doubles the results.您实际上只是向上箭头命令,它会使结果加倍。 When it writes to confluence you can see duplicate servers listed.当它写入 confluence 时,您可以看到列出了重复的服务器。 It does that each time you up arrow to run it again, with the same incorrect total (102 servers).每次向上箭头再次运行它时,它都会这样做,但总数不正确(102 个服务器)。

If you close the powershell command line and open again it's back to reporting the correct result (51 servers) which corresponds to what you see in the AWS console.如果您关闭 powershell 命令行并再次打开,它将返回报告正确结果(51 个服务器),这与您在 AWS 控制台中看到的内容相对应。 What the heck is happening, here?这到底是怎么回事? Why is it doing that and how do I correct the problem?为什么要这样做,我该如何解决问题?

This is pretty mysterious!这相当神秘! I don't think I'm going to be able to debug it without access to your environment.我认为如果不访问您的环境,我将无法对其进行调试。 My suggestion is that you use pdb to try to figure out how instance_count is being incremented past 51. I'd recommend adding import pdb; pdb.set_trace()我的建议是您使用pdb来尝试弄清楚instance_count如何增加超过 51。我建议添加import pdb; pdb.set_trace() import pdb; pdb.set_trace() at line 210, that is, right after for reservation in instance_list["Reservations"]: . import pdb; pdb.set_trace()在第 210 行,即for reservation in instance_list["Reservations"]: You can then inspect the value of instance_count each time through the loop, see whether instance_list["Reservations"] actually has duplicate data somehow, etc.然后,您可以每次通过循环检查instance_count的值,查看instance_list["Reservations"]是否实际上以某种方式具有重复数据等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM