mirror of https://github.com/docker/docs.git
Add regex based name filter to ls command.
Signed-off-by: Eric Sage <eric.david.sage@gmail.com> Add regex support Signed-off-by: Eric Sage <eric.david.sage@gmail.com> Allow bad regex passthrough to reg string amtch Signed-off-by: Eric Sage <eric.david.sage@gmail.com> Add unit test Signed-off-by: Eric Sage <eric.david.sage@gmail.com> Add integration tests Signed-off-by: Eric Sage <eric.david.sage@gmail.com> Add documentation for name filter. Signed-off-by: Eric Sage <eric.david.sage@gmail.com>
This commit is contained in:
parent
ad6d8d49a8
commit
b333ea5294
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
|
@ -17,6 +18,7 @@ type FilterOptions struct {
|
|||
SwarmName []string
|
||||
DriverName []string
|
||||
State []string
|
||||
Name []string
|
||||
}
|
||||
|
||||
func cmdLs(c *cli.Context) {
|
||||
|
@ -100,6 +102,8 @@ func parseFilters(filters []string) (FilterOptions, error) {
|
|||
options.DriverName = append(options.DriverName, value)
|
||||
case "state":
|
||||
options.State = append(options.State, value)
|
||||
case "name":
|
||||
options.Name = append(options.Name, value)
|
||||
default:
|
||||
return options, fmt.Errorf("Unsupported filter key '%s'", key)
|
||||
}
|
||||
|
@ -110,7 +114,8 @@ func parseFilters(filters []string) (FilterOptions, error) {
|
|||
func filterHosts(hosts []*libmachine.Host, filters FilterOptions) []*libmachine.Host {
|
||||
if len(filters.SwarmName) == 0 &&
|
||||
len(filters.DriverName) == 0 &&
|
||||
len(filters.State) == 0 {
|
||||
len(filters.State) == 0 &&
|
||||
len(filters.Name) == 0 {
|
||||
return hosts
|
||||
}
|
||||
|
||||
|
@ -140,8 +145,9 @@ func filterHost(host *libmachine.Host, filters FilterOptions, swarmMasters map[s
|
|||
swarmMatches := matchesSwarmName(host, filters.SwarmName, swarmMasters)
|
||||
driverMatches := matchesDriverName(host, filters.DriverName)
|
||||
stateMatches := matchesState(host, filters.State)
|
||||
nameMatches := matchesName(host, filters.Name)
|
||||
|
||||
return swarmMatches && driverMatches && stateMatches
|
||||
return swarmMatches && driverMatches && stateMatches && nameMatches
|
||||
}
|
||||
|
||||
func matchesSwarmName(host *libmachine.Host, swarmNames []string, swarmMasters map[string]string) bool {
|
||||
|
@ -185,3 +191,19 @@ func matchesState(host *libmachine.Host, states []string) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func matchesName(host *libmachine.Host, names []string) bool {
|
||||
if len(names) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, n := range names {
|
||||
r, err := regexp.Compile(n)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if r.MatchString(host.Driver.GetMachineName()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -30,14 +30,19 @@ func TestParseFiltersState(t *testing.T) {
|
|||
assert.Equal(t, actual, FilterOptions{State: []string{"Running"}})
|
||||
}
|
||||
|
||||
func TestParseFiltersName(t *testing.T) {
|
||||
actual, _ := parseFilters([]string{"name=dev"})
|
||||
assert.Equal(t, actual, FilterOptions{Name: []string{"dev"}})
|
||||
}
|
||||
|
||||
func TestParseFiltersAll(t *testing.T) {
|
||||
actual, _ := parseFilters([]string{"swarm=foo", "driver=bar", "state=Stopped"})
|
||||
assert.Equal(t, actual, FilterOptions{SwarmName: []string{"foo"}, DriverName: []string{"bar"}, State: []string{"Stopped"}})
|
||||
actual, _ := parseFilters([]string{"swarm=foo", "driver=bar", "state=Stopped", "name=dev"})
|
||||
assert.Equal(t, actual, FilterOptions{SwarmName: []string{"foo"}, DriverName: []string{"bar"}, State: []string{"Stopped"}, Name: []string{"dev"}})
|
||||
}
|
||||
|
||||
func TestParseFiltersDuplicates(t *testing.T) {
|
||||
actual, _ := parseFilters([]string{"swarm=foo", "driver=bar", "swarm=baz", "driver=qux", "state=Running", "state=Starting"})
|
||||
assert.Equal(t, actual, FilterOptions{SwarmName: []string{"foo", "baz"}, DriverName: []string{"bar", "qux"}, State: []string{"Running", "Starting"}})
|
||||
actual, _ := parseFilters([]string{"swarm=foo", "driver=bar", "name=mark", "swarm=baz", "driver=qux", "state=Running", "state=Starting", "name=time"})
|
||||
assert.Equal(t, actual, FilterOptions{SwarmName: []string{"foo", "baz"}, DriverName: []string{"bar", "qux"}, State: []string{"Running", "Starting"}, Name: []string{"mark", "time"}})
|
||||
}
|
||||
|
||||
func TestParseFiltersValueWithEqual(t *testing.T) {
|
||||
|
@ -170,6 +175,44 @@ func TestFilterHostsByState(t *testing.T) {
|
|||
assert.EqualValues(t, filterHosts(hosts, opts), expected)
|
||||
}
|
||||
|
||||
func TestFilterHostsByName(t *testing.T) {
|
||||
opts := FilterOptions{
|
||||
Name: []string{"fire", "ice", "earth", "a.?r"},
|
||||
}
|
||||
node1 :=
|
||||
&libmachine.Host{
|
||||
Name: "fire",
|
||||
DriverName: "fakedriver",
|
||||
HostOptions: &libmachine.HostOptions{},
|
||||
Driver: &fakedriver.FakeDriver{MockState: state.Paused, MockName: "fire"},
|
||||
}
|
||||
node2 :=
|
||||
&libmachine.Host{
|
||||
Name: "ice",
|
||||
DriverName: "adriver",
|
||||
HostOptions: &libmachine.HostOptions{},
|
||||
Driver: &fakedriver.FakeDriver{MockState: state.Paused, MockName: "ice"},
|
||||
}
|
||||
node3 :=
|
||||
&libmachine.Host{
|
||||
Name: "air",
|
||||
DriverName: "nodriver",
|
||||
HostOptions: &libmachine.HostOptions{},
|
||||
Driver: &fakedriver.FakeDriver{MockState: state.Paused, MockName: "air"},
|
||||
}
|
||||
node4 :=
|
||||
&libmachine.Host{
|
||||
Name: "water",
|
||||
DriverName: "falsedriver",
|
||||
HostOptions: &libmachine.HostOptions{},
|
||||
Driver: &fakedriver.FakeDriver{MockState: state.Paused, MockName: "water"},
|
||||
}
|
||||
hosts := []*libmachine.Host{node1, node2, node3, node4}
|
||||
expected := []*libmachine.Host{node1, node2, node3}
|
||||
|
||||
assert.EqualValues(t, filterHosts(hosts, opts), expected)
|
||||
}
|
||||
|
||||
func TestFilterHostsMultiFlags(t *testing.T) {
|
||||
opts := FilterOptions{
|
||||
SwarmName: []string{},
|
||||
|
|
|
@ -31,6 +31,7 @@ The currently supported filters are:
|
|||
* driver (driver name)
|
||||
* swarm (swarm master's name)
|
||||
* state (`Running|Paused|Saved|Stopped|Stopping|Starting|Error`)
|
||||
* name (Machine name returned by driver, supports golang style (https://github.com/google/re2/wiki/Syntax) regular expressions in machine name)
|
||||
|
||||
## Examples
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
type FakeDriver struct {
|
||||
*drivers.BaseDriver
|
||||
MockState state.State
|
||||
MockName string
|
||||
}
|
||||
|
||||
func (d *FakeDriver) DriverName() string {
|
||||
|
@ -23,7 +24,7 @@ func (d *FakeDriver) GetURL() (string, error) {
|
|||
}
|
||||
|
||||
func (d *FakeDriver) GetMachineName() string {
|
||||
return ""
|
||||
return d.MockName
|
||||
}
|
||||
|
||||
func (d *FakeDriver) GetIP() (string, error) {
|
||||
|
|
|
@ -19,3 +19,21 @@ teardown () {
|
|||
[ "$status" -eq 0 ]
|
||||
[[ ${lines[1]} =~ "testmachine" ]]
|
||||
}
|
||||
|
||||
@test "ls: filter on name" {
|
||||
run mchine create -d none -url tcp://127.0.0.1:2375 testmachine
|
||||
run mchine create -d none -url tcp://127.0.0.1:2375 testmachine2
|
||||
run mchine create -d none -url tcp://127.0.0.1:2375 testmachine3
|
||||
run mchine ls --filter name=testmachine2
|
||||
[ "$status" -eq 0 ]
|
||||
[[ ${lines[1]} =~ "testmachine2" ]]
|
||||
}
|
||||
|
||||
@test "ls: filter on name with regex" {
|
||||
run mchine create -d none -url tcp://127.0.0.1:2375 squirrel
|
||||
run mchine create -d none -url tcp://127.0.0.1:2375 cat
|
||||
run mchine create -d none -url tcp://127.0.0.1:2375 dog
|
||||
run mchine ls --filter name=c.?t
|
||||
[ "$status" -eq 0 ]
|
||||
[[ ${lines[1]} =~ "cat" ]]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue