package runtime import ( "context" "strings" ) // ContainerSpec describes a container to create and run. type ContainerSpec struct { Name string // container name, format: - Image string // full image reference Network string // docker network name User string // container user (e.g., "0:0") Restart string // restart policy (e.g., "unless-stopped") Ports []string // "host:container" port mappings Volumes []string // "host:container" volume mounts Cmd []string // command and arguments } // ContainerInfo describes the observed state of a running or stopped container. type ContainerInfo struct { Name string Image string State string // "running", "stopped", "exited", etc. Network string User string Restart string Ports []string Volumes []string Cmd []string Version string // extracted from image tag } // Runtime is the container runtime abstraction. type Runtime interface { Pull(ctx context.Context, image string) error Run(ctx context.Context, spec ContainerSpec) error Stop(ctx context.Context, name string) error Remove(ctx context.Context, name string) error Inspect(ctx context.Context, name string) (ContainerInfo, error) List(ctx context.Context) ([]ContainerInfo, error) } // ExtractVersion parses the tag from an image reference. // Examples: // // "registry/img:v1.2.0" -> "v1.2.0" // "registry/img:latest" -> "latest" // "registry/img" -> "" // "registry:5000/img:v1" -> "v1" func ExtractVersion(image string) string { // Strip registry/path prefix so that a port like "registry:5000" isn't // mistaken for a tag separator. name := image if i := strings.LastIndex(image, "/"); i >= 0 { name = image[i+1:] } if i := strings.LastIndex(name, ":"); i >= 0 { return name[i+1:] } return "" }