refactor ApplyResourceChange

Remove a bunch of indentation by returning early, and make sure we don't
fail on non-fatal error without saving the applied value.
This commit is contained in:
James Bardin 2019-01-15 12:15:39 -05:00
parent 0a731167db
commit 7d05dee08d
1 changed files with 57 additions and 44 deletions

View File

@ -729,60 +729,76 @@ func (s *GRPCProviderServer) ApplyResourceChange(_ context.Context, req *proto.A
return resp, nil return resp, nil
} }
plannedState := hcl2shim.FlatmapValueFromHCL2(plannedStateVal)
if newInstanceState != nil {
// here we use the planned state to check for unknown/zero containers values
// when normalizing the flatmap.
newInstanceState.Attributes = normalizeFlatmapContainers(plannedState, newInstanceState.Attributes, true)
}
newStateVal := cty.NullVal(block.ImpliedType()) newStateVal := cty.NullVal(block.ImpliedType())
// We keep the null val if we destroyed the resource, otherwise build the // always return a nul value for destroy
// entire object, even if the new state was nil. if newInstanceState == nil || destroy {
if !destroy { newStateMP, err := msgpack.Marshal(newStateVal, block.ImpliedType())
newStateVal, err = schema.StateValueFromInstanceState(newInstanceState, block.ImpliedType())
if err != nil { if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err) resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil return resp, nil
} }
resp.NewState = &proto.DynamicValue{
Msgpack: newStateMP,
}
return resp, nil
}
// here we use the planned state to check for unknown/zero containers values
// when normalizing the flatmap.
plannedState := hcl2shim.FlatmapValueFromHCL2(plannedStateVal)
newInstanceState.Attributes = normalizeFlatmapContainers(plannedState, newInstanceState.Attributes, true)
// We keep the null val if we destroyed the resource, otherwise build the
// entire object, even if the new state was nil.
newStateVal, err = schema.StateValueFromInstanceState(newInstanceState, block.ImpliedType())
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
} }
newStateVal = copyMissingValues(newStateVal, plannedStateVal) newStateVal = copyMissingValues(newStateVal, plannedStateVal)
if newInstanceState != nil { // Cycle through the shims, to ensure that the plan will create an identical
prevVal := newStateVal // value. Errors in this block are non-fatal (and should not happen, since
for i := 0; ; i++ { // we've already shimmed this type), because we already have an applied value
// cycle through the shims, to ensure that the plan will create an // and want to return that even if a later Plan may not agree.
// identical value prevVal := newStateVal
shimmedState, err := res.ShimInstanceStateFromValue(prevVal) for i := 0; ; i++ {
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
}
shimmedState.Attributes = normalizeFlatmapContainers(shimmedState.Attributes, shimmedState.Attributes, false)
tmpVal, err := hcl2shim.HCL2ValueFromFlatmap(shimmedState.Attributes, block.ImpliedType()) shimmedState, err := res.ShimInstanceStateFromValue(prevVal)
if err != nil { if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err) log.Printf("[ERROR] failed to shim cty.Value: %s", err)
return resp, nil break
} }
shimmedState.Attributes = normalizeFlatmapContainers(shimmedState.Attributes, shimmedState.Attributes, false)
tmpVal = copyMissingValues(tmpVal, prevVal) tmpVal, err := hcl2shim.HCL2ValueFromFlatmap(shimmedState.Attributes, block.ImpliedType())
if err != nil {
log.Printf("[ERROR] failed to shim flatmap: %s", err)
break
}
if tmpVal.RawEquals(prevVal) { tmpVal = copyMissingValues(tmpVal, prevVal)
newStateVal = tmpVal
break
}
if i < 2 { // If we have the same value before and after the shimming process, we
prevVal = tmpVal // can be reasonably certain that PlanResourceChange will return the
continue // same value.
} if tmpVal.RawEquals(prevVal) {
newStateVal = tmpVal
break
}
if i > 2 {
// This isn't fatal, since the value as actually applied.
log.Printf("[ERROR] hcl2shims failed to converge for value: %#v\n", newStateVal) log.Printf("[ERROR] hcl2shims failed to converge for value: %#v\n", newStateVal)
break break
} }
// The values are not the same, but we're only going to try this up to 3
// times before giving up. This should account for any empty nested values
// showing up a few levels deep.
prevVal = tmpVal
} }
newStateVal = copyTimeoutValues(newStateVal, plannedStateVal) newStateVal = copyTimeoutValues(newStateVal, plannedStateVal)
@ -796,15 +812,12 @@ func (s *GRPCProviderServer) ApplyResourceChange(_ context.Context, req *proto.A
Msgpack: newStateMP, Msgpack: newStateMP,
} }
if newInstanceState != nil { meta, err := json.Marshal(newInstanceState.Meta)
meta, err := json.Marshal(newInstanceState.Meta) if err != nil {
if err != nil { resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err) return resp, nil
return resp, nil
}
resp.Private = meta
} }
resp.Private = meta
return resp, nil return resp, nil
} }