search: Drop identity from state if no identity schema is present (#37709) (#37727)

* Modernize Go

* Check if identity schema is present before decoding state

* Test identity decoding from state without schema
This commit is contained in:
Daniel Banck 2025-10-07 10:48:29 +02:00 committed by GitHub
parent 74b6eb4cc7
commit 381606cc4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 77 additions and 10 deletions

View file

@ -117,7 +117,7 @@ func (os *ResourceInstanceObjectSrc) Decode(schema providers.Schema) (*ResourceI
var identity cty.Value
if os.decodeIdentityCache != cty.NilVal {
identity = os.decodeIdentityCache
} else if os.IdentityJSON != nil {
} else if os.IdentityJSON != nil && schema.Identity != nil {
identity, err = ctyjson.Unmarshal(os.IdentityJSON, schema.Identity.ImpliedType())
if err != nil {
return nil, fmt.Errorf("failed to decode identity: %s. This is most likely a bug in the Provider, providers must not change the identity schema without updating the identity schema version", err.Error())

View file

@ -61,22 +61,22 @@ func TestResourceInstanceObject_encode(t *testing.T) {
// multiple instances may have been assigned the same deps slice
objs := []*ResourceInstanceObject{
&ResourceInstanceObject{
{
Value: value,
Status: ObjectPlanned,
Dependencies: depsOne,
},
&ResourceInstanceObject{
{
Value: value,
Status: ObjectPlanned,
Dependencies: depsTwo,
},
&ResourceInstanceObject{
{
Value: value,
Status: ObjectPlanned,
Dependencies: depsOne,
},
&ResourceInstanceObject{
{
Value: value,
Status: ObjectPlanned,
Dependencies: depsOne,
@ -91,10 +91,7 @@ func TestResourceInstanceObject_encode(t *testing.T) {
var mu sync.Mutex
for _, obj := range objs {
obj := obj
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
rios, err := obj.Encode(schema)
if err != nil {
t.Errorf("unexpected error: %s", err)
@ -102,7 +99,7 @@ func TestResourceInstanceObject_encode(t *testing.T) {
mu.Lock()
encoded = append(encoded, rios)
mu.Unlock()
}()
})
}
wg.Wait()

View file

@ -309,6 +309,76 @@ func TestContext2Plan_resource_identity_refresh(t *testing.T) {
}
}
func TestContext2Plan_resource_identity_refresh_downgrade(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "refresh-basic")
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&providerSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Computed: true,
},
"foo": {
Type: cty.String,
Optional: true,
Computed: true,
},
},
},
},
})
state := states.NewState()
root := state.EnsureModule(addrs.RootModuleInstance)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("aws_instance.web").Resource,
&states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
AttrsJSON: []byte(`{"id":"foo","foo":"bar"}`),
IdentitySchemaVersion: 0,
IdentityJSON: []byte(`{"id": "foo"}`),
},
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"]
p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
return providers.ReadResourceResponse{
NewState: req.PriorState,
}
}
s, diags := ctx.Plan(m, state, &PlanOpts{Mode: plans.RefreshOnlyMode})
if diags.HasErrors() {
t.Fatal(diags.Err())
}
if !p.ReadResourceCalled {
t.Fatal("ReadResource should be called")
}
mod := s.PriorState.RootModule()
fromState, err := mod.Resources["aws_instance.web"].Instances[addrs.NoKey].Current.Decode(schema)
if err != nil {
t.Fatal(err)
}
if !fromState.Identity.IsNull() {
t.Fatalf("wrong identity\nwant: null\ngot: %s", fromState.Identity.GoString())
}
}
// This test validates if a resource identity that is deposed and will be destroyed
// can be refreshed with an identity during the plan.
func TestContext2Plan_resource_identity_refresh_destroy_deposed(t *testing.T) {