Search code examples
amazon-web-servicesaws-cloudformationaws-samaws-event-bridge

AWS CloudFormation: EventBridge rule still enabled when 'Enabled: false' is set


I have an AWS SAM application with a function that contains a schedule event, and I wish to conditionally enable/disable the EventBridge rule that is generated for the event based on the value of a parameter.

To do this, I've done the following in template.yaml -

  1. Added the FunctionEnabled parameter, which allows only [ 'true', 'false' ] as its value.
  2. Added the EnableFunction condition, which checks whether !Equals [ !Ref FunctionEnabled, 'true' ].
  3. Set the value of the Enabled property for the schedule event using !If [ EnableFunction, true, false ].

However, when I build the template and deploy it, the EventBridge rule is always enabled, regardless of the value of the FunctionEnabled parameter.

foo@bar:~/sam-project$ sam build -u
foo@bar:~/sam-project$ sam deploy --parameter-overrides FunctionEnabled=true
foo@bar:~/sam-project$ sam deploy --parameter-overrides FunctionEnabled=false

Note that the FunctionEnabled output correctly shows true or false based on the value of the parameter, suggesting that the correct boolean value is being passed to the Enabled property.

So how can I enable/disable the EventBridge rule based on the value of a parameter?


Update 1

I wondered if the !If function might be returning a string rather than a Boolean, so I tried to use the following condition functions as the value of of the Enabled property for the schedule event.

  • !Condition EnableFunction
  • !Equals [ !Ref FunctionEnabled, 'true' ]

However the result is still the same in both cases, so the EventBridge rule is still always enabled.

Update 2

When I hardcode the value of the Enabled property for the schedule event to be false, the EventBridge rule is disabled as expected.

Does this mean that all of the condition functions return a string as opposed to a Boolean?


SAM Application

code/app.py

def lambda_handler(event, context) -> dict:
    return {
            'statusCode': 200,
            'headers': {
                'AWS-Request-ID': context.aws_request_id,
                'Content-Type': 'application/json'
            },
            'body': '{"message": "Hello World!!"}'
        }

samconfig.toml

version = 0.1

[default.deploy.parameters]
capabilities = "CAPABILITY_IAM"
confirm_changeset = true

template.yaml

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

Parameters:
  FunctionEnabled:
    Description: Whether the EventBridge rule is enabled.
    Type: String
    AllowedValues: [ 'true', 'false' ]
  Schedule:
    Description: The schedule on which the EventBridge rule triggers the Function.
    Type: String
    Default: cron(0 3 1 * ? *)

Conditions:
  EnableFunction: !Equals [ !Ref FunctionEnabled, 'true' ]

Globals:
  Function:
    Architectures:
      - x86_64
    Handler: app.lambda_handler
    Runtime: python3.8
    Timeout: 1

Resources:
  FunctionLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub "/aws/lambda/${Function}"
      RetentionInDays: 7

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

  Function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: code/.
      Events:
        ScheduleEvent:
          Type: Schedule
          Properties:
            Enabled: !If [ EnableFunction, true, false ]
            Schedule: !Ref Schedule
            RetryPolicy:
              MaximumEventAgeInSeconds: 100
              MaximumRetryAttempts: 3
      Role: !GetAtt FunctionRole.Arn

Outputs:
  FunctionEnabled:
    Description: The value of the 'Resources.Function.Properties.Events.ScheduleEvent.Properties.Enabled'.
    Value: !If [ EnableFunction, true, false ]


Solution

  • This is completely undocumented, but rather than using Enabled: true|false, it's possible to simply use the CloudFormation AWS::Events::Rule property State: ENABLED|DISABLED.

    It seems that SAM ignores intrinsic functions, so when transforming to CF it see's a value for Enabled which it assumes as true, and thus the rule is enabled. Note that this behaviour in itself seems different to that described in the documentation.

    If this property is set to true then AWS SAM passes ENABLED, otherwise it passes DISABLED.

    As I didn't get any traction here, I also opened a GitHub issue.