1
0
Fork 0
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:
Jana Radhakrishnan 2015-06-05 15:02:56 -07:00
parent 7c64ed5c8c
commit c68e7f96f9
15 changed files with 132 additions and 14 deletions

View file

@ -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

View file

@ -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

View file

@ -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))
}

View file

@ -79,7 +79,7 @@
},
{
"ImportPath": "github.com/vishvananda/netns",
"Rev": "008d17ae001344769b031375bdb38a86219154c6"
"Rev": "5478c060110032f972e86a1f844fdb9a2f008f2c"
}
]
}

View file

@ -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()
}

View file

@ -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 {

View file

@ -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())
}
}
}

View file

@ -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()

View file

@ -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

View file

@ -1,3 +1,5 @@
// +build linux
package netns
import (

View file

@ -1,3 +1,5 @@
// +build linux,386
package netns
const (

View file

@ -1,3 +1,5 @@
// +build linux,amd64
package netns
const (

View file

@ -1,3 +1,5 @@
// +build linux,arm
package netns
const (

View file

@ -0,0 +1,7 @@
// +build linux,ppc64le
package netns
const (
SYS_SETNS = 350
)

View file

@ -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
}