Boto3, python и как обрабатывать ошибки


Я просто взял python в качестве своего языка сценариев, и я пытаюсь понять, как правильно обрабатывать ошибки с помощью boto3.

Я пытаюсь создать пользователя IAM:

def create_user(username, iam_conn):
    try:
        user = iam_conn.create_user(UserName=username)
        return user
    except Exception as e:
        return e

когда вызов create_user завершается успешно, я получаю аккуратный объект, который содержит код состояния http вызова API и данные вновь созданного пользователя.

пример:

{'ResponseMetadata': 
      {'HTTPStatusCode': 200, 
       'RequestId': 'omitted'
      },
 u'User': {u'Arn': 'arn:aws:iam::omitted:user/omitted',
           u'CreateDate': datetime.datetime(2015, 10, 11, 17, 13, 5, 882000, tzinfo=tzutc()),
           u'Path': '/',
           u'UserId': 'omitted',
           u'UserName': 'omitted'
          }
}

это прекрасно работает. Но когда это не удается (например, если пользователь уже существует), я просто получить объект типа ботокор.исключения.Клиентерор только с текстом, чтобы сказать мне, что пошло не так.

пример: ClientError ('произошла ошибка (EntityAlreadyExists) при вызове операции CreateUser: пользователь с опущенным именем уже существует.',)

Это (AFAIK) делает обработку ошибок очень сложной, потому что я не могу просто включить полученный код состояния http (409 для пользователя уже существует в соответствии с документами AWS API для IAM). Это заставляет меня думать, что я должен делать что-то не так. Оптимальным способом было бы для boto3 никогда не бросать исключения, но juts всегда возвращает объект, который отражает, как прошел вызов API.

может кто-нибудь просветить меня по этому вопросу или мне точку в правильном направлении?

Спасибо большое!

4 106

4 ответа:

используйте ответ, содержащийся в исключении. Вот пример:

import boto3
from botocore.exceptions import ClientError

try:
    iam = boto3.client('iam')
    user = iam.create_user(UserName='fred')
    print "Created user: %s" % user
except ClientError as e:
    if e.response['Error']['Code'] == 'EntityAlreadyExists':
        print "User already exists"
    else:
        print "Unexpected error: %s" % e

ответ dict в исключении будет содержать следующее:

  • ['Error']['Code'] например 'EntityAlreadyExists ' или'ValidationError'
  • ['ResponseMetadata']['HTTPStatusCode'] например, 400
  • ['ResponseMetadata']['RequestId'] например 'd2b06652-88d7-11e5-99d0-812348583a35'
  • ['Error']['Message'] например " произошла ошибка (EntityAlreadyExists)..."
  • ['Error']['Type'] например, "Отправитель"

для получения дополнительной информации см. обработка ошибок ботокора.

[Обновлено: 2018-03-07]

в AWS SDK для Python для начала, чтобы разоблачить исключения служб на клиенты (хотя и не на ресурсы) что вы можете явно поймать, так что теперь можно написать этот код что-то вроде этого:

import boto3
from botocore.exceptions import ClientError, ParamValidationError

try:
    iam = boto3.client('iam')
    user = iam.create_user(UserName='fred')
    print "Created user: %s" % user
except iam.exceptions.EntityAlreadyExistsException:
    print "User already exists"
except ParamValidationError as e:
    print "Parameter validation error: %s" % e
except ClientError as e:
    print "Unexpected error: %s" % e

к сожалению, в настоящее время нет документации на эти исключения.

просто обновление проблемы "без исключений на ресурсах", как указано @jarmod (пожалуйста, не стесняйтесь обновлять свой ответ, если ниже кажется применимым)

Я проверил приведенный ниже код и он работает нормально. Он использует "ресурсы" для делаешь вещи, но ловит client.exceptions - хотя это выглядит несколько неправильно... он хорошо тестирует, классы исключений отображаются и совпадают при просмотре использования отладчика во время исключения...

это может быть не так применимо для всех ресурсов и клиентов, но работает для папок данных (ака S3 ведра).

lab_session = boto3.Session() 
c = lab_session.client('s3') #this client is only for exception catching

try:
    b = s3.Bucket(bucket)
    b.delete()
except c.exceptions.NoSuchBucket as e:
    #ignoring no such bucket exceptions
    logger.debug("Failed deleting bucket. Continuing. {}".format(e))
except Exception as e:
    #logging all the others as warning
    logger.warning("Failed deleting bucket. Continuing. {}".format(e))

надеюсь, что это помогает...

или сравнение по имени класса, например

except ClientError as e:
    if 'EntityAlreadyExistsException' == e.__class__.__name__:
        # handle specific error

поскольку они создаются динамически, вы никогда не сможете импортировать класс и поймать его с помощью реального Python.

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

try:
    user = iam_conn.create_user(UserName=username)
    return user
except botocore.exceptions.ClientError as e:

    #this exception could actually be other things other than exists, so you want to evaluate it further in your real code.
    if e.message.startswith(
        'enough of the exception message to identify it as the one you want')

        print('that user already exists.')
        user = iam_conn.get_user(UserName=username)
        return user

    elif e.message.some_other_condition:

         #something else
    else:
         #unhandled ClientError
         raise(e)
except SomeOtherExceptionTypeYouCareAbout as e:
    #handle it

# any unhandled exception will raise here at this point.
# if you want a general handler

except Exception as e:
    #handle it.

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