Merge branch 'master' into pluginflag

Conflicts:
	pkg/cgroups/cgroups.go
	pkg/libcontainer/nsinit/exec.go
	pkg/libcontainer/nsinit/init.go
	pkg/libcontainer/nsinit/mount.go
	runconfig/hostconfig.go
	runconfig/parse.go
	runtime/execdriver/driver.go
	runtime/execdriver/lxc/lxc_template.go
	runtime/execdriver/lxc/lxc_template_unit_test.go
	runtime/execdriver/native/default_template.go
	runtime/execdriver/native/driver.go

Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
Upstream-commit: eab56ac007b263708b5526609c8be2bc19881467
Component: engine
This commit is contained in:
Michael Crosby
2014-03-27 08:00:18 +00:00
172 changed files with 9894 additions and 1535 deletions
+38 -16
View File
@@ -404,6 +404,7 @@ func populateCommand(c *Container) {
User: c.Config.User,
Config: driverConfig,
Resources: resources,
Context: c.Config.Context,
}
c.command.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
}
@@ -537,8 +538,18 @@ func (container *Container) Start() (err error) {
if container.Config.WorkingDir != "" {
container.Config.WorkingDir = path.Clean(container.Config.WorkingDir)
if err := os.MkdirAll(path.Join(container.basefs, container.Config.WorkingDir), 0755); err != nil {
return nil
pthInfo, err := os.Stat(path.Join(container.basefs, container.Config.WorkingDir))
if err != nil {
if !os.IsNotExist(err) {
return err
}
if err := os.MkdirAll(path.Join(container.basefs, container.Config.WorkingDir), 0755); err != nil {
return err
}
}
if pthInfo != nil && !pthInfo.IsDir() {
return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
}
}
@@ -905,12 +916,20 @@ func (container *Container) Stop(seconds int) error {
// 1. Send a SIGTERM
if err := container.KillSig(15); err != nil {
return err
utils.Debugf("Error sending kill SIGTERM: %s", err)
log.Print("Failed to send SIGTERM to the process, force killing")
if err := container.KillSig(9); err != nil {
return err
}
}
// 2. Wait for the process to exit on its own
if err := container.WaitTimeout(time.Duration(seconds) * time.Second); err != nil {
return err
log.Printf("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds)
// 3. If it doesn't, then send SIGKILL
if err := container.Kill(); err != nil {
return err
}
}
return nil
}
@@ -952,10 +971,11 @@ func (container *Container) ExportRw() (archive.Archive, error) {
return nil, err
}
return utils.NewReadCloserWrapper(archive, func() error {
err := archive.Close()
container.Unmount()
return err
}), nil
err := archive.Close()
container.Unmount()
return err
}),
nil
}
func (container *Container) Export() (archive.Archive, error) {
@@ -969,10 +989,11 @@ func (container *Container) Export() (archive.Archive, error) {
return nil, err
}
return utils.NewReadCloserWrapper(archive, func() error {
err := archive.Close()
container.Unmount()
return err
}), nil
err := archive.Close()
container.Unmount()
return err
}),
nil
}
func (container *Container) WaitTimeout(timeout time.Duration) error {
@@ -1121,10 +1142,11 @@ func (container *Container) Copy(resource string) (io.ReadCloser, error) {
return nil, err
}
return utils.NewReadCloserWrapper(archive, func() error {
err := archive.Close()
container.Unmount()
return err
}), nil
err := archive.Close()
container.Unmount()
return err
}),
nil
}
// Returns true if the container exposes a certain port
@@ -7,6 +7,10 @@ import (
"os/exec"
)
// Context is a generic key value pair that allows
// arbatrary data to be sent
type Context map[string]string
var (
ErrNotRunning = errors.New("Process could not be started")
ErrWaitTimeoutReached = errors.New("Wait timeout reached")
@@ -1,6 +1,7 @@
package lxc
import (
"github.com/dotcloud/docker/pkg/label"
"github.com/dotcloud/docker/runtime/execdriver"
"strings"
"text/template"
@@ -29,6 +30,10 @@ lxc.pts = 1024
# disable the main console
lxc.console = none
{{if getProcessLabel .Context}}
lxc.se_context = {{ getProcessLabel .Context}}
{{$MOUNTLABEL := getMountLabel .Context}}
{{end}}
# no controlling tty at all
lxc.tty = 1
@@ -85,8 +90,8 @@ lxc.mount.entry = sysfs {{escapeFstabSpaces $ROOTFS}}/sys sysfs nosuid,nodev,noe
lxc.mount.entry = {{.Console}} {{escapeFstabSpaces $ROOTFS}}/dev/console none bind,rw 0 0
{{end}}
lxc.mount.entry = devpts {{escapeFstabSpaces $ROOTFS}}/dev/pts devpts newinstance,ptmxmode=0666,nosuid,noexec 0 0
lxc.mount.entry = shm {{escapeFstabSpaces $ROOTFS}}/dev/shm tmpfs size=65536k,nosuid,nodev,noexec 0 0
lxc.mount.entry = devpts {{escapeFstabSpaces $ROOTFS}}/dev/pts devpts {{formatMountLabel "newinstance,ptmxmode=0666,nosuid,noexec" "$MOUNTLABEL"}} 0 0
lxc.mount.entry = shm {{escapeFstabSpaces $ROOTFS}}/dev/shm tmpfs {{formatMountLabel "size=65536k,nosuid,nodev,noexec" "$MOUNTLABEL"}} 0 0
{{range $value := .Mounts}}
{{if $value.Writable}}
@@ -142,11 +147,22 @@ func getMemorySwap(v *execdriver.Resources) int64 {
return v.Memory * 2
}
func getProcessLabel(c execdriver.Context) string {
return c["process_label"]
}
func getMountLabel(c execdriver.Context) string {
return c["mount_label"]
}
func init() {
var err error
funcMap := template.FuncMap{
"getMemorySwap": getMemorySwap,
"getProcessLabel": getProcessLabel,
"getMountLabel": getMountLabel,
"escapeFstabSpaces": escapeFstabSpaces,
"formatMountLabel": label.FormatMountLabel,
}
LxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate)
if err != nil {
@@ -75,10 +75,11 @@ func TestCustomLxcConfig(t *testing.T) {
command := &execdriver.Command{
ID: "1",
Privileged: false,
Config: map[string][]string{"lxc": {
"lxc.utsname = docker",
"lxc.cgroup.cpuset.cpus = 0,1",
},
Config: map[string][]string{
"lxc": {
"lxc.utsname = docker",
"lxc.cgroup.cpuset.cpus = 0,1",
},
},
Network: &execdriver.Network{
Mtu: 1500,
@@ -134,7 +134,7 @@ func (a Driver) Exists(id string) bool {
// Three folders are created for each id
// mnt, layers, and diff
func (a *Driver) Create(id, parent string) error {
func (a *Driver) Create(id, parent string, mountLabel string) error {
if err := a.createDirsFor(id); err != nil {
return err
}
@@ -90,7 +90,7 @@ func TestCreateNewDir(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
}
@@ -99,7 +99,7 @@ func TestCreateNewDirStructure(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -120,7 +120,7 @@ func TestRemoveImage(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -145,7 +145,7 @@ func TestGetWithoutParent(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -172,7 +172,7 @@ func TestCleanupWithDir(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -185,7 +185,7 @@ func TestMountedFalseResponse(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -204,10 +204,10 @@ func TestMountedTrueReponse(t *testing.T) {
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
if err := d.Create("2", "1"); err != nil {
if err := d.Create("2", "1", ""); err != nil {
t.Fatal(err)
}
@@ -230,10 +230,10 @@ func TestMountWithParent(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
if err := d.Create("2", "1"); err != nil {
if err := d.Create("2", "1", ""); err != nil {
t.Fatal(err)
}
@@ -261,10 +261,10 @@ func TestRemoveMountedDir(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
if err := d.Create("2", "1"); err != nil {
if err := d.Create("2", "1", ""); err != nil {
t.Fatal(err)
}
@@ -300,7 +300,7 @@ func TestCreateWithInvalidParent(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", "docker"); err == nil {
if err := d.Create("1", "docker", ""); err == nil {
t.Fatalf("Error should not be nil with parent does not exist")
}
}
@@ -309,7 +309,7 @@ func TestGetDiff(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -343,10 +343,10 @@ func TestChanges(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
if err := d.Create("2", "1"); err != nil {
if err := d.Create("2", "1", ""); err != nil {
t.Fatal(err)
}
@@ -392,7 +392,7 @@ func TestChanges(t *testing.T) {
t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
}
if err := d.Create("3", "2"); err != nil {
if err := d.Create("3", "2", ""); err != nil {
t.Fatal(err)
}
mntPoint, err = d.Get("3")
@@ -437,7 +437,7 @@ func TestDiffSize(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -479,7 +479,7 @@ func TestChildDiffSize(t *testing.T) {
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -515,7 +515,7 @@ func TestChildDiffSize(t *testing.T) {
t.Fatalf("Expected size to be %d got %d", size, diffSize)
}
if err := d.Create("2", "1"); err != nil {
if err := d.Create("2", "1", ""); err != nil {
t.Fatal(err)
}
@@ -534,7 +534,7 @@ func TestExists(t *testing.T) {
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -552,7 +552,7 @@ func TestStatus(t *testing.T) {
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -581,7 +581,7 @@ func TestApplyDiff(t *testing.T) {
defer os.RemoveAll(tmp)
defer d.Cleanup()
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -607,10 +607,10 @@ func TestApplyDiff(t *testing.T) {
t.Fatal(err)
}
if err := d.Create("2", ""); err != nil {
if err := d.Create("2", "", ""); err != nil {
t.Fatal(err)
}
if err := d.Create("3", "2"); err != nil {
if err := d.Create("3", "2", ""); err != nil {
t.Fatal(err)
}
@@ -656,7 +656,7 @@ func TestMountMoreThan42Layers(t *testing.T) {
}
current = hash(current)
if err := d.Create(current, parent); err != nil {
if err := d.Create(current, parent, ""); err != nil {
t.Logf("Current layer %d", i)
t.Fatal(err)
}
@@ -77,7 +77,7 @@ func (a *Driver) migrateContainers(pth string, setupInit func(p string) error) e
}
initID := fmt.Sprintf("%s-init", id)
if err := a.Create(initID, metadata.Image); err != nil {
if err := a.Create(initID, metadata.Image, ""); err != nil {
return err
}
@@ -90,7 +90,7 @@ func (a *Driver) migrateContainers(pth string, setupInit func(p string) error) e
return err
}
if err := a.Create(id, initID); err != nil {
if err := a.Create(id, initID, ""); err != nil {
return err
}
}
@@ -144,7 +144,7 @@ func (a *Driver) migrateImage(m *metadata, pth string, migrated map[string]bool)
return err
}
if !a.Exists(m.ID) {
if err := a.Create(m.ID, m.ParentID); err != nil {
if err := a.Create(m.ID, m.ParentID, ""); err != nil {
return err
}
}
@@ -80,7 +80,7 @@ func getDirFd(dir *C.DIR) uintptr {
return uintptr(C.dirfd(dir))
}
func subvolCreate(path, name string) error {
func subvolCreate(path, name string, mountLabel string) error {
dir, err := openDir(path)
if err != nil {
return err
@@ -155,13 +155,13 @@ func (d *Driver) subvolumesDirId(id string) string {
return path.Join(d.subvolumesDir(), id)
}
func (d *Driver) Create(id string, parent string) error {
func (d *Driver) Create(id string, parent string, mountLabel string) error {
subvolumes := path.Join(d.home, "subvolumes")
if err := os.MkdirAll(subvolumes, 0700); err != nil {
return err
}
if parent == "" {
if err := subvolCreate(subvolumes, id); err != nil {
if err := subvolCreate(subvolumes, id, mountLabel); err != nil {
return err
}
} else {
@@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/dotcloud/docker/pkg/label"
"github.com/dotcloud/docker/utils"
"io"
"io/ioutil"
@@ -14,6 +15,7 @@ import (
"strconv"
"strings"
"sync"
"syscall"
"time"
)
@@ -677,6 +679,12 @@ func (devices *DeviceSet) deactivateDevice(hash string) error {
utils.Debugf("[devmapper] deactivateDevice(%s)", hash)
defer utils.Debugf("[devmapper] deactivateDevice END")
// Wait for the unmount to be effective,
// by watching the value of Info.OpenCount for the device
if err := devices.waitClose(hash); err != nil {
utils.Errorf("Warning: error waiting for device %s to close: %s\n", hash, err)
}
info := devices.Devices[hash]
if info == nil {
return fmt.Errorf("Unknown device %s", hash)
@@ -799,26 +807,20 @@ func (devices *DeviceSet) Shutdown() error {
for _, info := range devices.Devices {
info.lock.Lock()
if info.mountCount > 0 {
if err := sysUnmount(info.mountPath, 0); err != nil {
// We use MNT_DETACH here in case it is still busy in some running
// container. This means it'll go away from the global scope directly,
// and the device will be released when that container dies.
if err := sysUnmount(info.mountPath, syscall.MNT_DETACH); err != nil {
utils.Debugf("Shutdown unmounting %s, error: %s\n", info.mountPath, err)
}
if err := devices.deactivateDevice(info.Hash); err != nil {
utils.Debugf("Shutdown deactivate %s , error: %s\n", info.Hash, err)
}
}
info.lock.Unlock()
}
for _, d := range devices.Devices {
d.lock.Lock()
if err := devices.waitClose(d.Hash); err != nil {
utils.Errorf("Warning: error waiting for device %s to unmount: %s\n", d.Hash, err)
}
if err := devices.deactivateDevice(d.Hash); err != nil {
utils.Debugf("Shutdown deactivate %s , error: %s\n", d.Hash, err)
}
d.lock.Unlock()
}
if err := devices.deactivatePool(); err != nil {
utils.Debugf("Shutdown deactivate pool , error: %s\n", err)
}
@@ -826,7 +828,7 @@ func (devices *DeviceSet) Shutdown() error {
return nil
}
func (devices *DeviceSet) MountDevice(hash, path string) error {
func (devices *DeviceSet) MountDevice(hash, path string, mountLabel string) error {
devices.Lock()
defer devices.Unlock()
@@ -858,9 +860,11 @@ func (devices *DeviceSet) MountDevice(hash, path string) error {
var flags uintptr = sysMsMgcVal
err := sysMount(info.DevName(), path, "ext4", flags, "discard")
mountOptions := label.FormatMountLabel("discard", mountLabel)
err := sysMount(info.DevName(), path, "ext4", flags, mountOptions)
if err != nil && err == sysEInval {
err = sysMount(info.DevName(), path, "ext4", flags, "")
mountOptions = label.FormatMountLabel(mountLabel, "")
err = sysMount(info.DevName(), path, "ext4", flags, mountOptions)
}
if err != nil {
return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), path, err)
@@ -920,14 +924,11 @@ func (devices *DeviceSet) UnmountDevice(hash string, mode UnmountMode) error {
return err
}
utils.Debugf("[devmapper] Unmount done")
// Wait for the unmount to be effective,
// by watching the value of Info.OpenCount for the device
if err := devices.waitClose(hash); err != nil {
if err := devices.deactivateDevice(hash); err != nil {
return err
}
devices.deactivateDevice(hash)
info.mountPath = ""
return nil
@@ -22,7 +22,8 @@ func init() {
type Driver struct {
*DeviceSet
home string
home string
MountLabel string
}
var Init = func(home string) (graphdriver.Driver, error) {
@@ -60,13 +61,13 @@ func (d *Driver) Cleanup() error {
return d.DeviceSet.Shutdown()
}
func (d *Driver) Create(id, parent string) error {
func (d *Driver) Create(id, parent string, mountLabel string) error {
d.MountLabel = mountLabel
if err := d.DeviceSet.AddDevice(id, parent); err != nil {
return err
}
mp := path.Join(d.home, "mnt", id)
if err := d.mount(id, mp); err != nil {
if err := d.mount(id, mp, d.MountLabel); err != nil {
return err
}
@@ -116,7 +117,7 @@ func (d *Driver) Remove(id string) error {
func (d *Driver) Get(id string) (string, error) {
mp := path.Join(d.home, "mnt", id)
if err := d.mount(id, mp); err != nil {
if err := d.mount(id, mp, d.MountLabel); err != nil {
return "", err
}
@@ -129,13 +130,13 @@ func (d *Driver) Put(id string) {
}
}
func (d *Driver) mount(id, mountPoint string) error {
func (d *Driver) mount(id, mountPoint string, mountLabel string) error {
// Create the target directories if they don't exist
if err := osMkdirAll(mountPoint, 0755); err != nil && !osIsExist(err) {
return err
}
// Mount the device
return d.DeviceSet.MountDevice(id, mountPoint)
return d.DeviceSet.MountDevice(id, mountPoint, mountLabel)
}
func (d *Driver) Exists(id string) bool {
@@ -494,7 +494,7 @@ func TestDriverCreate(t *testing.T) {
"?ioctl.loopctlgetfree",
)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
calls.Assert(t,
@@ -612,7 +612,7 @@ func TestDriverRemove(t *testing.T) {
"?ioctl.loopctlgetfree",
)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -668,7 +668,7 @@ func TestCleanup(t *testing.T) {
mountPoints := make([]string, 2)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
// Mount the id
@@ -678,7 +678,7 @@ func TestCleanup(t *testing.T) {
}
mountPoints[0] = p
if err := d.Create("2", "1"); err != nil {
if err := d.Create("2", "1", ""); err != nil {
t.Fatal(err)
}
@@ -731,7 +731,7 @@ func TestNotMounted(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -749,7 +749,7 @@ func TestMounted(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
if _, err := d.Get("1"); err != nil {
@@ -769,7 +769,7 @@ func TestInitCleanedDriver(t *testing.T) {
t.Skip("FIXME: not a unit test")
d := newDriver(t)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
if _, err := d.Get("1"); err != nil {
@@ -797,7 +797,7 @@ func TestMountMountedDriver(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -816,7 +816,7 @@ func TestGetReturnsValidDevice(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -844,7 +844,7 @@ func TestDriverGetSize(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
if err := d.Create("1", ""); err != nil {
if err := d.Create("1", "", ""); err != nil {
t.Fatal(err)
}
@@ -13,7 +13,7 @@ type InitFunc func(root string) (Driver, error)
type Driver interface {
String() string
Create(id, parent string) error
Create(id, parent string, mountLabel string) error
Remove(id string) error
Get(id string) (dir string, err error)
@@ -39,10 +39,9 @@ var (
// Slice of drivers that should be used in an order
priority = []string{
"aufs",
"btrfs",
"devicemapper",
"vfs",
// experimental, has to be enabled manually for now
"btrfs",
}
)
@@ -42,7 +42,7 @@ func copyDir(src, dst string) error {
return nil
}
func (d *Driver) Create(id string, parent string) error {
func (d *Driver) Create(id string, parent string, mountLabel string) error {
dir := d.dir(id)
if err := os.MkdirAll(path.Dir(dir), 0700); err != nil {
return err
@@ -1,4 +1,4 @@
package lxc
package bridge
import (
"fmt"
@@ -93,6 +93,12 @@ func InitDriver(job *engine.Job) engine.Status {
network = addr.(*net.IPNet)
} else {
network = addr.(*net.IPNet)
// validate that the bridge ip matches the ip specified by BridgeIP
if bridgeIP != "" {
if !network.IP.Equal(net.ParseIP(bridgeIP)) {
return job.Errorf("bridge ip (%s) does not match existing bridge configuration %s", network.IP, bridgeIP)
}
}
}
// Configure iptables for link support
@@ -100,22 +100,30 @@ func ReleaseAll() error {
}
func registerDynamicPort(ip net.IP, proto string) (int, error) {
allocated := defaultAllocatedPorts[proto]
port := nextPort(proto)
if port > EndPortRange {
return 0, ErrPortExceedsRange
}
if !equalsDefault(ip) {
registerIP(ip)
ipAllocated := otherAllocatedPorts[ip.String()][proto]
port, err := findNextPort(proto, ipAllocated)
if err != nil {
return 0, err
}
ipAllocated.Push(port)
return port, nil
} else {
allocated := defaultAllocatedPorts[proto]
port, err := findNextPort(proto, allocated)
if err != nil {
return 0, err
}
allocated.Push(port)
return port, nil
}
return port, nil
}
func registerSetPort(ip net.IP, proto string, port int) error {
@@ -142,6 +150,17 @@ func equalsDefault(ip net.IP) bool {
return ip == nil || ip.Equal(defaultIP)
}
func findNextPort(proto string, allocated *collections.OrderedIntSet) (int, error) {
port := nextPort(proto)
for allocated.Exists(port) {
port = nextPort(proto)
}
if port > EndPortRange {
return 0, ErrPortExceedsRange
}
return port, nil
}
func nextPort(proto string) int {
c := currentDynamicPort[proto] + 1
currentDynamicPort[proto] = c
@@ -181,4 +181,20 @@ func TestPortAllocation(t *testing.T) {
if _, err := RequestPort(ip, "tcp", 80); err != nil {
t.Fatal(err)
}
port, err = RequestPort(ip, "tcp", 0)
if err != nil {
t.Fatal(err)
}
port2, err := RequestPort(ip, "tcp", port+1)
if err != nil {
t.Fatal(err)
}
port3, err := RequestPort(ip, "tcp", 0)
if err != nil {
t.Fatal(err)
}
if port3 == port2 {
t.Fatal("Requesting a dynamic port should never allocate a used port")
}
}
+3 -3
View File
@@ -17,7 +17,7 @@ import (
"github.com/dotcloud/docker/runtime/execdriver/lxc"
"github.com/dotcloud/docker/runtime/graphdriver"
_ "github.com/dotcloud/docker/runtime/graphdriver/vfs"
_ "github.com/dotcloud/docker/runtime/networkdriver/lxc"
_ "github.com/dotcloud/docker/runtime/networkdriver/bridge"
"github.com/dotcloud/docker/runtime/networkdriver/portallocator"
"github.com/dotcloud/docker/utils"
"io"
@@ -467,7 +467,7 @@ func (runtime *Runtime) Create(config *runconfig.Config, name string) (*Containe
}
initID := fmt.Sprintf("%s-init", container.ID)
if err := runtime.driver.Create(initID, img.ID); err != nil {
if err := runtime.driver.Create(initID, img.ID, config.Context["mount_label"]); err != nil {
return nil, nil, err
}
initPath, err := runtime.driver.Get(initID)
@@ -480,7 +480,7 @@ func (runtime *Runtime) Create(config *runconfig.Config, name string) (*Containe
return nil, nil, err
}
if err := runtime.driver.Create(container.ID, initID); err != nil {
if err := runtime.driver.Create(container.ID, initID, config.Context["mount_label"]); err != nil {
return nil, nil, err
}
resolvConf, err := utils.GetResolvConf()
+3
View File
@@ -28,6 +28,9 @@ func (s *State) String() string {
}
return fmt.Sprintf("Up %s", utils.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
}
if s.FinishedAt.IsZero() {
return ""
}
return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, utils.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
}