statemove

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 11, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func Cleanup

func Cleanup(root, key string) (int, error)

Cleanup removes shim files matching key; an empty key removes ALL shims. Returns the number of files removed.

func RenderShim

func RenderShim(key string, ops []Op) string

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

func RenderXMove(key string, xm XMove) string

RenderXMove renders the HCL manifest (key in a header comment + an xmove block).

func ShimFileName

func ShimFileName(key string) string

ShimFileName is the colocated shim filename for a key, e.g. "_tfsp_move.PR-123.tf".

func ValidateMove

func ValidateMove(plan *tfjson.Plan, from, to string) error

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

func XMoveFileName(key string) string

XMoveFileName is the manifest filename for a key.

Types

type Action

type Action struct {
	From, To string
	Decision Decision
}

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 Decision

type Decision int

Decision is the per-move runtime action derived from the two live states.

const (
	DecisionMove Decision = iota // source has it, dest doesn't → move
	DecisionSkip                 // dest already has it → idempotent skip
)

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.

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

type Move struct {
	From string
	To   string
}

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

func CrossStackPairs(src, dst *tfjson.Plan, from, to string) ([]Move, error)

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

type Op struct {
	Kind string
	From string
	To   string
	ID   string
}

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

func ClassifyCrossStack(src, dst *tfjson.Plan, from, to string) (srcOps, dstOps []Op, err error)

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.

func MergeOps

func MergeOps(existing, add []Op) []Op

MergeOps appends add to existing, de-duplicating whole ops, preserving order.

func ParseShim

func ParseShim(content string) (key string, ops []Op, err error)

ParseShim reads a shim's header back into key + ops. Errors if not a tfstackplan shim.

type Runner

type Runner interface {
	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

func NewTerraform(execPath, workingDir string) (Runner, error)

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.

func Discover

func Discover(root string) ([]Shim, error)

Discover walks root for `_tfsp_move.*.tf` shim files and parses each.

type XMove

type XMove struct {
	SourceStack string
	Pairs       []Move
}

XMove is a cross-state move manifest, colocated in the DESTINATION stack: pull the Pairs' source addresses out of SourceStack's state and into this stack's.

func ParseXMove

func ParseXMove(content string) (key string, xm XMove, err error)

ParseXMove parses the manifest content into its key + XMove.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL