migrate

package
v1.76.0 Latest Latest
Warning

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

Go to latest
Published: Oct 12, 2026 License: MIT Imports: 36 Imported by: 0

Documentation

Overview

Package migrate copies the service's State from any adapter to any other through the ports and the domain stores (ADR 0031), and is the whole of `sluis migrate`.

It copies through the BUSINESS interfaces, never raw bytes: a domain record and its credential are read from the source's own store (the ConfigMaps and Secrets of internal/kube, or the State records of internal/portstore) and written to the destination's, so a credential lands in the destination's Secrets, and a record lands in the layout its adapter keeps. The issuer's logins in progress (sessions, refresh tokens, the keyring's schedule) are not a domain store; they are State records and Index sets under `issuer:`, which are copied with the lifetime each has left, so nobody signs in again.

A run has three phases, and the first writes nothing:

  1. Plan: read both sides, and say for every item whether it is new on the destination, already there with the same value, or there with another one. Without Overwrite any difference is a conflict and the run stops here, naming the keys, before a single write.
  2. Copy what is new (and, with Overwrite, what differs), item by item.
  3. Verify: read the source and the destination again, fresh, and compare every source item with the destination's, secrets read from each side's Secrets.

A re-run after a failure plans again and so copies exactly what is missing: the copy is idempotent, and an item the destination already holds equal is never rewritten.

What is not copied: leases (transient, and owned by whoever is running), the hub's snapshots (a cache the hub rewrites on its first refresh), and the controllers' in-flight hand-offs and caches (`share.`, `cache.`, `dedupe.`), which a tick rebuilds.

Index

Constants

View Source
const (
	DomainGoogle  = "google"
	DomainGitHub  = "github"
	DomainSlack   = "slack"
	DomainConsole = "console"
	DomainIssuer  = "issuer"
	DomainBlobs   = "blobs"
)

The domains a run can skip by name.

View Source
const (
	// KeptNotMigrated is a parameter the migration deliberately does not carry.
	KeptNotMigrated = "not-migrated"
	// KeptPulumi is a parameter the Pulumi library owns (a layout v5 apply deletes it).
	KeptPulumi = "pulumi-owned"
	// KeptUnmapped is a name layout v4 never wrote, or that is already a layout
	// v5 name.
	KeptUnmapped = "unmapped"
	// KeptUnverified is a parameter with a layout v5 address whose copy the
	// plan did not find equal (the plan did not look for it).
	KeptUnverified = "unverified"
	// KeptShared is a parameter whose layout v5 address is the same name in a
	// root both sides share: deleting it would delete the copy.
	KeptShared = "shared-address"
)

The reasons a parameter is kept.

View Source
const (
	// DefaultPrunePause is the wait between two delete requests.
	DefaultPrunePause = 500 * time.Millisecond
	// DefaultPruneBackoff is the first wait after a throttled request.
	DefaultPruneBackoff = time.Second
)

Prune pacing: SSM's DeleteParameters is throttled like PutParameter, so a batch of ten every half second, and a doubling wait when it is throttled.

View Source
const DomainDirectory = "directory"

DomainDirectory is the name the Google domain had before v1.75. A run still accepts it in Skip for one release and treats it as DomainGoogle; the report names the domain `google`.

Deprecated: use DomainGoogle. Removed in v1.76.

View Source
const S3Module = "google"

S3Module is the module that owns the blob prefix a static S3 credential opens: the Google module's cache, `google/`.

Variables

View Source
var (
	// ErrWritersRunning is a run that was not told the source is quiet.
	ErrWritersRunning = errors.New("migrate: refusing to copy while the source can still change: " +
		"freeze the source with `sluis maintenance on`, or stop every writer and pass --i-have-stopped-writers; " +
		"--dry-run reads and writes nothing and needs neither")
	// ErrConflict is a destination that already holds a different value.
	ErrConflict = errors.New("migrate: the destination already holds a different value")
	// ErrRefused is a source item the destination would refuse: nothing is
	// written until it is dealt with, and --overwrite does not change that.
	ErrRefused = errors.New("migrate: the destination would refuse source items")
	// ErrMismatch is a copy that did not verify.
	ErrMismatch = errors.New("migrate: the destination does not match the source after the copy")
	// ErrUnreadable is a source item that cannot be presented through its store.
	ErrUnreadable = errors.New("migrate: the source holds items its store cannot read")
)

Errors a run ends with. The report says the rest.

View Source
var (
	// ErrNotMigrated is a v4 item that has no v5 address on purpose: the reason
	// is in the error.
	ErrNotMigrated = errors.New("migrate: not carried to layout v5")
	// ErrNoTarget is a v4 item layout v5 has no address for.
	ErrNoTarget = errors.New("migrate: no address on layout v5")
)
View Source
var (
	// ErrPruneGate is a prune refused because the destination does not hold
	// every migrated item equal.
	ErrPruneGate = errors.New("migrate: prune refused: the destination does not hold every migrated item equal; nothing was deleted")
	// ErrPruneUnconfirmed is a real prune without the plan hash of a dry run, or
	// with the hash of another plan.
	ErrPruneUnconfirmed = errors.New("migrate: prune refused: a real run needs the plan hash a --dry-run printed (--confirm-plan)")
	// ErrPruneNoSecrets is a source that keeps no layout v4 parameters.
	ErrPruneNoSecrets = errors.New("migrate: the source keeps no layout v4 secrets of its own: there is nothing to prune")
)

AllDomains is every name a run accepts to skip.

View Source
var ErrDestinationMaintenance = errors.New("migrate: the destination holds a maintenance flag, so it would start frozen: " +
	"lift it first with `sluis maintenance off --config <v5 config>`; a copy never carries the source's flag")

ErrDestinationMaintenance is a destination that holds a maintenance flag: it would start frozen once the layout switch serves from it.

View Source
var ErrNotStarted = errors.New("migrate: nothing was written")

ErrNotStarted marks a run stopped by its Before hook: nothing was written.

Functions

func BlobID

func BlobID(c store.Config) string

BlobID says where a configuration keeps its blobs, so that two sides that keep them in one place are known to: the same S3 bucket and prefix, or, with no `ports.blob`, the same release's objects. The memory adapter keeps them nowhere another process reads, so it is never "the same".

func MapS3Ref added in v1.75.0

func MapS3Ref(ref string) (string, error)

MapS3Ref maps the `credentialsRef` of a layout v4 installation, `internal/<kind>/<id>`, to the v5 reference `internal/<module>/<name>`: the credential moves under the module that owns the blob prefix, and the two segments join (`internal/blobs/r2` becomes `internal/google/blobs-r2`). A ref that already begins with a module is unchanged.

Types

type BlobMode

type BlobMode string

BlobMode says whether the controllers' reports are copied.

const (
	// BlobsAuto copies them only when the two sides keep them in different
	// places. When they share one the next pass rewrites them anyway.
	BlobsAuto BlobMode = "auto"
	// BlobsCopy always copies them.
	BlobsCopy BlobMode = "copy"
	// BlobsSkip never does.
	BlobsSkip BlobMode = "skip"
)

The blob modes.

type ConcernSummary added in v1.58.0

type ConcernSummary struct {
	Concern string `json:"concern"`
	Items   int    `json:"items"`
	Bytes   int    `json:"bytes"`
	Refused int    `json:"refused,omitempty"`
}

ConcernSummary is what a run moves for one concern of the installation: state records, secrets, blobs. Items and Bytes are what the source holds and the run would write; Refused is what the destination would not take.

type Domains

type Domains struct {
	Workspaces  hub.Store
	Credentials hub.CredentialStore
	Orgs        orgStore
	Links       linkStore
	Runner      runnerStore
	Catalogue   catalogueStore
	SlackApps   slackCatalogueStore
	Slack       slackStore
	Shared      sharedStore
	Channels    channelStore
	SessionKey  sessionKeys
}

Domains is every domain store of one side.

func OpenDomains

func OpenDomains(ctx context.Context, st *store.Stores, create bool) (*Domains, error)

OpenDomains builds the domain stores of one side by the switch the service itself makes (internal/app): any adapter but `legacy` keeps them on the State port with every credential in Secrets, and `legacy` keeps today's ConfigMaps and Secrets. A source is opened as it is; a destination (create) also makes the objects a legacy store needs to exist, as the service does at its start.

func OpenDomainsExporting added in v1.74.0

func OpenDomainsExporting(ctx context.Context, st *store.Stores, create bool, exported func(id string) bool) (*Domains, error)

OpenDomainsExporting is OpenDomains for a side that may keep its secrets in the layout-v4 stores (the ssm source): an installed runner App, and a catalogue App for which exported says true, is the document external/github/<app> there and not an internal credential, and a Slack App's bot token is external/slack/<app> (ADR 0041). exported may be nil (no catalogue App is exported). A side without v4 stores changes nothing.

func OpenDomainsFor added in v1.75.0

func OpenDomainsFor(ctx context.Context, st *store.Stores, create bool, exported func(id string) bool,
	declared portstore.DeclaredGitHubApps,
) (*Domains, error)

OpenDomainsFor is OpenDomainsExporting for a side that also declares what the configuration says of the GitHub Apps. On layout v5 an organisation is written naming its App, which the declaration (AppRef) supplies.

type KeptParam added in v1.75.0

type KeptParam struct {
	Name   string `json:"name"`
	Class  string `json:"class"`
	Reason string `json:"reason"`
}

KeptParam is a parameter prune leaves.

type ModulePlan added in v1.75.0

type ModulePlan struct {
	Module string `json:"module"`
	PlanCounts
	Items []PlanItem `json:"items"`
}

ModulePlan is what the plan found for one module.

type Options

type Options struct {
	// DryRun plans and reports and writes nothing, the destination's objects
	// included.
	DryRun bool
	// Overwrite replaces what the destination holds with the source's. Without
	// it a destination value that differs fails the run, naming the key.
	Overwrite bool
	// WritersStopped is the operator's statement that nothing writes to the
	// source. A copy is a snapshot: a write during it is a copy of neither
	// state. A run that writes refuses without it.
	WritersStopped bool
	// Sessions also copies the issuer's logins in progress (sessions, refresh
	// tokens, the codes in flight, the Index sets). An installation's move does
	// not: people sign in again, and only the key ring's schedule is copied, so
	// that a token issued before the move keeps verifying.
	Sessions bool
	// Skip names domains left out (see the Domain constants).
	Skip []string
	// Blobs says whether the controllers' reports are copied.
	Blobs BlobMode
	// ReportBlob, when set, is a Blob name the report is also written to on
	// the destination (not by a dry run).
	ReportBlob string
	// ExportedGitHubApp says which catalogue GitHub Apps of the destination have
	// `export: true`. Nil exports none; a runner App is always
	// exported.
	ExportedGitHubApp func(id string) bool
	// Log receives progress. Nil is silent.
	Log *slog.Logger
	// Now is the clock the copied lifetimes are measured against; nil is
	// time.Now. For tests, which inject the delay between reading and writing.
	Now func() time.Time
}

Options is how a run behaves.

type PlanCounts added in v1.75.0

type PlanCounts struct {
	New       int `json:"new"`
	Same      int `json:"same"`
	Different int `json:"different"`
	Refused   int `json:"refused"`
	// Copied and Missing are what a copy wrote and a verify did not find.
	Copied  int `json:"copied,omitempty"`
	Missing int `json:"missing,omitempty"`
	// Expired is the issuer's records that ran out of lifetime before they were
	// written, and so were skipped.
	Expired int `json:"expired,omitempty"`
}

PlanCounts are the items of a module by status.

func (PlanCounts) String added in v1.75.0

func (c PlanCounts) String() string

String is a one-line summary per module, for a terminal.

type PlanItem added in v1.75.0

type PlanItem struct {
	// Concern is `state`, `secret` or `blob`.
	Concern string `json:"concern"`
	// Kind and ID are the item's kind and id on layout v5.
	Kind string `json:"kind"`
	ID   string `json:"id,omitempty"`
	// From is the v4 logical key (State) or the v4 name below the root (secret).
	From string `json:"from"`
	// To is the v5 address: `<module>/<kind>/<id>` for State, the name below
	// the root for a secret. A name ending in `<ref>` has a ref chosen at each
	// write.
	To     string     `json:"to,omitempty"`
	Status PlanStatus `json:"status"`
	// Count is how many records the row stands for; absent is one.
	Count int `json:"count,omitempty"`
	// Secrets is how many credentials the record carries; their v4 and v5
	// families are FromSecret and ToSecret.
	Secrets    int    `json:"secrets,omitempty"`
	FromSecret string `json:"fromSecret,omitempty"`
	ToSecret   string `json:"toSecret,omitempty"`
	// External is the document a consumer reads, which keeps its name.
	External string `json:"external,omitempty"`
	// FromVersion and ToVersion are the versions of a secret on each side.
	FromVersion string `json:"fromVersion,omitempty"`
	ToVersion   string `json:"toVersion,omitempty"`
	// Reason says why an item is refused, or Note what the operator must know.
	Reason string `json:"reason,omitempty"`
	Note   string `json:"note,omitempty"`
	// contains filtered or unexported fields
}

PlanItem is one thing the plan found, or, for the issuer's records whose keys are bearer values, a count of the records of one kind in one status.

type PlanOptions added in v1.75.0

type PlanOptions struct {
	// Skip names domains left out (see the Domain constants).
	Skip []string
	// Sessions also plans the issuer's sessions, refresh tokens, single
	// sign-on records, codes in flight and Index sets. Without it only the key
	// ring and the state secret's fingerprint are planned.
	Sessions bool
	// Blobs says whether the controllers' reports are planned.
	Blobs BlobMode
	// ExportedGitHubApp says which catalogue GitHub Apps have `export: true`.
	ExportedGitHubApp func(id string) bool
	// AppRef is the App each GitHub organisation uses on layout v5
	// (`controllers.github.appRefs`), an override and optional: an organisation
	// without one uses the source's App that installs it, or an App made of the
	// organisation's own (v5orgapp.go).
	AppRef func(org string) string
	// ConfigNames are the secrets the documents declare below internal/config
	// beyond the fixed ones: `providers/google/<provider>/client-id`,
	// `directory/<id>/key`.
	ConfigNames []string
	// CloudflareAccounts are the accounts whose minter credential is planned.
	CloudflareAccounts []string
	// S3Ref and S3RefTo are the `credentialsRef` of the source's and the
	// destination's blob, when they have one.
	S3Ref, S3RefTo string
	// Log receives progress. Nil is silent.
	Log *slog.Logger
	// Now is the clock the remaining lifetime of an issuer record is counted
	// by. Nil is [time.Now].
	Now func() time.Time
}

PlanOptions is what a plan is told beyond the two sides.

type PlanReport added in v1.75.0

type PlanReport struct {
	From    string       `json:"from"`
	To      string       `json:"to"`
	Modules []ModulePlan `json:"modules"`
	Totals  PlanCounts   `json:"totals"`
	Notes   []string     `json:"notes,omitempty"`
	// Mode is "copy" or "verify" for those commands; a plan leaves it out.
	Mode   string `json:"mode,omitempty"`
	DryRun bool   `json:"dryRun,omitempty"`
	// Live is a copy that ran without the writers stopped: the first pass, which
	// leaves the issuer out. A final pass is still required.
	Live bool `json:"live,omitempty"`
	// Verify is what a copy found when it read both sides again afterwards.
	Verify *VerifyResult `json:"verify,omitempty"`
	OK     bool          `json:"ok"`
	Error  string        `json:"error,omitempty"`
	// contains filtered or unexported fields
}

PlanReport is the plan: no value, no timestamp, and the same text for the same installations.

func CopyV5 added in v1.75.0

func CopyV5(ctx context.Context, from, to Side, opt V5Options) (*PlanReport, error)

CopyV5 copies a layout v4 installation to a layout v5 one, idempotently: nothing the destination already holds equal is written. It plans first and writes nothing when anything is refused or, without Overwrite, different. The report is returned with every error that is not a failure to start, so that a caller can still show it.

func Plan added in v1.75.0

func Plan(ctx context.Context, from, to Side, opt PlanOptions) (*PlanReport, error)

Plan reads a layout v4 installation (from) and a layout v5 one (to) and reports what a copy would do, per module. It makes no write.

The report is returned with ErrRefused or ErrUnreadable when anything is refused, so that a caller can still show it.

func VerifyV5 added in v1.75.0

func VerifyV5(ctx context.Context, from, to Side, opt PlanOptions) (*PlanReport, error)

VerifyV5 reads both sides and says, per module, whether the destination holds what the source does: secrets compared by hash, records by value, and an organisation by its record and the App it names (the source has no key of its own for it to match). It writes nothing. A source item the destination lacks is missing, and one it holds with another value is different; either ends the run with ErrMismatch.

func (*PlanReport) JSON added in v1.75.0

func (r *PlanReport) JSON() []byte

JSON renders the plan, indented.

type PlanStatus added in v1.75.0

type PlanStatus string

PlanStatus is what a copy would find for one item.

const (
	// PlanNew is an item the destination lacks.
	PlanNew PlanStatus = "new"
	// PlanSame is an item the destination holds with the same value.
	PlanSame PlanStatus = "same"
	// PlanDifferent is an item the destination holds with another value.
	PlanDifferent PlanStatus = "different"
	// PlanRefused is an item that cannot be carried: layout v5 has no address
	// for it, the destination would refuse it, or the source cannot read it.
	PlanRefused PlanStatus = "refused"
	// PlanCopied is an item a copy wrote (it was new, or different with
	// --overwrite).
	PlanCopied PlanStatus = "copied"
	// PlanMissing is an item a verify did not find on the destination.
	PlanMissing PlanStatus = "missing"
	// PlanExpired is an issuer record whose lifetime ran out between the
	// moment it was read and the moment a copy came to write it. It is skipped:
	// the source drops it too.
	PlanExpired PlanStatus = "expired"
)

The statuses.

type Problem

type Problem struct {
	Domain string `json:"domain"`
	Kind   string `json:"kind"`
	Key    string `json:"key"`
	Reason string `json:"reason"`
}

Problem names one item that is not as it should be. Key is the item's key within its kind; for the issuer's state, whose keys carry bearer values (a code, a session), it is a short hash of the key so that a report is safe to keep.

type PruneOptions added in v1.75.0

type PruneOptions struct {
	PlanOptions
	// DryRun reads, reports the plan hash and deletes nothing.
	DryRun bool
	// Confirm is the plan hash of a dry run; a real run needs it.
	Confirm string
	// SameRoot is true when both sides keep their parameters below one root: a
	// layout v4 name that is also the layout v5 name is then the copy itself.
	SameRoot bool
	// Pause is the wait between two requests (zero is [DefaultPrunePause]) and
	// Backoff the first wait after a throttled one (zero is [DefaultPruneBackoff]).
	Pause, Backoff time.Duration
	// Before is called once, after the plan hash is confirmed and before the
	// first delete. The command records its intent there; an error stops the run
	// with nothing deleted.
	Before func(ctx context.Context, r *PruneReport) error
	// Sleep waits; nil is a context-aware time.Sleep.
	Sleep func(ctx context.Context, d time.Duration) error
}

PruneOptions is how a prune behaves.

type PruneReport added in v1.75.0

type PruneReport struct {
	From string `json:"from"`
	To   string `json:"to"`
	// DryRun is a run that deleted nothing.
	DryRun bool `json:"dryRun,omitempty"`
	// PlanHash identifies the parameters to delete and the ones kept; a real
	// run is given it as --confirm-plan.
	PlanHash string `json:"planHash,omitempty"`
	// Verify is what the gate found, by status.
	Verify PlanCounts `json:"verify"`
	// Gate is "passed", or why the run was refused.
	Gate string `json:"gate"`
	// Delete are the parameters to delete (a dry run) or deleted.
	Delete []string `json:"delete"`
	// Deleted counts the parameters a real run removed, in Batches requests.
	Deleted int `json:"deleted,omitempty"`
	Batches int `json:"batches,omitempty"`
	// Kept are the parameters left, with the reason.
	Kept []KeptParam `json:"kept"`
	// LegacyTableItems are the migrated records on the source: the legacy table
	// holds them until it retires; prune does not touch it.
	LegacyTableItems int      `json:"legacyTableItems"`
	Notes            []string `json:"notes,omitempty"`
	OK               bool     `json:"ok"`
	Error            string   `json:"error,omitempty"`
}

PruneReport is what a prune found and did: names and counts, never a value.

func PruneV5 added in v1.75.0

func PruneV5(ctx context.Context, from, to Side, opt PruneOptions) (*PruneReport, error)

PruneV5 runs the gate, decides what to delete and keep, and, unless DryRun, deletes it once the plan hash is confirmed. The report is returned with every error that is not a failure to start, so that a caller can still show it.

func (*PruneReport) JSON added in v1.75.0

func (r *PruneReport) JSON() []byte

JSON renders the report, indented.

type Report

type Report struct {
	From        string    `json:"from"`
	To          string    `json:"to"`
	FromAdapter string    `json:"fromAdapter"`
	ToAdapter   string    `json:"toAdapter"`
	DryRun      bool      `json:"dryRun"`
	Overwrite   bool      `json:"overwrite"`
	StartedAt   time.Time `json:"startedAt"`
	FinishedAt  time.Time `json:"finishedAt"`
	Steps       []Step    `json:"steps"`
	Totals      Step      `json:"totals"`
	Conflicts   []Problem `json:"conflicts,omitempty"`
	Unreadable  []Problem `json:"unreadable,omitempty"`
	Mismatches  []Problem `json:"mismatches,omitempty"`
	// Refused are the items the destination would refuse, and why.
	Refused []Problem `json:"refused,omitempty"`
	// Concerns is the summary per concern: state, secrets, blobs.
	Concerns []ConcernSummary `json:"concerns,omitempty"`
	// Notes say what was left out and why (a domain skipped, a side with
	// nothing to read).
	Notes []string `json:"notes,omitempty"`
	// Error is how the run ended, if it did not end well.
	Error string `json:"error,omitempty"`
	// OK is true when the plan had no conflict, nothing unreadable, and, unless
	// this was a dry run, every item verified.
	OK bool `json:"ok"`
}

Report is what a run says it did: counts and the keys of what went wrong, never a value.

func Run

func Run(ctx context.Context, from, to Side, opt Options) (*Report, error)

Run copies from one side to the other and returns what it did. The report is returned with every error that is not a failure to start, so that a caller can still show what was found; a nil report is a run that did not begin.

func (*Report) JSON

func (r *Report) JSON() []byte

JSON renders the report, indented.

type SecretTarget added in v1.75.0

type SecretTarget struct {
	Module string
	Kind   string
	ID     string
	// V5 is the name below the installation's root, or the family when it
	// holds a `<ref>` the store chooses at each write.
	V5 string
	// Config is true for a name an operator or Pulumi seeds as plain text
	// (below internal/config), which the v4 source delivers by name.
	Config bool
}

SecretTarget is where a v4 secret lands on layout v5.

func MapSecret added in v1.75.0

func MapSecret(name string) (SecretTarget, error)

MapSecret maps a v4 secret name, below the installation's root (`internal/...` or `external/...`), to its v5 address. A name with a `<ref>` last segment is a family: its refs are random per write and are not preserved.

type Side

type Side struct {
	// Name labels it in the report: the configuration file it came from.
	Name string
	// Stores is the opened ports.
	Stores *store.Stores
	// BlobID identifies where this side keeps blobs, so that two sides that
	// share a place are known to; empty is "nowhere shared".
	BlobID string
}

Side is one end of a run: the ports and stores of a configuration, opened.

type Step

type Step struct {
	Domain string `json:"domain"`
	Kind   string `json:"kind"`
	// Source is how many readable items the source holds.
	Source int `json:"source"`
	// Unreadable is how many it holds that its store cannot present: they are
	// listed and not copied.
	Unreadable int `json:"unreadable,omitempty"`
	// New is how many the destination lacks, Present how many it already holds
	// with the same value, and Conflicts how many it holds with another.
	New       int `json:"new"`
	Present   int `json:"present"`
	Conflicts int `json:"conflicts,omitempty"`
	// Copied is how many were written: New, and with Overwrite the Conflicts.
	Copied int `json:"copied"`
	// Verified is how many matched on the second read; Mismatched how many did
	// not.
	Verified   int `json:"verified"`
	Mismatched int `json:"mismatched,omitempty"`
	// Refused is how many the destination would refuse (an item over a size
	// limit, an invalid key): they are listed under refused and stop the run
	// before anything is written.
	Refused int `json:"refused,omitempty"`
	// Bytes is the size of the readable source items (a record with its
	// credentials, a blob, a State value); Secrets and SecretBytes are the
	// credentials among them, which go to the Secrets port.
	Bytes       int `json:"bytes"`
	Secrets     int `json:"secrets,omitempty"`
	SecretBytes int `json:"secretBytes,omitempty"`
}

Step is the outcome of one collection.

type Target added in v1.75.0

type Target struct {
	Module string
	Kind   string
	ID     string
}

Target is the module, kind and id of an item on layout v5.

func IndexTarget added in v1.75.0

func IndexTarget(set string) (Target, error)

IndexTarget is where the Index set lands on layout v5.

func StateTarget added in v1.75.0

func StateTarget(key string) (Target, error)

StateTarget is where the State record with the logical key lands on layout v5.

func (Target) String added in v1.75.0

func (t Target) String() string

String is `<module>/<kind>/<id>`.

type V5Options added in v1.75.0

type V5Options struct {
	PlanOptions
	// DryRun reads and reports and writes nothing.
	DryRun bool
	// Overwrite replaces what the destination holds with the source's. Without
	// it a destination value that differs stops the run before any write.
	Overwrite bool
	// WritersStopped is the operator's statement that nothing writes to the
	// source. A run that writes refuses without it.
	WritersStopped bool
	// Before is called once, after the plan is read and every check passed and
	// before the first write, when there is something to write. The command
	// records its intent there; an error stops the run before it writes.
	Before func(ctx context.Context, w Writes) error
	// Wait pauses until the replicas have seen a freeze set a moment ago; nil
	// waits on the clock. A test replaces it.
	Wait func(ctx context.Context, d time.Duration)
}

V5Options is how a copy behaves: what the plan is told, and what may be written.

type VerifyResult added in v1.75.0

type VerifyResult struct {
	PlanCounts
	// Problems are the items that did not match.
	Problems []PlanItem `json:"problems,omitempty"`
	OK       bool       `json:"ok"`
}

VerifyResult is what a copy found when it read both sides again after writing.

type Writes added in v1.75.0

type Writes struct {
	// Items is how many items are written, New of them absent on the
	// destination and Replaced replacing a value that differs.
	Items, New, Replaced int
	// ReplacedNames are the replaced items, as module/concern/name.
	ReplacedNames []string
}

Writes is what a copy is about to write: counts and names, never a value.

Jump to

Keyboard shortcuts

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