Browse Source

Merge pull request #30810 from allencloud/make-secret-ls-support-filter

make secret ls support filters in CLI
Sebastiaan van Stijn 8 years ago
parent
commit
4df350b8c7

+ 3 - 0
api/swagger.yaml

@@ -7984,6 +7984,9 @@ paths:
           description: |
             A JSON encoded value of the filters (a `map[string][]string`) to process on the secrets list. Available filters:
 
+            - `id=<secret id>`
+            - `label=<key> or label=<key>=value`
+            - `name=<secret name>`
             - `names=<secret name>`
       tags: ["Secret"]
   /secrets/create:

+ 5 - 2
cli/command/secret/ls.go

@@ -5,6 +5,7 @@ import (
 	"github.com/docker/docker/cli"
 	"github.com/docker/docker/cli/command"
 	"github.com/docker/docker/cli/command/formatter"
+	"github.com/docker/docker/opts"
 	"github.com/spf13/cobra"
 	"golang.org/x/net/context"
 )
@@ -12,10 +13,11 @@ import (
 type listOptions struct {
 	quiet  bool
 	format string
+	filter opts.FilterOpt
 }
 
 func newSecretListCommand(dockerCli *command.DockerCli) *cobra.Command {
-	opts := listOptions{}
+	opts := listOptions{filter: opts.NewFilterOpt()}
 
 	cmd := &cobra.Command{
 		Use:     "ls [OPTIONS]",
@@ -30,6 +32,7 @@ func newSecretListCommand(dockerCli *command.DockerCli) *cobra.Command {
 	flags := cmd.Flags()
 	flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only display IDs")
 	flags.StringVarP(&opts.format, "format", "", "", "Pretty-print secrets using a Go template")
+	flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided")
 
 	return cmd
 }
@@ -38,7 +41,7 @@ func runSecretList(dockerCli *command.DockerCli, opts listOptions) error {
 	client := dockerCli.Client()
 	ctx := context.Background()
 
-	secrets, err := client.SecretList(ctx, types.SecretListOptions{})
+	secrets, err := client.SecretList(ctx, types.SecretListOptions{Filters: opts.filter.Value()})
 	if err != nil {
 		return err
 	}

+ 1 - 1
cli/command/service/parse.go

@@ -26,7 +26,7 @@ func ParseSecrets(client client.SecretAPIClient, requestedSecrets []*swarmtypes.
 
 	args := filters.NewArgs()
 	for _, s := range secretRefs {
-		args.Add("names", s.SecretName)
+		args.Add("name", s.SecretName)
 	}
 
 	secrets, err := client.SecretList(ctx, types.SecretListOptions{

+ 57 - 0
daemon/cluster/filters_test.go

@@ -0,0 +1,57 @@
+package cluster
+
+import (
+	"testing"
+
+	"github.com/docker/docker/api/types/filters"
+)
+
+func TestNewListSecretsFilters(t *testing.T) {
+	validNameFilter := filters.NewArgs()
+	validNameFilter.Add("name", "test_name")
+
+	validIDFilter := filters.NewArgs()
+	validIDFilter.Add("id", "7c9009d6720f6de3b492f5")
+
+	validLabelFilter := filters.NewArgs()
+	validLabelFilter.Add("label", "type=test")
+	validLabelFilter.Add("label", "storage=ssd")
+	validLabelFilter.Add("label", "memory")
+
+	validNamesFilter := filters.NewArgs()
+	validNamesFilter.Add("names", "test_name")
+
+	validAllFilter := filters.NewArgs()
+	validAllFilter.Add("name", "nodeName")
+	validAllFilter.Add("id", "7c9009d6720f6de3b492f5")
+	validAllFilter.Add("label", "type=test")
+	validAllFilter.Add("label", "memory")
+	validAllFilter.Add("names", "test_name")
+
+	validFilters := []filters.Args{
+		validNameFilter,
+		validIDFilter,
+		validLabelFilter,
+		validNamesFilter,
+		validAllFilter,
+	}
+
+	invalidTypeFilter := filters.NewArgs()
+	invalidTypeFilter.Add("nonexist", "aaaa")
+
+	invalidFilters := []filters.Args{
+		invalidTypeFilter,
+	}
+
+	for _, filter := range validFilters {
+		if _, err := newListSecretsFilters(filter); err != nil {
+			t.Fatalf("Should get no error, got %v", err)
+		}
+	}
+
+	for _, filter := range invalidFilters {
+		if _, err := newListSecretsFilters(filter); err == nil {
+			t.Fatalf("Should get an error for filter %s, while got nil", filter)
+		}
+	}
+}

+ 68 - 4
docs/reference/commandline/secret_ls.md

@@ -24,8 +24,10 @@ Aliases:
   ls, list
 
 Options:
-  -q, --quiet          Only display IDs
-  -format string       Pretty-print secrets using a Go template
+  -f, --filter filter   Filter output based on conditions provided
+      --format string   Pretty-print secrets using a Go template
+      --help            Print usage
+  -q, --quiet           Only display IDs
 ```
 
 ## Description
@@ -39,8 +41,70 @@ For detailed information about using secrets, refer to [manage sensitive data wi
 ```bash
 $ docker secret ls
 
-ID                          NAME                CREATED             UPDATED
-eo7jnzguqgtpdah3cm5srfb97   my_secret           11 minutes ago      11 minutes ago
+ID                          NAME                        CREATED             UPDATED
+6697bflskwj1998km1gnnjr38   q5s5570vtvnimefos1fyeo2u2   6 weeks ago         6 weeks ago
+9u9hk4br2ej0wgngkga6rp4hq   my_secret                   5 weeks ago         5 weeks ago
+mem02h8n73mybpgqjf0kfi1n0   test_secret                 3 seconds ago       3 seconds ago
+```
+
+### Filtering
+
+The filtering flag (`-f` or `--filter`) format is a `key=value` pair. If there is more
+than one filter, then pass multiple flags (e.g., `--filter "foo=bar" --filter "bif=baz"`)
+
+The currently supported filters are:
+
+* [id](secret_ls.md#id) (secret's ID)
+* [label](secret_ls.md#label) (`label=<key>` or `label=<key>=<value>`)
+* [name](secret_ls.md#name) (secret's name)
+
+#### id
+
+The `id` filter matches all or prefix of a secret's id.
+
+```bash
+$ docker secret ls -f "id=6697bflskwj1998km1gnnjr38"
+
+ID                          NAME                        CREATED             UPDATED
+6697bflskwj1998km1gnnjr38   q5s5570vtvnimefos1fyeo2u2   6 weeks ago         6 weeks ago
+```
+
+#### label
+
+The `label` filter matches secrets based on the presence of a `label` alone or
+a `label` and a value.
+
+The following filter matches all secrets with a `project` label regardless of
+its value:
+
+```bash
+$ docker secret ls --filter label=project
+
+ID                          NAME                        CREATED             UPDATED
+mem02h8n73mybpgqjf0kfi1n0   test_secret                 About an hour ago   About an hour ago
+```
+
+The following filter matches only services with the `project` label with the
+`project-a` value.
+
+```bash
+$ docker service ls --filter label=project=test
+
+ID                          NAME                        CREATED             UPDATED
+mem02h8n73mybpgqjf0kfi1n0   test_secret                 About an hour ago   About an hour ago
+```
+
+#### name
+
+The `name` filter matches on all or prefix of a secret's name.
+
+The following filter matches secret with a name containing a prefix of `test`.
+
+```bash
+$ docker secret ls --filter name=test_secret
+
+ID                          NAME                        CREATED             UPDATED
+mem02h8n73mybpgqjf0kfi1n0   test_secret                 About an hour ago   About an hour ago
 ```
 
 ### Format the output

+ 125 - 0
integration-cli/docker_cli_secret_ls_test.go

@@ -0,0 +1,125 @@
+// +build !windows
+
+package main
+
+import (
+	"strings"
+
+	"github.com/docker/docker/api/types/swarm"
+	"github.com/docker/docker/integration-cli/checker"
+	"github.com/go-check/check"
+)
+
+func (s *DockerSwarmSuite) TestSecretList(c *check.C) {
+	d := s.AddDaemon(c, true, true)
+
+	testName0 := "test0"
+	testName1 := "test1"
+
+	// create secret test0
+	id0 := d.CreateSecret(c, swarm.SecretSpec{
+		Annotations: swarm.Annotations{
+			Name:   testName0,
+			Labels: map[string]string{"type": "test"},
+		},
+		Data: []byte("TESTINGDATA0"),
+	})
+	c.Assert(id0, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id0))
+
+	secret := d.GetSecret(c, id0)
+	c.Assert(secret.Spec.Name, checker.Equals, testName0)
+
+	// create secret test1
+	id1 := d.CreateSecret(c, swarm.SecretSpec{
+		Annotations: swarm.Annotations{
+			Name:   testName1,
+			Labels: map[string]string{"type": "production"},
+		},
+		Data: []byte("TESTINGDATA1"),
+	})
+	c.Assert(id1, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id1))
+
+	secret = d.GetSecret(c, id1)
+	c.Assert(secret.Spec.Name, checker.Equals, testName1)
+
+	// test by command `docker secret ls`
+	out, err := d.Cmd("secret", "ls")
+	c.Assert(err, checker.IsNil, check.Commentf(out))
+	c.Assert(strings.TrimSpace(out), checker.Contains, testName0)
+	c.Assert(strings.TrimSpace(out), checker.Contains, testName1)
+
+	// test filter by name `docker secret ls --filter name=xxx`
+	args := []string{
+		"secret",
+		"ls",
+		"--filter",
+		"name=test0",
+	}
+	out, err = d.Cmd(args...)
+	c.Assert(err, checker.IsNil, check.Commentf(out))
+
+	c.Assert(strings.TrimSpace(out), checker.Contains, testName0)
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), testName1)
+
+	// test filter by id `docker secret ls --filter id=xxx`
+	args = []string{
+		"secret",
+		"ls",
+		"--filter",
+		"id=" + id1,
+	}
+	out, err = d.Cmd(args...)
+	c.Assert(err, checker.IsNil, check.Commentf(out))
+
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), testName0)
+	c.Assert(strings.TrimSpace(out), checker.Contains, testName1)
+
+	// test filter by label `docker secret ls --filter label=xxx`
+	args = []string{
+		"secret",
+		"ls",
+		"--filter",
+		"label=type",
+	}
+	out, err = d.Cmd(args...)
+	c.Assert(err, checker.IsNil, check.Commentf(out))
+
+	c.Assert(strings.TrimSpace(out), checker.Contains, testName0)
+	c.Assert(strings.TrimSpace(out), checker.Contains, testName1)
+
+	args = []string{
+		"secret",
+		"ls",
+		"--filter",
+		"label=type=test",
+	}
+	out, err = d.Cmd(args...)
+	c.Assert(err, checker.IsNil, check.Commentf(out))
+
+	c.Assert(strings.TrimSpace(out), checker.Contains, testName0)
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), testName1)
+
+	args = []string{
+		"secret",
+		"ls",
+		"--filter",
+		"label=type=production",
+	}
+	out, err = d.Cmd(args...)
+	c.Assert(err, checker.IsNil, check.Commentf(out))
+
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), testName0)
+	c.Assert(strings.TrimSpace(out), checker.Contains, testName1)
+
+	// test invalid filter `docker secret ls --filter noexisttype=xxx`
+	args = []string{
+		"secret",
+		"ls",
+		"--filter",
+		"noexisttype=test0",
+	}
+	out, err = d.Cmd(args...)
+	c.Assert(err, checker.NotNil, check.Commentf(out))
+
+	c.Assert(strings.TrimSpace(out), checker.Contains, "Error response from daemon: Invalid filter 'noexisttype'")
+}