Documentation
¶
Index ¶
- Constants
- Variables
- func DrainRequests() <-chan struct{}
- func HealthTimeout(seconds int) time.Duration
- func MaybeCrash(dataMountPath, point string, log *slog.Logger)
- func RequestDrain()
- func Retry(ctx context.Context, fn func() error, onError func(attempt int, err error)) error
- func WaitHealthy(ctx context.Context, apiClient client.APIClient, containerID string, ...) error
- func WithBootstrapLock(ctx context.Context, dataMountPath string, run func() error) error
- func WithPollLock(ctx context.Context, dataMountPath string, run func() error) error
- type Actor
- type CommitStatusInfo
- type Constraints
- type ContainerRef
- type DeployInfo
- type DriftSnapshot
- type Identity
- type Poison
- type Record
- type SourceInfo
- type State
- type Store
- func (s *Store) Active() (*Record, error)
- func (s *Store) AddPoison(p Poison) error
- func (s *Store) ClearPoison(contextName, stack string) error
- func (s *Store) Create(record *Record) error
- func (s *Store) IsPoisoned(contextName, stack, commitSHA, projectHash string) (Poison, bool, error)
- func (s *Store) Load(id string) (Record, error)
- func (s *Store) Quarantine(id string) error
- func (s *Store) ReadSnapshot(id string) (container.InspectResponse, bool, error)
- func (s *Store) Remove(id string) error
- func (s *Store) RemoveIfUnchanged(expected Record) error
- func (s *Store) Root() string
- func (s *Store) Save(record Record) error
- func (s *Store) Update(record Record, to State, actor Actor) (Record, error)
- func (s *Store) WriteSnapshot(id string, inspect container.InspectResponse) error
- type Strategy
- type Transition
Constants ¶
const ApplierMaxRestarts = 3
ApplierMaxRestarts bounds Docker's restarts of a failing applier while the predecessor still serves and can recover the handover. The predecessor lifts the bound right before it drains, since the applier is then the only process left to finish or roll back.
const CrashEnvVar = "SELF_UPDATE_CRASH_AT"
CrashEnvVar names the journal state at which the process must die, to test crash recovery. Never set it outside tests.
const DefaultHealthTimeout = 90 * time.Second
DefaultHealthTimeout is used when the deploy config sets no timeout.
const RecordVersion = 1
RecordVersion is bumped when the on-disk record layout changes.
const RecoveryRetries = 2
RecoveryRetries bounds in-process setup, cleanup and rollback retries. The applier's restart policy retries beyond that, so it only absorbs brief Docker or filesystem hiccups.
Variables ¶
var ( // ErrHandover signals that a deploy handed the stack over to another // process. It is neither a success nor a failure for the calling stage. ErrHandover = errors.New("self-update handover in progress") // ErrDisabled is returned when a stack contains this doco-cd instance but // the self-update feature is off. ErrDisabled = errors.New("self-update is disabled") // ErrUnsupported is returned when the self stack cannot be updated by any // strategy. ErrUnsupported = errors.New("self-update is not supported for this stack") // ErrInvalidTransition is returned when a journal state change is not allowed. ErrInvalidTransition = errors.New("invalid self-update state transition") // ErrStaleRecord is returned when another process advanced or removed a // journal record before a Save or Update could persist its changes. ErrStaleRecord = errors.New("stale self-update record") // ErrNoRecord is returned when no journal record exists for an ID. ErrNoRecord = errors.New("no self-update record") )
var ErrUnhealthy = errors.New("container did not become healthy")
ErrUnhealthy is returned when a container failed its health gate.
var RetryPause = time.Second
RetryPause is the delay between Retry attempts. Tests may shorten it.
Functions ¶
func DrainRequests ¶
func DrainRequests() <-chan struct{}
DrainRequests is the coordinator's side of RequestDrain.
func HealthTimeout ¶
HealthTimeout converts a deploy timeout in seconds, falling back to DefaultHealthTimeout when it is unset.
func MaybeCrash ¶
MaybeCrash exits the process when the configured crash point is reached for the first time. The marker on the data volume makes it fire once, so the restarted actor can make progress.
func RequestDrain ¶
func RequestDrain()
RequestDrain asks the coordinator to stop accepting work and hand over.
func Retry ¶
Retry runs fn up to RecoveryRetries+1 times, pausing between attempts. onError, if set, is called after every failed attempt with its 1-based number. Cancelling ctx stops further attempts and joins ctx.Err() to the last error; pass context.WithoutCancel for recovery that must keep going.
func WaitHealthy ¶
func WaitHealthy(ctx context.Context, apiClient client.APIClient, containerID string, timeout time.Duration, log *slog.Logger) error
WaitHealthy blocks until containerID reports healthy twice in a row, or the timeout expires. Containers without a healthcheck are probed by running the binary's own healthcheck subcommand inside them.
func WithBootstrapLock ¶ added in v0.122.1
WithBootstrapLock runs bootstrap deployments while excluding managed poll runs.
Types ¶
type CommitStatusInfo ¶ added in v0.122.1
type CommitStatusInfo struct {
// SourceURL is the deployment repository, used to resolve credentials.
SourceURL string `json:"source_url"`
RepoURL string `json:"repo_url,omitempty"`
FullName string `json:"full_name,omitempty"`
CommitSHA string `json:"commit_sha"`
Context string `json:"context"`
StartedAt time.Time `json:"started_at,omitzero"`
}
CommitStatusInfo identifies the commit status of a handed over deployment, so the process that resolves the handover can post its final state.
type Constraints ¶
type Constraints struct {
// NetworkDrift is true when a project network must be recreated, which
// would stop every attached container including this one.
NetworkDrift bool
}
Constraints are runtime facts the selector cannot read off the service.
type ContainerRef ¶
type ContainerRef struct {
ID string `json:"id"`
Name string `json:"name"`
Number int `json:"number,omitempty"`
}
ContainerRef identifies a container involved in a handover.
type DeployInfo ¶
type DeployInfo struct {
TimeoutSeconds int `json:"timeout_seconds"`
RecreateMode string `json:"recreate_mode"`
Services []string `json:"services,omitempty"`
NetworkDrift bool `json:"network_drift,omitempty"`
RemoveOrphans bool `json:"remove_orphans,omitempty"`
}
DeployInfo carries the deploy parameters the applier must reproduce.
func (DeployInfo) HealthTimeout ¶
func (d DeployInfo) HealthTimeout() time.Duration
HealthTimeout is how long the successor may take to become healthy.
type DriftSnapshot ¶
type DriftSnapshot struct {
Networks map[string]network.Inspect `json:"networks"`
Containers map[string]container.InspectResponse `json:"containers"`
}
DriftSnapshot is the state that must be recoverable if Compose replaces a network shared by the predecessor and other project services.
type Identity ¶
type Identity struct {
// OK is false when this process does not run in a compose-managed container.
OK bool
ContainerID string
ContainerName string
Project string
Service string
Number int
Image string
Labels map[string]string
}
Identity describes this doco-cd container's place in a compose project.
type Poison ¶
type Poison struct {
Context string `json:"context"`
Stack string `json:"stack"`
CommitSHA string `json:"commit_sha"`
ProjectHash string `json:"project_hash"`
Reason string `json:"reason"`
FailedAt time.Time `json:"failed_at"`
Attempts int `json:"attempts"`
}
Poison records a self-update that failed for a specific commit, so the retry logic cannot loop on it. A new commit clears the block by not matching.
type Record ¶
type Record struct {
Version int `json:"version"`
ID string `json:"id"`
State State `json:"state"`
Strategy Strategy `json:"strategy"`
Stack string `json:"stack"`
Context string `json:"context"`
Service string `json:"service"`
Predecessor ContainerRef `json:"predecessor"`
Successor ContainerRef `json:"successor,omitzero"`
Applier ContainerRef `json:"applier,omitzero"`
Restored ContainerRef `json:"restored,omitzero"`
Source SourceInfo `json:"source"`
Deploy DeployInfo `json:"deploy"`
Drift *DriftSnapshot `json:"drift,omitempty"`
DriftStarted bool `json:"drift_started,omitempty"`
Labels map[string]string `json:"labels"`
Error string `json:"error,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
History []Transition `json:"history"`
}
Record is the on-disk handover journal for one self-update.
func (Record) SameProgress ¶
SameProgress reports whether r has the same state and full transition history as other, i.e. no process advanced one past the other.
type SourceInfo ¶
type SourceInfo struct {
RepoName string `json:"repo_name"`
SourceURL string `json:"source_url"`
FullName string `json:"full_name"`
SourceType string `json:"source_type"`
Reference string `json:"reference"`
ConfigTarget string `json:"config_target"`
CommitSHA string `json:"commit_sha"`
ProjectHash string `json:"project_hash"`
JobID string `json:"job_id"`
Trigger string `json:"trigger"`
// CommitStatus is the status the predecessor left pending, nil when it
// posted none. It never holds a token: the finishing process resolves one.
CommitStatus *CommitStatusInfo `json:"commit_status,omitempty"`
}
SourceInfo carries everything the successor needs to report the deploy that it did not itself run.
type State ¶
type State string
State is a step in the self-update handover.
const ( StateStaged State = "staged" // predecessor: creating the successor or applier StateStarted State = "started" // predecessor (scale-out): successor created and started, health pending StateHandover State = "handover" // predecessor (scale-out): successor healthy StateDrained State = "drained" // predecessor (scale-out): no in-flight work, safe to stop me StateApplying State = "applying" // predecessor then applier: applier running StateApplyReady State = "apply_ready" // applier: preflight complete; predecessor may drain StateApplyDrained State = "apply_drained" // predecessor: admission drained; applier may change containers StateApplied State = "applied" // applier: successor healthy, predecessor gone StateRolledBack State = "rolled_back" // applier: successor unhealthy, predecessor restored StateFailed State = "failed" // applier: error, predecessor restored or still alive StateFinalising State = "finalising" // successor: predecessor removed, reporting pending StateAborted State = "aborted" // predecessor: gave up on the successor )
func (State) ApplierFinished ¶
ApplierFinished reports states the applier must not apply or recover again.
func (State) InApplierPhase ¶
InApplierPhase reports states in which an applier still owns the handover and can recover it.
func (State) RolledBackOrFailed ¶
RolledBackOrFailed reports the applier's unsuccessful outcomes.
func (State) Unsuccessful ¶
Unsuccessful reports outcomes the predecessor reports and cleans up.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store persists handover records on the data volume.
func (*Store) Active ¶
Active returns the single in-flight record, or nil when there is none. Malformed records are quarantined rather than failing the caller.
func (*Store) AddPoison ¶
AddPoison blocks further attempts for the same commit and project hash. Re-adding the same key increments the attempt counter.
func (*Store) ClearPoison ¶
ClearPoison removes the block for a stack.
func (*Store) Create ¶
Create writes the initial record. The caller sets everything but the bookkeeping fields.
func (*Store) IsPoisoned ¶
IsPoisoned reports whether this exact commit and project hash already failed.
func (*Store) Quarantine ¶
Quarantine renames an unreadable record so it stops blocking startup.
func (*Store) ReadSnapshot ¶
ReadSnapshot returns the stored predecessor snapshot, if one exists.
func (*Store) RemoveIfUnchanged ¶
RemoveIfUnchanged prevents a failed staging attempt from deleting a record that another process has advanced or assigned to another container.
func (*Store) Save ¶
Save persists metadata only while the record's state and transition history remain unchanged. It cannot recreate a removed record or overwrite a transition or clear a newly recorded recovery error written by another process.
func (*Store) Update ¶
Update advances a record if its state and transition history still match the persisted version. UpdatedAt is not part of the comparison: callers may Save(record) then Update(record, ...) using the same value.
func (*Store) WriteSnapshot ¶
func (s *Store) WriteSnapshot(id string, inspect container.InspectResponse) error
WriteSnapshot stores the predecessor's inspect output for rollback.
type Strategy ¶
type Strategy string
Strategy is how doco-cd replaces its own container.
const ( // StrategyAuto picks scale_out unless a constraint forces applier. StrategyAuto Strategy = "auto" // StrategyScaleOut starts a second container, health-checks it, then hands over. StrategyScaleOut Strategy = "scale_out" // StrategyApplier delegates the replacement to a throwaway clone. StrategyApplier Strategy = "applier" )
func Select ¶
func Select(svc types.ServiceConfig, sourceType, contextName string, requested Strategy, c Constraints) (Strategy, []string, error)
Select decides the strategy and returns the reasons that ruled out scale-out.