constructor()

in packages/@aws-cdk/aws-lambda/lib/function.ts [608:809]


  constructor(scope: Construct, id: string, props: FunctionProps) {
    super(scope, id, {
      physicalName: props.functionName,
    });

    const managedPolicies = new Array<iam.IManagedPolicy>();

    // the arn is in the form of - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
    managedPolicies.push(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'));

    if (props.vpc) {
      // Policy that will have ENI creation permissions
      managedPolicies.push(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaVPCAccessExecutionRole'));
    }

    this.role = props.role || new iam.Role(this, 'ServiceRole', {
      assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
      managedPolicies,
    });
    this.grantPrincipal = this.role;

    // add additional managed policies when necessary
    if (props.filesystem) {
      const config = props.filesystem.config;
      if (config.policies) {
        config.policies.forEach(p => {
          this.role?.addToPrincipalPolicy(p);
        });
      }
    }

    for (const statement of (props.initialPolicy || [])) {
      this.role.addToPrincipalPolicy(statement);
    }

    const code = props.code.bind(this);
    verifyCodeConfig(code, props);

    let profilingGroupEnvironmentVariables: { [key: string]: string } = {};
    if (props.profilingGroup && props.profiling !== false) {
      this.validateProfiling(props);
      props.profilingGroup.grantPublish(this.role);
      profilingGroupEnvironmentVariables = {
        AWS_CODEGURU_PROFILER_GROUP_ARN: Stack.of(scope).formatArn({
          service: 'codeguru-profiler',
          resource: 'profilingGroup',
          resourceName: props.profilingGroup.profilingGroupName,
        }),
        AWS_CODEGURU_PROFILER_ENABLED: 'TRUE',
      };
    } else if (props.profiling) {
      this.validateProfiling(props);
      const profilingGroup = new ProfilingGroup(this, 'ProfilingGroup', {
        computePlatform: ComputePlatform.AWS_LAMBDA,
      });
      profilingGroup.grantPublish(this.role);
      profilingGroupEnvironmentVariables = {
        AWS_CODEGURU_PROFILER_GROUP_ARN: profilingGroup.profilingGroupArn,
        AWS_CODEGURU_PROFILER_ENABLED: 'TRUE',
      };
    }

    const env = { ...profilingGroupEnvironmentVariables, ...props.environment };
    for (const [key, value] of Object.entries(env)) {
      this.addEnvironment(key, value);
    }

    this.deadLetterQueue = this.buildDeadLetterQueue(props);

    let fileSystemConfigs: CfnFunction.FileSystemConfigProperty[] | undefined = undefined;
    if (props.filesystem) {
      fileSystemConfigs = [{
        arn: props.filesystem.config.arn,
        localMountPath: props.filesystem.config.localMountPath,
      }];
    }

    if (props.architecture && props.architectures !== undefined) {
      throw new Error('Either architecture or architectures must be specified but not both.');
    }
    if (props.architectures && props.architectures.length > 1) {
      throw new Error('Only one architecture must be specified.');
    }
    this._architecture = props.architecture ?? (props.architectures && props.architectures[0]);

    const resource: CfnFunction = new CfnFunction(this, 'Resource', {
      functionName: this.physicalName,
      description: props.description,
      code: {
        s3Bucket: code.s3Location && code.s3Location.bucketName,
        s3Key: code.s3Location && code.s3Location.objectKey,
        s3ObjectVersion: code.s3Location && code.s3Location.objectVersion,
        zipFile: code.inlineCode,
        imageUri: code.image?.imageUri,
      },
      layers: Lazy.list({ produce: () => this.layers.map(layer => layer.layerVersionArn) }, { omitEmpty: true }), // Evaluated on synthesis
      handler: props.handler === Handler.FROM_IMAGE ? undefined : props.handler,
      timeout: props.timeout && props.timeout.toSeconds(),
      packageType: props.runtime === Runtime.FROM_IMAGE ? 'Image' : undefined,
      runtime: props.runtime === Runtime.FROM_IMAGE ? undefined : props.runtime.name,
      role: this.role.roleArn,
      // Uncached because calling '_checkEdgeCompatibility', which gets called in the resolve of another
      // Token, actually *modifies* the 'environment' map.
      environment: Lazy.uncachedAny({ produce: () => this.renderEnvironment() }),
      memorySize: props.memorySize,
      vpcConfig: this.configureVpc(props),
      deadLetterConfig: this.buildDeadLetterConfig(this.deadLetterQueue),
      tracingConfig: this.buildTracingConfig(props),
      reservedConcurrentExecutions: props.reservedConcurrentExecutions,
      imageConfig: undefinedIfNoKeys({
        command: code.image?.cmd,
        entryPoint: code.image?.entrypoint,
        workingDirectory: code.image?.workingDirectory,
      }),
      kmsKeyArn: props.environmentEncryption?.keyArn,
      fileSystemConfigs,
      codeSigningConfigArn: props.codeSigningConfig?.codeSigningConfigArn,
      architectures: this._architecture ? [this._architecture.name] : undefined,
    });

    resource.node.addDependency(this.role);

    this.functionName = this.getResourceNameAttribute(resource.ref);
    this.functionArn = this.getResourceArnAttribute(resource.attrArn, {
      service: 'lambda',
      resource: 'function',
      resourceName: this.physicalName,
      arnFormat: ArnFormat.COLON_RESOURCE_NAME,
    });

    this.runtime = props.runtime;
    this.timeout = props.timeout;

    this.architecture = props.architecture ?? Architecture.X86_64;

    if (props.layers) {
      if (props.runtime === Runtime.FROM_IMAGE) {
        throw new Error('Layers are not supported for container image functions');
      }

      this.addLayers(...props.layers);
    }

    for (const event of props.events || []) {
      this.addEventSource(event);
    }

    // Log retention
    if (props.logRetention) {
      const logRetention = new logs.LogRetention(this, 'LogRetention', {
        logGroupName: `/aws/lambda/${this.functionName}`,
        retention: props.logRetention,
        role: props.logRetentionRole,
        logRetentionRetryOptions: props.logRetentionRetryOptions as logs.LogRetentionRetryOptions,
      });
      this._logGroup = logs.LogGroup.fromLogGroupArn(this, 'LogGroup', logRetention.logGroupArn);
    }

    props.code.bindToResource(resource);

    // Event Invoke Config
    if (props.onFailure || props.onSuccess || props.maxEventAge || props.retryAttempts !== undefined) {
      this.configureAsyncInvoke({
        onFailure: props.onFailure,
        onSuccess: props.onSuccess,
        maxEventAge: props.maxEventAge,
        retryAttempts: props.retryAttempts,
      });
    }

    this.currentVersionOptions = props.currentVersionOptions;

    if (props.filesystem) {
      if (!props.vpc) {
        throw new Error('Cannot configure \'filesystem\' without configuring a VPC.');
      }
      const config = props.filesystem.config;
      if (config.dependency) {
        this.node.addDependency(...config.dependency);
      }
      // There could be a race if the Lambda is used in a CustomResource. It is possible for the Lambda to
      // fail to attach to a given FileSystem if we do not have a dependency on the SecurityGroup ingress/egress
      // rules that were created between this Lambda's SG & the Filesystem SG.
      this.connections.securityGroups.forEach(sg => {
        sg.node.findAll().forEach(child => {
          if (child instanceof CfnResource && child.cfnResourceType === 'AWS::EC2::SecurityGroupEgress') {
            resource.node.addDependency(child);
          }
        });
      });
      config.connections?.securityGroups.forEach(sg => {
        sg.node.findAll().forEach(child => {
          if (child instanceof CfnResource && child.cfnResourceType === 'AWS::EC2::SecurityGroupIngress') {
            resource.node.addDependency(child);
          }
        });
      });
    }

    // Configure Lambda insights
    this.configureLambdaInsights(props);
  }