Merge pull request #245 from crosbymichael/share-ipc

Allow IPC namespace to be shared between containers or with the host
This commit is contained in:
Michael Crosby 2014-10-28 15:17:07 -07:00
commit f60d7b9195
5 changed files with 158 additions and 2 deletions

View File

@ -12,10 +12,10 @@ sh:
GO_PACKAGES = $(shell find . -not \( -wholename ./vendor -prune -o -wholename ./.git -prune \) -name '*.go' -print0 | xargs -0n1 dirname | sort -u) GO_PACKAGES = $(shell find . -not \( -wholename ./vendor -prune -o -wholename ./.git -prune \) -name '*.go' -print0 | xargs -0n1 dirname | sort -u)
direct-test: direct-test:
go test -cover -v $(GO_PACKAGES) go test $(TEST_TAGS) -cover -v $(GO_PACKAGES)
direct-test-short: direct-test-short:
go test -cover -test.short -v $(GO_PACKAGES) go test $(TEST_TAGS) -cover -test.short -v $(GO_PACKAGES)
direct-build: direct-build:
go build -v $(GO_PACKAGES) go build -v $(GO_PACKAGES)

View File

@ -47,6 +47,9 @@ type Config struct {
// Networks specifies the container's network setup to be created // Networks specifies the container's network setup to be created
Networks []*Network `json:"networks,omitempty"` 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 can be specified to create entries in the route table as the container is started
Routes []*Route `json:"routes,omitempty"` Routes []*Route `json:"routes,omitempty"`

View File

@ -1,6 +1,7 @@
package integration package integration
import ( import (
"os"
"strings" "strings"
"testing" "testing"
) )
@ -36,3 +37,122 @@ func TestExecPS(t *testing.T) {
t.Fatalf("expected output %q but received %q", expected, actual) t.Fatalf("expected output %q but received %q", expected, actual)
} }
} }
func TestIPCPrivate(t *testing.T) {
if testing.Short() {
return
}
rootfs, err := newRootFs()
if err != nil {
t.Fatal(err)
}
defer remove(rootfs)
l, err := os.Readlink("/proc/1/ns/ipc")
if err != nil {
t.Fatal(err)
}
config := newTemplateConfig(rootfs)
config.Namespaces["NEWIPC"] = true
buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
if err != nil {
t.Fatal(err)
}
if exitCode != 0 {
t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
}
if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual == l {
t.Fatalf("ipc link should be private to the conatiner but equals host %q %q", actual, l)
}
}
func TestIPCHost(t *testing.T) {
if testing.Short() {
return
}
rootfs, err := newRootFs()
if err != nil {
t.Fatal(err)
}
defer remove(rootfs)
l, err := os.Readlink("/proc/1/ns/ipc")
if err != nil {
t.Fatal(err)
}
config := newTemplateConfig(rootfs)
config.Namespaces["NEWIPC"] = false
buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
if err != nil {
t.Fatal(err)
}
if exitCode != 0 {
t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
}
if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual != l {
t.Fatalf("ipc link not equal to host link %q %q", actual, l)
}
}
func TestIPCJoinPath(t *testing.T) {
if testing.Short() {
return
}
rootfs, err := newRootFs()
if err != nil {
t.Fatal(err)
}
defer remove(rootfs)
l, err := os.Readlink("/proc/1/ns/ipc")
if err != nil {
t.Fatal(err)
}
config := newTemplateConfig(rootfs)
config.Namespaces["NEWIPC"] = false
config.IpcNsPath = "/proc/1/ns/ipc"
buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
if err != nil {
t.Fatal(err)
}
if exitCode != 0 {
t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
}
if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual != l {
t.Fatalf("ipc link not equal to host link %q %q", actual, l)
}
}
func TestIPCBadPath(t *testing.T) {
if testing.Short() {
return
}
rootfs, err := newRootFs()
if err != nil {
t.Fatal(err)
}
defer remove(rootfs)
config := newTemplateConfig(rootfs)
config.Namespaces["NEWIPC"] = false
config.IpcNsPath = "/proc/1/ns/ipcc"
_, _, err = runContainer(config, "", "true")
if err == nil {
t.Fatal("container succeded with bad ipc path")
}
}

29
ipc/ipc.go Normal file
View File

@ -0,0 +1,29 @@
package ipc
import (
"fmt"
"os"
"syscall"
"github.com/docker/libcontainer/system"
)
// Join the IPC Namespace of specified ipc path if it exists.
// If the path does not exist then you are not joining a container.
func Initialize(nsPath string) error {
if nsPath == "" {
return nil
}
f, err := os.OpenFile(nsPath, os.O_RDONLY, 0)
if err != nil {
return fmt.Errorf("failed get IPC namespace fd: %v", err)
}
err = system.Setns(f.Fd(), syscall.CLONE_NEWIPC)
f.Close()
if err != nil {
return fmt.Errorf("failed to setns current IPC namespace: %v", err)
}
return nil
}

View File

@ -11,6 +11,7 @@ import (
"github.com/docker/libcontainer" "github.com/docker/libcontainer"
"github.com/docker/libcontainer/apparmor" "github.com/docker/libcontainer/apparmor"
"github.com/docker/libcontainer/console" "github.com/docker/libcontainer/console"
"github.com/docker/libcontainer/ipc"
"github.com/docker/libcontainer/label" "github.com/docker/libcontainer/label"
"github.com/docker/libcontainer/mount" "github.com/docker/libcontainer/mount"
"github.com/docker/libcontainer/netlink" "github.com/docker/libcontainer/netlink"
@ -66,6 +67,9 @@ func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syn
return fmt.Errorf("setctty %s", err) return fmt.Errorf("setctty %s", err)
} }
} }
if err := ipc.Initialize(container.IpcNsPath); err != nil {
return fmt.Errorf("setup IPC %s", err)
}
if err := setupNetwork(container, networkState); err != nil { if err := setupNetwork(container, networkState); err != nil {
return fmt.Errorf("setup networking %s", err) return fmt.Errorf("setup networking %s", err)
} }