mirror of
https://github.com/hashicorp/terraform.git
synced 2026-02-18 18:29:44 -05:00
97 lines
3.1 KiB
Go
97 lines
3.1 KiB
Go
// Copyright IBM Corp. 2014, 2026
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package addrs
|
|
|
|
import (
|
|
"github.com/hashicorp/hcl/v2"
|
|
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
)
|
|
|
|
// Like MoveEndpoint, RemoveTarget is a wrapping struct that captures the result
|
|
// of decoding an HCL traversal representing a relative path from the current
|
|
// module to a removeable object.
|
|
//
|
|
// Remove targets are somewhat simpler than move endpoints, in that they deal
|
|
// only with resources and modules defined in configuration, not instances of
|
|
// those objects as recorded in state. We are therefore able to determine the
|
|
// ConfigMoveable up front, since specifying any resource or module instance key
|
|
// in a removed block is invalid.
|
|
//
|
|
// An interesting quirk of RemoveTarget is that RelSubject denotes a
|
|
// configuration object that, if the removed block is valid, should no longer
|
|
// exist in configuration. This "last known address" is used to locate and delete
|
|
// the appropriate state objects, or, in the case in which the user has forgotten
|
|
// to remove the object from configuration, to report the address of that block
|
|
// in an error diagnostic.
|
|
type RemoveTarget struct {
|
|
// SourceRange is the location of the target address in configuration.
|
|
SourceRange tfdiags.SourceRange
|
|
|
|
// RelSubject, like MoveEndpoint's relSubject, abuses an absolute address
|
|
// type to represent a relative address.
|
|
RelSubject ConfigMoveable
|
|
}
|
|
|
|
func (t *RemoveTarget) ObjectKind() RemoveTargetKind {
|
|
return removeTargetKind(t.RelSubject)
|
|
}
|
|
|
|
func (t *RemoveTarget) String() string {
|
|
if t.ObjectKind() == RemoveTargetModule {
|
|
return t.RelSubject.(Module).String()
|
|
} else if t.ObjectKind() == RemoveTargetResource {
|
|
return t.RelSubject.(ConfigResource).String()
|
|
}
|
|
// No other valid address types
|
|
panic("Usupported remove target kind")
|
|
}
|
|
|
|
func (t *RemoveTarget) Equal(other *RemoveTarget) bool {
|
|
switch {
|
|
case (t == nil) != (other == nil):
|
|
return false
|
|
case t == nil:
|
|
return true
|
|
default:
|
|
// We can safely compare string representations, since the Subject is a
|
|
// simple module or resource address.
|
|
return t.String() == other.String() && t.SourceRange == other.SourceRange
|
|
}
|
|
}
|
|
|
|
func ParseRemoveTarget(traversal hcl.Traversal) (*RemoveTarget, tfdiags.Diagnostics) {
|
|
path, remain, diags := parseModulePrefix(traversal)
|
|
if diags.HasErrors() {
|
|
return nil, diags
|
|
}
|
|
|
|
rng := tfdiags.SourceRangeFromHCL(traversal.SourceRange())
|
|
|
|
if len(remain) == 0 {
|
|
return &RemoveTarget{
|
|
RelSubject: path,
|
|
SourceRange: rng,
|
|
}, diags
|
|
}
|
|
|
|
rAddr, moreDiags := parseConfigResourceUnderModule(path, remain)
|
|
diags = diags.Append(moreDiags)
|
|
if diags.HasErrors() {
|
|
return nil, diags
|
|
}
|
|
|
|
if rAddr.Resource.Mode == DataResourceMode {
|
|
diags = diags.Append(&hcl.Diagnostic{
|
|
Severity: hcl.DiagError,
|
|
Summary: "Data source address not allowed",
|
|
Detail: "Data sources are never destroyed, so they are not valid targets of removed blocks. To remove the data source from state, remove the data source block from configuration.",
|
|
Subject: rng.ToHCL().Ptr(),
|
|
})
|
|
}
|
|
|
|
return &RemoveTarget{
|
|
RelSubject: rAddr,
|
|
SourceRange: rng,
|
|
}, diags
|
|
}
|