Skip to content

Commit c9e14cc

Browse files
committed
Add resource identities to plan file and JSON output
1 parent 063757f commit c9e14cc

File tree

9 files changed

+350
-200
lines changed

9 files changed

+350
-200
lines changed

internal/command/jsonplan/plan.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ type Change struct {
156156
// might change in the future. However, not all Importing changes will
157157
// contain generated config.
158158
GeneratedConfig string `json:"generated_config,omitempty"`
159+
160+
BeforeIdentity json.RawMessage `json:"before_identity,omitempty"`
161+
AfterIdentity json.RawMessage `json:"after_identity,omitempty"`
159162
}
160163

161164
// Importing is a nested object for the resource import metadata.
@@ -168,6 +171,8 @@ type Importing struct {
168171
// would have led to the overall change being deferred, as such this should
169172
// only be true when processing changes from the deferred changes list.
170173
Unknown bool `json:"unknown,omitempty"`
174+
175+
Identity json.RawMessage `json:"identity,omitempty"`
171176
}
172177

173178
type output struct {
@@ -503,6 +508,29 @@ func marshalResourceChange(rc *plans.ResourceInstanceChangeSrc, schemas *terrafo
503508
} else {
504509
importing = &Importing{ID: rc.Importing.ID}
505510
}
511+
// TODO identity
512+
}
513+
514+
var beforeIdentity, afterIdentity []byte
515+
if schema.Identity != nil && rc.BeforeIdentity != nil {
516+
identity, err := rc.BeforeIdentity.Decode(schema.Identity.ImpliedType())
517+
if err != nil {
518+
return r, err
519+
}
520+
beforeIdentity, err = ctyjson.Marshal(identity, identity.Type())
521+
if err != nil {
522+
return r, err
523+
}
524+
}
525+
if schema.Identity != nil && rc.AfterIdentity != nil {
526+
identity, err := rc.AfterIdentity.Decode(schema.Identity.ImpliedType())
527+
if err != nil {
528+
return r, err
529+
}
530+
afterIdentity, err = ctyjson.Marshal(identity, identity.Type())
531+
if err != nil {
532+
return r, err
533+
}
506534
}
507535

508536
r.Change = Change{
@@ -515,6 +543,8 @@ func marshalResourceChange(rc *plans.ResourceInstanceChangeSrc, schemas *terrafo
515543
ReplacePaths: replacePaths,
516544
Importing: importing,
517545
GeneratedConfig: rc.GeneratedConfig,
546+
BeforeIdentity: json.RawMessage(beforeIdentity),
547+
AfterIdentity: json.RawMessage(afterIdentity),
518548
}
519549

520550
if rc.DeposedKey != states.NotDeposed {

internal/command/jsonplan/resource.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ type resource struct {
4242
// SensitiveValues is similar to AttributeValues, but with all sensitive
4343
// values replaced with true, and all non-sensitive leaf values omitted.
4444
SensitiveValues json.RawMessage `json:"sensitive_values,omitempty"`
45+
46+
IdentitySchemaVersion uint64 `json:"identity_schema_version"`
47+
48+
IdentityValues attributeValues `json:"identity,omitempty"`
4549
}
4650

4751
// ResourceChange is a description of an individual change action that Terraform

internal/command/jsonplan/values.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,21 @@ func marshalAttributeValues(value cty.Value, schema *configschema.Block) attribu
4545
return ret
4646
}
4747

48+
func marshalIdentityValues(value cty.Value) attributeValues {
49+
if value == cty.NilVal || value.IsNull() {
50+
return nil
51+
}
52+
ret := make(attributeValues)
53+
54+
it := value.ElementIterator()
55+
for it.Next() {
56+
k, v := it.Element()
57+
vJSON, _ := ctyjson.Marshal(v, v.Type())
58+
ret[k.AsString()] = json.RawMessage(vJSON)
59+
}
60+
return ret
61+
}
62+
4863
// marshalPlannedOutputs takes a list of changes and returns a map of output
4964
// values
5065
func marshalPlannedOutputs(changes *plans.ChangesSrc) (map[string]output, error) {
@@ -234,6 +249,11 @@ func marshalPlanResources(changes *plans.ChangesSrc, ris []addrs.AbsResourceInst
234249
}
235250
resource.SensitiveValues = v
236251

252+
if schema.Identity != nil {
253+
resource.IdentitySchemaVersion = uint64(schema.IdentityVersion)
254+
resource.IdentityValues = marshalIdentityValues(changeV.AfterIdentity)
255+
}
256+
237257
ret = append(ret, resource)
238258
}
239259

internal/plans/changes.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -556,14 +556,18 @@ type Importing struct {
556556

557557
// Encode converts the Importing object into a form suitable for serialization
558558
// to a plan file.
559-
func (i *Importing) Encode() *ImportingSrc {
559+
func (i *Importing) Encode(identityTy cty.Type) *ImportingSrc {
560560
if i == nil {
561561
return nil
562562
}
563563
if i.Target.IsWhollyKnown() {
564564
if i.Target.Type().IsObjectType() {
565+
identity, err := NewDynamicValue(i.Target, identityTy)
566+
if err != nil {
567+
return nil
568+
}
565569
return &ImportingSrc{
566-
Identity: i.Target,
570+
Identity: identity,
567571
}
568572
} else {
569573
return &ImportingSrc{
@@ -692,7 +696,7 @@ func (c *Change) Encode(schema *providers.Schema) (*ChangeSrc, error) {
692696
AfterSensitivePaths: sensitiveAttrsAfter,
693697
BeforeIdentity: beforeIdentityDV,
694698
AfterIdentity: afterIdentityDV,
695-
Importing: c.Importing.Encode(),
699+
Importing: c.Importing.Encode(identityTy),
696700
GeneratedConfig: c.GeneratedConfig,
697701
}, nil
698702
}

internal/plans/changes_src.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ type ImportingSrc struct {
350350
ID string
351351

352352
// Identity is the original identity of the imported resource.
353-
Identity cty.Value
353+
Identity DynamicValue
354354

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

361361
// Decode unmarshals the raw representation of the importing action.
362-
func (is *ImportingSrc) Decode() *Importing {
362+
func (is *ImportingSrc) Decode(identityType cty.Type) *Importing {
363363
if is == nil {
364364
return nil
365365
}
366366
if is.Unknown {
367-
if is.Identity.IsNull() {
367+
if is.Identity == nil {
368368
return &Importing{
369369
Target: cty.UnknownVal(cty.String),
370370
}
@@ -375,15 +375,20 @@ func (is *ImportingSrc) Decode() *Importing {
375375
}
376376
}
377377

378-
if is.Identity.IsNull() {
378+
if is.Identity == nil {
379379
return &Importing{
380380
Target: cty.StringVal(is.ID),
381381
}
382382
}
383383

384-
return &Importing{
385-
Target: is.Identity,
384+
target, err := is.Identity.Decode(identityType)
385+
if err != nil {
386+
return &Importing{
387+
Target: target,
388+
}
386389
}
390+
391+
return nil
387392
}
388393

389394
// ChangeSrc is a not-yet-decoded Change.
@@ -476,7 +481,7 @@ func (cs *ChangeSrc) Decode(schema *providers.Schema) (*Change, error) {
476481
BeforeIdentity: beforeIdentity,
477482
After: marks.MarkPaths(after, marks.Sensitive, cs.AfterSensitivePaths),
478483
AfterIdentity: afterIdentity,
479-
Importing: cs.Importing.Decode(),
484+
Importing: cs.Importing.Decode(identityType),
480485
GeneratedConfig: cs.GeneratedConfig,
481486
}, nil
482487
}

internal/plans/planfile/tfplan.go

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -421,9 +421,18 @@ func changeFromTfplan(rawChange *planproto.Change) (*plans.ChangeSrc, error) {
421421
}
422422

423423
if rawChange.Importing != nil {
424+
var identity plans.DynamicValue
425+
if rawChange.Importing.Identity != nil {
426+
var err error
427+
identity, err = valueFromTfplan(rawChange.Importing.Identity)
428+
if err != nil {
429+
return nil, fmt.Errorf("invalid \"identity\" value: %s", err)
430+
}
431+
}
424432
ret.Importing = &plans.ImportingSrc{
425-
ID: rawChange.Importing.Id,
426-
Unknown: rawChange.Importing.Unknown,
433+
ID: rawChange.Importing.Id,
434+
Unknown: rawChange.Importing.Unknown,
435+
Identity: identity,
427436
}
428437
}
429438
ret.GeneratedConfig = rawChange.GeneratedConfig
@@ -443,6 +452,21 @@ func changeFromTfplan(rawChange *planproto.Change) (*plans.ChangeSrc, error) {
443452
ret.AfterSensitivePaths = afterValSensitiveAttrs
444453
}
445454

455+
if rawChange.BeforeIdentity != nil {
456+
beforeIdentity, err := valueFromTfplan(rawChange.BeforeIdentity)
457+
if err != nil {
458+
return nil, fmt.Errorf("failed to decode before identity: %s", err)
459+
}
460+
ret.BeforeIdentity = beforeIdentity
461+
}
462+
if rawChange.AfterIdentity != nil {
463+
afterIdentity, err := valueFromTfplan(rawChange.AfterIdentity)
464+
if err != nil {
465+
return nil, fmt.Errorf("failed to decode after identity: %s", err)
466+
}
467+
ret.AfterIdentity = afterIdentity
468+
}
469+
446470
return ret, nil
447471
}
448472

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

811835
if change.Importing != nil {
836+
var identity *planproto.DynamicValue
837+
if change.Importing.Identity != nil {
838+
identity = planproto.NewPlanDynamicValue(change.Importing.Identity)
839+
}
812840
ret.Importing = &planproto.Importing{
813-
Id: change.Importing.ID,
814-
Unknown: change.Importing.Unknown,
841+
Id: change.Importing.ID,
842+
Unknown: change.Importing.Unknown,
843+
Identity: identity,
815844
}
816845

817846
}
818847
ret.GeneratedConfig = change.GeneratedConfig
819848

849+
if change.BeforeIdentity != nil {
850+
ret.BeforeIdentity = planproto.NewPlanDynamicValue(change.BeforeIdentity)
851+
}
852+
if change.AfterIdentity != nil {
853+
ret.AfterIdentity = planproto.NewPlanDynamicValue(change.AfterIdentity)
854+
}
855+
820856
ret.Action, err = ActionToProto(change.Action)
821857
if err != nil {
822858
return nil, err

0 commit comments

Comments
 (0)