Vendoring in libnetwork 2da2dc055de5a474c8540871ad88a48213b0994f
Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
parent
f5d3311839
commit
d429465b37
|
@ -55,7 +55,7 @@ clone hg code.google.com/p/go.net 84a4013f96e0
|
||||||
clone hg code.google.com/p/gosqlite 74691fb6f837
|
clone hg code.google.com/p/gosqlite 74691fb6f837
|
||||||
|
|
||||||
#get libnetwork packages
|
#get libnetwork packages
|
||||||
clone git github.com/docker/libnetwork 67438080724b17b641b411322822c00d0d3c3201
|
clone git github.com/docker/libnetwork 2da2dc055de5a474c8540871ad88a48213b0994f
|
||||||
clone git github.com/vishvananda/netns 008d17ae001344769b031375bdb38a86219154c6
|
clone git github.com/vishvananda/netns 008d17ae001344769b031375bdb38a86219154c6
|
||||||
clone git github.com/vishvananda/netlink 8eb64238879fed52fd51c5b30ad20b928fb4c36c
|
clone git github.com/vishvananda/netlink 8eb64238879fed52fd51c5b30ad20b928fb4c36c
|
||||||
|
|
||||||
|
|
|
@ -4,17 +4,27 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/docker/pkg/reexec"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
"github.com/vishvananda/netns"
|
"github.com/vishvananda/netns"
|
||||||
)
|
)
|
||||||
|
|
||||||
const prefix = "/var/run/docker/netns"
|
const prefix = "/var/run/docker/netns"
|
||||||
|
|
||||||
var once sync.Once
|
var (
|
||||||
|
once sync.Once
|
||||||
|
garbagePathMap = make(map[string]bool)
|
||||||
|
gpmLock sync.Mutex
|
||||||
|
gpmWg sync.WaitGroup
|
||||||
|
gpmCleanupPeriod = 60 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
// The networkNamespace type is the linux implementation of the Sandbox
|
// The networkNamespace type is the linux implementation of the Sandbox
|
||||||
// interface. It represents a linux network namespace, and moves an interface
|
// interface. It represents a linux network namespace, and moves an interface
|
||||||
|
@ -26,11 +36,49 @@ type networkNamespace struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
reexec.Register("netns-create", reexecCreateNamespace)
|
||||||
|
}
|
||||||
|
|
||||||
func createBasePath() {
|
func createBasePath() {
|
||||||
err := os.MkdirAll(prefix, 0644)
|
err := os.MkdirAll(prefix, 0644)
|
||||||
if err != nil && !os.IsExist(err) {
|
if err != nil && !os.IsExist(err) {
|
||||||
panic("Could not create net namespace path directory")
|
panic("Could not create net namespace path directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start the garbage collection go routine
|
||||||
|
go removeUnusedPaths()
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeUnusedPaths() {
|
||||||
|
for range time.Tick(gpmCleanupPeriod) {
|
||||||
|
gpmLock.Lock()
|
||||||
|
pathList := make([]string, 0, len(garbagePathMap))
|
||||||
|
for path := range garbagePathMap {
|
||||||
|
pathList = append(pathList, path)
|
||||||
|
}
|
||||||
|
garbagePathMap = make(map[string]bool)
|
||||||
|
gpmWg.Add(1)
|
||||||
|
gpmLock.Unlock()
|
||||||
|
|
||||||
|
for _, path := range pathList {
|
||||||
|
os.Remove(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
gpmWg.Done()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addToGarbagePaths(path string) {
|
||||||
|
gpmLock.Lock()
|
||||||
|
garbagePathMap[path] = true
|
||||||
|
gpmLock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeFromGarbagePaths(path string) {
|
||||||
|
gpmLock.Lock()
|
||||||
|
delete(garbagePathMap, path)
|
||||||
|
gpmLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateKey generates a sandbox key based on the passed
|
// GenerateKey generates a sandbox key based on the passed
|
||||||
|
@ -55,6 +103,20 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
||||||
return &networkNamespace{path: key, sinfo: info}, nil
|
return &networkNamespace{path: key, sinfo: info}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func reexecCreateNamespace() {
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
log.Fatal("no namespace path provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := syscall.Mount("/proc/self/ns/net", os.Args[1], "bind", syscall.MS_BIND, ""); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := loopbackUp(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createNetworkNamespace(path string, osCreate bool) (*Info, error) {
|
func createNetworkNamespace(path string, osCreate bool) (*Info, error) {
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
defer runtime.UnlockOSThread()
|
defer runtime.UnlockOSThread()
|
||||||
|
@ -69,23 +131,18 @@ func createNetworkNamespace(path string, osCreate bool) (*Info, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if osCreate {
|
cmd := &exec.Cmd{
|
||||||
defer netns.Set(origns)
|
Path: reexec.Self(),
|
||||||
newns, err := netns.New()
|
Args: append([]string{"netns-create"}, path),
|
||||||
if err != nil {
|
Stdout: os.Stdout,
|
||||||
return nil, err
|
Stderr: os.Stderr,
|
||||||
}
|
|
||||||
defer newns.Close()
|
|
||||||
|
|
||||||
if err := loopbackUp(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if osCreate {
|
||||||
procNet := fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid())
|
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||||
|
cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNET
|
||||||
if err := syscall.Mount(procNet, path, "bind", syscall.MS_BIND, ""); err != nil {
|
}
|
||||||
return nil, err
|
if err := cmd.Run(); err != nil {
|
||||||
|
return nil, fmt.Errorf("namespace creation reexec command failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
interfaces := []*Interface{}
|
interfaces := []*Interface{}
|
||||||
|
@ -93,10 +150,9 @@ func createNetworkNamespace(path string, osCreate bool) (*Info, error) {
|
||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanupNamespaceFile(path string) {
|
func unmountNamespaceFile(path string) {
|
||||||
if _, err := os.Stat(path); err == nil {
|
if _, err := os.Stat(path); err == nil {
|
||||||
n := &networkNamespace{path: path}
|
syscall.Unmount(path, syscall.MNT_DETACH)
|
||||||
n.Destroy()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,11 +160,20 @@ func createNamespaceFile(path string) (err error) {
|
||||||
var f *os.File
|
var f *os.File
|
||||||
|
|
||||||
once.Do(createBasePath)
|
once.Do(createBasePath)
|
||||||
// cleanup namespace file if it already exists because of a previous ungraceful exit.
|
// Remove it from garbage collection list if present
|
||||||
cleanupNamespaceFile(path)
|
removeFromGarbagePaths(path)
|
||||||
|
|
||||||
|
// If the path is there unmount it first
|
||||||
|
unmountNamespaceFile(path)
|
||||||
|
|
||||||
|
// wait for garbage collection to complete if it is in progress
|
||||||
|
// before trying to create the file.
|
||||||
|
gpmWg.Wait()
|
||||||
|
|
||||||
if f, err = os.Create(path); err == nil {
|
if f, err = os.Create(path); err == nil {
|
||||||
f.Close()
|
f.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,5 +334,7 @@ func (n *networkNamespace) Destroy() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.Remove(n.path)
|
// Stash it into the garbage collection list
|
||||||
|
addToGarbagePaths(n.path)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/docker/libnetwork/netutils"
|
"github.com/docker/libnetwork/netutils"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
|
@ -31,6 +32,9 @@ func newKey(t *testing.T) (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the rpmCleanupPeriod to be low to make the test run quicker
|
||||||
|
gpmCleanupPeriod = 2 * time.Second
|
||||||
|
|
||||||
return name, nil
|
return name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,3 +141,10 @@ func verifySandbox(t *testing.T, s Sandbox) {
|
||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func verifyCleanup(t *testing.T, s Sandbox) {
|
||||||
|
time.Sleep(time.Duration(gpmCleanupPeriod * 2))
|
||||||
|
if _, err := os.Stat(s.Key()); err == nil {
|
||||||
|
t.Fatalf("The sandbox path %s is not getting cleanup event after twice the cleanup period", s.Key())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,9 +2,19 @@ package sandbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/pkg/reexec"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
if reexec.Init() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
func TestSandboxCreate(t *testing.T) {
|
func TestSandboxCreate(t *testing.T) {
|
||||||
key, err := newKey(t)
|
key, err := newKey(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -44,6 +54,7 @@ func TestSandboxCreate(t *testing.T) {
|
||||||
|
|
||||||
verifySandbox(t, s)
|
verifySandbox(t, s)
|
||||||
s.Destroy()
|
s.Destroy()
|
||||||
|
verifyCleanup(t, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSandboxCreateTwice(t *testing.T) {
|
func TestSandboxCreateTwice(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue