2015-05-14 06:42:16 +08:00
|
|
|
// +build linux
|
|
|
|
|
2014-05-15 06:21:44 +08:00
|
|
|
package cgroups
|
|
|
|
|
|
|
|
import (
|
2014-08-21 01:32:01 +08:00
|
|
|
"fmt"
|
2014-02-18 07:14:30 +08:00
|
|
|
|
2015-06-22 10:29:59 +08:00
|
|
|
"github.com/opencontainers/runc/libcontainer/configs"
|
2014-05-15 06:21:44 +08:00
|
|
|
)
|
|
|
|
|
2015-01-13 05:54:00 +08:00
|
|
|
type Manager interface {
|
2016-03-25 11:11:48 +08:00
|
|
|
// Applies cgroup configuration to the process with the specified pid
|
2015-01-13 05:54:00 +08:00
|
|
|
Apply(pid int) error
|
|
|
|
|
2015-01-14 23:23:42 +08:00
|
|
|
// Returns the PIDs inside the cgroup set
|
2015-01-13 05:54:00 +08:00
|
|
|
GetPids() ([]int, error)
|
2015-01-14 23:23:42 +08:00
|
|
|
|
2016-01-09 03:37:18 +08:00
|
|
|
// Returns the PIDs inside the cgroup set & all sub-cgroups
|
|
|
|
GetAllPids() ([]int, error)
|
|
|
|
|
2015-01-14 23:23:42 +08:00
|
|
|
// Returns statistics for the cgroup set
|
2015-01-13 05:54:00 +08:00
|
|
|
GetStats() (*Stats, error)
|
|
|
|
|
2015-01-14 23:23:42 +08:00
|
|
|
// Toggles the freezer cgroup according with specified state
|
2015-02-01 11:56:27 +08:00
|
|
|
Freeze(state configs.FreezerState) error
|
2015-01-13 19:52:14 +08:00
|
|
|
|
2015-01-14 23:23:42 +08:00
|
|
|
// Destroys the cgroup set
|
|
|
|
Destroy() error
|
|
|
|
|
Simplify cgroup path handing in v2 via unified API
This unties the Gordian Knot of using GetPaths in cgroupv2 code.
The problem is, the current code uses GetPaths for three kinds of things:
1. Get all the paths to cgroup v1 controllers to save its state (see
(*linuxContainer).currentState(), (*LinuxFactory).loadState()
methods).
2. Get all the paths to cgroup v1 controllers to have the setns process
enter the proper cgroups in `(*setnsProcess).start()`.
3. Get the path to a specific controller (for example,
`m.GetPaths()["devices"]`).
Now, for cgroup v2 instead of a set of per-controller paths, we have only
one single unified path, and a dedicated function `GetUnifiedPath()` to get it.
This discrepancy between v1 and v2 cgroupManager API leads to the
following problems with the code:
- multiple if/else code blocks that have to treat v1 and v2 separately;
- backward-compatible GetPaths() methods in v2 controllers;
- - repeated writing of the PID into the same cgroup for v2;
Overall, it's hard to write the right code with all this, and the code
that is written is kinda hard to follow.
The solution is to slightly change the API to do the 3 things outlined
above in the same manner for v1 and v2:
1. Use `GetPaths()` for state saving and setns process cgroups entering.
2. Introduce and use Path(subsys string) to obtain a path to a
subsystem. For v2, the argument is ignored and the unified path is
returned.
This commit converts all the controllers to the new API, and modifies
all the users to use it.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2020-05-07 08:36:28 +08:00
|
|
|
// Path returns a cgroup path to the specified controller/subsystem.
|
|
|
|
// For cgroupv2, the argument is unused and can be empty.
|
|
|
|
Path(string) string
|
2019-10-19 00:40:46 +08:00
|
|
|
|
2016-09-09 16:18:54 +08:00
|
|
|
// Sets the cgroup as configured.
|
2015-02-25 17:20:01 +08:00
|
|
|
Set(container *configs.Config) error
|
2019-12-06 23:43:08 +08:00
|
|
|
|
Simplify cgroup path handing in v2 via unified API
This unties the Gordian Knot of using GetPaths in cgroupv2 code.
The problem is, the current code uses GetPaths for three kinds of things:
1. Get all the paths to cgroup v1 controllers to save its state (see
(*linuxContainer).currentState(), (*LinuxFactory).loadState()
methods).
2. Get all the paths to cgroup v1 controllers to have the setns process
enter the proper cgroups in `(*setnsProcess).start()`.
3. Get the path to a specific controller (for example,
`m.GetPaths()["devices"]`).
Now, for cgroup v2 instead of a set of per-controller paths, we have only
one single unified path, and a dedicated function `GetUnifiedPath()` to get it.
This discrepancy between v1 and v2 cgroupManager API leads to the
following problems with the code:
- multiple if/else code blocks that have to treat v1 and v2 separately;
- backward-compatible GetPaths() methods in v2 controllers;
- - repeated writing of the PID into the same cgroup for v2;
Overall, it's hard to write the right code with all this, and the code
that is written is kinda hard to follow.
The solution is to slightly change the API to do the 3 things outlined
above in the same manner for v1 and v2:
1. Use `GetPaths()` for state saving and setns process cgroups entering.
2. Introduce and use Path(subsys string) to obtain a path to a
subsystem. For v2, the argument is ignored and the unified path is
returned.
This commit converts all the controllers to the new API, and modifies
all the users to use it.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2020-05-07 08:36:28 +08:00
|
|
|
// GetPaths returns cgroup path(s) to save in a state file in order to restore later.
|
|
|
|
//
|
|
|
|
// For cgroup v1, a key is cgroup subsystem name, and the value is the path
|
|
|
|
// to the cgroup for this subsystem.
|
|
|
|
//
|
|
|
|
// For cgroup v2 unified hierarchy, a key is "", and the value is the unified path.
|
|
|
|
GetPaths() map[string]string
|
|
|
|
|
|
|
|
// GetCgroups returns the cgroup data as configured.
|
2019-12-06 23:43:08 +08:00
|
|
|
GetCgroups() (*configs.Cgroup, error)
|
2020-05-11 13:19:30 +08:00
|
|
|
|
|
|
|
// GetFreezerState retrieves the current FreezerState of the cgroup.
|
|
|
|
GetFreezerState() (configs.FreezerState, error)
|
2020-04-23 21:33:47 +08:00
|
|
|
|
|
|
|
// Whether the cgroup path exists or not
|
|
|
|
Exists() bool
|
2015-01-13 05:54:00 +08:00
|
|
|
}
|
|
|
|
|
2014-08-21 01:32:01 +08:00
|
|
|
type NotFoundError struct {
|
|
|
|
Subsystem string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *NotFoundError) Error() string {
|
|
|
|
return fmt.Sprintf("mountpoint for %s not found", e.Subsystem)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewNotFoundError(sub string) error {
|
|
|
|
return &NotFoundError{
|
|
|
|
Subsystem: sub,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func IsNotFound(err error) bool {
|
|
|
|
if err == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
_, ok := err.(*NotFoundError)
|
|
|
|
return ok
|
|
|
|
}
|