Creating a custom resource with Amazon Q Developer

8 minute read
Content level: Intermediate
0

This article outlines how you can use Amazon Q Developer to create a custom resource for tasks that aren’t supported by AWS CloudFormation.

Introduction

As organizations continue to adopt cloud technologies, they look for innovative ways to streamline their infrastructure management. Recently, AWS Support noticed an increase in customer interest in Amazon Q and its potential to change their approach to cloud infrastructure. This article aims to explain how you can use Amazon Q to help create custom resources for tasks that aren’t natively supported by CloudFormation. This article uses real-world applications and best practices to demonstrate how Amazon Q Developer can enhance efficiency, reduce complexity, and reduce the need for manual code creation.

Solution walkthrough

This guide will walk you through the creation of custom resources for CloudFormation with Amazon Q.

Install Amazon Q Developer

Download Amazon Q Developer, and then install it on the integrated development environment (IDE) of your choice. For more information, see Get started with Amazon Q Developer

Open Amazon Q from your IDE

  1. Open the IDE where you installed Amazon Q.

  2. Select the desired tier. For more information on tiers, see Understanding tiers of service for Amazon Q Developer.

  3. Sign in to AWS to allow integration with your IDE.

  4. Choose the Amazon Q icon to open a new chat window.

Identify the cloud operation that requires the custom resource

  1. Identify the resources from your stack that might require integration with the custom resource. Then, note down the logical IDs of these resources.
  2. Identify any desired outputs or returned values that the custom resource must have. For example, the desired output might be a single or multiple Amazon Resource Names (ARNs) of resources that fit a certain constraint and are required to be used elsewhere in the stack deployment.
  3. Identify the desired outcome of the custom resource creation, update, or deletion.

Ask Amazon Q to develop a custom resource in CloudFormation

Chat with Amazon Q to develop a custom resource in CloudFormation with the information that you gathered in the preceding step.

  1. Provide detailed information in the request, including any multi-part steps and how Amazon Q must send the custom resource return signal.

  2. Provide any parameters or references that must be included in the custom resource creation. These might be references to other resources in the stack whose identifier must be used to accomplish the desired task. It might also be any parameters in the stack that you might have to manually define based on environment, account, or Region. You can include these values as additional properties of the custom resource and use them in the code.

  3. Include any desired error handling or actions that Amazon Q must follow if there's an error. This information is important because it helps Amazon Q not keep the stack in a hanging state. The stack goes into the hanging state when the custom resource times out because of a lack of response.

Test your custom resource

  1. Copy the custom resource that Amazon Q provides into a stack template file or directly into the template editor in the CloudFormation console. It's a best practice to apply a deletion policy to retain the custom resource if there's a lack of response from your AWS Lambda function. This applies only when the deletion of the custom resource doesn't invoke an action.

  2. Deploy the custom resource stack template. If you need to include any references as additional properties of the custom resource, then you can hardcode them as properties of that resource.

  3. After you deploy the custom resource, make sure that the custom resource performs all actions successfully and returns outputs as expected. You can also reference the expected outputs in the Outputs section of the template to confirm the returned values.

  4. If the custom resource deploys successfully, but doesn't perform all actions or return values as expected, then provide this information to the Amazon Q chat. Use this information to update the code and repeat these required steps.

  5. If the stack fails with any error, then provide the errors to the Amazon Q chat to adjust the code and repeat the required steps.

Integrate with an existing stack template

  1. Copy the custom resource from the Resources section of the testing stack template, and then paste it into the Resources section of the existing stack template.

  2. Copy the parameters that the custom resource uses from the testing template to the existing template.

  3. Integrate the references to resources in the existing stack with the custom resource.

  4. Define dependencies of the custom resource on existing resources and dependencies of existing resources on the custom resource.

Note: If you're creating this stack or project in your IDE, then you can use /dev to integrate this custom resource into the template.

Example

These examples show a prompt that you can provide to Amazon Q, the returned template from Amazon Q, and the results of the template test.

Prompt:

"I would like a CloudFormation stack that uses a custom resource to delay the continuation of the stack creation by a set number of minutes specified as a parameter."

The following screenshot shows the prompt and the returned template:

Enter image description here

Returned template:

Parameters:
  DelayInMinutes:
    Type: Number
    Default: 5
    Description: Number of minutes to delay stack creation
Resources:
  DelayFunction:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.9
      Handler: index.handler
      Role: !GetAtt DelayFunctionRole.Arn
      Code:
        ZipFile: |
          import json
          import time
          import cfnresponse

          def handler(event, context):
              try:
                  if event['RequestType'] == 'Create':
                      # Get delay from ResourceProperties
                      delay_minutes = int(event['ResourceProperties']['DelayInMinutes'])
                      # Convert to seconds and sleep
                      time.sleep(delay_minutes * 60)
                      
                  response_data = {}
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data)
              except Exception as e:
                  response_data = {'Error': str(e)}
                  cfnresponse.send(event, context, cfnresponse.FAILED, response_data)

  DelayFunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

  Delay:
    Type: Custom::Delay
    Properties:
      ServiceToken: !GetAtt DelayFunction.Arn
      DelayInMinutes: !Ref DelayInMinutes

Results:

You can see from the following screenshot that the CloudFormation initiated the custom resource creation. However, there is no response even after the predefined period of 7 minutes.

Enter image description here

You can use this information to chat with Amazon Q and apply the necessary code changes.

Feedback prompt to Amazon Q:

“The custom resource isn’t receiving a response.”

Amazon Q response:

“The issue is likely that the Lambda function is timing out before sending the response. Here's the corrected template that includes the proper timeout and sends responses for the operation types:”

Parameters:
  DelayInMinutes:
    Type: Number
    Default: 5
    Description: Number of minutes to delay stack creation

Resources:
  DelayFunction:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.9
      Handler: index.handler
      Role: !GetAtt DelayFunctionRole.Arn
      Timeout: 900  # 15 minutes maximum
      Code:
        ZipFile: |
          import json
          import time
          import cfnresponse
          
          def handler(event, context):
              try:
                  print(f"Received event: {json.dumps(event)}")
                  
                  if event['RequestType'] == 'Create':
                      delay_minutes = int(event['ResourceProperties']['DelayInMinutes'])
                      print(f"Delaying for {delay_minutes} minutes")
                      time.sleep(delay_minutes * 60)
                      print("Delay completed")
                  elif event['RequestType'] == 'Update':
                      print("Update request - sending success immediately")
                  elif event['RequestType'] == 'Delete':
                      print("Delete request - sending success immediately")
                      
                  response_data = {'DelayCompleted': 'true'}
                  print("Sending success response")
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data)
                  
              except Exception as e:
                  print(f"Error occurred: {str(e)}")
                  response_data = {'Error': str(e)}
                  cfnresponse.send(event, context, cfnresponse.FAILED, response_data)

  DelayFunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

  Delay:
    Type: Custom::Delay
    Properties:
      ServiceToken: !GetAtt DelayFunction.Arn
      DelayInMinutes: !Ref DelayInMinutes
      # Add a random string to force updates when needed
      UpdateToken: !Sub '${AWS::StackName}-${AWS::Region}'

Results after deploying the new template:

The following is a screenshot of what happens before CloudFormation creates the stack successfully.

  1. CloudFormation creates the AWS Identity and Access Management (IAM) role.

  2. The Lambda function utilizes this role and executes the desired delay on the stack deployment.

  3. CloudFormation deploys the custom resource to invoke this function. The function waits for the specified delay to occur before it returns the success signal.

Enter image description here

Cleanup

Delete the CloudFormation stack that you created to walk through the steps in this article.

Conclusion

This article guides how to use Amazon Q Developer to create a custom resource for use with CloudFormation. First, define the desired outcome of running the custom resource in your request to Amazon Q. Then, test the custom resource to confirm that all expected operations are completed upon creation of the custom resource. Finally, integrate this custom resource with additional required resources in the stack. If you need assistance to create a custom resource with Amazon Q, then contact AWS Support. AWS Cloud Support Engineers can help you with general guidance, best practices, troubleshooting, and operational support on AWS. To learn more about our plans and offerings, see AWS Support.

Related information

Amazon Q -- Generative AI Assistant

AWS::CloudFormation::CustomResource

CloudFormation template Parameters syntax

DependsOn attribute

Ref

About the author

Enter image description here

Austin Darrah

Austin is an AWS Cloud Support Engineer who has worked in the Infrastructure as Code (IaC) domain for over 2 years. He is an accredited subject matter expert in the CloudFormation service and works to integrate and create resources with CloudFormation. Austin helps customers with troubleshooting various services in the IaC domain, including AWS Cloud Development Kit (AWS CDK), AWS Control Tower, and CloudFormation. Outside of work, Austin enjoys getting the high score at the local golf course and restoring his classic cars.