core: Handle forced-create_before_destroy during the plan walk
Previously we used a single plan action "Replace" to represent both the destroy-before-create and the create-before-destroy variants of replacing. However, this forces the apply graph builder to jump through a lot of hoops to figure out which nodes need it forced on and rebuild parts of the graph to represent that. If we instead decide between these two cases at plan time, the actual determination of it is more straightforward because each resource is represented by only one node in the plan graph, and then we can ensure we put the right nodes in the graph during DiffTransformer and thus avoid the logic for dealing with deposed instances being spread across various different transformers and node types. As a nice side-effect, this also allows us to show the difference between destroy-then-create and create-then-destroy in the rendered diff in the CLI, although this change doesn't fully implement that yet.
This commit is contained in:
parent
ebe3754fe6
commit
a43b7df282
|
@ -189,9 +189,15 @@ func (b *Local) renderPlan(plan *plans.Plan, schemas *terraform.Schemas) {
|
||||||
if counts[plans.Delete] > 0 {
|
if counts[plans.Delete] > 0 {
|
||||||
fmt.Fprintf(headerBuf, "%s destroy\n", format.DiffActionSymbol(terraform.DiffDestroy))
|
fmt.Fprintf(headerBuf, "%s destroy\n", format.DiffActionSymbol(terraform.DiffDestroy))
|
||||||
}
|
}
|
||||||
if counts[plans.Replace] > 0 {
|
if counts[plans.DeleteThenCreate] > 0 {
|
||||||
fmt.Fprintf(headerBuf, "%s destroy and then create replacement\n", format.DiffActionSymbol(terraform.DiffDestroyCreate))
|
fmt.Fprintf(headerBuf, "%s destroy and then create replacement\n", format.DiffActionSymbol(terraform.DiffDestroyCreate))
|
||||||
}
|
}
|
||||||
|
if counts[plans.CreateThenDelete] > 0 {
|
||||||
|
// FIXME: This shows the wrong symbol, because our old diff action
|
||||||
|
// type can't represent CreateThenDelete. We should switch
|
||||||
|
// format.DiffActionSymbol over to using plans.Action instead.
|
||||||
|
fmt.Fprintf(headerBuf, "%s create replacement and then destroy prior\n", format.DiffActionSymbol(terraform.DiffDestroyCreate))
|
||||||
|
}
|
||||||
if counts[plans.Read] > 0 {
|
if counts[plans.Read] > 0 {
|
||||||
fmt.Fprintf(headerBuf, "%s read (data resources)\n", format.DiffActionSymbol(terraform.DiffRefresh))
|
fmt.Fprintf(headerBuf, "%s read (data resources)\n", format.DiffActionSymbol(terraform.DiffRefresh))
|
||||||
}
|
}
|
||||||
|
@ -243,7 +249,7 @@ func (b *Local) renderPlan(plan *plans.Plan, schemas *terraform.Schemas) {
|
||||||
stats := map[plans.Action]int{}
|
stats := map[plans.Action]int{}
|
||||||
for _, change := range rChanges {
|
for _, change := range rChanges {
|
||||||
switch change.Action {
|
switch change.Action {
|
||||||
case plans.Replace:
|
case plans.CreateThenDelete, plans.DeleteThenCreate:
|
||||||
stats[plans.Create]++
|
stats[plans.Create]++
|
||||||
stats[plans.Delete]++
|
stats[plans.Delete]++
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -65,7 +65,7 @@ func (h *CountHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generat
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
switch action {
|
switch action {
|
||||||
case plans.Replace:
|
case plans.CreateThenDelete, plans.DeleteThenCreate:
|
||||||
h.Added++
|
h.Added++
|
||||||
h.Removed++
|
h.Removed++
|
||||||
case plans.Create:
|
case plans.Create:
|
||||||
|
@ -92,7 +92,7 @@ func (h *CountHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generati
|
||||||
}
|
}
|
||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
case plans.Replace:
|
case plans.CreateThenDelete, plans.DeleteThenCreate:
|
||||||
h.ToRemoveAndAdd += 1
|
h.ToRemoveAndAdd += 1
|
||||||
case plans.Create:
|
case plans.Create:
|
||||||
h.ToAdd += 1
|
h.ToAdd += 1
|
||||||
|
|
|
@ -55,7 +55,7 @@ func ResourceChange(
|
||||||
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(color.Color(fmt.Sprintf("[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)))
|
buf.WriteString(color.Color(fmt.Sprintf("[bold] # %s[reset] will be updated in-place", dispAddr)))
|
||||||
case plans.Replace:
|
case plans.CreateThenDelete, plans.DeleteThenCreate:
|
||||||
buf.WriteString(color.Color(fmt.Sprintf("[bold] # %s[reset] must be [bold][red]replaced", dispAddr)))
|
buf.WriteString(color.Color(fmt.Sprintf("[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)))
|
buf.WriteString(color.Color(fmt.Sprintf("[bold] # %s[reset] will be [bold][red]destroyed", dispAddr)))
|
||||||
|
@ -72,8 +72,10 @@ func ResourceChange(
|
||||||
buf.WriteString(color.Color("[cyan] <=[reset] "))
|
buf.WriteString(color.Color("[cyan] <=[reset] "))
|
||||||
case plans.Update:
|
case plans.Update:
|
||||||
buf.WriteString(color.Color("[yellow] ~[reset] "))
|
buf.WriteString(color.Color("[yellow] ~[reset] "))
|
||||||
case plans.Replace:
|
case plans.DeleteThenCreate:
|
||||||
buf.WriteString(color.Color("[red]-[reset]/[green]+[reset] "))
|
buf.WriteString(color.Color("[red]-[reset]/[green]+[reset] "))
|
||||||
|
case plans.CreateThenDelete:
|
||||||
|
buf.WriteString(color.Color("[green]+[reset]/[red]-[reset] "))
|
||||||
case plans.Delete:
|
case plans.Delete:
|
||||||
buf.WriteString(color.Color("[red] -[reset] "))
|
buf.WriteString(color.Color("[red] -[reset] "))
|
||||||
default:
|
default:
|
||||||
|
@ -837,7 +839,7 @@ func (p *blockBodyDiffPrinter) writeActionSymbol(action plans.Action) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *blockBodyDiffPrinter) pathForcesNewResource(path cty.Path) bool {
|
func (p *blockBodyDiffPrinter) pathForcesNewResource(path cty.Path) bool {
|
||||||
if p.action != plans.Replace {
|
if p.action.IsReplace() {
|
||||||
// "requiredReplace" only applies when the instance is being replaced
|
// "requiredReplace" only applies when the instance is being replaced
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ func NewPlan(changes *plans.Changes) *Plan {
|
||||||
did.Action = terraform.DiffRefresh
|
did.Action = terraform.DiffRefresh
|
||||||
case plans.Delete:
|
case plans.Delete:
|
||||||
did.Action = terraform.DiffDestroy
|
did.Action = terraform.DiffDestroy
|
||||||
case plans.Replace:
|
case plans.DeleteThenCreate, plans.CreateThenDelete:
|
||||||
did.Action = terraform.DiffDestroyCreate
|
did.Action = terraform.DiffDestroyCreate
|
||||||
case plans.Update:
|
case plans.Update:
|
||||||
did.Action = terraform.DiffUpdate
|
did.Action = terraform.DiffUpdate
|
||||||
|
|
|
@ -3,12 +3,20 @@ package plans
|
||||||
type Action rune
|
type Action rune
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NoOp Action = 0
|
NoOp Action = 0
|
||||||
Create Action = '+'
|
Create Action = '+'
|
||||||
Read Action = '←'
|
Read Action = '←'
|
||||||
Update Action = '~'
|
Update Action = '~'
|
||||||
Replace Action = '±'
|
DeleteThenCreate Action = '∓'
|
||||||
Delete Action = '-'
|
CreateThenDelete Action = '±'
|
||||||
|
Delete Action = '-'
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate stringer -type Action
|
//go:generate stringer -type Action
|
||||||
|
|
||||||
|
// IsReplace returns true if the action is one of the two actions that
|
||||||
|
// represents replacing an existing object with a new object:
|
||||||
|
// DeleteThenCreate or CreateThenDelete.
|
||||||
|
func (a Action) IsReplace() bool {
|
||||||
|
return a == DeleteThenCreate || a == CreateThenDelete
|
||||||
|
}
|
||||||
|
|
|
@ -169,7 +169,7 @@ func (rc *ResourceInstanceChange) Simplify(destroying bool) *ResourceInstanceCha
|
||||||
switch rc.Action {
|
switch rc.Action {
|
||||||
case Delete:
|
case Delete:
|
||||||
// We'll fall out and just return rc verbatim, then.
|
// We'll fall out and just return rc verbatim, then.
|
||||||
case Replace:
|
case CreateThenDelete, DeleteThenCreate:
|
||||||
return &ResourceInstanceChange{
|
return &ResourceInstanceChange{
|
||||||
Addr: rc.Addr,
|
Addr: rc.Addr,
|
||||||
DeposedKey: rc.DeposedKey,
|
DeposedKey: rc.DeposedKey,
|
||||||
|
@ -208,7 +208,7 @@ func (rc *ResourceInstanceChange) Simplify(destroying bool) *ResourceInstanceCha
|
||||||
After: rc.Before,
|
After: rc.Before,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case Replace:
|
case CreateThenDelete, DeleteThenCreate:
|
||||||
return &ResourceInstanceChange{
|
return &ResourceInstanceChange{
|
||||||
Addr: rc.Addr,
|
Addr: rc.Addr,
|
||||||
DeposedKey: rc.DeposedKey,
|
DeposedKey: rc.DeposedKey,
|
||||||
|
|
|
@ -23,12 +23,13 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
type Action int32
|
type Action int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Action_NOOP Action = 0
|
Action_NOOP Action = 0
|
||||||
Action_CREATE Action = 1
|
Action_CREATE Action = 1
|
||||||
Action_READ Action = 2
|
Action_READ Action = 2
|
||||||
Action_UPDATE Action = 3
|
Action_UPDATE Action = 3
|
||||||
Action_REPLACE Action = 4
|
Action_DELETE Action = 5
|
||||||
Action_DELETE Action = 5
|
Action_DELETE_THEN_CREATE Action = 6
|
||||||
|
Action_CREATE_THEN_DELETE Action = 7
|
||||||
)
|
)
|
||||||
|
|
||||||
var Action_name = map[int32]string{
|
var Action_name = map[int32]string{
|
||||||
|
@ -36,23 +37,25 @@ var Action_name = map[int32]string{
|
||||||
1: "CREATE",
|
1: "CREATE",
|
||||||
2: "READ",
|
2: "READ",
|
||||||
3: "UPDATE",
|
3: "UPDATE",
|
||||||
4: "REPLACE",
|
|
||||||
5: "DELETE",
|
5: "DELETE",
|
||||||
|
6: "DELETE_THEN_CREATE",
|
||||||
|
7: "CREATE_THEN_DELETE",
|
||||||
}
|
}
|
||||||
var Action_value = map[string]int32{
|
var Action_value = map[string]int32{
|
||||||
"NOOP": 0,
|
"NOOP": 0,
|
||||||
"CREATE": 1,
|
"CREATE": 1,
|
||||||
"READ": 2,
|
"READ": 2,
|
||||||
"UPDATE": 3,
|
"UPDATE": 3,
|
||||||
"REPLACE": 4,
|
"DELETE": 5,
|
||||||
"DELETE": 5,
|
"DELETE_THEN_CREATE": 6,
|
||||||
|
"CREATE_THEN_DELETE": 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x Action) String() string {
|
func (x Action) String() string {
|
||||||
return proto.EnumName(Action_name, int32(x))
|
return proto.EnumName(Action_name, int32(x))
|
||||||
}
|
}
|
||||||
func (Action) EnumDescriptor() ([]byte, []int) {
|
func (Action) EnumDescriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_planfile_2f8b9a0ae177578e, []int{0}
|
return fileDescriptor_planfile_f1de017ed03cb7aa, []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResourceInstanceChange_ResourceMode int32
|
type ResourceInstanceChange_ResourceMode int32
|
||||||
|
@ -75,7 +78,7 @@ func (x ResourceInstanceChange_ResourceMode) String() string {
|
||||||
return proto.EnumName(ResourceInstanceChange_ResourceMode_name, int32(x))
|
return proto.EnumName(ResourceInstanceChange_ResourceMode_name, int32(x))
|
||||||
}
|
}
|
||||||
func (ResourceInstanceChange_ResourceMode) EnumDescriptor() ([]byte, []int) {
|
func (ResourceInstanceChange_ResourceMode) EnumDescriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_planfile_2f8b9a0ae177578e, []int{3, 0}
|
return fileDescriptor_planfile_f1de017ed03cb7aa, []int{3, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plan is the root message type for the tfplan file
|
// Plan is the root message type for the tfplan file
|
||||||
|
@ -122,7 +125,7 @@ func (m *Plan) Reset() { *m = Plan{} }
|
||||||
func (m *Plan) String() string { return proto.CompactTextString(m) }
|
func (m *Plan) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Plan) ProtoMessage() {}
|
func (*Plan) ProtoMessage() {}
|
||||||
func (*Plan) Descriptor() ([]byte, []int) {
|
func (*Plan) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_planfile_2f8b9a0ae177578e, []int{0}
|
return fileDescriptor_planfile_f1de017ed03cb7aa, []int{0}
|
||||||
}
|
}
|
||||||
func (m *Plan) XXX_Unmarshal(b []byte) error {
|
func (m *Plan) XXX_Unmarshal(b []byte) error {
|
||||||
return xxx_messageInfo_Plan.Unmarshal(m, b)
|
return xxx_messageInfo_Plan.Unmarshal(m, b)
|
||||||
|
@ -212,7 +215,7 @@ func (m *Backend) Reset() { *m = Backend{} }
|
||||||
func (m *Backend) String() string { return proto.CompactTextString(m) }
|
func (m *Backend) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Backend) ProtoMessage() {}
|
func (*Backend) ProtoMessage() {}
|
||||||
func (*Backend) Descriptor() ([]byte, []int) {
|
func (*Backend) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_planfile_2f8b9a0ae177578e, []int{1}
|
return fileDescriptor_planfile_f1de017ed03cb7aa, []int{1}
|
||||||
}
|
}
|
||||||
func (m *Backend) XXX_Unmarshal(b []byte) error {
|
func (m *Backend) XXX_Unmarshal(b []byte) error {
|
||||||
return xxx_messageInfo_Backend.Unmarshal(m, b)
|
return xxx_messageInfo_Backend.Unmarshal(m, b)
|
||||||
|
@ -278,7 +281,7 @@ func (m *Change) Reset() { *m = Change{} }
|
||||||
func (m *Change) String() string { return proto.CompactTextString(m) }
|
func (m *Change) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Change) ProtoMessage() {}
|
func (*Change) ProtoMessage() {}
|
||||||
func (*Change) Descriptor() ([]byte, []int) {
|
func (*Change) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_planfile_2f8b9a0ae177578e, []int{2}
|
return fileDescriptor_planfile_f1de017ed03cb7aa, []int{2}
|
||||||
}
|
}
|
||||||
func (m *Change) XXX_Unmarshal(b []byte) error {
|
func (m *Change) XXX_Unmarshal(b []byte) error {
|
||||||
return xxx_messageInfo_Change.Unmarshal(m, b)
|
return xxx_messageInfo_Change.Unmarshal(m, b)
|
||||||
|
@ -364,7 +367,7 @@ func (m *ResourceInstanceChange) Reset() { *m = ResourceInstanceChange{}
|
||||||
func (m *ResourceInstanceChange) String() string { return proto.CompactTextString(m) }
|
func (m *ResourceInstanceChange) String() string { return proto.CompactTextString(m) }
|
||||||
func (*ResourceInstanceChange) ProtoMessage() {}
|
func (*ResourceInstanceChange) ProtoMessage() {}
|
||||||
func (*ResourceInstanceChange) Descriptor() ([]byte, []int) {
|
func (*ResourceInstanceChange) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_planfile_2f8b9a0ae177578e, []int{3}
|
return fileDescriptor_planfile_f1de017ed03cb7aa, []int{3}
|
||||||
}
|
}
|
||||||
func (m *ResourceInstanceChange) XXX_Unmarshal(b []byte) error {
|
func (m *ResourceInstanceChange) XXX_Unmarshal(b []byte) error {
|
||||||
return xxx_messageInfo_ResourceInstanceChange.Unmarshal(m, b)
|
return xxx_messageInfo_ResourceInstanceChange.Unmarshal(m, b)
|
||||||
|
@ -566,7 +569,7 @@ func (m *OutputChange) Reset() { *m = OutputChange{} }
|
||||||
func (m *OutputChange) String() string { return proto.CompactTextString(m) }
|
func (m *OutputChange) String() string { return proto.CompactTextString(m) }
|
||||||
func (*OutputChange) ProtoMessage() {}
|
func (*OutputChange) ProtoMessage() {}
|
||||||
func (*OutputChange) Descriptor() ([]byte, []int) {
|
func (*OutputChange) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_planfile_2f8b9a0ae177578e, []int{4}
|
return fileDescriptor_planfile_f1de017ed03cb7aa, []int{4}
|
||||||
}
|
}
|
||||||
func (m *OutputChange) XXX_Unmarshal(b []byte) error {
|
func (m *OutputChange) XXX_Unmarshal(b []byte) error {
|
||||||
return xxx_messageInfo_OutputChange.Unmarshal(m, b)
|
return xxx_messageInfo_OutputChange.Unmarshal(m, b)
|
||||||
|
@ -630,7 +633,7 @@ func (m *DynamicValue) Reset() { *m = DynamicValue{} }
|
||||||
func (m *DynamicValue) String() string { return proto.CompactTextString(m) }
|
func (m *DynamicValue) String() string { return proto.CompactTextString(m) }
|
||||||
func (*DynamicValue) ProtoMessage() {}
|
func (*DynamicValue) ProtoMessage() {}
|
||||||
func (*DynamicValue) Descriptor() ([]byte, []int) {
|
func (*DynamicValue) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_planfile_2f8b9a0ae177578e, []int{5}
|
return fileDescriptor_planfile_f1de017ed03cb7aa, []int{5}
|
||||||
}
|
}
|
||||||
func (m *DynamicValue) XXX_Unmarshal(b []byte) error {
|
func (m *DynamicValue) XXX_Unmarshal(b []byte) error {
|
||||||
return xxx_messageInfo_DynamicValue.Unmarshal(m, b)
|
return xxx_messageInfo_DynamicValue.Unmarshal(m, b)
|
||||||
|
@ -676,7 +679,7 @@ func (m *Hash) Reset() { *m = Hash{} }
|
||||||
func (m *Hash) String() string { return proto.CompactTextString(m) }
|
func (m *Hash) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Hash) ProtoMessage() {}
|
func (*Hash) ProtoMessage() {}
|
||||||
func (*Hash) Descriptor() ([]byte, []int) {
|
func (*Hash) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_planfile_2f8b9a0ae177578e, []int{6}
|
return fileDescriptor_planfile_f1de017ed03cb7aa, []int{6}
|
||||||
}
|
}
|
||||||
func (m *Hash) XXX_Unmarshal(b []byte) error {
|
func (m *Hash) XXX_Unmarshal(b []byte) error {
|
||||||
return xxx_messageInfo_Hash.Unmarshal(m, b)
|
return xxx_messageInfo_Hash.Unmarshal(m, b)
|
||||||
|
@ -717,7 +720,7 @@ func (m *Path) Reset() { *m = Path{} }
|
||||||
func (m *Path) String() string { return proto.CompactTextString(m) }
|
func (m *Path) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Path) ProtoMessage() {}
|
func (*Path) ProtoMessage() {}
|
||||||
func (*Path) Descriptor() ([]byte, []int) {
|
func (*Path) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_planfile_2f8b9a0ae177578e, []int{7}
|
return fileDescriptor_planfile_f1de017ed03cb7aa, []int{7}
|
||||||
}
|
}
|
||||||
func (m *Path) XXX_Unmarshal(b []byte) error {
|
func (m *Path) XXX_Unmarshal(b []byte) error {
|
||||||
return xxx_messageInfo_Path.Unmarshal(m, b)
|
return xxx_messageInfo_Path.Unmarshal(m, b)
|
||||||
|
@ -758,7 +761,7 @@ func (m *Path_Step) Reset() { *m = Path_Step{} }
|
||||||
func (m *Path_Step) String() string { return proto.CompactTextString(m) }
|
func (m *Path_Step) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Path_Step) ProtoMessage() {}
|
func (*Path_Step) ProtoMessage() {}
|
||||||
func (*Path_Step) Descriptor() ([]byte, []int) {
|
func (*Path_Step) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_planfile_2f8b9a0ae177578e, []int{7, 0}
|
return fileDescriptor_planfile_f1de017ed03cb7aa, []int{7, 0}
|
||||||
}
|
}
|
||||||
func (m *Path_Step) XXX_Unmarshal(b []byte) error {
|
func (m *Path_Step) XXX_Unmarshal(b []byte) error {
|
||||||
return xxx_messageInfo_Path_Step.Unmarshal(m, b)
|
return xxx_messageInfo_Path_Step.Unmarshal(m, b)
|
||||||
|
@ -899,64 +902,64 @@ func init() {
|
||||||
proto.RegisterEnum("tfplan.ResourceInstanceChange_ResourceMode", ResourceInstanceChange_ResourceMode_name, ResourceInstanceChange_ResourceMode_value)
|
proto.RegisterEnum("tfplan.ResourceInstanceChange_ResourceMode", ResourceInstanceChange_ResourceMode_name, ResourceInstanceChange_ResourceMode_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { proto.RegisterFile("planfile.proto", fileDescriptor_planfile_2f8b9a0ae177578e) }
|
func init() { proto.RegisterFile("planfile.proto", fileDescriptor_planfile_f1de017ed03cb7aa) }
|
||||||
|
|
||||||
var fileDescriptor_planfile_2f8b9a0ae177578e = []byte{
|
var fileDescriptor_planfile_f1de017ed03cb7aa = []byte{
|
||||||
// 885 bytes of a gzipped FileDescriptorProto
|
// 893 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x55, 0xdb, 0x6e, 0xe3, 0x36,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x55, 0xe1, 0x6e, 0xe3, 0x44,
|
||||||
0x13, 0xb6, 0x2c, 0xf9, 0x34, 0x76, 0x14, 0x2d, 0xff, 0x1f, 0x0b, 0x21, 0x5d, 0x6c, 0x5d, 0x01,
|
0x10, 0xae, 0x63, 0xc7, 0x49, 0x26, 0xa9, 0x9b, 0x5b, 0x50, 0x65, 0x95, 0xd3, 0x11, 0x2c, 0xc1,
|
||||||
0xed, 0xba, 0xbb, 0x85, 0x03, 0xb8, 0x68, 0xd3, 0x6d, 0x2f, 0x0a, 0x27, 0x31, 0x90, 0x60, 0x0f,
|
0x85, 0x3b, 0x94, 0x4a, 0x41, 0x50, 0x0e, 0x7e, 0xa0, 0xf6, 0x1a, 0x29, 0xd5, 0x41, 0x1b, 0x2d,
|
||||||
0x31, 0xd8, 0x6d, 0x2e, 0x7a, 0x51, 0x83, 0x96, 0x26, 0xb6, 0x10, 0x9d, 0x4a, 0xd2, 0x2e, 0xfc,
|
0xa5, 0x3f, 0xf8, 0x81, 0xb5, 0xb1, 0xa7, 0x89, 0x55, 0xc7, 0x36, 0xbb, 0x9b, 0xa0, 0x3c, 0x10,
|
||||||
0x40, 0x7d, 0x88, 0xbe, 0x44, 0x9f, 0xa9, 0x20, 0x29, 0xc9, 0x0e, 0x90, 0xe6, 0xca, 0x9a, 0x6f,
|
0x0f, 0xc1, 0x4b, 0xf0, 0x4c, 0x68, 0x77, 0x6d, 0x27, 0x95, 0x7a, 0xfd, 0x95, 0x9d, 0x6f, 0x66,
|
||||||
0x86, 0x1f, 0x67, 0xbe, 0x99, 0xa1, 0xc1, 0x2d, 0x12, 0x96, 0xdd, 0xc5, 0x09, 0x8e, 0x0b, 0x9e,
|
0x3e, 0xcf, 0x7e, 0x33, 0xb3, 0x01, 0xaf, 0x48, 0x59, 0x76, 0x9f, 0xa4, 0x38, 0x2a, 0x78, 0x2e,
|
||||||
0xcb, 0x9c, 0xb4, 0xe5, 0x9d, 0x42, 0x82, 0x7f, 0x1c, 0x70, 0xe6, 0x09, 0xcb, 0x88, 0x0f, 0x9d,
|
0x73, 0xe2, 0xca, 0x7b, 0x85, 0x04, 0xff, 0x39, 0xe0, 0xcc, 0x52, 0x96, 0x11, 0x1f, 0x5a, 0x1b,
|
||||||
0x2d, 0x72, 0x11, 0xe7, 0x99, 0x6f, 0x0d, 0xad, 0x91, 0x43, 0x2b, 0x93, 0xbc, 0x85, 0xde, 0x96,
|
0xe4, 0x22, 0xc9, 0x33, 0xdf, 0x1a, 0x58, 0x43, 0x87, 0x56, 0x26, 0x79, 0x07, 0x9d, 0x0d, 0xe3,
|
||||||
0xf1, 0x98, 0x2d, 0x13, 0x14, 0x7e, 0x73, 0x68, 0x8f, 0xfa, 0x93, 0xcf, 0xc6, 0xe6, 0xf8, 0x58,
|
0x09, 0x9b, 0xa7, 0x28, 0xfc, 0xc6, 0xc0, 0x1e, 0x76, 0xc7, 0x9f, 0x8d, 0x4c, 0xfa, 0x48, 0xa5,
|
||||||
0x1d, 0x1d, 0xdf, 0x56, 0xde, 0x59, 0x26, 0xf9, 0x8e, 0xee, 0xa3, 0xc9, 0x35, 0x78, 0x1c, 0x45,
|
0x8e, 0xee, 0x2a, 0xef, 0x24, 0x93, 0x7c, 0x4b, 0x77, 0xd1, 0xe4, 0x0a, 0xfa, 0x1c, 0x45, 0xbe,
|
||||||
0xbe, 0xe1, 0x21, 0x2e, 0xc2, 0x35, 0xcb, 0x56, 0x28, 0x7c, 0x5b, 0x33, 0xbc, 0xac, 0x18, 0x68,
|
0xe6, 0x11, 0x86, 0xd1, 0x92, 0x65, 0x0b, 0x14, 0xbe, 0xad, 0x19, 0x5e, 0x55, 0x0c, 0xb4, 0xf4,
|
||||||
0xe9, 0xbf, 0xce, 0x84, 0x64, 0x59, 0x88, 0x17, 0x3a, 0x8c, 0x1e, 0x57, 0xe7, 0x8c, 0x2d, 0xc8,
|
0x5f, 0x65, 0x42, 0xb2, 0x2c, 0xc2, 0xf7, 0x3a, 0x8c, 0x1e, 0x55, 0x79, 0xc6, 0x16, 0xe4, 0x27,
|
||||||
0x4f, 0xe0, 0xe6, 0x1b, 0x59, 0x6c, 0x64, 0x4d, 0xe4, 0x68, 0xa2, 0xff, 0x57, 0x44, 0x37, 0xda,
|
0xf0, 0xf2, 0xb5, 0x2c, 0xd6, 0xb2, 0x26, 0x72, 0x34, 0xd1, 0xa7, 0x15, 0xd1, 0x8d, 0xf6, 0x96,
|
||||||
0x5b, 0x1e, 0x3f, 0xca, 0x0f, 0x2c, 0x41, 0xbe, 0x80, 0x81, 0x64, 0x7c, 0x85, 0x72, 0xc1, 0xa2,
|
0xe9, 0x87, 0xf9, 0x9e, 0x25, 0xc8, 0x17, 0xd0, 0x93, 0x8c, 0x2f, 0x50, 0x86, 0x2c, 0x8e, 0xb9,
|
||||||
0x88, 0x0b, 0xbf, 0x35, 0xb4, 0x47, 0x3d, 0xda, 0x37, 0xd8, 0x54, 0x41, 0xe4, 0x0d, 0x3c, 0x93,
|
0xf0, 0x9b, 0x03, 0x7b, 0xd8, 0xa1, 0x5d, 0x83, 0x9d, 0x2b, 0x88, 0xbc, 0x85, 0x17, 0x12, 0x39,
|
||||||
0xc8, 0x39, 0xbb, 0xcb, 0x79, 0xba, 0xa8, 0x94, 0x70, 0x87, 0xd6, 0xa8, 0x47, 0xbd, 0xda, 0x71,
|
0x67, 0xf7, 0x39, 0x5f, 0x85, 0x95, 0x12, 0xde, 0xc0, 0x1a, 0x76, 0x68, 0xbf, 0x76, 0xdc, 0x95,
|
||||||
0x5b, 0x4a, 0x72, 0x0d, 0xc7, 0x05, 0xcf, 0xb7, 0x71, 0x84, 0x7c, 0xb1, 0x66, 0x62, 0x8d, 0xc2,
|
0x92, 0x5c, 0xc1, 0x51, 0xc1, 0xf3, 0x4d, 0x12, 0x23, 0x0f, 0x97, 0x4c, 0x2c, 0x51, 0xf8, 0x47,
|
||||||
0x3f, 0xd6, 0xd9, 0x0c, 0x1f, 0x08, 0x33, 0x2f, 0x63, 0xae, 0x74, 0x88, 0x51, 0xc7, 0x2d, 0x1e,
|
0xba, 0x9a, 0xc1, 0x23, 0x61, 0x66, 0x65, 0xcc, 0x54, 0x87, 0x18, 0x75, 0xbc, 0xe2, 0x11, 0x48,
|
||||||
0x80, 0xe4, 0x6b, 0xe8, 0x2c, 0x59, 0x78, 0x8f, 0x59, 0xe4, 0x1f, 0x0d, 0xad, 0x51, 0x7f, 0x72,
|
0xbe, 0x86, 0xd6, 0x9c, 0x45, 0x0f, 0x98, 0xc5, 0xfe, 0xe1, 0xc0, 0x1a, 0x76, 0xc7, 0x47, 0x15,
|
||||||
0x5c, 0x51, 0x9c, 0x1b, 0x98, 0x56, 0xfe, 0x13, 0x0a, 0xee, 0x43, 0xa9, 0x89, 0x07, 0xf6, 0x3d,
|
0xc5, 0x85, 0x81, 0x69, 0xe5, 0x3f, 0xa1, 0xe0, 0x3d, 0x96, 0x9a, 0xf4, 0xc1, 0x7e, 0xc0, 0xad,
|
||||||
0xee, 0x74, 0xc3, 0x7a, 0x54, 0x7d, 0x92, 0xd7, 0xd0, 0xda, 0xb2, 0x64, 0x83, 0x7e, 0x53, 0x93,
|
0x6e, 0x58, 0x87, 0xaa, 0x23, 0x79, 0x03, 0xcd, 0x0d, 0x4b, 0xd7, 0xe8, 0x37, 0x34, 0x59, 0xad,
|
||||||
0xd5, 0xea, 0x5c, 0xee, 0x32, 0x96, 0xc6, 0xe1, 0xad, 0xf2, 0x51, 0x13, 0xf2, 0x63, 0xf3, 0x07,
|
0xce, 0xe5, 0x36, 0x63, 0xab, 0x24, 0xba, 0x53, 0x3e, 0x6a, 0x42, 0x7e, 0x6c, 0xfc, 0x60, 0x9d,
|
||||||
0xeb, 0xe4, 0x06, 0xfe, 0xf7, 0x48, 0x96, 0x8f, 0x10, 0x07, 0x0f, 0x89, 0x07, 0x15, 0xb1, 0x3a,
|
0xdc, 0xc0, 0x27, 0x4f, 0x54, 0xf9, 0x04, 0x71, 0xf0, 0x98, 0xb8, 0x57, 0x11, 0xab, 0xac, 0x3d,
|
||||||
0x75, 0x40, 0x18, 0xc4, 0xd0, 0x29, 0x13, 0x27, 0x04, 0x1c, 0xb9, 0x2b, 0xb0, 0x64, 0xd1, 0xdf,
|
0xc2, 0x20, 0x81, 0x56, 0x59, 0x38, 0x21, 0xe0, 0xc8, 0x6d, 0x81, 0x25, 0x8b, 0x3e, 0x93, 0x6f,
|
||||||
0xe4, 0x1b, 0x68, 0x87, 0x79, 0x76, 0x17, 0xaf, 0x9e, 0x4c, 0xb0, 0x8c, 0x21, 0x2f, 0xa0, 0xf7,
|
0xc0, 0x8d, 0xf2, 0xec, 0x3e, 0x59, 0x3c, 0x5b, 0x60, 0x19, 0x43, 0x5e, 0x42, 0xe7, 0xef, 0x9c,
|
||||||
0x67, 0xce, 0xef, 0x45, 0xc1, 0x42, 0xf4, 0x6d, 0x4d, 0xb3, 0x07, 0x82, 0xdf, 0xa1, 0x6d, 0x1a,
|
0x3f, 0x88, 0x82, 0x45, 0xe8, 0xdb, 0x9a, 0x66, 0x07, 0x04, 0x7f, 0x82, 0x6b, 0x1a, 0x4c, 0xbe,
|
||||||
0x4c, 0xbe, 0x82, 0x36, 0x0b, 0x65, 0x35, 0xbb, 0xee, 0xc4, 0xad, 0x58, 0xa7, 0x1a, 0xa5, 0xa5,
|
0x02, 0x97, 0x45, 0xb2, 0x9a, 0x5d, 0x6f, 0xec, 0x55, 0xac, 0xe7, 0x1a, 0xa5, 0xa5, 0x57, 0x7d,
|
||||||
0x57, 0xdd, 0xae, 0x33, 0xad, 0xe6, 0xf8, 0x3f, 0x6e, 0x37, 0x31, 0xc1, 0xdf, 0x36, 0x3c, 0x7f,
|
0x5d, 0x57, 0x5a, 0xcd, 0xf1, 0x47, 0xbe, 0x6e, 0x62, 0x82, 0x7f, 0x6d, 0x38, 0x7e, 0x7a, 0x3c,
|
||||||
0x7c, 0x3c, 0xc9, 0xe7, 0xd0, 0x4f, 0xf3, 0x68, 0x93, 0xe0, 0xa2, 0x60, 0x72, 0x5d, 0x56, 0x08,
|
0xc9, 0xe7, 0xd0, 0x5d, 0xe5, 0xf1, 0x3a, 0xc5, 0xb0, 0x60, 0x72, 0x59, 0xde, 0x10, 0x0c, 0x34,
|
||||||
0x06, 0x9a, 0x33, 0xb9, 0x26, 0x3f, 0x83, 0x93, 0xe6, 0x91, 0x51, 0xcb, 0x9d, 0xbc, 0x79, 0x7a,
|
0x63, 0x72, 0x49, 0x7e, 0x06, 0x67, 0x95, 0xc7, 0x46, 0x2d, 0x6f, 0xfc, 0xf6, 0xf9, 0x69, 0xaf,
|
||||||
0xda, 0x6b, 0xf8, 0x43, 0x1e, 0x21, 0xd5, 0x07, 0x6b, 0xf1, 0xec, 0x03, 0xf1, 0x08, 0x38, 0x19,
|
0xe1, 0x5f, 0xf3, 0x18, 0xa9, 0x4e, 0xac, 0xc5, 0xb3, 0xf7, 0xc4, 0x23, 0xe0, 0x64, 0x6c, 0x85,
|
||||||
0x4b, 0xd1, 0x77, 0x0c, 0xa6, 0xbe, 0x09, 0x01, 0x5b, 0x48, 0xee, 0xb7, 0x14, 0x74, 0xd5, 0xa0,
|
0xbe, 0x63, 0x30, 0x75, 0x26, 0x04, 0x6c, 0x21, 0xb9, 0xdf, 0x54, 0xd0, 0xf4, 0x80, 0x2a, 0x43,
|
||||||
0xca, 0x50, 0x58, 0x9c, 0x49, 0xbf, 0x3d, 0xb4, 0x46, 0xb6, 0xc2, 0xe2, 0x4c, 0xaa, 0x8c, 0x23,
|
0x61, 0x49, 0x26, 0x7d, 0x77, 0x60, 0x0d, 0x6d, 0x85, 0x25, 0x99, 0x54, 0x15, 0xc7, 0x58, 0xe4,
|
||||||
0x2c, 0x72, 0x81, 0xd1, 0x42, 0x75, 0xb6, 0x63, 0x32, 0x2e, 0xa1, 0x77, 0xb8, 0x23, 0x27, 0xd0,
|
0x02, 0xe3, 0x50, 0x75, 0xb6, 0x65, 0x2a, 0x2e, 0xa1, 0x0f, 0xb8, 0x25, 0x27, 0xd0, 0xae, 0x46,
|
||||||
0xad, 0x46, 0xd3, 0xef, 0x6a, 0x6f, 0x6d, 0x2b, 0x7d, 0xcd, 0xd6, 0xf9, 0x3d, 0xdd, 0xb5, 0x5a,
|
0xd3, 0x6f, 0x6b, 0x6f, 0x6d, 0x2b, 0x7d, 0xcd, 0xd6, 0xf9, 0x1d, 0xdd, 0xb5, 0x5a, 0xdf, 0x72,
|
||||||
0xdf, 0x72, 0xdd, 0x4a, 0xaf, 0x7a, 0x44, 0x0a, 0x1e, 0x6f, 0x99, 0x44, 0x1f, 0x86, 0xd6, 0x68,
|
0xdd, 0x4a, 0xaf, 0x7a, 0x44, 0x0a, 0x9e, 0x6c, 0x98, 0x44, 0x1f, 0x06, 0xd6, 0xb0, 0x47, 0x2b,
|
||||||
0x40, 0x2b, 0x93, 0x9c, 0xa9, 0x97, 0xe0, 0x8f, 0x4d, 0xcc, 0x31, 0x5a, 0x70, 0x2c, 0x12, 0xd5,
|
0x93, 0x9c, 0xa9, 0x97, 0xe0, 0xaf, 0x75, 0xc2, 0x31, 0x0e, 0x39, 0x16, 0xa9, 0x6a, 0x68, 0x57,
|
||||||
0xd0, 0xbe, 0xee, 0x41, 0x3d, 0x49, 0x4a, 0x37, 0xb5, 0xf7, 0x26, 0x8a, 0x9a, 0xa0, 0xe0, 0x4b,
|
0xf7, 0xa0, 0x9e, 0x24, 0xa5, 0x9b, 0xda, 0x7b, 0x13, 0x45, 0x4d, 0x50, 0xf0, 0x25, 0xf4, 0xf6,
|
||||||
0x18, 0x1c, 0xaa, 0x43, 0xfa, 0xd0, 0x49, 0x59, 0xc6, 0x56, 0x18, 0x79, 0x0d, 0xd2, 0x05, 0x27,
|
0xd5, 0x21, 0x5d, 0x68, 0xad, 0x58, 0xc6, 0x16, 0x18, 0xf7, 0x0f, 0x48, 0x1b, 0x9c, 0x98, 0x49,
|
||||||
0x62, 0x92, 0x79, 0xd6, 0xb9, 0x0b, 0x83, 0xb8, 0xd4, 0x54, 0xd5, 0x17, 0xac, 0x61, 0x70, 0xf8,
|
0xd6, 0xb7, 0x2e, 0x3c, 0xe8, 0x25, 0xa5, 0xa6, 0xea, 0x7e, 0xc1, 0x12, 0x7a, 0xfb, 0x0f, 0x42,
|
||||||
0x20, 0xd4, 0xd2, 0x59, 0x07, 0xd2, 0xed, 0xab, 0x6a, 0x3e, 0x59, 0xd5, 0x0b, 0xe8, 0x09, 0xcc,
|
0x2d, 0x9d, 0xb5, 0x27, 0xdd, 0xee, 0x56, 0x8d, 0x67, 0x6f, 0xf5, 0x12, 0x3a, 0x02, 0x33, 0x91,
|
||||||
0x44, 0x2c, 0xe3, 0xad, 0xe9, 0x47, 0x97, 0xee, 0x81, 0x60, 0x04, 0x83, 0xc3, 0xe9, 0x51, 0x1a,
|
0xc8, 0x64, 0x63, 0xfa, 0xd1, 0xa6, 0x3b, 0x20, 0x18, 0x42, 0x6f, 0x7f, 0x7a, 0x94, 0x06, 0x2b,
|
||||||
0xa4, 0x62, 0x55, 0xb0, 0xf0, 0x5e, 0x5f, 0x36, 0xa0, 0x95, 0x19, 0xbc, 0x04, 0x47, 0x6d, 0x0b,
|
0xb1, 0x28, 0x58, 0xf4, 0xa0, 0x3f, 0xd6, 0xa3, 0x95, 0x19, 0xbc, 0x02, 0x47, 0x6d, 0x0b, 0x39,
|
||||||
0x79, 0x0e, 0x6d, 0xb1, 0x66, 0x93, 0xef, 0xbe, 0x2f, 0x03, 0x4a, 0x2b, 0xf8, 0xcb, 0x02, 0x47,
|
0x06, 0x57, 0x2c, 0xd9, 0xf8, 0xbb, 0xef, 0xcb, 0x80, 0xd2, 0x0a, 0xfe, 0xb1, 0xc0, 0xd1, 0xc3,
|
||||||
0x0f, 0xcf, 0x2b, 0x68, 0x09, 0x89, 0x85, 0xf0, 0x2d, 0xad, 0xd0, 0xb3, 0x43, 0x85, 0xc6, 0xbf,
|
0xf3, 0x1a, 0x9a, 0x42, 0x62, 0x21, 0x7c, 0x4b, 0x2b, 0xf4, 0x62, 0x5f, 0xa1, 0xd1, 0x6f, 0x12,
|
||||||
0x48, 0x2c, 0xa8, 0xf1, 0x9f, 0x48, 0x70, 0x94, 0x49, 0x5e, 0x81, 0xcb, 0xa4, 0xe4, 0xf1, 0x72,
|
0x0b, 0x6a, 0xfc, 0x27, 0x12, 0x1c, 0x65, 0x92, 0xd7, 0xe0, 0x31, 0x29, 0x79, 0x32, 0x5f, 0x4b,
|
||||||
0x23, 0x71, 0xb1, 0xaf, 0xf3, 0xaa, 0x41, 0x8f, 0x6a, 0xfc, 0xa3, 0x2a, 0xf9, 0x0c, 0xfa, 0x98,
|
0x0c, 0x77, 0xf7, 0x9c, 0x1e, 0xd0, 0xc3, 0x1a, 0xbf, 0x56, 0x57, 0x3e, 0x83, 0x2e, 0xa6, 0xb8,
|
||||||
0x60, 0x8a, 0x99, 0xd4, 0x53, 0xf0, 0xc4, 0x0e, 0x5e, 0x35, 0x28, 0x94, 0xa1, 0xef, 0x70, 0x77,
|
0xc2, 0x4c, 0xea, 0x29, 0x78, 0x66, 0x07, 0xa7, 0x07, 0x14, 0xca, 0xd0, 0x0f, 0xb8, 0xbd, 0x00,
|
||||||
0x0e, 0xd0, 0x15, 0x98, 0x60, 0x28, 0x73, 0xfe, 0xfa, 0x03, 0xb4, 0xcd, 0x5e, 0x29, 0xfd, 0x3f,
|
0x68, 0x0b, 0x4c, 0x31, 0x92, 0x39, 0x7f, 0x53, 0x80, 0x6b, 0xf6, 0x4a, 0xe9, 0x7f, 0x7d, 0x73,
|
||||||
0xde, 0xdc, 0xcc, 0xbd, 0x06, 0x01, 0x68, 0x5f, 0xd0, 0xd9, 0xf4, 0xd3, 0xcc, 0xb3, 0x14, 0x4a,
|
0x33, 0xeb, 0x1f, 0x10, 0x00, 0xf7, 0x3d, 0x9d, 0x9c, 0xdf, 0x4e, 0xfa, 0x96, 0x42, 0xe9, 0xe4,
|
||||||
0x67, 0xd3, 0x4b, 0xaf, 0xa9, 0xd0, 0x5f, 0xe7, 0x97, 0x0a, 0xb5, 0x55, 0xe3, 0xe8, 0x6c, 0xfe,
|
0xfc, 0xb2, 0xdf, 0x50, 0xe8, 0xef, 0xb3, 0x4b, 0x85, 0xda, 0xea, 0x7c, 0x39, 0xf9, 0x65, 0x72,
|
||||||
0x7e, 0x7a, 0x31, 0xf3, 0x1c, 0xe5, 0xb8, 0x9c, 0xbd, 0x9f, 0x7d, 0x9a, 0x79, 0xad, 0xf3, 0xb7,
|
0x3b, 0xe9, 0x37, 0xc9, 0x31, 0x10, 0x73, 0x0e, 0x6f, 0xa7, 0x93, 0xeb, 0xb0, 0xcc, 0x74, 0x15,
|
||||||
0xbf, 0x9d, 0xad, 0x62, 0xb9, 0xde, 0x2c, 0xc7, 0x61, 0x9e, 0x9e, 0xaa, 0xe7, 0x34, 0x0e, 0x73,
|
0x6e, 0xce, 0x06, 0x2f, 0xe3, 0x5b, 0x17, 0xef, 0xfe, 0x38, 0x5b, 0x24, 0x72, 0xb9, 0x9e, 0x8f,
|
||||||
0x5e, 0x9c, 0xd6, 0xaf, 0xee, 0xa9, 0x4a, 0x4e, 0x9c, 0xc6, 0x99, 0x44, 0x9e, 0xb1, 0x44, 0x9b,
|
0xa2, 0x7c, 0x75, 0xaa, 0x5e, 0xdc, 0x24, 0xca, 0x79, 0x71, 0x5a, 0x3f, 0xcc, 0xa7, 0xaa, 0x7e,
|
||||||
0xfa, 0x5f, 0x6c, 0xd9, 0xd6, 0x3f, 0xdf, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x41, 0x65,
|
0x71, 0x9a, 0x64, 0x12, 0x79, 0xc6, 0x52, 0x6d, 0xea, 0x3f, 0xba, 0xb9, 0xab, 0x7f, 0xbe, 0xfd,
|
||||||
0x5b, 0xde, 0x06, 0x00, 0x00,
|
0x3f, 0x00, 0x00, 0xff, 0xff, 0x30, 0x3e, 0x4e, 0x33, 0x01, 0x07, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,8 +63,9 @@ enum Action {
|
||||||
CREATE = 1;
|
CREATE = 1;
|
||||||
READ = 2;
|
READ = 2;
|
||||||
UPDATE = 3;
|
UPDATE = 3;
|
||||||
REPLACE = 4;
|
|
||||||
DELETE = 5;
|
DELETE = 5;
|
||||||
|
DELETE_THEN_CREATE = 6;
|
||||||
|
CREATE_THEN_DELETE = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change represents a change made to some object, transforming it from an old
|
// Change represents a change made to some object, transforming it from an old
|
||||||
|
|
|
@ -230,13 +230,17 @@ func changeFromTfplan(rawChange *planproto.Change) (*plans.ChangeSrc, error) {
|
||||||
ret.Action = plans.Update
|
ret.Action = plans.Update
|
||||||
beforeIdx = 0
|
beforeIdx = 0
|
||||||
afterIdx = 1
|
afterIdx = 1
|
||||||
case planproto.Action_REPLACE:
|
|
||||||
ret.Action = plans.Replace
|
|
||||||
beforeIdx = 0
|
|
||||||
afterIdx = 1
|
|
||||||
case planproto.Action_DELETE:
|
case planproto.Action_DELETE:
|
||||||
ret.Action = plans.Delete
|
ret.Action = plans.Delete
|
||||||
beforeIdx = 0
|
beforeIdx = 0
|
||||||
|
case planproto.Action_CREATE_THEN_DELETE:
|
||||||
|
ret.Action = plans.CreateThenDelete
|
||||||
|
beforeIdx = 0
|
||||||
|
afterIdx = 1
|
||||||
|
case planproto.Action_DELETE_THEN_CREATE:
|
||||||
|
ret.Action = plans.DeleteThenCreate
|
||||||
|
beforeIdx = 0
|
||||||
|
afterIdx = 1
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid change action %s", rawChange.Action)
|
return nil, fmt.Errorf("invalid change action %s", rawChange.Action)
|
||||||
}
|
}
|
||||||
|
@ -425,12 +429,15 @@ func changeToTfplan(change *plans.ChangeSrc) (*planproto.Change, error) {
|
||||||
case plans.Update:
|
case plans.Update:
|
||||||
ret.Action = planproto.Action_UPDATE
|
ret.Action = planproto.Action_UPDATE
|
||||||
ret.Values = []*planproto.DynamicValue{before, after}
|
ret.Values = []*planproto.DynamicValue{before, after}
|
||||||
case plans.Replace:
|
|
||||||
ret.Action = planproto.Action_REPLACE
|
|
||||||
ret.Values = []*planproto.DynamicValue{before, after}
|
|
||||||
case plans.Delete:
|
case plans.Delete:
|
||||||
ret.Action = planproto.Action_DELETE
|
ret.Action = planproto.Action_DELETE
|
||||||
ret.Values = []*planproto.DynamicValue{before}
|
ret.Values = []*planproto.DynamicValue{before}
|
||||||
|
case plans.DeleteThenCreate:
|
||||||
|
ret.Action = planproto.Action_DELETE_THEN_CREATE
|
||||||
|
ret.Values = []*planproto.DynamicValue{before, after}
|
||||||
|
case plans.CreateThenDelete:
|
||||||
|
ret.Action = planproto.Action_CREATE_THEN_DELETE
|
||||||
|
ret.Values = []*planproto.DynamicValue{before, after}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid change action %s", change.Action)
|
return nil, fmt.Errorf("invalid change action %s", change.Action)
|
||||||
}
|
}
|
||||||
|
|
|
@ -980,6 +980,9 @@ aws_instance.bar:
|
||||||
require_new = yes
|
require_new = yes
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
value = foo
|
value = foo
|
||||||
|
|
||||||
|
Dependencies:
|
||||||
|
aws_instance.foo
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider.aws
|
provider = provider.aws
|
||||||
|
|
|
@ -3885,7 +3885,7 @@ func TestContext2Plan_taint(t *testing.T) {
|
||||||
|
|
||||||
switch i := ric.Addr.String(); i {
|
switch i := ric.Addr.String(); i {
|
||||||
case "aws_instance.bar":
|
case "aws_instance.bar":
|
||||||
if res.Action != plans.Replace {
|
if res.Action != plans.DeleteThenCreate {
|
||||||
t.Fatalf("resource %s should be replaced", i)
|
t.Fatalf("resource %s should be replaced", i)
|
||||||
}
|
}
|
||||||
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
||||||
|
@ -3970,7 +3970,7 @@ func TestContext2Plan_taintIgnoreChanges(t *testing.T) {
|
||||||
|
|
||||||
switch i := ric.Addr.String(); i {
|
switch i := ric.Addr.String(); i {
|
||||||
case "aws_instance.foo":
|
case "aws_instance.foo":
|
||||||
if res.Action != plans.Replace {
|
if res.Action != plans.DeleteThenCreate {
|
||||||
t.Fatalf("resource %s should be replaced", i)
|
t.Fatalf("resource %s should be replaced", i)
|
||||||
}
|
}
|
||||||
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
||||||
|
@ -4050,7 +4050,7 @@ func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) {
|
||||||
|
|
||||||
switch i := ric.Addr.String(); i {
|
switch i := ric.Addr.String(); i {
|
||||||
case "aws_instance.foo[0]":
|
case "aws_instance.foo[0]":
|
||||||
if res.Action != plans.Replace {
|
if res.Action != plans.DeleteThenCreate {
|
||||||
t.Fatalf("resource %s should be replaced", i)
|
t.Fatalf("resource %s should be replaced", i)
|
||||||
}
|
}
|
||||||
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
||||||
|
|
|
@ -876,8 +876,10 @@ func legacyDiffComparisonString(changes *plans.Changes) string {
|
||||||
crud := "UPDATE"
|
crud := "UPDATE"
|
||||||
if rc.Current != nil {
|
if rc.Current != nil {
|
||||||
switch rc.Current.Action {
|
switch rc.Current.Action {
|
||||||
case plans.Replace:
|
case plans.DeleteThenCreate:
|
||||||
crud = "DESTROY/CREATE"
|
crud = "DESTROY/CREATE"
|
||||||
|
case plans.CreateThenDelete:
|
||||||
|
crud = "CREATE/DESTROY"
|
||||||
case plans.Delete:
|
case plans.Delete:
|
||||||
crud = "DESTROY"
|
crud = "DESTROY"
|
||||||
case plans.Create:
|
case plans.Create:
|
||||||
|
|
|
@ -53,7 +53,7 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.CreateNew != nil {
|
if n.CreateNew != nil {
|
||||||
*n.CreateNew = (change.Action == plans.Create || change.Action == plans.Replace)
|
*n.CreateNew = (change.Action == plans.Create || change.Action.IsReplace())
|
||||||
}
|
}
|
||||||
|
|
||||||
configVal := cty.NullVal(cty.DynamicPseudoType)
|
configVal := cty.NullVal(cty.DynamicPseudoType)
|
||||||
|
|
|
@ -29,7 +29,7 @@ func (n *EvalCheckPreventDestroy) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
change := *n.Change
|
change := *n.Change
|
||||||
preventDestroy := n.Config.Managed.PreventDestroy
|
preventDestroy := n.Config.Managed.PreventDestroy
|
||||||
|
|
||||||
if (change.Action == plans.Delete || change.Action == plans.Replace) && preventDestroy {
|
if (change.Action == plans.Delete || change.Action.IsReplace()) && preventDestroy {
|
||||||
var diags tfdiags.Diagnostics
|
var diags tfdiags.Diagnostics
|
||||||
diags = diags.Append(&hcl.Diagnostic{
|
diags = diags.Append(&hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
|
|
|
@ -92,6 +92,12 @@ type EvalDiff struct {
|
||||||
State **states.ResourceInstanceObject
|
State **states.ResourceInstanceObject
|
||||||
PreviousDiff **plans.ResourceInstanceChange
|
PreviousDiff **plans.ResourceInstanceChange
|
||||||
|
|
||||||
|
// CreateBeforeDestroy is set if either the resource's own config sets
|
||||||
|
// create_before_destroy explicitly or if dependencies have forced the
|
||||||
|
// resource to be handled as create_before_destroy in order to avoid
|
||||||
|
// a dependency cycle.
|
||||||
|
CreateBeforeDestroy bool
|
||||||
|
|
||||||
OutputChange **plans.ResourceInstanceChange
|
OutputChange **plans.ResourceInstanceChange
|
||||||
OutputValue *cty.Value
|
OutputValue *cty.Value
|
||||||
OutputState **states.ResourceInstanceObject
|
OutputState **states.ResourceInstanceObject
|
||||||
|
@ -270,14 +276,18 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
case !reqRep.Empty():
|
case !reqRep.Empty():
|
||||||
// If there are any "requires replace" paths left _after our filtering
|
// If there are any "requires replace" paths left _after our filtering
|
||||||
// above_ then this is a replace action.
|
// above_ then this is a replace action.
|
||||||
action = plans.Replace
|
if n.CreateBeforeDestroy {
|
||||||
|
action = plans.CreateThenDelete
|
||||||
|
} else {
|
||||||
|
action = plans.DeleteThenCreate
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
action = plans.Update
|
action = plans.Update
|
||||||
// "Delete" is never chosen here, because deletion plans are always
|
// "Delete" is never chosen here, because deletion plans are always
|
||||||
// created more directly elsewhere, such as in "orphan" handling.
|
// created more directly elsewhere, such as in "orphan" handling.
|
||||||
}
|
}
|
||||||
|
|
||||||
if action == plans.Replace {
|
if action.IsReplace() {
|
||||||
// In this strange situation we want to produce a change object that
|
// In this strange situation we want to produce a change object that
|
||||||
// shows our real prior object but has a _new_ object that is built
|
// shows our real prior object but has a _new_ object that is built
|
||||||
// from a null prior object, since we're going to delete the one
|
// from a null prior object, since we're going to delete the one
|
||||||
|
@ -327,7 +337,11 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
// as a replace change, even though so far we've been treating it as a
|
// as a replace change, even though so far we've been treating it as a
|
||||||
// create.
|
// create.
|
||||||
if action == plans.Create && priorValTainted != cty.NilVal {
|
if action == plans.Create && priorValTainted != cty.NilVal {
|
||||||
action = plans.Replace
|
if n.CreateBeforeDestroy {
|
||||||
|
action = plans.CreateThenDelete
|
||||||
|
} else {
|
||||||
|
action = plans.DeleteThenCreate
|
||||||
|
}
|
||||||
priorVal = priorValTainted
|
priorVal = priorValTainted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,9 +353,9 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
// we originally intended.
|
// we originally intended.
|
||||||
if n.PreviousDiff != nil {
|
if n.PreviousDiff != nil {
|
||||||
prevChange := *n.PreviousDiff
|
prevChange := *n.PreviousDiff
|
||||||
if prevChange.Action == plans.Replace && action == plans.Create {
|
if prevChange.Action.IsReplace() && action == plans.Create {
|
||||||
log.Printf("[TRACE] EvalDiff: %s treating Create change as Replace change to match with earlier plan", absAddr)
|
log.Printf("[TRACE] EvalDiff: %s treating Create change as %s change to match with earlier plan", absAddr, prevChange.Action)
|
||||||
action = plans.Replace
|
action = prevChange.Action
|
||||||
priorVal = prevChange.Before
|
priorVal = prevChange.Before
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,6 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
|
||||||
// ConfigTransformer above.
|
// ConfigTransformer above.
|
||||||
&DiffTransformer{
|
&DiffTransformer{
|
||||||
Concrete: concreteResourceInstance,
|
Concrete: concreteResourceInstance,
|
||||||
Config: b.Config,
|
|
||||||
State: b.State,
|
State: b.State,
|
||||||
Changes: b.Changes,
|
Changes: b.Changes,
|
||||||
},
|
},
|
||||||
|
|
|
@ -76,7 +76,7 @@ func TestApplyGraphBuilder_depCbd(t *testing.T) {
|
||||||
{
|
{
|
||||||
Addr: mustResourceInstanceAddr("test_object.A"),
|
Addr: mustResourceInstanceAddr("test_object.A"),
|
||||||
ChangeSrc: plans.ChangeSrc{
|
ChangeSrc: plans.ChangeSrc{
|
||||||
Action: plans.Replace,
|
Action: plans.CreateThenDelete,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -152,13 +152,13 @@ func TestApplyGraphBuilder_doubleCBD(t *testing.T) {
|
||||||
{
|
{
|
||||||
Addr: mustResourceInstanceAddr("test_object.A"),
|
Addr: mustResourceInstanceAddr("test_object.A"),
|
||||||
ChangeSrc: plans.ChangeSrc{
|
ChangeSrc: plans.ChangeSrc{
|
||||||
Action: plans.Replace,
|
Action: plans.CreateThenDelete,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Addr: mustResourceInstanceAddr("test_object.B"),
|
Addr: mustResourceInstanceAddr("test_object.B"),
|
||||||
ChangeSrc: plans.ChangeSrc{
|
ChangeSrc: plans.ChangeSrc{
|
||||||
Action: plans.Replace,
|
Action: plans.CreateThenDelete,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -157,6 +157,10 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
||||||
IgnoreIndices: true,
|
IgnoreIndices: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Detect when create_before_destroy must be forced on for a particular
|
||||||
|
// node due to dependency edges, to avoid graph cycles during apply.
|
||||||
|
&ForcedCBDTransformer{},
|
||||||
|
|
||||||
// Close opened plugin connections
|
// Close opened plugin connections
|
||||||
&CloseProviderTransformer{},
|
&CloseProviderTransformer{},
|
||||||
&CloseProvisionerTransformer{},
|
&CloseProvisionerTransformer{},
|
||||||
|
|
|
@ -241,7 +241,7 @@ func (n *NodeApplyableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe
|
||||||
If: func(ctx EvalContext) (bool, error) {
|
If: func(ctx EvalContext) (bool, error) {
|
||||||
destroy := false
|
destroy := false
|
||||||
if diffApply != nil {
|
if diffApply != nil {
|
||||||
destroy = (diffApply.Action == plans.Delete || diffApply.Action == plans.Replace)
|
destroy = (diffApply.Action == plans.Delete || diffApply.Action.IsReplace())
|
||||||
}
|
}
|
||||||
if destroy && n.createBeforeDestroy() {
|
if destroy && n.createBeforeDestroy() {
|
||||||
createBeforeDestroyEnabled = true
|
createBeforeDestroyEnabled = true
|
||||||
|
@ -395,7 +395,7 @@ func (n *NodeApplyableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe
|
||||||
// is no longer a diff!
|
// is no longer a diff!
|
||||||
&EvalIf{
|
&EvalIf{
|
||||||
If: func(ctx EvalContext) (bool, error) {
|
If: func(ctx EvalContext) (bool, error) {
|
||||||
if diff.Action != plans.Replace {
|
if !diff.Action.IsReplace() {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
if !n.createBeforeDestroy() {
|
if !n.createBeforeDestroy() {
|
||||||
|
|
|
@ -15,6 +15,10 @@ import (
|
||||||
// an associated deposed object key.
|
// an associated deposed object key.
|
||||||
type ConcreteResourceInstanceDeposedNodeFunc func(*NodeAbstractResourceInstance, states.DeposedKey) dag.Vertex
|
type ConcreteResourceInstanceDeposedNodeFunc func(*NodeAbstractResourceInstance, states.DeposedKey) dag.Vertex
|
||||||
|
|
||||||
|
type GraphNodeDeposedResourceInstanceObject interface {
|
||||||
|
DeposedInstanceObjectKey() states.DeposedKey
|
||||||
|
}
|
||||||
|
|
||||||
// NodePlanDeposedResourceInstanceObject represents deposed resource
|
// NodePlanDeposedResourceInstanceObject represents deposed resource
|
||||||
// instance objects during plan. These are distinct from the primary object
|
// instance objects during plan. These are distinct from the primary object
|
||||||
// for each resource instance since the only valid operation to do with them
|
// for each resource instance since the only valid operation to do with them
|
||||||
|
@ -28,19 +32,24 @@ type NodePlanDeposedResourceInstanceObject struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ GraphNodeResource = (*NodePlanDeposedResourceInstanceObject)(nil)
|
_ GraphNodeDeposedResourceInstanceObject = (*NodePlanDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeResourceInstance = (*NodePlanDeposedResourceInstanceObject)(nil)
|
_ GraphNodeResource = (*NodePlanDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeReferenceable = (*NodePlanDeposedResourceInstanceObject)(nil)
|
_ GraphNodeResourceInstance = (*NodePlanDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeReferencer = (*NodePlanDeposedResourceInstanceObject)(nil)
|
_ GraphNodeReferenceable = (*NodePlanDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeEvalable = (*NodePlanDeposedResourceInstanceObject)(nil)
|
_ GraphNodeReferencer = (*NodePlanDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeProviderConsumer = (*NodePlanDeposedResourceInstanceObject)(nil)
|
_ GraphNodeEvalable = (*NodePlanDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeProvisionerConsumer = (*NodePlanDeposedResourceInstanceObject)(nil)
|
_ GraphNodeProviderConsumer = (*NodePlanDeposedResourceInstanceObject)(nil)
|
||||||
|
_ GraphNodeProvisionerConsumer = (*NodePlanDeposedResourceInstanceObject)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (n *NodePlanDeposedResourceInstanceObject) Name() string {
|
func (n *NodePlanDeposedResourceInstanceObject) Name() string {
|
||||||
return fmt.Sprintf("%s (deposed %s)", n.Addr.String(), n.DeposedKey)
|
return fmt.Sprintf("%s (deposed %s)", n.Addr.String(), n.DeposedKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *NodePlanDeposedResourceInstanceObject) DeposedInstanceObjectKey() states.DeposedKey {
|
||||||
|
return n.DeposedKey
|
||||||
|
}
|
||||||
|
|
||||||
// GraphNodeReferenceable implementation, overriding the one from NodeAbstractResourceInstance
|
// GraphNodeReferenceable implementation, overriding the one from NodeAbstractResourceInstance
|
||||||
func (n *NodePlanDeposedResourceInstanceObject) ReferenceableAddrs() []addrs.Referenceable {
|
func (n *NodePlanDeposedResourceInstanceObject) ReferenceableAddrs() []addrs.Referenceable {
|
||||||
// Deposed objects don't participate in references.
|
// Deposed objects don't participate in references.
|
||||||
|
@ -155,21 +164,26 @@ type NodeDestroyDeposedResourceInstanceObject struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ GraphNodeResource = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
_ GraphNodeDeposedResourceInstanceObject = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeResourceInstance = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
_ GraphNodeResource = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeDestroyer = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
_ GraphNodeResourceInstance = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeDestroyerCBD = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
_ GraphNodeDestroyer = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeReferenceable = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
_ GraphNodeDestroyerCBD = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeReferencer = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
_ GraphNodeReferenceable = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeEvalable = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
_ GraphNodeReferencer = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeProviderConsumer = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
_ GraphNodeEvalable = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
||||||
_ GraphNodeProvisionerConsumer = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
_ GraphNodeProviderConsumer = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
||||||
|
_ GraphNodeProvisionerConsumer = (*NodeDestroyDeposedResourceInstanceObject)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (n *NodeDestroyDeposedResourceInstanceObject) Name() string {
|
func (n *NodeDestroyDeposedResourceInstanceObject) Name() string {
|
||||||
return fmt.Sprintf("%s (destroy deposed %s)", n.Addr.String(), n.DeposedKey)
|
return fmt.Sprintf("%s (destroy deposed %s)", n.Addr.String(), n.DeposedKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *NodeDestroyDeposedResourceInstanceObject) DeposedInstanceObjectKey() states.DeposedKey {
|
||||||
|
return n.DeposedKey
|
||||||
|
}
|
||||||
|
|
||||||
// GraphNodeReferenceable implementation, overriding the one from NodeAbstractResourceInstance
|
// GraphNodeReferenceable implementation, overriding the one from NodeAbstractResourceInstance
|
||||||
func (n *NodeDestroyDeposedResourceInstanceObject) ReferenceableAddrs() []addrs.Referenceable {
|
func (n *NodeDestroyDeposedResourceInstanceObject) ReferenceableAddrs() []addrs.Referenceable {
|
||||||
// Deposed objects don't participate in references.
|
// Deposed objects don't participate in references.
|
||||||
|
|
|
@ -11,10 +11,16 @@ import (
|
||||||
// it is ready to be planned in order to create a diff.
|
// it is ready to be planned in order to create a diff.
|
||||||
type NodePlannableResource struct {
|
type NodePlannableResource struct {
|
||||||
*NodeAbstractResource
|
*NodeAbstractResource
|
||||||
|
|
||||||
|
// ForceCreateBeforeDestroy might be set via our GraphNodeDestroyerCBD
|
||||||
|
// during graph construction, if dependencies require us to force this
|
||||||
|
// on regardless of what the configuration says.
|
||||||
|
ForceCreateBeforeDestroy *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ GraphNodeSubPath = (*NodePlannableResource)(nil)
|
_ GraphNodeSubPath = (*NodePlannableResource)(nil)
|
||||||
|
_ GraphNodeDestroyerCBD = (*NodePlannableResource)(nil)
|
||||||
_ GraphNodeDynamicExpandable = (*NodePlannableResource)(nil)
|
_ GraphNodeDynamicExpandable = (*NodePlannableResource)(nil)
|
||||||
_ GraphNodeReferenceable = (*NodePlannableResource)(nil)
|
_ GraphNodeReferenceable = (*NodePlannableResource)(nil)
|
||||||
_ GraphNodeReferencer = (*NodePlannableResource)(nil)
|
_ GraphNodeReferencer = (*NodePlannableResource)(nil)
|
||||||
|
@ -41,6 +47,26 @@ func (n *NodePlannableResource) EvalTree() EvalNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GraphNodeDestroyerCBD
|
||||||
|
func (n *NodePlannableResource) CreateBeforeDestroy() bool {
|
||||||
|
if n.ForceCreateBeforeDestroy != nil {
|
||||||
|
return *n.ForceCreateBeforeDestroy
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have no config, we just assume no
|
||||||
|
if n.Config == nil || n.Config.Managed == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return n.Config.Managed.CreateBeforeDestroy
|
||||||
|
}
|
||||||
|
|
||||||
|
// GraphNodeDestroyerCBD
|
||||||
|
func (n *NodePlannableResource) ModifyCreateBeforeDestroy(v bool) error {
|
||||||
|
n.ForceCreateBeforeDestroy = &v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GraphNodeDynamicExpandable
|
// GraphNodeDynamicExpandable
|
||||||
func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
||||||
var diags tfdiags.Diagnostics
|
var diags tfdiags.Diagnostics
|
||||||
|
@ -70,6 +96,11 @@ func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
||||||
|
|
||||||
return &NodePlannableResourceInstance{
|
return &NodePlannableResourceInstance{
|
||||||
NodeAbstractResourceInstance: a,
|
NodeAbstractResourceInstance: a,
|
||||||
|
|
||||||
|
// By the time we're walking, we've figured out whether we need
|
||||||
|
// to force on CreateBeforeDestroy due to dependencies on other
|
||||||
|
// nodes that have it.
|
||||||
|
ForceCreateBeforeDestroy: n.CreateBeforeDestroy(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
// count index, for example.
|
// count index, for example.
|
||||||
type NodePlannableResourceInstance struct {
|
type NodePlannableResourceInstance struct {
|
||||||
*NodeAbstractResourceInstance
|
*NodeAbstractResourceInstance
|
||||||
|
ForceCreateBeforeDestroy bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -137,14 +138,15 @@ func (n *NodePlannableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe
|
||||||
},
|
},
|
||||||
|
|
||||||
&EvalDiff{
|
&EvalDiff{
|
||||||
Addr: addr.Resource,
|
Addr: addr.Resource,
|
||||||
Config: n.Config,
|
Config: n.Config,
|
||||||
Provider: &provider,
|
CreateBeforeDestroy: n.ForceCreateBeforeDestroy,
|
||||||
ProviderAddr: n.ResolvedProvider,
|
Provider: &provider,
|
||||||
ProviderSchema: &providerSchema,
|
ProviderAddr: n.ResolvedProvider,
|
||||||
State: &state,
|
ProviderSchema: &providerSchema,
|
||||||
OutputChange: &change,
|
State: &state,
|
||||||
OutputState: &state,
|
OutputChange: &change,
|
||||||
|
OutputState: &state,
|
||||||
},
|
},
|
||||||
&EvalCheckPreventDestroy{
|
&EvalCheckPreventDestroy{
|
||||||
Addr: addr.Resource,
|
Addr: addr.Resource,
|
||||||
|
|
|
@ -10,10 +10,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// GraphNodeDestroyerCBD must be implemented by nodes that might be
|
// GraphNodeDestroyerCBD must be implemented by nodes that might be
|
||||||
// create-before-destroy destroyers.
|
// create-before-destroy destroyers, or might plan a create-before-destroy
|
||||||
|
// action.
|
||||||
type GraphNodeDestroyerCBD interface {
|
type GraphNodeDestroyerCBD interface {
|
||||||
GraphNodeDestroyer
|
|
||||||
|
|
||||||
// CreateBeforeDestroy returns true if this node represents a node
|
// CreateBeforeDestroy returns true if this node represents a node
|
||||||
// that is doing a CBD.
|
// that is doing a CBD.
|
||||||
CreateBeforeDestroy() bool
|
CreateBeforeDestroy() bool
|
||||||
|
@ -38,6 +37,75 @@ type GraphNodeAttachDestroyer interface {
|
||||||
AttachDestroyNode(n GraphNodeDestroyerCBD)
|
AttachDestroyNode(n GraphNodeDestroyerCBD)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForcedCBDTransformer detects when a particular CBD-able graph node has
|
||||||
|
// dependencies with another that has create_before_destroy set that require
|
||||||
|
// it to be forced on, and forces it on.
|
||||||
|
//
|
||||||
|
// This must be used in the plan graph builder to ensure that
|
||||||
|
// create_before_destroy settings are properly propagated before constructing
|
||||||
|
// the planned changes. This requires that the plannable resource nodes
|
||||||
|
// implement GraphNodeDestroyerCBD.
|
||||||
|
type ForcedCBDTransformer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ForcedCBDTransformer) Transform(g *Graph) error {
|
||||||
|
for _, v := range g.Vertices() {
|
||||||
|
dn, ok := v.(GraphNodeDestroyerCBD)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !dn.CreateBeforeDestroy() {
|
||||||
|
// If there are no CBD decendent (dependent nodes), then we
|
||||||
|
// do nothing here.
|
||||||
|
if !t.hasCBDDescendent(g, v) {
|
||||||
|
log.Printf("[TRACE] ForcedCBDTransformer: %q (%T) has no CBD ancestors, so skipping", dag.VertexName(v), v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this isn't naturally a CBD node, this means that an ancestor is
|
||||||
|
// and we need to auto-upgrade this node to CBD. We do this because
|
||||||
|
// a CBD node depending on non-CBD will result in cycles. To avoid this,
|
||||||
|
// we always attempt to upgrade it.
|
||||||
|
log.Printf("[TRACE] ForcedCBDTransformer: forcing create_before_destroy on for %q (%T)", dag.VertexName(v), v)
|
||||||
|
if err := dn.ModifyCreateBeforeDestroy(true); err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"%s: must have create before destroy enabled because "+
|
||||||
|
"a dependent resource has CBD enabled. However, when "+
|
||||||
|
"attempting to automatically do this, an error occurred: %s",
|
||||||
|
dag.VertexName(v), err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("[TRACE] ForcedCBDTransformer: %q (%T) already has create_before_destroy set", dag.VertexName(v), v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasCBDAncestor returns true if any ancestor (node that depends on this)
|
||||||
|
// has CBD set.
|
||||||
|
func (t *ForcedCBDTransformer) hasCBDDescendent(g *Graph, v dag.Vertex) bool {
|
||||||
|
s, _ := g.Descendents(v)
|
||||||
|
if s == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ov := range s.List() {
|
||||||
|
dn, ok := ov.(GraphNodeDestroyerCBD)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if dn.CreateBeforeDestroy() {
|
||||||
|
// some descendent is CreateBeforeDestroy, so we need to follow suit
|
||||||
|
log.Printf("[TRACE] ForcedCBDTransformer: %q has CBD descendent %q", dag.VertexName(v), dag.VertexName(ov))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// CBDEdgeTransformer modifies the edges of CBD nodes that went through
|
// CBDEdgeTransformer modifies the edges of CBD nodes that went through
|
||||||
// the DestroyEdgeTransformer to have the right dependencies. There are
|
// the DestroyEdgeTransformer to have the right dependencies. There are
|
||||||
// two real tasks here:
|
// two real tasks here:
|
||||||
|
@ -50,6 +118,12 @@ type GraphNodeAttachDestroyer interface {
|
||||||
// update to A. Example: adding a web server updates the load balancer
|
// update to A. Example: adding a web server updates the load balancer
|
||||||
// before deleting the old web server.
|
// before deleting the old web server.
|
||||||
//
|
//
|
||||||
|
// This transformer requires that a previous transformer has already forced
|
||||||
|
// create_before_destroy on for nodes that are depended on by explicit CBD
|
||||||
|
// nodes. This is the logic in ForcedCBDTransformer, though in practice we
|
||||||
|
// will get here by recording the CBD-ness of each change in the plan during
|
||||||
|
// the plan walk and then forcing the nodes into the appropriate setting during
|
||||||
|
// DiffTransformer when building the apply graph.
|
||||||
type CBDEdgeTransformer struct {
|
type CBDEdgeTransformer struct {
|
||||||
// Module and State are only needed to look up dependencies in
|
// Module and State are only needed to look up dependencies in
|
||||||
// any way possible. Either can be nil if not availabile.
|
// any way possible. Either can be nil if not availabile.
|
||||||
|
@ -70,26 +144,13 @@ func (t *CBDEdgeTransformer) Transform(g *Graph) error {
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
dern, ok := v.(GraphNodeDestroyer)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if !dn.CreateBeforeDestroy() {
|
if !dn.CreateBeforeDestroy() {
|
||||||
// If there are no CBD ancestors (dependent nodes), then we
|
continue
|
||||||
// do nothing here.
|
|
||||||
if !t.hasCBDAncestor(g, v) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this isn't naturally a CBD node, this means that an ancestor is
|
|
||||||
// and we need to auto-upgrade this node to CBD. We do this because
|
|
||||||
// a CBD node depending on non-CBD will result in cycles. To avoid this,
|
|
||||||
// we always attempt to upgrade it.
|
|
||||||
log.Printf("[TRACE] CBDEdgeTransformer: forcing create_before_destroy on for %q (%T)", dag.VertexName(v), v)
|
|
||||||
if err := dn.ModifyCreateBeforeDestroy(true); err != nil {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"%s: must have create before destroy enabled because "+
|
|
||||||
"a dependent resource has CBD enabled. However, when "+
|
|
||||||
"attempting to automatically do this, an error occurred: %s",
|
|
||||||
dag.VertexName(v), err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the destroy edge. There should only be one.
|
// Find the destroy edge. There should only be one.
|
||||||
|
@ -105,7 +166,9 @@ func (t *CBDEdgeTransformer) Transform(g *Graph) error {
|
||||||
|
|
||||||
// Found it! Invert.
|
// Found it! Invert.
|
||||||
g.RemoveEdge(de)
|
g.RemoveEdge(de)
|
||||||
g.Connect(&DestroyEdge{S: de.Target(), T: de.Source()})
|
applyNode := de.Source()
|
||||||
|
destroyNode := de.Target()
|
||||||
|
g.Connect(&DestroyEdge{S: destroyNode, T: applyNode})
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the address has an index, we strip that. Our depMap creation
|
// If the address has an index, we strip that. Our depMap creation
|
||||||
|
@ -113,7 +176,7 @@ func (t *CBDEdgeTransformer) Transform(g *Graph) error {
|
||||||
// dependencies. One day when we limit dependencies more exactly
|
// dependencies. One day when we limit dependencies more exactly
|
||||||
// this will have to change. We have a test case covering this
|
// this will have to change. We have a test case covering this
|
||||||
// (depNonCBDCountBoth) so it'll be caught.
|
// (depNonCBDCountBoth) so it'll be caught.
|
||||||
addr := dn.DestroyAddr()
|
addr := dern.DestroyAddr()
|
||||||
key := addr.ContainingResource().String()
|
key := addr.ContainingResource().String()
|
||||||
|
|
||||||
// Add this to the list of nodes that we need to fix up
|
// Add this to the list of nodes that we need to fix up
|
||||||
|
@ -243,26 +306,3 @@ func (t *CBDEdgeTransformer) depMap(destroyMap map[string][]dag.Vertex) (map[str
|
||||||
|
|
||||||
return depMap, nil
|
return depMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasCBDAncestor returns true if any ancestor (node that depends on this)
|
|
||||||
// has CBD set.
|
|
||||||
func (t *CBDEdgeTransformer) hasCBDAncestor(g *Graph, v dag.Vertex) bool {
|
|
||||||
s, _ := g.Ancestors(v)
|
|
||||||
if s == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range s.List() {
|
|
||||||
dn, ok := v.(GraphNodeDestroyerCBD)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if dn.CreateBeforeDestroy() {
|
|
||||||
// some ancestor is CreateBeforeDestroy, so we need to follow suit
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/configs"
|
|
||||||
"github.com/hashicorp/terraform/dag"
|
"github.com/hashicorp/terraform/dag"
|
||||||
"github.com/hashicorp/terraform/plans"
|
"github.com/hashicorp/terraform/plans"
|
||||||
"github.com/hashicorp/terraform/states"
|
"github.com/hashicorp/terraform/states"
|
||||||
|
@ -15,7 +14,6 @@ import (
|
||||||
// each of the resource changes described in the given Changes object.
|
// each of the resource changes described in the given Changes object.
|
||||||
type DiffTransformer struct {
|
type DiffTransformer struct {
|
||||||
Concrete ConcreteResourceInstanceNodeFunc
|
Concrete ConcreteResourceInstanceNodeFunc
|
||||||
Config *configs.Config
|
|
||||||
State *states.State
|
State *states.State
|
||||||
Changes *plans.Changes
|
Changes *plans.Changes
|
||||||
}
|
}
|
||||||
|
@ -30,7 +28,6 @@ func (t *DiffTransformer) Transform(g *Graph) error {
|
||||||
log.Printf("[TRACE] DiffTransformer starting")
|
log.Printf("[TRACE] DiffTransformer starting")
|
||||||
|
|
||||||
var diags tfdiags.Diagnostics
|
var diags tfdiags.Diagnostics
|
||||||
config := t.Config
|
|
||||||
state := t.State
|
state := t.State
|
||||||
changes := t.Changes
|
changes := t.Changes
|
||||||
|
|
||||||
|
@ -59,15 +56,9 @@ func (t *DiffTransformer) Transform(g *Graph) error {
|
||||||
for _, rc := range changes.Resources {
|
for _, rc := range changes.Resources {
|
||||||
addr := rc.Addr
|
addr := rc.Addr
|
||||||
dk := rc.DeposedKey
|
dk := rc.DeposedKey
|
||||||
var rCfg *configs.Resource
|
|
||||||
|
|
||||||
log.Printf("[TRACE] DiffTransformer: found %s change for %s %s", rc.Action, addr, dk)
|
log.Printf("[TRACE] DiffTransformer: found %s change for %s %s", rc.Action, addr, dk)
|
||||||
|
|
||||||
modCfg := config.DescendentForInstance(addr.Module)
|
|
||||||
if modCfg != nil {
|
|
||||||
rCfg = modCfg.Module.ResourceByAddr(addr.Resource.Resource)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Depending on the action we'll need some different combinations of
|
// Depending on the action we'll need some different combinations of
|
||||||
// nodes, because destroying uses a special node type separate from
|
// nodes, because destroying uses a special node type separate from
|
||||||
// other actions.
|
// other actions.
|
||||||
|
@ -77,9 +68,10 @@ func (t *DiffTransformer) Transform(g *Graph) error {
|
||||||
continue
|
continue
|
||||||
case plans.Delete:
|
case plans.Delete:
|
||||||
delete = true
|
delete = true
|
||||||
case plans.Replace:
|
case plans.DeleteThenCreate, plans.CreateThenDelete:
|
||||||
update = true
|
update = true
|
||||||
delete = true
|
delete = true
|
||||||
|
createBeforeDestroy = (rc.Action == plans.CreateThenDelete)
|
||||||
default:
|
default:
|
||||||
update = true
|
update = true
|
||||||
}
|
}
|
||||||
|
@ -93,10 +85,6 @@ func (t *DiffTransformer) Transform(g *Graph) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if rCfg != nil && rCfg.Managed != nil && rCfg.Managed.CreateBeforeDestroy {
|
|
||||||
createBeforeDestroy = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're going to do a create_before_destroy Replace operation then
|
// If we're going to do a create_before_destroy Replace operation then
|
||||||
// we need to allocate a DeposedKey to use to retain the
|
// we need to allocate a DeposedKey to use to retain the
|
||||||
// not-yet-destroyed prior object, so that the delete node can destroy
|
// not-yet-destroyed prior object, so that the delete node can destroy
|
||||||
|
@ -173,6 +161,7 @@ func (t *DiffTransformer) Transform(g *Graph) error {
|
||||||
NodeAbstractResourceInstance: abstract,
|
NodeAbstractResourceInstance: abstract,
|
||||||
DeposedKey: dk,
|
DeposedKey: dk,
|
||||||
}
|
}
|
||||||
|
node.(*NodeDestroyResourceInstance).ModifyCreateBeforeDestroy(createBeforeDestroy)
|
||||||
} else {
|
} else {
|
||||||
node = &NodeDestroyDeposedResourceInstanceObject{
|
node = &NodeDestroyDeposedResourceInstanceObject{
|
||||||
NodeAbstractResourceInstance: abstract,
|
NodeAbstractResourceInstance: abstract,
|
||||||
|
|
Loading…
Reference in New Issue