Remove slash prefix when matching name filters (Fixes #37453)
* Regex name filters were display undesired behavior due to names containing the trailing slash when being compared * Adjusted filterByNameIDMatches and includeContainerInList to strip the slash prefix before doing name comparisons * Added test case and helper functions for the test to list_test * Force failed tests during development to ensure there were no false positives Signed-off-by: Chris White <me@cwprogram.com>
This commit is contained in:
parent
17dc10123f
commit
5c8da2e967
2 changed files with 101 additions and 2 deletions
|
@ -146,7 +146,7 @@ func (daemon *Daemon) filterByNameIDMatches(view container.View, ctx *listContex
|
|||
continue
|
||||
}
|
||||
for _, eachName := range idNames {
|
||||
if ctx.filters.Match("name", eachName) {
|
||||
if ctx.filters.Match("name", strings.TrimPrefix(eachName, "/")) {
|
||||
matches[id] = true
|
||||
}
|
||||
}
|
||||
|
@ -429,7 +429,7 @@ func includeContainerInList(container *container.Snapshot, ctx *listContext) ite
|
|||
}
|
||||
|
||||
// Do not include container if the name doesn't match
|
||||
if !ctx.filters.Match("name", container.Name) {
|
||||
if !ctx.filters.Match("name", strings.TrimPrefix(container.Name, "/")) {
|
||||
return excludeContainer
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,82 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pborman/uuid"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
var root string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
root, err = ioutil.TempDir("", "docker-container-test-")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
// This sets up a container with a name so that name filters
|
||||
// work against it. It takes in a pointer to Daemon so that
|
||||
// minor operations are not repeated by the caller
|
||||
func setupContainerWithName(t *testing.T, name string, daemon *Daemon) *container.Container {
|
||||
var (
|
||||
id = uuid.New()
|
||||
computedImageID = digest.FromString(id)
|
||||
cRoot = filepath.Join(root, id)
|
||||
)
|
||||
if err := os.MkdirAll(cRoot, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := container.NewBaseContainer(id, cRoot)
|
||||
// these are for passing includeContainerInList
|
||||
c.Name = name
|
||||
c.Running = true
|
||||
c.HostConfig = &containertypes.HostConfig{}
|
||||
|
||||
// these are for passing the refreshImage reducer
|
||||
c.ImageID = image.IDFromDigest(computedImageID)
|
||||
c.Config = &containertypes.Config{
|
||||
Image: computedImageID.String(),
|
||||
}
|
||||
|
||||
// this is done here to avoid requiring these
|
||||
// operations n x number of containers in the
|
||||
// calling function
|
||||
daemon.containersReplica.Save(c)
|
||||
daemon.reserveName(id, name)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func containerListContainsName(containers []*types.Container, name string) bool {
|
||||
for _, container := range containers {
|
||||
for _, containerName := range container.Names {
|
||||
if strings.TrimPrefix(containerName, "/") == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func TestListInvalidFilter(t *testing.T) {
|
||||
db, err := container.NewViewDB()
|
||||
assert.Assert(t, err == nil)
|
||||
|
@ -24,3 +91,35 @@ func TestListInvalidFilter(t *testing.T) {
|
|||
})
|
||||
assert.Assert(t, is.Error(err, "Invalid filter 'invalid'"))
|
||||
}
|
||||
|
||||
func TestNameFilter(t *testing.T) {
|
||||
db, err := container.NewViewDB()
|
||||
assert.Assert(t, err == nil)
|
||||
d := &Daemon{
|
||||
containersReplica: db,
|
||||
}
|
||||
|
||||
var (
|
||||
one = setupContainerWithName(t, "a1", d)
|
||||
two = setupContainerWithName(t, "a2", d)
|
||||
three = setupContainerWithName(t, "b1", d)
|
||||
)
|
||||
|
||||
// moby/moby #37453 - ^ regex not working due to prefix slash
|
||||
// not being stripped
|
||||
containerList, err := d.Containers(&types.ContainerListOptions{
|
||||
Filters: filters.NewArgs(filters.Arg("name", "^a")),
|
||||
})
|
||||
assert.Assert(t, err == nil)
|
||||
assert.Assert(t, is.Len(containerList, 2))
|
||||
assert.Assert(t, containerListContainsName(containerList, one.Name))
|
||||
assert.Assert(t, containerListContainsName(containerList, two.Name))
|
||||
|
||||
// Same as above but make sure it works for exact names
|
||||
containerList, err = d.Containers(&types.ContainerListOptions{
|
||||
Filters: filters.NewArgs(filters.Arg("name", "b1")),
|
||||
})
|
||||
assert.Assert(t, err == nil)
|
||||
assert.Assert(t, is.Len(containerList, 1))
|
||||
assert.Assert(t, containerListContainsName(containerList, three.Name))
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue