aws-cdk-lib#Lazy TypeScript Examples

The following examples show how to use aws-cdk-lib#Lazy. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: plugin.ts    From lift with MIT License 5 votes vote down vote up
resolveReference({ address }: { address: string }): { value: string } {
        return {
            /**
             * Construct variables are resolved lazily using the CDK's "Token" system.
             * CDK Lazy values generate a unique `${Token[TOKEN.63]}` string. These strings
             * can later be resolved to the real value (which we do in `initialize()`).
             * Problem:
             * - Lift variables need constructs to be resolved
             * - Constructs can be created when Serverless variables are resolved
             * - Serverless variables must resolve Lift variables
             * This is a chicken and egg problem.
             * Solution:
             * - Serverless boots, plugins are created
             * - variables are resolved
             *   - Lift variables are resolved to CDK tokens (`${Token[TOKEN.63]}`) via `Lazy.any(...)`
             *     (we can't resolve the actual values since we don't have the constructs yet)
             * - `initialize` hook
             *   - Lift builds the constructs
             *   - CDK tokens are resolved into real value: we can now do that using the CDK "token resolver"
             */
            value: Lazy.any({
                produce: () => {
                    const constructs = this.getConstructs();
                    const [id, property] = address.split(".", 2);
                    if (!has(this.constructs, id)) {
                        throw new ServerlessError(
                            `No construct named '${id}' was found, the \${construct:${id}.${property}} variable is invalid.`,
                            "LIFT_VARIABLE_UNKNOWN_CONSTRUCT"
                        );
                    }
                    const construct = constructs[id];

                    const properties = construct.variables ? construct.variables() : {};
                    if (!has(properties, property)) {
                        if (Object.keys(properties).length === 0) {
                            throw new ServerlessError(
                                `\${construct:${id}.${property}} does not exist. The construct '${id}' does not expose any property`,
                                "LIFT_VARIABLE_UNKNOWN_PROPERTY"
                            );
                        }
                        throw new ServerlessError(
                            `\${construct:${id}.${property}} does not exist. Properties available on \${construct:${id}} are: ${Object.keys(
                                properties
                            ).join(", ")}`,
                            "LIFT_VARIABLE_UNKNOWN_PROPERTY"
                        );
                    }

                    return properties[property];
                },
            }).toString(),
        };
    }
Example #2
Source File: index.ts    From cdk-ssm-document with Apache License 2.0 5 votes vote down vote up
/**
   * Defines a new SSM document
   */
  constructor(scope: Construct, id: string, props: DocumentProps) {
    super(scope, id);

    this.tags = new TagManager(TagType.MAP, 'Custom::SSM-Document');
    this.tags.setTag(createdByTag, ID);

    const stack = Stack.of(this).stackName;
    this.lambda = this.ensureLambda();
    const name = this.fixDocumentName(props.name);

    if (name.length < 3 || name.length > 128) {
      Annotations.of(this).addError(
        `SSM Document name ${name} is invalid. The name must be between 3 and 128 characters.`
      );
      return;
    }

    let content = props.content;

    if (typeof content === 'string') {
      content = yaml.safeLoad(content) as DocumentContent;
    }

    const document = new CustomResource(this, `SSM-Document-${name}`, {
      serviceToken: this.lambda.functionArn,
      resourceType: resourceType,
      properties: {
        updateDefaultVersion: props.updateDefaultVersion || true,
        name: name,
        content: content,
        documentType: props.documentType || 'Command',
        targetType: props.targetType || '/',
        attachments: props.attachments,
        versionName: props.versionName,
        StackName: stack,
        tags: Lazy.any({
          produce: () => this.tags.renderTags(),
        }),
      },
      pascalCaseProperties: true,
    });

    this.name = document.getAttString('Name');
  }
Example #3
Source File: gitlab-runner-instance.ts    From cdk-gitlab-runner with Apache License 2.0 4 votes vote down vote up
constructor(scope: Construct, id: string, props: GitlabContainerRunnerProps) {
    super(scope, id);
    const spotFleetId = id;

    const defaultProps = {
      gitlabRunnerImage: 'public.ecr.aws/gitlab/gitlab-runner:alpine',
      gitlaburl: 'https://gitlab.com/',
      ec2type: 't3.micro',
      tags: ['gitlab', 'awscdk', 'runner'],
    };
    const runnerProps = { ...defaultProps, ...props };

    const runnerBucket = new Bucket(this, 'runnerBucket', {
      removalPolicy: RemovalPolicy.DESTROY,
      autoDeleteObjects: true,
    });
    const shell = UserData.forLinux();
    shell.addCommands(...this.createUserData(runnerProps, runnerBucket.bucketName));

    this.runnerRole =
      runnerProps.ec2iamrole ??
      new Role(this, 'runner-role', {
        assumedBy: new ServicePrincipal('ec2.amazonaws.com'),
        description: 'For Gitlab EC2 Runner Role',
      });
    this.validUntil = runnerProps.validUntil;
    const instanceProfile = new CfnInstanceProfile(this, 'InstanceProfile', {
      roles: [this.runnerRole.roleName],
    });
    runnerBucket.grantWrite(this.runnerRole);
    this.vpc =
      runnerProps.selfvpc ??
      new Vpc(this, 'VPC', {
        cidr: '10.0.0.0/16',
        maxAzs: 2,
        subnetConfiguration: [
          {
            cidrMask: 26,
            name: 'RunnerVPC',
            subnetType: SubnetType.PUBLIC,
          },
        ],
        natGateways: 0,
      });
    this.defaultRunnerSG = new SecurityGroup(this, 'SpotFleetSg', {
      vpc: this.vpc,
    });
    this.defaultRunnerSG.connections.allowFromAnyIpv4(Port.tcp(22));
    const spotOrOnDemand = runnerProps.spotFleet ?? false;
    if (spotOrOnDemand) {
      //throw new Error('yes new spotfleet');

      const imageId = MachineImage.latestAmazonLinux({
        generation: AmazonLinuxGeneration.AMAZON_LINUX_2,
      }).getImage(this).imageId;
      const lt = new CfnLaunchTemplate(this, 'LaunchTemplate', {
        launchTemplateData: {
          imageId,
          instanceType: runnerProps.ec2type,
          blockDeviceMappings: [
            {
              deviceName: '/dev/xvda',
              ebs: {
                volumeSize: runnerProps.ebsSize ?? 60,
              },
            },
          ],
          userData: Fn.base64(shell.render()),
          keyName: runnerProps.keyName,
          tagSpecifications: [
            {
              resourceType: 'instance',
              tags: [
                {
                  key: 'Name',
                  value: `${Stack.of(this).stackName
                  }/spotFleetGitlabRunner/${spotFleetId}`,
                },
              ],
            },
          ],
          instanceMarketOptions: {
            marketType: 'spot',
            spotOptions: {
              blockDurationMinutes:
                runnerProps.blockDuration ?? BlockDuration.ONE_HOUR,
              instanceInterruptionBehavior:
                runnerProps.instanceInterruptionBehavior ??
                InstanceInterruptionBehavior.TERMINATE,
            },
          },
          securityGroupIds: this.defaultRunnerSG.connections.securityGroups.map(
            (m) => m.securityGroupId,
          ),
          iamInstanceProfile: {
            arn: instanceProfile.attrArn,
          },
        },
      });

      const spotFleetRole = new Role(this, 'FleetRole', {
        assumedBy: new ServicePrincipal('spotfleet.amazonaws.com'),
        managedPolicies: [
          ManagedPolicy.fromAwsManagedPolicyName(
            'service-role/AmazonEC2SpotFleetTaggingRole',
          ),
        ],
      });

      const vpcSubnetSelection = runnerProps.vpcSubnet ?? {
        subnetType: SubnetType.PUBLIC,
      };
      const subnetConfig = this.vpc
        .selectSubnets(vpcSubnetSelection)
        .subnets.map((s) => ({
          subnetId: s.subnetId,
        }));

      const cfnSpotFleet = new CfnSpotFleet(this, id, {
        spotFleetRequestConfigData: {
          launchTemplateConfigs: [
            {
              launchTemplateSpecification: {
                launchTemplateId: lt.ref,
                version: lt.attrLatestVersionNumber,
              },
              overrides: subnetConfig,
            },
          ],
          iamFleetRole: spotFleetRole.roleArn,
          targetCapacity: 1,
          validUntil: Lazy.string({ produce: () => this.validUntil }),
          terminateInstancesWithExpiration: true,
        },
      });
      const onEvent = new lambda.Function(this, 'OnEvent', {
        code: lambda.Code.fromAsset(path.join(__dirname, '../assets/functions')),
        handler: 'index.on_event',
        runtime: lambda.Runtime.PYTHON_3_8,
        timeout: Duration.seconds(60),
      });

      const isComplete = new lambda.Function(this, 'IsComplete', {
        code: lambda.Code.fromAsset(path.join(__dirname, '../assets/functions')),
        handler: 'index.is_complete',
        runtime: lambda.Runtime.PYTHON_3_8,
        timeout: Duration.seconds(60),
        role: onEvent.role,
      });

      const myProvider = new cr.Provider(this, 'MyProvider', {
        onEventHandler: onEvent,
        isCompleteHandler: isComplete,
        logRetention: logs.RetentionDays.ONE_DAY,
      });

      onEvent.addToRolePolicy(
        new PolicyStatement({
          actions: ['ec2:DescribeSpotFleetInstances'],
          resources: ['*'],
        }),
      );

      const fleetInstances = new CustomResource(this, 'GetInstanceId', {
        serviceToken: myProvider.serviceToken,
        properties: {
          SpotFleetRequestId: cfnSpotFleet.ref,
        },
      });

      fleetInstances.node.addDependency(cfnSpotFleet);
      this.spotFleetInstanceId = Token.asString(
        fleetInstances.getAtt('InstanceId'),
      );
      this.spotFleetRequestId = Token.asString(
        fleetInstances.getAtt('SpotInstanceRequestId'),
      );
      new CfnOutput(this, 'InstanceId', { value: this.spotFleetInstanceId });
      new CfnOutput(this, 'SpotFleetId', { value: cfnSpotFleet.ref });
    } else {
      this.runnerEc2 = new Instance(this, 'GitlabRunner', {
        instanceType: new InstanceType(runnerProps.ec2type),
        instanceName: 'Gitlab-Runner',
        vpc: this.vpc,
        vpcSubnets: runnerProps.vpcSubnet ?? {
          subnetType: SubnetType.PUBLIC,
        },
        machineImage: MachineImage.latestAmazonLinux({
          generation: AmazonLinuxGeneration.AMAZON_LINUX_2,
        }),
        role: this.runnerRole,
        userData: shell,
        securityGroup: this.defaultRunnerSG,
        blockDevices: [
          {
            deviceName: '/dev/xvda',
            volume: BlockDeviceVolume.ebs(runnerProps.ebsSize ?? 60),
          },
        ],
      });
      new CfnOutput(this, 'Runner-Instance-ID', {
        value: this.runnerEc2.instanceId,
      });
    }

    const unregisterRunnerOnEvent = new lambda.Function(this, 'unregisterRunnerOnEvent', {
      code: lambda.Code.fromAsset(path.join(__dirname, '../assets/functions')),
      handler: 'unregister_runner.on_event',
      runtime: lambda.Runtime.PYTHON_3_8,
      timeout: Duration.seconds(60),
    });

    const unregisterRunnerProvider = new cr.Provider(this, 'unregisterRunnerProvider', {
      onEventHandler: unregisterRunnerOnEvent,
      logRetention: logs.RetentionDays.ONE_DAY,
    });

    const unregisterRunnerCR = new CustomResource(this, 'unregisterRunnerCR', {
      resourceType: 'Custom::unregisterRunnerProvider',
      serviceToken: unregisterRunnerProvider.serviceToken,
      properties: {
        BucketName: runnerBucket.bucketName,
        GitlabUrl: runnerProps.gitlaburl,
      },
    });

    runnerBucket.grantReadWrite(unregisterRunnerOnEvent);
    unregisterRunnerCR.node.addDependency(runnerBucket);
    this.runnerRole.addManagedPolicy(
      ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'),
    );

    new CfnOutput(this, 'Runner-Role-Arn', {
      value: this.runnerRole.roleArn,
    });
  }
Example #4
Source File: index.ts    From cdk-ec2-key-pair with Apache License 2.0 4 votes vote down vote up
/**
   * Defines a new EC2 Key Pair. The private key will be stored in AWS Secrets Manager
   */
  constructor(scope: Construct, id: string, props: KeyPairProps) {
    super(scope, id);

    if (
      props.removeKeySecretsAfterDays &&
      (props.removeKeySecretsAfterDays < 0 ||
        (props.removeKeySecretsAfterDays > 0 &&
          props.removeKeySecretsAfterDays < 7) ||
        props.removeKeySecretsAfterDays > 30)
    ) {
      Annotations.of(this).addError(
        `Parameter removeKeySecretsAfterDays must be 0 or between 7 and 30. Got ${props.removeKeySecretsAfterDays}`
      );
    }

    if (
      props.publicKey?.length &&
      props.publicKeyFormat !== undefined &&
      props.publicKeyFormat !== PublicKeyFormat.OPENSSH
    ) {
      Annotations.of(this).addError(
        'When importing a key, the format has to be of type OpenSSH'
      );
    }

    const stack = Stack.of(this).stackName;
    this.prefix = props.resourcePrefix || stack;
    if (this.prefix.length + cleanID.length > 62)
      // Cloudformation limits names to 63 characters.
      Annotations.of(this).addError(
        `Cloudformation limits names to 63 characters.
         Prefix ${this.prefix} is too long to be used as a prefix for your roleName. Define parameter resourcePrefix?:`
      );
    this.lambda = this.ensureLambda();

    this.tags = new TagManager(TagType.MAP, 'Custom::EC2-Key-Pair');
    this.tags.setTag(createdByTag, ID);

    const kmsPrivate = props.kmsPrivateKey || props.kms;
    const kmsPublic = props.kmsPublicKey || props.kms;

    const key = new CustomResource(this, `EC2-Key-Pair-${props.name}`, {
      serviceToken: this.lambda.functionArn,
      resourceType: resourceType,
      properties: {
        Name: props.name,
        Description: props.description || '',
        KmsPrivate: kmsPrivate?.keyArn || 'alias/aws/secretsmanager',
        KmsPublic: kmsPublic?.keyArn || 'alias/aws/secretsmanager',
        PublicKey: props.publicKey || '',
        StorePublicKey: props.storePublicKey || false,
        ExposePublicKey: props.exposePublicKey || false,
        PublicKeyFormat: props.publicKeyFormat || PublicKeyFormat.OPENSSH,
        RemoveKeySecretsAfterDays: props.removeKeySecretsAfterDays || 0,
        SecretPrefix: props.secretPrefix || 'ec2-ssh-key/',
        StackName: stack,
        Tags: Lazy.any({
          produce: () => this.tags.renderTags(),
        }),
      },
    });

    if (typeof props.kms !== 'undefined') {
      props.kms.grantEncryptDecrypt(this.lambda.role!);
      key.node.addDependency(props.kms);
      key.node.addDependency(this.lambda.role!);
    }

    if (typeof props.kmsPrivateKey !== 'undefined') {
      props.kmsPrivateKey.grantEncryptDecrypt(this.lambda.role!);
      key.node.addDependency(props.kmsPrivateKey);
      key.node.addDependency(this.lambda.role!);
    }

    if (typeof props.kmsPublicKey !== 'undefined') {
      props.kmsPublicKey.grantEncryptDecrypt(this.lambda.role!);
      key.node.addDependency(props.kmsPublicKey);
      key.node.addDependency(this.lambda.role!);
    }

    this.privateKeyArn = key.getAttString('PrivateKeyARN');
    this.publicKeyArn = key.getAttString('PublicKeyARN');
    this.publicKeyValue = key.getAttString('PublicKeyValue');
    this.keyPairName = key.getAttString('KeyPairName');
    this.keyPairID = key.getAttString('KeyPairID');
  }