- Terraform v1.8.4 darwin_arm64
- go1.22.1
- terraform-plugin-framework v1.9.0
Hi team, I tried to develop a provider using SetNestedAttribute, but when I executed terraform apply, I got an error. I tried for a long time but couldn’t figure out why this happened.
Error: Provider produced inconsistent result after apply
When applying changes to example_set_nested.test01, provider "provider[\"test.com/test/example\"]" produced an unexpected new value:
.set_nested: planned set element cty.ObjectVal(map[string]cty.Value{
"enable_gateway":cty.False,
"fixed_ip":cty.StringVal("127.0.0.1"),
"fixed_ip_v4":cty.NullVal(cty.String),
"mac":cty.NullVal(cty.String),
"port":cty.NullVal(cty.String),
"uuid":cty.StringVal("123")
})
does not correlate with any element in actual.
This is a bug in the provider, which should be reported in the provider's own issue tracker.
Sample code using SetNestedAttribute
type (
SetNestedResourceModel struct {
Id types.String `tfsdk:"id"`
SetNested types.Set `tfsdk:"set_nested"`
}
SetNestedModel struct {
Uuid types.String `tfsdk:"uuid"`
FixedIp types.String `tfsdk:"fixed_ip"`
FixedIpV4 types.String `tfsdk:"fixed_ip_v4"`
Port types.String `tfsdk:"port"`
Mac types.String `tfsdk:"mac"`
EnableGateway types.Bool `tfsdk:"enable_gateway"`
}
)
var (
setNestedModelTypeMap = map[string]attr.Type{
"uuid": types.StringType,
"fixed_ip": types.StringType,
"fixed_ip_v4": types.StringType,
"port": types.StringType,
"mac": types.StringType,
"enable_gateway": types.BoolType,
}
)
func (r *SetNestedResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
MarkdownDescription: "ID",
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"set_nested": schema.SetNestedAttribute{
MarkdownDescription: "Example configurable attribute",
Optional: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"uuid": schema.StringAttribute{
MarkdownDescription: "经典网络ID",
Required: true,
},
"fixed_ip": schema.StringAttribute{
MarkdownDescription: "指定IP地址",
Optional: true,
},
"fixed_ip_v4": schema.StringAttribute{
MarkdownDescription: "指定IPv4地址",
Computed: true,
},
"port": schema.StringAttribute{
MarkdownDescription: "网卡端口ID",
Computed: true,
},
"mac": schema.StringAttribute{
MarkdownDescription: "MAC地址",
Computed: true,
},
"enable_gateway": schema.BoolAttribute{
MarkdownDescription: "是否启用网关",
Optional: true,
Computed: true,
Default: booldefault.StaticBool(false),
//Required: true,
},
},
},
},
},
}
}
func (r *SetNestedBlockResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
// .........
data.Id = types.StringValue("example-id")
diags := data.fnConvert(ctx)
// .........
}
func (r *SetNestedBlockResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
// .........
diags := data.fnConvert(ctx)
// .........
}
func (s *SetNestedBlockResourceModel) fnConvert(ctx context.Context) diag.Diagnostics {
var diags diag.Diagnostics
sSetNested := s.SetNested
var sSetNestedBlockModels []SetNestedBlockModel
sSetNested.ElementsAs(ctx, &sSetNestedBlockModels, false)
processedSetNestedBlockModels := make([]SetNestedBlockModel, 0)
for i, model := range sSetNestedBlockModels {
model.Port = types.StringValue(fmt.Sprintf("port_id_%d", i))
model.Mac = types.StringValue(fmt.Sprintf("mac_address_%d", i))
mFixedIp := model.FixedIp
if mFixedIp.IsNull() || mFixedIp.IsUnknown() {
model.FixedIpV4 = types.StringValue(fmt.Sprintf("fixed_ip_%d", i))
} else {
model.FixedIpV4 = mFixedIp
}
processedSetNestedBlockModels = append(processedSetNestedBlockModels, model)
}
if len(processedSetNestedBlockModels) > 0 {
sets, diags1 := types.SetValueFrom(ctx, types.ObjectType{
AttrTypes: SetNestedBlockModelTypeMap,
}, processedSetNestedBlockModels)
diags.Append(diags1...)
s.SetNested = sets
}
return diags
}
main.tf.json
{
"resource": {
"example_set_nested": {
"test01": {
"set_nested": [
{
"uuid": "123",
"fixed_ip": "127.0.0.1"
}
]
},
"test02": {
"set_nested": [
{
"uuid": "234",
"enable_gateway": true
}
]
}
}
}
}
Command line output of executing terraform apply, I found that the output of “test01” and “test02” are different, “test01” does not display “fixed_ip_v4”, “mac”, “port”, I think “test01” should display these contents. Although the execution failed, the data was correctly written into the tfstate file.
And then, I modified the main.tf.json file, added " “enable_gateway”: true " in “test01”, and executed terraform apply again and got the correct result.
I am very confused now. I think whether I add “enable_gateway” in “main.tf.json” or not, the execution result should be the same.
Can someone answer this question? Thanks.
Sample code:set_nested_resource、main.tf.json