Source: lambda.js

const assert = require('assert')
const AWSComponent = require('./aws-component').AWSComponent
const Policy = require('./policy').Policy

const _ = require('lodash')

const LAMBDA_DEFAULT_TIMEOUT_SECS = 10
const LAMBDA_DEFAULT_MEMORY_SIZE_MB = 128

/**
 * This class represents a Lambda component. 
 * @inheritdoc
 */
class Lambda extends AWSComponent {
  /**
   * Don't call this manually. Use creator function in {@link CloudFormation}
   * @param {string} stackName 
   * @param {string} baseName 
   */
  constructor(
    stackName,
    baseName) {
    super(stackName, baseName)
    this.envVariables = {}
    this.timeoutSecs = LAMBDA_DEFAULT_TIMEOUT_SECS
    this.memorySizeMB = LAMBDA_DEFAULT_MEMORY_SIZE_MB

    //Default policyStatements for Lambda
    this.policyStatements = [{
        "Effect": "Allow",
        "Action": "logs:CreateLogGroup",
        "Resource": {
          "Fn::Join": [
            "", ['arn:aws:logs:', { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":*"]
          ]
        }
      },
      {
        "Effect": "Allow",
        "Action": [
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ],
        "Resource": {
          "Fn::Join": [
            "", ['arn:aws:logs:', { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":log-group:*"]
          ]
        }
      }
    ]

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

  policyStatementForAccessImpl(accessLevels, item) {
    //Item is ignored, because there is only one thing to offer 

    let actionsTable = {}
    actionsTable[AWSComponent.ACCESS_LEVEL_READ] = [
      'lambda:InvokeFunction'
    ]

    actionsTable[AWSComponent.ACCESS_LEVEL_WRITE] = [
      //TODO
    ]

    actionsTable[AWSComponent.ACCESS_LEVEL_ADMIN] = [
      //TODO
    ]

    let allowedActions = []
    accessLevels.forEach((level) => {
      let actions = actionsTable[level]
      allowedActions = allowedActions.concat(actions)
    })

    return {
      "Effect": "Allow",
      "Action": allowedActions.sort(),
      "Resource": [
        this.getValue('ARN')
      ]
    }
  }

  /**
   * Set the timeout value of this Lambda in seconds.
   * @param {float} timeoutSecs 
   */
  setTimeoutSecs(timeoutSecs) {
    this.timeoutSecs = timeoutSecs
  }

  /**
   * Set the memory limit of this Lambda in MB.
   * @param {float} memorySizeMB 
   */
  setMemorySizeMB(memorySizeMB) {
    this.memorySizeMB = memorySizeMB
  }

  /**
   * Set the source code of this Lambda in the form of array of text strings.
   * @param {array} code 
   */
  setCode(code) {
    assert.ok(!_.isEmpty(code))
    this.code = code
  }

  /**
   * Set teh source code zip in S3. You don't need to call this manually if "lambdaSourceFiles" is declared in package.json.
   *  
   * @param {string} bucketName 
   * @param {string} sourcePackageName 
   */
  setSourcePackageInS3Bucket(bucketName, sourcePackageName) {

    assert.ok(bucketName)
    assert.ok(sourcePackageName)

    this.bucketName = bucketName
    this.sourcePackageName = sourcePackageName
  }

  /**
   * Set the handler function path
   * @param {string} handlerPath 
   */
  setHandlerPath(handlerPath) {
    assert.ok(handlerPath)
    this.handlerPath = handlerPath
  }

  /**
   * Set the environment variables of this Lambda in the form of key-value pairs
   * @param {object} envVariables 
   */
  setEnvVariables(envVariables) {
    this.envVariables = envVariables
  }

  get template() {

    if (!this.code) {
      assert.ok(this.bucketName)
      assert.ok(this.sourcePackageName)
    }

    let template = {}

    //This is the role that's used by Lambda
    //console.log('DEFAULT ROLE: ' + JSON.stringify(this.defaultRole.template, null, 2))

    template = _.merge(template, this.defaultRole.template)

    /*
    template[this.roleName()] = {
      "Type": "AWS::IAM::Role",
      "Properties": {
        //Copied from AWS generated Role for Lambda 
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": "lambda.amazonaws.com"
              },
              "Action": "sts:AssumeRole"
            }
          ]
        },
        "Policies": this.getAllPoliciesTemplate(),
        "Path": "/"
      }
    } //End role
    */


    template[this.fullName] = {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Code": this.code || {
          "S3Bucket": this.bucketName,
          "S3Key": this.sourcePackageName
        },
        "Handler": this.handlerPath,
        "Runtime": 'nodejs8.10',
        "Timeout": this.timeoutSecs,
        "MemorySize": this.memorySizeMB,

        "Role": {
          "Fn::GetAtt": [this.roleName(), "Arn"]
        },

        "Description": `lambda function for stack ${this.stackName}, baseName=${this.baseName}`,
        "Environment": {
          "Variables": this.envVariables
        },
      }
    } //End lambda declaration 

    return template
  }
}

exports.Lambda = Lambda