Add oom support to events
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
70a8c1ec3f
commit
500ca74f38
10 changed files with 201 additions and 256 deletions
|
@ -2,6 +2,7 @@ package runtime
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -46,7 +47,15 @@ type Container interface {
|
|||
// Name or path of the OCI compliant runtime used to execute the container
|
||||
Runtime() string
|
||||
// OOM signals the channel if the container received an OOM notification
|
||||
// OOM() (<-chan struct{}, error)
|
||||
OOM() (OOM, error)
|
||||
}
|
||||
|
||||
type OOM interface {
|
||||
io.Closer
|
||||
FD() int
|
||||
ContainerID() string
|
||||
Flush()
|
||||
Removed() bool
|
||||
}
|
||||
|
||||
type Stdio struct {
|
||||
|
@ -159,8 +168,8 @@ type container struct {
|
|||
bundle string
|
||||
runtime string
|
||||
processes map[string]*process
|
||||
stdio Stdio
|
||||
labels []string
|
||||
oomFds []int
|
||||
}
|
||||
|
||||
func (c *container) ID() string {
|
||||
|
|
|
@ -2,6 +2,7 @@ package runtime
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
@ -240,6 +241,59 @@ func (c *container) Stats() (*Stat, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
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 (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
|
||||
}
|
||||
|
||||
func (c *container) writeEventFD(root string, cfd, efd int) error {
|
||||
f, err := os.OpenFile(filepath.Join(root, "cgroup.event_control"), os.O_WRONLY, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = f.WriteString(fmt.Sprintf("%d %d", efd, cfd))
|
||||
return err
|
||||
}
|
||||
|
||||
func waitForStart(p *process, cmd *exec.Cmd) error {
|
||||
for i := 0; i < 50; i++ {
|
||||
if _, err := p.getPidFromFile(); err != nil {
|
||||
|
@ -270,3 +324,36 @@ func isAlive(cmd *exec.Cmd) (bool, error) {
|
|||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
type oom struct {
|
||||
id string
|
||||
root string
|
||||
control *os.File
|
||||
eventfd int
|
||||
}
|
||||
|
||||
func (o *oom) ContainerID() string {
|
||||
return o.id
|
||||
}
|
||||
|
||||
func (o *oom) FD() int {
|
||||
return o.eventfd
|
||||
}
|
||||
|
||||
func (o *oom) Flush() {
|
||||
buf := make([]byte, 8)
|
||||
syscall.Read(o.eventfd, buf)
|
||||
}
|
||||
|
||||
func (o *oom) Removed() bool {
|
||||
_, err := os.Lstat(filepath.Join(o.root, "cgroup.event_control"))
|
||||
return os.IsNotExist(err)
|
||||
}
|
||||
|
||||
func (o *oom) Close() error {
|
||||
err := syscall.Close(o.eventfd)
|
||||
if cerr := o.control.Close(); err == nil {
|
||||
err = cerr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -60,3 +60,7 @@ func (c *container) Pids() ([]int, error) {
|
|||
func (c *container) Stats() (*Stat, error) {
|
||||
return nil, errors.New("Stats not yet implemented on Windows")
|
||||
}
|
||||
|
||||
func (c *container) OOM() (OOM, error) {
|
||||
return nil, errors.New("OOM not yet implemented on Windows")
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue