#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, если у вас более одного тега на ресурсе. Это сработало. Спасибо!