node.jsamazon-web-servicesaws-lambdaaws-sdkaws-service-catalog

AWS SDK and CLI behave differently for the same API


I'm trying to automatically create a new provisioning artifact (or version) for my product in the Service Catalog whenever there's an update.

I checked up the documentation and this seems to be the method I'm looking for. I try it via the AWS CloudShell and it works :

[cloudshell-user@ip-10-0-150-18 ~]$ aws servicecatalog search-products-as-admin 
{
    "ProductViewDetails": [
        {
            "ProductViewSummary": {
                "Id": "prodview-xxxxxx",
                "ProductId": "prod-xxxxxx",
                "Name": "9ce35033-b4ed-4354-b1f6-ee0f651f7280",
                "Owner": "me@mail.com",
                "Type": "CLOUD_FORMATION_TEMPLATE",
                "HasDefaultPath": false
            },
            "Status": "CREATED",
            "ProductARN": "arn:aws:catalog:xxxxxx:xxxxxx:product/prod-xxxxxx",
            "CreatedTime": "2021-10-22T10:33:02+00:00"
        }
    ]
}
[cloudshell-user@ip-10-0-150-18 ~]$ aws servicecatalog create-provisioning-artifact --product-id prod-xxxxxx --parameters Name=new-version,Info={LoadTemplateFromURL=https://s3.amazonaws.com/xxxxxx-xxxxxx-xxxxxx-output/v53/cloud-formation-template.json},Type=CLOUD_FORMATION_TEMPLATE
{
    "ProvisioningArtifactDetail": {
        "Id": "pa-xxxxxx",
        "Name": "new-version",
        "Type": "CLOUD_FORMATION_TEMPLATE",
        "CreatedTime": "2021-10-22T12:35:57+00:00",
        "Active": true,
        "Guidance": "DEFAULT"
    },
    "Info": {
        "TemplateUrl": "https://s3.amazonaws.com/xxxxxx-xxxxxx-xxxxxx-output/v53/cloud-formation-template.json"
    },
    "Status": "CREATING"
}

However, when I use the AWS SDK for JavaScript from my Lambda, and the createProvisioningArtifact method, this is what happens :

const updateParams = {
          IdempotencyToken: uuid_1.v4(),
          Parameters: {
            Name: `v${technicalAsset.version}`,
            Info: { LoadTemplateFromURL: outputS3Url },
            Type: "CLOUD_FORMATION_TEMPLATE",
          },
          ProductId: existingProductId,
        }
        console.log('updateParams', updateParams);
        const serviceCatalogResponse = await serviceCatalog
            .createProvisioningArtifact(updateParams, (err, data) => {
                if (err) {
                    console.log(err, err.stack);
                    serviceCatalogDeploymentStatus = utils_1.AssetServiceCatalogDeploymentStatus.FAILED;
                }
                else {
                    console.log("Successful response from service catalog" + data);
                    serviceCatalogDeploymentStatus = utils_1.AssetServiceCatalogDeploymentStatus.SUCCESSFUL;
                }
            })
            .promise();
InvalidParametersException: Invalid templateBody. Please make sure that your template is valid
    at Request.extractError (/opt/nodejs/node_modules/aws-sdk/lib/protocol/json.js:52:27)
    at Request.callListeners (/opt/nodejs/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
    at Request.emit (/opt/nodejs/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
    at Request.emit (/opt/nodejs/node_modules/aws-sdk/lib/request.js:688:14)
    at Request.transition (/opt/nodejs/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/opt/nodejs/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /opt/nodejs/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/opt/nodejs/node_modules/aws-sdk/lib/request.js:38:9)
    at Request.<anonymous> (/opt/nodejs/node_modules/aws-sdk/lib/request.js:690:12)
    at Request.callListeners (/opt/nodejs/node_modules/aws-sdk/lib/sequential_executor.js:116:18) {
  code: 'InvalidParametersException',
  time: 2021-10-22T10:39:44.319Z,
  requestId: 'bcd23b38-ed62-4684-a392-b9a0ee46f333',
  statusCode: 400,
  retryable: false,
  retryDelay: 51.827093801169944
}

And in case you think that the updateParams is the problem, this what it looks like :

{
  IdempotencyToken: 'b099ca57-47dd-4889-ae71-95d44cc1aae9',
  Parameters: {
    Name: 'v53',
    Info: {
      LoadTemplateFromURL: 'https://s3.amazonaws.com/xxxxxx-xxxxxx-output/v53/cloud-formation-template.json'
    },
    Type: 'CLOUD_FORMATION_TEMPLATE'
  },
  ProductId: 'prod-xxxxxx'
}

It's a really strange behavior and I'm curious to find out what's behind it... Thanks in advance!


Solution

  • AWS at its finest. As @jarnod was saying, it was necessary to add the cloudFormation:validateTemplate role to your Lambda execution role if you're using the createProvisioningArtifact method.