2016-05-19 17:12:50 +00:00
|
|
|
package runtime
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
"syscall"
|
|
|
|
|
|
|
|
"github.com/docker/containerd/specs"
|
|
|
|
"github.com/opencontainers/runc/libcontainer"
|
|
|
|
ocs "github.com/opencontainers/runtime-spec/specs-go"
|
|
|
|
)
|
|
|
|
|
|
|
|
func (c *container) getLibctContainer() (libcontainer.Container, error) {
|
|
|
|
runtimeRoot := "/run/runc"
|
|
|
|
|
|
|
|
// Check that the root wasn't changed
|
|
|
|
for _, opt := range c.runtimeArgs {
|
|
|
|
if strings.HasPrefix(opt, "--root=") {
|
|
|
|
runtimeRoot = strings.TrimPrefix(opt, "--root=")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f, err := libcontainer.New(runtimeRoot, libcontainer.Cgroupfs)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return f.Load(c.id)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *container) OOM() (OOM, error) {
|
|
|
|
container, err := c.getLibctContainer()
|
|
|
|
if err != nil {
|
|
|
|
if lerr, ok := err.(libcontainer.Error); ok {
|
|
|
|
// with oom registration sometimes the container can run, exit, and be destroyed
|
|
|
|
// faster than we can get the state back so we can just ignore this
|
|
|
|
if lerr.Code() == libcontainer.ContainerNotExists {
|
|
|
|
return nil, ErrContainerExited
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
state, err := container.State()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
memoryPath := state.CgroupPaths["memory"]
|
|
|
|
return c.getMemeoryEventFD(memoryPath)
|
|
|
|
}
|
|
|
|
|
|
|
|
func u64Ptr(i uint64) *uint64 { return &i }
|
|
|
|
|
|
|
|
func (c *container) UpdateResources(r *Resource) error {
|
|
|
|
sr := ocs.Resources{
|
|
|
|
Memory: &ocs.Memory{
|
|
|
|
Limit: u64Ptr(uint64(r.Memory)),
|
|
|
|
Reservation: u64Ptr(uint64(r.MemoryReservation)),
|
|
|
|
Swap: u64Ptr(uint64(r.MemorySwap)),
|
|
|
|
Kernel: u64Ptr(uint64(r.KernelMemory)),
|
2016-06-06 18:26:07 +00:00
|
|
|
KernelTCP: u64Ptr(uint64(r.KernelTCPMemory)),
|
2016-05-19 17:12:50 +00:00
|
|
|
},
|
|
|
|
CPU: &ocs.CPU{
|
|
|
|
Shares: u64Ptr(uint64(r.CPUShares)),
|
|
|
|
Quota: u64Ptr(uint64(r.CPUQuota)),
|
|
|
|
Period: u64Ptr(uint64(r.CPUPeriod)),
|
|
|
|
Cpus: &r.CpusetCpus,
|
|
|
|
Mems: &r.CpusetMems,
|
|
|
|
},
|
|
|
|
BlockIO: &ocs.BlockIO{
|
|
|
|
Weight: &r.BlkioWeight,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
srStr := bytes.NewBuffer(nil)
|
|
|
|
if err := json.NewEncoder(srStr).Encode(&sr); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
args := c.runtimeArgs
|
|
|
|
args = append(args, "update", "-r", "-", c.id)
|
|
|
|
cmd := exec.Command(c.runtime, args...)
|
|
|
|
cmd.Stdin = srStr
|
|
|
|
b, err := cmd.CombinedOutput()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf(string(b))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getRootIDs(s *specs.Spec) (int, int, error) {
|
|
|
|
if s == nil {
|
|
|
|
return 0, 0, nil
|
|
|
|
}
|
|
|
|
var hasUserns bool
|
|
|
|
for _, ns := range s.Linux.Namespaces {
|
|
|
|
if ns.Type == ocs.UserNamespace {
|
|
|
|
hasUserns = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !hasUserns {
|
|
|
|
return 0, 0, nil
|
|
|
|
}
|
|
|
|
uid := hostIDFromMap(0, s.Linux.UIDMappings)
|
|
|
|
gid := hostIDFromMap(0, s.Linux.GIDMappings)
|
|
|
|
return uid, gid, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *container) getMemeoryEventFD(root string) (*oom, error) {
|
|
|
|
f, err := os.Open(filepath.Join(root, "memory.oom_control"))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
fd, _, serr := syscall.RawSyscall(syscall.SYS_EVENTFD2, 0, syscall.FD_CLOEXEC, 0)
|
|
|
|
if serr != 0 {
|
|
|
|
f.Close()
|
|
|
|
return nil, serr
|
|
|
|
}
|
|
|
|
if err := c.writeEventFD(root, int(f.Fd()), int(fd)); err != nil {
|
|
|
|
syscall.Close(int(fd))
|
|
|
|
f.Close()
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &oom{
|
|
|
|
root: root,
|
|
|
|
id: c.id,
|
|
|
|
eventfd: int(fd),
|
|
|
|
control: f,
|
|
|
|
}, nil
|
|
|
|
}
|