constructor()

in packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts [943:1093]


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

    this.newInstancesProtectedFromScaleIn = props.newInstancesProtectedFromScaleIn;

    if (props.initOptions && !props.init) {
      throw new Error('Setting \'initOptions\' requires that \'init\' is also set');
    }

    this.securityGroup = props.securityGroup || new ec2.SecurityGroup(this, 'InstanceSecurityGroup', {
      vpc: props.vpc,
      allowAllOutbound: props.allowAllOutbound !== false,
    });
    this.connections = new ec2.Connections({ securityGroups: [this.securityGroup] });
    this.securityGroups.push(this.securityGroup);
    Tags.of(this).add(NAME_TAG, this.node.path);

    this.role = props.role || new iam.Role(this, 'InstanceRole', {
      roleName: PhysicalName.GENERATE_IF_NEEDED,
      assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
    });

    this.grantPrincipal = this.role;

    if (props.groupMetrics) {
      this.groupMetrics.push(...props.groupMetrics);
    }

    const iamProfile = new iam.CfnInstanceProfile(this, 'InstanceProfile', {
      roles: [this.role.roleName],
    });

    // use delayed evaluation
    const imageConfig = props.machineImage.getImage(this);
    this.userData = props.userData ?? imageConfig.userData;
    const userDataToken = Lazy.string({ produce: () => Fn.base64(this.userData.render()) });
    const securityGroupsToken = Lazy.list({ produce: () => this.securityGroups.map(sg => sg.securityGroupId) });

    const launchConfig = new CfnLaunchConfiguration(this, 'LaunchConfig', {
      imageId: imageConfig.imageId,
      keyName: props.keyName,
      instanceType: props.instanceType.toString(),
      instanceMonitoring: (props.instanceMonitoring !== undefined ? (props.instanceMonitoring === Monitoring.DETAILED) : undefined),
      securityGroups: securityGroupsToken,
      iamInstanceProfile: iamProfile.ref,
      userData: userDataToken,
      associatePublicIpAddress: props.associatePublicIpAddress,
      spotPrice: props.spotPrice,
      blockDeviceMappings: (props.blockDevices !== undefined ?
        synthesizeBlockDeviceMappings(this, props.blockDevices) : undefined),
    });

    launchConfig.node.addDependency(this.role);

    // desiredCapacity just reflects what the user has supplied.
    const desiredCapacity = props.desiredCapacity;
    const minCapacity = props.minCapacity ?? 1;
    const maxCapacity = props.maxCapacity ?? desiredCapacity ?? Math.max(minCapacity, 1);

    withResolved(minCapacity, maxCapacity, (min, max) => {
      if (min > max) {
        throw new Error(`minCapacity (${min}) should be <= maxCapacity (${max})`);
      }
    });
    withResolved(desiredCapacity, minCapacity, (desired, min) => {
      if (desired === undefined) { return; }
      if (desired < min) {
        throw new Error(`Should have minCapacity (${min}) <= desiredCapacity (${desired})`);
      }
    });
    withResolved(desiredCapacity, maxCapacity, (desired, max) => {
      if (desired === undefined) { return; }
      if (max < desired) {
        throw new Error(`Should have desiredCapacity (${desired}) <= maxCapacity (${max})`);
      }
    });

    if (desiredCapacity !== undefined) {
      Annotations.of(this).addWarning('desiredCapacity has been configured. Be aware this will reset the size of your AutoScalingGroup on every deployment. See https://github.com/aws/aws-cdk/issues/5215');
    }

    this.maxInstanceLifetime = props.maxInstanceLifetime;
    if (this.maxInstanceLifetime &&
      (this.maxInstanceLifetime.toSeconds() < 604800 || this.maxInstanceLifetime.toSeconds() > 31536000)) {
      throw new Error('maxInstanceLifetime must be between 7 and 365 days (inclusive)');
    }

    if (props.notificationsTopic && props.notifications) {
      throw new Error('Cannot set \'notificationsTopic\' and \'notifications\', \'notificationsTopic\' is deprecated use \'notifications\' instead');
    }

    if (props.notificationsTopic) {
      this.notifications = [{
        topic: props.notificationsTopic,
      }];
    }

    if (props.notifications) {
      this.notifications = props.notifications.map(nc => ({
        topic: nc.topic,
        scalingEvents: nc.scalingEvents ?? ScalingEvents.ALL,
      }));
    }

    const { subnetIds, hasPublic } = props.vpc.selectSubnets(props.vpcSubnets);
    const asgProps: CfnAutoScalingGroupProps = {
      autoScalingGroupName: this.physicalName,
      cooldown: props.cooldown?.toSeconds().toString(),
      minSize: Tokenization.stringifyNumber(minCapacity),
      maxSize: Tokenization.stringifyNumber(maxCapacity),
      desiredCapacity: desiredCapacity !== undefined ? Tokenization.stringifyNumber(desiredCapacity) : undefined,
      launchConfigurationName: launchConfig.ref,
      loadBalancerNames: Lazy.list({ produce: () => this.loadBalancerNames }, { omitEmpty: true }),
      targetGroupArns: Lazy.list({ produce: () => this.targetGroupArns }, { omitEmpty: true }),
      notificationConfigurations: this.renderNotificationConfiguration(),
      metricsCollection: Lazy.any({ produce: () => this.renderMetricsCollection() }),
      vpcZoneIdentifier: subnetIds,
      healthCheckType: props.healthCheck && props.healthCheck.type,
      healthCheckGracePeriod: props.healthCheck && props.healthCheck.gracePeriod && props.healthCheck.gracePeriod.toSeconds(),
      maxInstanceLifetime: this.maxInstanceLifetime ? this.maxInstanceLifetime.toSeconds() : undefined,
      newInstancesProtectedFromScaleIn: Lazy.any({ produce: () => this.newInstancesProtectedFromScaleIn }),
      terminationPolicies: props.terminationPolicies,
    };

    if (!hasPublic && props.associatePublicIpAddress) {
      throw new Error("To set 'associatePublicIpAddress: true' you must select Public subnets (vpcSubnets: { subnetType: SubnetType.PUBLIC })");
    }

    this.autoScalingGroup = new CfnAutoScalingGroup(this, 'ASG', asgProps);
    this.osType = imageConfig.osType;
    this.autoScalingGroupName = this.getResourceNameAttribute(this.autoScalingGroup.ref),
    this.autoScalingGroupArn = Stack.of(this).formatArn({
      service: 'autoscaling',
      resource: 'autoScalingGroup:*:autoScalingGroupName',
      resourceName: this.autoScalingGroupName,
    });
    this.node.defaultChild = this.autoScalingGroup;

    this.applyUpdatePolicies(props, { desiredCapacity, minCapacity });
    if (props.init) {
      this.applyCloudFormationInit(props.init, props.initOptions);
    }

    this.spotPrice = props.spotPrice;

    if (props.requireImdsv2) {
      Aspects.of(this).add(new AutoScalingGroupRequireImdsv2Aspect());
    }
  }