Python 解析 Amazon RDS 实例的字典输出的问题

Issues with Python parsing dictionary output of Amazon RDS instances

我正在尝试解析我猜想是 Python 中 AWS 的 boto 接口的字典输出,它应该会提供有关我的所有 Amazon RDS(数据库)实例的信息。我在这里使用的所有工具都是新手,所以请原谅我的无知。

我试图将其视为一个数组,这可能是一个糟糕的前提,因为它是一个字典类型。下面的代码可以很好地提取两 (2) 个实例,这很奇怪 - 它至少可重复一次,并且我通过打印 dict 输出验证显示我在 运行 中的所有四 (4) 个实例区域 - 但它不会在输出中拉出后两个。当我使用 len() 测量输出的长度时,它 returns 2.

有人能帮我理解我需要对这段代码做些什么才能让它真正解析出所有返回的实例吗? (然后功能是查找 rebootAllowed 标记,如果为 1,则停止实例...这似乎工作正常,但同样,仅针对返回的前两个结果。)

import json
import boto3

region = 'us-east-1'
rds = boto3.client('rds')

def lambda_handler(event, context):
    # Ingest all RDS instances
    dbinstances = rds.describe_db_instances() # Filtering by instance status is not supported
    
    print('* * *')
    
    # Set db instance counter for below loop   
    dbi = 0

    # Loop through each running RDS instance, checking tags and shutting down if tags match
    for dbinstance in dbinstances:
        # Set default values for tags we'll parse
        rebootAllowed = 0
        # We'll need this later
        try:
            dbinstanceId = dbinstances.get('DBInstances')[dbi]['DBInstanceIdentifier']
            dbinstanceArn = dbinstances.get('DBInstances')[dbi]['DBInstanceArn']
            rdstags = rds.list_tags_for_resource(ResourceName=dbinstanceArn)
            # Attempt to look into tags for EC2s that have them. If they don't, we'll get an exception
            try:
                # Does the instance have the rebootAllowed tag? Great, what's its value?
                if 'rebootAllowed' in rdstags['TagList'][dbi]['Key']:
                    rebootAllowed = rdstags['TagList'][dbi]['Value']
                # Let's log what we're doing.
                print('Examining RDS instance ' + dbinstanceId + '...')
                # Attempt to stop instance
                try:
                    if rebootAllowed == '1':
                        message = '-- This instance CAN be stopped. Doing that now.'
                        rdsid = [dbinstanceId]
                        rds.stop_db_instance(DBInstanceIdentifier=dbinstanceId)
                    elif rebootAllowed == '0':
                        message = '-- This instance is BLOCKED from being stopped. Doing nothing.'
                    else:
                        message = '-- This instance does not have the tags used by this script. Skipping.'
                except Exception, err:
                    message = 'Error with RDS instance: instanceId: ' +  err
                    raise err
                print (message)
                print ('* * *')
                dbi += 1
            except:
                print('Examining RDS instance ' + dbinstanceId + ')')
                print('-- An EXECPTION occurred while analyzing this instance. This could be because the instance has no tags at all.')
                print('* * *')
                dbi += 1
        except:
            print('End of list. Script complete.')

很难确切地说出发生了什么,尤其是因为我们并不完全知道您要迭代的字典的形状是什么,但您似乎确实了解了潜在的含义问题:你并没有真正python巧妙地处理这个迭代。

我去查看了输出,发现了这个样本:

{
    "DBInstances": [
        {
            "DBInstanceIdentifier": "mydbinstancecf",
            "DBInstanceClass": "db.t3.small",
            "Engine": "mysql",
            "DBInstanceStatus": "available",
            "MasterUsername": "masterawsuser",
            "Endpoint": {
                "Address": "mydbinstancecf.abcexample.us-east-1.rds.amazonaws.com",
                "Port": 3306,
                "HostedZoneId": "Z2R2ITUGPM61AM"
            },
            ...some output truncated...
        }
    ]
}

因此,您可以立即通过删除 dbinstances

中的无关数据来简化循环
# dbinstances = rds.describe_db_instances() becomes
dbinstances = rds.describe_db_instances()["DBInstances"]

现在,您正在处理一组数据库实例。在 python for 循环中,您将可迭代(列表)的每个元素作为变量。在这种情况下,根本没有必要维护 dbi 计数器。如果你想要计算元素,你可以这样做for i, e in enumerate(my_list):,其中i是索引,e是元素。

所以你的循环变得更像这样:

for instance in dbinstances: 
# Set default values for tags we'll parse
    rebootAllowed = 0
    # We'll need this later
    try:
       dbinstanceId = instance['DBInstanceIdentifier']
       dbinstanceArn = instance['DBInstanceArn']
       rdstags = rds.list_tags_for_resource(ResourceName=dbinstanceArn)
#     ... the rest is left as an exercise for Josh

作为一般建议,在Python中设计此类算法时,请大量使用REPL。您可以四处看看并尝试一下,以快速了解数据的实际结构。