mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #20195 from tiborvass/1.10.1-cherrypicks
1.10.1 cherrypicks
This commit is contained in:
commit
6ab0256048
36 changed files with 571 additions and 127 deletions
38
CHANGELOG.md
38
CHANGELOG.md
|
@ -5,6 +5,44 @@ information on the list of deprecated flags and APIs please have a look at
|
|||
https://docs.docker.com/misc/deprecated/ where target removal dates can also
|
||||
be found.
|
||||
|
||||
## 1.10.1 (2016-02-11)
|
||||
|
||||
### Runtime
|
||||
|
||||
* Do not stop daemon on migration hard failure [#20156](https://github.com/docker/docker/pull/20156)
|
||||
- Fix various issues with migration to content-addressable images [#20058](https://github.com/docker/docker/pull/20058)
|
||||
- Fix ZFS permission bug with user namespaces [#20045](https://github.com/docker/docker/pull/20045)
|
||||
- Do not leak /dev/mqueue from the host to all containers, keep it container-specific [#19876](https://github.com/docker/docker/pull/19876) [#20133](https://github.com/docker/docker/pull/20133)
|
||||
- Fix `docker ps --filter before=...` to work without needing `-a` flag [#20135](https://github.com/docker/docker/pull/20135)
|
||||
|
||||
### Security
|
||||
|
||||
- Fix issue preventing docker events to work properly with authorization plugin [#20002](https://github.com/docker/docker/pull/20002)
|
||||
|
||||
### Distribution
|
||||
|
||||
* Add additional verifications and prevent from uploading invalid data to registries [#20164](https://github.com/docker/docker/pull/20164)
|
||||
- Fix regression preventing uppercase characters in image reference hostname [#20175](https://github.com/docker/docker/pull/20175)
|
||||
|
||||
### Networking
|
||||
|
||||
- Fix embedded DNS for user-defined networks in the presence of firewalld [#20060](https://github.com/docker/docker/pull/20060)
|
||||
- Fix issue where removing a network during shutdown left Docker inoperable [#20181](https://github.com/docker/docker/issues/20181)
|
||||
- Embedded DNS is now able to return compressed results [#20181](https://github.com/docker/docker/issues/20181)
|
||||
- Fix port-mapping issue with `userland-proxy=false` [#20181](https://github.com/docker/docker/issues/20181)
|
||||
|
||||
### Logging
|
||||
|
||||
- Fix bug where tcp+tls protocol would be rejected [#20109](https://github.com/docker/docker/pull/20109)
|
||||
|
||||
### Volumes
|
||||
|
||||
- Fix issue whereby older volume drivers would not receive volume options [#19983](https://github.com/docker/docker/pull/19983)
|
||||
|
||||
### Misc
|
||||
|
||||
- Remove TasksMax from Docker systemd service [#20167](https://github.com/docker/docker/pull/20167)
|
||||
|
||||
## 1.10.0 (2016-02-04)
|
||||
|
||||
**IMPORTANT**: Docker 1.10 uses a new content-addressable storage for images and layers.
|
||||
|
|
|
@ -44,7 +44,6 @@ type Container struct {
|
|||
HostnamePath string
|
||||
HostsPath string
|
||||
ShmPath string
|
||||
MqueuePath string
|
||||
ResolvConfPath string
|
||||
SeccompProfile string
|
||||
}
|
||||
|
@ -563,18 +562,6 @@ func (container *Container) UnmountIpcMounts(unmount func(pth string) error) {
|
|||
}
|
||||
}
|
||||
|
||||
if !container.HasMountFor("/dev/mqueue") {
|
||||
mqueuePath, err := container.MqueueResourcePath()
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
warnings = append(warnings, err.Error())
|
||||
} else if mqueuePath != "" {
|
||||
if err := unmount(mqueuePath); err != nil {
|
||||
warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", mqueuePath, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(warnings) > 0 {
|
||||
logrus.Warnf("failed to cleanup ipc mounts:\n%v", strings.Join(warnings, "\n"))
|
||||
}
|
||||
|
@ -593,16 +580,6 @@ func (container *Container) IpcMounts() []execdriver.Mount {
|
|||
Propagation: volume.DefaultPropagationMode,
|
||||
})
|
||||
}
|
||||
|
||||
if !container.HasMountFor("/dev/mqueue") {
|
||||
label.SetFileLabel(container.MqueuePath, container.MountLabel)
|
||||
mounts = append(mounts, execdriver.Mount{
|
||||
Source: container.MqueuePath,
|
||||
Destination: "/dev/mqueue",
|
||||
Writable: true,
|
||||
Propagation: volume.DefaultPropagationMode,
|
||||
})
|
||||
}
|
||||
return mounts
|
||||
}
|
||||
|
||||
|
|
|
@ -1758,6 +1758,11 @@ _docker_run() {
|
|||
__docker_nospace
|
||||
fi
|
||||
;;
|
||||
seccomp:*)
|
||||
local cur=${cur##*:}
|
||||
_filedir
|
||||
COMPREPLY+=( $( compgen -W "unconfined" -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=( $( compgen -W "label apparmor seccomp" -S ":" -- "$cur") )
|
||||
__docker_nospace
|
||||
|
|
|
@ -11,7 +11,6 @@ MountFlags=slave
|
|||
LimitNOFILE=1048576
|
||||
LimitNPROC=1048576
|
||||
LimitCORE=infinity
|
||||
TasksMax=1048576
|
||||
TimeoutStartSec=0
|
||||
|
||||
[Install]
|
||||
|
|
|
@ -93,11 +93,6 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
|
|||
return err
|
||||
}
|
||||
|
||||
c.MqueuePath, err = c.MqueueResourcePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.HostConfig.IpcMode.IsContainer() {
|
||||
ic, err := daemon.getIpcContainer(c)
|
||||
if err != nil {
|
||||
|
@ -105,18 +100,13 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
|
|||
}
|
||||
ipc.ContainerID = ic.ID
|
||||
c.ShmPath = ic.ShmPath
|
||||
c.MqueuePath = ic.MqueuePath
|
||||
} else {
|
||||
ipc.HostIpc = c.HostConfig.IpcMode.IsHost()
|
||||
if ipc.HostIpc {
|
||||
if _, err := os.Stat("/dev/shm"); err != nil {
|
||||
return fmt.Errorf("/dev/shm is not mounted, but must be for --ipc=host")
|
||||
}
|
||||
if _, err := os.Stat("/dev/mqueue"); err != nil {
|
||||
return fmt.Errorf("/dev/mqueue is not mounted, but must be for --ipc=host")
|
||||
}
|
||||
c.ShmPath = "/dev/shm"
|
||||
c.MqueuePath = "/dev/mqueue"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1057,21 +1047,6 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
|
|||
}
|
||||
}
|
||||
|
||||
if !c.HasMountFor("/dev/mqueue") {
|
||||
mqueuePath, err := c.MqueueResourcePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := idtools.MkdirAllAs(mqueuePath, 0700, rootUID, rootGID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := syscall.Mount("mqueue", mqueuePath, "mqueue", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), ""); err != nil {
|
||||
return fmt.Errorf("mounting mqueue mqueue : %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,12 @@ func New() *configs.Config {
|
|||
Flags: syscall.MS_NOSUID | syscall.MS_NOEXEC,
|
||||
Data: "newinstance,ptmxmode=0666,mode=0620,gid=5",
|
||||
},
|
||||
{
|
||||
Source: "mqueue",
|
||||
Destination: "/dev/mqueue",
|
||||
Device: "mqueue",
|
||||
Flags: defaultMountFlags,
|
||||
},
|
||||
{
|
||||
Source: "sysfs",
|
||||
Destination: "/sys",
|
||||
|
|
|
@ -308,10 +308,14 @@ func (d *Driver) Get(id, mountLabel string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
err = mount.Mount(filesystem, mountpoint, "zfs", options)
|
||||
if err != nil {
|
||||
if err := mount.Mount(filesystem, mountpoint, "zfs", options); err != nil {
|
||||
return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err)
|
||||
}
|
||||
// this could be our first mount after creation of the filesystem, and the root dir may still have root
|
||||
// permissions instead of the remapped root uid:gid (if user namespaces are enabled):
|
||||
if err := os.Chown(mountpoint, rootUID, rootGID); err != nil {
|
||||
return "", fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err)
|
||||
}
|
||||
|
||||
return mountpoint, nil
|
||||
}
|
||||
|
|
|
@ -74,6 +74,13 @@ type listContext struct {
|
|||
filters filters.Args
|
||||
// exitAllowed is a list of exit codes allowed to filter with
|
||||
exitAllowed []int
|
||||
|
||||
// FIXME Remove this for 1.12 as --since and --before are deprecated
|
||||
// beforeContainer is a filter to ignore containers that appear before the one given
|
||||
beforeContainer *container.Container
|
||||
// sinceContainer is a filter to stop the filtering when the iterator arrive to the given container
|
||||
sinceContainer *container.Container
|
||||
|
||||
// beforeFilter is a filter to ignore containers that appear before the one given
|
||||
// this is used for --filter=before= and --before=, the latter is deprecated.
|
||||
beforeFilter *container.Container
|
||||
|
@ -165,6 +172,9 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error)
|
|||
}
|
||||
|
||||
var beforeContFilter, sinceContFilter *container.Container
|
||||
// FIXME remove this for 1.12 as --since and --before are deprecated
|
||||
var beforeContainer, sinceContainer *container.Container
|
||||
|
||||
err = psFilters.WalkValues("before", func(value string) error {
|
||||
beforeContFilter, err = daemon.GetContainer(value)
|
||||
return err
|
||||
|
@ -201,15 +211,17 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error)
|
|||
})
|
||||
}
|
||||
|
||||
if config.Before != "" && beforeContFilter == nil {
|
||||
beforeContFilter, err = daemon.GetContainer(config.Before)
|
||||
// FIXME remove this for 1.12 as --since and --before are deprecated
|
||||
if config.Before != "" {
|
||||
beforeContainer, err = daemon.GetContainer(config.Before)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if config.Since != "" && sinceContFilter == nil {
|
||||
sinceContFilter, err = daemon.GetContainer(config.Since)
|
||||
// FIXME remove this for 1.12 as --since and --before are deprecated
|
||||
if config.Since != "" {
|
||||
sinceContainer, err = daemon.GetContainer(config.Since)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -220,6 +232,8 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error)
|
|||
ancestorFilter: ancestorFilter,
|
||||
images: imagesFilter,
|
||||
exitAllowed: filtExited,
|
||||
beforeContainer: beforeContainer,
|
||||
sinceContainer: sinceContainer,
|
||||
beforeFilter: beforeContFilter,
|
||||
sinceFilter: sinceContFilter,
|
||||
ContainersConfig: config,
|
||||
|
@ -231,7 +245,8 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error)
|
|||
// It also decides if the iteration should be stopped or not.
|
||||
func includeContainerInList(container *container.Container, ctx *listContext) iterationAction {
|
||||
// Do not include container if it's stopped and we're not filters
|
||||
if !container.Running && !ctx.All && ctx.Limit <= 0 && ctx.beforeFilter == nil && ctx.sinceFilter == nil {
|
||||
// FIXME remove the ctx.beforContainer part of the condition for 1.12 as --since and --before are deprecated
|
||||
if !container.Running && !ctx.All && ctx.Limit <= 0 && ctx.beforeContainer == nil && ctx.sinceContainer == nil {
|
||||
return excludeContainer
|
||||
}
|
||||
|
||||
|
@ -255,6 +270,21 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
|
|||
return excludeContainer
|
||||
}
|
||||
|
||||
// FIXME remove this for 1.12 as --since and --before are deprecated
|
||||
if ctx.beforeContainer != nil {
|
||||
if container.ID == ctx.beforeContainer.ID {
|
||||
ctx.beforeContainer = nil
|
||||
}
|
||||
return excludeContainer
|
||||
}
|
||||
|
||||
// FIXME remove this for 1.12 as --since and --before are deprecated
|
||||
if ctx.sinceContainer != nil {
|
||||
if container.ID == ctx.sinceContainer.ID {
|
||||
return stopIteration
|
||||
}
|
||||
}
|
||||
|
||||
// Do not include container if it's in the list before the filter container.
|
||||
// Set the filter container to nil to include the rest of containers after this one.
|
||||
if ctx.beforeFilter != nil {
|
||||
|
|
|
@ -367,7 +367,7 @@ do_install() {
|
|||
|
||||
# aufs is preferred over devicemapper; try to ensure the driver is available.
|
||||
if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
|
||||
if uname -r | grep -q -- '-generic' && dpkg -l 'linux-image-*-generic' | grep -q '^ii' 2>/dev/null; then
|
||||
if uname -r | grep -q -- '-generic' && dpkg -l 'linux-image-*-generic' | grep -qE '^ii|^hi' 2>/dev/null; then
|
||||
kern_extras="linux-image-extra-$(uname -r) linux-image-extra-virtual"
|
||||
|
||||
apt_get_update
|
||||
|
|
|
@ -27,7 +27,7 @@ clone git github.com/RackSec/srslog 6eb773f331e46fbba8eecb8e794e635e75fc04de
|
|||
clone git github.com/imdario/mergo 0.2.1
|
||||
|
||||
#get libnetwork packages
|
||||
clone git github.com/docker/libnetwork v0.6.0-rc7
|
||||
clone git github.com/docker/libnetwork v0.6.1-rc2
|
||||
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
||||
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
||||
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
||||
|
|
|
@ -231,6 +231,9 @@ func (is *store) SetParent(id, parent ID) error {
|
|||
if parentMeta == nil {
|
||||
return fmt.Errorf("unknown parent image ID %s", parent.String())
|
||||
}
|
||||
if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil {
|
||||
delete(is.images[parent].children, id)
|
||||
}
|
||||
parentMeta.children[id] = struct{}{}
|
||||
return is.fs.SetMetadata(id, "parent", []byte(parent))
|
||||
}
|
||||
|
|
|
@ -233,6 +233,62 @@ func TestSearchAfterDelete(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestParentReset(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "images-fs-store")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
fs, err := NewFSStoreBackend(tmpdir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
is, err := NewImageStore(fs, &mockLayerGetReleaser{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
id, err := is.Create([]byte(`{"comment": "abc1", "rootfs": {"type": "layers"}}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
id2, err := is.Create([]byte(`{"comment": "abc2", "rootfs": {"type": "layers"}}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
id3, err := is.Create([]byte(`{"comment": "abc3", "rootfs": {"type": "layers"}}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := is.SetParent(id, id2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ids := is.Children(id2)
|
||||
if actual, expected := len(ids), 1; expected != actual {
|
||||
t.Fatalf("wrong number of children: %d, got %d", expected, actual)
|
||||
}
|
||||
|
||||
if err := is.SetParent(id, id3); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ids = is.Children(id2)
|
||||
if actual, expected := len(ids), 0; expected != actual {
|
||||
t.Fatalf("wrong number of children after parent reset: %d, got %d", expected, actual)
|
||||
}
|
||||
|
||||
ids = is.Children(id3)
|
||||
if actual, expected := len(ids), 1; expected != actual {
|
||||
t.Fatalf("wrong number of children after parent reset: %d, got %d", expected, actual)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type mockLayerGetReleaser struct{}
|
||||
|
||||
func (ls *mockLayerGetReleaser) Get(layer.ChainID) (layer.Layer, error) {
|
||||
|
|
|
@ -11,10 +11,15 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"bufio"
|
||||
"bytes"
|
||||
"github.com/docker/docker/pkg/authorization"
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
"github.com/docker/docker/pkg/plugins"
|
||||
"github.com/go-check/check"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -221,6 +226,71 @@ func (s *DockerAuthzSuite) TestAuthZPluginDenyResponse(c *check.C) {
|
|||
c.Assert(res, check.Equals, fmt.Sprintf("Error response from daemon: authorization denied by plugin %s: %s\n", testAuthZPlugin, unauthorizedMessage))
|
||||
}
|
||||
|
||||
// TestAuthZPluginAllowEventStream verifies event stream propogates correctly after request pass through by the authorization plugin
|
||||
func (s *DockerAuthzSuite) TestAuthZPluginAllowEventStream(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// Start the authorization plugin
|
||||
err := s.d.Start("--authorization-plugin=" + testAuthZPlugin)
|
||||
c.Assert(err, check.IsNil)
|
||||
s.ctrl.reqRes.Allow = true
|
||||
s.ctrl.resRes.Allow = true
|
||||
|
||||
startTime := strconv.FormatInt(daemonTime(c).Unix(), 10)
|
||||
// Add another command to to enable event pipelining
|
||||
eventsCmd := exec.Command(s.d.cmd.Path, "--host", s.d.sock(), "events", "--since", startTime)
|
||||
stdout, err := eventsCmd.StdoutPipe()
|
||||
if err != nil {
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
|
||||
observer := eventObserver{
|
||||
buffer: new(bytes.Buffer),
|
||||
command: eventsCmd,
|
||||
scanner: bufio.NewScanner(stdout),
|
||||
startTime: startTime,
|
||||
}
|
||||
|
||||
err = observer.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer observer.Stop()
|
||||
|
||||
// Create a container and wait for the creation events
|
||||
_, err = s.d.Cmd("pull", "busybox")
|
||||
c.Assert(err, check.IsNil)
|
||||
out, err := s.d.Cmd("run", "-d", "busybox", "top")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
containerID := strings.TrimSpace(out)
|
||||
|
||||
events := map[string]chan bool{
|
||||
"create": make(chan bool),
|
||||
"start": make(chan bool),
|
||||
}
|
||||
|
||||
matcher := matchEventLine(containerID, "container", events)
|
||||
processor := processEventMatch(events)
|
||||
go observer.Match(matcher, processor)
|
||||
|
||||
// Ensure all events are received
|
||||
for event, eventChannel := range events {
|
||||
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
// Fail the test
|
||||
observer.CheckEventError(c, containerID, event, matcher)
|
||||
c.FailNow()
|
||||
case <-eventChannel:
|
||||
// Ignore, event received
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure both events and container endpoints are passed to the authorization plugin
|
||||
assertURIRecorded(c, s.ctrl.requestsURIs, "/events")
|
||||
assertURIRecorded(c, s.ctrl.requestsURIs, "/containers/create")
|
||||
assertURIRecorded(c, s.ctrl.requestsURIs, fmt.Sprintf("/containers/%s/start", containerID))
|
||||
}
|
||||
|
||||
func (s *DockerAuthzSuite) TestAuthZPluginErrorResponse(c *check.C) {
|
||||
err := s.d.Start("--authorization-plugin=" + testAuthZPlugin)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
|
|
@ -178,7 +178,8 @@ func (s *DockerSuite) TestBuildCancellationKillsSleep(c *check.C) {
|
|||
}
|
||||
|
||||
matcher := matchEventLine(buildID, "container", testActions)
|
||||
go observer.Match(matcher)
|
||||
processor := processEventMatch(testActions)
|
||||
go observer.Match(matcher, processor)
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
|
|
|
@ -224,7 +224,8 @@ func (s *DockerSuite) TestEventsStreaming(c *check.C) {
|
|||
}
|
||||
|
||||
matcher := matchEventLine(containerID, "container", testActions)
|
||||
go observer.Match(matcher)
|
||||
processor := processEventMatch(testActions)
|
||||
go observer.Match(matcher, processor)
|
||||
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
|
@ -280,7 +281,8 @@ func (s *DockerSuite) TestEventsImageUntagDelete(c *check.C) {
|
|||
}
|
||||
|
||||
matcher := matchEventLine(imageID, "image", testActions)
|
||||
go observer.Match(matcher)
|
||||
processor := processEventMatch(testActions)
|
||||
go observer.Match(matcher, processor)
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
|
|
|
@ -48,8 +48,6 @@ func (s *DockerSuite) TestPsListContainersBase(c *check.C) {
|
|||
out, _ = dockerCmd(c, "ps")
|
||||
c.Assert(assertContainerList(out, []string{fourthID, secondID, firstID}), checker.Equals, true, check.Commentf("RUNNING: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// from here all flag '-a' is ignored
|
||||
|
||||
// limit
|
||||
out, _ = dockerCmd(c, "ps", "-n=2", "-a")
|
||||
expected := []string{fourthID, thirdID}
|
||||
|
@ -61,56 +59,138 @@ func (s *DockerSuite) TestPsListContainersBase(c *check.C) {
|
|||
// filter since
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-a")
|
||||
expected = []string{fourthID, thirdID, secondID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE & ALL: Container list is not in the correct order: \n%s", out))
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter & ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID)
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE: Container list is not in the correct order: \n%s", out))
|
||||
expected = []string{fourthID, secondID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// filter before
|
||||
out, _ = dockerCmd(c, "ps", "-f", "before="+thirdID, "-a")
|
||||
expected = []string{secondID, firstID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE & ALL: Container list is not in the correct order: \n%s", out))
|
||||
out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-a")
|
||||
expected = []string{thirdID, secondID, firstID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter & ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "before="+thirdID)
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE: Container list is not in the correct order: \n%s", out))
|
||||
out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID)
|
||||
expected = []string{secondID, firstID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// filter since & before
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-a")
|
||||
expected = []string{thirdID, secondID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE & ALL: Container list is not in the correct order: \n%s", out))
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter, BEFORE filter & ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID)
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE: Container list is not in the correct order: \n%s", out))
|
||||
expected = []string{secondID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter, BEFORE filter: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// filter since & limit
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-n=2", "-a")
|
||||
expected = []string{fourthID, thirdID}
|
||||
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-n=2")
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, LIMIT: Container list is not in the correct order: \n%s", out))
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter, LIMIT: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// filter before & limit
|
||||
out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1", "-a")
|
||||
expected = []string{thirdID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1")
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE, LIMIT: Container list is not in the correct order: \n%s", out))
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter, LIMIT: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
// filter since & filter before & limit
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-n=1", "-a")
|
||||
expected = []string{thirdID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter, BEFORE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-n=1")
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE, LIMIT: Container list is not in the correct order: \n%s", out))
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter, BEFORE filter, LIMIT: Container list is not in the correct order: \n%s", out))
|
||||
|
||||
}
|
||||
|
||||
// FIXME remove this for 1.12 as --since and --before are deprecated
|
||||
func (s *DockerSuite) TestPsListContainersDeprecatedSinceAndBefore(c *check.C) {
|
||||
out, _ := runSleepingContainer(c, "-d")
|
||||
firstID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = runSleepingContainer(c, "-d")
|
||||
secondID := strings.TrimSpace(out)
|
||||
|
||||
// not long running
|
||||
out, _ = dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
thirdID := strings.TrimSpace(out)
|
||||
|
||||
out, _ = runSleepingContainer(c, "-d")
|
||||
fourthID := strings.TrimSpace(out)
|
||||
|
||||
// make sure the second is running
|
||||
c.Assert(waitRun(secondID), checker.IsNil)
|
||||
|
||||
// make sure third one is not running
|
||||
dockerCmd(c, "wait", thirdID)
|
||||
|
||||
// make sure the forth is running
|
||||
c.Assert(waitRun(fourthID), checker.IsNil)
|
||||
|
||||
// since
|
||||
out, _ = dockerCmd(c, "ps", "--since="+firstID, "-a")
|
||||
expected := []string{fourthID, thirdID, secondID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE & ALL: Container list is not in the correct order: %v \n%s", expected, out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--since="+firstID)
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE: Container list is not in the correct order: %v \n%s", expected, out))
|
||||
|
||||
// before
|
||||
out, _ = dockerCmd(c, "ps", "--before="+thirdID, "-a")
|
||||
expected = []string{secondID, firstID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE & ALL: Container list is not in the correct order: %v \n%s", expected, out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--before="+thirdID)
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE: Container list is not in the correct order: %v \n%s", expected, out))
|
||||
|
||||
// since & before
|
||||
out, _ = dockerCmd(c, "ps", "--since="+firstID, "--before="+fourthID, "-a")
|
||||
expected = []string{thirdID, secondID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE & ALL: Container list is not in the correct order: %v \n%s", expected, out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--since="+firstID, "--before="+fourthID)
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE: Container list is not in the correct order: %v \n%s", expected, out))
|
||||
|
||||
// since & limit
|
||||
out, _ = dockerCmd(c, "ps", "--since="+firstID, "-n=2", "-a")
|
||||
expected = []string{fourthID, thirdID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, LIMIT & ALL: Container list is not in the correct order: %v \n%s", expected, out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--since="+firstID, "-n=2")
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, LIMIT: Container list is not in the correct order: %v \n%s", expected, out))
|
||||
|
||||
// before & limit
|
||||
out, _ = dockerCmd(c, "ps", "--before="+fourthID, "-n=1", "-a")
|
||||
expected = []string{thirdID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE, LIMIT & ALL: Container list is not in the correct order: %v \n%s", expected, out))
|
||||
|
||||
out, _ = dockerCmd(c, "ps", "--before="+fourthID, "-n=1")
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE, LIMIT: Container list is not in the correct order: %v \n%s", expected, out))
|
||||
|
||||
// since & before & limit
|
||||
out, _ = dockerCmd(c, "ps", "--since="+firstID, "--before="+fourthID, "-n=1", "-a")
|
||||
expected = []string{thirdID}
|
||||
c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE, LIMIT & ALL: Container list is not in the correct order: %v \n%s", expected, out))
|
||||
|
||||
}
|
||||
|
||||
func assertContainerList(out string, expected []string) bool {
|
||||
lines := strings.Split(strings.Trim(out, "\n "), "\n")
|
||||
// FIXME remove this for 1.12 as --since and --before are deprecated
|
||||
// This is here to remove potential Warning: lines (printed out with deprecated flags)
|
||||
for i := 0; i < 2; i++ {
|
||||
if strings.Contains(lines[0], "Warning:") {
|
||||
lines = lines[1:]
|
||||
}
|
||||
}
|
||||
|
||||
if len(lines)-1 != len(expected) {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -2365,7 +2365,7 @@ func (s *DockerSuite) TestRunModeIpcContainer(c *check.C) {
|
|||
// Not applicable on Windows as uses Unix-specific capabilities
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "echo -n test > /dev/shm/test && top")
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "echo -n test > /dev/shm/test && touch /dev/mqueue/toto && top")
|
||||
|
||||
id := strings.TrimSpace(out)
|
||||
state, err := inspectField(id, "State.Running")
|
||||
|
@ -2391,6 +2391,18 @@ func (s *DockerSuite) TestRunModeIpcContainer(c *check.C) {
|
|||
if catOutput != "test" {
|
||||
c.Fatalf("Output of /dev/shm/test expected test but found: %s", catOutput)
|
||||
}
|
||||
|
||||
// check that /dev/mqueue is actually of mqueue type
|
||||
grepOutput, _ := dockerCmd(c, "run", fmt.Sprintf("--ipc=container:%s", id), "busybox", "grep", "/dev/mqueue", "/proc/mounts")
|
||||
if !strings.HasPrefix(grepOutput, "mqueue /dev/mqueue mqueue rw") {
|
||||
c.Fatalf("Output of 'grep /proc/mounts' expected 'mqueue /dev/mqueue mqueue rw' but found: %s", grepOutput)
|
||||
}
|
||||
|
||||
lsOutput, _ := dockerCmd(c, "run", fmt.Sprintf("--ipc=container:%s", id), "busybox", "ls", "/dev/mqueue")
|
||||
lsOutput = strings.Trim(lsOutput, "\n")
|
||||
if lsOutput != "toto" {
|
||||
c.Fatalf("Output of 'ls /dev/mqueue' expected 'toto' but found: %s", lsOutput)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRunModeIpcContainerNotExists(c *check.C) {
|
||||
|
@ -2417,9 +2429,11 @@ func (s *DockerSuite) TestRunModeIpcContainerNotRunning(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunMountShmMqueueFromHost(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix-specific capabilities
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
|
||||
|
||||
dockerCmd(c, "run", "-d", "--name", "shmfromhost", "-v", "/dev/shm:/dev/shm", "busybox", "sh", "-c", "echo -n test > /dev/shm/test && top")
|
||||
dockerCmd(c, "run", "-d", "--name", "shmfromhost", "-v", "/dev/shm:/dev/shm", "-v", "/dev/mqueue:/dev/mqueue", "busybox", "sh", "-c", "echo -n test > /dev/shm/test && touch /dev/mqueue/toto && top")
|
||||
defer os.Remove("/dev/mqueue/toto")
|
||||
defer os.Remove("/dev/shm/test")
|
||||
volPath, err := inspectMountSourceField("shmfromhost", "/dev/shm")
|
||||
c.Assert(err, check.IsNil)
|
||||
if volPath != "/dev/shm" {
|
||||
|
@ -2430,6 +2444,11 @@ func (s *DockerSuite) TestRunMountShmMqueueFromHost(c *check.C) {
|
|||
if out != "test" {
|
||||
c.Fatalf("Output of /dev/shm/test expected test but found: %s", out)
|
||||
}
|
||||
|
||||
// Check that the mq was created
|
||||
if _, err := os.Stat("/dev/mqueue/toto"); err != nil {
|
||||
c.Fatalf("Failed to confirm '/dev/mqueue/toto' presence on host: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestContainerNetworkMode(c *check.C) {
|
||||
|
|
|
@ -24,11 +24,18 @@ func init() {
|
|||
})
|
||||
}
|
||||
|
||||
type vol struct {
|
||||
Name string
|
||||
Mountpoint string
|
||||
Opts map[string]string
|
||||
}
|
||||
|
||||
type DockerExternalVolumeSuiteCompatV1_1 struct {
|
||||
server *httptest.Server
|
||||
ds *DockerSuite
|
||||
d *Daemon
|
||||
ec *eventCounter
|
||||
server *httptest.Server
|
||||
ds *DockerSuite
|
||||
d *Daemon
|
||||
ec *eventCounter
|
||||
volList []vol
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuiteCompatV1_1) SetUpTest(c *check.C) {
|
||||
|
@ -47,6 +54,7 @@ func (s *DockerExternalVolumeSuiteCompatV1_1) SetUpSuite(c *check.C) {
|
|||
|
||||
type pluginRequest struct {
|
||||
Name string
|
||||
Opts map[string]string
|
||||
}
|
||||
|
||||
type pluginResp struct {
|
||||
|
@ -54,12 +62,6 @@ func (s *DockerExternalVolumeSuiteCompatV1_1) SetUpSuite(c *check.C) {
|
|||
Err string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type vol struct {
|
||||
Name string
|
||||
Mountpoint string
|
||||
}
|
||||
var volList []vol
|
||||
|
||||
read := func(b io.ReadCloser) (pluginRequest, error) {
|
||||
defer b.Close()
|
||||
var pr pluginRequest
|
||||
|
@ -94,7 +96,7 @@ func (s *DockerExternalVolumeSuiteCompatV1_1) SetUpSuite(c *check.C) {
|
|||
send(w, err)
|
||||
return
|
||||
}
|
||||
volList = append(volList, vol{Name: pr.Name})
|
||||
s.volList = append(s.volList, vol{Name: pr.Name, Opts: pr.Opts})
|
||||
send(w, nil)
|
||||
})
|
||||
|
||||
|
@ -111,13 +113,13 @@ func (s *DockerExternalVolumeSuiteCompatV1_1) SetUpSuite(c *check.C) {
|
|||
return
|
||||
}
|
||||
|
||||
for i, v := range volList {
|
||||
for i, v := range s.volList {
|
||||
if v.Name == pr.Name {
|
||||
if err := os.RemoveAll(hostVolumePath(v.Name)); err != nil {
|
||||
send(w, fmt.Sprintf(`{"Err": "%v"}`, err))
|
||||
return
|
||||
}
|
||||
volList = append(volList[:i], volList[i+1:]...)
|
||||
s.volList = append(s.volList[:i], s.volList[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -213,3 +215,20 @@ func (s *DockerExternalVolumeSuiteCompatV1_1) TestExternalVolumeDriverCompatV1_1
|
|||
out, err = s.d.Cmd("volume", "rm", "foo")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuiteCompatV1_1) TestExternalVolumeDriverCompatOptionsV1_1(c *check.C) {
|
||||
err := s.d.StartWithBusybox()
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
out, err := s.d.Cmd("volume", "create", "--name", "optvol", "--driver", "test-external-volume-driver", "--opt", "opt1=opt1val", "--opt", "opt2=opt2val")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
out, err = s.d.Cmd("volume", "inspect", "optvol")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
c.Assert(s.volList[0].Opts["opt1"], checker.Equals, "opt1val")
|
||||
c.Assert(s.volList[0].Opts["opt2"], checker.Equals, "opt2val")
|
||||
|
||||
out, err = s.d.Cmd("volume", "rm", "optvol")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
}
|
||||
|
|
|
@ -1704,3 +1704,19 @@ func getInspectBody(c *check.C, version, id string) []byte {
|
|||
c.Assert(status, check.Equals, http.StatusOK)
|
||||
return body
|
||||
}
|
||||
|
||||
// Run a long running idle task in a background container using the
|
||||
// system-specific default image and command.
|
||||
func runSleepingContainer(c *check.C, extraArgs ...string) (string, int) {
|
||||
return runSleepingContainerInImage(c, defaultSleepImage, extraArgs...)
|
||||
}
|
||||
|
||||
// Run a long running idle task in a background container using the specified
|
||||
// image and the system-specific command.
|
||||
func runSleepingContainerInImage(c *check.C, image string, extraArgs ...string) (string, int) {
|
||||
args := []string{"run", "-d"}
|
||||
args = append(args, extraArgs...)
|
||||
args = append(args, image)
|
||||
args = append(args, defaultSleepCommand...)
|
||||
return dockerCmd(c, args...)
|
||||
}
|
||||
|
|
|
@ -28,7 +28,13 @@ var (
|
|||
)
|
||||
|
||||
// eventMatcher is a function that tries to match an event input.
|
||||
type eventMatcher func(text string) bool
|
||||
// It returns true if the event matches and a map with
|
||||
// a set of key/value to identify the match.
|
||||
type eventMatcher func(text string) (map[string]string, bool)
|
||||
|
||||
// eventMatchProcessor is a function to handle an event match.
|
||||
// It receives a map of key/value with the information extracted in a match.
|
||||
type eventMatchProcessor func(matches map[string]string)
|
||||
|
||||
// eventObserver runs an events commands and observes its output.
|
||||
type eventObserver struct {
|
||||
|
@ -79,13 +85,15 @@ func (e *eventObserver) Stop() {
|
|||
}
|
||||
|
||||
// Match tries to match the events output with a given matcher.
|
||||
func (e *eventObserver) Match(match eventMatcher) {
|
||||
func (e *eventObserver) Match(match eventMatcher, process eventMatchProcessor) {
|
||||
for e.scanner.Scan() {
|
||||
text := e.scanner.Text()
|
||||
e.buffer.WriteString(text)
|
||||
e.buffer.WriteString("\n")
|
||||
|
||||
match(text)
|
||||
if matches, ok := match(text); ok {
|
||||
process(matches)
|
||||
}
|
||||
}
|
||||
|
||||
err := e.scanner.Err()
|
||||
|
@ -106,7 +114,7 @@ func (e *eventObserver) CheckEventError(c *check.C, id, event string, match even
|
|||
out, _ := dockerCmd(c, "events", "--since", e.startTime, "--until", until)
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
for _, e := range events {
|
||||
if match(e) {
|
||||
if _, ok := match(e); ok {
|
||||
foundEvent = true
|
||||
break
|
||||
}
|
||||
|
@ -119,22 +127,30 @@ func (e *eventObserver) CheckEventError(c *check.C, id, event string, match even
|
|||
}
|
||||
|
||||
// matchEventLine matches a text with the event regular expression.
|
||||
// It returns the action and true if the regular expression matches with the given id and event type.
|
||||
// It returns an empty string and false if there is no match.
|
||||
// It returns the matches and true if the regular expression matches with the given id and event type.
|
||||
// It returns an empty map and false if there is no match.
|
||||
func matchEventLine(id, eventType string, actions map[string]chan bool) eventMatcher {
|
||||
return func(text string) bool {
|
||||
return func(text string) (map[string]string, bool) {
|
||||
matches := parseEventText(text)
|
||||
if len(matches) == 0 {
|
||||
return false
|
||||
return matches, false
|
||||
}
|
||||
|
||||
if matchIDAndEventType(matches, id, eventType) {
|
||||
if ch, ok := actions[matches["action"]]; ok {
|
||||
close(ch)
|
||||
return true
|
||||
if _, ok := actions[matches["action"]]; ok {
|
||||
return matches, true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return matches, false
|
||||
}
|
||||
}
|
||||
|
||||
// processEventMatch closes an action channel when an event line matches the expected action.
|
||||
func processEventMatch(actions map[string]chan bool) eventMatchProcessor {
|
||||
return func(matches map[string]string) {
|
||||
if ch, ok := actions[matches["action"]]; ok {
|
||||
close(ch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,4 +7,10 @@ const (
|
|||
isUnixCli = true
|
||||
|
||||
expectedFileChmod = "-rw-r--r--"
|
||||
|
||||
// On Unix variants, the busybox image comes with the `top` command which
|
||||
// runs indefinitely while still being interruptible by a signal.
|
||||
defaultSleepImage = "busybox"
|
||||
)
|
||||
|
||||
var defaultSleepCommand = []string{"top"}
|
||||
|
|
|
@ -8,4 +8,10 @@ const (
|
|||
|
||||
// this is the expected file permission set on windows: gh#11395
|
||||
expectedFileChmod = "-rwxr-xr-x"
|
||||
|
||||
// On Windows, the busybox image doesn't have the `top` command, so we rely
|
||||
// on `sleep` with a high duration.
|
||||
defaultSleepImage = "busybox"
|
||||
)
|
||||
|
||||
var defaultSleepCommand = []string{"sleep", "60"}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
% Docker Community
|
||||
% JANUARY 2016
|
||||
# NAME
|
||||
HOME/.docker/confg.json - Default Docker configuration file
|
||||
HOME/.docker/config.json - Default Docker configuration file
|
||||
|
||||
# INTRODUCTION
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ func (ctx *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error {
|
|||
}
|
||||
}
|
||||
|
||||
rm.Flush()
|
||||
rm.FlushAll()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ func TestResponseModifier(t *testing.T) {
|
|||
m.Write([]byte("body"))
|
||||
m.WriteHeader(500)
|
||||
|
||||
m.Flush()
|
||||
m.FlushAll()
|
||||
if r.Header().Get("h1") != "v1" {
|
||||
t.Fatalf("Header value must exists %s", r.Header().Get("h1"))
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ func TestResponseModifierOverride(t *testing.T) {
|
|||
m.OverrideHeader(overrideHeaderBytes)
|
||||
m.OverrideBody([]byte("override body"))
|
||||
m.OverrideStatusCode(404)
|
||||
m.Flush()
|
||||
m.FlushAll()
|
||||
if r.Header().Get("h1") != "v2" {
|
||||
t.Fatalf("Header value must exists %s", r.Header().Get("h1"))
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Sirupsen/logrus"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
@ -12,6 +13,8 @@ import (
|
|||
// ResponseModifier allows authorization plugins to read and modify the content of the http.response
|
||||
type ResponseModifier interface {
|
||||
http.ResponseWriter
|
||||
http.Flusher
|
||||
http.CloseNotifier
|
||||
|
||||
// RawBody returns the current http content
|
||||
RawBody() []byte
|
||||
|
@ -32,7 +35,10 @@ type ResponseModifier interface {
|
|||
OverrideStatusCode(statusCode int)
|
||||
|
||||
// Flush flushes all data to the HTTP response
|
||||
Flush() error
|
||||
FlushAll() error
|
||||
|
||||
// Hijacked indicates the response has been hijacked by the Docker daemon
|
||||
Hijacked() bool
|
||||
}
|
||||
|
||||
// NewResponseModifier creates a wrapper to an http.ResponseWriter to allow inspecting and modifying the content
|
||||
|
@ -44,7 +50,10 @@ func NewResponseModifier(rw http.ResponseWriter) ResponseModifier {
|
|||
// the http request/response from docker daemon
|
||||
type responseModifier struct {
|
||||
// The original response writer
|
||||
rw http.ResponseWriter
|
||||
rw http.ResponseWriter
|
||||
|
||||
r *http.Request
|
||||
|
||||
status int
|
||||
// body holds the response body
|
||||
body []byte
|
||||
|
@ -52,15 +61,34 @@ type responseModifier struct {
|
|||
header http.Header
|
||||
// statusCode holds the response status code
|
||||
statusCode int
|
||||
// hijacked indicates the request has been hijacked
|
||||
hijacked bool
|
||||
}
|
||||
|
||||
func (rm *responseModifier) Hijacked() bool {
|
||||
return rm.hijacked
|
||||
}
|
||||
|
||||
// WriterHeader stores the http status code
|
||||
func (rm *responseModifier) WriteHeader(s int) {
|
||||
|
||||
// Use original request if hijacked
|
||||
if rm.hijacked {
|
||||
rm.rw.WriteHeader(s)
|
||||
return
|
||||
}
|
||||
|
||||
rm.statusCode = s
|
||||
}
|
||||
|
||||
// Header returns the internal http header
|
||||
func (rm *responseModifier) Header() http.Header {
|
||||
|
||||
// Use original header if hijacked
|
||||
if rm.hijacked {
|
||||
return rm.rw.Header()
|
||||
}
|
||||
|
||||
return rm.header
|
||||
}
|
||||
|
||||
|
@ -90,6 +118,11 @@ func (rm *responseModifier) OverrideHeader(b []byte) error {
|
|||
|
||||
// Write stores the byte array inside content
|
||||
func (rm *responseModifier) Write(b []byte) (int, error) {
|
||||
|
||||
if rm.hijacked {
|
||||
return rm.rw.Write(b)
|
||||
}
|
||||
|
||||
rm.body = append(rm.body, b...)
|
||||
return len(b), nil
|
||||
}
|
||||
|
@ -109,6 +142,10 @@ func (rm *responseModifier) RawHeaders() ([]byte, error) {
|
|||
|
||||
// Hijack returns the internal connection of the wrapped http.ResponseWriter
|
||||
func (rm *responseModifier) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
|
||||
rm.hijacked = true
|
||||
rm.FlushAll()
|
||||
|
||||
hijacker, ok := rm.rw.(http.Hijacker)
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("Internal reponse writer doesn't support the Hijacker interface")
|
||||
|
@ -116,8 +153,30 @@ func (rm *responseModifier) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|||
return hijacker.Hijack()
|
||||
}
|
||||
|
||||
// Flush flushes all data to the HTTP response
|
||||
func (rm *responseModifier) Flush() error {
|
||||
// CloseNotify uses the internal close notify API of the wrapped http.ResponseWriter
|
||||
func (rm *responseModifier) CloseNotify() <-chan bool {
|
||||
closeNotifier, ok := rm.rw.(http.CloseNotifier)
|
||||
if !ok {
|
||||
logrus.Errorf("Internal reponse writer doesn't support the CloseNotifier interface")
|
||||
return nil
|
||||
}
|
||||
return closeNotifier.CloseNotify()
|
||||
}
|
||||
|
||||
// Flush uses the internal flush API of the wrapped http.ResponseWriter
|
||||
func (rm *responseModifier) Flush() {
|
||||
flusher, ok := rm.rw.(http.Flusher)
|
||||
if !ok {
|
||||
logrus.Errorf("Internal reponse writer doesn't support the Flusher interface")
|
||||
return
|
||||
}
|
||||
|
||||
rm.FlushAll()
|
||||
flusher.Flush()
|
||||
}
|
||||
|
||||
// FlushAll flushes all data to the HTTP response
|
||||
func (rm *responseModifier) FlushAll() error {
|
||||
// Copy the status code
|
||||
if rm.statusCode > 0 {
|
||||
rm.rw.WriteHeader(rm.statusCode)
|
||||
|
@ -130,7 +189,15 @@ func (rm *responseModifier) Flush() error {
|
|||
}
|
||||
}
|
||||
|
||||
// Write body
|
||||
_, err := rm.rw.Write(rm.body)
|
||||
var err error
|
||||
if len(rm.body) > 0 {
|
||||
// Write body
|
||||
_, err = rm.rw.Write(rm.body)
|
||||
}
|
||||
|
||||
// Clean previous data
|
||||
rm.body = nil
|
||||
rm.statusCode = 0
|
||||
rm.header = http.Header{}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ var (
|
|||
validPrefixes = map[string][]string{
|
||||
"url": {"http://", "https://"},
|
||||
"git": {"git://", "github.com/", "git@"},
|
||||
"transport": {"tcp://", "udp://", "unix://"},
|
||||
"transport": {"tcp://", "tcp+tls://", "udp://", "unix://"},
|
||||
}
|
||||
urlPathWithFragmentSuffix = regexp.MustCompile(".git(?:#.+)?$")
|
||||
)
|
||||
|
@ -35,7 +35,7 @@ func IsGitTransport(str string) bool {
|
|||
return IsURL(str) || strings.HasPrefix(str, "git://") || strings.HasPrefix(str, "git@")
|
||||
}
|
||||
|
||||
// IsTransportURL returns true if the provided str is a transport (tcp, udp, unix) URL.
|
||||
// IsTransportURL returns true if the provided str is a transport (tcp, tcp+tls, udp, unix) URL.
|
||||
func IsTransportURL(str string) bool {
|
||||
return checkURL(str, "transport")
|
||||
}
|
||||
|
|
|
@ -18,6 +18,12 @@ var (
|
|||
invalidGitUrls = []string{
|
||||
"http://github.com/docker/docker.git:#branch",
|
||||
}
|
||||
transportUrls = []string{
|
||||
"tcp://example.com",
|
||||
"tcp+tls://example.com",
|
||||
"udp://example.com",
|
||||
"unix:///example",
|
||||
}
|
||||
)
|
||||
|
||||
func TestValidGitTransport(t *testing.T) {
|
||||
|
@ -53,3 +59,11 @@ func TestIsGIT(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsTransport(t *testing.T) {
|
||||
for _, url := range transportUrls {
|
||||
if IsTransportURL(url) == false {
|
||||
t.Fatalf("%q should be detected as valid Transport url", url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,8 @@ need to package Docker your way, without denaturing it in the process.
|
|||
To build Docker, you will need the following:
|
||||
|
||||
* A recent version of Git and Mercurial
|
||||
* Go version 1.4 or later
|
||||
* Go version 1.4 or later (Go version 1.5 or later required for hardware signing
|
||||
support in Docker Content Trust)
|
||||
* A clean checkout of the source added to a valid [Go
|
||||
workspace](https://golang.org/doc/code.html#Workspaces) under the path
|
||||
*src/github.com/docker/docker* (unless you plan to use `AUTO_GOPATH`,
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
# Changelog
|
||||
|
||||
## 0.6.1-rc2 (2016-02-09)
|
||||
- Fixes https://github.com/docker/docker/issues/20132
|
||||
- Fixes https://github.com/docker/docker/issues/20140
|
||||
- Fixes https://github.com/docker/docker/issues/20019
|
||||
|
||||
## 0.6.1-rc1 (2016-02-05)
|
||||
- Fixes https://github.com/docker/docker/issues/20026
|
||||
|
||||
## 0.6.0-rc7 (2016-02-01)
|
||||
- Allow inter-network connections via exposed ports
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt
|
|||
return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
|
||||
})
|
||||
|
||||
n.portMapper.SetIptablesChain(filterChain, n.getNetworkBridgeName())
|
||||
n.portMapper.SetIptablesChain(natChain, n.getNetworkBridgeName())
|
||||
}
|
||||
|
||||
if err := ensureJumpRule("FORWARD", IsolationChain); err != nil {
|
||||
|
@ -148,6 +148,9 @@ func setupIPTablesInternal(bridgeIface string, addr net.Addr, icc, ipmasq, hairp
|
|||
if err := programChainRule(natRule, "NAT", enable); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if ipmasq && !hairpin {
|
||||
if err := programChainRule(skipDNAT, "SKIP DNAT", enable); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -325,9 +325,11 @@ func Raw(args ...string) ([]byte, error) {
|
|||
if err == nil || !strings.Contains(err.Error(), "was not provided by any .service files") {
|
||||
return output, err
|
||||
}
|
||||
|
||||
}
|
||||
return raw(args...)
|
||||
}
|
||||
|
||||
func raw(args ...string) ([]byte, error) {
|
||||
if err := initCheck(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -362,6 +364,15 @@ func RawCombinedOutput(args ...string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// RawCombinedOutputNative behave as RawCombinedOutput with the difference it
|
||||
// will always invoke `iptables` binary
|
||||
func RawCombinedOutputNative(args ...string) error {
|
||||
if output, err := raw(args...); err != nil || len(output) != 0 {
|
||||
return fmt.Errorf("%s (%v)", string(output), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExistChain checks if a chain exists
|
||||
func ExistChain(chain string, table Table) bool {
|
||||
if _, err := Raw("-t", string(table), "-L", chain); err == nil {
|
||||
|
|
|
@ -95,7 +95,7 @@ func (r *resolver) SetupFunc() func() {
|
|||
}
|
||||
|
||||
for _, rule := range rules {
|
||||
r.err = iptables.RawCombinedOutput(rule...)
|
||||
r.err = iptables.RawCombinedOutputNative(rule...)
|
||||
if r.err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -229,6 +229,7 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
|
|||
|
||||
resp, _, err = c.Exchange(query, addr)
|
||||
if err == nil {
|
||||
resp.Compress = true
|
||||
break
|
||||
}
|
||||
log.Errorf("external resolution failed, %s", err)
|
||||
|
|
|
@ -104,7 +104,8 @@ func (c *controller) getNetworksForScope(scope string) ([]*network, error) {
|
|||
ec := &endpointCnt{n: n}
|
||||
err = store.GetObject(datastore.Key(ec.Key()...), ec)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find endpoint count key %s for network %s while listing: %v", datastore.Key(ec.Key()...), n.Name(), err)
|
||||
log.Warnf("Could not find endpoint count key %s for network %s while listing: %v", datastore.Key(ec.Key()...), n.Name(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
n.epCnt = ec
|
||||
|
|
|
@ -15,7 +15,20 @@ func (a *volumeDriverAdapter) Name() string {
|
|||
}
|
||||
|
||||
func (a *volumeDriverAdapter) Create(name string, opts map[string]string) (volume.Volume, error) {
|
||||
err := a.proxy.Create(name, opts)
|
||||
// First try a Get. For drivers that support Get this will return any
|
||||
// existing volume.
|
||||
v, err := a.proxy.Get(name)
|
||||
if v != nil {
|
||||
return &volumeAdapter{
|
||||
proxy: a.proxy,
|
||||
name: v.Name,
|
||||
driverName: a.Name(),
|
||||
eMount: v.Mountpoint,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Driver didn't support Get or volume didn't exist. Perform Create.
|
||||
err = a.proxy.Create(name, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -192,9 +192,6 @@ func (s *VolumeStore) create(name, driverName string, opts map[string]string) (v
|
|||
return nil, &OpErr{Op: "create", Name: name, Err: err}
|
||||
}
|
||||
|
||||
if v, err := vd.Get(name); err == nil {
|
||||
return v, nil
|
||||
}
|
||||
return vd.Create(name, opts)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue