container

package
v1.21.1 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2026 License: Apache-2.0 Imports: 34 Imported by: 0

Documentation

Overview

Package container provides functionality for managing Docker containers in Watchtower. It defines types and methods to interact with the Docker API, handle container metadata, and implement lifecycle operations like updates, restarts, and image management.

Key components:

  • Container: Implements types.Container interface for state and metadata operations.
  • Client: Interface for Docker API interactions (list, start, stop, etc.).
  • imageClient: Manages image pulling and staleness checks.
  • Filters: Logic to select containers by names, labels, and scopes.
  • Labels: Methods to interpret Watchtower-specific labels and lifecycle hooks.

Usage example:

cli := container.NewClient(container.ClientOptions{})
containers, _ := cli.ListContainers(filters.NoFilter)
for _, c := range containers {
    stale, _, _ := cli.IsContainerStale(c, types.UpdateParams{})
    if stale {
        cli.StopContainer(c, 10*time.Second)
    }
}

The package integrates with Docker's API via docker/docker client libraries and supports Watchtower's update workflows, including authentication, scope filtering, and custom lifecycle hooks.

Index

Constants

View Source
const (
	// CPUCopyModeAuto indicates automatic detection of container runtime for
	// CPU copying behavior.
	CPUCopyModeAuto = "auto"

	// DaemonInitTimeout is the default timeout for Docker daemon initialization operations.
	// This timeout applies to initial connection, ping, API version negotiation, and
	// server version retrieval during client initialization.
	// The value is 30 seconds, which should be sufficient for most Docker daemon
	// initialization scenarios while preventing indefinite hangs.
	DaemonInitTimeout = 30 * time.Second
)

Constants for CPUCopyMode values.

View Source
const (

	// ContainerChainLabel accumulates container IDs across Watchtower self-updates, comma-separated.
	ContainerChainLabel = "com.centurylinklabs.watchtower.container-chain"

	// OrchestratorLabel identifies ephemeral orchestrator containers used during self-update.
	OrchestratorLabel = "com.centurylinklabs.watchtower.ephemeral-orchestrator"
)

Watchtower-specific labels identify containers managed by Watchtower and their configurations.

Variables

View Source
var (
	ReadMountinfoFunc = os.ReadFile
	ReadCgroupFunc    = os.ReadFile
)

File reading functions for testing mocks.

View Source
var (
	// ErrImageInUse indicates that the image is actively used by a container and cannot be removed.
	ErrImageInUse = errors.New("image is actively used by a container")

	// ErrPullImageUnauthorized indicates an authentication failure during image pull.
	ErrPullImageUnauthorized = errors.New("failed to pull image: authentication required")
	// ErrPullImageNotFound indicates the image was not found in the registry.
	ErrPullImageNotFound = errors.New("failed to pull image: image not found")
)

Errors for image operations in image.go.

View Source
var (
	// ErrEphemeralCreateFailed indicates a failure to create the ephemeral orchestrator container.
	ErrEphemeralCreateFailed = errors.New("failed to create ephemeral orchestrator container")
	// ErrEphemeralStartFailed indicates a failure to start the ephemeral orchestrator container.
	ErrEphemeralStartFailed = errors.New("failed to start ephemeral orchestrator container")
)

Errors for ephemeral orchestrator operations in ephemeral.go.

View Source
var (

	// ErrContainerIDNotFound indicates the container ID could not be found using hostname matching.
	ErrContainerIDNotFound = errors.New("HOSTNAME environment variable is not set")
)

Errors for container ID detection operations in container_id.go.

View Source
var (
	// ErrImageCooldown indicates the image is within the configured cooldown window and should not be pulled.
	ErrImageCooldown = errors.New("image is within cooldown period")
)

Errors for image cooldown operations in cooldown.go and image.go.

View Source
var (

	// ErrUnexpectedContainerType indicates an unexpected container type was encountered.
	ErrUnexpectedContainerType = errors.New("unexpected container type")
)

Errors for container configuration and metadata operations in container.go.

Functions

func ContainsWatchtowerLabel

func ContainsWatchtowerLabel(labels map[string]string) bool

ContainsWatchtowerLabel checks if the container is Watchtower.

Parameters:

  • labels: Label map to check.

Returns:

  • bool: True if watchtower label is "true", false otherwise.

func CreateTargetContainer

func CreateTargetContainer(log *zerolog.Logger,
	ctx context.Context,
	api Operations,
	sourceContainer types.Container,
	networkConfig *dockerNetwork.NetworkingConfig,
	clientVersion string,
	minSupportedVersion string,
	disableMemorySwappiness bool,
	cpuCopyMode string,
	isPodman bool,
) (types.ContainerID, error)

CreateTargetContainer creates a new container based on the source container's configuration but does not start it. It applies the provided network configuration, renames the container, and attaches additional networks for legacy API versions.

Parameters:

  • ctx: Context for cancellation and timeout control.
  • api: Interface for container operations (Operations).
  • sourceContainer: Source container to replicate.
  • networkConfig: Network configuration to apply to the new container.
  • clientVersion: Docker API version used by the client.
  • minSupportedVersion: Minimum Docker API version required for full network features.
  • disableMemorySwappiness: If true, disables memory swappiness for Podman compatibility.
  • cpuCopyMode: CPU copy mode for container recreation, used for compatibility with Podman.
  • isPodman: If true, indicates Podman is being used for CPU compatibility.

Returns:

  • types.ContainerID: ID of the new container.
  • error: Non-nil if creation fails, nil on success.

func DetectCycles

func DetectCycles(containers []types.Container, useComposeDependsOn bool) map[string]bool

DetectCycles identifies all containers involved in circular dependencies using three-color DFS.

This function constructs a directed dependency graph from container relationships and uses depth-first search with node coloring to detect all cycles. The algorithm ensures that every connected component of the graph is explored, identifying all containers that are part of any circular dependency chain.

Graph Construction: 1. Each container becomes a node identified by its resolved container identifier 2. Dependencies (links) become directed edges from dependent to dependency 3. Container names are normalized to handle Docker Compose service name variations 4. Only containers present in the input list are included (missing dependencies ignored)

DFS Traversal Strategy:

  • Start DFS from each unvisited (white) node to ensure all components are explored
  • The three-color algorithm detects cycles during traversal and marks all involved nodes
  • Multiple DFS calls are needed because the graph may have disconnected components

Implementation Rationale:

  • Uses adjacency list representation for efficient neighbor iteration (O(1) per edge)
  • Normalization ensures consistent handling of Docker Compose vs container names
  • Returns all cyclic nodes rather than just detecting presence, enabling targeted handling
  • Single pass through graph with O(V + E) complexity makes it suitable for large deployments

Time Complexity: O(V + E) where V = containers, E = dependency links Space Complexity: O(V + E) for graph storage and DFS recursion stack

Edge Cases:

  • Empty container list: Returns empty map
  • No dependencies: Returns empty map (no cycles possible)
  • Single container with self-dependency: Detected as cycle
  • Multiple disconnected cycles: All detected and marked
  • Missing dependency targets: Ignored (only analyze provided containers)

Parameters:

  • containers: List of containers to analyze for cycles. Should not be nil.
  • useComposeDependsOn: Whether to include Docker Compose depends_on label in dependency resolution.

Returns:

  • map[string]bool: Map where keys are container names and values indicate cycle involvement. true = container is part of at least one cycle, false/absent = no cycles detected. Empty map returned if no cycles found.

func ExtractContainerIDFromPath

func ExtractContainerIDFromPath(path string) types.ContainerID

ExtractContainerIDFromPath extracts container ID from a path containing /containers/<id>.

func ExtractImageDigest

func ExtractImageDigest(repoDigests []string, imageName string) string

ExtractImageDigest extracts the manifest digest portion from RepoDigests.

When imageName is non-empty, it prefers a RepoDigest whose name portion matches the image repository (tag stripped). Otherwise it returns the digest from the first RepoDigest that contains an "@" separator.

Parameters:

  • repoDigests: Slice of RepoDigest strings, each in the format "name@sha256:...".
  • imageName: Optional container image name used to prefer a matching RepoDigest.

Returns:

  • string: The extracted digest (e.g., "sha256:abc..."), or "" if unavailable.

func GetContainerIDFromCgroupFile

func GetContainerIDFromCgroupFile(log *zerolog.Logger) (types.ContainerID, error)

GetContainerIDFromCgroupFile retrieves the container ID from /proc/<pid>/cgroup. Uses the cgroup file to find Docker container paths.

func GetContainerIDFromHostname

func GetContainerIDFromHostname(log *zerolog.Logger, ctx context.Context, client Client) (types.ContainerID, error)

GetContainerIDFromHostname retrieves the container ID by matching the HOSTNAME env var.

It uses the Docker API to list containers and find a matching hostname. When multiple containers share the same hostname (e.g., in Docker Compose setups), it prefers the container with the Watchtower label.

Parameters:

  • ctx: Context for cancellation and timeout control.
  • client: Docker client interface for container operations.

Returns:

  • types.ContainerID: The detected container ID if a match is found.
  • error: Non-nil if the HOSTNAME env var is missing, the Docker client's ListContainers call fails (wrapped and propagated), or no matching container is found.

func GetContainerIDFromMountinfo

func GetContainerIDFromMountinfo(log *zerolog.Logger) (types.ContainerID, error)

GetContainerIDFromMountinfo retrieves the container ID from /proc/self/mountinfo. Uses the mountinfo file to find container paths containing /containers/<id>.

func GetCurrentContainerID

func GetCurrentContainerID(log *zerolog.Logger, ctx context.Context, client Client) (types.ContainerID, error)

GetCurrentContainerID retrieves the current container ID using a fallback strategy. It attempts multiple detection methods in order of preference and reliability.

The detection methods are tried in the following order: 1. Mountinfo-based detection - cgroup v2 compatible 2. Cgroup file parsing - cgroup v1 compatible 3. Hostname matching - fallback using Docker API

Parameters:

  • client: Docker client interface for container operations

Returns:

  • types.ContainerID: The detected container ID if successful
  • error: Non-nil if all detection methods fail, containing the last error encountered

func GetEffectiveScope

func GetEffectiveScope(container types.Container, currentScope string) (string, error)

GetEffectiveScope determines the effective operational scope by prioritizing explicit scope over scope derived from the container's label. This is crucial for self-update scenarios where a new Watchtower instance needs to inherit the same scope as the instance being replaced to maintain proper isolation and prevent cross-scope interference during the update process.

Parameters:

  • container: The current Watchtower container.
  • currentScope: The explicit scope value (takes priority if non-empty).

Returns:

  • string: The effective scope.
  • error: Non-nil if derivation fails.

func GetLinksFromWatchtowerLabel

func GetLinksFromWatchtowerLabel(c *Container, clog *zerolog.Logger) []string

GetLinksFromWatchtowerLabel extracts dependency links from the watchtower depends-on label.

It parses the com.centurylinklabs.watchtower.depends-on label value, splitting on commas and normalizing each container name, returning all normalized links, including potential self-references.

Note: Watchtower depends-on labels reference container names directly, unlike Compose depends-on, which references services within the same project. Therefore, we do not prefix with project name for Watchtower labels.

Parameters:

  • c: Container instance
  • clog: Logger instance for debug output

Returns:

  • []string: List of all normalized links, including potential self-references, or nil if label not present

func GetSourceContainer

func GetSourceContainer(log *zerolog.Logger,
	ctx context.Context,
	api dockerClient.APIClient,
	containerID types.ContainerID,
) (types.Container, error)

GetSourceContainer retrieves detailed information about a container by its ID.

It resolves network mode if it references another container.

Parameters:

  • log: Logger for debug output.
  • ctx: Context for cancellation and timeout control.
  • api: Docker API client.
  • containerID: ID of the container to inspect.

Returns:

  • types.Container: Container object if successful.
  • error: Non-nil if inspection fails, nil on success.

func IsImagePinnedByDigest

func IsImagePinnedByDigest(imageName string) bool

IsImagePinnedByDigest reports whether imageName is an immutable digest reference.

It matches bare digests (sha256:...) and repository-qualified digests (repo@sha256:...), consistent with Config.Image / ImageName(log, ) for digest-pinned containers. Tag references such as nginx:latest are not pinned.

This is the shared pin-detection primitive used by pull/check paths and by the update flow after image-name resolution.

Parameters:

  • imageName: Image name from ImageName(log, ) or Config.Image.

Returns:

  • bool: True if the image is digest-pinned, false otherwise.

func IsOldContainer

func IsOldContainer(name string) bool

IsOldContainer reports whether the container's runtime name (from Name() or raw inspect) indicates a predecessor renamed during Watchtower self-update. It trims any leading '/' (as Docker names have) and checks for the WatchtowerOldPrefix convention. Used for disambiguation in hostname fallback, forcing cleanup of old containers, skipping redundant renames, and suppressing notifs for self-cleanup of prior incarnations.

Parameters:

  • name: The container name (may be empty, with or without leading '/').

Returns:

  • bool: true if the (normalized) name has the old- prefix.

func IsWatchtowerParent

func IsWatchtowerParent(currentID types.ContainerID, chain string) bool

IsWatchtowerParent checks if the current container ID exists in the comma-separated container-chain label values.

It handles edge cases like empty chain or invalid IDs by returning false appropriately. The chain values are trimmed of whitespace before comparison.

Parameters:

  • currentID: The container ID to check for in the chain.
  • chain: Comma-separated string of container IDs from the container-chain label.

Returns:

  • bool: True if currentID is found in the chain, false otherwise.

func ListSourceContainers

func ListSourceContainers(log *zerolog.Logger,
	ctx context.Context,
	api dockerClient.APIClient,
	opts ClientOptions,
	filter types.Filter,
	isPodmanOptional ...bool,
) ([]types.Container, error)

ListSourceContainers retrieves a list of containers from the container runtime host.

It filters containers based on options and a provided filter function.

Parameters:

  • ctx: Context for cancellation and timeout control.
  • api: Docker API client.
  • opts: Client options for filtering.
  • filter: Function to filter containers.
  • isPodmanOptional: Optional variadic flag indicating Podman runtime (defaults to false).

Returns:

  • []types.Container: Filtered list of containers.
  • error: Non-nil if listing fails, nil on success.

func ParseContainerIDFromCgroupString

func ParseContainerIDFromCgroupString(log *zerolog.Logger, cgroupString string) (types.ContainerID, error)

ParseContainerIDFromCgroupString parses the cgroup string to extract container ID.

func ParseContainerIDFromMountinfo

func ParseContainerIDFromMountinfo(log *zerolog.Logger, mountinfoString string) (types.ContainerID, error)

ParseContainerIDFromMountinfo parses the mountinfo string to extract container ID.

func RemoveOrphanedOrchestrators

func RemoveOrphanedOrchestrators(log *zerolog.Logger,
	ctx context.Context,
	client Client,
) (int, error)

RemoveOrphanedOrchestrators removes any ephemeral orchestrator containers that may have persisted due to crashes or unexpected termination.

This is called during startup alongside RemoveExcessWatchtowerInstances to ensure a clean state.

Parameters:

  • ctx: Context for cancellation and timeout control.
  • client: Container client for Docker operations.

Returns:

  • int: Number of orphaned orchestrators removed.
  • error: Non-nil if listing or removal fails, nil on success.

func RenameTargetContainer

func RenameTargetContainer(log *zerolog.Logger,
	ctx context.Context,
	api Operations,
	targetContainer types.Container,
	targetName string,
) error

RenameTargetContainer renames an existing container to the specified target name in Watchtower.

Parameters:

  • ctx: Context for cancellation and timeout control.
  • api: Interface for container operations (Operations).
  • targetContainer: Container to be renamed.
  • targetName: New name for the container.

Returns:

  • error: Non-nil if rename fails, nil on success.

func ResolveContainerIdentifier

func ResolveContainerIdentifier(c types.Container) string

ResolveContainerIdentifier returns a standardized container identifier used for dependency resolution, update coordination, logging, and cycle detection.

Container identifier formats:

  1. project-service-containerNumber (if project name, service name, and container number are all available)
  2. project-service (if project name and service name are available)
  3. service (if only service name is available)
  4. container name (if name is available)
  5. container ID (fallback)

Parameters:

  • c: Container to get identifier for

Returns:

  • string: Container identifier formatted according to the prioritization order, always returns a non-empty string for valid containers

func StartTargetContainer

func StartTargetContainer(log *zerolog.Logger,
	ctx context.Context,
	api Operations,
	sourceContainer types.Container,
	networkConfig *dockerNetwork.NetworkingConfig,
	reviveStopped bool,
	clientVersion string,
	minSupportedVersion string,
	disableMemorySwappiness bool,
	cpuCopyMode string,
	isPodman bool,
) (types.ContainerID, error)

StartTargetContainer creates and starts a new container based on the source container's configuration.

It applies the provided network configuration and respects the reviveStopped option. For legacy Docker API versions (< 1.44) with multiple networks, it creates the container with a single network and attaches others sequentially to avoid issues with multiple network endpoints in ContainerCreate. For modern API versions (>= 1.44) or single networks, it attaches all networks at creation.

Parameters:

  • ctx: Context for cancellation and timeout control.
  • api: Interface for container operations (Operations).
  • sourceContainer: Source container to replicate.
  • networkConfig: Network configuration to apply to the new container.
  • reviveStopped: If true, starts the new container even if the source is stopped.
  • clientVersion: Docker API version used by the client.
  • minSupportedVersion: Minimum Docker API version required for full network features.
  • disableMemorySwappiness: If true, disables memory swappiness for Podman compatibility.
  • cpuCopyMode: CPU copy mode for container recreation, used for compatibility with Podman.
  • isPodman: If true, indicates Podman is being used for CPU compatibility.

Returns:

  • types.ContainerID: ID of the new container.
  • error: Non-nil if creation or start fails, nil on success.

func StopAndRemoveSourceContainer

func StopAndRemoveSourceContainer(log *zerolog.Logger,
	ctx context.Context,
	api dockerClient.APIClient,
	sourceContainer types.Container,
	timeout time.Duration,
	removeVolumes bool,
) error

StopAndRemoveSourceContainer stops and removes the specified container using the Docker API.

It first stops the container if running, then removes it with optional volume cleanup. When HostConfig.AutoRemove is set, Docker only removes the container after a started instance exits. Explicit removal is therefore skipped only when the container was running before stop. Non-running containers (for example created but never started) are always removed explicitly so the name is freed for recreation.

Parameters:

  • ctx: Context for cancellation and timeout control.
  • api: Docker API client for interacting with the Docker daemon.
  • sourceContainer: Container object to stop and remove, containing metadata like name and ID.
  • timeout: Duration to wait for graceful shutdown before forcing termination with SIGKILL.
  • removeVolumes: Boolean indicating whether to remove associated volumes during container removal.

Returns:

  • error: Non-nil if stopping or removing the container fails, nil on successful completion.

func StopSourceContainer

func StopSourceContainer(log *zerolog.Logger,
	ctx context.Context,
	api dockerClient.APIClient,
	sourceContainer types.Container,
	timeout time.Duration,
) error

StopSourceContainer stops the specified container using the Docker API's StopContainer method.

It checks if the container is running, sends the configured stop signal (defaulting to SIGTERM if unset), and waits for the specified timeout for graceful shutdown, forcing termination with SIGKILL if necessary.

Parameters:

  • ctx: Context for cancellation and timeout control.
  • api: Docker API client for interacting with the Docker daemon.
  • sourceContainer: Container object to stop, containing metadata like name and ID.
  • timeout: Duration to wait for graceful shutdown before forcing termination with SIGKILL.

Returns:

  • error: Non-nil if stopping the container fails, nil on successful completion.

Types

type Client

type Client interface {
	// ListContainers retrieves a list of containers, optionally filtered.
	//
	// If no filters are provided, all containers are returned.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - filter: Optional filters to apply to container list. Multiple filters are combined with logical AND.
	//
	// Returns:
	//   - []types.Container: List of matching containers.
	//   - error: Non-nil if listing fails, nil on success.
	ListContainers(ctx context.Context, filter ...types.Filter) ([]types.Container, error)

	// GetContainer fetches detailed information about a specific container by its ID.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - containerID: ID of the container to retrieve.
	//
	// Returns:
	//   - types.Container: Container details if found.
	//   - error: Non-nil if retrieval fails, nil on success.
	GetContainer(ctx context.Context, containerID types.ContainerID) (types.Container, error)

	// GetCurrentWatchtowerContainer retrieves minimal container information
	// for the specified container ID, skipping image inspection.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - containerID: ID of the container to retrieve.
	//
	// Returns:
	//   - types.Container: Container with imageInfo set to nil.
	//   - error: Non-nil if inspection fails, nil on success.
	GetCurrentWatchtowerContainer(ctx context.Context, containerID types.ContainerID) (types.Container, error)

	// StopContainer stops a specified container, respecting the given timeout.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - container: Container to stop.
	//   - timeout: Duration to wait before forcing stop.
	//
	// Returns:
	//   - error: Non-nil if stop fails, nil on success.
	StopContainer(ctx context.Context, container types.Container, timeout time.Duration) error

	// StopAndRemoveContainer stops and removes a specified container,
	// respecting the given timeout.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - container: Container to stop and remove.
	//   - timeout: Duration to wait before forcing stop.
	//
	// Returns:
	//   - error: Non-nil if stop/removal fails, nil on success.
	StopAndRemoveContainer(ctx context.Context, container types.Container, timeout time.Duration) error

	// CreateContainer creates a new container based on the provided
	// container's configuration, but does not start it.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - container: Source container to replicate.
	//
	// Returns:
	//   - types.ContainerID: ID of the new container.
	//   - error: Non-nil if creation fails, nil on success.
	CreateContainer(ctx context.Context, container types.Container) (types.ContainerID, error)

	// StartContainer creates and starts a new container based on the provided
	// container's configuration.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - container: Source container to replicate.
	//
	// Returns:
	//   - types.ContainerID: ID of the new container.
	//   - error: Non-nil if creation/start fails, nil on success.
	StartContainer(ctx context.Context, container types.Container) (types.ContainerID, error)

	// RenameContainer renames an existing container to the specified new name.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - container: Container to rename.
	//   - newName: New name for the container.
	//
	// Returns:
	//   - error: Non-nil if rename fails, nil on success.
	RenameContainer(ctx context.Context, container types.Container, newName string) error

	// IsContainerStale checks if a container's image is outdated compared to
	// the latest available version.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - container: Container to check.
	//   - params: Update parameters for staleness check.
	//
	// Returns:
	//   - bool: True if image is stale, false otherwise.
	//   - types.ImageID: Latest image ID.
	//   - string: Latest registry manifest digest (empty if unavailable).
	//   - error: Non-nil if check fails, nil on success.
	IsContainerStale(
		ctx context.Context,
		container types.Container,
		params types.UpdateParams,
	) (bool, types.ImageID, string, error)

	// CheckContainerUpdate reports whether a newer image is available without
	// pulling image layers. When NoPull is active it inspects the local cache
	// only; otherwise, it compares registry digests. Cooldown is not applied.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - container: Container to check.
	//   - params: Update parameters (NoPull, LabelPrecedence).
	//
	// Returns:
	//   - bool: True if an update is available, false otherwise.
	//   - types.ImageID: Latest local image ID when known (empty for remote-only mismatch).
	//   - string: Latest registry manifest digest (empty if unavailable).
	//   - error: Non-nil if the check fails, nil on success.
	CheckContainerUpdate(
		ctx context.Context,
		container types.Container,
		params types.UpdateParams,
	) (bool, types.ImageID, string, error)

	// ExecuteCommand runs a command inside a container and returns whether
	// to skip updates based on the result.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - container: Container to execute command in.
	//   - command: Command to execute.
	//   - timeout: Minutes to wait before timeout (0 for no timeout).
	//   - uid: UID to run command as (-1 to use container default).
	//   - gid: GID to run command as (-1 to use container default).
	//
	// Returns:
	//   - bool: True if updates should be skipped, false otherwise.
	//   - error: Non-nil if execution fails, nil on success.
	ExecuteCommand(
		ctx context.Context,
		container types.Container,
		command string,
		timeout int,
		uid int,
		gid int,
	) (bool, error)

	// RemoveImageByID deletes an image from the Docker host by its ID.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - imageID: ID of the image to remove.
	//   - imageName: Name of the image to remove (for logging purposes).
	//
	// Returns:
	//   - error: Non-nil if removal fails, nil on success.
	RemoveImageByID(ctx context.Context, imageID types.ImageID, imageName string) error

	// WarnOnHeadPullFailed determines whether to log a warning when a HEAD request fails during image pulls.
	//
	// The decision is based on the configured warning strategy and container context.
	//
	// Parameters:
	//   - container: Container to evaluate.
	//
	// Returns:
	//   - bool: True if warning is needed, false otherwise.
	WarnOnHeadPullFailed(container types.Container) bool

	// GetVersion returns the client's API version.
	//
	// Returns:
	//   - string: Docker API version (e.g., "1.44").
	GetVersion() string

	// GetInfo returns system information from the Docker daemon.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//
	// Returns:
	//   - map[string]any: System information.
	//   - error: Non-nil if retrieval fails, nil on success.
	GetInfo(ctx context.Context) (map[string]any, error)

	// Ping verifies connectivity to the Docker daemon.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//
	// Returns:
	//   - error: Non-nil if the daemon is unreachable, nil on success.
	Ping(ctx context.Context) error

	// WaitForContainerHealthy waits for a container to become healthy or times out.
	//
	// The timeout parameter controls the maximum wait duration:
	//   - timeout > 0: Wait up to the specified duration for the container to become healthy.
	//   - timeout <= 0: Wait indefinitely until the container becomes healthy, unhealthy,
	//     or the context is cancelled.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - containerID: ID of the container to wait for.
	//   - timeout: Maximum duration to wait for health. Zero or negative values cause
	//     indefinite waiting.
	//
	// Returns:
	//   - error: Non-nil if timeout is reached, container becomes unhealthy, or inspection
	//     fails. nil if healthy or no health check is configured.
	WaitForContainerHealthy(ctx context.Context, containerID types.ContainerID, timeout time.Duration) error

	// UpdateContainer updates the configuration of an existing container.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - container: Container to update.
	//   - config: Update configuration containing the changes to apply.
	//
	// Returns:
	//   - error: Non-nil if update fails, nil on success.
	UpdateContainer(ctx context.Context, container types.Container, config dockerContainer.UpdateConfig) error

	// SetNoRestartPolicy updates the restart policy of a container to "no" to prevent
	// restart loops after fatal startup failures.
	//
	// It is a convenience wrapper around UpdateContainer that constructs the restart
	// policy configuration and logs a warning if the update fails, ensuring the
	// failure does not block the exit path.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - container: Container whose restart policy should be updated.
	SetNoRestartPolicy(ctx context.Context, container types.Container)

	// RemoveContainer removes a container from the Docker host.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - container: Container to remove.
	//
	// Returns:
	//   - error: Non-nil if removal fails, nil on success.
	RemoveContainer(ctx context.Context, container types.Container) error

	// CreateEphemeralOrchestrator creates a short-lived container that orchestrates
	// the Watchtower self-update transition.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - sourceContainer: The current Watchtower container being replaced.
	//   - newImage: The image reference for the new Watchtower container.
	//   - containerChain: The container chain label for lineage tracking.
	//
	// Returns:
	//   - types.ContainerID: ID of the ephemeral orchestrator container.
	//   - error: Non-nil if creation or start fails, nil on success.
	CreateEphemeralOrchestrator(
		ctx context.Context,
		sourceContainer types.Container,
		newImage string,
		containerChain string,
	) (types.ContainerID, error)

	// StartContainerByID starts a container by its ID directly.
	//
	// Unlike StartContainer, this does not check the reviveStopped option or
	// create a new container from a source configuration. It directly starts
	// an existing, already-created container. This is used by the ephemeral
	// orchestrator to start the new container after the old one has been stopped.
	//
	// Parameters:
	//   - ctx: Context for cancellation and timeout control.
	//   - containerID: ID of the container to start.
	//
	// Returns:
	//   - error: Non-nil if starting fails, nil on success.
	StartContainerByID(ctx context.Context, containerID types.ContainerID) error
}

Client defines the interface for interacting with the Docker API within Watchtower.

It provides methods for managing containers, images, and executing commands, abstracting the underlying Docker client operations.

func NewClient

func NewClient(log *zerolog.Logger, opts ClientOptions) Client

NewClient initializes a new Client instance for Docker API interactions.

It configures the client using environment variables (e.g., DOCKER_HOST, DOCKER_API_VERSION) and validates the API version, falling back to autonegotiation if necessary.

Parameters:

  • opts: Options to customize container management behavior.

Returns:

  • Client: Initialized client instance (exits on failure).

type ClientOptions

type ClientOptions struct {
	RemoveVolumes           bool
	IncludeStopped          bool
	ReviveStopped           bool
	IncludeRestarting       bool
	DisableMemorySwappiness bool
	CPUCopyMode             string
	WarnOnHeadFailed        WarningStrategy
	Fs                      afero.Fs
}

ClientOptions configures container management behavior for the Docker client.

type Container

type Container struct {
	LinkedToRestarting bool          // Indicates if linked to a restarting container
	Stale              bool          // Marks the container as having an outdated image
	OldImageID         types.ImageID // Stores the image ID before update for cleanup tracking
	// contains filtered or unexported fields
}

func NewContainer

func NewContainer(
	log *zerolog.Logger,
	containerInfo *dockerContainer.InspectResponse,
	imageInfo *dockerImage.InspectResponse,
) *Container

NewContainer creates a new Container instance with the specified metadata.

The resolved image name is cached so later ImageName calls do not recompute it.

Parameters:

  • log: Process logger. A nop logger is used when nil.
  • containerInfo: Docker container metadata.
  • imageInfo: Docker image metadata.

Returns:

  • *Container: Initialized container instance.

func (*Container) ContainerInfo

func (c *Container) ContainerInfo() *dockerContainer.InspectResponse

ContainerInfo returns the full Docker container metadata.

Returns:

  • *dockerContainerType.InspectResponse: Container metadata.

func (*Container) CooldownDelay

func (c *Container) CooldownDelay(params types.UpdateParams) time.Duration

CooldownDelay returns the effective cooldown delay for this container.

If the container has the cooldown-delay label set, its value is used (parsed as a duration string). Otherwise, the global CooldownDelay from UpdateParams is used. Setting the label to "0" disables cooldown for this container.

Parameters:

  • params: Update parameters from types.UpdateParams.

Returns:

  • time.Duration: Effective cooldown delay for this container.

func (*Container) Enabled

func (c *Container) Enabled() (bool, bool)

Enabled checks if Watchtower should manage the container.

Returns:

  • bool: True if enabled, false otherwise.
  • bool: True if label is set and valid, false if absent or invalid.

func (*Container) GetContainerChain

func (c *Container) GetContainerChain() (string, bool)

GetContainerChain returns the container chain label value.

Returns:

  • string: The label value or empty if absent.
  • bool: True if the label is present, false otherwise.

func (*Container) GetCreateConfig

func (c *Container) GetCreateConfig() *dockerContainer.Config

GetCreateConfig generates a container configuration for recreation.

It isolates runtime overrides from image defaults and sets the image name.

Returns:

  • *dockerContainerType.Config: Configuration for container creation.

func (*Container) GetCreateHostConfig

func (c *Container) GetCreateHostConfig() *dockerContainer.HostConfig

GetCreateHostConfig generates a host configuration for recreation.

It adjusts link formats for Docker API compatibility.

Returns:

  • *dockerContainerType.HostConfig: Host configuration for container creation.

func (*Container) GetLabel

func (c *Container) GetLabel(label string) (string, bool)

GetLabel retrieves the value of an arbitrary container label.

It returns the label value and true if the label is present, or an empty string and false if the label is absent.

Parameters:

  • label: Docker label key to look up.

Returns:

  • string: Label value if present.
  • bool: True if label exists, false otherwise.

func (*Container) GetLifecycleGID

func (c *Container) GetLifecycleGID() (int, bool)

GetLifecycleGID returns the GID for lifecycle hooks from labels.

Returns:

  • int: GID value if set and valid.
  • bool: True if label is present and valid, false otherwise.

func (*Container) GetLifecyclePostCheckCommand

func (c *Container) GetLifecyclePostCheckCommand() string

GetLifecyclePostCheckCommand returns the post-check command from labels.

Returns:

  • string: Post-check command or empty if unset.

func (*Container) GetLifecyclePostUpdateCommand

func (c *Container) GetLifecyclePostUpdateCommand() string

GetLifecyclePostUpdateCommand returns the post-update command from labels.

Returns:

  • string: Post-update command or empty if unset.

func (*Container) GetLifecyclePreCheckCommand

func (c *Container) GetLifecyclePreCheckCommand() string

GetLifecyclePreCheckCommand returns the pre-check command from labels.

Returns:

  • string: Pre-check command or empty if unset.

func (*Container) GetLifecyclePreUpdateCommand

func (c *Container) GetLifecyclePreUpdateCommand() string

GetLifecyclePreUpdateCommand returns the pre-update command from labels.

Returns:

  • string: Pre-update command or empty if unset.

func (*Container) GetLifecycleUID

func (c *Container) GetLifecycleUID() (int, bool)

GetLifecycleUID returns the UID for lifecycle hooks from labels.

Returns:

  • int: UID value if set and valid.
  • bool: True if label is present and valid, false otherwise.

func (*Container) HasExposedPorts

func (c *Container) HasExposedPorts() bool

HasExposedPorts checks if the container has any host-bound port mappings.

This is used to determine if a Watchtower container should skip self-updates, as host-bound ports cause port conflicts during the self-update process where the old container holds the port while the new container tries to bind it.

Only actual host-to-container port bindings (HostConfig.PortBindings) are considered, not merely declared exposed ports (Config.ExposedPorts), since declared-but-unbound ports do not cause conflicts.

Returns:

  • bool: True if the container has host-bound port mappings, false otherwise.

func (*Container) HasImageInfo

func (c *Container) HasImageInfo() bool

HasImageInfo indicates whether image metadata is available.

Returns:

  • bool: True if imageInfo is non-nil, false otherwise.

func (*Container) ID

func (c *Container) ID() types.ContainerID

ID returns the unique identifier of the container.

Returns:

  • types.ContainerID: Container ID.

func (*Container) ImageID

func (c *Container) ImageID() types.ImageID

ImageID returns the ID of the container's image.

Returns:

  • types.ImageID: Image ID or empty string if imageInfo is nil.

func (*Container) ImageInfo

func (c *Container) ImageInfo() *dockerImage.InspectResponse

ImageInfo returns the Docker image metadata.

Returns:

  • *dockerImageType.InspectResponse: Image metadata or nil if unavailable.

func (*Container) ImageName

func (c *Container) ImageName() string

ImageName returns the cached name of the container's image.

The value is resolved once in NewContainer from the Zodiac label or Config.Image. When containerInfo is later cleared, the name is resolved again. Callers that already hold c.mu must use imageNameLocked.

Returns:

  • string: Image name (e.g., "alpine:latest").

func (*Container) IsCreated

func (c *Container) IsCreated() bool

IsCreated checks if the container is in the Docker "created" state, meaning it was successfully created but never started.

Returns:

  • bool: True if the container is in created state, false otherwise.

func (*Container) IsLinkedToRestarting

func (c *Container) IsLinkedToRestarting() bool

IsLinkedToRestarting returns whether the container is linked to a restarting container.

Returns:

  • bool: True if linked, false otherwise.

func (*Container) IsMonitorOnly

func (c *Container) IsMonitorOnly(params types.UpdateParams) bool

IsMonitorOnly determines if the container is monitor-only.

It uses UpdateParams.MonitorOnly and label precedence.

Parameters:

  • params: Update parameters from types.UpdateParams.

Returns:

  • bool: True if monitor-only, false otherwise.

func (*Container) IsNoPull

func (c *Container) IsNoPull(params types.UpdateParams) bool

IsNoPull determines if image pulls should be skipped.

It uses UpdateParams.NoPull and label precedence.

Parameters:

  • params: Update parameters from types.UpdateParams.

Returns:

  • bool: True if no-pull, false otherwise.

func (*Container) IsRestarting

func (c *Container) IsRestarting() bool

IsRestarting checks if the container is currently restarting.

Returns:

  • bool: True if restarting, false otherwise.

func (*Container) IsRunning

func (c *Container) IsRunning() bool

IsRunning checks if the container is currently running.

Returns:

  • bool: True if running, false otherwise.

func (*Container) IsStale

func (c *Container) IsStale() bool

IsStale returns whether the container's image is outdated.

Returns:

  • bool: True if stale, false otherwise.

func (*Container) IsWatchtower

func (c *Container) IsWatchtower() bool

IsWatchtower identifies if this is the Watchtower container.

Returns:

  • bool: True if watchtower label is "true", false otherwise.
func (c *Container) Links(useComposeDependsOn bool) []string

Links returns a list of container names this container depends on.

It retrieves dependencies from multiple sources in priority order:

  1. com.centurylinklabs.watchtower.depends-on label (Watchtower's native dependency format)
  2. com.docker.compose.depends_on label (Docker Compose dependencies via v5 API)
  3. HostConfig.Links (legacy Docker links)
  4. NetworkMode.ConnectedContainer() (container network mode dependencies)

Self-references are filtered out from all link sources to prevent circular dependencies where a container would depend on itself. This ensures the dependency resolution algorithm can process containers in a valid topological order.

Parameters:

  • useComposeDependsOn: Whether to include Docker Compose depends_on label in dependency resolution.

Returns:

  • []string: List of linked container names with self-references removed.

func (*Container) Name

func (c *Container) Name() string

Name returns the normalized name of the container.

Returns:

  • string: Normalized container name.

func (*Container) PostUpdateTimeout

func (c *Container) PostUpdateTimeout() int

PostUpdateTimeout returns the post-update command timeout in minutes.

It defaults to 1 minute if unset or invalid. 0 allows indefinite execution.

Returns:

  • int: Timeout in minutes.

func (*Container) PreUpdateTimeout

func (c *Container) PreUpdateTimeout() int

PreUpdateTimeout returns the pre-update command timeout in minutes.

It defaults to 1 minute if unset or invalid. 0 allows indefinite execution.

Returns:

  • int: Timeout in minutes.

func (*Container) Scope

func (c *Container) Scope() (string, bool)

Scope retrieves the monitoring scope from labels.

Returns:

  • string: Scope value if set, empty otherwise.
  • bool: True if label is set, false if absent.

func (*Container) SetImageName

func (c *Container) SetImageName(name string)

SetImageName updates Config.Image and the cached image name used by ImageName.

An untagged name receives a ":latest" suffix so ImageName stays consistent with resolveImageName. Registry host ports are not treated as tags.

Parameters:

  • name: Image reference to store.

func (*Container) SetLinkedToRestarting

func (c *Container) SetLinkedToRestarting(value bool)

SetLinkedToRestarting sets the linked-to-restarting state.

Parameters:

  • value: New state value.

func (*Container) SetOldImageID

func (c *Container) SetOldImageID(id types.ImageID)

SetOldImageID sets the old image ID for cleanup tracking.

Parameters:

  • id: The old image ID.

func (*Container) SetStale

func (c *Container) SetStale(value bool)

SetStale marks the container as having an outdated image.

Parameters:

  • value: New stale value.

func (*Container) StopSignal

func (c *Container) StopSignal() string

StopSignal returns the custom stop signal from labels or HostConfig.

Returns:

  • string: Signal value, defaulting to "SIGTERM" if unset.

func (*Container) StopTimeout

func (c *Container) StopTimeout() *int

StopTimeout returns the container's configured stop timeout in seconds.

Returns:

  • *int: Timeout in seconds if set, nil if unset.

func (*Container) ToRestart

func (c *Container) ToRestart() bool

ToRestart determines if the container should be restarted.

Returns:

  • bool: True if stale or linked to restarting, false otherwise.

func (*Container) VerifyConfiguration

func (c *Container) VerifyConfiguration() error

VerifyConfiguration validates the container's metadata for recreation.

Returns:

  • error: Non-nil if metadata is missing or invalid, nil on success.

type CooldownError

type CooldownError struct {
	Age        string
	Delay      string
	Remaining  string
	EligibleAt time.Time
	Passed     bool
	// contains filtered or unexported fields
}

CooldownError represents a cooldown deferral with human-readable details (age, delay, remaining) and whether the window passed. It wraps ErrImageCooldown (or a fetch failure) so callers can use errors.Is/As while still extracting the fields needed for progress reports and rich notifications.

func (*CooldownError) Error

func (e *CooldownError) Error() string

func (*CooldownError) Is

func (e *CooldownError) Is(target error) bool

func (*CooldownError) Unwrap

func (e *CooldownError) Unwrap() error

type DockerConnectionConfig

type DockerConnectionConfig struct {
	// Host is the DOCKER_HOST value (e.g., "unix:///var/run/docker.sock", "tcp://host:2375").
	Host string
	// TLSVerify indicates whether TLS verification is enabled ("1" or empty).
	TLSVerify string
	// CertPath is the path to TLS certificates for remote connections.
	CertPath string
	// APIVersion is the pinned Docker API version (empty for autonegotiation).
	APIVersion string
	// IsLocal indicates whether the connection is to a local socket or named pipe.
	IsLocal bool
	// SocketBind is the socket bind mount string for local connections (e.g., "/var/run/docker.sock:/var/run/docker.sock").
	// Empty for remote connections.
	SocketBind string
	// CertBinds are additional bind mounts for TLS certificate directories.
	// Only populated for remote TLS connections where certificates need to be mounted.
	CertBinds []string
}

DockerConnectionConfig holds the Docker connection configuration extracted from a source container's environment variables and bind mounts. This enables the ephemeral orchestrator to maintain the same Docker connection as the source container, supporting local sockets, Windows named pipes, remote TCP/TLS hosts, and socket proxies.

type Operations

Operations defines the minimal interface for container operations in Watchtower.

type Runtime

type Runtime int

Runtime represents the type of container runtime detected.

const (
	// RuntimeUnknown indicates no container runtime has been detected.
	RuntimeUnknown Runtime = iota
	// RuntimeDocker indicates Docker is the container runtime.
	RuntimeDocker
	// RuntimePodman indicates Podman is the container runtime.
	RuntimePodman
)

type WarningStrategy

type WarningStrategy string

WarningStrategy defines the policy for logging warnings when HEAD requests fail during image pulls.

It allows configuration of verbosity:

  • "always" logs all failures
  • "never" suppresses them
  • "auto" delegates to registry-specific logic (e.g., WarnOnAPIConsumption).
const (
	// WarnAlways indicates warnings should always be logged for HEAD request failures.
	WarnAlways WarningStrategy = "always"
	// WarnNever indicates warnings should never be logged for HEAD request failures.
	WarnNever WarningStrategy = "never"
	// WarnAuto indicates warnings should be logged for HEAD request failures based on registry heuristics.
	WarnAuto WarningStrategy = "auto"
)

Warning strategies for HEAD request failures.

Directories

Path Synopsis
Package mocks provides hand-written HTTP API fixtures and Mockery-generated doubles for container package tests.
Package mocks provides hand-written HTTP API fixtures and Mockery-generated doubles for container package tests.

Jump to

Keyboard shortcuts

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