pulumi-aws
pulumi-aws copied to clipboard
Root cause 3421 and revert patches 0042 and 0043
What happened?
TLDR: lb.Listener panics if the forward parameter in defaultActions is not specified.
We shipped https://github.com/pulumi/pulumi-aws/pull/3426#issuecomment-1944127515 as a quick fix for https://github.com/pulumi/pulumi-aws/issues/3421
We should properly root cause the issue and revert the patches once we fix it.
More details in https://github.com/pulumi/pulumi-aws/issues/3421#issuecomment-1943569655
Note that the issue does not reproduce in TF and PlanResourceChange does not fix it https://github.com/pulumi/pulumi-aws/pull/3426#issuecomment-1944195346
Example
TestRegress3421 is a regression test for the issue - it should pass without the two upstream patches.
import * as aws from "@pulumi/aws";
const vpc = new aws.ec2.Vpc("main", {cidrBlock: "10.0.0.0/16"});
const subnet = new aws.ec2.Subnet("main", {
vpcId: vpc.id,
cidrBlock: "10.0.12.0/24",
availabilityZone: "us-east-1a"
});
const subnet2 = new aws.ec2.Subnet("subnet2", {
vpcId: vpc.id,
cidrBlock: "10.0.5.0/24",
availabilityZone: "us-east-1b"
});
const secGroup = new aws.ec2.SecurityGroup("allowTls", {
description: "Allow TLS inbound traffic and all outbound traffic",
vpcId: vpc.id,
tags: {
Name: "allow_tls",
},
});
const loadbalancer = new aws.lb.LoadBalancer("payload-lb", {
loadBalancerType: "application",
securityGroups: [secGroup.id],
subnets: [subnet.id, subnet2.id],
internal: true,
});
const targetGroup = new aws.lb.TargetGroup("payload-tg", {
port: 80,
protocol: "HTTP",
targetType: "ip",
vpcId: vpc.id,
});
new aws.lb.Listener("payload-lb-listner-http", {
loadBalancerArn: loadbalancer.arn,
port: 80,
protocol: "HTTP",
defaultActions: [
{
type: "forward",
targetGroupArn: targetGroup.arn,
},
],
});
panic:
Updating (dev)
View in Browser (Ctrl+O): https://app.pulumi.com/venelin-pulumi-corp/lb_panic/dev/updates/42
Type Name Status Info
Type Name Status Info
Type Name Status Info
pulumi:pulumi:Stack lb_panic-dev **failed** 1 er
+ └─ aws:lb:Listener payload-lb-listner-http **creating failed** 1 er
Diagnostics:
aws:lb:Listener (payload-lb-listner-http):
error: error reading from server: EOF
pulumi:pulumi:Stack (lb_panic-dev):
panic: value is null
goroutine 32 [running]:
github.com/hashicorp/go-cty/cty.Value.LengthInt({{{0x115bfd8a8?, 0x14004184880?}}, {0x0?, 0x0?}})
/home/runner/go/pkg/mod/github.com/hashicorp/[email protected]/cty/value_ops.go:989 +0x254
github.com/hashicorp/terraform-provider-aws/internal/service/elbv2.flattenLbForwardActionOneOf({{{0x115bfd8a8?, 0x140041848b0?}}, {0x112e84260?, 0x14004100a20?}}, 0x110dde6e7?, {{0x14003340980, 0x7}, 0x0, 0x0, 0x0, ...}, ...)
/home/runner/work/pulumi-aws/pulumi-aws/upstream/internal/service/elbv2/listener.go:1036 +0x18c
github.com/hashicorp/terraform-provider-aws/internal/service/elbv2.flattenLbForwardAction(0x113cba6e0?, {0x110dde6e7, 0xe}, 0x5?, {{0x14003340980, 0x7}, 0x0, 0x0, 0x0, 0x140043124b0, ...}, ...)
/home/runner/work/pulumi-aws/pulumi-aws/upstream/internal/service/elbv2/listener.go:1014 +0x188
github.com/hashicorp/terraform-provider-aws/internal/service/elbv2.flattenLbListenerActions(0x112eb1480?, {0x110dde6e7, 0xe}, {0x14003346b40?, 0x1, 0x0?})
/home/runner/work/pulumi-aws/pulumi-aws/upstream/internal/service/elbv2/listener.go:979 +0x240
github.com/hashicorp/terraform-provider-aws/internal/service/elbv2.resourceListenerRead({0x115bfd528, 0x140041bcae0}, 0x14004182600, {0x1159ed3c0?, 0x140005f51d0?})
/home/runner/work/pulumi-aws/pulumi-aws/upstream/internal/service/elbv2/listener.go:535 +0x508
github.com/hashicorp/terraform-provider-aws/internal/service/elbv2.resourceListenerCreate({0x115bfd528?, 0x140041bcae0}, 0x14004182600, {0x1159ed3c0?, 0x140005f51d0})
/home/runner/work/pulumi-aws/pulumi-aws/upstream/internal/service/elbv2/listener.go:506 +0xe20
github.com/hashicorp/terraform-provider-aws/internal/provider.New.(*wrappedResource).Create.interceptedHandler[...].func8(0x0?, {0x1159ed3c0?, 0x140005f51d0?})
/home/runner/work/pulumi-aws/pulumi-aws/upstream/internal/provider/intercept.go:112 +0x1d4
github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema.(*Resource).create(0x115bfd528?, {0x115bfd528?, 0x14004167860?}, 0xd?, {0x1159ed3c0?, 0x140005f51d0?})
/home/runner/go/pkg/mod/github.com/pulumi/terraform-plugin-sdk/[email protected]/helper/schema/resource.go:778 +0x64
github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema.(*Resource).Apply(0x1400214ed20, {0x115bfd528, 0x14004167860}, 0x0, 0x14004182380, {0x1159ed3c0, 0x140005f51d0})
/home/runner/go/pkg/mod/github.com/pulumi/terraform-plugin-sdk/[email protected]/helper/schema/resource.go:914 +0x86c
github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2.v2Provider.Apply({0x14000147da0?, {0x14001fcf5a0?, 0x0?, 0x14004167ad0?}}, {0x115bfd528, 0x14004167860}, {0x110de90e5, 0xf}, {0x0?, 0x0}, ...)
/home/runner/go/pkg/mod/github.com/pulumi/pulumi-terraform-bridge/[email protected]/pkg/tfshim/sdk-v2/provider.go:122 +0x140
github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2.(*providerWithPlanResourceChangeDispatch).Apply(0x14002183f50, {0x115bfd528, 0x14004167860}, {0x110de90e5, 0xf}, {0x0, 0x0}, {0x115c0e4e0, 0x14004182380})
/home/runner/go/pkg/mod/github.com/pulumi/pulumi-terraform-bridge/[email protected]/pkg/tfshim/sdk-v2/provider2.go:700 +0xc8
github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge.(*Provider).Create(0x14000c9f980, {0x115bfd528?, 0x14004167410?}, 0x14004093450)
/home/runner/go/pkg/mod/github.com/pulumi/pulumi-terraform-bridge/[email protected]/pkg/tfbridge/provider.go:1025 +0x654
github.com/pulumi/pulumi-terraform-bridge/x/muxer.(*muxer).Create.func1({0x115c5ba20?, 0x14000c9f980?})
/home/runner/go/pkg/mod/github.com/pulumi/pulumi-terraform-bridge/x/[email protected]/muxer.go:363 +0x3c
github.com/pulumi/pulumi-terraform-bridge/x/muxer.resourceMethod[...](0x14002baf020?, 0x14002b196c8, 0x14002b196a8?)
/home/runner/go/pkg/mod/github.com/pulumi/pulumi-terraform-bridge/x/[email protected]/muxer.go:322 +0xc4
github.com/pulumi/pulumi-terraform-bridge/x/muxer.(*muxer).Create(0x14002b19708?, {0x115bfd528?, 0x14004167410?}, 0x113277320?)
/home/runner/go/pkg/mod/github.com/pulumi/pulumi-terraform-bridge/x/[email protected]/muxer.go:362 +0x5c
github.com/pulumi/pulumi/sdk/v3/proto/go._ResourceProvider_Create_Handler.func1({0x115bfd528, 0x14004167410}, {0x11520a260?, 0x14004093450})
/home/runner/go/pkg/mod/github.com/pulumi/pulumi/sdk/[email protected]/proto/go/provider_grpc.pb.go:593 +0x74
github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc.OpenTracingServerInterceptor.func1({0x115bfd528, 0x140041670b0}, {0x11520a260, 0x14004093450}, 0x140040fb660, 0x14004100840)
/home/runner/go/pkg/mod/github.com/grpc-ecosystem/[email protected]/go/otgrpc/server.go:57 +0x2e8
github.com/pulumi/pulumi/sdk/v3/proto/go._ResourceProvider_Create_Handler({0x11583a4e0?, 0x14002baf020}, {0x115bfd528, 0x140041670b0}, 0x14003fc3d80, 0x14002ac7c80)
/home/runner/go/pkg/mod/github.com/pulumi/pulumi/sdk/[email protected]/proto/go/provider_grpc.pb.go:595 +0x12c
google.golang.org/grpc.(*Server).processUnaryRPC(0x14002ab2200, {0x115bfd528, 0x14004167020}, {0x115c2f300, 0x14001890820}, 0x14004168ea0, 0x14002c6b650, 0x11f0b1a40, 0x0)
/home/runner/go/pkg/mod/google.golang.org/[email protected]/server.go:1385 +0xb8c
google.golang.org/grpc.(*Server).handleStream(0x14002ab2200, {0x115c2f300, 0x14001890820}, 0x14004168ea0)
/home/runner/go/pkg/mod/google.golang.org/[email protected]/server.go:1796 +0xc4c
google.golang.org/grpc.(*Server).serveStreams.func2.1()
/home/runner/go/pkg/mod/google.golang.org/[email protected]/server.go:1029 +0x8c
created by google.golang.org/grpc.(*Server).serveStreams.func2 in goroutine 56
/home/runner/go/pkg/mod/google.golang.org/[email protected]/server.go:1040 +0x150
error: update failed
Resources:
7 unchanged
Duration: 7s
Output of pulumi about
.
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).
I created a GRPC test for iterating on this which just runs the Create on the Listener resource:
func TestLBPanic(t *testing.T) {
replay(t, `[
{
"method": "/pulumirpc.ResourceProvider/Configure",
"request": {
"variables": {
"aws:config:region": "us-east-1",
"aws:config:skipCredentialsValidation": "false",
"aws:config:skipMetadataApiCheck": "true",
"aws:config:skipRegionValidation": "true"
},
"args": {
"region": "us-east-1",
"skipCredentialsValidation": "false",
"skipMetadataApiCheck": "true",
"skipRegionValidation": "true",
"version": "6.22.0"
},
"acceptSecrets": true,
"acceptResources": true,
"sendsOldInputs": true,
"sendsOldInputsToDelete": true
},
"response": {
"supportsPreview": true
},
"metadata": {
"kind": "resource",
"mode": "client",
"name": "aws"
}
},
{
"method": "/pulumirpc.ResourceProvider/Create",
"request": {
"urn": "urn:pulumi:dev::lb_panic::aws:lb/listener:Listener::payload-lb-listner-http",
"properties": {
"__defaults": [],
"defaultActions": [
{
"__defaults": [],
"targetGroupArn": "arn:aws:elasticloadbalancing:us-east-1:616138583583:targetgroup/payload-tg-cae0e1a/92aa6f538c20f368",
"type": "forward"
}
],
"loadBalancerArn": "arn:aws:elasticloadbalancing:us-east-1:616138583583:loadbalancer/app/payload-lb-f60c982/289d36c768b0b480",
"port": 80,
"protocol": "HTTP"
}
},
"response:": "*",
"metadata": {
"kind": "resource",
"mode": "client",
"name": "aws"
}
}
]`)
}
~~This goes around the panic with the following hack in the bridge:~~ ~~https://github.com/pulumi/pulumi-terraform-bridge/blob/39a92a469cf6ec3452fdd446d26119852909d6af/pkg/tfshim/sdk-v2/provider_diff.go#L56~~
~~Add:~~
config.Config["forward"] = []interface{}{}
config.Raw["forward"] = []interface{}{}
~~This likely means that TF i passing empty lists there instead of nils - I have yet to verify it though.~~
EDIT: This was an artifact of my local testing setup, not actually true. I'll continue trying to hack it into working.
I've enrolled the listener into PlanResourceChange since it's in the same area, so should be better, hopefully.
Here is the result of dumping cfg and plan from https://github.com/pulumi/pulumi-terraform-bridge/blob/e91ed7ee525a89502467902ae4f8e52d1e2fa694/pkg/tfshim/sdk-v2/provider2.go#L127
cfg=cty.ObjectVal(map[string]cty.Value{"alpn_policy":cty.NullVal(cty.String), "arn":cty.NullVal(cty.String), "certificate_arn":cty.NullVal(cty.String), "default_action":cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"authenticate_cognito":cty.NullVal(cty.List(cty.Object(map[string]cty.Type{"authentication_request_extra_params":cty.Map(cty.String), "on_unauthenticated_request":cty.String, "scope":cty.String, "session_cookie_name":cty.String, "session_timeout":cty.Number, "user_pool_arn":cty.String, "user_pool_client_id":cty.String, "user_pool_domain":cty.String}))), "authenticate_oidc":cty.NullVal(cty.List(cty.Object(map[string]cty.Type{"authentication_request_extra_params":cty.Map(cty.String), "authorization_endpoint":cty.String, "client_id":cty.String, "client_secret":cty.String, "issuer":cty.String, "on_unauthenticated_request":cty.String, "scope":cty.String, "session_cookie_name":cty.String, "session_timeout":cty.Number, "token_endpoint":cty.String, "user_info_endpoint":cty.String}))), "fixed_response":cty.NullVal(cty.List(cty.Object(map[string]cty.Type{"content_type":cty.String, "message_body":cty.String, "status_code":cty.String}))), "forward":cty.NullVal(cty.List(cty.Object(map[string]cty.Type{"stickiness":cty.List(cty.Object(map[string]cty.Type{"duration":cty.Number, "enabled":cty.Bool})), "target_group":cty.Set(cty.Object(map[string]cty.Type{"arn":cty.String, "weight":cty.Number}))}))), "order":cty.NullVal(cty.Number), "redirect":cty.NullVal(cty.List(cty.Object(map[string]cty.Type{"host":cty.String, "path":cty.String, "port":cty.String, "protocol":cty.String, "query":cty.String, "status_code":cty.String}))), "target_group_arn":cty.StringVal("arn:aws:elasticloadbalancing:us-east-1:616138583583:targetgroup/payload-tg-cae0e1a/92aa6f538c20f368"), "type":cty.StringVal("forward")})}), "id":cty.NullVal(cty.String), "load_balancer_arn":cty.StringVal("arn:aws:elasticloadbalancing:us-east-1:616138583583:loadbalancer/app/payload-lb-f60c982/289d36c768b0b480"), "mutual_authentication":cty.NullVal(cty.List(cty.Object(map[string]cty.Type{"ignore_client_certificate_expiry":cty.Bool, "mode":cty.String, "trust_store_arn":cty.String}))), "port":cty.NumberIntVal(80), "protocol":cty.StringVal("HTTP"), "ssl_policy":cty.NullVal(cty.String), "tags":cty.NullVal(cty.Map(cty.String)), "tags_all":cty.NullVal(cty.Map(cty.String)), "timeouts":cty.NullVal(cty.Object(map[string]cty.Type{"create":cty.String, "update":cty.String}))})
plan=&struct { PlannedState cty.Value; PlannedMeta map[string]interface {}; PlannedDiff *terraform.InstanceDiff }{
PlannedState: cty.ObjectVal(map[string]cty.Value{"alpn_policy":cty.NullVal(cty.String), "arn":cty.UnknownVal(cty.String), "certificate_arn":cty.NullVal(cty.String), "default_action":cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"authenticate_cognito":cty.ListValEmpty(cty.Object(map[string]cty.Type{"authentication_request_extra_params":cty.Map(cty.String), "on_unauthenticated_request":cty.String, "scope":cty.String, "session_cookie_name":cty.String, "session_timeout":cty.Number, "user_pool_arn":cty.String, "user_pool_client_id":cty.String, "user_pool_domain":cty.String})), "authenticate_oidc":cty.ListValEmpty(cty.Object(map[string]cty.Type{"authentication_request_extra_params":cty.Map(cty.String), "authorization_endpoint":cty.String, "client_id":cty.String, "client_secret":cty.String, "issuer":cty.String, "on_unauthenticated_request":cty.String, "scope":cty.String, "session_cookie_name":cty.String, "session_timeout":cty.Number, "token_endpoint":cty.String, "user_info_endpoint":cty.String})), "fixed_response":cty.ListValEmpty(cty.Object(map[string]cty.Type{"content_type":cty.String, "message_body":cty.String, "status_code":cty.String})), "forward":cty.ListValEmpty(cty.Object(map[string]cty.Type{"stickiness":cty.List(cty.Object(map[string]cty.Type{"duration":cty.Number, "enabled":cty.Bool})), "target_group":cty.Set(cty.Object(map[string]cty.Type{"arn":cty.String, "weight":cty.Number}))})), "order":cty.UnknownVal(cty.Number), "redirect":cty.ListValEmpty(cty.Object(map[string]cty.Type{"host":cty.String, "path":cty.String, "port":cty.String, "protocol":cty.String, "query":cty.String, "status_code":cty.String})), "target_group_arn":cty.StringVal("arn:aws:elasticloadbalancing:us-east-1:616138583583:targetgroup/payload-tg-cae0e1a/92aa6f538c20f368"), "type":cty.StringVal("forward")})}), "id":cty.UnknownVal(cty.String), "load_balancer_arn":cty.StringVal("arn:aws:elasticloadbalancing:us-east-1:616138583583:loadbalancer/app/payload-lb-f60c982/289d36c768b0b480"), "mutual_authentication":cty.UnknownVal(cty.List(cty.Object(map[string]cty.Type{"ignore_client_certificate_expiry":cty.Bool, "mode":cty.String, "trust_store_arn":cty.String}))), "port":cty.NumberIntVal(80), "protocol":cty.StringVal("HTTP"), "ssl_policy":cty.UnknownVal(cty.String), "tags":cty.NullVal(cty.Map(cty.String)), "tags_all":cty.NullVal(cty.Map(cty.String)), "timeouts":cty.NullVal(cty.Object(map[string]cty.Type{"create":cty.String, "update":cty.String}))}),
PlannedMeta: {
"_new_extra_shim": map[string]interface {}{
"protocol": "HTTP",
},
"e2bfb730-ecaa-11e6-8f88-34363bc7c4c0": map[string]interface {}{
"create": float64(3e+11),
"update": float64(3e+11),
},
},
PlannedDiff: *terraform.InstanceDiff{mu:sync.Mutex{state:0, sema:0x0}, Attributes:map[string]*terraform.ResourceAttrDiff{"arn":*terraform.ResourceAttrDiff{Old:"", New:"", NewComputed:true, NewRemoved:false, NewExtra:interface {}(nil), RequiresNew:false, Sensitive:false, Type:0x0}, "default_action.#":*terraform.ResourceAttrDiff{Old:"", New:"1", NewComputed:false, NewRemoved:false, NewExtra:interface {}(nil), RequiresNew:false, Sensitive:false, Type:0x0}, "default_action.0.order":*terraform.ResourceAttrDiff{Old:"", New:"", NewComputed:true, NewRemoved:false, NewExtra:interface {}(nil), RequiresNew:false, Sensitive:false, Type:0x0}, "default_action.0.target_group_arn":*terraform.ResourceAttrDiff{Old:"", New:"arn:aws:elasticloadbalancing:us-east-1:616138583583:targetgroup/payload-tg-cae0e1a/92aa6f538c20f368", NewComputed:false, NewRemoved:false, NewExtra:interface {}(nil), RequiresNew:false, Sensitive:false, Type:0x0}, "default_action.0.type":*terraform.ResourceAttrDiff{Old:"", New:"forward", NewComputed:false, NewRemoved:false, NewExtra:interface {}(nil), RequiresNew:false, Sensitive:false, Type:0x0}, "load_balancer_arn":*terraform.ResourceAttrDiff{Old:"", New:"arn:aws:elasticloadbalancing:us-east-1:616138583583:loadbalancer/app/payload-lb-f60c982/289d36c768b0b480", NewComputed:false, NewRemoved:false, NewExtra:interface {}(nil), RequiresNew:true, Sensitive:false, Type:0x0}, "mutual_authentication.#":*terraform.ResourceAttrDiff{Old:"", New:"", NewComputed:true, NewRemoved:false, NewExtra:interface {}(nil), RequiresNew:false, Sensitive:false, Type:0x0}, "port":*terraform.ResourceAttrDiff{Old:"", New:"80", NewComputed:false, NewRemoved:false, NewExtra:interface {}(nil), RequiresNew:false, Sensitive:false, Type:0x0}, "protocol":*terraform.ResourceAttrDiff{Old:"", New:"HTTP", NewComputed:false, NewRemoved:false, NewExtra:"HTTP", RequiresNew:false, Sensitive:false, Type:0x0}, "ssl_policy":*terraform.ResourceAttrDiff{Old:"", New:"", NewComputed:true, NewRemoved:false, NewExtra:interface {}(nil), RequiresNew:false, Sensitive:false, Type:0x0}}, Destroy:false, DestroyDeposed:false, DestroyTainted:false, RawConfig:cty.NilVal, RawState:cty.NilVal, RawPlan:cty.NilVal, Meta:map[string]interface {}(nil)},
}
Noticed that forward is:
cty.NullValincfgcty.ListValEmptyinPlannedState- does not exist in
PlannedDiff.
Perhaps we should be ending up with a ListValEmpty for forward in PlannedDiff? I'll see what TF does here next.
I dumped some TF state from
https://github.com/hashicorp/terraform/blob/13e26b60dd545533efab76ab6f48ce20b1e47f37/internal/terraform/node_resource_abstract_instance.go#L860
and got the following:
unmarkedConfigVal=cty.ObjectVal(map[string]cty.Value{"alpn_policy":cty.NullVal(cty.String), "arn":cty.NullVal(cty.String), "certificate_arn":cty.NullVal(cty.String), "default_action":cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"authenticate_cognito":cty.ListValEmpty(cty.Object(map[string]cty.Type{"authentication_request_extra_params":cty.Map(cty.String), "on_unauthenticated_request":cty.String, "scope":cty.String, "session_cookie_name":cty.String, "session_timeout":cty.Number, "user_pool_arn":cty.String, "user_pool_client_id":cty.String, "user_pool_domain":cty.String})), "authenticate_oidc":cty.ListValEmpty(cty.Object(map[string]cty.Type{"authentication_request_extra_params":cty.Map(cty.String), "authorization_endpoint":cty.String, "client_id":cty.String, "client_secret":cty.String, "issuer":cty.String, "on_unauthenticated_request":cty.String, "scope":cty.String, "session_cookie_name":cty.String, "session_timeout":cty.Number, "token_endpoint":cty.String, "user_info_endpoint":cty.String})), "fixed_response":cty.ListValEmpty(cty.Object(map[string]cty.Type{"content_type":cty.String, "message_body":cty.String, "status_code":cty.String})), "forward":cty.ListValEmpty(cty.Object(map[string]cty.Type{"stickiness":cty.List(cty.Object(map[string]cty.Type{"duration":cty.Number, "enabled":cty.Bool})), "target_group":cty.Set(cty.Object(map[string]cty.Type{"arn":cty.String, "weight":cty.Number}))})), "order":cty.NullVal(cty.Number), "redirect":cty.ListValEmpty(cty.Object(map[string]cty.Type{"host":cty.String, "path":cty.String, "port":cty.String, "protocol":cty.String, "query":cty.String, "status_code":cty.String})), "target_group_arn":cty.StringVal("arn:aws:elasticloadbalancing:us-east-1:616138583583:targetgroup/tf-example-lb-tg/bf161d25c508d8d4"), "type":cty.StringVal("forward")})}), "id":cty.NullVal(cty.String), "load_balancer_arn":cty.StringVal("arn:aws:elasticloadbalancing:us-east-1:616138583583:loadbalancer/app/test-lb-tf/cce57494469d0283"), "mutual_authentication":cty.ListValEmpty(cty.Object(map[string]cty.Type{"ignore_client_certificate_expiry":cty.Bool, "mode":cty.String, "trust_store_arn":cty.String})), "port":cty.NumberIntVal(80), "protocol":cty.StringVal("HTTP"), "ssl_policy":cty.NullVal(cty.String), "tags":cty.NullVal(cty.Map(cty.String)), "tags_all":cty.NullVal(cty.Map(cty.String)), "timeouts":cty.NullVal(cty.Object(map[string]cty.Type{"create":cty.String, "update":cty.String}))})
proposedNewVal=cty.ObjectVal(map[string]cty.Value{"alpn_policy":cty.NullVal(cty.String), "arn":cty.NullVal(cty.String), "certificate_arn":cty.NullVal(cty.String), "default_action":cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"authenticate_cognito":cty.ListValEmpty(cty.Object(map[string]cty.Type{"authentication_request_extra_params":cty.Map(cty.String), "on_unauthenticated_request":cty.String, "scope":cty.String, "session_cookie_name":cty.String, "session_timeout":cty.Number, "user_pool_arn":cty.String, "user_pool_client_id":cty.String, "user_pool_domain":cty.String})), "authenticate_oidc":cty.ListValEmpty(cty.Object(map[string]cty.Type{"authentication_request_extra_params":cty.Map(cty.String), "authorization_endpoint":cty.String, "client_id":cty.String, "client_secret":cty.String, "issuer":cty.String, "on_unauthenticated_request":cty.String, "scope":cty.String, "session_cookie_name":cty.String, "session_timeout":cty.Number, "token_endpoint":cty.String, "user_info_endpoint":cty.String})), "fixed_response":cty.ListValEmpty(cty.Object(map[string]cty.Type{"content_type":cty.String, "message_body":cty.String, "status_code":cty.String})), "forward":cty.ListValEmpty(cty.Object(map[string]cty.Type{"stickiness":cty.List(cty.Object(map[string]cty.Type{"duration":cty.Number, "enabled":cty.Bool})), "target_group":cty.Set(cty.Object(map[string]cty.Type{"arn":cty.String, "weight":cty.Number}))})), "order":cty.NullVal(cty.Number), "redirect":cty.ListValEmpty(cty.Object(map[string]cty.Type{"host":cty.String, "path":cty.String, "port":cty.String, "protocol":cty.String, "query":cty.String, "status_code":cty.String})), "target_group_arn":cty.StringVal("arn:aws:elasticloadbalancing:us-east-1:616138583583:targetgroup/tf-example-lb-tg/bf161d25c508d8d4"), "type":cty.StringVal("forward")})}), "id":cty.NullVal(cty.String), "load_balancer_arn":cty.StringVal("arn:aws:elasticloadbalancing:us-east-1:616138583583:loadbalancer/app/test-lb-tf/cce57494469d0283"), "mutual_authentication":cty.ListValEmpty(cty.Object(map[string]cty.Type{"ignore_client_certificate_expiry":cty.Bool, "mode":cty.String, "trust_store_arn":cty.String})), "port":cty.NumberIntVal(80), "protocol":cty.StringVal("HTTP"), "ssl_policy":cty.NullVal(cty.String), "tags":cty.NullVal(cty.Map(cty.String)), "tags_all":cty.NullVal(cty.Map(cty.String)), "timeouts":cty.NullVal(cty.Object(map[string]cty.Type{"create":cty.String, "update":cty.String}))})
resp=providers.PlanResourceChangeResponse{
PlannedState: cty.ObjectVal(map[string]cty.Value{"alpn_policy":cty.NullVal(cty.String), "arn":cty.UnknownVal(cty.String), "certificate_arn":cty.NullVal(cty.String), "default_action":cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"authenticate_cognito":cty.ListValEmpty(cty.Object(map[string]cty.Type{"authentication_request_extra_params":cty.Map(cty.String), "on_unauthenticated_request":cty.String, "scope":cty.String, "session_cookie_name":cty.String, "session_timeout":cty.Number, "user_pool_arn":cty.String, "user_pool_client_id":cty.String, "user_pool_domain":cty.String})), "authenticate_oidc":cty.ListValEmpty(cty.Object(map[string]cty.Type{"authentication_request_extra_params":cty.Map(cty.String), "authorization_endpoint":cty.String, "client_id":cty.String, "client_secret":cty.String, "issuer":cty.String, "on_unauthenticated_request":cty.String, "scope":cty.String, "session_cookie_name":cty.String, "session_timeout":cty.Number, "token_endpoint":cty.String, "user_info_endpoint":cty.String})), "fixed_response":cty.ListValEmpty(cty.Object(map[string]cty.Type{"content_type":cty.String, "message_body":cty.String, "status_code":cty.String})), "forward":cty.ListValEmpty(cty.Object(map[string]cty.Type{"stickiness":cty.List(cty.Object(map[string]cty.Type{"duration":cty.Number, "enabled":cty.Bool})), "target_group":cty.Set(cty.Object(map[string]cty.Type{"arn":cty.String, "weight":cty.Number}))})), "order":cty.UnknownVal(cty.Number), "redirect":cty.ListValEmpty(cty.Object(map[string]cty.Type{"host":cty.String, "path":cty.String, "port":cty.String, "protocol":cty.String, "query":cty.String, "status_code":cty.String})), "target_group_arn":cty.StringVal("arn:aws:elasticloadbalancing:us-east-1:616138583583:targetgroup/tf-example-lb-tg/bf161d25c508d8d4"), "type":cty.StringVal("forward")})}), "id":cty.UnknownVal(cty.String), "load_balancer_arn":cty.StringVal("arn:aws:elasticloadbalancing:us-east-1:616138583583:loadbalancer/app/test-lb-tf/cce57494469d0283"), "mutual_authentication":cty.UnknownVal(cty.List(cty.Object(map[string]cty.Type{"ignore_client_certificate_expiry":cty.Bool, "mode":cty.String, "trust_store_arn":cty.String}))), "port":cty.NumberIntVal(80), "protocol":cty.StringVal("HTTP"), "ssl_policy":cty.UnknownVal(cty.String), "tags":cty.NullVal(cty.Map(cty.String)), "tags_all":cty.UnknownVal(cty.Map(cty.String)), "timeouts":cty.NullVal(cty.Object(map[string]cty.Type{"create":cty.String, "update":cty.String}))}),
RequiresReplace: {
{
cty.GetAttrStep{Name:"load_balancer_arn"},
},
{
cty.GetAttrStep{Name:"id"},
},
},
PlannedPrivate: {0x7b, 0x22, 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x73, 0x68, 0x69, 0x6d, 0x22, 0x3a, 0x7b, 0x22, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, 0x3a, 0x22, 0x48, 0x54, 0x54, 0x50, 0x22, 0x7d, 0x2c, 0x22, 0x65, 0x32, 0x62, 0x66, 0x62, 0x37, 0x33, 0x30, 0x2d, 0x65, 0x63, 0x61, 0x61, 0x2d, 0x31, 0x31, 0x65, 0x36, 0x2d, 0x38, 0x66, 0x38, 0x38, 0x2d, 0x33, 0x34, 0x33, 0x36, 0x33, 0x62, 0x63, 0x37, 0x63, 0x34, 0x63, 0x30, 0x22, 0x3a, 0x7b, 0x22, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2c, 0x22, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x7d, 0x7d},
Diagnostics: nil,
LegacyTypeSystem: true,
}
Noticeably, PlanResourceChangeResponse's PlannedState is basically identical to the PlannedState we return.
Can't really compare PlannedDiff here as TF doesn't integrate at that level, still digging into where I can get the TF equivalent of PlannedDiff.
Might be easier to observe the diffs with just an update to the relevant arguments, instead of a Create.
Here is the modified pulumi program:
import * as aws from "@pulumi/aws";
const vpc = new aws.ec2.Vpc("main", { cidrBlock: "10.0.0.0/16" });
const subnet = new aws.ec2.Subnet("main", {
vpcId: vpc.id,
cidrBlock: "10.0.12.0/24",
availabilityZone: "us-east-1a"
});
const subnet2 = new aws.ec2.Subnet("subnet2", {
vpcId: vpc.id,
cidrBlock: "10.0.5.0/24",
availabilityZone: "us-east-1b"
});
const secGroup = new aws.ec2.SecurityGroup("allowTls", {
description: "Allow TLS inbound traffic and all outbound traffic",
vpcId: vpc.id,
tags: {
Name: "allow_tls",
},
});
const loadbalancer = new aws.lb.LoadBalancer("payload-lb", {
loadBalancerType: "application",
securityGroups: [secGroup.id],
subnets: [subnet.id, subnet2.id],
internal: true,
});
const targetGroup = new aws.lb.TargetGroup("payload-tg", {
port: 80,
protocol: "HTTP",
targetType: "ip",
vpcId: vpc.id,
});
export const vpcId = vpc.id;
export const subnet1Id = subnet.id
export const subnet2Id = subnet2.id
new aws.lb.Listener("payload-lb-listner-http", {
loadBalancerArn: loadbalancer.arn,
port: 80,
protocol: "HTTP",
defaultActions: [
{
type: "forward",
// type: "redirect",
targetGroupArn: targetGroup.arn,
redirect: {
statusCode: "HTTP_301",
host: "google.com"
}
},
],
});
And the equivalent TF one:
provider "aws" {
region = "us-east-1"
version = "5.37"
}
resource "aws_lb" "test" {
name = "test-lb-tf"
load_balancer_type = "application"
subnets = ["subnet-0b2a83a27caf03420", "subnet-0e3cfe0880125b082"]
internal = true
}
resource "aws_lb_target_group" "test" {
name = "tf-example-lb-tg"
port = 80
protocol = "HTTP"
vpc_id = "vpc-018901b37128b063b"
}
resource "aws_lb_listener" "front_end" {
load_balancer_arn = aws_lb.test.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
# type = "redirect"
target_group_arn = aws_lb_target_group.test.arn
redirect {
status_code = "HTTP_301"
host = "google.com"
}
}
}
Having both the forward and redirect parameters is tolerated upstream.
Will try comparing the diffs etc again between these two.
EDIT: Actually, I might have better luck logging on the upstream provider side and comparing what the upstream provider gets when used via TF and via pulumi - I'll try that next.
I dumped the resource data from the Listener create call. Noticed some differences:
In RawConfig:
pulumi:
v: map[string]interface {}{
"alpn_policy": nil,
"arn": nil,
"certificate_arn": nil,
"default_action": []interface {}{
map[string]interface {}{
"authenticate_cognito": nil,
"authenticate_oidc": nil,
"fixed_response": nil,
"forward": nil,
"order": nil,
"redirect": []interface {}{
map[string]interface {}{
"host": "google.com",
"path": "/#{path}",
"port": "#{port}",
"protocol": "#{protocol}",
"query": "#{query}",
"status_code": "HTTP_301",
},
},
"target_group_arn": "arn:aws:elasticloadbalancing:us-east-1:616138583583:targetgroup/payload-tg-0371ecb/2b75c3816ba75b87",
"type": "forward",
},
},
"id": nil,
"load_balancer_arn": "arn:aws:elasticloadbalancing:us-east-1:616138583583:loadbalancer/app/payload-lb-f27807c/2887b439ba17141e",
"mutual_authentication": nil,
"port": &big.Float{
prec: 0x40,
mode: 0x0,
acc: 0,
form: 0x1,
neg: false,
mant: {0xa000000000000000},
exp: 7,
},
"protocol": "HTTP",
"ssl_policy": nil,
"tags": nil,
"tags_all": nil,
"timeouts": nil,
},
TF:
v: map[string]interface {}{
"alpn_policy": nil,
"arn": nil,
"certificate_arn": nil,
"default_action": []interface {}{
map[string]interface {}{
"authenticate_cognito": []interface {}{
},
"authenticate_oidc": []interface {}{
},
"fixed_response": []interface {}{
},
"forward": []interface {}{
},
"order": nil,
"redirect": []interface {}{
map[string]interface {}{
"host": "google.com",
"path": nil,
"port": nil,
"protocol": nil,
"query": nil,
"status_code": "HTTP_301",
},
},
"target_group_arn": "arn:aws:elasticloadbalancing:us-east-1:616138583583:targetgroup/tf-example-lb-tg/bf161d25c508d8d4",
"type": "forward",
},
},
"id": nil,
"load_balancer_arn": "arn:aws:elasticloadbalancing:us-east-1:616138583583:loadbalancer/app/test-lb-tf/aacedeb23b2b6245",
"mutual_authentication": []interface {}{
},
"port": &big.Float{
prec: 0x40,
mode: 0x0,
acc: 0,
form: 0x1,
neg: false,
mant: {0xa000000000000000},
exp: 7,
},
"protocol": "HTTP",
"ssl_policy": nil,
"tags": nil,
"tags_all": nil,
"timeouts": nil,
},
Also state:
pulumi:
state: &terraform.InstanceState{}
TF:
state: &terraform.InstanceState{
ID: "",
Attributes: {},
Ephemeral: terraform.EphemeralState{},
Meta: {},
ProviderMeta: cty.Value{
ty: cty.Type{
typeImpl: cty.typeObject{
typeImplSigil: cty.typeImplSigil{},
AttrTypes: {
},
},
},
v: nil,
},
RawConfig: cty.Value{},
RawState: cty.Value{},
RawPlan: cty.Value{},
Tainted: false,
mu: sync.Mutex{},
}
as well as some differences in tags_all but I believe that is expected.
Specifically, what I believe is causing the issue here is forward in RawConfig - we pass nil while in TF they have []interface {}{}
Also, unrelated, but noticed the lack of defaults applied on the TF side. I believe this is related to https://github.com/pulumi/pulumi-terraform-bridge/issues/1546#issuecomment-1866565333 but I have yet to write down what I know for this in a separate issue.
I verified that makeResourceInputs does not return a value for forward here https://github.com/pulumi/pulumi-terraform-bridge/blob/173822242c0df5fad503dd16135895a05bb02c71/pkg/tfbridge/schema.go#L1224
I have a "fix" here: https://github.com/pulumi/pulumi-terraform-bridge/pull/1688 and have verified that it gets rid of the diff in the values passed to the LB Create, barring resource ARNs, defaults, tags and the state being nil.
https://github.com/pulumi/pulumi-terraform-bridge/pull/1688 was not the full story - Looks like TF does send nulls for MaxItemsOne properties sometimes:
https://github.com/pulumi/pulumi-fastly/actions/runs/8023474176/job/21920355421?pr=446#step:22:86
https://github.com/fastly/terraform-provider-fastly/blob/1cd5da77207aee9f1a1bd1813f091fc0f45998cc/fastly/block_fastly_service_product_enablement.go#L83C1-L93C3
Investigating the issue again in https://github.com/pulumi/pulumi-terraform-bridge/pull/1725.
I've ran downstream tests on all the bridged providers and collected the following groups of errors:
Observing some issues around defaults and ConflictsWith/ExactlyOneOf: https://github.com/pulumi/pulumi-cloudflare/pull/671 https://github.com/pulumi/pulumi-docker/pull/1018 https://github.com/pulumi/pulumi-vault/pull/428 https://github.com/pulumi/pulumi-aws/pull/3561 https://github.com/pulumi/pulumi-gcp/pull/1771
Issues around MinLength 1: https://github.com/pulumi/pulumi-openstack/pull/525 https://github.com/pulumi/pulumi-fastly/pull/460 https://github.com/pulumi/pulumi-azure/pull/1818
Attribute must be a single value, not a list: https://github.com/pulumi/pulumi-rke/pull/284
Value for unconfigurable attribute: https://github.com/pulumi/pulumi-linode/pull/522
I'll work through them all but most of these look like Check issues - these should be solvable by not doing the default empty list during Check, similarly to what we did for default values in https://github.com/pulumi/pulumi-terraform-bridge/issues/1546
The last one I haven't seen before but might also be an issue with Check.
The plan is to write regression tests for all of these in the bridge and in at least one provider for each and then make sure the change passes before re-merging.
Yeah we can pretest the PR against all the providers again before merging. But I'm curious what you find on the Check issues. Thanks!
The RKE error is the only one I was not able to repro in tests so far: https://github.com/pulumi/pulumi-rke/actions/runs/8143179673/job/22290626266
We have a slightly odd schema there. upstream:
"role": {
Type: schema.TypeList,
Required: true,
Description: "Node roles in k8s cluster [controlplane/worker/etcd])",
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice(rkeClusterNodesRoles, true),
},
},
"roles": {
Type: schema.TypeString,
Optional: true,
Deprecated: "Use role instead",
Description: "Node role in kubernetes cluster [controlplane/worker/etcd], specified by a comma-separated string",
ValidateFunc: validation.StringInSlice(rkeClusterNodesRoles, true),
},
us:
"nodes": {
Elem: &tfbridge.SchemaInfo{
Fields: map[string]*tfbridge.SchemaInfo{
"roles": {
Name: "rolesDeprecated",
CSharpName: "RolesDeprecated",
},
},
},
},
Then the test has:
roles: [ "controlplane", "etcd", "worker" ],
Interestingly, no MaxItemsOne anywhere in these properties, so not sure why my changes are causing a regression there.
My attempts at reproing are in https://github.com/pulumi/pulumi-terraform-bridge/pull/1725/files TestSingularAndPluralProp and TestSingularAndPluralPropTopLevel. I'll run the examples next and dump the grpc logs to see what is happening there.
Sanitized GRPC log from before my change:
{
"method": "/pulumirpc.ResourceProvider/Check",
"request": {
"urn": "urn:pulumi:dev::nodejs-singlenode::rke:index/cluster:Cluster::actions",
"olds": {},
"news": {
"cloudProvider": {
"name": "aws"
},
"clusterName": "nodejs-test-cluster",
"enableCriDockerd": true,
"nodes": [
{
"address": "35.91.63.227",
"internalAddress": "172.31.20.126",
"roles": [
"controlplane",
"etcd",
"worker"
],
"user": "ubuntu"
}
]
},
"randomSeed": "u4bzc8sXQnlykomRfaRaMyMIySbIvcoLDM8bOH6UoKE="
},
"response": {
"inputs": {
"__defaults": [
"customCerts",
"dind",
"dindDnsServer",
"dindStorageDriver",
"disablePortCheck",
"kubernetesVersion",
"updateOnly"
],
"cloudProvider": {
"__defaults": [],
"name": "aws"
},
"clusterName": "nodejs-test-cluster",
"customCerts": false,
"dind": false,
"dindDnsServer": "",
"dindStorageDriver": "",
"disablePortCheck": false,
"enableCriDockerd": true,
"kubernetesVersion": "v1.26.9-rancher1-1",
"nodes": [
{
"__defaults": [],
"address": "35.91.63.227",
"internalAddress": "172.31.20.126",
"roles": [
"controlplane",
"etcd",
"worker"
],
"user": {
"4dabf18193072939515e22adb298388d": "1b47061264138c4ac30d75fd1eb44270",
"value": "ubuntu"
}
}
],
"updateOnly": false
}
},
"metadata": {
"kind": "resource",
"mode": "client",
"name": "rke"
}
}
After:
{
"method": "/pulumirpc.ResourceProvider/Check",
"request": {
"urn": "urn:pulumi:dev::nodejs-singlenode::rke:index/cluster:Cluster::actions",
"olds": {},
"news": {
"cloudProvider": {
"name": "aws"
},
"clusterName": "nodejs-test-cluster",
"enableCriDockerd": true,
"nodes": [
{
"address": "35.91.63.227",
"internalAddress": "172.31.20.126",
"roles": [
"controlplane",
"etcd",
"worker"
],
"user": "ubuntu"
}
]
},
"randomSeed": "oKVLyrq0I4TuGOa3V1UKwDPUVugpOi32s8KXbhaj60M="
},
"response": {
"inputs": {
"__defaults": [
"customCerts",
"dind",
"dindDnsServer",
"dindStorageDriver",
"disablePortCheck",
"kubernetesVersion",
"updateOnly"
],
"authentication": null,
"authorization": null,
"bastionHost": null,
"cloudProvider": {
"__defaults": [],
"awsCloudConfig": null,
"awsCloudProvider": null,
"azureCloudConfig": null,
"azureCloudProvider": null,
"name": "aws",
"openstackCloudConfig": null,
"openstackCloudProvider": null,
"vsphereCloudConfig": null,
"vsphereCloudProvider": null
},
"clusterName": "nodejs-test-cluster",
"customCerts": false,
"dind": false,
"dindDnsServer": "",
"dindStorageDriver": "",
"disablePortCheck": false,
"dns": null,
"enableCriDockerd": true,
"ingress": null,
"kubernetesVersion": "v1.26.9-rancher1-1",
"monitoring": null,
"network": null,
"nodes": [
{
"__defaults": [],
"address": "35.91.63.227",
"internalAddress": "172.31.20.126",
"rolesDeprecated": [
"controlplane",
"etcd",
"worker"
],
"user": {
"4dabf18193072939515e22adb298388d": "1b47061264138c4ac30d75fd1eb44270",
"value": "ubuntu"
}
}
],
"restore": null,
"rotateCertificates": null,
"services": null,
"servicesEtcdDeprecated": null,
"servicesKubeApiDeprecated": null,
"servicesKubeControllerDeprecated": null,
"servicesKubeProxyDeprecated": null,
"servicesKubeSchedulerDeprecated": null,
"servicesKubeletDeprecated": null,
"systemImages": null,
"updateOnly": false,
"upgradeStrategy": null
},
"failures": [
{
"reason": "Missing required argument. The argument \"nodes.0.role\" is required, but no definition was found.. Examine values at 'actions.nodes[0].roles'."
},
{
"reason": "Attribute must be a single value, not a list. Examine values at 'actions.nodes[0].rolesDeprecated'."
}
]
},
"metadata": {
"kind": "resource",
"mode": "client",
"name": "rke"
}
}
Notice that the nodes[0].roles input used to get translated to roles but now becomes rolesDeprecated, which isn't the right property.
The RKE error seems present on master too, so unrelated to my changes. I've raised https://github.com/pulumi/pulumi-terraform-bridge/issues/1729 for that.
https://github.com/pulumi/pulumi-terraform-bridge/pull/1725/commits/f9630084b1419c057e7386a114e972b9fef844ac should have addressed the other issues, pre-testing the change in all providers now.
Blocked by https://github.com/pulumi/pulumi-terraform-bridge/issues/1767
I understand this is still blocked right. Marking it as such, we'll revisit periodically.