mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
libnetwork: Add garbage collection trigger
When the daemon is going down trigger immediate garbage collection of libnetwork resources deleted like namespace path since there will be no way to remove them when the daemon restarts. Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
parent
7c64ed5c8c
commit
c68e7f96f9
15 changed files with 132 additions and 14 deletions
|
@ -996,6 +996,11 @@ func (daemon *Daemon) Shutdown() error {
|
|||
}
|
||||
}
|
||||
group.Wait()
|
||||
|
||||
// trigger libnetwork GC only if it's initialized
|
||||
if daemon.netController != nil {
|
||||
daemon.netController.GC()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -55,8 +55,8 @@ clone hg code.google.com/p/go.net 84a4013f96e0
|
|||
clone hg code.google.com/p/gosqlite 74691fb6f837
|
||||
|
||||
#get libnetwork packages
|
||||
clone git github.com/docker/libnetwork f72ad20491e8c46d9664da3f32a0eddb301e7c8d
|
||||
clone git github.com/vishvananda/netns 008d17ae001344769b031375bdb38a86219154c6
|
||||
clone git github.com/docker/libnetwork ace6b576239cd671d1645d82520b16791737f60d
|
||||
clone git github.com/vishvananda/netns 5478c060110032f972e86a1f844fdb9a2f008f2c
|
||||
clone git github.com/vishvananda/netlink 8eb64238879fed52fd51c5b30ad20b928fb4c36c
|
||||
|
||||
# get distribution packages
|
||||
|
|
|
@ -1174,6 +1174,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithContainerRunning(t *check.C) {
|
|||
if out, err := s.d.Cmd("run", "-ti", "-d", "--name", "test", "busybox"); err != nil {
|
||||
t.Fatal(out, err)
|
||||
}
|
||||
|
||||
if err := s.d.Restart(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1182,3 +1183,41 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithContainerRunning(t *check.C) {
|
|||
t.Fatal(out, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestDaemonRestartCleanupNetns(c *check.C) {
|
||||
if err := s.d.StartWithBusybox(); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
out, err := s.d.Cmd("run", "--name", "netns", "-d", "busybox", "top")
|
||||
if err != nil {
|
||||
c.Fatal(out, err)
|
||||
}
|
||||
if out, err := s.d.Cmd("stop", "netns"); err != nil {
|
||||
c.Fatal(out, err)
|
||||
}
|
||||
|
||||
// Construct netns file name from container id
|
||||
out = strings.TrimSpace(out)
|
||||
nsFile := out[:12]
|
||||
|
||||
// Test if the file still exists
|
||||
out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", "/var/run/docker/netns/"+nsFile))
|
||||
out = strings.TrimSpace(out)
|
||||
c.Assert(err, check.IsNil, check.Commentf("Output: %s", out))
|
||||
c.Assert(out, check.Equals, "/var/run/docker/netns/"+nsFile, check.Commentf("Output: %s", out))
|
||||
|
||||
// Remove the container and restart the daemon
|
||||
if out, err := s.d.Cmd("rm", "netns"); err != nil {
|
||||
c.Fatal(out, err)
|
||||
}
|
||||
|
||||
if err := s.d.Restart(); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
// Test again and see now the netns file does not exist
|
||||
out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", "/var/run/docker/netns/"+nsFile))
|
||||
out = strings.TrimSpace(out)
|
||||
c.Assert(err, check.Not(check.IsNil), check.Commentf("Output: %s", out))
|
||||
// c.Assert(out, check.Equals, "", check.Commentf("Output: %s", out))
|
||||
}
|
||||
|
|
2
vendor/src/github.com/docker/libnetwork/Godeps/Godeps.json
generated
vendored
2
vendor/src/github.com/docker/libnetwork/Godeps/Godeps.json
generated
vendored
|
@ -79,7 +79,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/vishvananda/netns",
|
||||
"Rev": "008d17ae001344769b031375bdb38a86219154c6"
|
||||
"Rev": "5478c060110032f972e86a1f844fdb9a2f008f2c"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -76,6 +76,9 @@ type NetworkController interface {
|
|||
|
||||
// NetworkByID returns the Network which has the passed id. If not found, the error ErrNoSuchNetwork is returned.
|
||||
NetworkByID(id string) (Network, error)
|
||||
|
||||
// GC triggers immediate garbage collection of resources which are garbage collected.
|
||||
GC()
|
||||
}
|
||||
|
||||
// NetworkWalker is a client provided function which will be used to walk the Networks.
|
||||
|
@ -299,3 +302,7 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
|
|||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (c *controller) GC() {
|
||||
sandbox.GC()
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ var (
|
|||
gpmLock sync.Mutex
|
||||
gpmWg sync.WaitGroup
|
||||
gpmCleanupPeriod = 60 * time.Second
|
||||
gpmChan = make(chan chan struct{})
|
||||
)
|
||||
|
||||
// The networkNamespace type is the linux implementation of the Sandbox
|
||||
|
@ -55,7 +56,18 @@ func removeUnusedPaths() {
|
|||
period := gpmCleanupPeriod
|
||||
gpmLock.Unlock()
|
||||
|
||||
for range time.Tick(period) {
|
||||
ticker := time.NewTicker(period)
|
||||
for {
|
||||
var (
|
||||
gc chan struct{}
|
||||
gcOk bool
|
||||
)
|
||||
|
||||
select {
|
||||
case <-ticker.C:
|
||||
case gc, gcOk = <-gpmChan:
|
||||
}
|
||||
|
||||
gpmLock.Lock()
|
||||
pathList := make([]string, 0, len(garbagePathMap))
|
||||
for path := range garbagePathMap {
|
||||
|
@ -70,6 +82,9 @@ func removeUnusedPaths() {
|
|||
}
|
||||
|
||||
gpmWg.Done()
|
||||
if gcOk {
|
||||
close(gc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,6 +100,18 @@ func removeFromGarbagePaths(path string) {
|
|||
gpmLock.Unlock()
|
||||
}
|
||||
|
||||
// GC triggers garbage collection of namespace path right away
|
||||
// and waits for it.
|
||||
func GC() {
|
||||
waitGC := make(chan struct{})
|
||||
|
||||
// Trigger GC now
|
||||
gpmChan <- waitGC
|
||||
|
||||
// wait for gc to complete
|
||||
<-waitGC
|
||||
}
|
||||
|
||||
// GenerateKey generates a sandbox key based on the passed
|
||||
// container id.
|
||||
func GenerateKey(containerID string) string {
|
||||
|
|
|
@ -144,9 +144,16 @@ func verifySandbox(t *testing.T, s Sandbox) {
|
|||
}
|
||||
}
|
||||
|
||||
func verifyCleanup(t *testing.T, s Sandbox) {
|
||||
time.Sleep(time.Duration(gpmCleanupPeriod * 2))
|
||||
func verifyCleanup(t *testing.T, s Sandbox, wait bool) {
|
||||
if wait {
|
||||
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())
|
||||
if wait {
|
||||
t.Fatalf("The sandbox path %s is not getting cleaned up even after twice the cleanup period", s.Key())
|
||||
} else {
|
||||
t.Fatalf("The sandbox path %s is not cleaned up after running gc", s.Key())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ func TestSandboxCreate(t *testing.T) {
|
|||
|
||||
verifySandbox(t, s)
|
||||
s.Destroy()
|
||||
verifyCleanup(t, s)
|
||||
verifyCleanup(t, s, true)
|
||||
}
|
||||
|
||||
func TestSandboxCreateTwice(t *testing.T) {
|
||||
|
@ -77,6 +77,23 @@ func TestSandboxCreateTwice(t *testing.T) {
|
|||
s.Destroy()
|
||||
}
|
||||
|
||||
func TestSandboxGC(t *testing.T) {
|
||||
key, err := newKey(t)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to obtain a key: %v", err)
|
||||
}
|
||||
|
||||
s, err := NewSandbox(key, true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a new sandbox: %v", err)
|
||||
}
|
||||
|
||||
s.Destroy()
|
||||
|
||||
GC()
|
||||
verifyCleanup(t, s, false)
|
||||
}
|
||||
|
||||
func TestInterfaceEqual(t *testing.T) {
|
||||
list := getInterfaceList()
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"fmt"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// NsHandle is a handle to a network namespace. It can be cast directly
|
||||
// to an int and used as a file descriptor.
|
||||
type NsHandle int
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build linux
|
||||
|
||||
package netns
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build linux,386
|
||||
|
||||
package netns
|
||||
|
||||
const (
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build linux,amd64
|
||||
|
||||
package netns
|
||||
|
||||
const (
|
|
@ -1,3 +1,5 @@
|
|||
// +build linux,arm
|
||||
|
||||
package netns
|
||||
|
||||
const (
|
||||
|
|
7
vendor/src/github.com/vishvananda/netns/netns_linux_ppc64le.go
vendored
Normal file
7
vendor/src/github.com/vishvananda/netns/netns_linux_ppc64le.go
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
// +build linux,ppc64le
|
||||
|
||||
package netns
|
||||
|
||||
const (
|
||||
SYS_SETNS = 350
|
||||
)
|
|
@ -10,26 +10,26 @@ var (
|
|||
ErrNotImplemented = errors.New("not implemented")
|
||||
)
|
||||
|
||||
func Set(ns Namespace) (err error) {
|
||||
func Set(ns NsHandle) (err error) {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func New() (ns Namespace, err error) {
|
||||
func New() (ns NsHandle, err error) {
|
||||
return -1, ErrNotImplemented
|
||||
}
|
||||
|
||||
func Get() (Namespace, error) {
|
||||
func Get() (NsHandle, error) {
|
||||
return -1, ErrNotImplemented
|
||||
}
|
||||
|
||||
func GetFromName(name string) (Namespace, error) {
|
||||
func GetFromName(name string) (NsHandle, error) {
|
||||
return -1, ErrNotImplemented
|
||||
}
|
||||
|
||||
func GetFromPid(pid int) (Namespace, error) {
|
||||
func GetFromPid(pid int) (NsHandle, error) {
|
||||
return -1, ErrNotImplemented
|
||||
}
|
||||
|
||||
func GetFromDocker(id string) (Namespace, error) {
|
||||
func GetFromDocker(id string) (NsHandle, error) {
|
||||
return -1, ErrNotImplemented
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue