Browse code

review changes

- fix lint issues
- use errors pkg for wrapping errors
- cleanup on error when setting up secrets mount
- fix erroneous import
- remove unneeded switch for secret reference mode
- return single mount for secrets instead of slice

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

Evan Hazlett authored on 2016/10/27 05:30:53
Showing 12 changed files
... ...
@@ -11,7 +11,7 @@ type Secret struct {
11 11
 
12 12
 type SecretSpec struct {
13 13
 	Annotations
14
-	Data []byte `json",omitempty"`
14
+	Data []byte `json:",omitempty"`
15 15
 }
16 16
 
17 17
 type SecretReferenceMode int
... ...
@@ -3,6 +3,7 @@ package service
3 3
 import (
4 4
 	"context"
5 5
 	"fmt"
6
+	"path/filepath"
6 7
 	"strings"
7 8
 
8 9
 	"github.com/docker/docker/api/types"
... ...
@@ -31,6 +32,13 @@ func parseSecretString(secretString string) (string, string, error) {
31 31
 	} else {
32 32
 		targetName = secretName
33 33
 	}
34
+
35
+	// ensure target is a filename only; no paths allowed
36
+	tDir, _ := filepath.Split(targetName)
37
+	if tDir != "" {
38
+		return "", "", fmt.Errorf("target must not have a path")
39
+	}
40
+
34 41
 	return secretName, targetName, nil
35 42
 }
36 43
 
... ...
@@ -22,8 +22,8 @@ import (
22 22
 	"golang.org/x/sys/unix"
23 23
 )
24 24
 
25
-// DefaultSHMSize is the default size (64MB) of the SHM which will be mounted in the container
26 25
 const (
26
+	// DefaultSHMSize is the default size (64MB) of the SHM which will be mounted in the container
27 27
 	DefaultSHMSize           int64 = 67108864
28 28
 	containerSecretMountPath       = "/run/secrets"
29 29
 )
... ...
@@ -178,6 +178,7 @@ func (container *Container) NetworkMounts() []Mount {
178 178
 	return mounts
179 179
 }
180 180
 
181
+// SecretMountPath returns the path of the secret mount for the container
181 182
 func (container *Container) SecretMountPath() string {
182 183
 	return filepath.Join(container.Root, "secrets")
183 184
 }
... ...
@@ -267,19 +268,19 @@ func (container *Container) IpcMounts() []Mount {
267 267
 	return mounts
268 268
 }
269 269
 
270
-// SecretMounts returns the list of Secret mounts
271
-func (container *Container) SecretMounts() []Mount {
272
-	var mounts []Mount
270
+// SecretMount returns the list of Secret mounts
271
+func (container *Container) SecretMount() Mount {
272
+	var mount Mount
273 273
 
274 274
 	if len(container.Secrets) > 0 {
275
-		mounts = append(mounts, Mount{
275
+		mount = Mount{
276 276
 			Source:      container.SecretMountPath(),
277 277
 			Destination: containerSecretMountPath,
278 278
 			Writable:    false,
279
-		})
279
+		}
280 280
 	}
281 281
 
282
-	return mounts
282
+	return mount
283 283
 }
284 284
 
285 285
 // UnmountSecrets unmounts the local tmpfs for secrets
... ...
@@ -79,12 +79,9 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) types.ContainerSpec {
79 79
 func secretReferencesToGRPC(sr []*types.SecretReference) []*swarmapi.SecretReference {
80 80
 	refs := []*swarmapi.SecretReference{}
81 81
 	for _, s := range sr {
82
-		var mode swarmapi.SecretReference_Mode
83
-		switch s.Mode {
84
-		case types.SecretReferenceSystem:
82
+		mode := swarmapi.SecretReference_FILE
83
+		if s.Mode == types.SecretReferenceSystem {
85 84
 			mode = swarmapi.SecretReference_SYSTEM
86
-		default:
87
-			mode = swarmapi.SecretReference_FILE
88 85
 		}
89 86
 		refs = append(refs, &swarmapi.SecretReference{
90 87
 			SecretID:   s.SecretID,
... ...
@@ -1,7 +1,6 @@
1 1
 package convert
2 2
 
3 3
 import (
4
-	"github.com/Sirupsen/logrus"
5 4
 	swarmtypes "github.com/docker/docker/api/types/swarm"
6 5
 	swarmapi "github.com/docker/swarmkit/api"
7 6
 	"github.com/docker/swarmkit/protobuf/ptypes"
... ...
@@ -9,7 +8,6 @@ import (
9 9
 
10 10
 // SecretFromGRPC converts a grpc Secret to a Secret.
11 11
 func SecretFromGRPC(s *swarmapi.Secret) swarmtypes.Secret {
12
-	logrus.Debugf("%+v", s)
13 12
 	secret := swarmtypes.Secret{
14 13
 		ID:         s.ID,
15 14
 		Digest:     s.Digest,
... ...
@@ -33,14 +31,12 @@ func SecretFromGRPC(s *swarmapi.Secret) swarmtypes.Secret {
33 33
 }
34 34
 
35 35
 // SecretSpecToGRPC converts Secret to a grpc Secret.
36
-func SecretSpecToGRPC(s swarmtypes.SecretSpec) (swarmapi.SecretSpec, error) {
37
-	spec := swarmapi.SecretSpec{
36
+func SecretSpecToGRPC(s swarmtypes.SecretSpec) swarmapi.SecretSpec {
37
+	return swarmapi.SecretSpec{
38 38
 		Annotations: swarmapi.Annotations{
39 39
 			Name:   s.Name,
40 40
 			Labels: s.Labels,
41 41
 		},
42 42
 		Data: s.Data,
43 43
 	}
44
-
45
-	return spec, nil
46 44
 }
... ...
@@ -2,9 +2,9 @@ package container
2 2
 
3 3
 import (
4 4
 	executorpkg "github.com/docker/docker/daemon/cluster/executor"
5
+	"github.com/docker/swarmkit/agent/exec"
5 6
 	"github.com/docker/swarmkit/api"
6 7
 	"golang.org/x/net/context"
7
-	"src/github.com/docker/swarmkit/agent/exec"
8 8
 )
9 9
 
10 10
 // networkAttacherController implements agent.Controller against docker's API.
... ...
@@ -63,10 +63,7 @@ func (c *Cluster) CreateSecret(s types.SecretSpec) (string, error) {
63 63
 	ctx, cancel := c.getRequestContext()
64 64
 	defer cancel()
65 65
 
66
-	secretSpec, err := convert.SecretSpecToGRPC(s)
67
-	if err != nil {
68
-		return "", err
69
-	}
66
+	secretSpec := convert.SecretSpecToGRPC(s)
70 67
 
71 68
 	r, err := c.node.client.CreateSecret(ctx,
72 69
 		&swarmapi.CreateSecretRequest{Spec: &secretSpec})
... ...
@@ -111,10 +108,7 @@ func (c *Cluster) UpdateSecret(id string, version uint64, spec types.SecretSpec)
111 111
 	ctx, cancel := c.getRequestContext()
112 112
 	defer cancel()
113 113
 
114
-	secretSpec, err := convert.SecretSpecToGRPC(spec)
115
-	if err != nil {
116
-		return err
117
-	}
114
+	secretSpec := convert.SecretSpecToGRPC(spec)
118 115
 
119 116
 	if _, err := c.client.UpdateSecret(ctx,
120 117
 		&swarmapi.UpdateSecretRequest{
... ...
@@ -13,6 +13,7 @@ import (
13 13
 	"time"
14 14
 
15 15
 	"github.com/Sirupsen/logrus"
16
+	"github.com/cloudflare/cfssl/log"
16 17
 	containertypes "github.com/docker/docker/api/types/container"
17 18
 	"github.com/docker/docker/container"
18 19
 	"github.com/docker/docker/daemon/links"
... ...
@@ -25,6 +26,7 @@ import (
25 25
 	"github.com/opencontainers/runc/libcontainer/devices"
26 26
 	"github.com/opencontainers/runc/libcontainer/label"
27 27
 	"github.com/opencontainers/runtime-spec/specs-go"
28
+	"github.com/pkg/errors"
28 29
 )
29 30
 
30 31
 func u32Ptr(i int64) *uint32     { u := uint32(i); return &u }
... ...
@@ -146,36 +148,58 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) error {
146 146
 	localMountPath := c.SecretMountPath()
147 147
 	logrus.Debugf("secrets: setting up secret dir: %s", localMountPath)
148 148
 
149
+	var setupErr error
150
+
151
+	defer func(err error) {
152
+		if err != nil {
153
+			// cleanup
154
+			_ = detachMounted(localMountPath)
155
+
156
+			if err := os.RemoveAll(localMountPath); err != nil {
157
+				log.Errorf("error cleaning up secret mount: %s", err)
158
+			}
159
+		}
160
+	}(setupErr)
161
+
149 162
 	// create tmpfs
150 163
 	if err := os.MkdirAll(localMountPath, 0700); err != nil {
151
-		return fmt.Errorf("error creating secret local mount path: %s", err)
164
+		setupErr = errors.Wrap(err, "error creating secret local mount path")
152 165
 	}
153 166
 	if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "nodev"); err != nil {
154
-		return fmt.Errorf("unable to setup secret mount: %s", err)
167
+		setupErr = errors.Wrap(err, "unable to setup secret mount")
155 168
 	}
156 169
 
157 170
 	for _, s := range c.Secrets {
158
-		fPath := filepath.Join(localMountPath, s.Target)
171
+		// ensure that the target is a filename only; no paths allowed
172
+		tDir, tPath := filepath.Split(s.Target)
173
+		if tDir != "" {
174
+			setupErr = fmt.Errorf("error creating secret: secret must not have a path")
175
+		}
176
+
177
+		fPath := filepath.Join(localMountPath, tPath)
159 178
 		if err := os.MkdirAll(filepath.Dir(fPath), 0700); err != nil {
160
-			return fmt.Errorf("error creating secret mount path: %s", err)
179
+			setupErr = errors.Wrap(err, "error creating secret mount path")
161 180
 		}
162 181
 
163
-		logrus.Debugf("injecting secret: name=%s path=%s", s.Name, fPath)
182
+		logrus.WithFields(logrus.Fields{
183
+			"name": s.Name,
184
+			"path": fPath,
185
+		}).Debug("injecting secret")
164 186
 		if err := ioutil.WriteFile(fPath, s.Data, s.Mode); err != nil {
165
-			return fmt.Errorf("error injecting secret: %s", err)
187
+			setupErr = errors.Wrap(err, "error injecting secret")
166 188
 		}
167 189
 
168 190
 		if err := os.Chown(fPath, s.Uid, s.Gid); err != nil {
169
-			return fmt.Errorf("error setting ownership for secret: %s", err)
191
+			setupErr = errors.Wrap(err, "error setting ownership for secret")
170 192
 		}
171 193
 	}
172 194
 
173 195
 	// remount secrets ro
174 196
 	if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "remount,ro"); err != nil {
175
-		return fmt.Errorf("unable to remount secret dir as readonly: %s", err)
197
+		setupErr = errors.Wrap(err, "unable to remount secret dir as readonly")
176 198
 	}
177 199
 
178
-	return nil
200
+	return setupErr
179 201
 }
180 202
 
181 203
 func killProcessDirectly(container *container.Container) error {
... ...
@@ -718,7 +718,8 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
718 718
 	}
719 719
 	ms = append(ms, tmpfsMounts...)
720 720
 
721
-	ms = append(ms, c.SecretMounts()...)
721
+	ms = append(ms, c.SecretMount())
722
+
722 723
 	sort.Sort(mounts(ms))
723 724
 	if err := setMounts(daemon, &s, c, ms); err != nil {
724 725
 		return nil, fmt.Errorf("linux mounts: %v", err)
... ...
@@ -5,8 +5,9 @@ import (
5 5
 	containertypes "github.com/docker/docker/api/types/container"
6 6
 )
7 7
 
8
+// SetContainerSecrets sets the container secrets needed
8 9
 func (daemon *Daemon) SetContainerSecrets(name string, secrets []*containertypes.ContainerSecret) error {
9
-	if !secretsSupported() {
10
+	if !secretsSupported() && len(secrets) > 0 {
10 11
 		logrus.Warn("secrets are not supported on this platform")
11 12
 		return nil
12 13
 	}
... ...
@@ -284,6 +284,16 @@ func (d *SwarmDaemon) listServices(c *check.C) []swarm.Service {
284 284
 	return services
285 285
 }
286 286
 
287
+func (d *SwarmDaemon) listSecrets(c *check.C) []swarm.Service {
288
+	status, out, err := d.SockRequest("GET", "/secrets", nil)
289
+	c.Assert(err, checker.IsNil, check.Commentf(string(out)))
290
+	c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
291
+
292
+	secrets := []swarm.Secret{}
293
+	c.Assert(json.Unmarshal(out, &secrets), checker.IsNil)
294
+	return services
295
+}
296
+
287 297
 func (d *SwarmDaemon) getSwarm(c *check.C) swarm.Swarm {
288 298
 	var sw swarm.Swarm
289 299
 	status, out, err := d.SockRequest("GET", "/swarm", nil)
... ...
@@ -1263,3 +1263,27 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesUpdateWithName(c *check.C) {
1263 1263
 	c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
1264 1264
 	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, instances)
1265 1265
 }
1266
+
1267
+func (s *DockerSwarmSuite) TestAPISwarmSecretsEmptyList(c *check.C) {
1268
+	d := s.AddDaemon(c, true, true)
1269
+
1270
+	secrets := d.listSecrets(c)
1271
+	c.Assert(secrets, checker.NotNil)
1272
+	c.Assert(len(secrets), checker.Equals, 0, check.Commentf("secrets: %#v", secrets))
1273
+}
1274
+
1275
+//func (s *DockerSwarmSuite) TestAPISwarmServicesCreate(c *check.C) {
1276
+//	d := s.AddDaemon(c, true, true)
1277
+//
1278
+//	instances := 2
1279
+//	id := d.createService(c, simpleTestService, setInstances(instances))
1280
+//	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, instances)
1281
+//
1282
+//	service := d.getService(c, id)
1283
+//	instances = 5
1284
+//	d.updateService(c, service, setInstances(instances))
1285
+//	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, instances)
1286
+//
1287
+//	d.removeService(c, service.ID)
1288
+//	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 0)
1289
+//}