lifecyclemutation

package
v0.41.0 Latest Latest
Warning

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

Go to latest
Published: Sep 24, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package lifecyclemutation owns the one local cross-process mutation authority shared by StackSpec authoring, generation, Apply, drift reconcile, and upgrade recovery.

Index

Constants

View Source
const (
	APIVersion = "stackkit.lifecycle-mutation/v1"

	StatusActive    = "active"
	StatusSucceeded = "succeeded"
	StatusRecovered = "recovered"

	KindUpgrade           = "upgrade"
	KindRestoreActivation = "restore-activation"

	PhasePrepared                = "prepared"
	PhaseTargetGenerateStarted   = "target-generate-started"
	PhaseTargetGenerateSucceeded = "target-generate-succeeded"
	PhaseTargetApplyStarted      = "target-apply-started"
	PhaseTargetApplySucceeded    = "target-apply-succeeded"
	PhaseTargetVerifyStarted     = "target-verify-started"
	PhaseTargetVerifySucceeded   = "target-verify-succeeded"
	PhaseCommitStarted           = "commit-started"
	PhaseCommitSucceeded         = "commit-succeeded"
	PhaseRollbackStarted         = "rollback-started"
	PhaseRollbackGenerateStarted = "rollback-generate-started"
	PhaseRollbackGenerateDone    = "rollback-generate-succeeded"
	PhaseRollbackApplyStarted    = "rollback-apply-started"
	PhaseRollbackApplyDone       = "rollback-apply-succeeded"
	PhaseRollbackVerifyStarted   = "rollback-verify-started"
	PhaseRollbackVerifyDone      = "rollback-verify-succeeded"
	PhaseRollbackSucceeded       = "rollback-succeeded"

	PhaseQuiesceStarted                  = "quiesce-started"
	PhaseQuiesced                        = "quiesced"
	PhaseRollbackCopyStarted             = "rollback-copy-started"
	PhaseRollbackCopySucceeded           = "rollback-copy-succeeded"
	PhaseRollbackReady                   = "rollback-ready"
	PhaseActivationCopyStarted           = "activation-copy-started"
	PhaseActivationCopySucceeded         = "activation-copy-succeeded"
	PhaseActivationSucceeded             = "activation-succeeded"
	PhaseRuntimeStartStarted             = "runtime-start-started"
	PhaseRuntimeStartSucceeded           = "runtime-start-succeeded"
	PhaseVerifyStarted                   = "verify-started"
	PhaseVerifySucceeded                 = "verify-succeeded"
	PhaseRollbackVolumeStarted           = "rollback-volume-started"
	PhaseRollbackVolumeSucceeded         = "rollback-volume-succeeded"
	PhaseRollbackRuntimeStarted          = "rollback-runtime-started"
	PhaseRollbackRuntimeSucceeded        = "rollback-runtime-succeeded"
	PhaseRollbackActivationVerifyStarted = "rollback-verify-started"
	PhaseRollbackActivationVerifyDone    = "rollback-verify-succeeded"
)
View Source
const (
	// Upgrade data activation phases are deliberately outside the old
	// generate/apply/verify join phases. A prior executor cannot be admitted
	// while the current controller is copying data back into live volumes.
	PhaseRollbackDataQuiesceStarted          = "rollback-data-quiesce-started"
	PhaseRollbackDataQuiesced                = "rollback-data-quiesced"
	PhaseRollbackDataCopyStarted             = "rollback-data-copy-started"
	PhaseRollbackDataCopySucceeded           = "rollback-data-copy-succeeded"
	PhaseRollbackDataActivationSucceeded     = "rollback-data-activation-succeeded"
	PhaseRollbackPriorRuntimeStartStarted    = "rollback-prior-runtime-start-started"
	PhaseRollbackPriorRuntimeStartSucceeded  = "rollback-prior-runtime-start-succeeded"
	PhaseRollbackPriorRuntimeVerifyStarted   = "rollback-prior-runtime-verify-started"
	PhaseRollbackPriorRuntimeVerifySucceeded = "rollback-prior-runtime-verify-succeeded"
)

Variables

View Source
var ErrUpgradeDataActivationRequired = errors.New("lifecycle mutation: prior-runtime rollback requires verified live data activation after target Apply or an ambiguous recovery phase")

ErrUpgradeDataActivationRequired prevents a prior runtime from opening data that a newer runtime may already have changed. Isolated backup staging alone is not proof that the live data belongs to the prior runtime.

Functions

func AdmitJoin

func AdmitJoin(workspace string, request JoinRequest) error

AdmitJoin validates and atomically consumes the exact one-use child nonce.

func CurrentExecutableSHA256

func CurrentExecutableSHA256() (string, error)

CurrentExecutableSHA256 hashes the bytes of the currently executing binary; hidden flags cannot supply or substitute this authority.

func InspectJoin

func InspectJoin(workspace string, request JoinRequest) error

InspectJoin validates a signed child admission without consuming its one-use nonce. It is safe for pre-observability admission only.

func InspectUpgradeTargetApplySnapshot

func InspectUpgradeTargetApplySnapshot(workspace string, request JoinRequest) (string, error)

InspectUpgradeTargetApplySnapshot exposes the signed pre-target checkpoint only to the exact admitted upgrade Apply child. The caller can use its original Compose definition to prove ownership of a running old listener after target Generate has replaced the active Compose file.

func OpenRecovery

func OpenRecovery(workspace, operationID string) (*Session, Record, error)

OpenRecovery acquires the shared lock and accepts only the exact active, signed operation. It never advances or resumes the target path.

func OpenRestoreActivationRecovery

func OpenRestoreActivationRecovery(
	workspace, operationID string,
) (*Session, Record, error)

func OpenUpgradeRecovery

func OpenUpgradeRecovery(workspace, operationID string) (*Session, Record, error)

func RecoveryContext

func RecoveryContext(parent context.Context) (context.Context, context.CancelFunc)

RecoveryContext gives an already authorized compensating operation its own bounded phase. Cancellation of the failed mutation must not also cancel its recovery. Callers must retain the mutation lock and verify recovery authority.

func RequireIdle

func RequireIdle(workspace string) error

func WithIdleMutation

func WithIdleMutation(
	workspace string,
	join JoinRequest,
	execute func() error,
) error

WithIdleMutation holds the same lock as an upgrade Session across the exact ordinary mutation boundary. A joined upgrade child is admitted from the signed parent journal and deliberately does not reacquire the parent's lock.

Types

type BeginRequest

type BeginRequest struct {
	OperationID string
	OwnerRef    string
	Checkpoint  CheckpointAuthority
	Target      ReleaseAuthority
	Prior       ReleaseAuthority
}

type CheckpointAuthority

type CheckpointAuthority struct {
	ExecutorStateSnapshotID string `json:"executorStateSnapshotId"`
	KopiaAnchorID           string `json:"kopiaAnchorId"`
}

type JoinAuthority

type JoinAuthority struct {
	Command          string `json:"command"`
	BinaryVersion    string `json:"binaryVersion"`
	ExecutableSHA256 string `json:"executableSha256"`
	NonceSHA256      string `json:"nonceSha256"`
}

type JoinRequest

type JoinRequest struct {
	OperationID      string
	Phase            string
	BinaryVersion    string
	ExecutableSHA256 string
	Nonce            string
	Command          string
}

type Record

type Record struct {
	APIVersion            string                                        `json:"apiVersion"`
	OperationID           string                                        `json:"operationId"`
	Kind                  string                                        `json:"kind"`
	WorkspaceHash         string                                        `json:"workspaceHash"`
	OwnerRef              string                                        `json:"ownerRef"`
	Status                string                                        `json:"status"`
	Phase                 string                                        `json:"phase"`
	Sequence              uint64                                        `json:"sequence"`
	PreviousRecordDigest  string                                        `json:"previousRecordDigest,omitempty"`
	Checkpoint            CheckpointAuthority                           `json:"checkpoint"`
	Target                ReleaseAuthority                              `json:"target"`
	Prior                 ReleaseAuthority                              `json:"prior"`
	RestoreActivation     *RestoreActivationState                       `json:"restoreActivation,omitempty"`
	UpgradeDataActivation *UpgradeDataActivationState                   `json:"upgradeDataActivation,omitempty"`
	Join                  *JoinAuthority                                `json:"join,omitempty"`
	UpdatedAt             time.Time                                     `json:"updatedAt"`
	Signature             localevidence.OwnerLifecycleMutationSignature `json:"signature"`
}

func (Record) RequirePreApplyUpgradeRollback

func (record Record) RequirePreApplyUpgradeRollback() error

RequirePreApplyUpgradeRollback admits executor-only recovery while the signed journal proves that no target Apply was admitted. Once Apply may have run, recovery must restore the complete prior data set before starting old images. A bare rollback-started record does not retain that proof and is denied too.

type ReleaseAuthority

type ReleaseAuthority struct {
	Version          string `json:"version"`
	ArchiveSHA256    string `json:"archiveSha256"`
	ExecutableSHA256 string `json:"executableSha256"`
}

type RestoreActivationAuthority

type RestoreActivationAuthority struct {
	OperationID          string   `json:"operationId"`
	OwnerRef             string   `json:"ownerRef"`
	RestoreResultID      string   `json:"restoreResultId"`
	SafetySnapshotID     string   `json:"safetySnapshotId"`
	PlanHash             string   `json:"planHash"`
	ManifestHash         string   `json:"manifestHash"`
	ApplyResultHash      string   `json:"applyResultHash"`
	ManagedVolumeSetHash string   `json:"managedVolumeSetHash"`
	Volumes              []string `json:"volumes"`
}

type RestoreActivationBeginRequest

type RestoreActivationBeginRequest struct {
	OperationID          string
	OwnerRef             string
	RestoreResultID      string
	SafetySnapshotID     string
	PlanHash             string
	ManifestHash         string
	ApplyResultHash      string
	ManagedVolumeSetHash string
	Volumes              []string
}

type RestoreActivationProgress

type RestoreActivationProgress struct {
	RollbackPrepared []string               `json:"rollbackPrepared"`
	Activated        []string               `json:"activated"`
	InFlight         *RestoreActivationStep `json:"inFlight,omitempty"`
}

type RestoreActivationState

type RestoreActivationState struct {
	Authority        RestoreActivationAuthority `json:"authority"`
	RollbackPrepared []string                   `json:"rollbackPrepared"`
	Activated        []string                   `json:"activated"`
	InFlight         *RestoreActivationStep     `json:"inFlight,omitempty"`
}

type RestoreActivationStep

type RestoreActivationStep struct {
	Volume string `json:"volume"`
}

type Session

type Session struct {
	// contains filtered or unexported fields
}

func BeginRestoreActivationPrepared

func BeginRestoreActivationPrepared(
	workspace string,
	prepare func() (RestoreActivationBeginRequest, error),
) (*Session, error)

BeginRestoreActivationPrepared holds the shared lifecycle lock while the caller prepares the immutable restore and safety-snapshot authority.

func BeginUpgrade

func BeginUpgrade(workspace string, request BeginRequest) (*Session, error)

func BeginUpgradePrepared

func BeginUpgradePrepared(
	workspace string,
	prepare func() (BeginRequest, error),
) (*Session, error)

BeginUpgradePrepared holds the shared lifecycle lock while the caller prepares the exact checkpoint/release authority and persists the first signed journal record without a checkpoint-to-Begin race.

func (*Session) BeginJoin

func (session *Session) BeginJoin(
	expected, next, command, binaryVersion, executableSHA256 string,
) (string, error)

func (*Session) BeginUpgradeDataActivation

func (session *Session) BeginUpgradeDataActivation(
	authority UpgradeDataActivationAuthority,
) error

BeginUpgradeDataActivation records the source/target custody binding and enters the quiescence phase under the already-held KindUpgrade lock.

func (*Session) Close

func (session *Session) Close() (returnErr error)

func (*Session) Complete

func (session *Session) Complete(status string) error

func (*Session) ReconcileForRecovery

func (session *Session) ReconcileForRecovery() error

ReconcileForRecovery repairs a stale active pointer from the immutable signed history while the caller still holds the lifecycle lock. A failed transition can therefore roll back in the same process when its history record was installed before the pointer write reported an error. Root and identity failures remain fail-closed in recoverLatestRecord.

func (*Session) Record

func (session *Session) Record() Record

func (*Session) Transition

func (session *Session) Transition(expected, next string) error

func (*Session) TransitionRestoreActivation

func (session *Session) TransitionRestoreActivation(
	expectedPhase, nextPhase string,
	progress RestoreActivationProgress,
) error

func (*Session) TransitionUpgradeDataActivation

func (session *Session) TransitionUpgradeDataActivation(
	expectedPhase, nextPhase string,
	progress UpgradeDataActivationProgress,
) error

TransitionUpgradeDataActivation persists one exact, resumable phase under the same signed KindUpgrade journal. It never creates a second journal or a child-executor join authority.

type UpgradeDataActivationAuthority

type UpgradeDataActivationAuthority struct {
	SourceGraphDigest    string   `json:"sourceGraphDigest"`
	TargetTopologyDigest string   `json:"targetTopologyDigest"`
	TargetCustodyDigest  string   `json:"targetCustodyDigest"`
	RestoreResultID      string   `json:"restoreResultId"`
	ManagedVolumeSetHash string   `json:"managedVolumeSetHash"`
	LiveVolumes          []string `json:"liveVolumes"`
}

UpgradeDataActivationAuthority is the immutable, owner-signed binding for post-Apply prior-data activation. The lifecycle record already carries the operation owner and release/checkpoint authority, so they are intentionally not duplicated here.

type UpgradeDataActivationProgress

type UpgradeDataActivationProgress struct {
	CompletedPrefix []string                   `json:"completedPrefix"`
	InFlight        *UpgradeDataActivationStep `json:"inFlight,omitempty"`
}

UpgradeDataActivationProgress is the caller's next signed progress value. CompletedPrefix is the exact ordered prefix whose copies completed; InFlight is persisted before a copy starts and remains until its completion transition is committed.

type UpgradeDataActivationState

type UpgradeDataActivationState struct {
	Authority       UpgradeDataActivationAuthority `json:"authority"`
	CompletedPrefix []string                       `json:"completedPrefix"`
	InFlight        *UpgradeDataActivationStep     `json:"inFlight,omitempty"`
}

UpgradeDataActivationState is stored additively on a KindUpgrade record only once post-Apply data recovery actually begins. Keeping it nil before then preserves the old record shape for older controllers.

type UpgradeDataActivationStep

type UpgradeDataActivationStep struct {
	Volume string `json:"volume"`
}

UpgradeDataActivationStep identifies the one volume whose copy may have started before a process crash. Retrying that step is deliberately allowed.

Jump to

Keyboard shortcuts

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