1
votes

I have CodeBuild project and Lambda function. I want lambda function to be executed every time CodeBuild build succeeds. For some reason Lambda is not called at all. Here is my terraform config for lambda and event rule/target:

resource "aws_iam_role" "iam_for_lambda" {
  name = "invalidate_cache_${var.name}"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_iam_role_policy" "invalidate_cache" {
  name = "invalidate_cache_${var.name}-policy"
  role="${aws_iam_role.iam_for_lambda.id}"
  policy= <<PATTERN
{
  "Id": "InvalidateCachePolicy",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "cloudfront:CreateInvalidation",
        "cloudfront:GetInvalidation",
        "cloudfront:ListInvalidations"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
PATTERN
}

resource "aws_lambda_function" "invalidate_cache" {
  filename      = local.lambda_path
  function_name = "invalidate_cache_${var.name}"
  role          = "${aws_iam_role.iam_for_lambda.arn}"
  handler       = "index.handler"

  source_code_hash = "${filebase64sha256(local.lambda_path)}"

  runtime = "nodejs10.x"

  environment {
    variables = {
      CLOUDFRONT_DISTRIBUTION_ID = "${aws_cloudfront_distribution.website_distribution.id}"
    }
  }

  depends_on = [null_resource.deps]
}

locals {
  lambda_path = split("|", join("|", ["./../lambda/invalidateCache/invalidateCache.zip", null_resource.deps.id]))[0]
}

resource "aws_cloudwatch_event_rule" "invalidate_cache" {
  count = var.codebuild_project_name == "" ? 0 : 1
  name        = "invalidate-cache-${var.name}"

  event_pattern = <<PATTERN
{
  "source": [ 
    "aws.codebuild"
  ], 
  "detail-type": [
    "CodeBuild Build Success"
  ],
  "detail": {
    "build-status": [
      "SUCCEEDED"
    ],
    "project-name": [${jsonencode(var.codebuild_project_name)}]
  }  
}
PATTERN
}

resource "aws_cloudwatch_event_target" "invalidate_cache" {
  count = var.codebuild_project_name == "" ? 0 : 1
  rule = "${aws_cloudwatch_event_rule.invalidate_cache[0].name}"
  target_id = "invalidate-cache-${var.name}"
  arn = "${aws_lambda_function.invalidate_cache.arn}"
}

resource "aws_lambda_permission" "invalidate_cache" {
  count = var.codebuild_project_name == "" ? 0 : 1
  statement_id = "AllowExecutionFromCloudWatch"
  action = "lambda:InvokeFunction"
  function_name = "${aws_lambda_function.invalidate_cache.function_name}"
  principal = "events.amazonaws.com"
  source_arn = "${aws_cloudwatch_event_rule.invalidate_cache[0].arn}"
}

For some reason when build of "frontend" project succeeds no lambda is called. In AWS console on lambda page I see lambda trigger set up correctly and also in cloudwatch events it looks ok (but in metrics there aren't any lambda excutions). Also tested lambda manually and it works. So it seems that my event rule is incorrect and event is never triggered but cant figure out whats wrong.

enter image description here

enter image description here


Following patter worked for me (it seems detail-type prevented correct event handling):

{
  "source": [ 
    "aws.codebuild"
  ], 
  "detail": {
    "build-status": [
      "SUCCEEDED"
    ],
    "project-name": ["frontend"]
  }  
}
1

1 Answers

2
votes

Your cloudwatch event rule isn't matching on the detail-type. At least according to the sample event

resource "aws_cloudwatch_event_rule" "invalidate_cache" {
  count = var.codebuild_project_name == "" ? 0 : 1
  name        = "invalidate-cache-${var.name}"

  event_pattern = <<PATTERN
{
  "source": [ 
    "aws.codebuild"
  ], 
  "detail-type": [
    "CodeBuild Build State Change"
  ],
  "detail": {
    "build-status": [
      "SUCCEEDED"
    ],
    "project-name": [${jsonencode(var.codebuild_project_name)}]
  }  
}
PATTERN
}

Here is the sample event provided by AWS for a code build state change that succeeded. This came from the AWS console when you manually go to create an event rule.

{
  "version": "0",
  "id": "bfdc1220-60ff-44ad-bfa7-3b6e6ba3b2d0",
  "detail-type": "CodeBuild Build State Change",
  "source": "aws.codebuild",
  "account": "123456789012",
  "time": "2017-07-12T00:42:28Z",
  "region": "us-east-1",
  "resources": [
    "arn:aws:codebuild:us-east-1:123456789012:build/SampleProjectName:ed6aa685-0d76-41da-a7f5-6d8760f41f55"
  ],
  "detail": {
    "build-status": "SUCCEEDED",
    "project-name": "SampleProjectName",
    "build-id": "arn:aws:codebuild:us-east-1:123456789012:build/SampleProjectName:ed6aa685-0d76-41da-a7f5-6d8760f41f55",
    "current-phase": "COMPLETED",
    "current-phase-context": "[]",
    "version": "1"
  }
}

If for some reason the updated pattern doesn't work, one thing I do is send all events from the service to a lambda that just prints the events so I can see the current structure. In this case your event rule would look like this:

{
  "source": [
    "aws.codebuild"
  ]
}