diff options
Diffstat (limited to 'pkg/specgen')
-rw-r--r-- | pkg/specgen/generate/container.go | 150 | ||||
-rw-r--r-- | pkg/specgen/generate/container_create.go | 39 | ||||
-rw-r--r-- | pkg/specgen/generate/oci.go | 9 | ||||
-rw-r--r-- | pkg/specgen/generate/pod_create.go | 2 |
4 files changed, 197 insertions, 3 deletions
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index a4d862a60..64669f34d 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -2,6 +2,7 @@ package generate import ( "context" + "encoding/json" "os" "strings" "time" @@ -335,3 +336,152 @@ func FinishThrottleDevices(s *specgen.SpecGenerator) error { } return nil } + +// ConfigToSpec takes a completed container config and converts it back into a specgenerator for purposes of cloning an exisiting container +func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, contaierID string) (*libpod.Container, error) { + c, err := rt.LookupContainer(contaierID) + if err != nil { + return nil, err + } + conf := c.Config() + + tmpSystemd := conf.Systemd + tmpMounts := conf.Mounts + + conf.Systemd = nil + conf.Mounts = []string{} + + specg.Pod = conf.Pod + + matching, err := json.Marshal(conf) + if err != nil { + return nil, err + } + + err = json.Unmarshal(matching, specg) + if err != nil { + return nil, err + } + conf.Systemd = tmpSystemd + conf.Mounts = tmpMounts + + if conf.Spec != nil && conf.Spec.Linux != nil && conf.Spec.Linux.Resources != nil { + if specg.ResourceLimits == nil { + specg.ResourceLimits = conf.Spec.Linux.Resources + } + } + + nameSpaces := []string{"pid", "net", "cgroup", "ipc", "uts", "user"} + containers := []string{conf.PIDNsCtr, conf.NetNsCtr, conf.CgroupNsCtr, conf.IPCNsCtr, conf.UTSNsCtr, conf.UserNsCtr} + place := []*specgen.Namespace{&specg.PidNS, &specg.NetNS, &specg.CgroupNS, &specg.IpcNS, &specg.UtsNS, &specg.UserNS} + for i, ns := range containers { + if len(ns) > 0 { + ns := specgen.Namespace{NSMode: specgen.FromContainer, Value: ns} + place[i] = &ns + } else { + switch nameSpaces[i] { + case "pid": + specg.PidNS = specgen.Namespace{NSMode: specgen.Default} //default + case "net": + switch { + case conf.NetMode.IsBridge(): + toExpose := make(map[uint16]string, len(conf.ExposedPorts)) + for _, expose := range []map[uint16][]string{conf.ExposedPorts} { + for port, proto := range expose { + toExpose[port] = strings.Join(proto, ",") + } + } + specg.Expose = toExpose + specg.PortMappings = conf.PortMappings + specg.NetNS = specgen.Namespace{NSMode: specgen.Bridge} + case conf.NetMode.IsSlirp4netns(): + toExpose := make(map[uint16]string, len(conf.ExposedPorts)) + for _, expose := range []map[uint16][]string{conf.ExposedPorts} { + for port, proto := range expose { + toExpose[port] = strings.Join(proto, ",") + } + } + specg.Expose = toExpose + specg.PortMappings = conf.PortMappings + netMode := strings.Split(string(conf.NetMode), ":") + var val string + if len(netMode) > 1 { + val = netMode[1] + } + specg.NetNS = specgen.Namespace{NSMode: specgen.Slirp, Value: val} + case conf.NetMode.IsPrivate(): + specg.NetNS = specgen.Namespace{NSMode: specgen.Private} + case conf.NetMode.IsDefault(): + specg.NetNS = specgen.Namespace{NSMode: specgen.Default} + case conf.NetMode.IsUserDefined(): + specg.NetNS = specgen.Namespace{NSMode: specgen.Path, Value: strings.Split(string(conf.NetMode), ":")[1]} + case conf.NetMode.IsContainer(): + specg.NetNS = specgen.Namespace{NSMode: specgen.FromContainer, Value: strings.Split(string(conf.NetMode), ":")[1]} + case conf.NetMode.IsPod(): + specg.NetNS = specgen.Namespace{NSMode: specgen.FromPod, Value: strings.Split(string(conf.NetMode), ":")[1]} + } + case "cgroup": + specg.CgroupNS = specgen.Namespace{NSMode: specgen.Default} //default + case "ipc": + if conf.ShmDir == "/dev/shm" { + specg.IpcNS = specgen.Namespace{NSMode: specgen.Host} + } else { + specg.IpcNS = specgen.Namespace{NSMode: specgen.Default} //default + } + case "uts": + specg.UtsNS = specgen.Namespace{NSMode: specgen.Default} //default + case "user": + if conf.AddCurrentUserPasswdEntry { + specg.UserNS = specgen.Namespace{NSMode: specgen.KeepID} + } else { + specg.UserNS = specgen.Namespace{NSMode: specgen.Default} //default + } + } + } + } + + specg.IDMappings = &conf.IDMappings + specg.ContainerCreateCommand = conf.CreateCommand + if len(specg.Rootfs) == 0 { + specg.Rootfs = conf.Rootfs + } + if len(specg.Image) == 0 { + specg.Image = conf.RootfsImageID + } + var named []*specgen.NamedVolume + if len(conf.NamedVolumes) != 0 { + for _, v := range conf.NamedVolumes { + named = append(named, &specgen.NamedVolume{ + Name: v.Name, + Dest: v.Dest, + Options: v.Options, + }) + } + } + specg.Volumes = named + var image []*specgen.ImageVolume + if len(conf.ImageVolumes) != 0 { + for _, v := range conf.ImageVolumes { + image = append(image, &specgen.ImageVolume{ + Source: v.Source, + Destination: v.Dest, + ReadWrite: v.ReadWrite, + }) + } + } + specg.ImageVolumes = image + var overlay []*specgen.OverlayVolume + if len(conf.OverlayVolumes) != 0 { + for _, v := range conf.OverlayVolumes { + overlay = append(overlay, &specgen.OverlayVolume{ + Source: v.Source, + Destination: v.Dest, + Options: v.Options, + }) + } + } + specg.OverlayVolumes = overlay + specg.Mounts = conf.Spec.Mounts + specg.HostDeviceList = conf.DeviceHostSrc + return c, nil +} diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index a7a7353d0..c0b23953f 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -8,6 +8,7 @@ import ( cdi "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi" "github.com/containers/common/libimage" + "github.com/containers/common/pkg/cgroups" "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/namespaces" @@ -22,7 +23,7 @@ import ( // MakeContainer creates a container based on the SpecGenerator. // Returns the created, container and any warnings resulting from creating the // container, or an error. -func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator) (*spec.Spec, *specgen.SpecGenerator, []libpod.CtrCreateOption, error) { +func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, clone bool, c *libpod.Container) (*spec.Spec, *specgen.SpecGenerator, []libpod.CtrCreateOption, error) { rtc, err := rt.GetConfigNoCopy() if err != nil { return nil, nil, nil, err @@ -170,6 +171,42 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener options = append(options, opts...) } runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts, pod, command, compatibleOptions) + if clone { // the container fails to start if cloned due to missing Linux spec entries + if c == nil { + return nil, nil, nil, errors.New("the given container could not be retrieved") + } + conf := c.Config() + out, err := json.Marshal(conf.Spec.Linux) + if err != nil { + return nil, nil, nil, err + } + err = json.Unmarshal(out, runtimeSpec.Linux) + if err != nil { + return nil, nil, nil, err + } + + switch { + case s.ResourceLimits.CPU != nil: + runtimeSpec.Linux.Resources.CPU = s.ResourceLimits.CPU + case s.ResourceLimits.Memory != nil: + runtimeSpec.Linux.Resources.Memory = s.ResourceLimits.Memory + case s.ResourceLimits.BlockIO != nil: + runtimeSpec.Linux.Resources.BlockIO = s.ResourceLimits.BlockIO + case s.ResourceLimits.Devices != nil: + runtimeSpec.Linux.Resources.Devices = s.ResourceLimits.Devices + } + + cgroup2, err := cgroups.IsCgroup2UnifiedMode() + if err != nil { + return nil, nil, nil, err + } + if cgroup2 && s.ResourceLimits.Memory != nil && s.ResourceLimits.Memory.Swappiness != nil { // conf.Spec.Linux contains memory swappiness established after the spec process we need to remove that + s.ResourceLimits.Memory.Swappiness = nil + if runtimeSpec.Linux.Resources.Memory != nil { + runtimeSpec.Linux.Resources.Memory.Swappiness = nil + } + } + } if err != nil { return nil, nil, nil, err } diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go index 945c994ea..8b3550e36 100644 --- a/pkg/specgen/generate/oci.go +++ b/pkg/specgen/generate/oci.go @@ -301,7 +301,14 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt } if compatibleOptions.InfraResources == nil && s.ResourceLimits != nil { - g.Config.Linux.Resources = s.ResourceLimits + out, err := json.Marshal(s.ResourceLimits) + if err != nil { + return nil, err + } + err = json.Unmarshal(out, g.Config.Linux.Resources) + if err != nil { + return nil, err + } } else if s.ResourceLimits != nil { // if we have predefined resource limits we need to make sure we keep the infra and container limits originalResources, err := json.Marshal(s.ResourceLimits) if err != nil { diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go index 68fda3ad7..8450fe7ce 100644 --- a/pkg/specgen/generate/pod_create.go +++ b/pkg/specgen/generate/pod_create.go @@ -135,7 +135,7 @@ func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) { return nil, err } p.PodSpecGen.InfraContainerSpec.User = "" // infraSpec user will get incorrectly assigned via the container creation process, overwrite here - rtSpec, spec, opts, err := MakeContainer(context.Background(), rt, p.PodSpecGen.InfraContainerSpec) + rtSpec, spec, opts, err := MakeContainer(context.Background(), rt, p.PodSpecGen.InfraContainerSpec, false, nil) if err != nil { return nil, err } |