-
Notifications
You must be signed in to change notification settings - Fork 100
Description
Module version
github.com/hashicorp/terraform-plugin-framework v1.17.0
Relevant provider source code
func (r IncusNetworkLBResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"network": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"listen_address": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"description": schema.StringAttribute{
Optional: true,
Computed: true,
Default: stringdefault.StaticString(""),
},
"project": schema.StringAttribute{
Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
},
"remote": schema.StringAttribute{
Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"config": schema.MapAttribute{
Optional: true,
Computed: true,
ElementType: types.StringType,
},
},
Blocks: map[string]schema.Block{
"backend": schema.SetNestedBlock{
Description: "Network load balancer backend",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Required: true,
Description: "LB backend name",
},
"description": schema.StringAttribute{
Optional: true,
Computed: true,
Description: "LB backend description",
Default: stringdefault.StaticString(""),
},
"target_address": schema.StringAttribute{
Required: true,
Description: "LB backend target address",
},
"target_port": schema.StringAttribute{
Optional: true,
Description: "LB backend target port",
},
},
},
},
"port": schema.SetNestedBlock{
Description: "Network load balancer port",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"description": schema.StringAttribute{
Optional: true,
Computed: true,
Default: stringdefault.StaticString(""),
Description: "Port description",
},
"protocol": schema.StringAttribute{
Optional: true,
Computed: true,
Default: stringdefault.StaticString("tcp"),
Description: "Port protocol",
Validators: []validator.String{
stringvalidator.OneOf("tcp", "udp"),
},
},
"listen_port": schema.StringAttribute{
Required: true,
Description: "Port to listen to",
},
"target_backend": schema.SetAttribute{
Required: true,
Description: "List of target LB backends",
ElementType: types.StringType,
Validators: []validator.Set{
setvalidator.SizeAtLeast(1),
},
},
},
},
},
},
}
}Terraform Configuration Files
resource "incus_network_lb" "test_v4_debug" {
network = incus_network.ovn-test.name
listen_address = "10.10.10.50"
port {
protocol = "udp"
listen_port = "100"
target_backend = [
"toto_udp",
]
}
backend {
description = "myback"
name = "toto_udp"
target_address = "10.10.10.150"
}
}Debug Output
{"@caller":"/home/admin/go/pkg/mod/github.com/hashicorp/terraform-plugin-framework@v1.17.0/internal/fwschemadata/data_default.go:370","@level":"trace","@message":"setting attribute port[Value({\"description\":\"\",\"listen_port\":\"100\",\"protocol\":\"udp\",\"target_backend\":[\"toto_udp\"]})].protocol to default value: \"tcp\"","@mo
dule":"sdk.framework","@timestamp":"2026-01-17T17:03:25.869120+01:00","tf_provider_addr":"registry.opentofu.org/lxc/incus","tf_req_id":"e81a5e95-bcca-1cf8-d36f-457cfb8ed825","tf_resource_type":"incus_network_lb","tf_rpc":"PlanResourceChange"}
Expected Behavior
The port protocol should remain UDP and not be set to the default value
Actual Behavior
The port protocol is changed to TCP
Steps to Reproduce
tofu applya first time; the port will be correctly created in UDP.tofu planortofu apply; the port protocol will be changed to TCP
Workaround
- Setting a description (the only other optional attribute with a default in the same block) prevents the bug.
References
Issue location
Using Delve, I was able to locate the issue at github.com/hashicorp/terraform-plugin-framework/internal/fwschemadata.Data.ValueAtPath
When we are not setting the description attribute in the port block, the framework will set it to its default value at internal/fwschemadata/data_default.go:350. This behavior is expected.
Then Terraform will look for the protocol attribute of the port in internal/fwschemadata.Data.ValueAtPath()
Line 64 tfValue, err := d.TerraformValueAtTerraformPath(ctx, tftypesPath) returns nil and ErrInvalidStep.
Since tfValue is nil it will cause the protocol attribute to be set to his default.
Cause of the issue
This error is raised by https://github.com/hashicorp/terraform-plugin-go/blob/dfb1155c79e13595a8c70a4c487e1a0ba9a478f5/tftypes/value.go#L202
This is caused by stepValue (the state of the port block as initially defined, who got its value from the d arg in the function internal/fwschemadata.Data.ValueAtPath()) differing from sl (who represents the state of the port as it is now, meaning after Terraform sets description to its default value. The sl value comes from tftypesPath
| tftypesPath, tftypesPathDiags := totftypes.AttributePath(ctx, schemaPath) |
This means that in
stepValue, the description attribute of the port block is nil, while in sl it is an empty string "".Therefore these 2 variables are not equal, and this interrupts the function
TerraformValueAtTerraformPath() before it can retrieve the value of the protocol attribute.