Signed-off-by: Evan Hazlett <ejhazlett@gmail.com>
| ... | ... |
@@ -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 |
+} |
| ... | ... |
@@ -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 |
+} |