constructor()

in packages/aws-cdk-lib/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts [461:582]


  constructor(scope: Construct, id: string, props: ApplicationLoadBalancedServiceBaseProps = {}) {
    super(scope, id);

    if (props.cluster && props.vpc) {
      throw new Error('You can only specify either vpc or cluster. Alternatively, you can leave both blank');
    }
    this.cluster = props.cluster || this.getDefaultCluster(this, props.vpc);

    if (props.desiredCount !== undefined && !cdk.Token.isUnresolved(props.desiredCount) && props.desiredCount < 1) {
      throw new Error('You must specify a desiredCount greater than 0');
    }

    this.desiredCount = props.desiredCount || 1;
    this.internalDesiredCount = props.desiredCount;

    const internetFacing = props.publicLoadBalancer ?? true;

    if (props.idleTimeout) {
      const idleTimeout = props.idleTimeout.toSeconds();
      if (idleTimeout > Duration.seconds(4000).toSeconds() || idleTimeout < Duration.seconds(1).toSeconds()) {
        throw new Error('Load balancer idle timeout must be between 1 and 4000 seconds.');
      }
    }

    const lbProps: ApplicationLoadBalancerProps = {
      vpc: this.cluster.vpc,
      loadBalancerName: props.loadBalancerName,
      internetFacing,
      idleTimeout: props.idleTimeout,
      ipAddressType: props.ipAddressType,
    };

    const loadBalancer = props.loadBalancer ?? new ApplicationLoadBalancer(this, 'LB', lbProps);

    if (props.certificate !== undefined && props.protocol !== undefined && props.protocol !== ApplicationProtocol.HTTPS) {
      throw new Error('The HTTPS protocol must be used when a certificate is given');
    }
    const protocol = props.protocol ?? (props.certificate ? ApplicationProtocol.HTTPS : ApplicationProtocol.HTTP);

    if (protocol !== ApplicationProtocol.HTTPS && props.redirectHTTP === true) {
      throw new Error('The HTTPS protocol must be used when redirecting HTTP traffic');
    }

    const targetProps: AddApplicationTargetsProps = {
      protocol: props.targetProtocol ?? ApplicationProtocol.HTTP,
      protocolVersion: props.protocolVersion,
    };

    this.listener = loadBalancer.addListener('PublicListener', {
      protocol,
      port: props.listenerPort,
      open: props.openListener ?? true,
      sslPolicy: props.sslPolicy,
    });
    this.targetGroup = this.listener.addTargets('ECS', targetProps);

    if (protocol === ApplicationProtocol.HTTPS) {
      if (props.certificate !== undefined) {
        this.certificate = props.certificate;
      } else {
        if (typeof props.domainName === 'undefined' || typeof props.domainZone === 'undefined') {
          throw new Error('A domain name and zone is required when using the HTTPS protocol');
        }

        this.certificate = new Certificate(this, 'Certificate', {
          domainName: props.domainName,
          validation: CertificateValidation.fromDns(props.domainZone),
        });
      }
    }
    if (this.certificate !== undefined) {
      this.listener.addCertificates('Arns', [ListenerCertificate.fromCertificateManager(this.certificate)]);
    }
    if (props.redirectHTTP) {
      this.redirectListener = loadBalancer.addListener('PublicRedirectListener', {
        protocol: ApplicationProtocol.HTTP,
        port: 80,
        open: props.openListener ?? true,
        defaultAction: ListenerAction.redirect({
          port: props.listenerPort?.toString() || '443',
          protocol: ApplicationProtocol.HTTPS,
          permanent: true,
        }),
      });
    }

    let domainName = loadBalancer.loadBalancerDnsName;
    if (typeof props.domainName !== 'undefined') {
      if (typeof props.domainZone === 'undefined') {
        throw new Error('A Route53 hosted domain zone name is required to configure the specified domain name');
      }

      switch (props.recordType ?? ApplicationLoadBalancedServiceRecordType.ALIAS) {
        case ApplicationLoadBalancedServiceRecordType.ALIAS:
          let aliasRecord = new ARecord(this, 'DNS', {
            zone: props.domainZone,
            recordName: props.domainName,
            target: RecordTarget.fromAlias(new LoadBalancerTarget(loadBalancer)),
          });
          domainName = aliasRecord.domainName;
          break;
        case ApplicationLoadBalancedServiceRecordType.CNAME:
          let cnameRecord = new CnameRecord(this, 'DNS', {
            zone: props.domainZone,
            recordName: props.domainName,
            domainName: loadBalancer.loadBalancerDnsName,
          });
          domainName = cnameRecord.domainName;
          break;
        case ApplicationLoadBalancedServiceRecordType.NONE:
          // Do not create a DNS record
          break;
      }
    }

    if (loadBalancer instanceof ApplicationLoadBalancer) {
      this._applicationLoadBalancer = loadBalancer;
    }

    new cdk.CfnOutput(this, 'LoadBalancerDNS', { value: loadBalancer.loadBalancerDnsName });
    new cdk.CfnOutput(this, 'ServiceURL', { value: protocol.toLowerCase() + '://' + domainName });
  }