Documentation
¶
Overview ¶
Package statemove validates declared Terraform resource moves against plan data and generates/maintains the native `moved {}` shim files that effect them (SP1: within one stack). It consumes tfplan.json — it does not run terraform.
Index ¶
- func CheckXMoveSource(src *tfjson.Plan, from string) error
- func Cleanup(root, key string) (int, error)
- func CleanupXMoves(root, key string) (int, error)
- func DataSourceOrphans(pairs []Move, dataSources []string) []string
- func IsSpent(pairs []Move, dstPriorAddrs AddressSet) bool
- func PriorStateDataSources(planJSON []byte) []string
- func RenderShim(key string, ops []Op) string
- func RenderXMove(key string, xm XMove) string
- func ShimFileName(key string) string
- func ValidateMove(plan *tfjson.Plan, from, to string) error
- func XMoveFileName(key string) string
- type Action
- type AddressSet
- type Decision
- type DestProviders
- type Diagnostic
- type ExecDeps
- type FoundXMove
- type Locker
- type Move
- type Op
- type Runner
- type Severity
- type Shim
- type XMove
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CheckXMoveSource ¶ added in v0.18.6
CheckXMoveSource verifies that src has a prior_state containing at least one resource under from. Returns an error when prior_state is absent (source stack has no state — nothing to move) or when nothing under from is found (wrong address prefix or wrong stack).
func Cleanup ¶
Cleanup removes same-state shim files (_tfsp_move.*.tf) matching key; an empty key removes ALL shims. It matches by FILENAME and does not parse, so a corrupt or key-mismatched shim (which Discover rejects) is still removable. Returns the number of files removed.
func CleanupXMoves ¶ added in v0.9.7
CleanupXMoves removes cross-state xmove manifests (_tfsp_xmove.*.hcl) matching key; an empty key removes ALL. Like Cleanup it matches by filename and does not parse. Returns the number removed.
func DataSourceOrphans ¶ added in v0.19.0
DataSourceOrphans returns the data-source addresses from dataSources that fall under any declared pair's From prefix. These remain in the source stack after the move because stateAddresses filters data sources out of the move set — the operator may need to forget them (terraform state rm) before the source stack can be retired.
func IsSpent ¶ added in v0.19.0
func IsSpent(pairs []Move, dstPriorAddrs AddressSet) bool
IsSpent reports whether all declared moves have already been applied: every pair's To-prefix has at least one address present in dstPriorAddrs. Returns false when dstPriorAddrs is empty (indeterminate) or pairs is empty.
func PriorStateDataSources ¶ added in v0.19.0
PriorStateDataSources parses prior_state from a raw Terraform plan JSON and returns the addresses of data sources (Mode==data). These are excluded from stateAddresses but may be stranded in the source stack after a move if they fall under the declared From prefix — use DataSourceOrphans to find them. Returns nil when there is no prior_state or the JSON is unparseable.
func RenderShim ¶
RenderShim renders a PR-keyed shim: a machine-readable header (banner, key, one tab-separated op line each) followed by the native Terraform blocks. The header is the source of truth for list/maintenance.
func RenderXMove ¶
RenderXMove renders the HCL manifest (key in a header comment + an xmove block).
func ShimFileName ¶
ShimFileName is the colocated shim filename for a key, e.g. "_tfsp_move.PR-123.tf".
func ValidateMove ¶
ValidateMove fail-closes unless the plan shows a clean relocation from→to: every resource being destroyed under `from` has a created counterpart under `to` at the rewritten address with the same type, and vice versa (no unmatched creates under `to`). Works for a single resource (exact match), a whole module (prefix), and count/for_each (bracketed) forms.
func XMoveFileName ¶
XMoveFileName is the manifest filename for a key.
Types ¶
type Action ¶
Action is what Execute did/would do for one pair.
func Execute ¶
func Execute(ctx context.Context, deps ExecDeps, root, destStack string, xm XMove, dryRun bool) ([]Action, error)
Execute performs one xmove (dest = root/destStack, source = root/xm.SourceStack): pull both states → backup → decide per pair → (unless dryRun) state mv the to-move pairs on local files and push both (never --force). Fail-closed: any error aborts before pushing.
type AddressSet ¶ added in v0.18.2
AddressSet maps resource addresses to their corresponding ProviderName.
func PriorStateAddrs ¶ added in v0.18.5
func PriorStateAddrs(planJSON []byte) AddressSet
PriorStateAddrs parses prior_state from a raw Terraform plan JSON document and returns an AddressSet mapping every resource address to its provider name. Returns nil when the JSON is unparseable or the plan has no prior_state.
The prior_state is the raw Terraform state before the plan ran — the same addresses that apply-time xmove validation will see in the live state. Using this instead of ResourceChanges for source address validation prevents module-level moved{} blocks from causing a plan/apply split: those blocks rename resources inside ResourceChanges (e.g. module.foo → module.foo[0]) without setting per-resource PreviousAddress, so the plan shows post-rename addresses while the live state still holds the originals.
Parsing bypasses tfjson.Plan/State.Validate() (which requires FormatVersion) so that this function works on both real plan JSON and test fixtures.
type Decision ¶
type Decision int
Decision is the per-move runtime action derived from the two live states.
type DestProviders ¶ added in v0.18.2
DestProviders represents a set of destination providers.
func DiscoverDestProviders ¶ added in v0.18.2
func DiscoverDestProviders(stackDir string) DestProviders
DiscoverDestProviders scans a stack directory for defined providers in HCL config.
type Diagnostic ¶ added in v0.18.2
func ValidateMovePlan ¶ added in v0.18.2
func ValidateMovePlan(src, dst, dstPrior AddressSet, providers DestProviders, m XMove, isApply bool) []Diagnostic
ValidateMovePlan validates a cross-state move manifest against source and destination AddressSets and configured providers.
dstPrior is the destination stack's prior_state address set, used only at plan time (isApply=false) to tell a spent manifest entry from a stale one: a source address absent from the source plan whose To-address is already in dstPrior was moved by an earlier apply — warning (xmove/spent), not error. Apply-time callers validate against live states (dst *is* the prior state) and may pass nil.
type ExecDeps ¶
type ExecDeps struct {
NewTF func(workingDir string) (Runner, error) // builds a Runner rooted at a stack dir
BackupDir string // pre-move state backups (empty disables)
Locker Locker // optional pessimistic lock around the move (nil = none)
}
ExecDeps injects the terraform factory + a backup dir.
type FoundXMove ¶
type FoundXMove struct {
Path string
DestStack string // dir relative to root (slash form)
Key string
XMove XMove
}
FoundXMove is a discovered manifest with its location.
func DiscoverXMoves ¶
func DiscoverXMoves(root string) ([]FoundXMove, error)
DiscoverXMoves walks root for `_tfsp_xmove.*.hcl` manifests. It is fail-closed: a file in our reserved namespace that won't parse, or whose header key disagrees with its filename, returns an error (the filename is authoritative). Use CleanupXMoves to remove such a file.
type Locker ¶
type Locker interface {
Acquire(ctx context.Context, stackDir string) (release func() error, err error)
}
Locker is an optional pessimistic lock acquired before the pull→mv→push window so a concurrent terraform op on the same state fails to lock (rather than the move failing mid-flight). Acquire returns a release func; an error means the state is already locked and the move must NOT proceed.
type Move ¶
Move is one declared relocation, from one address to another (same stack in SP1). Addresses are opaque Terraform addresses (resource, module, or with count/for_each brackets).
func CrossStackPairs ¶
CrossStackPairs validates a cross-stack move and returns the matched from→to address pairs (fail-closed; same rules as ClassifyCrossStack minus the import id). Used by the `state mv` path, which is address-based and needs no id.
type Op ¶
Op is one operation in a shim file. Kind is "moved" (From→To, same state), "import" (To + ID, adopt into this state), or "removed" (From, drop from this state without destroying). Addresses/ids never contain a tab, so the header encodes ops tab-separated.
func ClassifyCrossStack ¶
ClassifyCrossStack validates a cross-stack move from `from` (in src's plan) to `to` (in dst's plan) and returns the ops to write: `removed` ops in the source shim and `import` ops (id from src's before.id) in the destination shim. Fail- closed: every resource destroyed under `from` must be created under `to` at the rewritten address with the same type and a usable import id, and every create under `to` must have a destroyed counterpart.
type Runner ¶
type Runner interface {
Init(ctx context.Context, opts ...tfexec.InitOption) error
StatePull(ctx context.Context, opts ...tfexec.StatePullOption) (string, error)
StatePush(ctx context.Context, path string, opts ...tfexec.StatePushCmdOption) error
ShowStateFile(ctx context.Context, statePath string, opts ...tfexec.ShowOption) (*tfjson.State, error)
StateMv(ctx context.Context, source, destination string, opts ...tfexec.StateMvCmdOption) error
}
Runner is the subset of *tfexec.Terraform the executor needs (so tests can fake it without a binary).
func NewTerraform ¶
NewTerraform builds the real Runner for a stack dir.
type Shim ¶
type Shim struct {
Path string // path to the .tf
Stack string // dir containing it, relative to the discover root (slash form)
Key string
Ops []Op
}
Shim is a discovered shim file.