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  }