From c00138748daeef52d353dda66c7b89322b7708fc Mon Sep 17 00:00:00 2001 From: Evan Hazlett Date: Thu, 3 Nov 2016 11:08:22 -0400 Subject: [PATCH] move secretopt to opts pkg Signed-off-by: Evan Hazlett --- api/types/client.go | 10 ++++ api/types/swarm/secret.go | 9 ++++ cli/command/service/opts.go | 2 +- cli/command/service/parse.go | 18 +++---- cli/command/service/update.go | 2 +- opts/secret.go | 95 +++++++++++++++++++++++++++++++++++ 6 files changed, 125 insertions(+), 11 deletions(-) create mode 100644 opts/secret.go diff --git a/api/types/client.go b/api/types/client.go index 769c836446..d79ebd9e55 100644 --- a/api/types/client.go +++ b/api/types/client.go @@ -4,6 +4,7 @@ import ( "bufio" "io" "net" + "os" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" @@ -339,3 +340,12 @@ type PluginInstallOptions struct { AcceptPermissionsFunc func(PluginPrivileges) (bool, error) Args []string } + +// SecretRequestOptions is a type for requesting secrets +type SecretRequestOptions struct { + Source string + Target string + UID string + GID string + Mode os.FileMode +} diff --git a/api/types/swarm/secret.go b/api/types/swarm/secret.go index 1f842c32ca..21a9e7cde2 100644 --- a/api/types/swarm/secret.go +++ b/api/types/swarm/secret.go @@ -28,3 +28,12 @@ type SecretReference struct { SecretName string Target SecretReferenceFileTarget } + +// SecretRequestSpec is a type for requesting secrets +type SecretRequestSpec struct { + Source string + Target string + UID string + GID string + Mode os.FileMode +} diff --git a/cli/command/service/opts.go b/cli/command/service/opts.go index 00cdecb67d..45adb37672 100644 --- a/cli/command/service/opts.go +++ b/cli/command/service/opts.go @@ -432,7 +432,7 @@ type serviceOptions struct { logDriver logDriverOptions healthcheck healthCheckOptions - secrets SecretOpt + secrets opts.SecretOpt } func newServiceOptions() *serviceOptions { diff --git a/cli/command/service/parse.go b/cli/command/service/parse.go index 73fa8a0cb9..cbf2745dce 100644 --- a/cli/command/service/parse.go +++ b/cli/command/service/parse.go @@ -12,25 +12,25 @@ import ( // parseSecrets retrieves the secrets from the requested names and converts // them to secret references to use with the spec -func parseSecrets(client client.APIClient, requestedSecrets []*SecretRequestSpec) ([]*swarmtypes.SecretReference, error) { +func parseSecrets(client client.APIClient, requestedSecrets []*types.SecretRequestOptions) ([]*swarmtypes.SecretReference, error) { secretRefs := make(map[string]*swarmtypes.SecretReference) ctx := context.Background() for _, secret := range requestedSecrets { secretRef := &swarmtypes.SecretReference{ - SecretName: secret.source, + SecretName: secret.Source, Target: swarmtypes.SecretReferenceFileTarget{ - Name: secret.target, - UID: secret.uid, - GID: secret.gid, - Mode: secret.mode, + Name: secret.Target, + UID: secret.UID, + GID: secret.GID, + Mode: secret.Mode, }, } - if _, exists := secretRefs[secret.target]; exists { - return nil, fmt.Errorf("duplicate secret target for %s not allowed", secret.source) + if _, exists := secretRefs[secret.Target]; exists { + return nil, fmt.Errorf("duplicate secret target for %s not allowed", secret.Source) } - secretRefs[secret.target] = secretRef + secretRefs[secret.Target] = secretRef } args := filters.NewArgs() diff --git a/cli/command/service/update.go b/cli/command/service/update.go index 37f709e230..1bc72a8f19 100644 --- a/cli/command/service/update.go +++ b/cli/command/service/update.go @@ -413,7 +413,7 @@ func updateEnvironment(flags *pflag.FlagSet, field *[]string) { func getUpdatedSecrets(apiClient client.APIClient, flags *pflag.FlagSet, secrets []*swarm.SecretReference) ([]*swarm.SecretReference, error) { if flags.Changed(flagSecretAdd) { - values := flags.Lookup(flagSecretAdd).Value.(*SecretOpt).Value() + values := flags.Lookup(flagSecretAdd).Value.(*opts.SecretOpt).Value() addSecrets, err := parseSecrets(apiClient, values) if err != nil { diff --git a/opts/secret.go b/opts/secret.go new file mode 100644 index 0000000000..34ed42a680 --- /dev/null +++ b/opts/secret.go @@ -0,0 +1,95 @@ +package opts + +import ( + "encoding/csv" + "fmt" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/docker/docker/api/types" +) + +// SecretOpt is a Value type for parsing secrets +type SecretOpt struct { + values []*types.SecretRequestOptions +} + +// Set a new secret value +func (o *SecretOpt) Set(value string) error { + csvReader := csv.NewReader(strings.NewReader(value)) + fields, err := csvReader.Read() + if err != nil { + return err + } + + options := &types.SecretRequestOptions{ + Source: "", + Target: "", + UID: "0", + GID: "0", + Mode: 0444, + } + + for _, field := range fields { + parts := strings.SplitN(field, "=", 2) + key := strings.ToLower(parts[0]) + + if len(parts) != 2 { + return fmt.Errorf("invalid field '%s' must be a key=value pair", field) + } + + value := parts[1] + switch key { + case "source": + options.Source = value + case "target": + tDir, _ := filepath.Split(value) + if tDir != "" { + return fmt.Errorf("target must not be a path") + } + options.Target = value + case "uid": + options.UID = value + case "gid": + options.GID = value + case "mode": + m, err := strconv.ParseUint(value, 0, 32) + if err != nil { + return fmt.Errorf("invalid mode specified: %v", err) + } + + options.Mode = os.FileMode(m) + default: + return fmt.Errorf("invalid field in secret request: %s", key) + } + } + + if options.Source == "" { + return fmt.Errorf("source is required") + } + + o.values = append(o.values, options) + return nil +} + +// Type returns the type of this option +func (o *SecretOpt) Type() string { + return "secret" +} + +// String returns a string repr of this option +func (o *SecretOpt) String() string { + secrets := []string{} + for _, secret := range o.values { + repr := fmt.Sprintf("%s -> %s", secret.Source, secret.Target) + secrets = append(secrets, repr) + } + return strings.Join(secrets, ", ") +} + +// Value returns the secret requests +func (o *SecretOpt) Value() []*types.SecretRequestOptions { + return o.values +}