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:
commit
f60d7b9195
4
Makefile
4
Makefile
|
@ -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)
|
||||||
|
|
|
@ -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"`
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue