aws-cloudformation / cloudformation-coverage-roadmap

The AWS CloudFormation Public Coverage Roadmap
https://aws.amazon.com/cloudformation/
Creative Commons Attribution Share Alike 4.0 International
1.11k stars 54 forks source link

AWS::CloudFormation::Delay (new resource) #589

Open eduardomourar opened 4 years ago

eduardomourar commented 4 years ago

1. Title

AWS::CloudFormation::Delay (new resource)

2. Scope of request

In order to solve issues such as throttling (#588) or other scenarios where you want to delay the the next resource in line for deployment, I would like to propose to create a new CloudFormation resource type. It should be very similar to AWS::CloudFormation::WaitCondition[1], except that we don't need to wait for an external process, only for a period of time.

3. Expected behavior

A property should be available to receive the timeout. The value must be in ISO8601 duration format [2], in the form: PT#H#M#S, where each # is the number of hours, minutes, and seconds, respectively.

In Create/Update/Delete, it should return SUCCESS after the amount of time specified by user has passed.

4. Suggest specific test cases

This is an example usage for this hypothetical resource type:

  DomainName1:
    Type: AWS::ApiGateway::DomainName
    Properties:
      DomainName: example.com
      CertificateArn: ...

  Delay:
    Type: AWS::CloudFormation::Delay
    Properties:
      Timeout: PT1M

  # This should only start after 1 minute has passed
  DomainName2:
    Type: AWS::ApiGateway::DomainName
    DependsOn: Delay
    Properties:
      DomainName: api.example.com
      CertificateArn: ...

5. Helpful Links to speed up research and evaluation

[1]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-waitcondition.html

[2]: http://en.wikipedia.org/wiki/ISO_8601#Durations

6. Category

  1. Management (CloudTrail, Config...)
badaldavda8 commented 4 years ago

Was able to work on something similar :) Hope it helps -


Resources:
  domainName1:
    Type: 'AWS::ApiGateway::DomainName'
    Properties:
      DomainName: k.badaldavda.xyz
      CertificateArn: >-
        arn:aws:acm:us-east-1:xxx:certificate/103217f9-884b-4d6d-9ac6-ba7500e61029
  domainName2:
    DependsOn: Delay2
    Type: 'AWS::ApiGateway::DomainName'
    Properties:
      DomainName: l.badaldavda.xyz
      CertificateArn: >-
        arn:aws:acm:us-east-1:xxx:certificate/103217f9-884b-4d6d-9ac6-ba7500e61029
  domainName3:
    DependsOn: Delay3
    Type: 'AWS::ApiGateway::DomainName'
    Properties:
      DomainName: m.badaldavda.xyz
      CertificateArn: >-
        arn:aws:acm:us-east-1:xxx:certificate/103217f9-884b-4d6d-9ac6-ba7500e61029

  Delay2:
    Type: 'Custom::Delay'
    Properties:
      ServiceToken: !GetAtt DelayFunction.Arn
      TimeToWait: 60
      domainName: !Ref domainName1

  Delay3:
    Type: 'Custom::Delay'
    Properties:
      ServiceToken: !GetAtt DelayFunction.Arn
      TimeToWait: 60
      domainName: !Ref domainName2

  LambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: "lambda-logs"
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource:
                  - "arn:aws:logs:*:*:*"

  DelayFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Handler: "index.handler"
      Timeout: 120
      Role: !GetAtt 'LambdaRole.Arn'
      Runtime: python3.7
      Code:
        ZipFile: |
          import json
          import cfnresponse
          import time
          def handler(event, context):
            time_to_wait = int(event['ResourceProperties']['TimeToWait'])
            print('wait started')
            time.sleep(time_to_wait)
            responseData = {}
            responseData['Data'] = "wait complete"
            print("wait completed")
            physicalId = event['ResourceProperties']['domainName'] + 'wait'
            print(physicalId)
            cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, physicalId)
eduardomourar commented 4 years ago

Following the proposal, a new private resource type Community::CloudFormation::Delay has been released in the meantime.

Installation instructions:

aws cloudformation register-type \
  --region us-east-1 \
  --type-name "Community::CloudFormation::Delay" \
  --schema-handler-package "s3://community-resource-provider-catalog/community-cloudformation-delay-0.1.0.zip" \
  --type RESOURCE

Usage example:

AWSTemplateFormatVersion: 2010-09-09
Resources:
  Delay:
    Type: Community::CloudFormation::Delay
    Properties:
      Duration: PT30S
jdiegosierra commented 3 years ago

@eduardomourar is it possible to use with CDK?

eduardomourar commented 3 years ago

Partially, because you cannot register the type using CDK yet. But, after registering in some other way, you can deploy a Delay by leveraging cdk.CfnResource directly (details here).

githubnoobieme commented 3 years ago

Following the proposal, a new private resource type Community::CloudFormation::Delay has been released in the meantime.

Installation instructions:

aws cloudformation register-type \
  --region us-east-1 \
  --type-name "Community::CloudFormation::Delay" \
  --schema-handler-package "s3://community-resource-provider-catalog/community-cloudformation-delay-0.1.0.zip" \
  --type RESOURCE

Usage example:

AWSTemplateFormatVersion: 2010-09-09
Resources:
  Delay:
    Type: Community::CloudFormation::Delay
    Properties:
      Duration: PT30S

I registered this resource in my environment in region eu-central-1, when I try to run this from stacksets I receive an error message "Template format error: Unrecognized resource types: [Community::CloudFormation::Delay]"

githubnoobieme commented 3 years ago

Following the proposal, a new private resource type Community::CloudFormation::Delay has been released in the meantime. Installation instructions:

aws cloudformation register-type \
  --region us-east-1 \
  --type-name "Community::CloudFormation::Delay" \
  --schema-handler-package "s3://community-resource-provider-catalog/community-cloudformation-delay-0.1.0.zip" \
  --type RESOURCE

Usage example:

AWSTemplateFormatVersion: 2010-09-09
Resources:
  Delay:
    Type: Community::CloudFormation::Delay
    Properties:
      Duration: PT30S

I registered this resource in my environment in region eu-central-1, when I try to run this from stacksets I receive an error message "Template format error: Unrecognized resource types: [Community::CloudFormation::Delay]"

Oh wait I got it, I would need to register that in all accounts I want to use this delay right? so this is a NOGO for deployment through organization... would be nice to have a real resource -> AWS::CloudFormation::Delay

eduardomourar commented 3 years ago

yes, you need to register the delay resource in every account and region you plan to use it

githubnoobieme commented 3 years ago

@eduardomourar do you have a ETA for the official new resource type Delay?

eduardomourar commented 3 years ago

I don't work for AWS, so @luiseduardocolon is this in the short-term plans?

dobomode commented 3 years ago

This works great, thanks so much for this resource type. I find it a bit strange that AWS doesn't provide this out of the box. One suggestion for improving this further: specify properties to instruct CF whether to run the delay for each of the build operations (Create, Update, Delete). I foresee scenarios where the delay is needed for Create / Delete but not Update, so it would be nice to have control over this.

petrgazarov commented 3 years ago

@eduardomourar I found that the delay only happens the first time, and doesn't happen on subsequent stack updates. Looking at the events, CloudFormation only creates the resource the first time, and skips it afterwards.

I think you can work around this issue if you add a property such as Timestamp and pass it into the resource with a different value on each run.

nbrational commented 3 years ago

much needed. @eduardomourar your workaround helps!

TomasChmelik commented 2 years ago

I feel like this is not a great fix for throttling issue in API gateway. AWS service like Cloudformation should be aware of throttling limits of other AWS services it creates resources in. Or any 429 error shouldn't cause creation to fail, since it has very specific meaning and default action should be wait and retry

ericzbeard commented 1 year ago

Following the proposal, a new private resource type Community::CloudFormation::Delay has been released in the meantime.

Installation instructions:

aws cloudformation register-type \
  --region us-east-1 \
  --type-name "Community::CloudFormation::Delay" \
  --schema-handler-package "s3://community-resource-provider-catalog/community-cloudformation-delay-0.1.0.zip" \
  --type RESOURCE

Usage example:

AWSTemplateFormatVersion: 2010-09-09
Resources:
  Delay:
    Type: Community::CloudFormation::Delay
    Properties:
      Duration: PT30S

@eduardomourar Any chance you would be willing to contribute this to the new registry extension repo? I created an issue there for this exact thing before I realized we already had a request for it here: https://github.com/aws-cloudformation/community-registry-extensions/issues/80

eduardomourar commented 1 year ago

The source code written in TypeScript is already available here (https://github.com/org-formation/aws-resource-providers/tree/master/cloud-formation/delay). If that helps, I am happy to create PR copying the code as is to your repository.

AlHanouf-BH commented 1 year ago

is this implemented yet?

mdeguzis commented 7 months ago

Any update on this?