Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conditional event attachment #214

Closed
glenveegee opened this issue Nov 27, 2017 · 28 comments
Closed

Conditional event attachment #214

glenveegee opened this issue Nov 27, 2017 · 28 comments
Labels
area/cloudformation maintainer/need-response priority/2-important stage/pm-review Waiting for review by our Product Manager, please don't work on this yet type/feature

Comments

@glenveegee
Copy link

If conditional resource creation is eventually supported you might also have to support conditional events as in the following example where in some environments a bucket might not already exist and so it can be created and the event attached to the lambda. While in other environments the bucket may already exist and the trigger needs to be manually defined because cloudformation doesn't yet use existing resources.

For example

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Description: Lambda that responds to S3 events

Parameters:
    PreExistingBucket:
        Description: "Does an existing bucket exist (not managed by cloudformation)"
        Type: String
        Default: 'no'
        AllowedValues:
            - 'yes'
            - 'no'
        ConstraintDescription: must specify yes or no.

Conditions:
  NeedsSomeBucket: !Equals [ !Ref PreExistingBucket, 'no' ]

Resources:
    BucketEventConsumer:
        Type: AWS::Serverless::Function
        Properties:
            Handler: BucketEventConsumer.main.lambda_handler
            Runtime: python3.6
            CodeUri: bundle.zip
            Events:
                CreateMetaEvent:
                    Condition: NeedsSomeBucket
                    Type: S3
                    Properties:
                        Bucket: !Ref SomeBucket
                        Events: "s3:ObjectCreated:*"
                        Filter:
                            S3Key:
                                Rules:
                                    -
                                        Name: suffix
                                        Value: meta.json
    SomeBucket:
        Condition: NeedsSomeBucket
        Type: "AWS::S3::Bucket"
        Properties:
            BucketName: 'some-bucket-somewhere'
        DeletionPolicy: Retain

I'd like to draw your attention to the following crucial lines:

                CreateMetaEvent:
                    Condition: NeedsSomeBucket

Can this already be acheived using Fn::If?

@brettstack
Copy link
Contributor

Closing in favor of #142

@jaypadia-frame
Copy link

This one was created as a new Feature-Request based on the discussion in #142 .

@ glenveegee That is an interesting thought and idea! Would you mind create a new issue with this use case? It will help us prioritize this in the future and will ensure it does not get lost or forgotten about in this issue (since they are slightly different).

Closing this in favor of #142 doesn't make sense. Both of these are separate and useful features.

@brettstack brettstack reopened this Aug 9, 2018
@glenak1911
Copy link

Any update on this? I've run into a similar use case and would like to use this feature as well.

@brettstack
Copy link
Contributor

There are currently higher priority items we are focusing on. I've increased the priority label for visibility during planning and hope to get to this one along with #142 soon

@glenak1911
Copy link

Thanks for the feedback @brettstack !

@made2591-eb
Copy link

@brettstack Any update on this? I would like to conditionally enable or disable the event rule. I tried also using mapping but it seems it doesn't work either... so I'm wondering which kind of intrinsic functions (see doc) are supported for real inside SAM template. Is there any other way to conditionally enable events? Thank you!

@keetonian
Copy link
Contributor

@made2591-eb We have passed this along to our product team for possible prioritization. Please +1 on the feature to help with prioritization.

@takeshi4126
Copy link

+1
I appreciate if you prioritise this issue. I have the exactly same issue as #1229 and have to manually disable a CloudWatch event once it is deployed in a staging environment. Thank you!

@ghost
Copy link

ghost commented Aug 25, 2020

Ran across this with an AWS::Serverless::Function using EventSource - unable to conditionally apply it. Would be great to see.

@awsjeffg awsjeffg added the stage/pm-review Waiting for review by our Product Manager, please don't work on this yet label Sep 4, 2020
@andrescastillol
Copy link

+1

@jiminkk
Copy link

jiminkk commented Sep 24, 2020

+1
This will help lessen a lot of cost savings and manual maintenance in dev stages.

@Catastropha
Copy link

Issue was opened in 2017
Soon 2021 arrives
Can you prioritize a bit more?

@RichDavis1
Copy link

+1

3 similar comments
@jiojanen
Copy link

+1

@sleekmountaincat
Copy link

+1

@tniemann
Copy link

tniemann commented Mar 1, 2021

+1

@tniemann
Copy link

tniemann commented Mar 1, 2021

As a workaround, you can use AWS::Events::Rule

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-events-rule.html#aws-resource-events-rule-syntax.yaml

@navigator3
Copy link

+1

1 similar comment
@rickard-andersson-wcar
Copy link

+1

@dave-kennedy
Copy link

As a workaround, you can use AWS::Events::Rule

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-events-rule.html#aws-resource-events-rule-syntax.yaml

How do you add an AWS::Events::Rule to an AWS::Serverless::Function?

@chrisoverzero
Copy link
Contributor

@dave-kennedy

It's the other way around. As one of the Targets of the AWS::Events::Rule, specify the Lambda Function.

ExampleRule:
  Type: AWS::Events::Rule
  Properties:
    EventBusName: !Ref ExampleEventBus
    EventPattern: # the pattern to match, or use `ScheduleExpression` instead
    Targets:
    - Arn: !GetAtt ExampleFunction.Arn
      Id: Example # But use a unique value, natch.

And it's there in the resource that one can specify optionality. Either by Condition at the top level or something like !If on the Targets property.

@dave-kennedy
Copy link

@chrisoverzero if the event emitter is an SNS topic, is there any difference between creating an AWS::SNS::Subscription between the topic and the function as opposed to using AWS::Events::Rule?

@chrisoverzero
Copy link
Contributor

I'm afraid I must not understand your question correctly. Are you asking whether you can use a rule to subscribe to a topic? SNS doesn't emit messages onto EventBridge buses, EventBridge does. An AWS::Events::Rule won't react to messages in SNS topics.

@dave-kennedy
Copy link

The proposed workaround doesn't seem to work, at least not for SNS events. I believe it's the same issue as this one, even though the OP was asking about EventBridge.

Here's the relevant parts of my template:

Parameters:
  TestEventTopicArn:
    Type: String
    Description: The fully qualified ARN for the SNS topic

Conditions:
  SubscribeToTestEventTopic:
    !Not [!Equals [!Ref TestEventTopicArn, ""]]

Resources:
  TestEventHandlerRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: test-event-handler-role
      Path: /
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - lambda.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
        - arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess

  TestEventHandler:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ../../src/
      FunctionName: test-event-handler
      Handler: test_event_handler.handle_event
      Runtime: python3.8
      Role: !GetAtt TestEventHandlerRole.Arn
      AutoPublishAlias: live
      DeploymentPreference: AllAtOnce
      Timeout: 10
      MemorySize: 128

  TestEventSubscription:
    Type: AWS::SNS::Subscription
    Condition: SubscribeToTestEventTopic
    Properties:
      TopicArn: !Ref TestEventTopicArn
      Endpoint: !GetAtt TestEventHandler.Arn
      Protocol: lambda

With the above resources, the subscription was created and confirmed only when TestEventsTopicArn was set to a non-empty string, as desired, but the function was never invoked. Viewing the function in the Lambda console, it had no associated triggers.

I suspected the issue might have been the lack of a ":live" alias at the end of the endpoint ARN and updated the subscription like so:

  TestEventSubscription:
    Type: AWS::SNS::Subscription
    Condition: SubscribeToTestEventTopic
    Properties:
      TopicArn: !Ref TestEventTopicArn
      Endpoint:
        !Sub
          - "${test_event_handler_arn}:live"
          - test_event_handler_arn: !GetAtt TestEventHandler.Arn
      Protocol: lambda

This correctly added the ":live" alias to the subscription endpoint but the function but had the same issue, i.e. no events or triggers.

In the end I had to revert to defining the event source on the function itself:

  TestEventHandler:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ../../src/
      FunctionName: test-event-handler
      Handler: test_event_handler.handle_event
      Runtime: python3.8
      Role: !GetAtt TestEventHandlerRole.Arn
      AutoPublishAlias: live
      DeploymentPreference: AllAtOnce
      Timeout: 10
      MemorySize: 128
      Events:
        TestEventTopic:
          Type: SNS
          Properties:
            Topic: !Ref TestEventTopicArn

Of course, the problem now is I can't conditionally turn the subscription off, same as the OP.

@Jacco
Copy link
Contributor

Jacco commented May 10, 2022

Not entirely sure but can this request not already be solved:

Resources:
    BucketEventConsumer:
        Type: AWS::Serverless::Function
        Properties:
            Handler: BucketEventConsumer.main.lambda_handler
            Runtime: python3.6
            CodeUri: bundle.zip
            Events:
                !If
                    - NeedsSomeBucket
                    - 
                        CreateMetaEvent:
                            Condition: NeedsSomeBucket
                            Type: S3
                            Properties:
                                Bucket: !Ref SomeBucket
                                Events: "s3:ObjectCreated:*"
                                Filter:
                                    S3Key:
                                        Rules:
                                            -
                                                Name: suffix
                                                Value: meta.json
                    - !Ref "AWS::NoValue"

The yaml is a little uggly. But is is similar to example 4 here https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html

Haven't testes this yet. The way described above could be syntactic sugar then.

@mluypaert
Copy link

Not entirely sure but can this request not already be solved:

Resources:
    BucketEventConsumer:
        Type: AWS::Serverless::Function
        Properties:
            Handler: BucketEventConsumer.main.lambda_handler
            Runtime: python3.6
            CodeUri: bundle.zip
            Events:
                !If
                    - NeedsSomeBucket
                    - 
                        CreateMetaEvent:
                            Condition: NeedsSomeBucket
                            Type: S3
                            Properties:
                                Bucket: !Ref SomeBucket
                                Events: "s3:ObjectCreated:*"
                                Filter:
                                    S3Key:
                                        Rules:
                                            -
                                                Name: suffix
                                                Value: meta.json
                    - !Ref "AWS::NoValue"

The yaml is a little uggly. But is is similar to example 4 here https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html

Haven't testes this yet. The way described above could be syntactic sugar then.

Using the !If statement within the Events block does not work, as doing so throws the validation off. Having such a conditional in your template results in sam validate returning you an error like Event with id [Fn::If:] is invalid. 'list' object has no attribute 'get'.

@aws: It's been more than 4.5 years since this feature was requested. Please implement a solution for this!

@rrobby86
Copy link

I had a similar issue trying to conditionally add a Schedule event to a SAM function. I post here all the relevant parts for a workaround (including the necessary permission to invoke the function) in case anyone needs it.

Parameters:
  TargetFunctionSchedule:
    Type: String
    Default: ""

Conditions:
  EnableSchedule: !Not [ !Equals [ !Ref TargetFunctionSchedule, "" ] ]

Resources:

  TargetFunction:  # function whose execution may be scheduled or not
    Type: AWS::Serverless::Function
    Properties: ...

  FunctionScheduleRule:
    Condition: EnableSchedule
    Type: AWS::Events::Rule
    Properties:
      ScheduleExpression: !Ref TargetFunctionSchedule
      Targets:
        Id: InvokeFunction  # an arbitrary name
        Arn: !GetAtt TargetFunction.Arn

  FunctionSchedulePermission:
    Condition: EnableSchedule
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref TargetFunction
      Action: lambda:InvokeFunction
      Principal: events.amazonaws.com
      SourceArn: !GetAtt FunctionScheduleRule.Arn

Morichan added a commit to Morichan/minecraft-environment-deployment that referenced this issue Oct 16, 2022
aws/serverless-application-model#214 のIssueの通り、コミット時点での
AWS SAMでは、Lambdaのイベントソース指定時にFn::Ifを利用できない。
そこで、別リソースに分割することで、イベントソース生成に条件を付けられる
ようにする。
Morichan added a commit to Morichan/minecraft-environment-deployment that referenced this issue Oct 16, 2022
aws/serverless-application-model#214 のIssueの通り、コミット時点での
AWS SAMでは、Lambdaのイベントソース指定時にFn::Ifを利用できない。
そこで、別リソースに分割することで、イベントソース生成に条件を付けられる
ようにする。
@hoffa
Copy link
Contributor

hoffa commented Dec 7, 2022

This is now doable.

Save the following as template.yaml:

Transform:
  - AWS::LanguageExtensions
  - AWS::Serverless-2016-10-31

Parameters:
  NeedBucket:
    Type: String

Conditions:
  NeedBucketCondition: !Equals [!Ref NeedBucket, "yes"]

Resources:
  MyBucket:
    Condition: NeedBucketCondition
    Type: AWS::S3::Bucket

  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: python3.8
      Handler: foo
      InlineCode: bar
      Events:
        S3Event:
          Fn::If:
            - NeedBucketCondition
            - Type: S3
              Properties:
                Bucket: !Ref MyBucket
                Events: s3:ObjectCreated:*
            - !Ref AWS::NoValue

Then deploy with the S3 event:

sam deploy --region us-west-2 --resolve-s3 --capabilities CAPABILITY_IAM --stack-name test-214 --template template.yaml --parameter-overrides NeedBucket=yes

Or without the S3 event:

sam deploy --region us-west-2 --resolve-s3 --capabilities CAPABILITY_IAM --stack-name test-214 --template template.yaml --parameter-overrides NeedBucket=no

Adding AWS::LanguageExtensions ensures intrinsic functions that are known before deployment (such as the above) are resolved; see #2533.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/cloudformation maintainer/need-response priority/2-important stage/pm-review Waiting for review by our Product Manager, please don't work on this yet type/feature
Projects
None yet
Development

No branches or pull requests