Documentation
¶
Overview ¶
Package actions provides core logic for Watchtower's container update operations. It handles container staleness checks, updates, and lifecycle management.
Key components:
- Update: Scans and updates containers based on parameters.
- ValidateRollingRestartDependencies: Validates environment for rolling restarts.
- CheckForMultipleWatchtowerContainers: Ensures single Watchtower container.
- RunUpdatesWithNotifications: Performs container updates and sends notifications about the results.
- CleanupImages: Removes specified image IDs from the Docker environment.
- UpdateImplicitRestart: Marks containers linked to restarting ones for proper restart order.
Logging: every function that logs requires a non-nil *zerolog.Logger (first parameter or Logger field on params structs). Callers (typically cmd) construct the logger via internal/logging and pass it explicitly. There is no package-level or global logger.
Usage example:
report, _, err := actions.Update(log, ctx, client, params)
if err != nil {
log.Error().Err(err).Msg("Update failed")
}
useComposeDependsOn := true
err = actions.ValidateRollingRestartDependencies(log, ctx, client, filter, useComposeDependsOn)
if err != nil {
log.Error().Err(err).Msg("Sanity check failed")
}
runParams := actions.RunUpdatesWithNotificationsParams{
Logger: log,
Client: client,
Notifier: notifier,
NotificationSplitByContainer: false,
NotificationReport: false,
Update: types.UpdateParams{
Filter: filter,
Cleanup: true,
Timeout: 30 * time.Second,
},
}
metric := actions.RunUpdatesWithNotifications(ctx, runParams)
The package integrates with the container package for Docker operations, session package for update reporting, sorter package for container ordering, and lifecycle package for pre/post-update hooks, using github.com/rs/zerolog for logging operations and errors.
Index ¶
- Constants
- Variables
- func CleanupOldWatchtowerContainers(log *zerolog.Logger, ctx context.Context, client container.Client, ...) (int, error)
- func EphemeralSelfUpdate(log *zerolog.Logger, ctx context.Context, client container.Client, ...) (types.ContainerID, bool, error)
- func RemoveExcessWatchtowerInstances(log *zerolog.Logger, ctx context.Context, client container.Client, ...) (int, error)
- func RemoveImages(log *zerolog.Logger, ctx context.Context, client container.Client, ...) ([]types.RemovedImageInfo, error)
- func RunOrchestrator(log *zerolog.Logger, ctx context.Context, client container.Client)
- func RunUpdatesWithNotifications(ctx context.Context, params RunUpdatesWithNotificationsParams) *metrics.Metric
- func TryRecoverOrphanedContainer(log *zerolog.Logger, ctx context.Context, client container.Client, ...) (types.Container, bool)
- func Update(log *zerolog.Logger, ctx context.Context, client container.Client, ...) (types.Report, []types.RemovedImageInfo, error)
- func UpdateImplicitRestart(log *zerolog.Logger, allContainers, containers []types.Container, ...)
- func ValidateRollingRestartDependencies(log *zerolog.Logger, ctx context.Context, client container.Client, ...) error
- type RunUpdatesWithNotificationsParams
Constants ¶
const ( // FoundNewImageMessage is the message logged when a new image is found for a container. FoundNewImageMessage = "Found new image" // StoppingContainerMessage is the message logged when stopping a container for update. StoppingContainerMessage = "Stopping container" // StartedNewContainerMessage is the message logged when a new container is started after update. StartedNewContainerMessage = "Started new container" // StoppingLinkedContainerMessage is the message logged when stopping a linked container for restart. StoppingLinkedContainerMessage = "Stopping linked container" // StartedLinkedContainerMessage is the message logged when a linked container is started after restart. StartedLinkedContainerMessage = "Started linked container" // UpdateSkippedMessage is the message logged when an update is skipped in monitor-only mode. UpdateSkippedMessage = "Update available but skipped (monitor-only mode)" // ContainerRemainsRunningMessage is the message logged when a container remains running in monitor-only mode. ContainerRemainsRunningMessage = "Container remains running (monitor-only mode)" )
Exported constants for update message literals to ensure consistency across the codebase. These constants define the standard messages used in container update logging and notifications.
Variables ¶
var RemovalRetryDelay = 1 * time.Second
RemovalRetryDelay sets the delay before retrying removal operations.
Functions ¶
func CleanupOldWatchtowerContainers ¶
func CleanupOldWatchtowerContainers(log *zerolog.Logger, ctx context.Context, client container.Client, cleanupImages bool, scope string, currentContainerID types.ContainerID, removeImageInfos *[]types.RemovedImageInfo, ) (int, error)
CleanupOldWatchtowerContainers removes old Watchtower containers that linger from a previous self-update. Unlike RemoveExcessWatchtowerInstances (which runs once at startup), this is designed to be called during each update cycle to catch any old containers that the startup cleanup may have missed.
It identifies containers matching the watchtower-old- prefix within the same scope as the current container, stops them, and optionally cleans up their images. This ensures that even if an old container survives the initial cleanup (e.g., it was still stopping), it won't persist across update cycles.
Parameters:
- log: Process logger. Required and must be non-nil. A nil logger panics on the first log call.
- ctx: Context for cancellation and timeouts.
- client: Container client for Docker operations.
- cleanupImages: Remove images if true.
- scope: Scope to filter Watchtower containers (empty for unscoped).
- currentContainerID: ID of the currently running Watchtower container.
- removeImageInfos: Pointer to slice of images to remove after stopping old containers.
Returns:
- int: Number of removed old Watchtower containers.
- error: Non-nil if removal fails, nil if none found or successful removal.
func EphemeralSelfUpdate ¶
func EphemeralSelfUpdate(log *zerolog.Logger, ctx context.Context, client container.Client, sourceContainer types.Container, config types.UpdateParams, ) (types.ContainerID, bool, error)
EphemeralSelfUpdate performs a self-update using an ephemeral orchestrator container.
Instead of the rename-based approach, this creates a short-lived container that:
- Inspects the old container's configuration
- Stops the old container
- Creates a new container from the new image with the same config
- Starts the new container
- Removes the old container
- Exits (AutoRemove cleans up the orchestrator)
This function returns immediately after starting the orchestrator. The orchestrator handles the full replacement sequence asynchronously. The current Watchtower process will be stopped by the orchestrator shortly after this function returns.
The ephemeral container uses the same Watchtower image (already pulled) and mounts the Docker socket for container management.
Parameters:
- log: Process logger. Required and must be non-nil. A nil logger panics on the first log call.
- ctx: Context for cancellation and timeouts.
- client: Container client for Docker operations.
- sourceContainer: Current Watchtower container being replaced.
- config: Update parameters.
Returns:
- types.ContainerID: Empty string (the new container's ID is not known to the caller).
- bool: False (old container is removed, not renamed).
- error: Non-nil if orchestrator creation fails.
func RemoveExcessWatchtowerInstances ¶
func RemoveExcessWatchtowerInstances(log *zerolog.Logger, ctx context.Context, client container.Client, cleanupImages bool, scope string, removeImageInfos *[]types.RemovedImageInfo, currentContainer types.Container, ) (int, error)
RemoveExcessWatchtowerInstances ensures a single Watchtower container within the same scope.
It identifies multiple Watchtower containers within the same scope, stops all but the current, and collects removed images for deferred removal if enabled, preventing conflicts from concurrent containers. Chain identification uses the current container's labels to determine old containers to remove. Scoped instances only remove other instances in the same scope, allowing coexistence with different scopes. Removal operations respect scope boundaries to prevent cross-scope interference.
Parameters:
- log: Process logger. Required and must be non-nil. A nil logger panics on the first log call.
- ctx: Context for cancellation and timeouts.
- client: Container client for Docker operations.
- cleanupImages: Remove images if true.
- watchtowerScope: Scope to filter Watchtower containers.
- removeImageInfos: Pointer to slice of images to remove after stopping excess containers.
- currentContainer: The current running Watchtower container.
Returns:
- int: Number of removed Watchtower containers.
- error: Non-nil if removal fails, nil if single instance or successful removal.
func RemoveImages ¶
func RemoveImages(log *zerolog.Logger, ctx context.Context, client container.Client, images []types.RemovedImageInfo, ) ([]types.RemovedImageInfo, error)
RemoveImages removes specified images and returns successfully removed ones.
It iterates through the provided images, attempting to remove each from the Docker environment, logging successes or failures for debugging and monitoring. Tracks successfully removed image info. If no images are provided, it returns an empty slice and no error.
Parameters:
- log: Process logger. Required and must be non-nil. A nil logger panics on the first log call.
- ctx: Context for cancellation and timeouts.
- client: Container client for Docker operations.
- images: Slice of images to remove.
Returns:
- []RemovedImageInfo: Slice of successfully removed image info.
- error: Non-nil if any image removal failed, nil otherwise.
func RunOrchestrator ¶
RunOrchestrator executes the orchestrator mode for self-update.
This is the entry point when Watchtower is started with --self-update-orchestrator. It reads environment variables to determine the old container ID, new image, and original container name, then performs the container replacement sequence.
The orchestrator follows a deterministic state machine:
- VALIDATE: Read and validate environment variables
- INSPECT: Get the old container's full configuration
- STOP OLD: Stop the old container (frees host ports)
- RENAME OLD: Move the stopped predecessor off the original name
- CREATE NEW: Create a new container from the new image with the same config
- START NEW: Start the new Watchtower container
- VERIFY: Confirm the new container is running
- REMOVE OLD: Delete the renamed predecessor
Stop before create releases published host ports. Rename keeps the stopped predecessor for recovery if create or start fails (restore name and start).
Parameters:
- log: Process logger. Required and must be non-nil. A nil logger panics on the first log call.
- ctx: Context for cancellation and timeouts.
- client: Container client for Docker operations.
func RunUpdatesWithNotifications ¶
func RunUpdatesWithNotifications( ctx context.Context, params RunUpdatesWithNotificationsParams, ) *metrics.Metric
RunUpdatesWithNotifications performs container updates and sends notifications about the results.
It executes the update action with configured parameters, batches notifications, and returns a metric summarizing the session for monitoring purposes, ensuring users are informed of update outcomes.
Parameters:
- ctx: Context for cancellation and timeouts.
- params: The RunUpdatesWithNotificationsParams struct containing all configuration parameters. params.Logger is required and must be non-nil (nil panics on first log call).
Returns:
- *metrics.Metric: A pointer to a metric object summarizing the update session (scanned, updated, failed counts).
func TryRecoverOrphanedContainer ¶
func TryRecoverOrphanedContainer(log *zerolog.Logger, ctx context.Context, client container.Client, currentContainer types.Container, ) (types.Container, bool)
TryRecoverOrphanedContainer attempts to start an orphaned Watchtower container that is stuck in the Docker "created" state. This can happen when a self-update creates a replacement container but fails to start it, leaving the old container running and the new container never started.
It lists all containers, filters for Watchtower containers in the created state that are not the current container, and attempts to start the first match.
Parameters:
- log: Process logger. Required and must be non-nil. A nil logger panics on the first log call.
- ctx: Context for cancellation and timeouts.
- client: Container client for Docker API operations.
- currentContainer: The current running container to exclude from recovery.
Returns:
- types.Container: The recovered container if successful, nil otherwise.
- bool: True if a container was found and started, false otherwise.
func Update ¶
func Update(log *zerolog.Logger, ctx context.Context, client container.Client, config types.UpdateParams, ) (types.Report, []types.RemovedImageInfo, error)
Update scans and updates containers based on parameters.
It checks container staleness, sorts by dependencies, and updates or restarts containers as needed, collecting cleaned image info for cleanup. Non-stale linked containers are restarted but not marked as updated. Containers with pinned images (referenced by digest) are skipped to preserve immutability.
Parameters:
- log: Process logger. Required and must be non-nil. A nil logger panics on the first log call.
- ctx: Context for cancellation and timeouts.
- client: Container client for interacting with Docker API.
- config: UpdateParams specifying behavior like cleanup, restart, and filtering.
Returns:
- types.Report: Session report summarizing scanned, updated, and failed containers.
- []types.RemovedImageInfo: Slice of cleaned image info to clean up after updates.
- error: Non-nil if listing or sorting fails, nil on success.
func UpdateImplicitRestart ¶
func UpdateImplicitRestart(log *zerolog.Logger, allContainers, containers []types.Container, useComposeDependsOn bool, )
UpdateImplicitRestart marks containers linked to restarting ones.
It uses a multi-pass algorithm to ensure transitive propagation through the dependency chain, continuing until no more containers are marked for restart.
Parameters:
- log: Process logger. Required and must be non-nil. A nil logger panics on the first log call.
- allContainers: Full list of containers being managed.
- containers: Slice of containers to evaluate and potentially mark for restart.
- useComposeDependsOn: Whether to consider Docker Compose depends_on labels.
This function mutates the ToRestart / LinkedToRestarting state on containers in place.
func ValidateRollingRestartDependencies ¶
func ValidateRollingRestartDependencies( log *zerolog.Logger, ctx context.Context, client container.Client, filter types.Filter, useComposeDependsOn bool, ) error
ValidateRollingRestartDependencies validates the environment for rolling restart updates.
It iterates through the filtered containers and returns an error if any container has a linked dependency, which is incompatible with the use of a rolling restart update policy.
Parameters:
- log: Process logger. Required and must be non-nil. A nil logger panics on the first log call.
- ctx: Context for cancellation and timeouts.
- client: Container client for Docker operations.
- filter: Container filter to select relevant containers.
- useComposeDependsOn: Whether to include Docker Compose depends_on label in dependency resolution.
Returns:
- error: Non-nil if dependencies conflict with rolling restarts, nil otherwise.
Types ¶
type RunUpdatesWithNotificationsParams ¶
type RunUpdatesWithNotificationsParams struct {
// Logger is the process logger for this update session. Required and must be non-nil.
Logger *zerolog.Logger
// Client is the Docker client for container operations.
Client container.Client
// Notifier sends update status messages to configured channels.
Notifier types.Notifier
// NotificationSplitByContainer enables a separate notification per updated container.
NotificationSplitByContainer bool
// NotificationReport enables report-based notification templates.
NotificationReport bool
// EventBroadcaster publishes SSE events during the update session.
EventBroadcaster *events.Broadcaster
// Update is the complete update policy for this invocation (filter, cleanup, timeouts, etc.).
Update types.UpdateParams
}
RunUpdatesWithNotificationsParams holds runtime dependencies and update policy.
Update carries the full types.UpdateParams snapshot from config.UpdateParams (or an equivalent complete construction).