pulumi / pulumi-ai

226 stars 16 forks source link

AWS Application Load Balancer cannot be created with HTTPS target group #66

Closed smsmithee closed 10 months ago

smsmithee commented 10 months ago

What happened?

I'm trying to create an Application load balancer with a target group that sends to my servers via HTTPS; however, the Pulumi AWS SDK is throwing a null pointer exception due to TargetGroupTargetHealthState. My code does not set that field as it is not a valid element for an application load balancer. I tried setting it anyway and the Pulumi code errors saying that field cannot exist if the target group is using HTTPS

Here is the error I get when I do NOT include the targetGroupTargetHealthStatus (matches the example provided):

error: Running program [PID: 1887](/usr/lib/jvm/temurin-11-jdk-amd64/bin/java -classpath /usr/share/apache-maven-3.8.8/boot/plexus-classworlds-2.6.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.8.8/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.8.8 -Dlibrary.jansi.path=/usr/share/apache-maven-3.8.8/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/runner/work/selfiie-aws-pulumi-core-stage/selfiie-aws-pulumi-core-stage org.codehaus.plexus.classworlds.launcher.Launcher -Dorg.slf4j.simpleLogger.defaultLogLevel=warn --no-transfer-progress compile exec:java) failed with an unhandled exception:
      java.lang.UnsupportedOperationException: Convert [com.pulumi.aws.alb.TargetGroup.targetHealthStates]: Error converting 'java.util.Collections$UnmodifiableRandomAccessList' to 'TypeShape{type=interface java.util.List, parameters=[TypeShape{type=class com.pulumi.aws.alb.outputs.TargetGroupTargetHealthState, parameters=[]}]}'. null
        at com.pulumi.serialization.internal.Converter.convertObjectUntyped(Converter.java:119)
        at com.pulumi.serialization.internal.Converter.convertValue(Converter.java:86)
        at com.pulumi.core.internal.OutputCompletionSource.setValue(OutputCompletionSource.java:95)
        at com.pulumi.deployment.internal.DeploymentImpl$ReadOrRegisterResourceInternal.lambda$completeResourceAsync$0(DeploymentImpl.java:1187)
        at java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:642)
        at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:478)
        at java.base/java.lang.Thread.run(Thread.java:829)
      Caused by: java.lang.NullPointerException
        at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:903)
        at com.google.common.collect.ImmutableList$Builder.add(ImmutableList.java:815)
        at com.pulumi.serialization.internal.Converter.tryConvertList(Converter.java:642)
        at com.pulumi.serialization.internal.Converter.tryConvertObjectInner(Converter.java:277)
        at com.pulumi.serialization.internal.Converter.convertObjectUntyped(Converter.java:115)
        ... 6 more
      error: an unhandled error occurred: '/usr/bin/mvn /usr/bin/mvn -Dorg.slf4j.simpleLogger.defaultLogLevel=warn --no-transfer-progress compile exec:java' exited with non-zero exit code: 32

Here is the error I get when I DO include the targetGroupTargetHealthStatus:

updating urn:pulumi:stage::selfiie-aws-pulumi-core::aws:alb/targetGroup:TargetGroup::targetGroup: 1 error occurred:
        * modifying Target Group Attributes: InvalidConfigurationRequest: A target group with HTTPS protocol does not support the attribute target_health_state.unhealthy.connection_termination.enabled

Example

import com.pulumi.Pulumi;
import com.pulumi.aws.alb.Listener;
import com.pulumi.aws.alb.ListenerArgs;
import com.pulumi.aws.alb.ListenerRule;
import com.pulumi.aws.alb.ListenerRuleArgs;
import com.pulumi.aws.alb.LoadBalancer;
import com.pulumi.aws.alb.LoadBalancerArgs;
import com.pulumi.aws.alb.TargetGroup;
import com.pulumi.aws.alb.TargetGroupArgs;
import com.pulumi.aws.alb.inputs.ListenerDefaultActionArgs;
import com.pulumi.aws.alb.inputs.ListenerDefaultActionFixedResponseArgs;
import com.pulumi.aws.alb.inputs.ListenerDefaultActionRedirectArgs;
import com.pulumi.aws.alb.inputs.ListenerRuleActionArgs;
import com.pulumi.aws.alb.inputs.ListenerRuleConditionArgs;
import com.pulumi.aws.alb.inputs.ListenerRuleConditionPathPatternArgs;
import com.pulumi.aws.alb.inputs.TargetGroupHealthCheckArgs;
import com.pulumi.aws.ec2.Instance;
import com.pulumi.aws.ec2.InstanceArgs;
import com.pulumi.aws.ec2.SecurityGroup;
import com.pulumi.aws.ec2.SecurityGroupArgs;
import com.pulumi.aws.ec2.Subnet;
import com.pulumi.aws.ec2.SubnetArgs;
import com.pulumi.aws.ec2.Vpc;
import com.pulumi.aws.ec2.VpcArgs;
import com.pulumi.aws.ec2.enums.InstanceType;
import com.pulumi.aws.ec2.enums.Tenancy;
import com.pulumi.aws.ec2.inputs.SecurityGroupEgressArgs;
import com.pulumi.aws.ec2.inputs.SecurityGroupIngressArgs;
import com.pulumi.core.Output;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;

public class CoreInfrastructureStage {

  public static void main(String[] args) {
    Pulumi.run(ctx -> {

    var vpc = new Vpc("stageVpc", VpcArgs.builder()
          .cidrBlock("10.10.0.0/16")
          .instanceTenancy(Tenancy.Default.getValue())
          .enableDnsSupport(true)
          .enableDnsHostnames(false)
          .build());

      var subnet1 = new Subnet("subnet1", SubnetArgs.builder()
          .vpcId(vpc.id())
          .cidrBlock("10.10.0.0/20")
          .mapPublicIpOnLaunch(true)
          .availabilityZone("us-west-2a")
          .build(), CustomResourceOptions.builder()
              .dependsOn(List.of(vpc))
              .build());

      var subnet2 = new Subnet("subnet2", SubnetArgs.builder()
          .vpcId(vpc.id())
          .cidrBlock("10.10.16.0/20")
          .mapPublicIpOnLaunch(true)
          .availabilityZone("us-west-2b")
          .build(), CustomResourceOptions.builder()
              .dependsOn(List.of(vpc))
              .build());

      var subnet3 = new Subnet("subnet3", SubnetArgs.builder()
          .vpcId(vpc.id())
          .cidrBlock("10.10.32.0/20")
          .mapPublicIpOnLaunch(false)
          .availabilityZone("us-west-2a")
          .build(), CustomResourceOptions.builder()
              .dependsOn(List.of(vpc))
              .build());

      var subnet4 = new Subnet("subnet4", SubnetArgs.builder()
          .vpcId(vpc.id())
          .cidrBlock("10.10.48.0/20")
          .mapPublicIpOnLaunch(false)
          .availabilityZone("us-west-2b")
          .build(), CustomResourceOptions.builder()
              .dependsOn(List.of(vpc))
              .build());

      var lbSg = new SecurityGroup("LoadBalancerSecurityGroup", SecurityGroupArgs.builder()
          .vpcId(vpc.id())
          .ingress(SecurityGroupIngressArgs.builder()
              .protocol("tcp")
              .description("Allow TLS (443) from the internet")
              .fromPort(443)
              .toPort(443)
              .cidrBlocks("0.0.0.0/0")
              .build())
          .build(), CustomResourceOptions.builder()
              .dependsOn(List.of(vpc))
              .build());

      var lb = new LoadBalancer("loadBalancer", LoadBalancerArgs.builder()
          .loadBalancerType("application")
          .subnets(Output.concatList(subnet1.id().applyValue(List::of), subnet2.id().applyValue(List::of)))
          .securityGroups(lbSg.id().applyValue(List::of))
          .build());

      var tg = new TargetGroup("targetGroup", TargetGroupArgs.builder()
          .port(443)
          .protocol("HTTPS")
          .vpcId(vpc.id())
          .healthCheck(TargetGroupHealthCheckArgs.builder()
              .enabled(true)
              .path("/")
              .protocol("HTTPS")
              .matcher("401")
              .build())
          .build());

      var ec2Sg = new SecurityGroup("Ec2SecurityGroup", SecurityGroupArgs.builder()
          .vpcId(vpc.id())
          .ingress(SecurityGroupIngressArgs.builder()
              .description("Allow load balancer access to port 443")
              .protocol("tcp")
              .fromPort(443)
              .toPort(443)
              .securityGroups(lbSg.id().applyValue(List::of))
              .build())
          .egress(SecurityGroupEgressArgs.builder()
              .description("Allow all outbound traffic to internet")
              .fromPort(0)
              .toPort(0)
              .protocol("-1")
              .cidrBlocks("0.0.0.0/0")
              .ipv6CidrBlocks("::/0")
              .build())
          .build(), CustomResourceOptions.builder()
              .dependsOn(List.of(vpc))
              .build());

      var ec2_1 = new Instance("ec2_1", InstanceArgs.builder()
          .ami("ami-03fd0aa14bd102718")
          .associatePublicIpAddress(false)
          .availabilityZone(subnet3.availabilityZone())
          .instanceType(InstanceType.T4g_Micro)
          .vpcSecurityGroupIds(ec2Sg.id().applyValue(List::of))
          .subnetId(subnet3.id())
          .build(), CustomResourceOptions.builder()
              .dependsOn(List.of(subnet3, ec2Sg))
              .build());

      var ec2_2 = new Instance("ec2_2", InstanceArgs.builder()
          .ami("ami-03fd0aa14bd102718")
          .associatePublicIpAddress(false)
          .availabilityZone(subnet4.availabilityZone())
          .instanceType(InstanceType.T4g_Micro)
          .vpcSecurityGroupIds(ec2Sg.id().applyValue(List::of))
          .subnetId(subnet4.id())
          .build(), CustomResourceOptions.builder()
              .dependsOn(List.of(subnet3, ec2Sg))
              .build());

      var nonTlsListener = new Listener("nonTlsListener", ListenerArgs.builder()
          .loadBalancerArn(lb.arn())
          .port(80)
          .protocol("HTTP")
          .defaultActions(List.of(
              ListenerDefaultActionArgs.builder()
                  .type("redirect")
                  .redirect(ListenerDefaultActionRedirectArgs.builder()
                      .port("443")
                      .protocol("HTTPS")
                      .statusCode("HTTP_301")
                      .build())
                  .build()))
          .build());

      var tlsListener = new Listener("tlsListener", ListenerArgs.builder()
          .loadBalancerArn(lb.arn())
          .port(443)
          .protocol("HTTPS")
          .defaultActions(List.of(
              ListenerDefaultActionArgs.builder()
                  .type("fixed-response")
                  .fixedResponse(ListenerDefaultActionFixedResponseArgs.builder()
                      .statusCode("401")
                      .contentType("application/json")
                      .messageBody("{\n\"type\":\"Unauthorized\",\n  \"status\":401\n}")
                      .build())
                  .build()))
          .build());

      var listenerRule = new ListenerRule("listenerRule", ListenerRuleArgs.builder()
          .listenerArn(tlsListener.arn())
          .conditions(List.of(
              ListenerRuleConditionArgs.builder()
                  .pathPattern(ListenerRuleConditionPathPatternArgs.builder()
                      .values(List.of("/api"))
                      .build())
                  .build()))
          .actions(List.of(
              ListenerRuleActionArgs.builder()
                  .type("forward")
                  .targetGroupArn(tg.arn())
                  .build()))
          .priority(10)
          .build()
      );
    });
  }
}

Output of pulumi about

This is built using pulumi/actions@v5 in a GitHub action. Here is the output of the pulumi version: 3.97.0 warning: A new version of Pulumi is available. To upgrade from version '3.97.0' to '3.100.0', visit https://pulumi.com/docs/install/ for manual instructions and release notes. Pulumi is not detected in the PATH. Proceeding to download Matched version: v3.100.0 Install destination is /home/runner/.pulumi Successfully deleted pre-existing /home/runner/.pulumi/bin /usr/bin/tar xz --warning=no-unknown-keyword --overwrite -C /home/runner/.pulumi -f /home/runner/work/_temp/498e3d6e-5125-4515-a838-e549827726f3 Logging into the Pulumi Cloud backend.

The Java code dependencies are:

com.pulumi pulumi 0.9.9
<!-- https://mvnrepository.com/artifact/com.pulumi/aws -->
<dependency>
  <groupId>com.pulumi</groupId>
  <artifactId>aws</artifactId>
  <version>6.17.0</version>
</dependency>

Additional context

No response

Contributing

Vote on this issue by adding a 👍 reaction. To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).

AaronFriel commented 10 months ago

@smsmithee Sorry you ran into this! It looks like this is probably the other issue, so we'll treat this as a duplicate for now.

AaronFriel commented 10 months ago

Closing as a duplicate of the upstream Java issue: