github.com/containers/podman/v4@v4.9.4/libpod/runtime_pod_linux.go (about) 1 //go:build !remote 2 // +build !remote 3 4 package libpod 5 6 import ( 7 "fmt" 8 "path" 9 "path/filepath" 10 "strings" 11 12 "github.com/containers/common/pkg/cgroups" 13 "github.com/containers/common/pkg/config" 14 "github.com/containers/podman/v4/libpod/define" 15 "github.com/containers/podman/v4/pkg/rootless" 16 "github.com/containers/podman/v4/utils" 17 spec "github.com/opencontainers/runtime-spec/specs-go" 18 "github.com/sirupsen/logrus" 19 ) 20 21 func (r *Runtime) platformMakePod(pod *Pod, resourceLimits *spec.LinuxResources) (string, error) { 22 cgroupParent := "" 23 // Check Cgroup parent sanity, and set it if it was not set 24 if r.config.Cgroups() != "disabled" { 25 switch r.config.Engine.CgroupManager { 26 case config.CgroupfsCgroupsManager: 27 canUseCgroup := !rootless.IsRootless() || isRootlessCgroupSet(pod.config.CgroupParent) 28 if canUseCgroup { 29 // need to actually create parent here 30 if pod.config.CgroupParent == "" { 31 pod.config.CgroupParent = CgroupfsDefaultCgroupParent 32 } else if strings.HasSuffix(path.Base(pod.config.CgroupParent), ".slice") { 33 return "", fmt.Errorf("systemd slice received as cgroup parent when using cgroupfs: %w", define.ErrInvalidArg) 34 } 35 // If we are set to use pod cgroups, set the cgroup parent that 36 // all containers in the pod will share 37 if pod.config.UsePodCgroup { 38 pod.state.CgroupPath = filepath.Join(pod.config.CgroupParent, pod.ID()) 39 cgroupParent = pod.state.CgroupPath 40 // cgroupfs + rootless = permission denied when creating the cgroup. 41 if !rootless.IsRootless() { 42 res, err := GetLimits(resourceLimits) 43 if err != nil { 44 return "", err 45 } 46 res.SkipDevices = true 47 // Need to both create and update the cgroup 48 // rather than create a new path in c/common for pod cgroup creation 49 // just create as if it is a ctr and then update figures out that we need to 50 // populate the resource limits on the pod level 51 cgc, err := cgroups.New(pod.state.CgroupPath, &res) 52 if err != nil { 53 return "", err 54 } 55 err = cgc.Update(&res) 56 if err != nil { 57 return "", err 58 } 59 } 60 } 61 } 62 case config.SystemdCgroupsManager: 63 if pod.config.CgroupParent == "" { 64 if rootless.IsRootless() { 65 pod.config.CgroupParent = SystemdDefaultRootlessCgroupParent 66 } else { 67 pod.config.CgroupParent = SystemdDefaultCgroupParent 68 } 69 } else if len(pod.config.CgroupParent) < 6 || !strings.HasSuffix(path.Base(pod.config.CgroupParent), ".slice") { 70 return "", fmt.Errorf("did not receive systemd slice as cgroup parent when using systemd to manage cgroups: %w", define.ErrInvalidArg) 71 } 72 // If we are set to use pod cgroups, set the cgroup parent that 73 // all containers in the pod will share 74 if pod.config.UsePodCgroup { 75 cgroupPath, err := systemdSliceFromPath(pod.config.CgroupParent, fmt.Sprintf("libpod_pod_%s", pod.ID()), resourceLimits) 76 if err != nil { 77 return "", fmt.Errorf("unable to create pod cgroup for pod %s: %w", pod.ID(), err) 78 } 79 pod.state.CgroupPath = cgroupPath 80 cgroupParent = pod.state.CgroupPath 81 } 82 default: 83 return "", fmt.Errorf("unsupported Cgroup manager: %s - cannot validate cgroup parent: %w", r.config.Engine.CgroupManager, define.ErrInvalidArg) 84 } 85 } 86 87 if pod.config.UsePodCgroup { 88 logrus.Debugf("Got pod cgroup as %s", pod.state.CgroupPath) 89 } 90 91 return cgroupParent, nil 92 } 93 94 func (p *Pod) removePodCgroup() error { 95 // Remove pod cgroup, if present 96 if p.state.CgroupPath == "" { 97 return nil 98 } 99 logrus.Debugf("Removing pod cgroup %s", p.state.CgroupPath) 100 101 cgroup, err := utils.GetOwnCgroup() 102 if err != nil { 103 return err 104 } 105 106 // if we are trying to delete a cgroup that is our ancestor, we need to move the 107 // current process out of it before the cgroup is destroyed. 108 if isSubDir(cgroup, string(filepath.Separator)+p.state.CgroupPath) { 109 parent := path.Dir(p.state.CgroupPath) 110 if err := utils.MoveUnderCgroup(parent, "cleanup", nil); err != nil { 111 return err 112 } 113 } 114 115 switch p.runtime.config.Engine.CgroupManager { 116 case config.SystemdCgroupsManager: 117 if err := deleteSystemdCgroup(p.state.CgroupPath, p.ResourceLim()); err != nil { 118 return fmt.Errorf("removing pod %s cgroup: %w", p.ID(), err) 119 } 120 case config.CgroupfsCgroupsManager: 121 // Delete the cgroupfs cgroup 122 // Make sure the conmon cgroup is deleted first 123 // Since the pod is almost gone, don't bother failing 124 // hard - instead, just log errors. 125 conmonCgroupPath := filepath.Join(p.state.CgroupPath, "conmon") 126 conmonCgroup, err := cgroups.Load(conmonCgroupPath) 127 if err != nil && err != cgroups.ErrCgroupDeleted && err != cgroups.ErrCgroupV1Rootless { 128 return fmt.Errorf("retrieving pod %s conmon cgroup: %w", p.ID(), err) 129 } 130 if err == nil { 131 if err = conmonCgroup.Delete(); err != nil { 132 return fmt.Errorf("removing pod %s conmon cgroup: %w", p.ID(), err) 133 } 134 } 135 cgroup, err := cgroups.Load(p.state.CgroupPath) 136 if err != nil && err != cgroups.ErrCgroupDeleted && err != cgroups.ErrCgroupV1Rootless { 137 return fmt.Errorf("retrieving pod %s cgroup: %w", p.ID(), err) 138 } 139 if err == nil { 140 if err := cgroup.Delete(); err != nil { 141 return fmt.Errorf("removing pod %s cgroup: %w", p.ID(), err) 142 } 143 } 144 default: 145 // This should be caught much earlier, but let's still 146 // keep going so we make sure to evict the pod before 147 // ending up with an inconsistent state. 148 return fmt.Errorf("unrecognized cgroup manager %s when removing pod %s cgroups: %w", p.runtime.config.Engine.CgroupManager, p.ID(), define.ErrInternal) 149 } 150 return nil 151 }