Browse code

move secretopt to opts pkg

Signed-off-by: Evan Hazlett <ejhazlett@gmail.com>

Evan Hazlett authored on 2016/11/04 00:08:22
Showing 6 changed files
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"bufio"
5 5
 	"io"
6 6
 	"net"
7
+	"os"
7 8
 
8 9
 	"github.com/docker/docker/api/types/container"
9 10
 	"github.com/docker/docker/api/types/filters"
... ...
@@ -339,3 +340,12 @@ type PluginInstallOptions struct {
339 339
 	AcceptPermissionsFunc func(PluginPrivileges) (bool, error)
340 340
 	Args                  []string
341 341
 }
342
+
343
+// SecretRequestOptions is a type for requesting secrets
344
+type SecretRequestOptions struct {
345
+	Source string
346
+	Target string
347
+	UID    string
348
+	GID    string
349
+	Mode   os.FileMode
350
+}
... ...
@@ -28,3 +28,12 @@ type SecretReference struct {
28 28
 	SecretName string
29 29
 	Target     SecretReferenceFileTarget
30 30
 }
31
+
32
+// SecretRequestSpec is a type for requesting secrets
33
+type SecretRequestSpec struct {
34
+	Source string
35
+	Target string
36
+	UID    string
37
+	GID    string
38
+	Mode   os.FileMode
39
+}
... ...
@@ -432,7 +432,7 @@ type serviceOptions struct {
432 432
 	logDriver logDriverOptions
433 433
 
434 434
 	healthcheck healthCheckOptions
435
-	secrets     SecretOpt
435
+	secrets     opts.SecretOpt
436 436
 }
437 437
 
438 438
 func newServiceOptions() *serviceOptions {
... ...
@@ -12,25 +12,25 @@ import (
12 12
 
13 13
 // parseSecrets retrieves the secrets from the requested names and converts
14 14
 // them to secret references to use with the spec
15
-func parseSecrets(client client.APIClient, requestedSecrets []*SecretRequestSpec) ([]*swarmtypes.SecretReference, error) {
15
+func parseSecrets(client client.APIClient, requestedSecrets []*types.SecretRequestOptions) ([]*swarmtypes.SecretReference, error) {
16 16
 	secretRefs := make(map[string]*swarmtypes.SecretReference)
17 17
 	ctx := context.Background()
18 18
 
19 19
 	for _, secret := range requestedSecrets {
20 20
 		secretRef := &swarmtypes.SecretReference{
21
-			SecretName: secret.source,
21
+			SecretName: secret.Source,
22 22
 			Target: swarmtypes.SecretReferenceFileTarget{
23
-				Name: secret.target,
24
-				UID:  secret.uid,
25
-				GID:  secret.gid,
26
-				Mode: secret.mode,
23
+				Name: secret.Target,
24
+				UID:  secret.UID,
25
+				GID:  secret.GID,
26
+				Mode: secret.Mode,
27 27
 			},
28 28
 		}
29 29
 
30
-		if _, exists := secretRefs[secret.target]; exists {
31
-			return nil, fmt.Errorf("duplicate secret target for %s not allowed", secret.source)
30
+		if _, exists := secretRefs[secret.Target]; exists {
31
+			return nil, fmt.Errorf("duplicate secret target for %s not allowed", secret.Source)
32 32
 		}
33
-		secretRefs[secret.target] = secretRef
33
+		secretRefs[secret.Target] = secretRef
34 34
 	}
35 35
 
36 36
 	args := filters.NewArgs()
... ...
@@ -413,7 +413,7 @@ func updateEnvironment(flags *pflag.FlagSet, field *[]string) {
413 413
 
414 414
 func getUpdatedSecrets(apiClient client.APIClient, flags *pflag.FlagSet, secrets []*swarm.SecretReference) ([]*swarm.SecretReference, error) {
415 415
 	if flags.Changed(flagSecretAdd) {
416
-		values := flags.Lookup(flagSecretAdd).Value.(*SecretOpt).Value()
416
+		values := flags.Lookup(flagSecretAdd).Value.(*opts.SecretOpt).Value()
417 417
 
418 418
 		addSecrets, err := parseSecrets(apiClient, values)
419 419
 		if err != nil {
420 420
new file mode 100644
... ...
@@ -0,0 +1,95 @@
0
+package opts
1
+
2
+import (
3
+	"encoding/csv"
4
+	"fmt"
5
+	"os"
6
+	"path/filepath"
7
+	"strconv"
8
+	"strings"
9
+
10
+	"github.com/docker/docker/api/types"
11
+)
12
+
13
+// SecretOpt is a Value type for parsing secrets
14
+type SecretOpt struct {
15
+	values []*types.SecretRequestOptions
16
+}
17
+
18
+// Set a new secret value
19
+func (o *SecretOpt) Set(value string) error {
20
+	csvReader := csv.NewReader(strings.NewReader(value))
21
+	fields, err := csvReader.Read()
22
+	if err != nil {
23
+		return err
24
+	}
25
+
26
+	options := &types.SecretRequestOptions{
27
+		Source: "",
28
+		Target: "",
29
+		UID:    "0",
30
+		GID:    "0",
31
+		Mode:   0444,
32
+	}
33
+
34
+	for _, field := range fields {
35
+		parts := strings.SplitN(field, "=", 2)
36
+		key := strings.ToLower(parts[0])
37
+
38
+		if len(parts) != 2 {
39
+			return fmt.Errorf("invalid field '%s' must be a key=value pair", field)
40
+		}
41
+
42
+		value := parts[1]
43
+		switch key {
44
+		case "source":
45
+			options.Source = value
46
+		case "target":
47
+			tDir, _ := filepath.Split(value)
48
+			if tDir != "" {
49
+				return fmt.Errorf("target must not be a path")
50
+			}
51
+			options.Target = value
52
+		case "uid":
53
+			options.UID = value
54
+		case "gid":
55
+			options.GID = value
56
+		case "mode":
57
+			m, err := strconv.ParseUint(value, 0, 32)
58
+			if err != nil {
59
+				return fmt.Errorf("invalid mode specified: %v", err)
60
+			}
61
+
62
+			options.Mode = os.FileMode(m)
63
+		default:
64
+			return fmt.Errorf("invalid field in secret request: %s", key)
65
+		}
66
+	}
67
+
68
+	if options.Source == "" {
69
+		return fmt.Errorf("source is required")
70
+	}
71
+
72
+	o.values = append(o.values, options)
73
+	return nil
74
+}
75
+
76
+// Type returns the type of this option
77
+func (o *SecretOpt) Type() string {
78
+	return "secret"
79
+}
80
+
81
+// String returns a string repr of this option
82
+func (o *SecretOpt) String() string {
83
+	secrets := []string{}
84
+	for _, secret := range o.values {
85
+		repr := fmt.Sprintf("%s -> %s", secret.Source, secret.Target)
86
+		secrets = append(secrets, repr)
87
+	}
88
+	return strings.Join(secrets, ", ")
89
+}
90
+
91
+// Value returns the secret requests
92
+func (o *SecretOpt) Value() []*types.SecretRequestOptions {
93
+	return o.values
94
+}