Skip to content

Commit

Permalink
Update libcontainer to 1597c68f7b941fd97881155d7f077852e2914e7b
Browse files Browse the repository at this point in the history
This commit contains changes for docker:
* user.GetGroupFile to user.GetGroupPath docker-archive/libcontainer#301
* Add systemd support for OOM docker-archive/libcontainer#307
* Support for custom namespaces docker-archive/libcontainer#279, docker-archive/libcontainer#312
* Fixes moby#9699 docker-archive/libcontainer#308

Signed-off-by: Alexander Morozov <[email protected]>
  • Loading branch information
LK4D4 committed Dec 23, 2014
1 parent 043e33c commit 50905a6
Show file tree
Hide file tree
Showing 43 changed files with 515 additions and 360 deletions.
2 changes: 1 addition & 1 deletion api/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1399,7 +1399,7 @@ func serveFd(addr string, job *engine.Job) error {
}

func lookupGidByName(nameOrGid string) (int, error) {
groupFile, err := user.GetGroupFile()
groupFile, err := user.GetGroupPath()
if err != nil {
return -1, err
}
Expand Down
11 changes: 4 additions & 7 deletions daemon/execdriver/native/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e

func (d *driver) createNetwork(container *libcontainer.Config, c *execdriver.Command) error {
if c.Network.HostNetworking {
container.Namespaces["NEWNET"] = false
container.Namespaces.Remove(libcontainer.NEWNET)
return nil
}

Expand Down Expand Up @@ -119,18 +119,15 @@ func (d *driver) createNetwork(container *libcontainer.Config, c *execdriver.Com
cmd := active.cmd

nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net")
container.Networks = append(container.Networks, &libcontainer.Network{
Type: "netns",
NsPath: nspath,
})
container.Namespaces.Add(libcontainer.NEWNET, nspath)
}

return nil
}

func (d *driver) createIpc(container *libcontainer.Config, c *execdriver.Command) error {
if c.Ipc.HostIpc {
container.Namespaces["NEWIPC"] = false
container.Namespaces.Remove(libcontainer.NEWIPC)
return nil
}

Expand All @@ -144,7 +141,7 @@ func (d *driver) createIpc(container *libcontainer.Config, c *execdriver.Command
}
cmd := active.cmd

container.IpcNsPath = filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "ipc")
container.Namespaces.Add(libcontainer.NEWIPC, filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "ipc"))
}

return nil
Expand Down
15 changes: 8 additions & 7 deletions daemon/execdriver/native/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ func NewDriver(root, initPath string) (*driver, error) {
}, nil
}

func (d *driver) notifyOnOOM(config *libcontainer.Config) (<-chan struct{}, error) {
return fs.NotifyOnOOM(config.Cgroups)
}

type execOutput struct {
exitCode int
err error
Expand Down Expand Up @@ -152,11 +148,16 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
}

oomKill := false
oomKillNotification, err := d.notifyOnOOM(container)
state, err := libcontainer.GetState(filepath.Join(d.root, c.ID))
if err == nil {
_, oomKill = <-oomKillNotification
oomKillNotification, err := libcontainer.NotifyOnOOM(state)
if err == nil {
_, oomKill = <-oomKillNotification
} else {
log.Warnf("WARNING: Your kernel does not support OOM notifications: %s", err)
}
} else {
log.Warnf("WARNING: Your kernel does not support OOM notifications: %s", err)
log.Warnf("Failed to get container state, oom notify will not work: %s", err)
}
// wait for the container to exit.
execOutput := <-execOutputChan
Expand Down
12 changes: 6 additions & 6 deletions daemon/execdriver/native/template/default_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ func New() *libcontainer.Config {
"KILL",
"AUDIT_WRITE",
},
Namespaces: map[string]bool{
"NEWNS": true,
"NEWUTS": true,
"NEWIPC": true,
"NEWPID": true,
"NEWNET": true,
Namespaces: libcontainer.Namespaces{
{Type: "NEWNS"},
{Type: "NEWUTS"},
{Type: "NEWIPC"},
{Type: "NEWPID"},
{Type: "NEWNET"},
},
Cgroups: &cgroups.Cgroup{
Parent: "docker",
Expand Down
2 changes: 1 addition & 1 deletion project/vendor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ if [ "$1" = '--go' ]; then
mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
fi

clone git github.com/docker/libcontainer 53eca435e63db58b06cf796d3a9326db5fd42253
clone git github.com/docker/libcontainer 1597c68f7b941fd97881155d7f077852e2914e7b
# see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file)
rm -rf src/github.com/docker/libcontainer/vendor
eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')"
Expand Down
6 changes: 3 additions & 3 deletions vendor/src/github.com/docker/libcontainer/Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@

all:
docker build -t docker/libcontainer .
docker build -t dockercore/libcontainer .

test:
# we need NET_ADMIN for the netlink tests and SYS_ADMIN for mounting
docker run --rm -it --privileged docker/libcontainer
docker run --rm -it --privileged dockercore/libcontainer

sh:
docker run --rm -it --privileged -w /busybox docker/libcontainer nsinit exec sh
docker run --rm -it --privileged -w /busybox dockercore/libcontainer nsinit exec sh

GO_PACKAGES = $(shell find . -not \( -wholename ./vendor -prune -o -wholename ./.git -prune \) -name '*.go' -print0 | xargs -0n1 dirname | sort -u)

Expand Down
25 changes: 25 additions & 0 deletions vendor/src/github.com/docker/libcontainer/SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,4 +318,29 @@ a container.
| Resume | Resume all processes inside the container if paused |
| Exec | Execute a new process inside of the container ( requires setns ) |

### Execute a new process inside of a running container.

User can execute a new process inside of a running container. Any binaries to be
executed must be accessible within the container's rootfs.

The started process will run inside the container's rootfs. Any changes
made by the process to the container's filesystem will persist after the
process finished executing.

The started process will join all the container's existing namespaces. When the
container is paused, the process will also be paused and will resume when
the container is unpaused. The started process will only run when the container's
primary process (PID 1) is running, and will not be restarted when the container
is restarted.

#### Planned additions

The started process will have its own cgroups nested inside the container's
cgroups. This is used for process tracking and optionally resource allocation
handling for the new process. Freezer cgroup is required, the rest of the cgroups
are optional. The process executor must place its pid inside the correct
cgroups before starting the process. This is done so that no child processes or
threads can escape the cgroups.

When the process is stopped, the process executor will try (in a best-effort way)
to stop all its children and remove the sub-cgroups.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type Cgroup struct {
CpuQuota int64 `json:"cpu_quota,omitempty"` // CPU hardcap limit (in usecs). Allowed cpu time in a given period.
CpuPeriod int64 `json:"cpu_period,omitempty"` // CPU period to be used for hardcapping (in usecs). 0 to use system default.
CpusetCpus string `json:"cpuset_cpus,omitempty"` // CPU to use
CpusetMems string `json:"cpuset_mems,omitempty"` // MEM to use
Freezer FreezerState `json:"freezer,omitempty"` // set the freeze value for the process
Slice string `json:"slice,omitempty"` // Parent slice to use for systemd
}
17 changes: 11 additions & 6 deletions vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuset.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func (s *CpusetGroup) Set(d *data) error {
if err != nil {
return err
}
return s.SetDir(dir, d.c.CpusetCpus, d.pid)
return s.SetDir(dir, d.c.CpusetCpus, d.c.CpusetMems, d.pid)
}

func (s *CpusetGroup) Remove(d *data) error {
Expand All @@ -29,7 +29,7 @@ func (s *CpusetGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}

func (s *CpusetGroup) SetDir(dir, value string, pid int) error {
func (s *CpusetGroup) SetDir(dir, cpus string, mems string, pid int) error {
if err := s.ensureParent(dir); err != nil {
return err
}
Expand All @@ -40,10 +40,15 @@ func (s *CpusetGroup) SetDir(dir, value string, pid int) error {
return err
}

// If we don't use --cpuset, the default cpuset.cpus is set in
// s.ensureParent, otherwise, use the value we set
if value != "" {
if err := writeFile(dir, "cpuset.cpus", value); err != nil {
// If we don't use --cpuset-xxx, the default value inherit from parent cgroup
// is set in s.ensureParent, otherwise, use the value we set
if cpus != "" {
if err := writeFile(dir, "cpuset.cpus", cpus); err != nil {
return err
}
}
if mems != "" {
if err := writeFile(dir, "cpuset.mems", mems); err != nil {
return err
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,17 @@ func (s *MemoryGroup) Set(d *data) error {
}
}
// By default, MemorySwap is set to twice the size of RAM.
// If you want to omit MemorySwap, set it to `-1'.
if d.c.MemorySwap != -1 {
// If you want to omit MemorySwap, set it to '-1'.
if d.c.MemorySwap == 0 {
if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(d.c.Memory*2, 10)); err != nil {
return err
}
}
if d.c.MemorySwap > 0 {
if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(d.c.MemorySwap, 10)); err != nil {
return err
}
}
}
return nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,8 @@ func expectMemoryStatEquals(t *testing.T, expected, actual cgroups.MemoryStats)
t.Fail()
}
}
if expected.Failcnt != actual.Failcnt {
log.Printf("Expected memory failcnt %d but found %d\n", expected.Failcnt, actual.Failcnt)
t.Fail()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -313,5 +313,5 @@ func joinCpuset(c *cgroups.Cgroup, pid int) error {

s := &fs.CpusetGroup{}

return s.SetDir(path, c.CpusetCpus, pid)
return s.SetDir(path, c.CpusetCpus, c.CpusetMems, pid)
}
30 changes: 24 additions & 6 deletions vendor/src/github.com/docker/libcontainer/cgroups/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"path/filepath"
"strconv"
"strings"
"time"

"github.com/docker/docker/pkg/mount"
)
Expand Down Expand Up @@ -193,13 +194,30 @@ func EnterPid(cgroupPaths map[string]string, pid int) error {
}

// RemovePaths iterates over the provided paths removing them.
// If an error is encountered the removal proceeds and the first error is
// returned to ensure a partial removal is not possible.
// We trying to remove all paths five times with increasing delay between tries.
// If after all there are not removed cgroups - appropriate error will be
// returned.
func RemovePaths(paths map[string]string) (err error) {
for _, path := range paths {
if rerr := os.RemoveAll(path); err == nil {
err = rerr
delay := 10 * time.Millisecond
for i := 0; i < 5; i++ {
if i != 0 {
time.Sleep(delay)
delay *= 2
}
for s, p := range paths {
os.RemoveAll(p)
// TODO: here probably should be logging
_, err := os.Stat(p)
// We need this strange way of checking cgroups existence because
// RemoveAll almost always returns error, even on already removed
// cgroups
if os.IsNotExist(err) {
delete(paths, s)
}
}
if len(paths) == 0 {
return nil
}
}
return err
return fmt.Errorf("Failed to remove paths: %s", paths)
}
56 changes: 52 additions & 4 deletions vendor/src/github.com/docker/libcontainer/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,57 @@ type MountConfig mount.MountConfig

type Network network.Network

type NamespaceType string

const (
NEWNET NamespaceType = "NEWNET"
NEWPID NamespaceType = "NEWPID"
NEWNS NamespaceType = "NEWNS"
NEWUTS NamespaceType = "NEWUTS"
NEWIPC NamespaceType = "NEWIPC"
NEWUSER NamespaceType = "NEWUSER"
)

// Namespace defines configuration for each namespace. It specifies an
// alternate path that is able to be joined via setns.
type Namespace struct {
Type NamespaceType `json:"type"`
Path string `json:"path,omitempty"`
}

type Namespaces []Namespace

func (n Namespaces) Remove(t NamespaceType) bool {
i := n.index(t)
if i == -1 {
return false
}
n = append(n[:i], n[i+1:]...)
return true
}

func (n Namespaces) Add(t NamespaceType, path string) {
i := n.index(t)
if i == -1 {
n = append(n, Namespace{Type: t, Path: path})
return
}
n[i].Path = path
}

func (n Namespaces) index(t NamespaceType) int {
for i, ns := range n {
if ns.Type == t {
return i
}
}
return -1
}

func (n Namespaces) Contains(t NamespaceType) bool {
return n.index(t) != -1
}

// Config defines configuration options for executing a process inside a contained environment.
type Config struct {
// Mount specific options.
Expand Down Expand Up @@ -38,7 +89,7 @@ type Config struct {

// Namespaces specifies the container's namespaces that it should setup when cloning the init process
// If a namespace is not provided that namespace is shared from the container's parent process
Namespaces map[string]bool `json:"namespaces,omitempty"`
Namespaces Namespaces `json:"namespaces,omitempty"`

// Capabilities specify the capabilities to keep when executing the process inside the container
// All capbilities not specified will be dropped from the processes capability mask
Expand All @@ -47,9 +98,6 @@ type Config struct {
// Networks specifies the container's network setup to be created
Networks []*Network `json:"networks,omitempty"`

// Ipc specifies the container's ipc setup to be created
IpcNsPath string `json:"ipc,omitempty"`

// Routes can be specified to create entries in the route table as the container is started
Routes []*Route `json:"routes,omitempty"`

Expand Down
4 changes: 2 additions & 2 deletions vendor/src/github.com/docker/libcontainer/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ func TestConfigJsonFormat(t *testing.T) {
t.Fail()
}

if !container.Namespaces["NEWNET"] {
if !container.Namespaces.Contains(NEWNET) {
t.Log("namespaces should contain NEWNET")
t.Fail()
}

if container.Namespaces["NEWUSER"] {
if container.Namespaces.Contains(NEWUSER) {
t.Log("namespaces should not contain NEWUSER")
t.Fail()
}
Expand Down
Loading

0 comments on commit 50905a6

Please sign in to comment.