Add golint to test (#255)

* Add a new lint rule to the Makefile

Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>

* Fix linter errors

Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>

* Allow replacing the default apt mirror

Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
This commit is contained in:
Kenfe-Mickaël Laventure 2016-06-03 15:00:49 -07:00 committed by Michael Crosby
parent 4176ba7b52
commit 5624732128
38 changed files with 297 additions and 151 deletions

View file

@ -1,5 +1,9 @@
FROM debian:jessie FROM debian:jessie
# allow replacing httpredir mirror
ARG APT_MIRROR=httpredir.debian.org
RUN sed -i s/httpredir.debian.org/$APT_MIRROR/g /etc/apt/sources.list
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
build-essential \ build-essential \
ca-certificates \ ca-certificates \
@ -18,6 +22,20 @@ RUN curl -sSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd6
ENV PATH /go/bin:/usr/local/go/bin:$PATH ENV PATH /go/bin:/usr/local/go/bin:$PATH
ENV GOPATH /go:/go/src/github.com/docker/containerd/vendor ENV GOPATH /go:/go/src/github.com/docker/containerd/vendor
ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3
# Grab Go's cover tool for dead-simple code coverage testing
# Grab Go's vet tool for examining go code to find suspicious constructs
# and help prevent errors that the compiler might not catch
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
&& (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT) \
&& go install -v golang.org/x/tools/cmd/cover \
&& go install -v golang.org/x/tools/cmd/vet
# Grab Go's lint tool
ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
&& go install -v github.com/golang/lint/golint
WORKDIR /go/src/github.com/docker/containerd WORKDIR /go/src/github.com/docker/containerd
# install seccomp: the version shipped in trusty is too old # install seccomp: the version shipped in trusty is too old

View file

@ -80,7 +80,7 @@ fmt:
@gofmt -s -l . | grep -v vendor | grep -v .pb. | tee /dev/stderr @gofmt -s -l . | grep -v vendor | grep -v .pb. | tee /dev/stderr
lint: lint:
@golint ./... | grep -v vendor | grep -v .pb. | tee /dev/stderr @hack/validate-lint
shell: dbuild shell: dbuild
$(DOCKER_RUN) bash $(DOCKER_RUN) bash
@ -95,7 +95,7 @@ endif
bench: shim validate install bundles-rootfs bench: shim validate install bundles-rootfs
go test -bench=. -v $(shell go list ./... | grep -v /vendor | grep -v /integration-test) go test -bench=. -v $(shell go list ./... | grep -v /vendor | grep -v /integration-test)
validate: fmt validate: fmt lint
uninstall: uninstall:
$(foreach file,containerd containerd-shim ctr,rm /usr/local/bin/$(file);) $(foreach file,containerd containerd-shim ctr,rm /usr/local/bin/$(file);)

View file

@ -82,7 +82,7 @@ func (s *apiServer) CreateCheckpoint(ctx context.Context, r *types.CreateCheckpo
e.Checkpoint = &runtime.Checkpoint{ e.Checkpoint = &runtime.Checkpoint{
Name: r.Checkpoint.Name, Name: r.Checkpoint.Name,
Exit: r.Checkpoint.Exit, Exit: r.Checkpoint.Exit,
Tcp: r.Checkpoint.Tcp, TCP: r.Checkpoint.Tcp,
UnixSockets: r.Checkpoint.UnixSockets, UnixSockets: r.Checkpoint.UnixSockets,
Shell: r.Checkpoint.Shell, Shell: r.Checkpoint.Shell,
} }
@ -135,7 +135,7 @@ func (s *apiServer) ListCheckpoint(ctx context.Context, r *types.ListCheckpointR
for _, c := range checkpoints { for _, c := range checkpoints {
out = append(out, &types.Checkpoint{ out = append(out, &types.Checkpoint{
Name: c.Name, Name: c.Name,
Tcp: c.Tcp, Tcp: c.TCP,
Shell: c.Shell, Shell: c.Shell,
UnixSockets: c.UnixSockets, UnixSockets: c.UnixSockets,
// TODO: figure out timestamp // TODO: figure out timestamp
@ -333,15 +333,15 @@ func convertToPb(st *runtime.Stat) *types.StatsResponse {
systemUsage, _ := getSystemCPUUsage() systemUsage, _ := getSystemCPUUsage()
pbSt.CgroupStats.CpuStats = &types.CpuStats{ pbSt.CgroupStats.CpuStats = &types.CpuStats{
CpuUsage: &types.CpuUsage{ CpuUsage: &types.CpuUsage{
TotalUsage: st.Cpu.Usage.Total, TotalUsage: st.CPU.Usage.Total,
PercpuUsage: st.Cpu.Usage.Percpu, PercpuUsage: st.CPU.Usage.Percpu,
UsageInKernelmode: st.Cpu.Usage.Kernel, UsageInKernelmode: st.CPU.Usage.Kernel,
UsageInUsermode: st.Cpu.Usage.User, UsageInUsermode: st.CPU.Usage.User,
}, },
ThrottlingData: &types.ThrottlingData{ ThrottlingData: &types.ThrottlingData{
Periods: st.Cpu.Throttling.Periods, Periods: st.CPU.Throttling.Periods,
ThrottledPeriods: st.Cpu.Throttling.ThrottledPeriods, ThrottledPeriods: st.CPU.Throttling.ThrottledPeriods,
ThrottledTime: st.Cpu.Throttling.ThrottledTime, ThrottledTime: st.CPU.Throttling.ThrottledTime,
}, },
SystemUsage: systemUsage, SystemUsage: systemUsage,
} }

View file

@ -1,6 +1,7 @@
package pprof package pprof
import ( import (
// expvar init routine adds the "/debug/vars" handler
_ "expvar" _ "expvar"
"net/http" "net/http"
"net/http/pprof" "net/http/pprof"
@ -8,6 +9,7 @@ import (
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
) )
// Enable registers the "/debug/pprof" handler
func Enable(address string) { func Enable(address string) {
http.Handle("/", http.RedirectHandler("/debug/pprof", http.StatusMovedPermanently)) http.Handle("/", http.RedirectHandler("/debug/pprof", http.StatusMovedPermanently))

View file

@ -6,14 +6,17 @@ import (
"syscall" "syscall"
) )
// EpollCreate1 directly calls syscall.EpollCreate1
func EpollCreate1(flag int) (int, error) { func EpollCreate1(flag int) (int, error) {
return syscall.EpollCreate1(flag) return syscall.EpollCreate1(flag)
} }
// EpollCtl directly calls syscall.EpollCtl
func EpollCtl(epfd int, op int, fd int, event *syscall.EpollEvent) error { func EpollCtl(epfd int, op int, fd int, event *syscall.EpollEvent) error {
return syscall.EpollCtl(epfd, op, fd, event) return syscall.EpollCtl(epfd, op, fd, event)
} }
// EpollWait directly calls syscall.EpollWait
func EpollWait(epfd int, events []syscall.EpollEvent, msec int) (int, error) { func EpollWait(epfd int, events []syscall.EpollEvent, msec int) (int, error) {
return syscall.EpollWait(epfd, events, msec) return syscall.EpollWait(epfd, events, msec)
} }

View file

@ -40,6 +40,7 @@ import (
"unsafe" "unsafe"
) )
// EpollCreate1 calls a C implementation
func EpollCreate1(flag int) (int, error) { func EpollCreate1(flag int) (int, error) {
fd := int(C.EpollCreate1(C.int(flag))) fd := int(C.EpollCreate1(C.int(flag)))
if fd < 0 { if fd < 0 {
@ -48,6 +49,7 @@ func EpollCreate1(flag int) (int, error) {
return fd, nil return fd, nil
} }
// EpollCtl calls a C implementation
func EpollCtl(epfd int, op int, fd int, event *syscall.EpollEvent) error { func EpollCtl(epfd int, op int, fd int, event *syscall.EpollEvent) error {
errno := C.EpollCtl(C.int(epfd), C.int(syscall.EPOLL_CTL_ADD), C.int(fd), C.int(event.Events), C.int(event.Fd)) errno := C.EpollCtl(C.int(epfd), C.int(syscall.EPOLL_CTL_ADD), C.int(fd), C.int(event.Events), C.int(event.Fd))
if errno < 0 { if errno < 0 {
@ -56,6 +58,7 @@ func EpollCtl(epfd int, op int, fd int, event *syscall.EpollEvent) error {
return nil return nil
} }
// EpollWait calls a C implementation
func EpollWait(epfd int, events []syscall.EpollEvent, msec int) (int, error) { func EpollWait(epfd int, events []syscall.EpollEvent, msec int) (int, error) {
var c_events [128]C.struct_event_t var c_events [128]C.struct_event_t
n := int(C.run_epoll_wait(C.int(epfd), (*C.struct_event_t)(unsafe.Pointer(&c_events)))) n := int(C.run_epoll_wait(C.int(epfd), (*C.struct_event_t)(unsafe.Pointer(&c_events))))

View file

@ -24,8 +24,8 @@ type checkpoint struct {
Created time.Time `json:"created"` Created time.Time `json:"created"`
// Name is the name of the checkpoint // Name is the name of the checkpoint
Name string `json:"name"` Name string `json:"name"`
// Tcp checkpoints open tcp connections // TCP checkpoints open tcp connections
Tcp bool `json:"tcp"` TCP bool `json:"tcp"`
// UnixSockets persists unix sockets in the checkpoint // UnixSockets persists unix sockets in the checkpoint
UnixSockets bool `json:"unixSockets"` UnixSockets bool `json:"unixSockets"`
// Shell persists tty sessions in the checkpoint // Shell persists tty sessions in the checkpoint
@ -140,7 +140,7 @@ func (p *process) start() error {
if p.checkpoint.Shell { if p.checkpoint.Shell {
add("--shell-job") add("--shell-job")
} }
if p.checkpoint.Tcp { if p.checkpoint.TCP {
add("--tcp-established") add("--tcp-established")
} }
if p.checkpoint.UnixSockets { if p.checkpoint.UnixSockets {
@ -292,6 +292,7 @@ func (p *process) openIO() error {
return nil return nil
} }
// IO holds all 3 standard io Reader/Writer (stdin,stdout,stderr)
type IO struct { type IO struct {
Stdin io.WriteCloser Stdin io.WriteCloser
Stdout io.ReadCloser Stdout io.ReadCloser

View file

@ -15,7 +15,7 @@ import (
const usage = `High performance container daemon cli` const usage = `High performance container daemon cli`
type Exit struct { type exit struct {
Code int Code int
} }
@ -23,7 +23,7 @@ func main() {
// We want our defer functions to be run when calling fatal() // We want our defer functions to be run when calling fatal()
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
if ex, ok := e.(Exit); ok == true { if ex, ok := e.(exit); ok == true {
os.Exit(ex.Code) os.Exit(ex.Code)
} }
panic(e) panic(e)
@ -86,5 +86,5 @@ var versionCommand = cli.Command{
func fatal(err string, code int) { func fatal(err string, code int) {
fmt.Fprintf(os.Stderr, "[ctr] %s\n", err) fmt.Fprintf(os.Stderr, "[ctr] %s\n", err)
panic(Exit{code}) panic(exit{code})
} }

9
hack/validate-lint Executable file
View file

@ -0,0 +1,9 @@
#!/bin/bash
lint_error=$(golint ./... | grep -v vendor | grep -v .pb. | tee /dev/stderr)
if [ "$lint_error" != "" ]; then
exit 1
fi
exit 0

View file

@ -44,14 +44,14 @@ func untarRootfs(source string, destination string) error {
func CreateBundleWithFilter(source, name string, args []string, filter func(spec *ocs.Spec)) error { func CreateBundleWithFilter(source, name string, args []string, filter func(spec *ocs.Spec)) error {
// Generate the spec // Generate the spec
var spec ocs.Spec var spec ocs.Spec
if f, err := os.Open(utils.RefOciSpecsPath); err != nil { f, err := os.Open(utils.RefOciSpecsPath)
if err != nil {
return fmt.Errorf("Failed to open default spec: %v", err) return fmt.Errorf("Failed to open default spec: %v", err)
} else {
if err := json.NewDecoder(f).Decode(&spec); err != nil {
return fmt.Errorf("Failed to load default spec: %v", err)
}
f.Close()
} }
if err := json.NewDecoder(f).Decode(&spec); err != nil {
return fmt.Errorf("Failed to load default spec: %v", err)
}
f.Close()
spec.Process.Args = args spec.Process.Args = args
spec.Process.Terminal = false spec.Process.Terminal = false

View file

@ -21,10 +21,10 @@ func (cs *ContainerdSuite) ListRunningContainers() ([]*types.Container, error) {
return resp.Containers, nil return resp.Containers, nil
} }
func (cs *ContainerdSuite) SignalContainerProcess(id string, procId string, sig uint32) error { func (cs *ContainerdSuite) SignalContainerProcess(id string, procID string, sig uint32) error {
_, err := cs.grpcClient.Signal(context.Background(), &types.SignalRequest{ _, err := cs.grpcClient.Signal(context.Background(), &types.SignalRequest{
Id: id, Id: id,
Pid: procId, Pid: procID,
Signal: sig, Signal: sig,
}) })
return err return err
@ -74,8 +74,8 @@ type stdio struct {
stderrBuffer bytes.Buffer stderrBuffer bytes.Buffer
} }
type containerProcess struct { type ContainerProcess struct {
containerId string containerID string
pid string pid string
bundle *Bundle bundle *Bundle
io stdio io stdio
@ -84,7 +84,7 @@ type containerProcess struct {
hasExited bool hasExited bool
} }
func (c *containerProcess) openIo() (err error) { func (c *ContainerProcess) openIo() (err error) {
defer func() { defer func() {
if err != nil { if err != nil {
c.Cleanup() c.Cleanup()
@ -111,11 +111,11 @@ func (c *containerProcess) openIo() (err error) {
return nil return nil
} }
func (c *containerProcess) GetEventsChannel() chan *types.Event { func (c *ContainerProcess) GetEventsChannel() chan *types.Event {
return c.eventsCh return c.eventsCh
} }
func (c *containerProcess) GetNextEvent() *types.Event { func (c *ContainerProcess) GetNextEvent() *types.Event {
if c.hasExited { if c.hasExited {
return nil return nil
} }
@ -131,16 +131,16 @@ func (c *containerProcess) GetNextEvent() *types.Event {
return e return e
} }
func (c *containerProcess) CloseStdin() error { func (c *ContainerProcess) CloseStdin() error {
_, err := c.cs.grpcClient.UpdateProcess(context.Background(), &types.UpdateProcessRequest{ _, err := c.cs.grpcClient.UpdateProcess(context.Background(), &types.UpdateProcessRequest{
Id: c.containerId, Id: c.containerID,
Pid: c.pid, Pid: c.pid,
CloseStdin: true, CloseStdin: true,
}) })
return err return err
} }
func (c *containerProcess) Cleanup() { func (c *ContainerProcess) Cleanup() {
for _, f := range []*os.File{ for _, f := range []*os.File{
c.io.stdinf, c.io.stdinf,
c.io.stdoutf, c.io.stdoutf,
@ -153,9 +153,9 @@ func (c *containerProcess) Cleanup() {
} }
} }
func NewContainerProcess(cs *ContainerdSuite, bundle *Bundle, cid, pid string) (c *containerProcess, err error) { func NewContainerProcess(cs *ContainerdSuite, bundle *Bundle, cid, pid string) (c *ContainerProcess, err error) {
c = &containerProcess{ c = &ContainerProcess{
containerId: cid, containerID: cid,
pid: "init", pid: "init",
bundle: bundle, bundle: bundle,
eventsCh: make(chan *types.Event, 8), eventsCh: make(chan *types.Event, 8),
@ -181,7 +181,7 @@ func NewContainerProcess(cs *ContainerdSuite, bundle *Bundle, cid, pid string) (
return c, nil return c, nil
} }
func (cs *ContainerdSuite) StartContainerWithEventFilter(id, bundleName string, filter func(*types.Event)) (c *containerProcess, err error) { func (cs *ContainerdSuite) StartContainerWithEventFilter(id, bundleName string, filter func(*types.Event)) (c *ContainerProcess, err error) {
bundle := GetBundle(bundleName) bundle := GetBundle(bundleName)
if bundle == nil { if bundle == nil {
return nil, fmt.Errorf("No such bundle '%s'", bundleName) return nil, fmt.Errorf("No such bundle '%s'", bundleName)
@ -216,11 +216,11 @@ func (cs *ContainerdSuite) StartContainerWithEventFilter(id, bundleName string,
return c, nil return c, nil
} }
func (cs *ContainerdSuite) StartContainer(id, bundleName string) (c *containerProcess, err error) { func (cs *ContainerdSuite) StartContainer(id, bundleName string) (c *ContainerProcess, err error) {
return cs.StartContainerWithEventFilter(id, bundleName, nil) return cs.StartContainerWithEventFilter(id, bundleName, nil)
} }
func (cs *ContainerdSuite) RunContainer(id, bundleName string) (c *containerProcess, err error) { func (cs *ContainerdSuite) RunContainer(id, bundleName string) (c *ContainerProcess, err error) {
c, err = cs.StartContainer(id, bundleName) c, err = cs.StartContainer(id, bundleName)
if err != nil { if err != nil {
return nil, err return nil, err
@ -236,14 +236,14 @@ func (cs *ContainerdSuite) RunContainer(id, bundleName string) (c *containerProc
return c, err return c, err
} }
func (cs *ContainerdSuite) AddProcessToContainer(init *containerProcess, pid, cwd string, env, args []string, uid, gid uint32) (c *containerProcess, err error) { func (cs *ContainerdSuite) AddProcessToContainer(init *ContainerProcess, pid, cwd string, env, args []string, uid, gid uint32) (c *ContainerProcess, err error) {
c, err = NewContainerProcess(cs, init.bundle, init.containerId, pid) c, err = NewContainerProcess(cs, init.bundle, init.containerID, pid)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pr := &types.AddProcessRequest{ pr := &types.AddProcessRequest{
Id: init.containerId, Id: init.containerID,
Pid: pid, Pid: pid,
Args: args, Args: args,
Cwd: cwd, Cwd: cwd,

View file

@ -17,12 +17,12 @@ func (cs *ContainerdSuite) TestBusyboxTopExecEcho(t *check.C) {
var ( var (
err error err error
initp *containerProcess initp *ContainerProcess
echop *containerProcess echop *ContainerProcess
) )
containerId := "top" containerID := "top"
initp, err = cs.StartContainer(containerId, bundleName) initp, err = cs.StartContainer(containerID, bundleName)
t.Assert(err, checker.Equals, nil) t.Assert(err, checker.Equals, nil)
echop, err = cs.AddProcessToContainer(initp, "echo", "/", []string{"PATH=/bin"}, []string{"sh", "-c", "echo -n Ay Caramba! ; exit 1"}, 0, 0) echop, err = cs.AddProcessToContainer(initp, "echo", "/", []string{"PATH=/bin"}, []string{"sh", "-c", "echo -n Ay Caramba! ; exit 1"}, 0, 0)
@ -31,19 +31,19 @@ func (cs *ContainerdSuite) TestBusyboxTopExecEcho(t *check.C) {
for _, evt := range []types.Event{ for _, evt := range []types.Event{
{ {
Type: "start-container", Type: "start-container",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: "", Pid: "",
}, },
{ {
Type: "start-process", Type: "start-process",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: "echo", Pid: "echo",
}, },
{ {
Type: "exit", Type: "exit",
Id: containerId, Id: containerID,
Status: 1, Status: 1,
Pid: "echo", Pid: "echo",
}, },
@ -66,35 +66,35 @@ func (cs *ContainerdSuite) TestBusyboxTopExecTop(t *check.C) {
var ( var (
err error err error
initp *containerProcess initp *ContainerProcess
) )
containerId := "top" containerID := "top"
initp, err = cs.StartContainer(containerId, bundleName) initp, err = cs.StartContainer(containerID, bundleName)
t.Assert(err, checker.Equals, nil) t.Assert(err, checker.Equals, nil)
execId := "top1" execID := "top1"
_, err = cs.AddProcessToContainer(initp, execId, "/", []string{"PATH=/usr/bin"}, []string{"top"}, 0, 0) _, err = cs.AddProcessToContainer(initp, execID, "/", []string{"PATH=/usr/bin"}, []string{"top"}, 0, 0)
t.Assert(err, checker.Equals, nil) t.Assert(err, checker.Equals, nil)
for idx, evt := range []types.Event{ for idx, evt := range []types.Event{
{ {
Type: "start-container", Type: "start-container",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: "", Pid: "",
}, },
{ {
Type: "start-process", Type: "start-process",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: execId, Pid: execID,
}, },
{ {
Type: "exit", Type: "exit",
Id: containerId, Id: containerID,
Status: 137, Status: 137,
Pid: execId, Pid: execID,
}, },
} { } {
ch := initp.GetEventsChannel() ch := initp.GetEventsChannel()
@ -103,7 +103,7 @@ func (cs *ContainerdSuite) TestBusyboxTopExecTop(t *check.C) {
t.Assert(*e, checker.Equals, evt) t.Assert(*e, checker.Equals, evt)
if idx == 1 { if idx == 1 {
// Process Started, kill it // Process Started, kill it
cs.SignalContainerProcess(containerId, "top1", uint32(syscall.SIGKILL)) cs.SignalContainerProcess(containerID, "top1", uint32(syscall.SIGKILL))
} }
} }
@ -126,39 +126,39 @@ func (cs *ContainerdSuite) TestBusyboxTopExecTopKillInit(t *check.C) {
var ( var (
err error err error
initp *containerProcess initp *ContainerProcess
) )
containerId := "top" containerID := "top"
initp, err = cs.StartContainer(containerId, bundleName) initp, err = cs.StartContainer(containerID, bundleName)
t.Assert(err, checker.Equals, nil) t.Assert(err, checker.Equals, nil)
execId := "top1" execID := "top1"
_, err = cs.AddProcessToContainer(initp, execId, "/", []string{"PATH=/usr/bin"}, []string{"top"}, 0, 0) _, err = cs.AddProcessToContainer(initp, execID, "/", []string{"PATH=/usr/bin"}, []string{"top"}, 0, 0)
t.Assert(err, checker.Equals, nil) t.Assert(err, checker.Equals, nil)
for idx, evt := range []types.Event{ for idx, evt := range []types.Event{
{ {
Type: "start-container", Type: "start-container",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: "", Pid: "",
}, },
{ {
Type: "start-process", Type: "start-process",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: execId, Pid: execID,
}, },
{ {
Type: "exit", Type: "exit",
Id: containerId, Id: containerID,
Status: 137, Status: 137,
Pid: execId, Pid: execID,
}, },
{ {
Type: "exit", Type: "exit",
Id: containerId, Id: containerID,
Status: 143, Status: 143,
Pid: "init", Pid: "init",
}, },
@ -169,7 +169,7 @@ func (cs *ContainerdSuite) TestBusyboxTopExecTopKillInit(t *check.C) {
t.Assert(*e, checker.Equals, evt) t.Assert(*e, checker.Equals, evt)
if idx == 1 { if idx == 1 {
// Process Started, kill it // Process Started, kill it
cs.SignalContainerProcess(containerId, "init", uint32(syscall.SIGTERM)) cs.SignalContainerProcess(containerID, "init", uint32(syscall.SIGTERM))
} }
} }
} }

View file

@ -79,8 +79,8 @@ func (cs *ContainerdSuite) TestStartBusyboxLsEvents(t *check.C) {
t.Fatal(err) t.Fatal(err)
} }
containerId := "ls-events" containerID := "ls-events"
c, err := cs.StartContainer(containerId, "busybox-ls") c, err := cs.StartContainer(containerID, "busybox-ls")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -88,13 +88,13 @@ func (cs *ContainerdSuite) TestStartBusyboxLsEvents(t *check.C) {
for _, evt := range []types.Event{ for _, evt := range []types.Event{
{ {
Type: "start-container", Type: "start-container",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: "", Pid: "",
}, },
{ {
Type: "exit", Type: "exit",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: "init", Pid: "init",
}, },
@ -144,7 +144,7 @@ func (cs *ContainerdSuite) TestStartBusyboxTopKill(t *check.C) {
t.Fatal(err) t.Fatal(err)
} }
containerId := "top" containerID := "top"
c, err := cs.StartContainer("top", bundleName) c, err := cs.StartContainer("top", bundleName)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -152,7 +152,7 @@ func (cs *ContainerdSuite) TestStartBusyboxTopKill(t *check.C) {
<-time.After(1 * time.Second) <-time.After(1 * time.Second)
err = cs.KillContainer(containerId) err = cs.KillContainer(containerID)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -160,13 +160,13 @@ func (cs *ContainerdSuite) TestStartBusyboxTopKill(t *check.C) {
for _, evt := range []types.Event{ for _, evt := range []types.Event{
{ {
Type: "start-container", Type: "start-container",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: "", Pid: "",
}, },
{ {
Type: "exit", Type: "exit",
Id: containerId, Id: containerID,
Status: 128 + uint32(syscall.SIGKILL), Status: 128 + uint32(syscall.SIGKILL),
Pid: "init", Pid: "init",
}, },
@ -189,7 +189,7 @@ func (cs *ContainerdSuite) TestStartBusyboxTopSignalSigterm(t *check.C) {
t.Fatal(err) t.Fatal(err)
} }
containerId := "top" containerID := "top"
c, err := cs.StartContainer("top", bundleName) c, err := cs.StartContainer("top", bundleName)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -197,7 +197,7 @@ func (cs *ContainerdSuite) TestStartBusyboxTopSignalSigterm(t *check.C) {
<-time.After(1 * time.Second) <-time.After(1 * time.Second)
err = cs.SignalContainer(containerId, uint32(syscall.SIGTERM)) err = cs.SignalContainer(containerID, uint32(syscall.SIGTERM))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -205,13 +205,13 @@ func (cs *ContainerdSuite) TestStartBusyboxTopSignalSigterm(t *check.C) {
for _, evt := range []types.Event{ for _, evt := range []types.Event{
{ {
Type: "start-container", Type: "start-container",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: "", Pid: "",
}, },
{ {
Type: "exit", Type: "exit",
Id: containerId, Id: containerID,
Status: 128 + uint32(syscall.SIGTERM), Status: 128 + uint32(syscall.SIGTERM),
Pid: "init", Pid: "init",
}, },
@ -233,13 +233,13 @@ func (cs *ContainerdSuite) TestStartBusyboxTrapUSR1(t *check.C) {
t.Fatal(err) t.Fatal(err)
} }
containerId := "trap-usr1" containerID := "trap-usr1"
c, err := cs.StartContainer(containerId, "busybox-trap-usr1") c, err := cs.StartContainer(containerID, "busybox-trap-usr1")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := cs.SignalContainer(containerId, uint32(syscall.SIGUSR1)); err != nil { if err := cs.SignalContainer(containerID, uint32(syscall.SIGUSR1)); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -259,36 +259,36 @@ func (cs *ContainerdSuite) TestStartBusyboxTopPauseResume(t *check.C) {
t.Fatal(err) t.Fatal(err)
} }
containerId := "top" containerID := "top"
c, err := cs.StartContainer(containerId, bundleName) c, err := cs.StartContainer(containerID, bundleName)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := cs.PauseContainer(containerId); err != nil { if err := cs.PauseContainer(containerID); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := cs.ResumeContainer(containerId); err != nil { if err := cs.ResumeContainer(containerID); err != nil {
t.Fatal(err) t.Fatal(err)
} }
for _, evt := range []types.Event{ for _, evt := range []types.Event{
{ {
Type: "start-container", Type: "start-container",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: "", Pid: "",
}, },
{ {
Type: "pause", Type: "pause",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: "", Pid: "",
}, },
{ {
Type: "resume", Type: "resume",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: "", Pid: "",
}, },
@ -323,8 +323,8 @@ func (cs *ContainerdSuite) TestRestart(t *check.C) {
totalCtr := 10 totalCtr := 10
for i := 0; i < totalCtr; i++ { for i := 0; i < totalCtr; i++ {
containerId := fmt.Sprintf("top%d", i) containerID := fmt.Sprintf("top%d", i)
c, err := cs.StartContainer(containerId, bundleName) c, err := cs.StartContainer(containerID, bundleName)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -333,7 +333,7 @@ func (cs *ContainerdSuite) TestRestart(t *check.C) {
t.Assert(*e, checker.Equals, types.Event{ t.Assert(*e, checker.Equals, types.Event{
Type: "start-container", Type: "start-container",
Id: containerId, Id: containerID,
Status: 0, Status: 0,
Pid: "", Pid: "",
Timestamp: e.Timestamp, Timestamp: e.Timestamp,
@ -369,18 +369,18 @@ func (cs *ContainerdSuite) TestRestart(t *check.C) {
deathChans := make([]chan error, len(killedCtr)) deathChans := make([]chan error, len(killedCtr))
deathChansIdx := 0 deathChansIdx := 0
for i, _ := range killedCtr { for i := range killedCtr {
ch := make(chan error, 1) ch := make(chan error, 1)
deathChans[deathChansIdx] = ch deathChans[deathChansIdx] = ch
deathChansIdx++ deathChansIdx++
syscall.Kill(int(containers[i].Pids[0]), syscall.SIGKILL) syscall.Kill(int(containers[i].Pids[0]), syscall.SIGKILL)
// Filter to be notified of their death // Filter to be notified of their death
containerId := fmt.Sprintf("top%d", i) containerID := fmt.Sprintf("top%d", i)
f = func(event *types.Event) { f = func(event *types.Event) {
expectedEvent := types.Event{ expectedEvent := types.Event{
Type: "exit", Type: "exit",
Id: containerId, Id: containerID,
Status: 137, Status: 137,
Pid: "init", Pid: "init",
} }
@ -391,13 +391,13 @@ func (cs *ContainerdSuite) TestRestart(t *check.C) {
ch <- nil ch <- nil
} }
} }
cs.SetContainerEventFilter(containerId, f) cs.SetContainerEventFilter(containerID, f)
} }
cs.RestartDaemon(true) cs.RestartDaemon(true)
// Ensure we got our events // Ensure we got our events
for i, _ := range deathChans { for i := range deathChans {
done := false done := false
for done == false { for done == false {
select { select {

View file

@ -1,6 +1,8 @@
// +build linux // +build linux
// http://man7.org/linux/man-pages/man2/prctl.2.html // Package osutils provide access to the Get Child and Set Child prctl
// flags.
// See http://man7.org/linux/man-pages/man2/prctl.2.html
package osutils package osutils
import ( import (
@ -8,6 +10,7 @@ import (
"unsafe" "unsafe"
) )
// PR_SET_CHILD_SUBREAPER allows setting the child subreaper.
// If arg2 is nonzero, set the "child subreaper" attribute of the // If arg2 is nonzero, set the "child subreaper" attribute of the
// calling process; if arg2 is zero, unset the attribute. When a // calling process; if arg2 is zero, unset the attribute. When a
// process is marked as a child subreaper, all of the children // process is marked as a child subreaper, all of the children
@ -19,16 +22,18 @@ import (
// nearest still living ancestor subreaper will receive a SIGCHLD // nearest still living ancestor subreaper will receive a SIGCHLD
// signal and be able to wait(2) on the process to discover its // signal and be able to wait(2) on the process to discover its
// termination status. // termination status.
const PR_SET_CHILD_SUBREAPER = 36 const prSetChildSubreaper = 36
// PR_GET_CHILD_SUBREAPER allows retrieving the current child
// subreaper.
// Return the "child subreaper" setting of the caller, in the // Return the "child subreaper" setting of the caller, in the
// location pointed to by (int *) arg2. // location pointed to by (int *) arg2.
const PR_GET_CHILD_SUBREAPER = 37 const prGetChildSubreaper = 37
// GetSubreaper returns the subreaper setting for the calling process // GetSubreaper returns the subreaper setting for the calling process
func GetSubreaper() (int, error) { func GetSubreaper() (int, error) {
var i uintptr var i uintptr
if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, PR_GET_CHILD_SUBREAPER, uintptr(unsafe.Pointer(&i)), 0); err != 0 { if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, prGetChildSubreaper, uintptr(unsafe.Pointer(&i)), 0); err != 0 {
return -1, err return -1, err
} }
return int(i), nil return int(i), nil
@ -36,7 +41,7 @@ func GetSubreaper() (int, error) {
// SetSubreaper sets the value i as the subreaper setting for the calling process // SetSubreaper sets the value i as the subreaper setting for the calling process
func SetSubreaper(i int) error { func SetSubreaper(i int) error {
if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, PR_SET_CHILD_SUBREAPER, uintptr(i), 0); err != 0 { if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, prSetChildSubreaper, uintptr(i), 0); err != 0 {
return err return err
} }
return nil return nil

View file

@ -7,6 +7,7 @@ import (
) )
//Solaris TODO //Solaris TODO
// GetSubreaper returns the subreaper setting for the calling process // GetSubreaper returns the subreaper setting for the calling process
func GetSubreaper() (int, error) { func GetSubreaper() (int, error) {
return 0, errors.New("osutils GetSubreaper not implemented on Solaris") return 0, errors.New("osutils GetSubreaper not implemented on Solaris")

View file

@ -16,6 +16,7 @@ import (
ocs "github.com/opencontainers/runtime-spec/specs-go" ocs "github.com/opencontainers/runtime-spec/specs-go"
) )
// Container defines the operations allowed on a container
type Container interface { type Container interface {
// ID returns the container ID // ID returns the container ID
ID() string ID() string
@ -60,6 +61,7 @@ type Container interface {
Status() (State, error) Status() (State, error)
} }
// OOM wraps a container OOM.
type OOM interface { type OOM interface {
io.Closer io.Closer
FD() int FD() int
@ -68,12 +70,15 @@ type OOM interface {
Removed() bool Removed() bool
} }
// Stdio holds the path to the 3 pipes used for the standard ios.
type Stdio struct { type Stdio struct {
Stdin string Stdin string
Stdout string Stdout string
Stderr string Stderr string
} }
// NewStdio wraps the given standard io path into an Stdio struct.
// If a given parameter is the empty string, it is replaced by "/dev/null"
func NewStdio(stdin, stdout, stderr string) Stdio { func NewStdio(stdin, stdout, stderr string) Stdio {
for _, s := range []*string{ for _, s := range []*string{
&stdin, &stdout, &stderr, &stdin, &stdout, &stderr,
@ -89,6 +94,7 @@ func NewStdio(stdin, stdout, stderr string) Stdio {
} }
} }
// ContainerOpts keeps the options passed at container creation
type ContainerOpts struct { type ContainerOpts struct {
Root string Root string
ID string ID string
@ -136,6 +142,7 @@ func New(opts ContainerOpts) (Container, error) {
return c, nil return c, nil
} }
// Load return a new container from the matchin state file on disk.
func Load(root, id string, timeout time.Duration) (Container, error) { func Load(root, id string, timeout time.Duration) (Container, error) {
var s state var s state
f, err := os.Open(filepath.Join(root, id, StateFile)) f, err := os.Open(filepath.Join(root, id, StateFile))
@ -355,7 +362,7 @@ func (c *container) Checkpoint(cpt Checkpoint, checkpointDir string) error {
if cpt.Shell { if cpt.Shell {
add("--shell-job") add("--shell-job")
} }
if cpt.Tcp { if cpt.TCP {
add("--tcp-established") add("--tcp-established")
} }
if cpt.UnixSockets { if cpt.UnixSockets {

View file

@ -15,6 +15,7 @@ import (
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
// Process holds the operation allowed on a container's process
type Process interface { type Process interface {
io.Closer io.Closer

View file

@ -8,15 +8,17 @@ import (
) )
var ( var (
ErrNotChildProcess = errors.New("containerd: not a child process for container") // ErrContainerExited is returned when access to an exited
ErrInvalidContainerType = errors.New("containerd: invalid container type for runtime") // container is attempted
ErrCheckpointNotExists = errors.New("containerd: checkpoint does not exist for container") ErrContainerExited = errors.New("containerd: container has exited")
ErrCheckpointExists = errors.New("containerd: checkpoint already exists") // ErrProcessNotExited is returned when trying to retrive the exit
ErrContainerExited = errors.New("containerd: container has exited") // status of an alive process
ErrTerminalsNotSupported = errors.New("containerd: terminals are not supported for runtime") ErrProcessNotExited = errors.New("containerd: process has not exited")
ErrProcessNotExited = errors.New("containerd: process has not exited") // ErrContainerNotStarted is returned when a container fails to
ErrProcessExited = errors.New("containerd: process has exited") // start without error from the shim or the OCI runtime
ErrContainerNotStarted = errors.New("containerd: container not started") ErrContainerNotStarted = errors.New("containerd: container not started")
// ErrContainerStartTimeout is returned if a container takes too
// long to start
ErrContainerStartTimeout = errors.New("containerd: container did not start before the specified timeout") ErrContainerStartTimeout = errors.New("containerd: container did not start before the specified timeout")
errNoPidFile = errors.New("containerd: no process pid file found") errNoPidFile = errors.New("containerd: no process pid file found")
@ -25,20 +27,30 @@ var (
) )
const ( const (
ExitFile = "exit" // ExitFile holds the name of the pipe used to monitor process
// exit
ExitFile = "exit"
// ExitStatusFile holds the name of the file where the container
// exit code is to be written
ExitStatusFile = "exitStatus" ExitStatusFile = "exitStatus"
StateFile = "state.json" // StateFile holds the name of the file where the container state
ControlFile = "control" // is written
InitProcessID = "init" StateFile = "state.json"
// ControlFile holds the name of the pipe used to control the shim
ControlFile = "control"
// InitProcessID holds the special ID used for the very first
// container's process
InitProcessID = "init"
) )
// Checkpoint holds information regarding a container checkpoint
type Checkpoint struct { type Checkpoint struct {
// Timestamp is the time that checkpoint happened // Timestamp is the time that checkpoint happened
Created time.Time `json:"created"` Created time.Time `json:"created"`
// Name is the name of the checkpoint // Name is the name of the checkpoint
Name string `json:"name"` Name string `json:"name"`
// Tcp checkpoints open tcp connections // TCP checkpoints open tcp connections
Tcp bool `json:"tcp"` TCP bool `json:"tcp"`
// UnixSockets persists unix sockets in the checkpoint // UnixSockets persists unix sockets in the checkpoint
UnixSockets bool `json:"unixSockets"` UnixSockets bool `json:"unixSockets"`
// Shell persists tty sessions in the checkpoint // Shell persists tty sessions in the checkpoint
@ -53,8 +65,11 @@ type PlatformProcessState struct {
RootUID int `json:"rootUID"` RootUID int `json:"rootUID"`
RootGID int `json:"rootGID"` RootGID int `json:"rootGID"`
} }
// State represents a container state
type State string type State string
// Resource regroups the various container limits that can be updated
type Resource struct { type Resource struct {
CPUShares int64 CPUShares int64
BlkioWeight uint16 BlkioWeight uint16
@ -68,6 +83,7 @@ type Resource struct {
MemorySwap int64 MemorySwap int64
} }
// Possible container states
const ( const (
Paused = State("paused") Paused = State("paused")
Stopped = State("stopped") Stopped = State("stopped")
@ -86,6 +102,8 @@ type state struct {
NoPivotRoot bool `json:"noPivotRoot"` NoPivotRoot bool `json:"noPivotRoot"`
} }
// ProcessState holds the process OCI specs along with various fields
// required by containerd
type ProcessState struct { type ProcessState struct {
specs.ProcessSpec specs.ProcessSpec
Exec bool `json:"exec"` Exec bool `json:"exec"`

View file

@ -2,22 +2,25 @@ package runtime
import "time" import "time"
// Stat holds a container statistics
type Stat struct { type Stat struct {
// Timestamp is the time that the statistics where collected // Timestamp is the time that the statistics where collected
Timestamp time.Time Timestamp time.Time
Cpu Cpu `json:"cpu"` CPU CPU `json:"cpu"`
Memory Memory `json:"memory"` Memory Memory `json:"memory"`
Pids Pids `json:"pids"` Pids Pids `json:"pids"`
Blkio Blkio `json:"blkio"` Blkio Blkio `json:"blkio"`
Hugetlb map[string]Hugetlb `json:"hugetlb"` Hugetlb map[string]Hugetlb `json:"hugetlb"`
} }
// Hugetlb holds information regarding a container huge tlb usage
type Hugetlb struct { type Hugetlb struct {
Usage uint64 `json:"usage,omitempty"` Usage uint64 `json:"usage,omitempty"`
Max uint64 `json:"max,omitempty"` Max uint64 `json:"max,omitempty"`
Failcnt uint64 `json:"failcnt"` Failcnt uint64 `json:"failcnt"`
} }
// BlkioEntry represents a single record for a Blkio stat
type BlkioEntry struct { type BlkioEntry struct {
Major uint64 `json:"major,omitempty"` Major uint64 `json:"major,omitempty"`
Minor uint64 `json:"minor,omitempty"` Minor uint64 `json:"minor,omitempty"`
@ -25,6 +28,7 @@ type BlkioEntry struct {
Value uint64 `json:"value,omitempty"` Value uint64 `json:"value,omitempty"`
} }
// Blkio regroups all the Blkio related stats
type Blkio struct { type Blkio struct {
IoServiceBytesRecursive []BlkioEntry `json:"ioServiceBytesRecursive,omitempty"` IoServiceBytesRecursive []BlkioEntry `json:"ioServiceBytesRecursive,omitempty"`
IoServicedRecursive []BlkioEntry `json:"ioServicedRecursive,omitempty"` IoServicedRecursive []BlkioEntry `json:"ioServicedRecursive,omitempty"`
@ -36,18 +40,21 @@ type Blkio struct {
SectorsRecursive []BlkioEntry `json:"sectorsRecursive,omitempty"` SectorsRecursive []BlkioEntry `json:"sectorsRecursive,omitempty"`
} }
// Pids holds the stat of the pid usage of the machine
type Pids struct { type Pids struct {
Current uint64 `json:"current,omitempty"` Current uint64 `json:"current,omitempty"`
Limit uint64 `json:"limit,omitempty"` Limit uint64 `json:"limit,omitempty"`
} }
// Throttling holds a cpu throttling information
type Throttling struct { type Throttling struct {
Periods uint64 `json:"periods,omitempty"` Periods uint64 `json:"periods,omitempty"`
ThrottledPeriods uint64 `json:"throttledPeriods,omitempty"` ThrottledPeriods uint64 `json:"throttledPeriods,omitempty"`
ThrottledTime uint64 `json:"throttledTime,omitempty"` ThrottledTime uint64 `json:"throttledTime,omitempty"`
} }
type CpuUsage struct { // CPUUsage holds information regarding cpu usage
type CPUUsage struct {
// Units: nanoseconds. // Units: nanoseconds.
Total uint64 `json:"total,omitempty"` Total uint64 `json:"total,omitempty"`
Percpu []uint64 `json:"percpu,omitempty"` Percpu []uint64 `json:"percpu,omitempty"`
@ -55,11 +62,13 @@ type CpuUsage struct {
User uint64 `json:"user"` User uint64 `json:"user"`
} }
type Cpu struct { // CPU regroups both a CPU usage and throttling information
Usage CpuUsage `json:"usage,omitempty"` type CPU struct {
Usage CPUUsage `json:"usage,omitempty"`
Throttling Throttling `json:"throttling,omitempty"` Throttling Throttling `json:"throttling,omitempty"`
} }
// MemoryEntry regroups statistic about a given type of memory
type MemoryEntry struct { type MemoryEntry struct {
Limit uint64 `json:"limit"` Limit uint64 `json:"limit"`
Usage uint64 `json:"usage,omitempty"` Usage uint64 `json:"usage,omitempty"`
@ -67,6 +76,7 @@ type MemoryEntry struct {
Failcnt uint64 `json:"failcnt"` Failcnt uint64 `json:"failcnt"`
} }
// Memory holds information regarding the different type of memories available
type Memory struct { type Memory struct {
Cache uint64 `json:"cache,omitempty"` Cache uint64 `json:"cache,omitempty"`
Usage MemoryEntry `json:"usage,omitempty"` Usage MemoryEntry `json:"usage,omitempty"`

View file

@ -1,9 +1,12 @@
package specs package specs
import ocs "github.com/opencontainers/runtime-spec/specs-go" import oci "github.com/opencontainers/runtime-spec/specs-go"
type ( type (
ProcessSpec ocs.Process // ProcessSpec aliases the platform process specs
Spec ocs.Spec ProcessSpec oci.Process
Rlimit ocs.Rlimit // Spec aliases the platform oci spec
Spec oci.Spec
// Rlimit aliases the platform resource limit
Rlimit oci.Rlimit
) )

View file

@ -7,6 +7,8 @@ import (
"github.com/docker/containerd/specs" "github.com/docker/containerd/specs"
) )
// AddProcessTask holds everything necessary to add a process to a
// container
type AddProcessTask struct { type AddProcessTask struct {
baseTask baseTask
ID string ID string

View file

@ -4,6 +4,7 @@ package supervisor
import "github.com/docker/containerd/runtime" import "github.com/docker/containerd/runtime"
// CreateCheckpointTask holds needed parameters to create a new checkpoint
type CreateCheckpointTask struct { type CreateCheckpointTask struct {
baseTask baseTask
ID string ID string
@ -19,6 +20,7 @@ func (s *Supervisor) createCheckpoint(t *CreateCheckpointTask) error {
return i.container.Checkpoint(*t.Checkpoint, t.CheckpointDir) return i.container.Checkpoint(*t.Checkpoint, t.CheckpointDir)
} }
// DeleteCheckpointTask holds needed parameters to delete a checkpoint
type DeleteCheckpointTask struct { type DeleteCheckpointTask struct {
baseTask baseTask
ID string ID string

View file

@ -7,6 +7,7 @@ import (
"github.com/docker/containerd/runtime" "github.com/docker/containerd/runtime"
) )
// StartTask holds needed parameters to create a new container
type StartTask struct { type StartTask struct {
baseTask baseTask
ID string ID string

View file

@ -7,6 +7,7 @@ import (
"github.com/docker/containerd/runtime" "github.com/docker/containerd/runtime"
) )
// DeleteTask holds needed parameters to remove a container
type DeleteTask struct { type DeleteTask struct {
baseTask baseTask
ID string ID string

View file

@ -3,14 +3,18 @@ package supervisor
import "errors" import "errors"
var ( var (
// External errors // ErrContainerNotFound is returned when the container ID passed
ErrTaskChanNil = errors.New("containerd: task channel is nil") // for a given operation is invalid
ErrBundleNotFound = errors.New("containerd: bundle not found") ErrContainerNotFound = errors.New("containerd: container not found")
ErrContainerNotFound = errors.New("containerd: container not found") // ErrProcessNotFound is returned when the process ID passed for
ErrContainerExists = errors.New("containerd: container already exists") // a given operation is invalid
ErrProcessNotFound = errors.New("containerd: process not found for container") ErrProcessNotFound = errors.New("containerd: process not found for container")
// ErrUnknownContainerStatus is returned when the container status
// cannot be determined
ErrUnknownContainerStatus = errors.New("containerd: unknown container status ") ErrUnknownContainerStatus = errors.New("containerd: unknown container status ")
ErrUnknownTask = errors.New("containerd: unknown task type") // ErrUnknownTask is returned when an unknown Task type is
// scheduled (should never happen).
ErrUnknownTask = errors.New("containerd: unknown task type")
// Internal errors // Internal errors
errShutdown = errors.New("containerd: supervisor is shutdown") errShutdown = errors.New("containerd: supervisor is shutdown")

View file

@ -7,6 +7,7 @@ import (
"github.com/docker/containerd/runtime" "github.com/docker/containerd/runtime"
) )
// ExitTask holds needed parameters to execute the exit task
type ExitTask struct { type ExitTask struct {
baseTask baseTask
Process runtime.Process Process runtime.Process
@ -56,6 +57,7 @@ func (s *Supervisor) exit(t *ExitTask) error {
return nil return nil
} }
// ExecExitTask holds needed parameters to execute the exec exit task
type ExecExitTask struct { type ExecExitTask struct {
baseTask baseTask
ID string ID string

View file

@ -2,6 +2,8 @@ package supervisor
import "github.com/docker/containerd/runtime" import "github.com/docker/containerd/runtime"
// GetContainersTask holds needed parameters to retrieve a list of
// containers
type GetContainersTask struct { type GetContainersTask struct {
baseTask baseTask
ID string ID string

View file

@ -4,11 +4,14 @@ package supervisor
import "github.com/cloudfoundry/gosigar" import "github.com/cloudfoundry/gosigar"
// Machine holds the current machine cpu count and ram size
type Machine struct { type Machine struct {
Cpus int Cpus int
Memory int64 Memory int64
} }
// CollectMachineInformation returns information regarding the current
// machine (e.g. CPU count, RAM amount)
func CollectMachineInformation() (Machine, error) { func CollectMachineInformation() (Machine, error) {
m := Machine{} m := Machine{}
cpu := sigar.CpuList{} cpu := sigar.CpuList{}

View file

@ -3,18 +3,29 @@ package supervisor
import "github.com/rcrowley/go-metrics" import "github.com/rcrowley/go-metrics"
var ( var (
ContainerCreateTimer = metrics.NewTimer() // ContainerCreateTimer holds the metrics timer associated with container creation
ContainerDeleteTimer = metrics.NewTimer() ContainerCreateTimer = metrics.NewTimer()
ContainerStartTimer = metrics.NewTimer() // ContainerDeleteTimer holds the metrics timer associated with container deletion
ContainerStatsTimer = metrics.NewTimer() ContainerDeleteTimer = metrics.NewTimer()
ContainersCounter = metrics.NewCounter() // ContainerStartTimer holds the metrics timer associated with container start duration
ContainerStartTimer = metrics.NewTimer()
// ContainerStatsTimer holds the metrics timer associated with container stats generation
ContainerStatsTimer = metrics.NewTimer()
// ContainersCounter keeps track of the number of active containers
ContainersCounter = metrics.NewCounter()
// EventSubscriberCounter keeps track of the number of active event subscribers
EventSubscriberCounter = metrics.NewCounter() EventSubscriberCounter = metrics.NewCounter()
TasksCounter = metrics.NewCounter() // TasksCounter keeps track of the number of active supervisor tasks
ExecProcessTimer = metrics.NewTimer() TasksCounter = metrics.NewCounter()
ExitProcessTimer = metrics.NewTimer() // ExecProcessTimer holds the metrics timer associated with container exec
EpollFdCounter = metrics.NewCounter() ExecProcessTimer = metrics.NewTimer()
// ExitProcessTimer holds the metrics timer associated with reporting container exit status
ExitProcessTimer = metrics.NewTimer()
// EpollFdCounter keeps trac of how many process are being monitored
EpollFdCounter = metrics.NewCounter()
) )
// Metrics return the list of all available metrics
func Metrics() map[string]interface{} { func Metrics() map[string]interface{} {
return map[string]interface{}{ return map[string]interface{}{
"container-create-time": ContainerCreateTimer, "container-create-time": ContainerCreateTimer,

View file

@ -9,6 +9,7 @@ import (
"github.com/docker/containerd/runtime" "github.com/docker/containerd/runtime"
) )
// NewMonitor starts a new process monitor and returns it
func NewMonitor() (*Monitor, error) { func NewMonitor() (*Monitor, error) {
m := &Monitor{ m := &Monitor{
receivers: make(map[int]interface{}), receivers: make(map[int]interface{}),
@ -24,6 +25,7 @@ func NewMonitor() (*Monitor, error) {
return m, nil return m, nil
} }
// Monitor represents a runtime.Process monitor
type Monitor struct { type Monitor struct {
m sync.Mutex m sync.Mutex
receivers map[int]interface{} receivers map[int]interface{}
@ -32,14 +34,17 @@ type Monitor struct {
epollFd int epollFd int
} }
// Exits returns the channel used to notify of a process exit
func (m *Monitor) Exits() chan runtime.Process { func (m *Monitor) Exits() chan runtime.Process {
return m.exits return m.exits
} }
// OOMs returns the channel used to notify of a container exit due to OOM
func (m *Monitor) OOMs() chan string { func (m *Monitor) OOMs() chan string {
return m.ooms return m.ooms
} }
// Monitor adds a process to the list of the one being monitored
func (m *Monitor) Monitor(p runtime.Process) error { func (m *Monitor) Monitor(p runtime.Process) error {
m.m.Lock() m.m.Lock()
defer m.m.Unlock() defer m.m.Unlock()
@ -56,6 +61,7 @@ func (m *Monitor) Monitor(p runtime.Process) error {
return nil return nil
} }
// MonitorOOM adds a container to the list of the ones monitored for OOM
func (m *Monitor) MonitorOOM(c runtime.Container) error { func (m *Monitor) MonitorOOM(c runtime.Container) error {
m.m.Lock() m.m.Lock()
defer m.m.Unlock() defer m.m.Unlock()
@ -76,6 +82,7 @@ func (m *Monitor) MonitorOOM(c runtime.Container) error {
return nil return nil
} }
// Close cleans up resources allocated by NewMonitor()
func (m *Monitor) Close() error { func (m *Monitor) Close() error {
return syscall.Close(m.epollFd) return syscall.Close(m.epollFd)
} }

View file

@ -6,6 +6,7 @@ import (
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
) )
// OOMTask holds needed parameters to report a container OOM
type OOMTask struct { type OOMTask struct {
baseTask baseTask
ID string ID string

View file

@ -2,6 +2,7 @@ package supervisor
import "os" import "os"
// SignalTask holds needed parameters to signal a container
type SignalTask struct { type SignalTask struct {
baseTask baseTask
ID string ID string

View file

@ -6,6 +6,7 @@ import (
"github.com/docker/containerd/runtime" "github.com/docker/containerd/runtime"
) )
// StatsTask holds needed parameters to retrieve a container statistics
type StatsTask struct { type StatsTask struct {
baseTask baseTask
ID string ID string

View file

@ -144,6 +144,7 @@ func readEventLog(s *Supervisor) error {
return nil return nil
} }
// Supervisor represents a container supervisor
type Supervisor struct { type Supervisor struct {
// stateDir is the directory on the system to store container runtime state information. // stateDir is the directory on the system to store container runtime state information.
stateDir string stateDir string
@ -179,6 +180,7 @@ func (s *Supervisor) Close() error {
return nil return nil
} }
// Event represents a container event
type Event struct { type Event struct {
ID string `json:"id"` ID string `json:"id"`
Type string `json:"type"` Type string `json:"type"`

View file

@ -6,6 +6,7 @@ import (
"github.com/docker/containerd/runtime" "github.com/docker/containerd/runtime"
) )
// UpdateTask holds needed parameters to update a container resource constraints
type UpdateTask struct { type UpdateTask struct {
baseTask baseTask
ID string ID string
@ -50,6 +51,8 @@ func (s *Supervisor) updateContainer(t *UpdateTask) error {
return nil return nil
} }
// UpdateProcessTask holds needed parameters to update a container
// process terminal size or close its stdin
type UpdateProcessTask struct { type UpdateProcessTask struct {
baseTask baseTask
ID string ID string

View file

@ -8,6 +8,7 @@ import (
"github.com/docker/containerd/runtime" "github.com/docker/containerd/runtime"
) )
// Worker interface
type Worker interface { type Worker interface {
Start() Start()
} }
@ -22,6 +23,7 @@ type startTask struct {
StartResponse chan StartResponse StartResponse chan StartResponse
} }
// NewWorker return a new initialized worker
func NewWorker(s *Supervisor, wg *sync.WaitGroup) Worker { func NewWorker(s *Supervisor, wg *sync.WaitGroup) Worker {
return &worker{ return &worker{
s: s, s: s,
@ -34,6 +36,7 @@ type worker struct {
s *Supervisor s *Supervisor
} }
// Start runs a loop in charge of starting new containers
func (w *worker) Start() { func (w *worker) Start() {
defer w.wg.Done() defer w.wg.Done()
for t := range w.s.startTasks { for t := range w.s.startTasks {

View file

@ -8,7 +8,7 @@ import (
"strings" "strings"
) )
// Output directory for testing and benchmark artifacts // GetTestOutDir returns the output directory for testing and benchmark artifacts
func GetTestOutDir() string { func GetTestOutDir() string {
out, _ := exec.Command("git", "rev-parse", "--show-toplevel").CombinedOutput() out, _ := exec.Command("git", "rev-parse", "--show-toplevel").CombinedOutput()
repoRoot := string(out) repoRoot := string(out)
@ -17,11 +17,18 @@ func GetTestOutDir() string {
} }
var ( var (
ArchivesDir = filepath.Join("test-artifacts", "archives") // ArchivesDir holds the location of the available rootfs
BundlesRoot = filepath.Join("test-artifacts", "oci-bundles") ArchivesDir = filepath.Join("test-artifacts", "archives")
// BundlesRoot holds the location where OCI Bundles are stored
BundlesRoot = filepath.Join("test-artifacts", "oci-bundles")
// OutputDirFormat holds the standard format used when creating a
// new test output directory
OutputDirFormat = filepath.Join("test-artifacts", "runs", "%s") OutputDirFormat = filepath.Join("test-artifacts", "runs", "%s")
// RefOciSpecsPath holds the path to the generic OCI config
RefOciSpecsPath = filepath.Join(BundlesRoot, "config.json") RefOciSpecsPath = filepath.Join(BundlesRoot, "config.json")
StateDir = "/run/containerd-bench-test" // StateDir holds the path to the directory used by the containerd
// started by tests
StateDir = "/run/containerd-bench-test"
) )
// untarRootfs untars the given `source` tarPath into `destination/rootfs` // untarRootfs untars the given `source` tarPath into `destination/rootfs`
@ -36,6 +43,7 @@ func untarRootfs(source string, destination string) error {
return tar.Run() return tar.Run()
} }
// GenerateReferenceSpecs generates a default OCI specs via `runc spec`
func GenerateReferenceSpecs(destination string) error { func GenerateReferenceSpecs(destination string) error {
if _, err := os.Stat(filepath.Join(destination, "config.json")); err == nil { if _, err := os.Stat(filepath.Join(destination, "config.json")); err == nil {
return nil return nil
@ -45,6 +53,7 @@ func GenerateReferenceSpecs(destination string) error {
return specs.Run() return specs.Run()
} }
// CreateBundle generates a valid OCI bundle from the given rootfs
func CreateBundle(source, name string) error { func CreateBundle(source, name string) error {
bundlePath := filepath.Join(BundlesRoot, name) bundlePath := filepath.Join(BundlesRoot, name)
@ -55,6 +64,7 @@ func CreateBundle(source, name string) error {
return nil return nil
} }
// CreateBusyboxBundle generates a bundle based on the busybox rootfs
func CreateBusyboxBundle(name string) error { func CreateBusyboxBundle(name string) error {
return CreateBundle("busybox", name) return CreateBundle("busybox", name)
} }

View file

@ -2,10 +2,19 @@ package containerd
import "fmt" import "fmt"
// VersionMajor holds the release major number
const VersionMajor = 0 const VersionMajor = 0
// VersionMinor holds the release minor number
const VersionMinor = 2 const VersionMinor = 2
// VersionPatch holds the release patch number
const VersionPatch = 0 const VersionPatch = 0
// Version holds the combination of major minor and patch as a string
// of format Major.Minor.Patch
var Version = fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch) var Version = fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch)
// GitCommit is filled with the Git revision being used to build the
// program at linking time
var GitCommit = "" var GitCommit = ""