File: runtime_pod_linux.go

package info (click to toggle)
podman 5.4.2%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 23,124 kB
  • sloc: sh: 6,119; perl: 2,710; python: 2,258; ansic: 1,556; makefile: 1,022; xml: 121; ruby: 42; awk: 12; csh: 8
file content (149 lines) | stat: -rw-r--r-- 5,520 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//go:build !remote

package libpod

import (
	"fmt"
	"path"
	"path/filepath"
	"strings"

	"github.com/containers/common/pkg/cgroups"
	"github.com/containers/common/pkg/config"
	"github.com/containers/podman/v5/libpod/define"
	"github.com/containers/podman/v5/pkg/rootless"
	spec "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/sirupsen/logrus"
)

func (r *Runtime) platformMakePod(pod *Pod, resourceLimits *spec.LinuxResources) (string, error) {
	cgroupParent := ""
	// Check Cgroup parent sanity, and set it if it was not set
	if r.config.Cgroups() != "disabled" {
		switch r.config.Engine.CgroupManager {
		case config.CgroupfsCgroupsManager:
			canUseCgroup := !rootless.IsRootless() || isRootlessCgroupSet(pod.config.CgroupParent)
			if canUseCgroup {
				// need to actually create parent here
				if pod.config.CgroupParent == "" {
					pod.config.CgroupParent = CgroupfsDefaultCgroupParent
				} else if strings.HasSuffix(path.Base(pod.config.CgroupParent), ".slice") {
					return "", fmt.Errorf("systemd slice received as cgroup parent when using cgroupfs: %w", define.ErrInvalidArg)
				}
				// If we are set to use pod cgroups, set the cgroup parent that
				// all containers in the pod will share
				if pod.config.UsePodCgroup {
					pod.state.CgroupPath = filepath.Join(pod.config.CgroupParent, pod.ID())
					cgroupParent = pod.state.CgroupPath
					// cgroupfs + rootless = permission denied when creating the cgroup.
					if !rootless.IsRootless() {
						res, err := GetLimits(resourceLimits)
						if err != nil {
							return "", err
						}
						res.SkipDevices = true
						// Need to both create and update the cgroup
						// rather than create a new path in c/common for pod cgroup creation
						// just create as if it is a ctr and then update figures out that we need to
						// populate the resource limits on the pod level
						cgc, err := cgroups.New(pod.state.CgroupPath, &res)
						if err != nil {
							return "", err
						}
						err = cgc.Update(&res)
						if err != nil {
							return "", err
						}
					}
				}
			}
		case config.SystemdCgroupsManager:
			if pod.config.CgroupParent == "" {
				if rootless.IsRootless() {
					pod.config.CgroupParent = SystemdDefaultRootlessCgroupParent
				} else {
					pod.config.CgroupParent = SystemdDefaultCgroupParent
				}
			} else if len(pod.config.CgroupParent) < 6 || !strings.HasSuffix(path.Base(pod.config.CgroupParent), ".slice") {
				return "", fmt.Errorf("did not receive systemd slice as cgroup parent when using systemd to manage cgroups: %w", define.ErrInvalidArg)
			}
			// If we are set to use pod cgroups, set the cgroup parent that
			// all containers in the pod will share
			if pod.config.UsePodCgroup {
				cgroupPath, err := systemdSliceFromPath(pod.config.CgroupParent, fmt.Sprintf("libpod_pod_%s", pod.ID()), resourceLimits)
				if err != nil {
					return "", fmt.Errorf("unable to create pod cgroup for pod %s: %w", pod.ID(), err)
				}
				pod.state.CgroupPath = cgroupPath
				cgroupParent = pod.state.CgroupPath
			}
		default:
			return "", fmt.Errorf("unsupported Cgroup manager: %s - cannot validate cgroup parent: %w", r.config.Engine.CgroupManager, define.ErrInvalidArg)
		}
	}

	if pod.config.UsePodCgroup {
		logrus.Debugf("Got pod cgroup as %s", pod.state.CgroupPath)
	}

	return cgroupParent, nil
}

func (p *Pod) removePodCgroup() error {
	// Remove pod cgroup, if present
	if p.state.CgroupPath == "" {
		return nil
	}
	logrus.Debugf("Removing pod cgroup %s", p.state.CgroupPath)

	cgroup, err := cgroups.GetOwnCgroup()
	if err != nil {
		return err
	}

	// if we are trying to delete a cgroup that is our ancestor, we need to move the
	// current process out of it before the cgroup is destroyed.
	if isSubDir(cgroup, string(filepath.Separator)+p.state.CgroupPath) {
		parent := path.Dir(p.state.CgroupPath)
		if err := cgroups.MoveUnderCgroup(parent, "cleanup", nil); err != nil {
			return err
		}
	}

	switch p.runtime.config.Engine.CgroupManager {
	case config.SystemdCgroupsManager:
		if err := deleteSystemdCgroup(p.state.CgroupPath, p.ResourceLim()); err != nil {
			return fmt.Errorf("removing pod %s cgroup: %w", p.ID(), err)
		}
	case config.CgroupfsCgroupsManager:
		// Delete the cgroupfs cgroup
		// Make sure the conmon cgroup is deleted first
		// Since the pod is almost gone, don't bother failing
		// hard - instead, just log errors.
		conmonCgroupPath := filepath.Join(p.state.CgroupPath, "conmon")
		conmonCgroup, err := cgroups.Load(conmonCgroupPath)
		if err != nil && err != cgroups.ErrCgroupDeleted && err != cgroups.ErrCgroupV1Rootless {
			return fmt.Errorf("retrieving pod %s conmon cgroup: %w", p.ID(), err)
		}
		if err == nil {
			if err = conmonCgroup.Delete(); err != nil {
				return fmt.Errorf("removing pod %s conmon cgroup: %w", p.ID(), err)
			}
		}
		cgroup, err := cgroups.Load(p.state.CgroupPath)
		if err != nil && err != cgroups.ErrCgroupDeleted && err != cgroups.ErrCgroupV1Rootless {
			return fmt.Errorf("retrieving pod %s cgroup: %w", p.ID(), err)
		}
		if err == nil {
			if err := cgroup.Delete(); err != nil {
				return fmt.Errorf("removing pod %s cgroup: %w", p.ID(), err)
			}
		}
	default:
		// This should be caught much earlier, but let's still
		// keep going so we make sure to evict the pod before
		// ending up with an inconsistent state.
		return fmt.Errorf("unrecognized cgroup manager %s when removing pod %s cgroups: %w", p.runtime.config.Engine.CgroupManager, p.ID(), define.ErrInternal)
	}
	return nil
}