Merge pull request #29589 from hashicorp/alisdair/planfile-drifted-resources
core: Compute resource drift during plan phase, store in plan file
This commit is contained in:
commit
d425c26d77
|
@ -20,6 +20,21 @@ import (
|
||||||
"github.com/hashicorp/terraform/internal/states"
|
"github.com/hashicorp/terraform/internal/states"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DiffLanguage controls the description of the resource change reasons.
|
||||||
|
type DiffLanguage rune
|
||||||
|
|
||||||
|
//go:generate go run golang.org/x/tools/cmd/stringer -type=DiffLanguage diff.go
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DiffLanguageProposedChange indicates that the change is one which is
|
||||||
|
// planned to be applied.
|
||||||
|
DiffLanguageProposedChange DiffLanguage = 'P'
|
||||||
|
|
||||||
|
// DiffLanguageDetectedDrift indicates that the change is detected drift
|
||||||
|
// from the configuration.
|
||||||
|
DiffLanguageDetectedDrift DiffLanguage = 'D'
|
||||||
|
)
|
||||||
|
|
||||||
// ResourceChange returns a string representation of a change to a particular
|
// ResourceChange returns a string representation of a change to a particular
|
||||||
// resource, for inclusion in user-facing plan output.
|
// resource, for inclusion in user-facing plan output.
|
||||||
//
|
//
|
||||||
|
@ -33,6 +48,7 @@ func ResourceChange(
|
||||||
change *plans.ResourceInstanceChangeSrc,
|
change *plans.ResourceInstanceChangeSrc,
|
||||||
schema *configschema.Block,
|
schema *configschema.Block,
|
||||||
color *colorstring.Colorize,
|
color *colorstring.Colorize,
|
||||||
|
language DiffLanguage,
|
||||||
) string {
|
) string {
|
||||||
addr := change.Addr
|
addr := change.Addr
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
@ -52,29 +68,43 @@ func ResourceChange(
|
||||||
|
|
||||||
switch change.Action {
|
switch change.Action {
|
||||||
case plans.Create:
|
case plans.Create:
|
||||||
buf.WriteString(color.Color(fmt.Sprintf("[bold] # %s[reset] will be created", dispAddr)))
|
buf.WriteString(fmt.Sprintf(color.Color("[bold] # %s[reset] will be created"), dispAddr))
|
||||||
case plans.Read:
|
case plans.Read:
|
||||||
buf.WriteString(color.Color(fmt.Sprintf("[bold] # %s[reset] will be read during apply\n # (config refers to values not yet known)", dispAddr)))
|
buf.WriteString(fmt.Sprintf(color.Color("[bold] # %s[reset] will be read during apply\n # (config refers to values not yet known)"), dispAddr))
|
||||||
case plans.Update:
|
case plans.Update:
|
||||||
buf.WriteString(color.Color(fmt.Sprintf("[bold] # %s[reset] will be updated in-place", dispAddr)))
|
switch language {
|
||||||
|
case DiffLanguageProposedChange:
|
||||||
|
buf.WriteString(fmt.Sprintf(color.Color("[bold] # %s[reset] will be updated in-place"), dispAddr))
|
||||||
|
case DiffLanguageDetectedDrift:
|
||||||
|
buf.WriteString(fmt.Sprintf(color.Color("[bold] # %s[reset] has changed"), dispAddr))
|
||||||
|
default:
|
||||||
|
buf.WriteString(fmt.Sprintf(color.Color("[bold] # %s[reset] update (unknown reason %s)"), dispAddr, language))
|
||||||
|
}
|
||||||
case plans.CreateThenDelete, plans.DeleteThenCreate:
|
case plans.CreateThenDelete, plans.DeleteThenCreate:
|
||||||
switch change.ActionReason {
|
switch change.ActionReason {
|
||||||
case plans.ResourceInstanceReplaceBecauseTainted:
|
case plans.ResourceInstanceReplaceBecauseTainted:
|
||||||
buf.WriteString(color.Color(fmt.Sprintf("[bold] # %s[reset] is tainted, so must be [bold][red]replaced", dispAddr)))
|
buf.WriteString(fmt.Sprintf(color.Color("[bold] # %s[reset] is tainted, so must be [bold][red]replaced"), dispAddr))
|
||||||
case plans.ResourceInstanceReplaceByRequest:
|
case plans.ResourceInstanceReplaceByRequest:
|
||||||
buf.WriteString(color.Color(fmt.Sprintf("[bold] # %s[reset] will be [bold][red]replaced[reset], as requested", dispAddr)))
|
buf.WriteString(fmt.Sprintf(color.Color("[bold] # %s[reset] will be [bold][red]replaced[reset], as requested"), dispAddr))
|
||||||
default:
|
default:
|
||||||
buf.WriteString(color.Color(fmt.Sprintf("[bold] # %s[reset] must be [bold][red]replaced", dispAddr)))
|
buf.WriteString(fmt.Sprintf(color.Color("[bold] # %s[reset] must be [bold][red]replaced"), dispAddr))
|
||||||
}
|
}
|
||||||
case plans.Delete:
|
case plans.Delete:
|
||||||
buf.WriteString(color.Color(fmt.Sprintf("[bold] # %s[reset] will be [bold][red]destroyed", dispAddr)))
|
switch language {
|
||||||
|
case DiffLanguageProposedChange:
|
||||||
|
buf.WriteString(fmt.Sprintf(color.Color("[bold] # %s[reset] will be [bold][red]destroyed"), dispAddr))
|
||||||
|
case DiffLanguageDetectedDrift:
|
||||||
|
buf.WriteString(fmt.Sprintf(color.Color("[bold] # %s[reset] has been deleted"), dispAddr))
|
||||||
|
default:
|
||||||
|
buf.WriteString(fmt.Sprintf(color.Color("[bold] # %s[reset] delete (unknown reason %s)"), dispAddr, language))
|
||||||
|
}
|
||||||
if change.DeposedKey != states.NotDeposed {
|
if change.DeposedKey != states.NotDeposed {
|
||||||
// Some extra context about this unusual situation.
|
// Some extra context about this unusual situation.
|
||||||
buf.WriteString(color.Color("\n # (left over from a partially-failed replacement of this instance)"))
|
buf.WriteString(color.Color("\n # (left over from a partially-failed replacement of this instance)"))
|
||||||
}
|
}
|
||||||
case plans.NoOp:
|
case plans.NoOp:
|
||||||
if change.Moved() {
|
if change.Moved() {
|
||||||
buf.WriteString(color.Color(fmt.Sprintf("[bold] # %s[reset] has moved to [bold]%s[reset]", change.PrevRunAddr.String(), dispAddr)))
|
buf.WriteString(fmt.Sprintf(color.Color("[bold] # %s[reset] has moved to [bold]%s[reset]"), change.PrevRunAddr.String(), dispAddr))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
|
@ -85,7 +115,7 @@ func ResourceChange(
|
||||||
buf.WriteString(color.Color("[reset]\n"))
|
buf.WriteString(color.Color("[reset]\n"))
|
||||||
|
|
||||||
if change.Moved() && change.Action != plans.NoOp {
|
if change.Moved() && change.Action != plans.NoOp {
|
||||||
buf.WriteString(color.Color(fmt.Sprintf("[bold] # [reset]([bold]%s[reset] has moved to [bold]%s[reset])\n", change.PrevRunAddr.String(), dispAddr)))
|
buf.WriteString(fmt.Sprintf(color.Color("[bold] # [reset]([bold]%s[reset] has moved to [bold]%s[reset])\n"), change.PrevRunAddr.String(), dispAddr))
|
||||||
}
|
}
|
||||||
|
|
||||||
if change.Moved() && change.Action == plans.NoOp {
|
if change.Moved() && change.Action == plans.NoOp {
|
||||||
|
@ -154,147 +184,6 @@ func ResourceChange(
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceInstanceDrift returns a string representation of a change to a
|
|
||||||
// particular resource instance that was made outside of Terraform, for
|
|
||||||
// reporting a change that has already happened rather than one that is planned.
|
|
||||||
//
|
|
||||||
// The the two resource instances have equal current objects then the result
|
|
||||||
// will be an empty string to indicate that there is no drift to render.
|
|
||||||
//
|
|
||||||
// The resource schema must be provided along with the change so that the
|
|
||||||
// formatted change can reflect the configuration structure for the associated
|
|
||||||
// resource.
|
|
||||||
//
|
|
||||||
// If "color" is non-nil, it will be used to color the result. Otherwise,
|
|
||||||
// no color codes will be included.
|
|
||||||
func ResourceInstanceDrift(
|
|
||||||
addr addrs.AbsResourceInstance,
|
|
||||||
before, after *states.ResourceInstance,
|
|
||||||
schema *configschema.Block,
|
|
||||||
color *colorstring.Colorize,
|
|
||||||
) string {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
|
|
||||||
if color == nil {
|
|
||||||
color = &colorstring.Colorize{
|
|
||||||
Colors: colorstring.DefaultColors,
|
|
||||||
Disable: true,
|
|
||||||
Reset: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dispAddr := addr.String()
|
|
||||||
action := plans.Update
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case before == nil || before.Current == nil:
|
|
||||||
// before should never be nil, but before.Current can be if the
|
|
||||||
// instance was deposed. There is nothing to render for a deposed
|
|
||||||
// instance, since we intend to remove it.
|
|
||||||
return ""
|
|
||||||
|
|
||||||
case after == nil || after.Current == nil:
|
|
||||||
// The object was deleted
|
|
||||||
buf.WriteString(color.Color(fmt.Sprintf("[bold] # %s[reset] has been deleted", dispAddr)))
|
|
||||||
action = plans.Delete
|
|
||||||
default:
|
|
||||||
// The object was changed
|
|
||||||
buf.WriteString(color.Color(fmt.Sprintf("[bold] # %s[reset] has been changed", dispAddr)))
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.WriteString(color.Color("[reset]\n"))
|
|
||||||
|
|
||||||
buf.WriteString(color.Color(DiffActionSymbol(action)) + " ")
|
|
||||||
|
|
||||||
switch addr.Resource.Resource.Mode {
|
|
||||||
case addrs.ManagedResourceMode:
|
|
||||||
buf.WriteString(fmt.Sprintf(
|
|
||||||
"resource %q %q",
|
|
||||||
addr.Resource.Resource.Type,
|
|
||||||
addr.Resource.Resource.Name,
|
|
||||||
))
|
|
||||||
case addrs.DataResourceMode:
|
|
||||||
buf.WriteString(fmt.Sprintf(
|
|
||||||
"data %q %q ",
|
|
||||||
addr.Resource.Resource.Type,
|
|
||||||
addr.Resource.Resource.Name,
|
|
||||||
))
|
|
||||||
default:
|
|
||||||
// should never happen, since the above is exhaustive
|
|
||||||
buf.WriteString(addr.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.WriteString(" {")
|
|
||||||
|
|
||||||
p := blockBodyDiffPrinter{
|
|
||||||
buf: &buf,
|
|
||||||
color: color,
|
|
||||||
action: action,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Most commonly-used resources have nested blocks that result in us
|
|
||||||
// going at least three traversals deep while we recurse here, so we'll
|
|
||||||
// start with that much capacity and then grow as needed for deeper
|
|
||||||
// structures.
|
|
||||||
path := make(cty.Path, 0, 3)
|
|
||||||
|
|
||||||
ty := schema.ImpliedType()
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var oldObj, newObj *states.ResourceInstanceObject
|
|
||||||
oldObj, err = before.Current.Decode(ty)
|
|
||||||
if err != nil {
|
|
||||||
// We shouldn't encounter errors here because Terraform Core should've
|
|
||||||
// made sure that the previous run object conforms to the current
|
|
||||||
// schema by having the provider upgrade it, but we'll be robust here
|
|
||||||
// in case there are some edges we didn't find yet.
|
|
||||||
return fmt.Sprintf(" # %s previous run state doesn't conform to current schema; this is a Terraform bug\n # %s\n", addr, err)
|
|
||||||
}
|
|
||||||
if after != nil && after.Current != nil {
|
|
||||||
newObj, err = after.Current.Decode(ty)
|
|
||||||
if err != nil {
|
|
||||||
// We shouldn't encounter errors here because Terraform Core should've
|
|
||||||
// made sure that the prior state object conforms to the current
|
|
||||||
// schema by having the provider upgrade it, even if we skipped
|
|
||||||
// refreshing on this run, but we'll be robust here in case there are
|
|
||||||
// some edges we didn't find yet.
|
|
||||||
return fmt.Sprintf(" # %s refreshed state doesn't conform to current schema; this is a Terraform bug\n # %s\n", addr, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
oldVal := oldObj.Value
|
|
||||||
var newVal cty.Value
|
|
||||||
if newObj != nil {
|
|
||||||
newVal = newObj.Value
|
|
||||||
} else {
|
|
||||||
newVal = cty.NullVal(ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
if newVal.RawEquals(oldVal) {
|
|
||||||
// Nothing to show, then.
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// We currently have an opt-out that permits the legacy SDK to return values
|
|
||||||
// that defy our usual conventions around handling of nesting blocks. To
|
|
||||||
// avoid the rendering code from needing to handle all of these, we'll
|
|
||||||
// normalize first.
|
|
||||||
// (Ideally we'd do this as part of the SDK opt-out implementation in core,
|
|
||||||
// but we've added it here for now to reduce risk of unexpected impacts
|
|
||||||
// on other code in core.)
|
|
||||||
oldVal = objchange.NormalizeObjectFromLegacySDK(oldVal, schema)
|
|
||||||
newVal = objchange.NormalizeObjectFromLegacySDK(newVal, schema)
|
|
||||||
|
|
||||||
result := p.writeBlockBodyDiff(schema, oldVal, newVal, 6, path)
|
|
||||||
if result.bodyWritten {
|
|
||||||
buf.WriteString("\n")
|
|
||||||
buf.WriteString(strings.Repeat(" ", 4))
|
|
||||||
}
|
|
||||||
buf.WriteString("}\n")
|
|
||||||
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// OutputChanges returns a string representation of a set of changes to output
|
// OutputChanges returns a string representation of a set of changes to output
|
||||||
// values for inclusion in user-facing plan output.
|
// values for inclusion in user-facing plan output.
|
||||||
//
|
//
|
||||||
|
@ -401,7 +290,7 @@ func (p *blockBodyDiffPrinter) writeBlockBodyDiff(schema *configschema.Block, ol
|
||||||
}
|
}
|
||||||
p.buf.WriteString("\n")
|
p.buf.WriteString("\n")
|
||||||
p.buf.WriteString(strings.Repeat(" ", indent+2))
|
p.buf.WriteString(strings.Repeat(" ", indent+2))
|
||||||
p.buf.WriteString(p.color.Color(fmt.Sprintf("[dark_gray]# (%d unchanged %s hidden)[reset]", result.skippedBlocks, noun)))
|
p.buf.WriteString(fmt.Sprintf(p.color.Color("[dark_gray]# (%d unchanged %s hidden)[reset]"), result.skippedBlocks, noun))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1421,7 +1310,7 @@ func (p *blockBodyDiffPrinter) writeValueDiff(old, new cty.Value, indent int, pa
|
||||||
if suppressedElements == 1 {
|
if suppressedElements == 1 {
|
||||||
noun = "element"
|
noun = "element"
|
||||||
}
|
}
|
||||||
p.buf.WriteString(p.color.Color(fmt.Sprintf("[dark_gray]# (%d unchanged %s hidden)[reset]", suppressedElements, noun)))
|
p.buf.WriteString(fmt.Sprintf(p.color.Color("[dark_gray]# (%d unchanged %s hidden)[reset]"), suppressedElements, noun))
|
||||||
p.buf.WriteString("\n")
|
p.buf.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1482,7 +1371,7 @@ func (p *blockBodyDiffPrinter) writeValueDiff(old, new cty.Value, indent int, pa
|
||||||
if hidden == 1 {
|
if hidden == 1 {
|
||||||
noun = "element"
|
noun = "element"
|
||||||
}
|
}
|
||||||
p.buf.WriteString(p.color.Color(fmt.Sprintf("[dark_gray]# (%d unchanged %s hidden)[reset]", hidden, noun)))
|
p.buf.WriteString(fmt.Sprintf(p.color.Color("[dark_gray]# (%d unchanged %s hidden)[reset]"), hidden, noun))
|
||||||
p.buf.WriteString("\n")
|
p.buf.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1624,7 +1513,7 @@ func (p *blockBodyDiffPrinter) writeValueDiff(old, new cty.Value, indent int, pa
|
||||||
if suppressedElements == 1 {
|
if suppressedElements == 1 {
|
||||||
noun = "element"
|
noun = "element"
|
||||||
}
|
}
|
||||||
p.buf.WriteString(p.color.Color(fmt.Sprintf("[dark_gray]# (%d unchanged %s hidden)[reset]", suppressedElements, noun)))
|
p.buf.WriteString(fmt.Sprintf(p.color.Color("[dark_gray]# (%d unchanged %s hidden)[reset]"), suppressedElements, noun))
|
||||||
p.buf.WriteString("\n")
|
p.buf.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1716,7 +1605,7 @@ func (p *blockBodyDiffPrinter) writeValueDiff(old, new cty.Value, indent int, pa
|
||||||
if suppressedElements == 1 {
|
if suppressedElements == 1 {
|
||||||
noun = "element"
|
noun = "element"
|
||||||
}
|
}
|
||||||
p.buf.WriteString(p.color.Color(fmt.Sprintf("[dark_gray]# (%d unchanged %s hidden)[reset]", suppressedElements, noun)))
|
p.buf.WriteString(fmt.Sprintf(p.color.Color("[dark_gray]# (%d unchanged %s hidden)[reset]"), suppressedElements, noun))
|
||||||
p.buf.WriteString("\n")
|
p.buf.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1789,7 +1678,7 @@ func (p *blockBodyDiffPrinter) writeSensitivityWarning(old, new cty.Value, inden
|
||||||
|
|
||||||
if new.HasMark(marks.Sensitive) && !old.HasMark(marks.Sensitive) {
|
if new.HasMark(marks.Sensitive) && !old.HasMark(marks.Sensitive) {
|
||||||
p.buf.WriteString(strings.Repeat(" ", indent))
|
p.buf.WriteString(strings.Repeat(" ", indent))
|
||||||
p.buf.WriteString(p.color.Color(fmt.Sprintf("# [yellow]Warning:[reset] this %s will be marked as sensitive and will not\n", diffType)))
|
p.buf.WriteString(fmt.Sprintf(p.color.Color("# [yellow]Warning:[reset] this %s will be marked as sensitive and will not\n"), diffType))
|
||||||
p.buf.WriteString(strings.Repeat(" ", indent))
|
p.buf.WriteString(strings.Repeat(" ", indent))
|
||||||
p.buf.WriteString(fmt.Sprintf("# display in UI output after applying this change.%s\n", valueUnchangedSuffix))
|
p.buf.WriteString(fmt.Sprintf("# display in UI output after applying this change.%s\n", valueUnchangedSuffix))
|
||||||
}
|
}
|
||||||
|
@ -1797,7 +1686,7 @@ func (p *blockBodyDiffPrinter) writeSensitivityWarning(old, new cty.Value, inden
|
||||||
// Note if changing this attribute will change its sensitivity
|
// Note if changing this attribute will change its sensitivity
|
||||||
if old.HasMark(marks.Sensitive) && !new.HasMark(marks.Sensitive) {
|
if old.HasMark(marks.Sensitive) && !new.HasMark(marks.Sensitive) {
|
||||||
p.buf.WriteString(strings.Repeat(" ", indent))
|
p.buf.WriteString(strings.Repeat(" ", indent))
|
||||||
p.buf.WriteString(p.color.Color(fmt.Sprintf("# [yellow]Warning:[reset] this %s will no longer be marked as sensitive\n", diffType)))
|
p.buf.WriteString(fmt.Sprintf(p.color.Color("# [yellow]Warning:[reset] this %s will no longer be marked as sensitive\n"), diffType))
|
||||||
p.buf.WriteString(strings.Repeat(" ", indent))
|
p.buf.WriteString(strings.Repeat(" ", indent))
|
||||||
p.buf.WriteString(fmt.Sprintf("# after applying this change.%s\n", valueUnchangedSuffix))
|
p.buf.WriteString(fmt.Sprintf("# after applying this change.%s\n", valueUnchangedSuffix))
|
||||||
}
|
}
|
||||||
|
@ -2059,7 +1948,7 @@ func (p *blockBodyDiffPrinter) writeSkippedAttr(skipped, indent int) {
|
||||||
}
|
}
|
||||||
p.buf.WriteString("\n")
|
p.buf.WriteString("\n")
|
||||||
p.buf.WriteString(strings.Repeat(" ", indent))
|
p.buf.WriteString(strings.Repeat(" ", indent))
|
||||||
p.buf.WriteString(p.color.Color(fmt.Sprintf("[dark_gray]# (%d unchanged %s hidden)[reset]", skipped, noun)))
|
p.buf.WriteString(fmt.Sprintf(p.color.Color("[dark_gray]# (%d unchanged %s hidden)[reset]"), skipped, noun))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2070,7 +1959,7 @@ func (p *blockBodyDiffPrinter) writeSkippedElems(skipped, indent int) {
|
||||||
noun = "element"
|
noun = "element"
|
||||||
}
|
}
|
||||||
p.buf.WriteString(strings.Repeat(" ", indent))
|
p.buf.WriteString(strings.Repeat(" ", indent))
|
||||||
p.buf.WriteString(p.color.Color(fmt.Sprintf("[dark_gray]# (%d unchanged %s hidden)[reset]", skipped, noun)))
|
p.buf.WriteString(fmt.Sprintf(p.color.Color("[dark_gray]# (%d unchanged %s hidden)[reset]"), skipped, noun))
|
||||||
p.buf.WriteString("\n")
|
p.buf.WriteString("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4599,7 +4599,7 @@ func runTestCases(t *testing.T, testCases map[string]testCase) {
|
||||||
RequiredReplace: tc.RequiredReplace,
|
RequiredReplace: tc.RequiredReplace,
|
||||||
}
|
}
|
||||||
|
|
||||||
output := ResourceChange(change, tc.Schema, color)
|
output := ResourceChange(change, tc.Schema, color, DiffLanguageProposedChange)
|
||||||
if diff := cmp.Diff(output, tc.ExpectedOutput); diff != "" {
|
if diff := cmp.Diff(output, tc.ExpectedOutput); diff != "" {
|
||||||
t.Errorf("wrong output\n%s", diff)
|
t.Errorf("wrong output\n%s", diff)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Code generated by "stringer -type=DiffLanguage diff.go"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package format
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[DiffLanguageProposedChange-80]
|
||||||
|
_ = x[DiffLanguageDetectedDrift-68]
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
_DiffLanguage_name_0 = "DiffLanguageDetectedDrift"
|
||||||
|
_DiffLanguage_name_1 = "DiffLanguageProposedChange"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i DiffLanguage) String() string {
|
||||||
|
switch {
|
||||||
|
case i == 68:
|
||||||
|
return _DiffLanguage_name_0
|
||||||
|
case i == 80:
|
||||||
|
return _DiffLanguage_name_1
|
||||||
|
default:
|
||||||
|
return "DiffLanguage(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
}
|
|
@ -130,15 +130,17 @@ func Marshal(
|
||||||
}
|
}
|
||||||
|
|
||||||
// output.ResourceDrift
|
// output.ResourceDrift
|
||||||
err = output.marshalResourceDrift(p.PrevRunState, p.PriorState, schemas)
|
output.ResourceDrift, err = output.marshalResourceChanges(p.DriftedResources, schemas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error in marshalResourceDrift: %s", err)
|
return nil, fmt.Errorf("error in marshaling resource drift: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// output.ResourceChanges
|
// output.ResourceChanges
|
||||||
err = output.marshalResourceChanges(p.Changes, schemas)
|
if p.Changes != nil {
|
||||||
|
output.ResourceChanges, err = output.marshalResourceChanges(p.Changes.Resources, schemas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error in marshalResourceChanges: %s", err)
|
return nil, fmt.Errorf("error in marshaling resource changes: %s", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// output.OutputChanges
|
// output.OutputChanges
|
||||||
|
@ -188,149 +190,10 @@ func (p *plan) marshalPlanVariables(vars map[string]plans.DynamicValue, schemas
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *plan) marshalResourceDrift(oldState, newState *states.State, schemas *terraform.Schemas) error {
|
func (p *plan) marshalResourceChanges(resources []*plans.ResourceInstanceChangeSrc, schemas *terraform.Schemas) ([]resourceChange, error) {
|
||||||
// Our goal here is to build a data structure of the same shape as we use
|
var ret []resourceChange
|
||||||
// to describe planned resource changes, but in this case we'll be
|
|
||||||
// taking the old and new values from different state snapshots rather
|
|
||||||
// than from a real "Changes" object.
|
|
||||||
//
|
|
||||||
// In doing this we make an assumption that drift detection can only
|
|
||||||
// ever show objects as updated or removed, and will never show anything
|
|
||||||
// as created because we only refresh objects we were already tracking
|
|
||||||
// after the previous run. This means we can use oldState as our baseline
|
|
||||||
// for what resource instances we might include, and check for each item
|
|
||||||
// whether it's present in newState. If we ever have some mechanism to
|
|
||||||
// detect "additive drift" later then we'll need to take a different
|
|
||||||
// approach here, but we have no plans for that at the time of writing.
|
|
||||||
//
|
|
||||||
// We also assume that both states have had all managed resource objects
|
|
||||||
// upgraded to match the current schemas given in schemas, so we shouldn't
|
|
||||||
// need to contend with oldState having old-shaped objects even if the
|
|
||||||
// user changed provider versions since the last run.
|
|
||||||
|
|
||||||
if newState.ManagedResourcesEqual(oldState) {
|
for _, rc := range resources {
|
||||||
// Nothing to do, because we only detect and report drift for managed
|
|
||||||
// resource instances.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for _, ms := range oldState.Modules {
|
|
||||||
for _, rs := range ms.Resources {
|
|
||||||
if rs.Addr.Resource.Mode != addrs.ManagedResourceMode {
|
|
||||||
// Drift reporting is only for managed resources
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
provider := rs.ProviderConfig.Provider
|
|
||||||
for key, oldIS := range rs.Instances {
|
|
||||||
if oldIS.Current == nil {
|
|
||||||
// Not interested in instances that only have deposed objects
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
addr := rs.Addr.Instance(key)
|
|
||||||
newIS := newState.ResourceInstance(addr)
|
|
||||||
|
|
||||||
schema, _ := schemas.ResourceTypeConfig(
|
|
||||||
provider,
|
|
||||||
addr.Resource.Resource.Mode,
|
|
||||||
addr.Resource.Resource.Type,
|
|
||||||
)
|
|
||||||
if schema == nil {
|
|
||||||
return fmt.Errorf("no schema found for %s (in provider %s)", addr, provider)
|
|
||||||
}
|
|
||||||
ty := schema.ImpliedType()
|
|
||||||
|
|
||||||
oldObj, err := oldIS.Current.Decode(ty)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to decode previous run data for %s: %s", addr, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var newObj *states.ResourceInstanceObject
|
|
||||||
if newIS != nil && newIS.Current != nil {
|
|
||||||
newObj, err = newIS.Current.Decode(ty)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to decode refreshed data for %s: %s", addr, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var oldVal, newVal cty.Value
|
|
||||||
oldVal = oldObj.Value
|
|
||||||
if newObj != nil {
|
|
||||||
newVal = newObj.Value
|
|
||||||
} else {
|
|
||||||
newVal = cty.NullVal(ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
if oldVal.RawEquals(newVal) {
|
|
||||||
// No drift if the two values are semantically equivalent
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
oldSensitive := jsonstate.SensitiveAsBool(oldVal)
|
|
||||||
newSensitive := jsonstate.SensitiveAsBool(newVal)
|
|
||||||
oldVal, _ = oldVal.UnmarkDeep()
|
|
||||||
newVal, _ = newVal.UnmarkDeep()
|
|
||||||
|
|
||||||
var before, after []byte
|
|
||||||
var beforeSensitive, afterSensitive []byte
|
|
||||||
before, err = ctyjson.Marshal(oldVal, oldVal.Type())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to encode previous run data for %s as JSON: %s", addr, err)
|
|
||||||
}
|
|
||||||
after, err = ctyjson.Marshal(newVal, oldVal.Type())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to encode refreshed data for %s as JSON: %s", addr, err)
|
|
||||||
}
|
|
||||||
beforeSensitive, err = ctyjson.Marshal(oldSensitive, oldSensitive.Type())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to encode previous run data sensitivity for %s as JSON: %s", addr, err)
|
|
||||||
}
|
|
||||||
afterSensitive, err = ctyjson.Marshal(newSensitive, newSensitive.Type())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to encode refreshed data sensitivity for %s as JSON: %s", addr, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can only detect updates and deletes as drift.
|
|
||||||
action := plans.Update
|
|
||||||
if newVal.IsNull() {
|
|
||||||
action = plans.Delete
|
|
||||||
}
|
|
||||||
|
|
||||||
change := resourceChange{
|
|
||||||
Address: addr.String(),
|
|
||||||
ModuleAddress: addr.Module.String(),
|
|
||||||
Mode: "managed", // drift reporting is only for managed resources
|
|
||||||
Name: addr.Resource.Resource.Name,
|
|
||||||
Type: addr.Resource.Resource.Type,
|
|
||||||
ProviderName: provider.String(),
|
|
||||||
|
|
||||||
Change: change{
|
|
||||||
Actions: actionString(action.String()),
|
|
||||||
Before: json.RawMessage(before),
|
|
||||||
BeforeSensitive: json.RawMessage(beforeSensitive),
|
|
||||||
After: json.RawMessage(after),
|
|
||||||
AfterSensitive: json.RawMessage(afterSensitive),
|
|
||||||
// AfterUnknown is never populated here because
|
|
||||||
// values in a state are always fully known.
|
|
||||||
},
|
|
||||||
}
|
|
||||||
p.ResourceDrift = append(p.ResourceDrift, change)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(p.ResourceChanges, func(i, j int) bool {
|
|
||||||
return p.ResourceChanges[i].Address < p.ResourceChanges[j].Address
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *plan) marshalResourceChanges(changes *plans.Changes, schemas *terraform.Schemas) error {
|
|
||||||
if changes == nil {
|
|
||||||
// Nothing to do!
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for _, rc := range changes.Resources {
|
|
||||||
var r resourceChange
|
var r resourceChange
|
||||||
addr := rc.Addr
|
addr := rc.Addr
|
||||||
r.Address = addr.String()
|
r.Address = addr.String()
|
||||||
|
@ -349,12 +212,12 @@ func (p *plan) marshalResourceChanges(changes *plans.Changes, schemas *terraform
|
||||||
addr.Resource.Resource.Type,
|
addr.Resource.Resource.Type,
|
||||||
)
|
)
|
||||||
if schema == nil {
|
if schema == nil {
|
||||||
return fmt.Errorf("no schema found for %s (in provider %s)", r.Address, rc.ProviderAddr.Provider)
|
return nil, fmt.Errorf("no schema found for %s (in provider %s)", r.Address, rc.ProviderAddr.Provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
changeV, err := rc.Decode(schema.ImpliedType())
|
changeV, err := rc.Decode(schema.ImpliedType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
// We drop the marks from the change, as decoding is only an
|
// We drop the marks from the change, as decoding is only an
|
||||||
// intermediate step to re-encode the values as json
|
// intermediate step to re-encode the values as json
|
||||||
|
@ -368,7 +231,7 @@ func (p *plan) marshalResourceChanges(changes *plans.Changes, schemas *terraform
|
||||||
if changeV.Before != cty.NilVal {
|
if changeV.Before != cty.NilVal {
|
||||||
before, err = ctyjson.Marshal(changeV.Before, changeV.Before.Type())
|
before, err = ctyjson.Marshal(changeV.Before, changeV.Before.Type())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
marks := rc.BeforeValMarks
|
marks := rc.BeforeValMarks
|
||||||
if schema.ContainsSensitive() {
|
if schema.ContainsSensitive() {
|
||||||
|
@ -377,14 +240,14 @@ func (p *plan) marshalResourceChanges(changes *plans.Changes, schemas *terraform
|
||||||
bs := jsonstate.SensitiveAsBool(changeV.Before.MarkWithPaths(marks))
|
bs := jsonstate.SensitiveAsBool(changeV.Before.MarkWithPaths(marks))
|
||||||
beforeSensitive, err = ctyjson.Marshal(bs, bs.Type())
|
beforeSensitive, err = ctyjson.Marshal(bs, bs.Type())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if changeV.After != cty.NilVal {
|
if changeV.After != cty.NilVal {
|
||||||
if changeV.After.IsWhollyKnown() {
|
if changeV.After.IsWhollyKnown() {
|
||||||
after, err = ctyjson.Marshal(changeV.After, changeV.After.Type())
|
after, err = ctyjson.Marshal(changeV.After, changeV.After.Type())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
afterUnknown = cty.EmptyObjectVal
|
afterUnknown = cty.EmptyObjectVal
|
||||||
} else {
|
} else {
|
||||||
|
@ -394,7 +257,7 @@ func (p *plan) marshalResourceChanges(changes *plans.Changes, schemas *terraform
|
||||||
} else {
|
} else {
|
||||||
after, err = ctyjson.Marshal(filteredAfter, filteredAfter.Type())
|
after, err = ctyjson.Marshal(filteredAfter, filteredAfter.Type())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
afterUnknown = unknownAsBool(changeV.After)
|
afterUnknown = unknownAsBool(changeV.After)
|
||||||
|
@ -406,17 +269,17 @@ func (p *plan) marshalResourceChanges(changes *plans.Changes, schemas *terraform
|
||||||
as := jsonstate.SensitiveAsBool(changeV.After.MarkWithPaths(marks))
|
as := jsonstate.SensitiveAsBool(changeV.After.MarkWithPaths(marks))
|
||||||
afterSensitive, err = ctyjson.Marshal(as, as.Type())
|
afterSensitive, err = ctyjson.Marshal(as, as.Type())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err := ctyjson.Marshal(afterUnknown, afterUnknown.Type())
|
a, err := ctyjson.Marshal(afterUnknown, afterUnknown.Type())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
replacePaths, err := encodePaths(rc.RequiredReplace)
|
replacePaths, err := encodePaths(rc.RequiredReplace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Change = change{
|
r.Change = change{
|
||||||
|
@ -444,7 +307,7 @@ func (p *plan) marshalResourceChanges(changes *plans.Changes, schemas *terraform
|
||||||
case addrs.DataResourceMode:
|
case addrs.DataResourceMode:
|
||||||
r.Mode = "data"
|
r.Mode = "data"
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("resource %s has an unsupported mode %s", r.Address, addr.Resource.Resource.Mode.String())
|
return nil, fmt.Errorf("resource %s has an unsupported mode %s", r.Address, addr.Resource.Resource.Mode.String())
|
||||||
}
|
}
|
||||||
r.ModuleAddress = addr.Module.String()
|
r.ModuleAddress = addr.Module.String()
|
||||||
r.Name = addr.Resource.Resource.Name
|
r.Name = addr.Resource.Resource.Name
|
||||||
|
@ -461,18 +324,18 @@ func (p *plan) marshalResourceChanges(changes *plans.Changes, schemas *terraform
|
||||||
case plans.ResourceInstanceReplaceByRequest:
|
case plans.ResourceInstanceReplaceByRequest:
|
||||||
r.ActionReason = "replace_by_request"
|
r.ActionReason = "replace_by_request"
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("resource %s has an unsupported action reason %s", r.Address, rc.ActionReason)
|
return nil, fmt.Errorf("resource %s has an unsupported action reason %s", r.Address, rc.ActionReason)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.ResourceChanges = append(p.ResourceChanges, r)
|
ret = append(ret, r)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(p.ResourceChanges, func(i, j int) bool {
|
sort.Slice(ret, func(i, j int) bool {
|
||||||
return p.ResourceChanges[i].Address < p.ResourceChanges[j].Address
|
return ret[i].Address < ret[j].Address
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *plan) marshalOutputChanges(changes *plans.Changes) error {
|
func (p *plan) marshalOutputChanges(changes *plans.Changes) error {
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
"id": "placeholder"
|
"id": "placeholder"
|
||||||
},
|
},
|
||||||
"after_sensitive": {},
|
"after_sensitive": {},
|
||||||
|
"after_unknown": {},
|
||||||
"before_sensitive": {}
|
"before_sensitive": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,8 @@
|
||||||
},
|
},
|
||||||
"after": null,
|
"after": null,
|
||||||
"before_sensitive": {},
|
"before_sensitive": {},
|
||||||
"after_sensitive": false
|
"after_sensitive": false,
|
||||||
|
"after_unknown": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/hashicorp/terraform/internal/states/statefile"
|
"github.com/hashicorp/terraform/internal/states/statefile"
|
||||||
"github.com/hashicorp/terraform/internal/terminal"
|
"github.com/hashicorp/terraform/internal/terminal"
|
||||||
"github.com/hashicorp/terraform/internal/terraform"
|
"github.com/hashicorp/terraform/internal/terraform"
|
||||||
|
"github.com/zclconf/go-cty/cty"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestOperation_stopping(t *testing.T) {
|
func TestOperation_stopping(t *testing.T) {
|
||||||
|
@ -84,8 +85,6 @@ func TestOperation_planNoChanges(t *testing.T) {
|
||||||
return &plans.Plan{
|
return &plans.Plan{
|
||||||
UIMode: plans.NormalMode,
|
UIMode: plans.NormalMode,
|
||||||
Changes: plans.NewChanges(),
|
Changes: plans.NewChanges(),
|
||||||
PrevRunState: states.NewState(),
|
|
||||||
PriorState: states.NewState(),
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"no differences, so no changes are needed.",
|
"no differences, so no changes are needed.",
|
||||||
|
@ -95,8 +94,6 @@ func TestOperation_planNoChanges(t *testing.T) {
|
||||||
return &plans.Plan{
|
return &plans.Plan{
|
||||||
UIMode: plans.RefreshOnlyMode,
|
UIMode: plans.RefreshOnlyMode,
|
||||||
Changes: plans.NewChanges(),
|
Changes: plans.NewChanges(),
|
||||||
PrevRunState: states.NewState(),
|
|
||||||
PriorState: states.NewState(),
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Terraform has checked that the real remote objects still match",
|
"Terraform has checked that the real remote objects still match",
|
||||||
|
@ -106,146 +103,88 @@ func TestOperation_planNoChanges(t *testing.T) {
|
||||||
return &plans.Plan{
|
return &plans.Plan{
|
||||||
UIMode: plans.DestroyMode,
|
UIMode: plans.DestroyMode,
|
||||||
Changes: plans.NewChanges(),
|
Changes: plans.NewChanges(),
|
||||||
PrevRunState: states.NewState(),
|
|
||||||
PriorState: states.NewState(),
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"No objects need to be destroyed.",
|
"No objects need to be destroyed.",
|
||||||
},
|
},
|
||||||
"no drift to display with only deposed instances": {
|
|
||||||
// changes in deposed instances will cause a change in state, but
|
|
||||||
// have nothing to display to the user
|
|
||||||
func(schemas *terraform.Schemas) *plans.Plan {
|
|
||||||
return &plans.Plan{
|
|
||||||
UIMode: plans.NormalMode,
|
|
||||||
Changes: plans.NewChanges(),
|
|
||||||
PrevRunState: states.BuildState(func(state *states.SyncState) {
|
|
||||||
state.SetResourceInstanceDeposed(
|
|
||||||
addrs.Resource{
|
|
||||||
Mode: addrs.ManagedResourceMode,
|
|
||||||
Type: "test_resource",
|
|
||||||
Name: "somewhere",
|
|
||||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
|
||||||
states.NewDeposedKey(),
|
|
||||||
&states.ResourceInstanceObjectSrc{
|
|
||||||
Status: states.ObjectReady,
|
|
||||||
AttrsJSON: []byte(`{"foo": "ok", "bars":[]}`),
|
|
||||||
},
|
|
||||||
addrs.RootModuleInstance.ProviderConfigDefault(addrs.NewDefaultProvider("test")),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
PriorState: states.NewState(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"no differences, so no changes are needed.",
|
|
||||||
},
|
|
||||||
"drift detected in normal mode": {
|
"drift detected in normal mode": {
|
||||||
func(schemas *terraform.Schemas) *plans.Plan {
|
func(schemas *terraform.Schemas) *plans.Plan {
|
||||||
return &plans.Plan{
|
addr := addrs.Resource{
|
||||||
UIMode: plans.NormalMode,
|
|
||||||
Changes: plans.NewChanges(),
|
|
||||||
PrevRunState: states.BuildState(func(state *states.SyncState) {
|
|
||||||
state.SetResourceInstanceCurrent(
|
|
||||||
addrs.Resource{
|
|
||||||
Mode: addrs.ManagedResourceMode,
|
Mode: addrs.ManagedResourceMode,
|
||||||
Type: "test_resource",
|
Type: "test_resource",
|
||||||
Name: "somewhere",
|
Name: "somewhere",
|
||||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
||||||
&states.ResourceInstanceObjectSrc{
|
schema, _ := schemas.ResourceTypeConfig(
|
||||||
Status: states.ObjectReady,
|
addrs.NewDefaultProvider("test"),
|
||||||
AttrsJSON: []byte(`{}`),
|
addr.Resource.Resource.Mode,
|
||||||
},
|
addr.Resource.Resource.Type,
|
||||||
addrs.RootModuleInstance.ProviderConfigDefault(addrs.NewDefaultProvider("test")),
|
|
||||||
)
|
)
|
||||||
|
ty := schema.ImpliedType()
|
||||||
|
rc := &plans.ResourceInstanceChange{
|
||||||
|
Addr: addr,
|
||||||
|
PrevRunAddr: addr,
|
||||||
|
ProviderAddr: addrs.RootModuleInstance.ProviderConfigDefault(
|
||||||
|
addrs.NewDefaultProvider("test"),
|
||||||
|
),
|
||||||
|
Change: plans.Change{
|
||||||
|
Action: plans.Update,
|
||||||
|
Before: cty.NullVal(ty),
|
||||||
|
After: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"id": cty.StringVal("1234"),
|
||||||
|
"foo": cty.StringVal("bar"),
|
||||||
}),
|
}),
|
||||||
PriorState: states.NewState(),
|
},
|
||||||
}
|
}
|
||||||
},
|
rcs, err := rc.Encode(ty)
|
||||||
"to update the Terraform state to match, create and apply a refresh-only plan",
|
if err != nil {
|
||||||
},
|
panic(err)
|
||||||
"drift detected with deposed": {
|
}
|
||||||
func(schemas *terraform.Schemas) *plans.Plan {
|
drs := []*plans.ResourceInstanceChangeSrc{rcs}
|
||||||
return &plans.Plan{
|
return &plans.Plan{
|
||||||
UIMode: plans.NormalMode,
|
UIMode: plans.NormalMode,
|
||||||
Changes: plans.NewChanges(),
|
Changes: plans.NewChanges(),
|
||||||
PrevRunState: states.BuildState(func(state *states.SyncState) {
|
DriftedResources: drs,
|
||||||
state.SetResourceInstanceCurrent(
|
|
||||||
addrs.Resource{
|
|
||||||
Mode: addrs.ManagedResourceMode,
|
|
||||||
Type: "test_resource",
|
|
||||||
Name: "changes",
|
|
||||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
|
||||||
&states.ResourceInstanceObjectSrc{
|
|
||||||
Status: states.ObjectReady,
|
|
||||||
AttrsJSON: []byte(`{"foo":"b"}`),
|
|
||||||
},
|
|
||||||
addrs.RootModuleInstance.ProviderConfigDefault(addrs.NewDefaultProvider("test")),
|
|
||||||
)
|
|
||||||
state.SetResourceInstanceDeposed(
|
|
||||||
addrs.Resource{
|
|
||||||
Mode: addrs.ManagedResourceMode,
|
|
||||||
Type: "test_resource",
|
|
||||||
Name: "broken",
|
|
||||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
|
||||||
states.NewDeposedKey(),
|
|
||||||
&states.ResourceInstanceObjectSrc{
|
|
||||||
Status: states.ObjectReady,
|
|
||||||
AttrsJSON: []byte(`{"foo":"c"}`),
|
|
||||||
},
|
|
||||||
addrs.RootModuleInstance.ProviderConfigDefault(addrs.NewDefaultProvider("test")),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
PriorState: states.BuildState(func(state *states.SyncState) {
|
|
||||||
state.SetResourceInstanceCurrent(
|
|
||||||
addrs.Resource{
|
|
||||||
Mode: addrs.ManagedResourceMode,
|
|
||||||
Type: "test_resource",
|
|
||||||
Name: "changed",
|
|
||||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
|
||||||
&states.ResourceInstanceObjectSrc{
|
|
||||||
Status: states.ObjectReady,
|
|
||||||
AttrsJSON: []byte(`{"foo":"b"}`),
|
|
||||||
},
|
|
||||||
addrs.RootModuleInstance.ProviderConfigDefault(addrs.NewDefaultProvider("test")),
|
|
||||||
)
|
|
||||||
state.SetResourceInstanceDeposed(
|
|
||||||
addrs.Resource{
|
|
||||||
Mode: addrs.ManagedResourceMode,
|
|
||||||
Type: "test_resource",
|
|
||||||
Name: "broken",
|
|
||||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
|
||||||
states.NewDeposedKey(),
|
|
||||||
&states.ResourceInstanceObjectSrc{
|
|
||||||
Status: states.ObjectReady,
|
|
||||||
AttrsJSON: []byte(`{"foo":"d"}`),
|
|
||||||
},
|
|
||||||
addrs.RootModuleInstance.ProviderConfigDefault(addrs.NewDefaultProvider("test")),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"to update the Terraform state to match, create and apply a refresh-only plan",
|
"to update the Terraform state to match, create and apply a refresh-only plan",
|
||||||
},
|
},
|
||||||
"drift detected in refresh-only mode": {
|
"drift detected in refresh-only mode": {
|
||||||
func(schemas *terraform.Schemas) *plans.Plan {
|
func(schemas *terraform.Schemas) *plans.Plan {
|
||||||
return &plans.Plan{
|
addr := addrs.Resource{
|
||||||
UIMode: plans.RefreshOnlyMode,
|
|
||||||
Changes: plans.NewChanges(),
|
|
||||||
PrevRunState: states.BuildState(func(state *states.SyncState) {
|
|
||||||
state.SetResourceInstanceCurrent(
|
|
||||||
addrs.Resource{
|
|
||||||
Mode: addrs.ManagedResourceMode,
|
Mode: addrs.ManagedResourceMode,
|
||||||
Type: "test_resource",
|
Type: "test_resource",
|
||||||
Name: "somewhere",
|
Name: "somewhere",
|
||||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
|
||||||
&states.ResourceInstanceObjectSrc{
|
schema, _ := schemas.ResourceTypeConfig(
|
||||||
Status: states.ObjectReady,
|
addrs.NewDefaultProvider("test"),
|
||||||
AttrsJSON: []byte(`{}`),
|
addr.Resource.Resource.Mode,
|
||||||
},
|
addr.Resource.Resource.Type,
|
||||||
addrs.RootModuleInstance.ProviderConfigDefault(addrs.NewDefaultProvider("test")),
|
|
||||||
)
|
)
|
||||||
|
ty := schema.ImpliedType()
|
||||||
|
rc := &plans.ResourceInstanceChange{
|
||||||
|
Addr: addr,
|
||||||
|
PrevRunAddr: addr,
|
||||||
|
ProviderAddr: addrs.RootModuleInstance.ProviderConfigDefault(
|
||||||
|
addrs.NewDefaultProvider("test"),
|
||||||
|
),
|
||||||
|
Change: plans.Change{
|
||||||
|
Action: plans.Update,
|
||||||
|
Before: cty.NullVal(ty),
|
||||||
|
After: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"id": cty.StringVal("1234"),
|
||||||
|
"foo": cty.StringVal("bar"),
|
||||||
}),
|
}),
|
||||||
PriorState: states.NewState(),
|
},
|
||||||
|
}
|
||||||
|
rcs, err := rc.Encode(ty)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
drs := []*plans.ResourceInstanceChangeSrc{rcs}
|
||||||
|
return &plans.Plan{
|
||||||
|
UIMode: plans.RefreshOnlyMode,
|
||||||
|
Changes: plans.NewChanges(),
|
||||||
|
DriftedResources: drs,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"If you were expecting these changes then you can apply this plan",
|
"If you were expecting these changes then you can apply this plan",
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"github.com/hashicorp/terraform/internal/command/arguments"
|
"github.com/hashicorp/terraform/internal/command/arguments"
|
||||||
"github.com/hashicorp/terraform/internal/command/format"
|
"github.com/hashicorp/terraform/internal/command/format"
|
||||||
"github.com/hashicorp/terraform/internal/plans"
|
"github.com/hashicorp/terraform/internal/plans"
|
||||||
"github.com/hashicorp/terraform/internal/states"
|
|
||||||
"github.com/hashicorp/terraform/internal/terraform"
|
"github.com/hashicorp/terraform/internal/terraform"
|
||||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||||
)
|
)
|
||||||
|
@ -97,8 +96,9 @@ func (v *PlanJSON) HelpPrompt() {
|
||||||
// The plan renderer is used by the Operation view (for plan and apply
|
// The plan renderer is used by the Operation view (for plan and apply
|
||||||
// commands) and the Show view (for the show command).
|
// commands) and the Show view (for the show command).
|
||||||
func renderPlan(plan *plans.Plan, schemas *terraform.Schemas, view *View) {
|
func renderPlan(plan *plans.Plan, schemas *terraform.Schemas, view *View) {
|
||||||
haveRefreshChanges := renderChangesDetectedByRefresh(plan.PrevRunState, plan.PriorState, schemas, view)
|
haveRefreshChanges := len(plan.DriftedResources) > 0
|
||||||
if haveRefreshChanges {
|
if haveRefreshChanges {
|
||||||
|
renderChangesDetectedByRefresh(plan.DriftedResources, schemas, view)
|
||||||
switch plan.UIMode {
|
switch plan.UIMode {
|
||||||
case plans.RefreshOnlyMode:
|
case plans.RefreshOnlyMode:
|
||||||
view.streams.Println(format.WordWrap(
|
view.streams.Println(format.WordWrap(
|
||||||
|
@ -292,6 +292,7 @@ func renderPlan(plan *plans.Plan, schemas *terraform.Schemas, view *View) {
|
||||||
rcs,
|
rcs,
|
||||||
rSchema,
|
rSchema,
|
||||||
view.colorize,
|
view.colorize,
|
||||||
|
format.DiffLanguageProposedChange,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,67 +345,7 @@ func renderPlan(plan *plans.Plan, schemas *terraform.Schemas, view *View) {
|
||||||
// renderChangesDetectedByRefresh returns true if it produced at least one
|
// renderChangesDetectedByRefresh returns true if it produced at least one
|
||||||
// line of output, and guarantees to always produce whole lines terminated
|
// line of output, and guarantees to always produce whole lines terminated
|
||||||
// by newline characters.
|
// by newline characters.
|
||||||
func renderChangesDetectedByRefresh(before, after *states.State, schemas *terraform.Schemas, view *View) bool {
|
func renderChangesDetectedByRefresh(drs []*plans.ResourceInstanceChangeSrc, schemas *terraform.Schemas, view *View) {
|
||||||
// ManagedResourceEqual checks that the state is exactly equal for all
|
|
||||||
// managed resources; but semantically equivalent states, or changes to
|
|
||||||
// deposed instances may not actually represent changes we need to present
|
|
||||||
// to the user, so for now this only serves as a short-circuit to skip
|
|
||||||
// attempting to render the diffs below.
|
|
||||||
if after.ManagedResourcesEqual(before) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var diffs []string
|
|
||||||
|
|
||||||
for _, bms := range before.Modules {
|
|
||||||
for _, brs := range bms.Resources {
|
|
||||||
if brs.Addr.Resource.Mode != addrs.ManagedResourceMode {
|
|
||||||
continue // only managed resources can "drift"
|
|
||||||
}
|
|
||||||
addr := brs.Addr
|
|
||||||
prs := after.Resource(brs.Addr)
|
|
||||||
|
|
||||||
provider := brs.ProviderConfig.Provider
|
|
||||||
providerSchema := schemas.ProviderSchema(provider)
|
|
||||||
if providerSchema == nil {
|
|
||||||
// Should never happen
|
|
||||||
view.streams.Printf("(schema missing for %s)\n", provider)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rSchema, _ := providerSchema.SchemaForResourceAddr(addr.Resource)
|
|
||||||
if rSchema == nil {
|
|
||||||
// Should never happen
|
|
||||||
view.streams.Printf("(schema missing for %s)\n", addr)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, bis := range brs.Instances {
|
|
||||||
if bis.Current == nil {
|
|
||||||
// No current instance to render here
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var pis *states.ResourceInstance
|
|
||||||
if prs != nil {
|
|
||||||
pis = prs.Instance(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
diff := format.ResourceInstanceDrift(
|
|
||||||
addr.Instance(key),
|
|
||||||
bis, pis,
|
|
||||||
rSchema,
|
|
||||||
view.colorize,
|
|
||||||
)
|
|
||||||
if diff != "" {
|
|
||||||
diffs = append(diffs, diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we only have changes regarding deposed instances, or the diff
|
|
||||||
// renderer is suppressing irrelevant changes from the legacy SDK, there
|
|
||||||
// may not have been anything to display to the user.
|
|
||||||
if len(diffs) > 0 {
|
|
||||||
view.streams.Print(
|
view.streams.Print(
|
||||||
view.colorize.Color("[reset]\n[bold][cyan]Note:[reset][bold] Objects have changed outside of Terraform[reset]\n\n"),
|
view.colorize.Color("[reset]\n[bold][cyan]Note:[reset][bold] Objects have changed outside of Terraform[reset]\n\n"),
|
||||||
)
|
)
|
||||||
|
@ -413,13 +354,44 @@ func renderChangesDetectedByRefresh(before, after *states.State, schemas *terraf
|
||||||
view.outputColumns(),
|
view.outputColumns(),
|
||||||
))
|
))
|
||||||
|
|
||||||
for _, diff := range diffs {
|
// Note: we're modifying the backing slice of this plan object in-place
|
||||||
view.streams.Print(diff)
|
// here. The ordering of resource changes in a plan is not significant,
|
||||||
|
// but we can only do this safely here because we can assume that nobody
|
||||||
|
// is concurrently modifying our changes while we're trying to print it.
|
||||||
|
sort.Slice(drs, func(i, j int) bool {
|
||||||
|
iA := drs[i].Addr
|
||||||
|
jA := drs[j].Addr
|
||||||
|
if iA.String() == jA.String() {
|
||||||
|
return drs[i].DeposedKey < drs[j].DeposedKey
|
||||||
}
|
}
|
||||||
return true
|
return iA.Less(jA)
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, rcs := range drs {
|
||||||
|
if rcs.Action == plans.NoOp && !rcs.Moved() {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
providerSchema := schemas.ProviderSchema(rcs.ProviderAddr.Provider)
|
||||||
|
if providerSchema == nil {
|
||||||
|
// Should never happen
|
||||||
|
view.streams.Printf("(schema missing for %s)\n\n", rcs.ProviderAddr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rSchema, _ := providerSchema.SchemaForResourceAddr(rcs.Addr.Resource.Resource)
|
||||||
|
if rSchema == nil {
|
||||||
|
// Should never happen
|
||||||
|
view.streams.Printf("(schema missing for %s)\n\n", rcs.Addr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
view.streams.Println(format.ResourceChange(
|
||||||
|
rcs,
|
||||||
|
rSchema,
|
||||||
|
view.colorize,
|
||||||
|
format.DiffLanguageDetectedDrift,
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const planHeaderIntro = `
|
const planHeaderIntro = `
|
||||||
|
|
|
@ -222,6 +222,10 @@ type Plan struct {
|
||||||
// configuration, including any nested modules. Use the address of
|
// configuration, including any nested modules. Use the address of
|
||||||
// each resource to determine which module it belongs to.
|
// each resource to determine which module it belongs to.
|
||||||
ResourceChanges []*ResourceInstanceChange `protobuf:"bytes,3,rep,name=resource_changes,json=resourceChanges,proto3" json:"resource_changes,omitempty"`
|
ResourceChanges []*ResourceInstanceChange `protobuf:"bytes,3,rep,name=resource_changes,json=resourceChanges,proto3" json:"resource_changes,omitempty"`
|
||||||
|
// An unordered set of detected drift: changes made to resources outside of
|
||||||
|
// Terraform, computed by comparing the previous run's state to the state
|
||||||
|
// after refresh.
|
||||||
|
ResourceDrift []*ResourceInstanceChange `protobuf:"bytes,18,rep,name=resource_drift,json=resourceDrift,proto3" json:"resource_drift,omitempty"`
|
||||||
// An unordered set of proposed changes to outputs in the root module
|
// An unordered set of proposed changes to outputs in the root module
|
||||||
// of the configuration. This set also includes "no action" changes for
|
// of the configuration. This set also includes "no action" changes for
|
||||||
// outputs that are not changing, as context for detecting inconsistencies
|
// outputs that are not changing, as context for detecting inconsistencies
|
||||||
|
@ -306,6 +310,13 @@ func (x *Plan) GetResourceChanges() []*ResourceInstanceChange {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Plan) GetResourceDrift() []*ResourceInstanceChange {
|
||||||
|
if x != nil {
|
||||||
|
return x.ResourceDrift
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *Plan) GetOutputChanges() []*OutputChange {
|
func (x *Plan) GetOutputChanges() []*OutputChange {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.OutputChanges
|
return x.OutputChanges
|
||||||
|
@ -952,7 +963,7 @@ var File_planfile_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_planfile_proto_rawDesc = []byte{
|
var file_planfile_proto_rawDesc = []byte{
|
||||||
0x0a, 0x0e, 0x70, 0x6c, 0x61, 0x6e, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
0x0a, 0x0e, 0x70, 0x6c, 0x61, 0x6e, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x12, 0x06, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x22, 0xa5, 0x05, 0x0a, 0x04, 0x50, 0x6c, 0x61,
|
0x12, 0x06, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x22, 0xec, 0x05, 0x0a, 0x04, 0x50, 0x6c, 0x61,
|
||||||
0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01,
|
0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01,
|
||||||
0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x07, 0x75,
|
0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x07, 0x75,
|
||||||
0x69, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x74,
|
0x69, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x74,
|
||||||
|
@ -965,124 +976,128 @@ var file_planfile_proto_rawDesc = []byte{
|
||||||
0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e,
|
0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e,
|
||||||
0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
|
0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
|
||||||
0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
||||||
0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x0e, 0x6f, 0x75, 0x74, 0x70,
|
0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x45, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f,
|
||||||
0x75, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b,
|
0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x72, 0x69, 0x66, 0x74, 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b,
|
||||||
0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74,
|
0x32, 0x1e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||||
0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x43, 0x68,
|
0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
|
||||||
0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f,
|
0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x72, 0x69, 0x66, 0x74, 0x12,
|
||||||
0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x61, 0x72,
|
0x3b, 0x0a, 0x0e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
|
||||||
0x67, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x66, 0x6f, 0x72, 0x63,
|
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e,
|
||||||
0x65, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18,
|
0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0d, 0x6f,
|
||||||
0x10, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c,
|
0x75, 0x74, 0x70, 0x75, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c,
|
||||||
0x61, 0x63, 0x65, 0x41, 0x64, 0x64, 0x72, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x65, 0x72, 0x72,
|
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03,
|
||||||
0x61, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0e, 0x20,
|
0x28, 0x09, 0x52, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x73, 0x12,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x10, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x56, 0x65,
|
0x2e, 0x0a, 0x13, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65,
|
||||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
|
0x5f, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x66, 0x6f,
|
||||||
0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20,
|
0x72, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x41, 0x64, 0x64, 0x72, 0x73, 0x12,
|
||||||
0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x72, 0x6f,
|
0x2b, 0x0a, 0x11, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x76, 0x65, 0x72,
|
||||||
0x76, 0x69, 0x64, 0x65, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
|
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x74, 0x65, 0x72, 0x72,
|
||||||
0x52, 0x0e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73,
|
0x61, 0x66, 0x6f, 0x72, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x0f,
|
||||||
0x12, 0x29, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28,
|
0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18,
|
||||||
0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x65,
|
0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50,
|
||||||
0x6e, 0x64, 0x52, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x1a, 0x52, 0x0a, 0x0e, 0x56,
|
0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x48, 0x61, 0x73, 0x68,
|
||||||
0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
|
0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
|
||||||
|
0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65,
|
||||||
|
0x6e, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61,
|
||||||
|
0x6e, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65,
|
||||||
|
0x6e, 0x64, 0x1a, 0x52, 0x0a, 0x0e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x45,
|
||||||
|
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
|
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
|
||||||
|
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x44,
|
||||||
|
0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c,
|
||||||
|
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4f, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64,
|
||||||
|
0x65, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
|
||||||
0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
|
0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
|
||||||
0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14,
|
0x22, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c,
|
||||||
0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56,
|
0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x05, 0x76, 0x61,
|
||||||
0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a,
|
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x69, 0x0a, 0x07, 0x42, 0x61, 0x63, 0x6b, 0x65,
|
||||||
0x4f, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x48, 0x61, 0x73, 0x68, 0x65,
|
0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
|
0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e,
|
||||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e,
|
0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f,
|
||||||
0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
|
0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63,
|
||||||
0x22, 0x69, 0x0a, 0x07, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74,
|
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
|
||||||
0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12,
|
0x63, 0x65, 0x22, 0xe4, 0x01, 0x0a, 0x06, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x26, 0x0a,
|
||||||
0x2c, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e,
|
||||||
0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63,
|
0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61,
|
||||||
0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a,
|
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18,
|
||||||
0x09, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
|
0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x44,
|
||||||
0x52, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0xe4, 0x01, 0x0a, 0x06,
|
0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c,
|
||||||
0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
0x75, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x16, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x5f, 0x73, 0x65,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e,
|
0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x03, 0x20,
|
||||||
0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c,
|
0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x61, 0x74,
|
||||||
0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14,
|
0x68, 0x52, 0x14, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69,
|
||||||
0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56,
|
0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x40, 0x0a, 0x15, 0x61, 0x66, 0x74, 0x65, 0x72,
|
||||||
0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x16,
|
0x5f, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
|
||||||
0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x5f, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65,
|
0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e,
|
||||||
0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74,
|
0x50, 0x61, 0x74, 0x68, 0x52, 0x13, 0x61, 0x66, 0x74, 0x65, 0x72, 0x53, 0x65, 0x6e, 0x73, 0x69,
|
||||||
0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x52, 0x14, 0x62, 0x65, 0x66, 0x6f,
|
0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x22, 0xd3, 0x02, 0x0a, 0x16, 0x52, 0x65,
|
||||||
0x72, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73,
|
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68,
|
||||||
0x12, 0x40, 0x0a, 0x15, 0x61, 0x66, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74,
|
0x61, 0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x0d, 0x20, 0x01,
|
||||||
0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x70, 0x72, 0x65, 0x76,
|
||||||
0x0c, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x52, 0x13, 0x61,
|
0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x66, 0x74, 0x65, 0x72, 0x53, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x74,
|
0x0b, 0x70, 0x72, 0x65, 0x76, 0x52, 0x75, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1f, 0x0a, 0x0b,
|
||||||
0x68, 0x73, 0x22, 0xd3, 0x02, 0x0a, 0x16, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49,
|
0x64, 0x65, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28,
|
||||||
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a,
|
0x09, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a,
|
||||||
0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64,
|
0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x72, 0x12, 0x22, 0x0a, 0x0d, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x61, 0x64,
|
0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x06, 0x63, 0x68, 0x61,
|
||||||
0x64, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x65, 0x76, 0x52, 0x75,
|
0x6e, 0x67, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74, 0x66, 0x70, 0x6c,
|
||||||
0x6e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x65, 0x64,
|
0x61, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67,
|
||||||
0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x6f,
|
0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x0a, 0x20, 0x01,
|
||||||
0x73, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64,
|
0x28, 0x0c, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x10, 0x72,
|
||||||
0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64,
|
0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18,
|
||||||
0x65, 0x72, 0x12, 0x26, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x09, 0x20, 0x01,
|
0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50,
|
||||||
0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e,
|
0x61, 0x74, 0x68, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, 0x70,
|
||||||
0x67, 0x65, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72,
|
0x6c, 0x61, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72,
|
||||||
0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x72, 0x69,
|
0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x74, 0x66,
|
||||||
0x76, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64,
|
0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73,
|
||||||
0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c,
|
0x74, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f,
|
||||||
0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x52, 0x0f, 0x72, 0x65,
|
0x6e, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22,
|
||||||
0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x12, 0x49, 0x0a,
|
0x68, 0x0a, 0x0c, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12,
|
||||||
0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x0c,
|
0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
|
||||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x52, 0x65,
|
0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20,
|
||||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x63,
|
0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x61,
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69,
|
0x6e, 0x67, 0x65, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73,
|
||||||
0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x68, 0x0a, 0x0c, 0x4f, 0x75, 0x74, 0x70,
|
0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09,
|
||||||
0x75, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x22, 0x28, 0x0a, 0x0c, 0x44, 0x79, 0x6e,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x06,
|
0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x73, 0x67,
|
||||||
0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74,
|
0x70, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x73, 0x67, 0x70,
|
||||||
0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x06, 0x63, 0x68,
|
0x61, 0x63, 0x6b, 0x22, 0x1e, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x73,
|
||||||
0x61, 0x6e, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76,
|
0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x68, 0x61,
|
||||||
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69,
|
0x32, 0x35, 0x36, 0x22, 0xa5, 0x01, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x27, 0x0a, 0x05,
|
||||||
0x76, 0x65, 0x22, 0x28, 0x0a, 0x0c, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c,
|
0x73, 0x74, 0x65, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66,
|
||||||
0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20,
|
0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x2e, 0x53, 0x74, 0x65, 0x70, 0x52, 0x05,
|
||||||
0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x22, 0x1e, 0x0a, 0x04,
|
0x73, 0x74, 0x65, 0x70, 0x73, 0x1a, 0x74, 0x0a, 0x04, 0x53, 0x74, 0x65, 0x70, 0x12, 0x27, 0x0a,
|
||||||
0x48, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x01,
|
0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x22, 0xa5, 0x01, 0x0a,
|
0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
|
||||||
0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x27, 0x0a, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x18, 0x01,
|
0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e,
|
||||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x61,
|
0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66,
|
||||||
0x74, 0x68, 0x2e, 0x53, 0x74, 0x65, 0x70, 0x52, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x1a, 0x74,
|
0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75,
|
||||||
0x0a, 0x04, 0x53, 0x74, 0x65, 0x70, 0x12, 0x27, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62,
|
0x65, 0x48, 0x00, 0x52, 0x0a, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x42,
|
||||||
0x75, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00,
|
0x0a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2a, 0x31, 0x0a, 0x04, 0x4d,
|
||||||
0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12,
|
0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12,
|
||||||
0x37, 0x0a, 0x0b, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02,
|
0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f, 0x59, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c,
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x44, 0x79,
|
0x52, 0x45, 0x46, 0x52, 0x45, 0x53, 0x48, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x02, 0x2a, 0x70,
|
||||||
0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x65, 0x6c,
|
0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4f, 0x50,
|
||||||
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x0a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65,
|
0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x08,
|
||||||
0x63, 0x74, 0x6f, 0x72, 0x2a, 0x31, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06,
|
0x0a, 0x04, 0x52, 0x45, 0x41, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41,
|
||||||
0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54,
|
0x54, 0x45, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x05,
|
||||||
0x52, 0x4f, 0x59, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x46, 0x52, 0x45, 0x53, 0x48,
|
0x12, 0x16, 0x0a, 0x12, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f,
|
||||||
0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x02, 0x2a, 0x70, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f,
|
0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x52, 0x45, 0x41,
|
||||||
0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4f, 0x50, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43,
|
0x54, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x07,
|
||||||
0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x52, 0x45, 0x41, 0x44, 0x10,
|
0x2a, 0x80, 0x01, 0x0a, 0x1c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73,
|
||||||
0x02, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03, 0x12, 0x0a, 0x0a,
|
0x74, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f,
|
||||||
0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x45, 0x4c,
|
0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x52,
|
||||||
0x45, 0x54, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10,
|
0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x54,
|
||||||
0x06, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e,
|
0x41, 0x49, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x50, 0x4c,
|
||||||
0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x07, 0x2a, 0x80, 0x01, 0x0a, 0x1c, 0x52, 0x65,
|
0x41, 0x43, 0x45, 0x5f, 0x42, 0x59, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x02,
|
||||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x63,
|
0x12, 0x21, 0x0a, 0x1d, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41,
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f,
|
0x55, 0x53, 0x45, 0x5f, 0x43, 0x41, 0x4e, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54,
|
||||||
0x4e, 0x45, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f,
|
0x45, 0x10, 0x03, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||||
0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x54, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x44, 0x10,
|
0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x74, 0x65, 0x72, 0x72,
|
||||||
0x01, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x59, 0x5f,
|
0x61, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70,
|
||||||
0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x52, 0x45, 0x50,
|
0x6c, 0x61, 0x6e, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6c,
|
||||||
0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x41, 0x4e,
|
0x61, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03, 0x42, 0x42, 0x5a, 0x40,
|
|
||||||
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69,
|
|
||||||
0x63, 0x6f, 0x72, 0x70, 0x2f, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x69,
|
|
||||||
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x2f, 0x69, 0x6e,
|
|
||||||
0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6c, 0x61, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
|
||||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -1119,27 +1134,28 @@ var file_planfile_proto_depIdxs = []int32{
|
||||||
0, // 0: tfplan.Plan.ui_mode:type_name -> tfplan.Mode
|
0, // 0: tfplan.Plan.ui_mode:type_name -> tfplan.Mode
|
||||||
11, // 1: tfplan.Plan.variables:type_name -> tfplan.Plan.VariablesEntry
|
11, // 1: tfplan.Plan.variables:type_name -> tfplan.Plan.VariablesEntry
|
||||||
6, // 2: tfplan.Plan.resource_changes:type_name -> tfplan.ResourceInstanceChange
|
6, // 2: tfplan.Plan.resource_changes:type_name -> tfplan.ResourceInstanceChange
|
||||||
7, // 3: tfplan.Plan.output_changes:type_name -> tfplan.OutputChange
|
6, // 3: tfplan.Plan.resource_drift:type_name -> tfplan.ResourceInstanceChange
|
||||||
12, // 4: tfplan.Plan.provider_hashes:type_name -> tfplan.Plan.ProviderHashesEntry
|
7, // 4: tfplan.Plan.output_changes:type_name -> tfplan.OutputChange
|
||||||
4, // 5: tfplan.Plan.backend:type_name -> tfplan.Backend
|
12, // 5: tfplan.Plan.provider_hashes:type_name -> tfplan.Plan.ProviderHashesEntry
|
||||||
8, // 6: tfplan.Backend.config:type_name -> tfplan.DynamicValue
|
4, // 6: tfplan.Plan.backend:type_name -> tfplan.Backend
|
||||||
1, // 7: tfplan.Change.action:type_name -> tfplan.Action
|
8, // 7: tfplan.Backend.config:type_name -> tfplan.DynamicValue
|
||||||
8, // 8: tfplan.Change.values:type_name -> tfplan.DynamicValue
|
1, // 8: tfplan.Change.action:type_name -> tfplan.Action
|
||||||
10, // 9: tfplan.Change.before_sensitive_paths:type_name -> tfplan.Path
|
8, // 9: tfplan.Change.values:type_name -> tfplan.DynamicValue
|
||||||
10, // 10: tfplan.Change.after_sensitive_paths:type_name -> tfplan.Path
|
10, // 10: tfplan.Change.before_sensitive_paths:type_name -> tfplan.Path
|
||||||
5, // 11: tfplan.ResourceInstanceChange.change:type_name -> tfplan.Change
|
10, // 11: tfplan.Change.after_sensitive_paths:type_name -> tfplan.Path
|
||||||
10, // 12: tfplan.ResourceInstanceChange.required_replace:type_name -> tfplan.Path
|
5, // 12: tfplan.ResourceInstanceChange.change:type_name -> tfplan.Change
|
||||||
2, // 13: tfplan.ResourceInstanceChange.action_reason:type_name -> tfplan.ResourceInstanceActionReason
|
10, // 13: tfplan.ResourceInstanceChange.required_replace:type_name -> tfplan.Path
|
||||||
5, // 14: tfplan.OutputChange.change:type_name -> tfplan.Change
|
2, // 14: tfplan.ResourceInstanceChange.action_reason:type_name -> tfplan.ResourceInstanceActionReason
|
||||||
13, // 15: tfplan.Path.steps:type_name -> tfplan.Path.Step
|
5, // 15: tfplan.OutputChange.change:type_name -> tfplan.Change
|
||||||
8, // 16: tfplan.Plan.VariablesEntry.value:type_name -> tfplan.DynamicValue
|
13, // 16: tfplan.Path.steps:type_name -> tfplan.Path.Step
|
||||||
9, // 17: tfplan.Plan.ProviderHashesEntry.value:type_name -> tfplan.Hash
|
8, // 17: tfplan.Plan.VariablesEntry.value:type_name -> tfplan.DynamicValue
|
||||||
8, // 18: tfplan.Path.Step.element_key:type_name -> tfplan.DynamicValue
|
9, // 18: tfplan.Plan.ProviderHashesEntry.value:type_name -> tfplan.Hash
|
||||||
19, // [19:19] is the sub-list for method output_type
|
8, // 19: tfplan.Path.Step.element_key:type_name -> tfplan.DynamicValue
|
||||||
19, // [19:19] is the sub-list for method input_type
|
20, // [20:20] is the sub-list for method output_type
|
||||||
19, // [19:19] is the sub-list for extension type_name
|
20, // [20:20] is the sub-list for method input_type
|
||||||
19, // [19:19] is the sub-list for extension extendee
|
20, // [20:20] is the sub-list for extension type_name
|
||||||
0, // [0:19] is the sub-list for field type_name
|
20, // [20:20] is the sub-list for extension extendee
|
||||||
|
0, // [0:20] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_planfile_proto_init() }
|
func init() { file_planfile_proto_init() }
|
||||||
|
|
|
@ -33,6 +33,11 @@ message Plan {
|
||||||
// each resource to determine which module it belongs to.
|
// each resource to determine which module it belongs to.
|
||||||
repeated ResourceInstanceChange resource_changes = 3;
|
repeated ResourceInstanceChange resource_changes = 3;
|
||||||
|
|
||||||
|
// An unordered set of detected drift: changes made to resources outside of
|
||||||
|
// Terraform, computed by comparing the previous run's state to the state
|
||||||
|
// after refresh.
|
||||||
|
repeated ResourceInstanceChange resource_drift = 18;
|
||||||
|
|
||||||
// An unordered set of proposed changes to outputs in the root module
|
// An unordered set of proposed changes to outputs in the root module
|
||||||
// of the configuration. This set also includes "no action" changes for
|
// of the configuration. This set also includes "no action" changes for
|
||||||
// outputs that are not changing, as context for detecting inconsistencies
|
// outputs that are not changing, as context for detecting inconsistencies
|
||||||
|
|
|
@ -31,6 +31,7 @@ type Plan struct {
|
||||||
|
|
||||||
VariableValues map[string]DynamicValue
|
VariableValues map[string]DynamicValue
|
||||||
Changes *Changes
|
Changes *Changes
|
||||||
|
DriftedResources []*ResourceInstanceChangeSrc
|
||||||
TargetAddrs []addrs.Targetable
|
TargetAddrs []addrs.Targetable
|
||||||
ForceReplaceAddrs []addrs.AbsResourceInstance
|
ForceReplaceAddrs []addrs.AbsResourceInstance
|
||||||
ProviderSHA256s map[string][]byte
|
ProviderSHA256s map[string][]byte
|
||||||
|
|
|
@ -51,6 +51,7 @@ func TestRoundtrip(t *testing.T) {
|
||||||
Resources: []*plans.ResourceInstanceChangeSrc{},
|
Resources: []*plans.ResourceInstanceChangeSrc{},
|
||||||
Outputs: []*plans.OutputChangeSrc{},
|
Outputs: []*plans.OutputChangeSrc{},
|
||||||
},
|
},
|
||||||
|
DriftedResources: []*plans.ResourceInstanceChangeSrc{},
|
||||||
ProviderSHA256s: map[string][]byte{},
|
ProviderSHA256s: map[string][]byte{},
|
||||||
VariableValues: map[string]plans.DynamicValue{
|
VariableValues: map[string]plans.DynamicValue{
|
||||||
"foo": plans.DynamicValue([]byte("foo placeholder")),
|
"foo": plans.DynamicValue([]byte("foo placeholder")),
|
||||||
|
|
|
@ -56,6 +56,7 @@ func readTfplan(r io.Reader) (*plans.Plan, error) {
|
||||||
Outputs: []*plans.OutputChangeSrc{},
|
Outputs: []*plans.OutputChangeSrc{},
|
||||||
Resources: []*plans.ResourceInstanceChangeSrc{},
|
Resources: []*plans.ResourceInstanceChangeSrc{},
|
||||||
},
|
},
|
||||||
|
DriftedResources: []*plans.ResourceInstanceChangeSrc{},
|
||||||
|
|
||||||
ProviderSHA256s: map[string][]byte{},
|
ProviderSHA256s: map[string][]byte{},
|
||||||
}
|
}
|
||||||
|
@ -98,6 +99,16 @@ func readTfplan(r io.Reader) (*plans.Plan, error) {
|
||||||
plan.Changes.Resources = append(plan.Changes.Resources, change)
|
plan.Changes.Resources = append(plan.Changes.Resources, change)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, rawRC := range rawPlan.ResourceDrift {
|
||||||
|
change, err := resourceChangeFromTfplan(rawRC)
|
||||||
|
if err != nil {
|
||||||
|
// errors from resourceChangeFromTfplan already include context
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
plan.DriftedResources = append(plan.DriftedResources, change)
|
||||||
|
}
|
||||||
|
|
||||||
for _, rawTargetAddr := range rawPlan.TargetAddrs {
|
for _, rawTargetAddr := range rawPlan.TargetAddrs {
|
||||||
target, diags := addrs.ParseTargetStr(rawTargetAddr)
|
target, diags := addrs.ParseTargetStr(rawTargetAddr)
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
|
@ -342,6 +353,7 @@ func writeTfplan(plan *plans.Plan, w io.Writer) error {
|
||||||
Variables: map[string]*planproto.DynamicValue{},
|
Variables: map[string]*planproto.DynamicValue{},
|
||||||
OutputChanges: []*planproto.OutputChange{},
|
OutputChanges: []*planproto.OutputChange{},
|
||||||
ResourceChanges: []*planproto.ResourceInstanceChange{},
|
ResourceChanges: []*planproto.ResourceInstanceChange{},
|
||||||
|
ResourceDrift: []*planproto.ResourceInstanceChange{},
|
||||||
}
|
}
|
||||||
|
|
||||||
switch plan.UIMode {
|
switch plan.UIMode {
|
||||||
|
@ -388,6 +400,14 @@ func writeTfplan(plan *plans.Plan, w io.Writer) error {
|
||||||
rawPlan.ResourceChanges = append(rawPlan.ResourceChanges, rawRC)
|
rawPlan.ResourceChanges = append(rawPlan.ResourceChanges, rawRC)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, rc := range plan.DriftedResources {
|
||||||
|
rawRC, err := resourceChangeToTfplan(rc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rawPlan.ResourceDrift = append(rawPlan.ResourceDrift, rawRC)
|
||||||
|
}
|
||||||
|
|
||||||
for _, targetAddr := range plan.TargetAddrs {
|
for _, targetAddr := range plan.TargetAddrs {
|
||||||
rawPlan.TargetAddrs = append(rawPlan.TargetAddrs, targetAddr.String())
|
rawPlan.TargetAddrs = append(rawPlan.TargetAddrs, targetAddr.String())
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,46 @@ func TestTFPlanRoundTrip(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DriftedResources: []*plans.ResourceInstanceChangeSrc{
|
||||||
|
{
|
||||||
|
Addr: addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "woot",
|
||||||
|
}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
|
||||||
|
PrevRunAddr: addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "woot",
|
||||||
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||||
|
ProviderAddr: addrs.AbsProviderConfig{
|
||||||
|
Provider: addrs.NewDefaultProvider("test"),
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
},
|
||||||
|
ChangeSrc: plans.ChangeSrc{
|
||||||
|
Action: plans.DeleteThenCreate,
|
||||||
|
Before: mustNewDynamicValue(cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"id": cty.StringVal("foo-bar-baz"),
|
||||||
|
"boop": cty.ListVal([]cty.Value{
|
||||||
|
cty.StringVal("beep"),
|
||||||
|
}),
|
||||||
|
}), objTy),
|
||||||
|
After: mustNewDynamicValue(cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"id": cty.UnknownVal(cty.String),
|
||||||
|
"boop": cty.ListVal([]cty.Value{
|
||||||
|
cty.StringVal("beep"),
|
||||||
|
cty.StringVal("bonk"),
|
||||||
|
}),
|
||||||
|
}), objTy),
|
||||||
|
AfterValMarks: []cty.PathValueMarks{
|
||||||
|
{
|
||||||
|
Path: cty.GetAttrPath("boop").IndexInt(1),
|
||||||
|
Marks: cty.NewValueMarks(marks.Sensitive),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
TargetAddrs: []addrs.Targetable{
|
TargetAddrs: []addrs.Targetable{
|
||||||
addrs.Resource{
|
addrs.Resource{
|
||||||
Mode: addrs.ManagedResourceMode,
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
@ -243,6 +283,7 @@ func TestTFPlanRoundTripDestroy(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DriftedResources: []*plans.ResourceInstanceChangeSrc{},
|
||||||
TargetAddrs: []addrs.Targetable{
|
TargetAddrs: []addrs.Targetable{
|
||||||
addrs.Resource{
|
addrs.Resource{
|
||||||
Mode: addrs.ManagedResourceMode,
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
|
|
@ -411,11 +411,17 @@ func (c *Context) planWalk(config *configs.Config, prevRunState *states.State, r
|
||||||
diags = diags.Append(walkDiags)
|
diags = diags.Append(walkDiags)
|
||||||
diags = diags.Append(c.postPlanValidateMoves(config, moveStmts, walker.InstanceExpander.AllInstances()))
|
diags = diags.Append(c.postPlanValidateMoves(config, moveStmts, walker.InstanceExpander.AllInstances()))
|
||||||
|
|
||||||
|
prevRunState = walker.PrevRunState.Close()
|
||||||
|
priorState := walker.RefreshState.Close()
|
||||||
|
driftedResources, driftDiags := c.driftedResources(config, prevRunState, priorState, moveResults)
|
||||||
|
diags = diags.Append(driftDiags)
|
||||||
|
|
||||||
plan := &plans.Plan{
|
plan := &plans.Plan{
|
||||||
UIMode: opts.Mode,
|
UIMode: opts.Mode,
|
||||||
Changes: changes,
|
Changes: changes,
|
||||||
PriorState: walker.RefreshState.Close(),
|
DriftedResources: driftedResources,
|
||||||
PrevRunState: walker.PrevRunState.Close(),
|
PrevRunState: prevRunState,
|
||||||
|
PriorState: priorState,
|
||||||
|
|
||||||
// Other fields get populated by Context.Plan after we return
|
// Other fields get populated by Context.Plan after we return
|
||||||
}
|
}
|
||||||
|
@ -462,6 +468,126 @@ func (c *Context) planGraph(config *configs.Config, prevRunState *states.State,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Context) driftedResources(config *configs.Config, oldState, newState *states.State, moves map[addrs.UniqueKey]refactoring.MoveResult) ([]*plans.ResourceInstanceChangeSrc, tfdiags.Diagnostics) {
|
||||||
|
var diags tfdiags.Diagnostics
|
||||||
|
|
||||||
|
if newState.ManagedResourcesEqual(oldState) {
|
||||||
|
// Nothing to do, because we only detect and report drift for managed
|
||||||
|
// resource instances.
|
||||||
|
return nil, diags
|
||||||
|
}
|
||||||
|
|
||||||
|
schemas, schemaDiags := c.Schemas(config, newState)
|
||||||
|
diags = diags.Append(schemaDiags)
|
||||||
|
if diags.HasErrors() {
|
||||||
|
return nil, diags
|
||||||
|
}
|
||||||
|
|
||||||
|
var drs []*plans.ResourceInstanceChangeSrc
|
||||||
|
|
||||||
|
for _, ms := range oldState.Modules {
|
||||||
|
for _, rs := range ms.Resources {
|
||||||
|
if rs.Addr.Resource.Mode != addrs.ManagedResourceMode {
|
||||||
|
// Drift reporting is only for managed resources
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := rs.ProviderConfig.Provider
|
||||||
|
for key, oldIS := range rs.Instances {
|
||||||
|
if oldIS.Current == nil {
|
||||||
|
// Not interested in instances that only have deposed objects
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addr := rs.Addr.Instance(key)
|
||||||
|
newIS := newState.ResourceInstance(addr)
|
||||||
|
|
||||||
|
schema, _ := schemas.ResourceTypeConfig(
|
||||||
|
provider,
|
||||||
|
addr.Resource.Resource.Mode,
|
||||||
|
addr.Resource.Resource.Type,
|
||||||
|
)
|
||||||
|
if schema == nil {
|
||||||
|
// This should never happen, but just in case
|
||||||
|
return nil, diags.Append(tfdiags.Sourceless(
|
||||||
|
tfdiags.Error,
|
||||||
|
"Missing resource schema from provider",
|
||||||
|
fmt.Sprintf("No resource schema found for %s.", addr.Resource.Resource.Type),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
ty := schema.ImpliedType()
|
||||||
|
|
||||||
|
oldObj, err := oldIS.Current.Decode(ty)
|
||||||
|
if err != nil {
|
||||||
|
// This should also never happen
|
||||||
|
return nil, diags.Append(tfdiags.Sourceless(
|
||||||
|
tfdiags.Error,
|
||||||
|
"Failed to decode resource from state",
|
||||||
|
fmt.Sprintf("Error decoding %q from previous state: %s", addr.String(), err),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
var newObj *states.ResourceInstanceObject
|
||||||
|
if newIS != nil && newIS.Current != nil {
|
||||||
|
newObj, err = newIS.Current.Decode(ty)
|
||||||
|
if err != nil {
|
||||||
|
// This should also never happen
|
||||||
|
return nil, diags.Append(tfdiags.Sourceless(
|
||||||
|
tfdiags.Error,
|
||||||
|
"Failed to decode resource from state",
|
||||||
|
fmt.Sprintf("Error decoding %q from prior state: %s", addr.String(), err),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var oldVal, newVal cty.Value
|
||||||
|
oldVal = oldObj.Value
|
||||||
|
if newObj != nil {
|
||||||
|
newVal = newObj.Value
|
||||||
|
} else {
|
||||||
|
newVal = cty.NullVal(ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldVal.RawEquals(newVal) {
|
||||||
|
// No drift if the two values are semantically equivalent
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can only detect updates and deletes as drift.
|
||||||
|
action := plans.Update
|
||||||
|
if newVal.IsNull() {
|
||||||
|
action = plans.Delete
|
||||||
|
}
|
||||||
|
|
||||||
|
prevRunAddr := addr
|
||||||
|
if move, ok := moves[addr.UniqueKey()]; ok {
|
||||||
|
prevRunAddr = move.From
|
||||||
|
}
|
||||||
|
|
||||||
|
change := &plans.ResourceInstanceChange{
|
||||||
|
Addr: addr,
|
||||||
|
PrevRunAddr: prevRunAddr,
|
||||||
|
ProviderAddr: rs.ProviderConfig,
|
||||||
|
Change: plans.Change{
|
||||||
|
Action: action,
|
||||||
|
Before: oldVal,
|
||||||
|
After: newVal,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
changeSrc, err := change.Encode(ty)
|
||||||
|
if err != nil {
|
||||||
|
diags = diags.Append(err)
|
||||||
|
return nil, diags
|
||||||
|
}
|
||||||
|
|
||||||
|
drs = append(drs, changeSrc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return drs, diags
|
||||||
|
}
|
||||||
|
|
||||||
// PlanGraphForUI is a last vestage of graphs in the public interface of Context
|
// PlanGraphForUI is a last vestage of graphs in the public interface of Context
|
||||||
// (as opposed to graphs as an implementation detail) intended only for use
|
// (as opposed to graphs as an implementation detail) intended only for use
|
||||||
// by the "terraform graph" command when asked to render a plan-time graph.
|
// by the "terraform graph" command when asked to render a plan-time graph.
|
||||||
|
|
|
@ -108,6 +108,23 @@ resource "test_object" "a" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This situation should result in a drifted resource change.
|
||||||
|
var drifted *plans.ResourceInstanceChangeSrc
|
||||||
|
for _, dr := range plan.DriftedResources {
|
||||||
|
if dr.Addr.Equal(addr) {
|
||||||
|
drifted = dr
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if drifted == nil {
|
||||||
|
t.Errorf("instance %s is missing from the drifted resource changes", addr)
|
||||||
|
} else {
|
||||||
|
if got, want := drifted.Action, plans.Delete; got != want {
|
||||||
|
t.Errorf("unexpected instance %s drifted resource change action. got: %s, want: %s", addr, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Because the configuration still mentions test_object.a, we should've
|
// Because the configuration still mentions test_object.a, we should've
|
||||||
// planned to recreate it in order to fix the drift.
|
// planned to recreate it in order to fix the drift.
|
||||||
for _, c := range plan.Changes.Resources {
|
for _, c := range plan.Changes.Resources {
|
||||||
|
@ -1236,6 +1253,11 @@ func TestContext2Plan_refreshOnlyMode_deposed(t *testing.T) {
|
||||||
t.Errorf("wrong value for output value 'out'\ngot: %#v\nwant: %#v", got, want)
|
t.Errorf("wrong value for output value 'out'\ngot: %#v\nwant: %#v", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deposed objects should not be represented in drift.
|
||||||
|
if len(plan.DriftedResources) > 0 {
|
||||||
|
t.Errorf("unexpected drifted resources (%d)", len(plan.DriftedResources))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContext2Plan_invalidSensitiveModuleOutput(t *testing.T) {
|
func TestContext2Plan_invalidSensitiveModuleOutput(t *testing.T) {
|
||||||
|
|
|
@ -219,6 +219,10 @@ func TestContext2Refresh_targeted(t *testing.T) {
|
||||||
ResourceTypes: map[string]*configschema.Block{
|
ResourceTypes: map[string]*configschema.Block{
|
||||||
"aws_elb": {
|
"aws_elb": {
|
||||||
Attributes: map[string]*configschema.Attribute{
|
Attributes: map[string]*configschema.Attribute{
|
||||||
|
"id": {
|
||||||
|
Type: cty.String,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
"instances": {
|
"instances": {
|
||||||
Type: cty.Set(cty.String),
|
Type: cty.Set(cty.String),
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
@ -295,6 +299,10 @@ func TestContext2Refresh_targetedCount(t *testing.T) {
|
||||||
ResourceTypes: map[string]*configschema.Block{
|
ResourceTypes: map[string]*configschema.Block{
|
||||||
"aws_elb": {
|
"aws_elb": {
|
||||||
Attributes: map[string]*configschema.Attribute{
|
Attributes: map[string]*configschema.Attribute{
|
||||||
|
"id": {
|
||||||
|
Type: cty.String,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
"instances": {
|
"instances": {
|
||||||
Type: cty.Set(cty.String),
|
Type: cty.Set(cty.String),
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
@ -381,6 +389,10 @@ func TestContext2Refresh_targetedCountIndex(t *testing.T) {
|
||||||
ResourceTypes: map[string]*configschema.Block{
|
ResourceTypes: map[string]*configschema.Block{
|
||||||
"aws_elb": {
|
"aws_elb": {
|
||||||
Attributes: map[string]*configschema.Attribute{
|
Attributes: map[string]*configschema.Attribute{
|
||||||
|
"id": {
|
||||||
|
Type: cty.String,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
"instances": {
|
"instances": {
|
||||||
Type: cty.Set(cty.String),
|
Type: cty.Set(cty.String),
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
|
Loading…
Reference in New Issue