mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
104 lines
4.0 KiB
Go
104 lines
4.0 KiB
Go
|
package differ
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
|
||
|
"github.com/hashicorp/terraform/internal/command/jsonplan"
|
||
|
)
|
||
|
|
||
|
// Value contains the unmarshalled generic interface{} types that are output by
|
||
|
// the JSON functions in the various json packages (such as jsonplan and
|
||
|
// jsonprovider).
|
||
|
//
|
||
|
// A Value can be converted into a change.Change, ready for rendering, with the
|
||
|
// ComputeChangeForAttribute, ComputeChangeForOutput, and ComputeChangeForBlock
|
||
|
// functions.
|
||
|
//
|
||
|
// The Before and After fields are actually go-cty values, but we cannot convert
|
||
|
// them directly because of the Terraform Cloud redacted endpoint. The redacted
|
||
|
// endpoint turns sensitive values into strings regardless of their types.
|
||
|
// Because of this, we cannot just do a direct conversion using the ctyjson
|
||
|
// package. We would have to iterate through the schema first, find the
|
||
|
// sensitive values and their mapped types, update the types inside the schema
|
||
|
// to strings, and then go back and do the overall conversion. This isn't
|
||
|
// including any of the more complicated parts around what happens if something
|
||
|
// was sensitive before and isn't sensitive after or vice versa. This would mean
|
||
|
// the type would need to change between the before and after value. It is in
|
||
|
// fact just easier to iterate through the values as generic JSON interfaces.
|
||
|
type Value struct {
|
||
|
// BeforeExplicit refers to whether the Before value is explicit or
|
||
|
// implicit. It is explicit if it has been specified by the user, and
|
||
|
// implicit if it has been set as a consequence of other changes.
|
||
|
//
|
||
|
// For example, explicitly setting a value to null in a list should result
|
||
|
// in Before being null and BeforeExplicit being true. In comparison,
|
||
|
// removing an element from a list should also result in Before being null
|
||
|
// and BeforeExplicit being false. Without the explicit information our
|
||
|
// functions would not be able to tell the difference between these two
|
||
|
// cases.
|
||
|
BeforeExplicit bool
|
||
|
|
||
|
// AfterExplicit matches BeforeExplicit except references the After value.
|
||
|
AfterExplicit bool
|
||
|
|
||
|
// Before contains the value before the proposed change.
|
||
|
//
|
||
|
// The type of the value should be informed by the schema and cast
|
||
|
// appropriately when needed.
|
||
|
Before interface{}
|
||
|
|
||
|
// After contains the value after the proposed change.
|
||
|
//
|
||
|
// The type of the value should be informed by the schema and cast
|
||
|
// appropriately when needed.
|
||
|
After interface{}
|
||
|
|
||
|
// Unknown describes whether the After value is known or unknown at the time
|
||
|
// of the plan. In practice, this means the after value should be rendered
|
||
|
// simply as `(known after apply)`.
|
||
|
//
|
||
|
// The concrete value could be a boolean describing whether the entirety of
|
||
|
// the After value is unknown, or it could be a list or a map depending on
|
||
|
// the schema describing whether specific elements or attributes within the
|
||
|
// value are unknown.
|
||
|
Unknown interface{}
|
||
|
|
||
|
// BeforeSensitive matches Unknown, but references whether the Before value
|
||
|
// is sensitive.
|
||
|
BeforeSensitive interface{}
|
||
|
|
||
|
// AfterSensitive matches Unknown, but references whether the After value is
|
||
|
// sensitive.
|
||
|
AfterSensitive interface{}
|
||
|
|
||
|
// ReplacePaths generally contains nested slices that describe paths to
|
||
|
// elements or attributes that are causing the overall resource to be
|
||
|
// replaced.
|
||
|
ReplacePaths interface{}
|
||
|
}
|
||
|
|
||
|
// ValueFromJsonChange unmarshals the raw []byte values in the jsonplan.Change
|
||
|
// structs into generic interface{} types that can be reasoned about.
|
||
|
func ValueFromJsonChange(change jsonplan.Change) Value {
|
||
|
return Value{
|
||
|
Before: unmarshalGeneric(change.Before),
|
||
|
After: unmarshalGeneric(change.After),
|
||
|
Unknown: unmarshalGeneric(change.AfterUnknown),
|
||
|
BeforeSensitive: unmarshalGeneric(change.BeforeSensitive),
|
||
|
AfterSensitive: unmarshalGeneric(change.AfterSensitive),
|
||
|
ReplacePaths: unmarshalGeneric(change.ReplacePaths),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func unmarshalGeneric(raw json.RawMessage) interface{} {
|
||
|
if raw == nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
var out interface{}
|
||
|
if err := json.Unmarshal(raw, &out); err != nil {
|
||
|
panic("unrecognized json type: " + err.Error())
|
||
|
}
|
||
|
return out
|
||
|
}
|