Проблемы с выводом словаря синтаксического анализа Python экземпляров Amazon RDS

#python #amazon-web-services #boto

#python #amazon-веб-сервисы #boto

Вопрос:

Я пытаюсь проанализировать то, что, как я полагаю, является выводом dict из интерфейса AWS boto на Python, который должен предоставить мне информацию обо всех моих экземплярах Amazon RDS (базы данных). Я новичок во всех инструментах, которые я использую здесь, поэтому, пожалуйста, простите мое невежество.

Я пытаюсь рассматривать его как массив, что может быть плохой предпосылкой для начала, поскольку это тип dict. Приведенный ниже код отлично работает для извлечения двух (2) экземпляров, что странно — он по крайней мере повторяется один раз, и я проверил, распечатав вывод dict, показывающий все четыре (4) экземпляра, которые у меня запущены в регионе, но он не извлекает последние два в выводе. Когда я использую len() для измерения длины вывода, он возвращает 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.')
  

Ответ №1:

Немного сложно точно сказать, что происходит, тем более, что мы точно не знаем, какова форма dict, которую вы пытаетесь выполнить, но, похоже, у вас есть ощущение основной проблемы: вы на самом деле не очень хорошо обрабатываете эту итерацию по-питонически.

Я пошел и посмотрел выходные данные и нашел этот образец:

 {
    "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. Вы можете покопаться и попробовать что-то, чтобы быстро получить представление о фактической структуре данных.

Комментарии:

1. Спасибо за подробный ответ, и я расскажу об этом подробнее; причина, по которой у меня был счетчик dbi, заключалась в том, что я получал бы ошибки, если бы не указывал индекс, но если сужение области действия исходного запроса поможет сделать итерации более очевидными для цикла, возможно, этого не произойдет.это необходимо.

2. если вы не выберете массив в исходном возвращаемом значении, в вашем цикле будет только один элемент, который является самим списком экземпляров, хотя вы хотели перебирать каждый элемент в этом списке.

3. Спасибо, это сработало, с еще одним примечанием (которое не было частью моего первоначального запроса): list_tags_for_resource(arn) нуждается в собственном цикле for, если у вас более одного тега на ресурсе. Это сработало. Спасибо!