2015-10-11 1 views
84

Je viens de choisir python comme langage de script et j'essaie de comprendre comment gérer correctement les erreurs avec boto3.Boto3, python et comment gérer les erreurs

Je suis en train de créer un utilisateur IAM:

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

Lorsque l'appel à create_user réussit, je reçois un objet propre qui contient le code d'état HTTP de l'appel de l'API et les données de l'utilisateur nouvellement créé .

Exemple:

{'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' 
      } 
} 

Cela fonctionne très bien. Mais quand cela échoue (comme si l'utilisateur existe déjà), je viens d'obtenir un objet de type botocore.exceptions.ClientError avec seulement du texte pour me dire ce qui s'est mal passé.

Exemple: ClientError (« Une erreur est survenue (EntityAlreadyExists) lors de l'appel de l'opération CreateUser. L'utilisateur avec le nom omis existe déjà »,)

Ce (AFAIK) fait erreur de manipulation très difficile parce que je ne peux pas il suffit d'activer le code d'état http résultant (409 pour l'utilisateur existe déjà en fonction des documents de l'API AWS pour IAM). Cela me fait penser que je dois faire quelque chose dans le mauvais sens. Le moyen optimal serait que boto3 ne lève jamais d'exceptions, mais il doit toujours renvoyer un objet qui reflète la façon dont l'appel API est passé. Est-ce que quelqu'un peut m'éclairer sur cette question ou me diriger dans la bonne direction?

Merci beaucoup!

+1

Documents AWS http://botocore.readthedocs.io/en/latest/client_upgrades.html#errorhandling –

Répondre

177

Utilisez la réponse contenue dans l'exception. Voici un exemple:

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 

La réponse dict à l'exception contiendra les éléments suivants:

  • ['Error']['Code'] par exemple 'EntityAlreadyExists' ou 'ValidationError'
  • ['ResponseMetadata']['HTTPStatusCode'] par exemple. 400
  • ['ResponseMetadata']['RequestId'] par exemple. 'd2b06652-88d7-11e5-99d0-812348583a35'
  • ['Error']['Message'] par exemple. "Une erreur s'est produite (EntityAlreadyExists) ..."
  • ['Error']['Type'] par exemple. 'Expéditeur'

Pour plus d'informations, voir botocore error handling.

[Mise à jour: 07/03/2018]

Le SDK Python AWS a commencé à exposer des exceptions de service sur clients (mais pas sur resources) que vous pouvez prendre explicitement, il est maintenant possible d'écrire ce code quelque chose comme ceci:

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 

Malheureusement, il n'existe actuellement aucune documentation pour ces exceptions.

-2

Vous devez faire quelque chose quand il ne parvient pas à résoudre le problème. En ce moment, vous renvoyez l'exception réelle. Par exemple, si ce n'est pas un problème que l'utilisateur existe déjà et que vous souhaitez l'utiliser en tant que fonction get_or_create, vous pouvez peut-être gérer le problème en renvoyant l'objet utilisateur existant.

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. 

Cela dit, peut-être un problème pour votre application, dans ce cas, vous voulez vouloir mettre le gestionnaire d'exception autour du code qui a appelé votre fonction de création d'utilisateur et laissez la fonction appelante déterminer comment traiter Par exemple, en demandant à l'utilisateur d'entrer un autre nom d'utilisateur, ou tout ce qui est logique pour votre application.

+0

Mais que l'utilisateur existe déjà est seulement l'un des moyens que l'appel API peut échouer. Je ne vois pas de moyen de les différencier avec cette méthode. – SQDK

+0

Démonstration juste comment la gestion des exceptions fonctionne à un niveau de base parce que cela semble être là où la confusion est. J'ai mis un commentaire à cet effet. – tlastowka

+0

Merci pour cela. Cela ne fait que renforcer mon soupçon que cette question est plus spécifique à Boto3 que spécifique à Python. Je ne suis pas au courant des modèles courants pour la gestion des erreurs en python, d'où ma manière générique de poser la question – SQDK

0

Ou une comparaison sur le nom de la classe, par ex. Parce qu'ils sont créés dynamiquement, vous ne pouvez jamais importer la classe et l'attraper en utilisant Python réel.

+0

Donc, j'attraperais toutes les exceptions avec 'except Exception as e' et ensuite si des instructions pour déterminer l'exception spécifique? En quoi est-ce différent/meilleur que d'attraper des exceptions spécifiques? Il y a plus de lignes, et vous auriez besoin d'importer la bibliothèque pour obtenir le nom de la classe quand même. Sauf si vous voulez aller avec le codage en dur le nom de l'exception. Dans l'ensemble, cela semble être une mauvaise façon de procéder. – SQDK

+0

@SQDK désolé ma réponse n'était pas claire, mais pas de quoi vous parlez. Je l'ai mis à jour. – jmoz