浏览代码

Move secret name or ID prefix resolving from client to daemon

This fix is a follow up for comment:
https://github.com/docker/docker/pull/28896#issuecomment-265392703

Currently secret name or ID prefix resolving is done at the client
side, which means different behavior of API and CMD.

This fix moves the resolving from client to daemon, with exactly the
same rule:
- Full ID
- Full Name
- Partial ID (prefix)

All existing tests should pass.

This fix is related to #288896, #28884 and may be related to #29125.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
Yong Tang 8 年之前
父节点
当前提交
fa358a8757

+ 1 - 5
cli/command/secret/inspect.go

@@ -33,13 +33,9 @@ func runSecretInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
 	client := dockerCli.Client()
 	client := dockerCli.Client()
 	ctx := context.Background()
 	ctx := context.Background()
 
 
-	ids, err := getCliRequestedSecretIDs(ctx, client, opts.names)
-	if err != nil {
-		return err
-	}
 	getRef := func(id string) (interface{}, []byte, error) {
 	getRef := func(id string) (interface{}, []byte, error) {
 		return client.SecretInspectWithRaw(ctx, id)
 		return client.SecretInspectWithRaw(ctx, id)
 	}
 	}
 
 
-	return inspect.Inspect(dockerCli.Out(), ids, opts.format, getRef)
+	return inspect.Inspect(dockerCli.Out(), opts.names, opts.format, getRef)
 }
 }

+ 3 - 8
cli/command/secret/remove.go

@@ -33,20 +33,15 @@ func runSecretRemove(dockerCli *command.DockerCli, opts removeOptions) error {
 	client := dockerCli.Client()
 	client := dockerCli.Client()
 	ctx := context.Background()
 	ctx := context.Background()
 
 
-	ids, err := getCliRequestedSecretIDs(ctx, client, opts.names)
-	if err != nil {
-		return err
-	}
-
 	var errs []string
 	var errs []string
 
 
-	for _, id := range ids {
-		if err := client.SecretRemove(ctx, id); err != nil {
+	for _, name := range opts.names {
+		if err := client.SecretRemove(ctx, name); err != nil {
 			errs = append(errs, err.Error())
 			errs = append(errs, err.Error())
 			continue
 			continue
 		}
 		}
 
 
-		fmt.Fprintln(dockerCli.Out(), id)
+		fmt.Fprintln(dockerCli.Out(), name)
 	}
 	}
 
 
 	if len(errs) > 0 {
 	if len(errs) > 0 {

+ 60 - 7
daemon/cluster/secrets.go

@@ -1,14 +1,63 @@
 package cluster
 package cluster
 
 
 import (
 import (
+	"fmt"
+	"strings"
+
 	apitypes "github.com/docker/docker/api/types"
 	apitypes "github.com/docker/docker/api/types"
 	types "github.com/docker/docker/api/types/swarm"
 	types "github.com/docker/docker/api/types/swarm"
 	"github.com/docker/docker/daemon/cluster/convert"
 	"github.com/docker/docker/daemon/cluster/convert"
 	swarmapi "github.com/docker/swarmkit/api"
 	swarmapi "github.com/docker/swarmkit/api"
+	"golang.org/x/net/context"
 )
 )
 
 
+func getSecretByNameOrIDPrefix(ctx context.Context, state *nodeState, nameOrIDPrefix string) (*swarmapi.Secret, error) {
+	// attempt to lookup secret by full ID
+	if r, err := state.controlClient.GetSecret(ctx, &swarmapi.GetSecretRequest{
+		SecretID: nameOrIDPrefix,
+	}); err == nil {
+		return r.Secret, nil
+	}
+
+	// attempt to lookup secret by full name and partial ID
+	// Note here ListSecretRequest_Filters operate with `or`
+	r, err := state.controlClient.ListSecrets(ctx, &swarmapi.ListSecretsRequest{
+		Filters: &swarmapi.ListSecretsRequest_Filters{
+			Names:      []string{nameOrIDPrefix},
+			IDPrefixes: []string{nameOrIDPrefix},
+		},
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	// attempt to lookup secret by full name
+	for _, s := range r.Secrets {
+		if s.Spec.Annotations.Name == nameOrIDPrefix {
+			return s, nil
+		}
+	}
+	// attempt to lookup secret by partial ID (prefix)
+	// return error if more than one matches found (ambiguous)
+	n := 0
+	var found *swarmapi.Secret
+	for _, s := range r.Secrets {
+		if strings.HasPrefix(s.ID, nameOrIDPrefix) {
+			found = s
+			n++
+		}
+	}
+	if n > 1 {
+		return nil, fmt.Errorf("secret %s is ambiguous (%d matches found)", nameOrIDPrefix, n)
+	}
+	if found == nil {
+		return nil, fmt.Errorf("no such secret: %s", nameOrIDPrefix)
+	}
+	return found, nil
+}
+
 // GetSecret returns a secret from a managed swarm cluster
 // GetSecret returns a secret from a managed swarm cluster
-func (c *Cluster) GetSecret(id string) (types.Secret, error) {
+func (c *Cluster) GetSecret(nameOrIDPrefix string) (types.Secret, error) {
 	c.mu.RLock()
 	c.mu.RLock()
 	defer c.mu.RUnlock()
 	defer c.mu.RUnlock()
 
 
@@ -20,12 +69,11 @@ func (c *Cluster) GetSecret(id string) (types.Secret, error) {
 	ctx, cancel := c.getRequestContext()
 	ctx, cancel := c.getRequestContext()
 	defer cancel()
 	defer cancel()
 
 
-	r, err := state.controlClient.GetSecret(ctx, &swarmapi.GetSecretRequest{SecretID: id})
+	secret, err := getSecretByNameOrIDPrefix(ctx, &state, nameOrIDPrefix)
 	if err != nil {
 	if err != nil {
 		return types.Secret{}, err
 		return types.Secret{}, err
 	}
 	}
-
-	return convert.SecretFromGRPC(r.Secret), nil
+	return convert.SecretFromGRPC(secret), nil
 }
 }
 
 
 // GetSecrets returns all secrets of a managed swarm cluster.
 // GetSecrets returns all secrets of a managed swarm cluster.
@@ -85,7 +133,7 @@ func (c *Cluster) CreateSecret(s types.SecretSpec) (string, error) {
 }
 }
 
 
 // RemoveSecret removes a secret from a managed swarm cluster.
 // RemoveSecret removes a secret from a managed swarm cluster.
-func (c *Cluster) RemoveSecret(id string) error {
+func (c *Cluster) RemoveSecret(nameOrIDPrefix string) error {
 	c.mu.RLock()
 	c.mu.RLock()
 	defer c.mu.RUnlock()
 	defer c.mu.RUnlock()
 
 
@@ -97,11 +145,16 @@ func (c *Cluster) RemoveSecret(id string) error {
 	ctx, cancel := c.getRequestContext()
 	ctx, cancel := c.getRequestContext()
 	defer cancel()
 	defer cancel()
 
 
+	secret, err := getSecretByNameOrIDPrefix(ctx, &state, nameOrIDPrefix)
+	if err != nil {
+		return err
+	}
+
 	req := &swarmapi.RemoveSecretRequest{
 	req := &swarmapi.RemoveSecretRequest{
-		SecretID: id,
+		SecretID: secret.ID,
 	}
 	}
 
 
-	_, err := state.controlClient.RemoveSecret(ctx, req)
+	_, err = state.controlClient.RemoveSecret(ctx, req)
 	return err
 	return err
 }
 }
 
 

+ 1 - 1
integration-cli/docker_cli_secret_create_test.go

@@ -101,7 +101,7 @@ func (s *DockerSwarmSuite) TestSecretCreateResolve(c *check.C) {
 
 
 	// Remove based on ID prefix of the fake one should succeed
 	// Remove based on ID prefix of the fake one should succeed
 	out, err = d.Cmd("secret", "rm", fake[:5])
 	out, err = d.Cmd("secret", "rm", fake[:5])
-	c.Assert(out, checker.Contains, fake)
+	c.Assert(out, checker.Contains, fake[:5])
 	out, err = d.Cmd("secret", "ls")
 	out, err = d.Cmd("secret", "ls")
 	c.Assert(err, checker.IsNil)
 	c.Assert(err, checker.IsNil)
 	c.Assert(out, checker.Not(checker.Contains), name)
 	c.Assert(out, checker.Not(checker.Contains), name)