Files
DockMV/internal/spec/spec.go
T
2026-08-11 09:00:01 +02:00

215 lines
9.1 KiB
Go

// Package spec defines a normalized, JSON-serializable description of a Docker
// container and everything it needs to be recreated on another host.
//
// The spec is deliberately independent of the Docker SDK types: it is produced
// on the source host, travels over SSH or inside an offline migration package,
// and is consumed either by the SSH engine or by a generated shell script that
// only has the docker CLI available.
package spec
// MountKind classifies a data location attached to a container.
type MountKind string
const (
MountVolume MountKind = "volume" // named volume
MountAnonymous MountKind = "anonymous" // volume with a generated name
MountBind MountKind = "bind" // host directory or file
MountTmpfs MountKind = "tmpfs" // in-memory, never carries data
)
// Mount is one data location attached to a container.
type Mount struct {
Kind MountKind `json:"kind"`
Name string `json:"name,omitempty"` // volume name (volume kind only)
Source string `json:"source,omitempty"` // host path (bind kind only)
Destination string `json:"destination"` // path inside the container
ReadOnly bool `json:"readOnly"`
Propagation string `json:"propagation,omitempty"`
TmpfsOpts string `json:"tmpfsOpts,omitempty"`
// SizeBytes is a best-effort measurement of the data at this location,
// used to show progress and to warn about very large transfers. -1 = unknown.
SizeBytes int64 `json:"sizeBytes"`
}
// HasData reports whether this mount is worth copying. tmpfs never is.
func (m Mount) HasData() bool { return m.Kind != MountTmpfs }
// Volume describes a named volume so it can be recreated with the same driver,
// options and labels rather than falling back to a plain local volume.
type Volume struct {
Name string `json:"name"`
Driver string `json:"driver"`
DriverOpts map[string]string `json:"driverOpts,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
}
// IPAMPool is one subnet definition of a user-defined network.
type IPAMPool struct {
Subnet string `json:"subnet,omitempty"`
IPRange string `json:"ipRange,omitempty"`
Gateway string `json:"gateway,omitempty"`
AuxAddress map[string]string `json:"auxAddress,omitempty"`
}
// Network describes a user-defined network to recreate on the target.
type Network struct {
Name string `json:"name"`
Driver string `json:"driver"`
Scope string `json:"scope,omitempty"`
EnableIPv6 bool `json:"enableIPv6,omitempty"`
Internal bool `json:"internal,omitempty"`
Attachable bool `json:"attachable,omitempty"`
Ingress bool `json:"ingress,omitempty"`
IPAMDriver string `json:"ipamDriver,omitempty"`
IPAMPools []IPAMPool `json:"ipamPools,omitempty"`
Options map[string]string `json:"options,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
}
// Endpoint is a container's attachment to one network.
type Endpoint struct {
Network string `json:"network"`
Aliases []string `json:"aliases,omitempty"`
IPv4Address string `json:"ipv4Address,omitempty"`
IPv6Address string `json:"ipv6Address,omitempty"`
MacAddress string `json:"macAddress,omitempty"`
Links []string `json:"links,omitempty"`
DriverOpts map[string]string `json:"driverOpts,omitempty"`
}
// PortBinding maps a container port onto the host.
type PortBinding struct {
ContainerPort string `json:"containerPort"` // e.g. "80/tcp"
HostIP string `json:"hostIp,omitempty"`
HostPort string `json:"hostPort,omitempty"`
}
// Healthcheck mirrors the container health configuration when it was
// overridden at run time (an image-provided healthcheck is not re-emitted).
type Healthcheck struct {
Test []string `json:"test,omitempty"`
Interval int64 `json:"interval,omitempty"` // nanoseconds
Timeout int64 `json:"timeout,omitempty"` // nanoseconds
StartPeriod int64 `json:"startPeriod,omitempty"` // nanoseconds
Retries int `json:"retries,omitempty"`
}
// Resources holds the cgroup limits applied to the container.
type Resources struct {
Memory int64 `json:"memory,omitempty"`
MemoryReservation int64 `json:"memoryReservation,omitempty"`
MemorySwap int64 `json:"memorySwap,omitempty"`
MemorySwappiness *int64 `json:"memorySwappiness,omitempty"`
NanoCPUs int64 `json:"nanoCpus,omitempty"`
CPUShares int64 `json:"cpuShares,omitempty"`
CPUPeriod int64 `json:"cpuPeriod,omitempty"`
CPUQuota int64 `json:"cpuQuota,omitempty"`
CpusetCpus string `json:"cpusetCpus,omitempty"`
CpusetMems string `json:"cpusetMems,omitempty"`
PidsLimit *int64 `json:"pidsLimit,omitempty"`
OomKillDisable *bool `json:"oomKillDisable,omitempty"`
OomScoreAdj int `json:"oomScoreAdj,omitempty"`
ShmSize int64 `json:"shmSize,omitempty"`
}
// Ulimit is a per-container resource limit.
type Ulimit struct {
Name string `json:"name"`
Soft int64 `json:"soft"`
Hard int64 `json:"hard"`
}
// Device is a host device exposed to the container.
type Device struct {
PathOnHost string `json:"pathOnHost"`
PathInContainer string `json:"pathInContainer"`
CgroupPermissions string `json:"cgroupPermissions"`
}
// Container is the full normalized description of one container.
type Container struct {
ID string `json:"id"`
Name string `json:"name"` // without the leading slash
State string `json:"state"` // running, exited, ...
Image string `json:"image"` // reference as the user wrote it, e.g. nginx:1.27
ImageID string `json:"imageId"` // sha256:...
ImageDigest string `json:"imageDigest,omitempty"`
// Compose grouping, taken from the standard compose labels. Empty when the
// container was not created by docker compose.
ComposeProject string `json:"composeProject,omitempty"`
ComposeService string `json:"composeService,omitempty"`
Hostname string `json:"hostname,omitempty"`
Domainname string `json:"domainname,omitempty"`
User string `json:"user,omitempty"`
WorkingDir string `json:"workingDir,omitempty"`
Env []string `json:"env,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Cmd []string `json:"cmd,omitempty"`
Entrypoint []string `json:"entrypoint,omitempty"`
EntrypointSet bool `json:"entrypointSet,omitempty"` // true when overridden at run time
CmdSet bool `json:"cmdSet,omitempty"`
Tty bool `json:"tty,omitempty"`
OpenStdin bool `json:"openStdin,omitempty"`
StopSignal string `json:"stopSignal,omitempty"`
StopTimeout *int `json:"stopTimeout,omitempty"`
Init *bool `json:"init,omitempty"`
RestartPolicy string `json:"restartPolicy,omitempty"`
RestartMaxRetries int `json:"restartMaxRetries,omitempty"`
AutoRemove bool `json:"autoRemove,omitempty"`
Privileged bool `json:"privileged,omitempty"`
ReadonlyRootfs bool `json:"readonlyRootfs,omitempty"`
CapAdd []string `json:"capAdd,omitempty"`
CapDrop []string `json:"capDrop,omitempty"`
SecurityOpt []string `json:"securityOpt,omitempty"`
GroupAdd []string `json:"groupAdd,omitempty"`
Sysctls map[string]string `json:"sysctls,omitempty"`
Devices []Device `json:"devices,omitempty"`
Ulimits []Ulimit `json:"ulimits,omitempty"`
Runtime string `json:"runtime,omitempty"`
PidMode string `json:"pidMode,omitempty"`
IpcMode string `json:"ipcMode,omitempty"`
UtsMode string `json:"utsMode,omitempty"`
UsernsMode string `json:"usernsMode,omitempty"`
CgroupnsMode string `json:"cgroupnsMode,omitempty"`
DNS []string `json:"dns,omitempty"`
DNSSearch []string `json:"dnsSearch,omitempty"`
DNSOptions []string `json:"dnsOptions,omitempty"`
ExtraHosts []string `json:"extraHosts,omitempty"`
NetworkMode string `json:"networkMode,omitempty"` // bridge, host, none, <name>, container:<id>
Endpoints []Endpoint `json:"endpoints,omitempty"`
Ports []PortBinding `json:"ports,omitempty"`
ExposedPorts []string `json:"exposedPorts,omitempty"`
PublishAll bool `json:"publishAll,omitempty"`
Mounts []Mount `json:"mounts,omitempty"`
LogDriver string `json:"logDriver,omitempty"`
LogOptions map[string]string `json:"logOptions,omitempty"`
Healthcheck *Healthcheck `json:"healthcheck,omitempty"`
Resources Resources `json:"resources"`
// Warnings collected while reading the container, surfaced in the UI.
Warnings []string `json:"warnings,omitempty"`
}
// DataMounts returns the mounts that actually carry data.
func (c *Container) DataMounts() []Mount {
out := make([]Mount, 0, len(c.Mounts))
for _, m := range c.Mounts {
if m.HasData() {
out = append(out, m)
}
}
return out
}