summaryrefslogtreecommitdiff
path: root/libpod/oci_conmon_linux.go
diff options
context:
space:
mode:
Diffstat (limited to 'libpod/oci_conmon_linux.go')
-rw-r--r--libpod/oci_conmon_linux.go316
1 files changed, 248 insertions, 68 deletions
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index fde8624b0..0cdfe90e9 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -7,6 +7,7 @@ import (
"bufio"
"bytes"
"context"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -23,8 +24,13 @@ import (
"text/template"
"time"
+ runcconfig "github.com/opencontainers/runc/libcontainer/configs"
+ "github.com/opencontainers/runc/libcontainer/devices"
+
"github.com/containers/common/pkg/cgroups"
"github.com/containers/common/pkg/config"
+ "github.com/containers/common/pkg/resize"
+ cutil "github.com/containers/common/pkg/util"
conmonConfig "github.com/containers/conmon/runner/config"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/libpod/logs"
@@ -38,7 +44,6 @@ import (
pmount "github.com/containers/storage/pkg/mount"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux/label"
- "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -78,7 +83,7 @@ type ConmonOCIRuntime struct {
// libpod.
func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtimeFlags []string, runtimeCfg *config.Config) (OCIRuntime, error) {
if name == "" {
- return nil, errors.Wrapf(define.ErrInvalidArg, "the OCI runtime must be provided a non-empty name")
+ return nil, fmt.Errorf("the OCI runtime must be provided a non-empty name: %w", define.ErrInvalidArg)
}
// Make lookup tables for runtime support
@@ -122,7 +127,7 @@ func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtime
if os.IsNotExist(err) {
continue
}
- return nil, errors.Wrapf(err, "cannot stat OCI runtime %s path", name)
+ return nil, fmt.Errorf("cannot stat OCI runtime %s path: %w", name, err)
}
if !stat.Mode().IsRegular() {
continue
@@ -143,7 +148,7 @@ func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtime
}
if !foundPath {
- return nil, errors.Wrapf(define.ErrInvalidArg, "no valid executable found for OCI runtime %s", name)
+ return nil, fmt.Errorf("no valid executable found for OCI runtime %s: %w", name, define.ErrInvalidArg)
}
runtime.exitsDir = filepath.Join(runtime.tmpDir, "exits")
@@ -152,7 +157,7 @@ func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtime
if err := os.MkdirAll(runtime.exitsDir, 0750); err != nil {
// The directory is allowed to exist
if !os.IsExist(err) {
- return nil, errors.Wrapf(err, "error creating OCI runtime exit files directory")
+ return nil, fmt.Errorf("error creating OCI runtime exit files directory: %w", err)
}
}
return runtime, nil
@@ -228,7 +233,7 @@ func (r *ConmonOCIRuntime) CreateContainer(ctr *Container, restoreOptions *Conta
// changes are propagated to the host.
err = unix.Mount("/sys", "/sys", "none", unix.MS_REC|unix.MS_SLAVE, "")
if err != nil {
- return 0, errors.Wrapf(err, "cannot make /sys slave")
+ return 0, fmt.Errorf("cannot make /sys slave: %w", err)
}
mounts, err := pmount.GetMounts()
@@ -241,7 +246,7 @@ func (r *ConmonOCIRuntime) CreateContainer(ctr *Container, restoreOptions *Conta
}
err = unix.Unmount(m.Mountpoint, 0)
if err != nil && !os.IsNotExist(err) {
- return 0, errors.Wrapf(err, "cannot unmount %s", m.Mountpoint)
+ return 0, fmt.Errorf("cannot unmount %s: %w", m.Mountpoint, err)
}
}
return r.createOCIContainer(ctr, restoreOptions)
@@ -264,11 +269,6 @@ func (r *ConmonOCIRuntime) CreateContainer(ctr *Container, restoreOptions *Conta
// status, but will instead only check for the existence of the conmon exit file
// and update state to stopped if it exists.
func (r *ConmonOCIRuntime) UpdateContainerStatus(ctr *Container) error {
- exitFile, err := r.ExitFilePath(ctr)
- if err != nil {
- return err
- }
-
runtimeDir, err := util.GetRuntimeDir()
if err != nil {
return err
@@ -284,17 +284,17 @@ func (r *ConmonOCIRuntime) UpdateContainerStatus(ctr *Container) error {
outPipe, err := cmd.StdoutPipe()
if err != nil {
- return errors.Wrapf(err, "getting stdout pipe")
+ return fmt.Errorf("getting stdout pipe: %w", err)
}
errPipe, err := cmd.StderrPipe()
if err != nil {
- return errors.Wrapf(err, "getting stderr pipe")
+ return fmt.Errorf("getting stderr pipe: %w", err)
}
if err := cmd.Start(); err != nil {
out, err2 := ioutil.ReadAll(errPipe)
if err2 != nil {
- return errors.Wrapf(err, "error getting container %s state", ctr.ID())
+ return fmt.Errorf("error getting container %s state: %w", ctr.ID(), err)
}
if strings.Contains(string(out), "does not exist") || strings.Contains(string(out), "No such file") {
if err := ctr.removeConmonFiles(); err != nil {
@@ -305,7 +305,7 @@ func (r *ConmonOCIRuntime) UpdateContainerStatus(ctr *Container) error {
ctr.state.State = define.ContainerStateExited
return nil
}
- return errors.Wrapf(err, "error getting container %s state. stderr/out: %s", ctr.ID(), out)
+ return fmt.Errorf("error getting container %s state. stderr/out: %s: %w", ctr.ID(), out, err)
}
defer func() {
_ = cmd.Wait()
@@ -316,10 +316,10 @@ func (r *ConmonOCIRuntime) UpdateContainerStatus(ctr *Container) error {
}
out, err := ioutil.ReadAll(outPipe)
if err != nil {
- return errors.Wrapf(err, "error reading stdout: %s", ctr.ID())
+ return fmt.Errorf("error reading stdout: %s: %w", ctr.ID(), err)
}
if err := json.NewDecoder(bytes.NewBuffer(out)).Decode(state); err != nil {
- return errors.Wrapf(err, "error decoding container status for container %s", ctr.ID())
+ return fmt.Errorf("error decoding container status for container %s: %w", ctr.ID(), err)
}
ctr.state.PID = state.Pid
@@ -333,29 +333,17 @@ func (r *ConmonOCIRuntime) UpdateContainerStatus(ctr *Container) error {
case "stopped":
ctr.state.State = define.ContainerStateStopped
default:
- return errors.Wrapf(define.ErrInternal, "unrecognized status returned by runtime for container %s: %s",
- ctr.ID(), state.Status)
+ return fmt.Errorf("unrecognized status returned by runtime for container %s: %s: %w",
+ ctr.ID(), state.Status, define.ErrInternal)
}
// Only grab exit status if we were not already stopped
// If we were, it should already be in the database
if ctr.state.State == define.ContainerStateStopped && oldState != define.ContainerStateStopped {
- var fi os.FileInfo
- chWait := make(chan error)
- defer close(chWait)
-
- _, err := WaitForFile(exitFile, chWait, time.Second*5)
- if err == nil {
- fi, err = os.Stat(exitFile)
- }
- if err != nil {
- ctr.state.ExitCode = -1
- ctr.state.FinishedTime = time.Now()
- logrus.Errorf("No exit file for container %s found: %v", ctr.ID(), err)
- return nil
+ if _, err := ctr.Wait(context.Background()); err != nil {
+ logrus.Errorf("Waiting for container %s to exit: %v", ctr.ID(), err)
}
-
- return ctr.handleExitFile(exitFile, fi)
+ return nil
}
// Handle ContainerStateStopping - keep it unless the container
@@ -414,7 +402,7 @@ func (r *ConmonOCIRuntime) KillContainer(ctr *Container, signal uint, all bool)
if ctr.ensureState(define.ContainerStateStopped, define.ContainerStateExited) {
return define.ErrCtrStateInvalid
}
- return errors.Wrapf(err, "error sending signal to container %s", ctr.ID())
+ return fmt.Errorf("error sending signal to container %s: %w", ctr.ID(), err)
}
return nil
@@ -471,7 +459,7 @@ func (r *ConmonOCIRuntime) StopContainer(ctr *Container, timeout uint, all bool)
return nil
}
- return errors.Wrapf(err, "error sending SIGKILL to container %s", ctr.ID())
+ return fmt.Errorf("error sending SIGKILL to container %s: %w", ctr.ID(), err)
}
// Give runtime a few seconds to make it happen
@@ -528,7 +516,7 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.
if streams != nil {
if !streams.Stdin && !streams.Stdout && !streams.Stderr {
- return errors.Wrapf(define.ErrInvalidArg, "must specify at least one stream to attach to")
+ return fmt.Errorf("must specify at least one stream to attach to: %w", define.ErrInvalidArg)
}
}
@@ -541,7 +529,7 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.
if streamAttach {
newConn, err := openUnixSocket(attachSock)
if err != nil {
- return errors.Wrapf(err, "failed to connect to container's attach socket: %v", attachSock)
+ return fmt.Errorf("failed to connect to container's attach socket: %v: %w", attachSock, err)
}
conn = newConn
defer func() {
@@ -576,12 +564,12 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.
// Alright, let's hijack.
hijacker, ok := w.(http.Hijacker)
if !ok {
- return errors.Errorf("unable to hijack connection")
+ return fmt.Errorf("unable to hijack connection")
}
httpCon, httpBuf, err := hijacker.Hijack()
if err != nil {
- return errors.Wrapf(err, "error hijacking connection")
+ return fmt.Errorf("error hijacking connection: %w", err)
}
hijackDone <- true
@@ -590,7 +578,7 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.
// Force a flush after the header is written.
if err := httpBuf.Flush(); err != nil {
- return errors.Wrapf(err, "error flushing HTTP hijack header")
+ return fmt.Errorf("error flushing HTTP hijack header: %w", err)
}
defer func() {
@@ -705,7 +693,7 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.
// Next, STDIN. Avoid entirely if attachStdin unset.
if attachStdin {
go func() {
- _, err := utils.CopyDetachable(conn, httpBuf, detach)
+ _, err := cutil.CopyDetachable(conn, httpBuf, detach)
logrus.Debugf("STDIN copy completed")
stdinChan <- err
}()
@@ -736,7 +724,8 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.
// isRetryable returns whether the error was caused by a blocked syscall or the
// specified operation on a non blocking file descriptor wasn't ready for completion.
func isRetryable(err error) bool {
- if errno, isErrno := errors.Cause(err).(syscall.Errno); isErrno {
+ var errno syscall.Errno
+ if errors.As(err, &errno) {
return errno == syscall.EINTR || errno == syscall.EAGAIN
}
return false
@@ -751,15 +740,15 @@ func openControlFile(ctr *Container, parentDir string) (*os.File, error) {
return controlFile, nil
}
if !isRetryable(err) {
- return nil, errors.Wrapf(err, "could not open ctl file for terminal resize for container %s", ctr.ID())
+ return nil, fmt.Errorf("could not open ctl file for terminal resize for container %s: %w", ctr.ID(), err)
}
time.Sleep(time.Second / 10)
}
- return nil, errors.Errorf("timeout waiting for %q", controlPath)
+ return nil, fmt.Errorf("timeout waiting for %q", controlPath)
}
// AttachResize resizes the terminal used by the given container.
-func (r *ConmonOCIRuntime) AttachResize(ctr *Container, newSize define.TerminalSize) error {
+func (r *ConmonOCIRuntime) AttachResize(ctr *Container, newSize resize.TerminalSize) error {
controlFile, err := openControlFile(ctr, ctr.bundlePath())
if err != nil {
return err
@@ -768,7 +757,7 @@ func (r *ConmonOCIRuntime) AttachResize(ctr *Container, newSize define.TerminalS
logrus.Debugf("Received a resize event for container %s: %+v", ctr.ID(), newSize)
if _, err = fmt.Fprintf(controlFile, "%d %d %d\n", 1, newSize.Height, newSize.Width); err != nil {
- return errors.Wrapf(err, "failed to write to ctl file to resize terminal")
+ return fmt.Errorf("failed to write to ctl file to resize terminal: %w", err)
}
return nil
@@ -876,7 +865,7 @@ func (r *ConmonOCIRuntime) CheckConmonRunning(ctr *Container) (bool, error) {
if err == unix.ESRCH {
return false, nil
}
- return false, errors.Wrapf(err, "error pinging container %s conmon with signal 0", ctr.ID())
+ return false, fmt.Errorf("error pinging container %s conmon with signal 0: %w", ctr.ID(), err)
}
return true, nil
}
@@ -908,7 +897,7 @@ func (r *ConmonOCIRuntime) SupportsKVM() bool {
// AttachSocketPath is the path to a single container's attach socket.
func (r *ConmonOCIRuntime) AttachSocketPath(ctr *Container) (string, error) {
if ctr == nil {
- return "", errors.Wrapf(define.ErrInvalidArg, "must provide a valid container to get attach socket path")
+ return "", fmt.Errorf("must provide a valid container to get attach socket path: %w", define.ErrInvalidArg)
}
return filepath.Join(ctr.bundlePath(), "attach"), nil
@@ -917,7 +906,7 @@ func (r *ConmonOCIRuntime) AttachSocketPath(ctr *Container) (string, error) {
// ExitFilePath is the path to a container's exit file.
func (r *ConmonOCIRuntime) ExitFilePath(ctr *Container) (string, error) {
if ctr == nil {
- return "", errors.Wrapf(define.ErrInvalidArg, "must provide a valid container to get exit file path")
+ return "", fmt.Errorf("must provide a valid container to get exit file path: %w", define.ErrInvalidArg)
}
return filepath.Join(r.exitsDir, ctr.ID()), nil
}
@@ -928,11 +917,11 @@ func (r *ConmonOCIRuntime) RuntimeInfo() (*define.ConmonInfo, *define.OCIRuntime
conmonPackage := packageVersion(r.conmonPath)
runtimeVersion, err := r.getOCIRuntimeVersion()
if err != nil {
- return nil, nil, errors.Wrapf(err, "error getting version of OCI runtime %s", r.name)
+ return nil, nil, fmt.Errorf("error getting version of OCI runtime %s: %w", r.name, err)
}
conmonVersion, err := r.getConmonVersion()
if err != nil {
- return nil, nil, errors.Wrapf(err, "error getting conmon version")
+ return nil, nil, fmt.Errorf("error getting conmon version: %w", err)
}
conmon := define.ConmonInfo{
@@ -1002,7 +991,7 @@ func waitPidStop(pid int, timeout time.Duration) error {
return nil
case <-time.After(timeout):
close(chControl)
- return errors.Errorf("given PIDs did not die within timeout")
+ return fmt.Errorf("given PIDs did not die within timeout")
}
}
@@ -1018,7 +1007,7 @@ func (r *ConmonOCIRuntime) getLogTag(ctr *Container) (string, error) {
}
tmpl, err := template.New("container").Parse(logTag)
if err != nil {
- return "", errors.Wrapf(err, "template parsing error %s", logTag)
+ return "", fmt.Errorf("template parsing error %s: %w", logTag, err)
}
var b bytes.Buffer
err = tmpl.Execute(&b, data)
@@ -1039,13 +1028,13 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
parentSyncPipe, childSyncPipe, err := newPipe()
if err != nil {
- return 0, errors.Wrapf(err, "error creating socket pair")
+ return 0, fmt.Errorf("error creating socket pair: %w", err)
}
defer errorhandling.CloseQuiet(parentSyncPipe)
childStartPipe, parentStartPipe, err := newPipe()
if err != nil {
- return 0, errors.Wrapf(err, "error creating socket pair for start pipe")
+ return 0, fmt.Errorf("error creating socket pair for start pipe: %w", err)
}
defer errorhandling.CloseQuiet(parentStartPipe)
@@ -1166,7 +1155,6 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
}).Debugf("running conmon: %s", r.conmonPath)
cmd := exec.Command(r.conmonPath, args...)
- cmd.Dir = ctr.bundlePath()
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
@@ -1217,12 +1205,12 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
if havePortMapping {
ctr.rootlessPortSyncR, ctr.rootlessPortSyncW, err = os.Pipe()
if err != nil {
- return 0, errors.Wrapf(err, "failed to create rootless port sync pipe")
+ return 0, fmt.Errorf("failed to create rootless port sync pipe: %w", err)
}
}
ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe()
if err != nil {
- return 0, errors.Wrapf(err, "failed to create rootless network sync pipe")
+ return 0, fmt.Errorf("failed to create rootless network sync pipe: %w", err)
}
} else {
if ctr.rootlessSlirpSyncR != nil {
@@ -1354,8 +1342,6 @@ func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, p
logDriverArg = define.NoLogging
case define.PassthroughLogging:
logDriverArg = define.PassthroughLogging
- case define.JSONLogging:
- fallthrough
//lint:ignore ST1015 the default case has to be here
default: //nolint:stylecheck,gocritic
// No case here should happen except JSONLogging, but keep this here in case the options are extended
@@ -1365,6 +1351,8 @@ func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, p
// to get here, either a user would specify `--log-driver ""`, or this came from another place in libpod
// since the former case is obscure, and the latter case isn't an error, let's silently fallthrough
fallthrough
+ case define.JSONLogging:
+ fallthrough
case define.KubernetesLogging:
logDriverArg = fmt.Sprintf("%s:%s", define.KubernetesLogging, logPath)
}
@@ -1451,9 +1439,14 @@ func (r *ConmonOCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec
// TODO: This should be a switch - we are not guaranteed that
// there are only 2 valid cgroup managers
cgroupParent := ctr.CgroupParent()
+ cgroupPath := filepath.Join(ctr.config.CgroupParent, "conmon")
+ Resource := ctr.Spec().Linux.Resources
+ cgroupResources, err := GetLimits(Resource)
+ if err != nil {
+ logrus.StandardLogger().Log(logLevel, "Could not get ctr resources")
+ }
if ctr.CgroupManager() == config.SystemdCgroupsManager {
unitName := createUnitName("libpod-conmon", ctr.ID())
-
realCgroupParent := cgroupParent
splitParent := strings.Split(cgroupParent, "/")
if strings.HasSuffix(cgroupParent, ".slice") && len(splitParent) > 1 {
@@ -1465,8 +1458,7 @@ func (r *ConmonOCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec
logrus.StandardLogger().Logf(logLevel, "Failed to add conmon to systemd sandbox cgroup: %v", err)
}
} else {
- cgroupPath := filepath.Join(ctr.config.CgroupParent, "conmon")
- control, err := cgroups.New(cgroupPath, &spec.LinuxResources{})
+ control, err := cgroups.New(cgroupPath, &cgroupResources)
if err != nil {
logrus.StandardLogger().Logf(logLevel, "Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
} else if err := control.AddPid(cmd.Process.Pid); err != nil {
@@ -1555,7 +1547,7 @@ func readConmonPipeData(runtimeName string, pipe *os.File, ociLog string) (int,
}
}
}
- return -1, errors.Wrapf(ss.err, "container create failed (no logs from conmon)")
+ return -1, fmt.Errorf("container create failed (no logs from conmon): %w", ss.err)
}
logrus.Debugf("Received: %d", ss.si.Data)
if ss.si.Data < 0 {
@@ -1572,11 +1564,11 @@ func readConmonPipeData(runtimeName string, pipe *os.File, ociLog string) (int,
if ss.si.Message != "" {
return ss.si.Data, getOCIRuntimeError(runtimeName, ss.si.Message)
}
- return ss.si.Data, errors.Wrapf(define.ErrInternal, "container create failed")
+ return ss.si.Data, fmt.Errorf("container create failed: %w", define.ErrInternal)
}
data = ss.si.Data
case <-time.After(define.ContainerCreateTimeout):
- return -1, errors.Wrapf(define.ErrInternal, "container creation timeout")
+ return -1, fmt.Errorf("container creation timeout: %w", define.ErrInternal)
}
return data, nil
}
@@ -1748,3 +1740,191 @@ func httpAttachNonTerminalCopy(container *net.UnixConn, http *bufio.ReadWriter,
}
}
}
+
+// GetLimits converts spec resource limits to cgroup consumable limits
+func GetLimits(resource *spec.LinuxResources) (runcconfig.Resources, error) {
+ if resource == nil {
+ resource = &spec.LinuxResources{}
+ }
+ final := &runcconfig.Resources{}
+ devs := []*devices.Rule{}
+
+ // Devices
+ for _, entry := range resource.Devices {
+ if entry.Major == nil || entry.Minor == nil {
+ continue
+ }
+ runeType := 'a'
+ switch entry.Type {
+ case "b":
+ runeType = 'b'
+ case "c":
+ runeType = 'c'
+ }
+
+ devs = append(devs, &devices.Rule{
+ Type: devices.Type(runeType),
+ Major: *entry.Major,
+ Minor: *entry.Minor,
+ Permissions: devices.Permissions(entry.Access),
+ Allow: entry.Allow,
+ })
+ }
+ final.Devices = devs
+
+ // HugepageLimits
+ pageLimits := []*runcconfig.HugepageLimit{}
+ for _, entry := range resource.HugepageLimits {
+ pageLimits = append(pageLimits, &runcconfig.HugepageLimit{
+ Pagesize: entry.Pagesize,
+ Limit: entry.Limit,
+ })
+ }
+ final.HugetlbLimit = pageLimits
+
+ // Networking
+ netPriorities := []*runcconfig.IfPrioMap{}
+ if resource.Network != nil {
+ for _, entry := range resource.Network.Priorities {
+ netPriorities = append(netPriorities, &runcconfig.IfPrioMap{
+ Interface: entry.Name,
+ Priority: int64(entry.Priority),
+ })
+ }
+ }
+ final.NetPrioIfpriomap = netPriorities
+ rdma := make(map[string]runcconfig.LinuxRdma)
+ for name, entry := range resource.Rdma {
+ rdma[name] = runcconfig.LinuxRdma{HcaHandles: entry.HcaHandles, HcaObjects: entry.HcaObjects}
+ }
+ final.Rdma = rdma
+
+ // Memory
+ if resource.Memory != nil {
+ if resource.Memory.Limit != nil {
+ final.Memory = *resource.Memory.Limit
+ }
+ if resource.Memory.Reservation != nil {
+ final.MemoryReservation = *resource.Memory.Reservation
+ }
+ if resource.Memory.Swap != nil {
+ final.MemorySwap = *resource.Memory.Swap
+ }
+ if resource.Memory.Swappiness != nil {
+ final.MemorySwappiness = resource.Memory.Swappiness
+ }
+ }
+
+ // CPU
+ if resource.CPU != nil {
+ if resource.CPU.Period != nil {
+ final.CpuPeriod = *resource.CPU.Period
+ }
+ if resource.CPU.Quota != nil {
+ final.CpuQuota = *resource.CPU.Quota
+ }
+ if resource.CPU.RealtimePeriod != nil {
+ final.CpuRtPeriod = *resource.CPU.RealtimePeriod
+ }
+ if resource.CPU.RealtimeRuntime != nil {
+ final.CpuRtRuntime = *resource.CPU.RealtimeRuntime
+ }
+ if resource.CPU.Shares != nil {
+ final.CpuShares = *resource.CPU.Shares
+ }
+ final.CpusetCpus = resource.CPU.Cpus
+ final.CpusetMems = resource.CPU.Mems
+ }
+
+ // BlkIO
+ if resource.BlockIO != nil {
+ if len(resource.BlockIO.ThrottleReadBpsDevice) > 0 {
+ for _, entry := range resource.BlockIO.ThrottleReadBpsDevice {
+ throttle := &runcconfig.ThrottleDevice{}
+ dev := &runcconfig.BlockIODevice{
+ Major: entry.Major,
+ Minor: entry.Minor,
+ }
+ throttle.BlockIODevice = *dev
+ throttle.Rate = entry.Rate
+ final.BlkioThrottleReadBpsDevice = append(final.BlkioThrottleReadBpsDevice, throttle)
+ }
+ }
+ if len(resource.BlockIO.ThrottleWriteBpsDevice) > 0 {
+ for _, entry := range resource.BlockIO.ThrottleWriteBpsDevice {
+ throttle := &runcconfig.ThrottleDevice{}
+ dev := &runcconfig.BlockIODevice{
+ Major: entry.Major,
+ Minor: entry.Minor,
+ }
+ throttle.BlockIODevice = *dev
+ throttle.Rate = entry.Rate
+ final.BlkioThrottleWriteBpsDevice = append(final.BlkioThrottleWriteBpsDevice, throttle)
+ }
+ }
+ if len(resource.BlockIO.ThrottleReadIOPSDevice) > 0 {
+ for _, entry := range resource.BlockIO.ThrottleReadIOPSDevice {
+ throttle := &runcconfig.ThrottleDevice{}
+ dev := &runcconfig.BlockIODevice{
+ Major: entry.Major,
+ Minor: entry.Minor,
+ }
+ throttle.BlockIODevice = *dev
+ throttle.Rate = entry.Rate
+ final.BlkioThrottleReadIOPSDevice = append(final.BlkioThrottleReadIOPSDevice, throttle)
+ }
+ }
+ if len(resource.BlockIO.ThrottleWriteIOPSDevice) > 0 {
+ for _, entry := range resource.BlockIO.ThrottleWriteIOPSDevice {
+ throttle := &runcconfig.ThrottleDevice{}
+ dev := &runcconfig.BlockIODevice{
+ Major: entry.Major,
+ Minor: entry.Minor,
+ }
+ throttle.BlockIODevice = *dev
+ throttle.Rate = entry.Rate
+ final.BlkioThrottleWriteIOPSDevice = append(final.BlkioThrottleWriteIOPSDevice, throttle)
+ }
+ }
+ if resource.BlockIO.LeafWeight != nil {
+ final.BlkioLeafWeight = *resource.BlockIO.LeafWeight
+ }
+ if resource.BlockIO.Weight != nil {
+ final.BlkioWeight = *resource.BlockIO.Weight
+ }
+ if len(resource.BlockIO.WeightDevice) > 0 {
+ for _, entry := range resource.BlockIO.WeightDevice {
+ weight := &runcconfig.WeightDevice{}
+ dev := &runcconfig.BlockIODevice{
+ Major: entry.Major,
+ Minor: entry.Minor,
+ }
+ if entry.Weight != nil {
+ weight.Weight = *entry.Weight
+ }
+ if entry.LeafWeight != nil {
+ weight.LeafWeight = *entry.LeafWeight
+ }
+ weight.BlockIODevice = *dev
+ final.BlkioWeightDevice = append(final.BlkioWeightDevice, weight)
+ }
+ }
+ }
+
+ // Pids
+ if resource.Pids != nil {
+ final.PidsLimit = resource.Pids.Limit
+ }
+
+ // Networking
+ if resource.Network != nil {
+ if resource.Network.ClassID != nil {
+ final.NetClsClassid = *resource.Network.ClassID
+ }
+ }
+
+ // Unified state
+ final.Unified = resource.Unified
+
+ return *final, nil
+}