Skip to content

Add resource identities to plan file and JSON output #36903

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions internal/command/jsonplan/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ type Change struct {
// might change in the future. However, not all Importing changes will
// contain generated config.
GeneratedConfig string `json:"generated_config,omitempty"`

BeforeIdentity json.RawMessage `json:"before_identity,omitempty"`
AfterIdentity json.RawMessage `json:"after_identity,omitempty"`
}

// Importing is a nested object for the resource import metadata.
Expand All @@ -168,6 +171,8 @@ type Importing struct {
// would have led to the overall change being deferred, as such this should
// only be true when processing changes from the deferred changes list.
Unknown bool `json:"unknown,omitempty"`

Identity json.RawMessage `json:"identity,omitempty"`
}

type output struct {
Expand Down Expand Up @@ -503,6 +508,29 @@ func marshalResourceChange(rc *plans.ResourceInstanceChangeSrc, schemas *terrafo
} else {
importing = &Importing{ID: rc.Importing.ID}
}
// TODO identity
}

var beforeIdentity, afterIdentity []byte
if schema.Identity != nil && rc.BeforeIdentity != nil {
identity, err := rc.BeforeIdentity.Decode(schema.Identity.ImpliedType())
if err != nil {
return r, err
}
beforeIdentity, err = ctyjson.Marshal(identity, identity.Type())
if err != nil {
return r, err
}
}
if schema.Identity != nil && rc.AfterIdentity != nil {
identity, err := rc.AfterIdentity.Decode(schema.Identity.ImpliedType())
if err != nil {
return r, err
}
afterIdentity, err = ctyjson.Marshal(identity, identity.Type())
if err != nil {
return r, err
}
}

r.Change = Change{
Expand All @@ -515,6 +543,8 @@ func marshalResourceChange(rc *plans.ResourceInstanceChangeSrc, schemas *terrafo
ReplacePaths: replacePaths,
Importing: importing,
GeneratedConfig: rc.GeneratedConfig,
BeforeIdentity: json.RawMessage(beforeIdentity),
AfterIdentity: json.RawMessage(afterIdentity),
}

if rc.DeposedKey != states.NotDeposed {
Expand Down
4 changes: 4 additions & 0 deletions internal/command/jsonplan/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ type resource struct {
// SensitiveValues is similar to AttributeValues, but with all sensitive
// values replaced with true, and all non-sensitive leaf values omitted.
SensitiveValues json.RawMessage `json:"sensitive_values,omitempty"`

IdentitySchemaVersion uint64 `json:"identity_schema_version"`

IdentityValues attributeValues `json:"identity,omitempty"`
}

// ResourceChange is a description of an individual change action that Terraform
Expand Down
20 changes: 20 additions & 0 deletions internal/command/jsonplan/values.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ func marshalAttributeValues(value cty.Value, schema *configschema.Block) attribu
return ret
}

func marshalIdentityValues(value cty.Value) attributeValues {
if value == cty.NilVal || value.IsNull() {
return nil
}
ret := make(attributeValues)

it := value.ElementIterator()
for it.Next() {
k, v := it.Element()
vJSON, _ := ctyjson.Marshal(v, v.Type())
ret[k.AsString()] = json.RawMessage(vJSON)
}
return ret
}

// marshalPlannedOutputs takes a list of changes and returns a map of output
// values
func marshalPlannedOutputs(changes *plans.ChangesSrc) (map[string]output, error) {
Expand Down Expand Up @@ -234,6 +249,11 @@ func marshalPlanResources(changes *plans.ChangesSrc, ris []addrs.AbsResourceInst
}
resource.SensitiveValues = v

if schema.Identity != nil {
resource.IdentitySchemaVersion = uint64(schema.IdentityVersion)
resource.IdentityValues = marshalIdentityValues(changeV.AfterIdentity)
}

ret = append(ret, resource)
}

Expand Down
10 changes: 7 additions & 3 deletions internal/plans/changes.go
Original file line number Diff line number Diff line change
Expand Up @@ -556,14 +556,18 @@ type Importing struct {

// Encode converts the Importing object into a form suitable for serialization
// to a plan file.
func (i *Importing) Encode() *ImportingSrc {
func (i *Importing) Encode(identityTy cty.Type) *ImportingSrc {
if i == nil {
return nil
}
if i.Target.IsWhollyKnown() {
if i.Target.Type().IsObjectType() {
identity, err := NewDynamicValue(i.Target, identityTy)
if err != nil {
return nil
}
return &ImportingSrc{
Identity: i.Target,
Identity: identity,
}
} else {
return &ImportingSrc{
Expand Down Expand Up @@ -692,7 +696,7 @@ func (c *Change) Encode(schema *providers.Schema) (*ChangeSrc, error) {
AfterSensitivePaths: sensitiveAttrsAfter,
BeforeIdentity: beforeIdentityDV,
AfterIdentity: afterIdentityDV,
Importing: c.Importing.Encode(),
Importing: c.Importing.Encode(identityTy),
GeneratedConfig: c.GeneratedConfig,
}, nil
}
19 changes: 12 additions & 7 deletions internal/plans/changes_src.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ type ImportingSrc struct {
ID string

// Identity is the original identity of the imported resource.
Identity cty.Value
Identity DynamicValue

// Unknown is true if the ID was unknown when we tried to import it. This
// should only be true if the overall change is embedded within a deferred
Expand All @@ -359,12 +359,12 @@ type ImportingSrc struct {
}

// Decode unmarshals the raw representation of the importing action.
func (is *ImportingSrc) Decode() *Importing {
func (is *ImportingSrc) Decode(identityType cty.Type) *Importing {
if is == nil {
return nil
}
if is.Unknown {
if is.Identity.IsNull() {
if is.Identity == nil {
return &Importing{
Target: cty.UnknownVal(cty.String),
}
Expand All @@ -375,15 +375,20 @@ func (is *ImportingSrc) Decode() *Importing {
}
}

if is.Identity.IsNull() {
if is.Identity == nil {
return &Importing{
Target: cty.StringVal(is.ID),
}
}

return &Importing{
Target: is.Identity,
target, err := is.Identity.Decode(identityType)
if err != nil {
return &Importing{
Target: target,
}
}

return nil
}

// ChangeSrc is a not-yet-decoded Change.
Expand Down Expand Up @@ -476,7 +481,7 @@ func (cs *ChangeSrc) Decode(schema *providers.Schema) (*Change, error) {
BeforeIdentity: beforeIdentity,
After: marks.MarkPaths(after, marks.Sensitive, cs.AfterSensitivePaths),
AfterIdentity: afterIdentity,
Importing: cs.Importing.Decode(),
Importing: cs.Importing.Decode(identityType),
GeneratedConfig: cs.GeneratedConfig,
}, nil
}
44 changes: 40 additions & 4 deletions internal/plans/planfile/tfplan.go
Original file line number Diff line number Diff line change
Expand Up @@ -421,9 +421,18 @@ func changeFromTfplan(rawChange *planproto.Change) (*plans.ChangeSrc, error) {
}

if rawChange.Importing != nil {
var identity plans.DynamicValue
if rawChange.Importing.Identity != nil {
var err error
identity, err = valueFromTfplan(rawChange.Importing.Identity)
if err != nil {
return nil, fmt.Errorf("invalid \"identity\" value: %s", err)
}
}
ret.Importing = &plans.ImportingSrc{
ID: rawChange.Importing.Id,
Unknown: rawChange.Importing.Unknown,
ID: rawChange.Importing.Id,
Unknown: rawChange.Importing.Unknown,
Identity: identity,
}
}
ret.GeneratedConfig = rawChange.GeneratedConfig
Expand All @@ -443,6 +452,21 @@ func changeFromTfplan(rawChange *planproto.Change) (*plans.ChangeSrc, error) {
ret.AfterSensitivePaths = afterValSensitiveAttrs
}

if rawChange.BeforeIdentity != nil {
beforeIdentity, err := valueFromTfplan(rawChange.BeforeIdentity)
if err != nil {
return nil, fmt.Errorf("failed to decode before identity: %s", err)
}
ret.BeforeIdentity = beforeIdentity
}
if rawChange.AfterIdentity != nil {
afterIdentity, err := valueFromTfplan(rawChange.AfterIdentity)
if err != nil {
return nil, fmt.Errorf("failed to decode after identity: %s", err)
}
ret.AfterIdentity = afterIdentity
}

return ret, nil
}

Expand Down Expand Up @@ -809,14 +833,26 @@ func changeToTfplan(change *plans.ChangeSrc) (*planproto.Change, error) {
ret.AfterSensitivePaths = afterSensitivePaths

if change.Importing != nil {
var identity *planproto.DynamicValue
if change.Importing.Identity != nil {
identity = planproto.NewPlanDynamicValue(change.Importing.Identity)
}
ret.Importing = &planproto.Importing{
Id: change.Importing.ID,
Unknown: change.Importing.Unknown,
Id: change.Importing.ID,
Unknown: change.Importing.Unknown,
Identity: identity,
}

}
ret.GeneratedConfig = change.GeneratedConfig

if change.BeforeIdentity != nil {
ret.BeforeIdentity = planproto.NewPlanDynamicValue(change.BeforeIdentity)
}
if change.AfterIdentity != nil {
ret.AfterIdentity = planproto.NewPlanDynamicValue(change.AfterIdentity)
}

ret.Action, err = ActionToProto(change.Action)
if err != nil {
return nil, err
Expand Down
Loading
Loading