Boto3: iot client register_certificate missing resourceArn and resourceId in ResourceAlreadyExistsException

Created on 13 Feb 2017  路  8Comments  路  Source: boto/boto3

I'm working on a registration script. When I register a certificate, which is already registered I get back ResourceAlreadyExistsException.

import boto3
import botocore
from collections import namedtuple

#debug
boto3.set_stream_logger(name='botocore')

CAResponse = namedtuple("CAResponse", "certId arn")

client = boto3.client('iot')
try:
    with open("device_pem", 'r') as device_pem_file, open("rootCA.pem", 'r') as root_pem_file:
        device_pem_string = device_pem_file.read()
        root_pem_string = root_pem_file.read()
        try:
            response = self.client.register_certificate(
                certificatePem=device_pem_string,
                caCertificatePem=root_pem_string
            )
            if "certificateId" in response and "certificateArn" in response:
                return CAResponse(certId=response["certificateId"], arn=response["certificateArn"])

        except botocore.exceptions.ClientError as e:
            print "%s register errror %r " % (e, e.response)
            raise e

except IOError as e:
    raise e

The exception is a botocore.errorfactory.ResourceAlreadyExistsException which I can't seem to find the BotoCore source.
When I cast it as a botocore.exceptions.ClientError I only get a Message & Code in the error.response.

With the logger running I can see that AWS gives the following response:

2017-02-13 17:03:52,634 botocore.parsers [DEBUG] Response body:
{
"message":"The certificate is already provisioned or registered",
"resourceArn":"target_arn",
"resourceId":"target_id"
}

Is there any way to retrieve this response body, or parse it out of the exception?
As I see it there's no function to retrieve the resourceArn & rescueId only by going through all of them wich will be a hassle when working with thousands of devices.

closed-for-staleness enhancement

Most helpful comment

Hi! you have to catch it from the client itself. eg from a cloudwatch logs client:

    cw_client = boto3.client('logs')
    try:
        cw_client.create_log_stream(
            logGroupName='someloggroup',
            logStreamName='somestream'
        )
    except cw_client.exceptions.ResourceAlreadyExistsException as e:
        print('Log Stream already created. Continuing to publishing the log')

All 8 comments

Digging into the code, it appears as if this data is not currently passed onto the exception itself. Marking this as an enhancement.

Thanks @dstufft I found the exception data in: https://github.com/boto/botocore/blob/0387055fc157846d300c116f5da9d63e869814a6/botocore/data/iot/2015-05-28/service-2.json

"RegisterCertificate":{
      "name":"RegisterCertificate",
      "http":{
        "method":"POST",
        "requestUri":"/certificate/register"
      },
      "input":{
        "shape":"RegisterCertificateRequest",
        "documentation":"<p>The input to the RegisterCertificate operation.</p>"
      },
      "output":{
        "shape":"RegisterCertificateResponse",
        "documentation":"<p>The output from the RegisterCertificate operation.</p>"
      },
      "errors":[
        {
          "shape":"ResourceAlreadyExistsException",
          "error":{"httpStatusCode":409},
          "exception":true,
          "documentation":"<p>The resource already exists.</p>"
        },
        {
          "shape":"InvalidRequestException",
          "error":{"httpStatusCode":400},
          "exception":true,
          "documentation":"<p>The request is not valid.</p>"
        },
        {
          "shape":"CertificateValidationException",
          "error":{"httpStatusCode":400},
          "exception":true,
          "documentation":"<p>The certificate is invalid.</p>"
        },
        {
          "shape":"CertificateStateException",
          "error":{"httpStatusCode":406},
          "exception":true,
          "documentation":"<p>The certificate operation is not allowed.</p>"
        },
        {
          "shape":"CertificateConflictException",
          "error":{"httpStatusCode":409},
          "exception":true,
          "documentation":"<p>Unable to verify the CA certificate used to sign the device certificate you are attempting to register. This is happens when you have registered more than one CA certificate that has the same subject field and public key.</p>"
        },
        {
          "shape":"ThrottlingException",
          "error":{"httpStatusCode":429},
          "exception":true,
          "documentation":"<p>The rate exceeds the limit.</p>"
        },
        {
          "shape":"UnauthorizedException",
          "error":{"httpStatusCode":401},
          "exception":true,
          "documentation":"<p>You are not authorized to perform this operation.</p>"
        },
        {
          "shape":"ServiceUnavailableException",
          "error":{"httpStatusCode":503},
          "exception":true,
          "fault":true,
          "documentation":"<p>The service is temporarily unavailable.</p>"
        },
        {
          "shape":"InternalFailureException",
          "error":{"httpStatusCode":500},
          "exception":true,
          "fault":true,
          "documentation":"<p>An unexpected error has occurred.</p>"
        }
      ],
      "documentation":"<p>Registers a device certificate with AWS IoT. If you have more than one CA certificate that has the same subject field, you must specify the CA certificate that was used to sign the device certificate being registered.</p>"
    },

Can't seem to find where the exception is raised or parsed. Could you direct me in the right direction?

@skorebrits I'm still figuring my way around this code base, but I believe that https://github.com/boto/botocore/blob/develop/botocore/errorfactory.py#L76-L95 is where the exceptions get generated.

It seems this exception class gets created on the fly, so I don't think it's possible to import it. Has anybody found a way to catch it? I can import and catch botocore.errorfactory.BaseClientExceptions; is there a function to test whether it's a ResourceAlreadyExistsException?

Actually, this answer on StackOverflow looks promising.

@mscheper - did you work out how to grab the exceptions you want out of boto? BTW - I think I went to UWS Nepean with you :)

Hi! you have to catch it from the client itself. eg from a cloudwatch logs client:

    cw_client = boto3.client('logs')
    try:
        cw_client.create_log_stream(
            logGroupName='someloggroup',
            logStreamName='somestream'
        )
    except cw_client.exceptions.ResourceAlreadyExistsException as e:
        print('Log Stream already created. Continuing to publishing the log')

Greetings! It looks like this issue hasn鈥檛 been active in longer than one year. We encourage you to check if this is still an issue in the latest release. Because it has been longer than one year since the last update on this, and in the absence of more information, we will be closing this issue soon. If you find that this is still a problem, please feel free to provide a comment to prevent automatic closure, or if the issue is already closed, please feel free to reopen it.

Was this page helpful?
0 / 5 - 0 ratings