spud/podman/main.go
Marc Cataford a11bbe2eec
Some checks failed
/ build (push) Has been cancelled
feat: add port type support
2024-09-27 00:03:20 -04:00

164 lines
3.5 KiB
Go

// The Podman package handles any interactions with Podman entities or state.
package podman
import (
"log"
"os"
"os/exec"
service_definition "spud/service_definition"
)
// Creates a Podman volume of name `name` if it does not exist.
//
// If the volume exists, then behaviour depends on `existsOk`:
// - If `existsOk` is truthy, then the already-exists error is ignored and
// nothing is done;
// - Else, an error is returned.
func CreateVolume(name string, existsOk bool) error {
args := []string{"volume", "create", name}
if existsOk {
args = append(args, "--ignore")
}
command := exec.Command("podman", args...)
if err := command.Run(); err != nil {
return err
}
log.Printf("✅ Created volume \"%s\".", name)
return nil
}
// Creates a Podman pod to keep related containers together.
//
// The pod created will expose ports necessary for individual containers
// to be accessible from the host.
func CreatePod(name string, ports []service_definition.PortMapping) error {
args := []string{"pod", "create", "--replace"}
for _, portMapping := range ports {
portMapStr := portMapping.Host + ":" + portMapping.Container
if portMapping.Type != "" {
portMapStr = portMapStr + "/" + portMapping.Type
}
portArgs := []string{"-p", portMapStr}
args = append(args, portArgs...)
}
args = append(args, name)
command := exec.Command("podman", args...)
if err := command.Run(); err != nil {
return err
}
log.Printf("✅ Created pod \"%s\".", name)
return nil
}
// Stops a running pod.
func StopPod(name string) error {
args := []string{"pod", "stop", name}
command := exec.Command("podman", args...)
if err := command.Run(); err != nil {
return err
}
log.Printf("✅ Stopped pod \"%s\" and child containers.", name)
return nil
}
// Creates individual containers.
//
// Individual containers do not expose any ports by themselves, these
// are handled by the pod that wraps the containers.
func CreateContainer(definition service_definition.ContainerDefinition, knownVolumes map[string]string, service string) error {
namespacedContainerName := service + "_" + definition.Name
args := []string{
"run",
"-d",
"--name",
namespacedContainerName,
"--pod",
service,
"--replace",
}
if definition.EnvFile != "" {
args = append(args, []string{"--env-file", definition.EnvFile}...)
}
for _, volume := range definition.Volumes {
var host string
var suffix string
container := volume.Container
if volume.Name != "" {
namespacedName := service + "_" + volume.Name
host = namespacedName
} else if volume.Host != "" {
host = volume.Host
} else {
log.Fatal("Invalid volume source configuration")
}
if volume.ReadOnly == true {
suffix = ":ro"
}
arg := []string{"-v", host + ":" + container + suffix}
args = append(args, arg...)
}
args = append(args, definition.Image)
for _, extra := range definition.ExtraArgs {
args = append(args, extra)
}
command := exec.Command("podman", args...)
if err := command.Start(); err != nil {
log.Fatal("Failed to start")
return err
}
if err := command.Wait(); err != nil {
log.Fatal(args)
return err
}
log.Printf("✅ Started container \"%s\".", namespacedContainerName)
return nil
}
// Builds a container image.
func Build(imageDefinition service_definition.BuildImage) error {
args := []string{"build", "-f", imageDefinition.Path, "-t", imageDefinition.TagPrefix}
command := exec.Command("podman", args...)
command.Stdout = os.Stdout
command.Stderr = os.Stderr
if err := command.Run(); err != nil {
return err
}
return nil
}