3
votes

I'm working on setting up my Java AWS lambda functions to be deployed via Codepipeline -> Cloudformation and am having some difficulty with Cloudformation. I've worked with Terraform before, so I understand the general concepts...

To clarify, my code is housed in a Codecommit repository and everything was setup by Codestar, so it created a Codepipeline with a single stage, two-step deployment (generate changeset, execute changeset).

For right now, I am just marking up the sample template.yml file that Codestar created in the repository, hence the HelloWorld references.

In addition to the template.yml file, I also have a buildspec.yml file for Codebuild, though the build process completes successfully.

Below is my template.yml cloudformation script. The ChangeSet step in the Codepipeline deployment stage completes successfully, however the ExecuteChangeset step fails, with "No reason provided" (super helpful). Clicking on the details link brings me to the Cloudformation page for the execute step which does not actually show any errors. It shows a few of the add/remove steps I would expect to see, though not all of the ones I would think would need to happen. If I click "Execute", it fails with the following error:

Error: Failed to execute change set: ChangeSet [arn:aws:cloudformation:us-east-1:XXXXXXXXXXXX:stack/awscodestar-test2-lambda/07e71ee0-6a73-11e7-bee5-50d5cd24fac6] cannot be executed in its current execution status of [EXECUTE_FAILED]

What am I doing wrong here? I don't have a good grasp of the Fn::GetAtt call, but I've tried that a few different ways with no joy.

**In addition to identifying what's going wrong, I have two questions:

  1. Please explain what exactly I'm supposed to reference in the Fn::GetAtt function call? Is it the resource name I provide at the top of the resource I'm trying to call (e.g. GetHelloWorld)? Or an explicit name that's provided as a property of that resource (i.e. FunctionName)?

  2. In the Lambda function declaration, I'm trying to setup the Event trigger in-line, which then needs to reference the Lambda function. Can I refer to the Lambda function resource from within the Event declaration that's nested within the Lambda function resource??

Below is my template.yml file.

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

Parameters:
  ProjectId:
    Type: String
    Description: AWS CodeStar projectID used to associate new resources to team members

Resources:
  RoleForLambda:
    Type: "AWS::IAM::Role"
    Properties: 
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement: 
          - Effect: "Allow"
            Principal: 
              Service: "lambda.amazonaws.com"
            Action: "sts:AssumeRole"
      Policies:
      - PolicyName: s3put
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
          - Effect: "Allow"
            Action:
            - 'logs:CreateLogGroup'
            - 'logs:CreateLogStream'
            - 'logs:PutLogEvents'
            - 's3:PutObject'
            Resource: 
            - 'arn:aws:logs:*:*:*'
            - 'arn:aws:s3:*'
  GetHelloWorld:
    Type: AWS::Serverless::Function
    Properties:
      Handler: com.aws.codestar.projecttemplates.handler.HelloWorldHandler
      Runtime: java8
      Timeout: 60
      MemorySize: 256
      Role:
        'Fn::GetAtt':
          - RoleForLambda
          - Arn
    ScheduleRule:
      Type: 'AWS::Events::Rule'
      Properties:
        Name: DownloadFiles
        ScheduleExpression: 'cron(2,7,12,17,22,27,32,37,42,47,52,57 * * * ? *)'
        State: ENABLED
        Targets:
          - Arn: 
              'Fn::GetAtt':
                - GetHelloWorld
                - Arn
            Id: downloadFiles
    LambdaInvokePermission:
      Type: "AWS::Lambda::Permission"
      Properties: 
        Action: lambda:InvokeFunction
        FunctionName: GetHelloWorld
        Principal: events.amazonaws.com
        SourceAccount: AWS::XXXXXXXXXXXX
        SourceArn:
          - Arn:
              'Fn::GetAtt':
                - ScheduleRule
                - Arn
1

1 Answers

4
votes

In case anyone else gets to this with similar issues. Turns out, I had a few syntax errors and, I'm sure, other problems... Here is a working template.

AWSTemplateFormatVersion: 2010-09-09
Description: >-
  This Lambda function does something
Parameters:
  ProjectId:
    Description: AWS CodeStar projectID used to associate new resources to team members
    Type: String
Resources:
  DownloadRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: ''
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: 'sts:AssumeRole'
      Policies:
        - PolicyName: PutS3Policy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                  - 's3:PutObject'
                  - 's3:PutObjectAcl'
                  - 's3:PutObjectTagging'
                  - 'sns:Publish'
                Resource:
                  - 'arn:aws:logs:*:*:*'
                  - 'arn:aws:s3:::myBucket'
                  - 'arn:aws:s3:::myBucket/*'
                  - 'arn:aws:sns:us-east-1:xxxxxxxxxxxx:SNS_TOPIC'
      Path: /
  DownloadFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Handler: 'com.mycompany.download.LambdaFunction::lambdaHandler'
      MemorySize: '256'
      Description: A scheduled Lambda function
      FunctionName: Download
      Role: !GetAtt 
        - DownloadRole
        - Arn
      Runtime: java8
      Timeout: '60'
    DependsOn:
      - DownloadRole
  ScheduleRule:
    Type: 'AWS::Events::Rule'
    Properties:
      Name: DownloadFiles
      ScheduleExpression: 'cron(2,7,12,17,22,27,32,37,42,47,52,57 * * * ? *)'
      State: ENABLED
      Targets:
        - Arn: !GetAtt 
            - DownloadFunction
            - Arn
          Id: DownloadFiles
    DependsOn:
      - DownloadFunction
  LambdaInvokePermission:
    Type: 'AWS::Lambda::Permission'
    Properties:
      FunctionName: !GetAtt 
        - DownloadFunction
        - Arn
      Action: 'lambda:InvokeFunction'
      Principal: events.amazonaws.com
      SourceArn: !GetAtt 
        - ScheduleRule
        - Arn
    DependsOn:
      - DownloadFunction
      - ScheduleRule