On unix, merge secrets/configs handling. This is important because
configs can contain secrets (via templating) and potentially a config
could just simply have secret information "by accident" from the user.
This just make sure that configs are as secure as secrets and de-dups a
lot of code.
Generally this makes everything simpler and configs more secure.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
| ... | ... |
@@ -68,13 +68,6 @@ type ExitStatus struct {
|
| 68 | 68 |
ExitedAt time.Time |
| 69 | 69 |
} |
| 70 | 70 |
|
| 71 |
-// ConfigReference wraps swarmtypes.ConfigReference to add a Sensitive flag. |
|
| 72 |
-type ConfigReference struct {
|
|
| 73 |
- *swarmtypes.ConfigReference |
|
| 74 |
- // Sensitive is set if this config should not be written to disk. |
|
| 75 |
- Sensitive bool |
|
| 76 |
-} |
|
| 77 |
- |
|
| 78 | 71 |
// Container holds the structure defining a container object. |
| 79 | 72 |
type Container struct {
|
| 80 | 73 |
StreamConfig *stream.Config |
| ... | ... |
@@ -106,7 +99,7 @@ type Container struct {
|
| 106 | 106 |
ExecCommands *exec.Store `json:"-"` |
| 107 | 107 |
DependencyStore agentexec.DependencyGetter `json:"-"` |
| 108 | 108 |
SecretReferences []*swarmtypes.SecretReference |
| 109 |
- ConfigReferences []*ConfigReference |
|
| 109 |
+ ConfigReferences []*swarmtypes.ConfigReference |
|
| 110 | 110 |
// logDriver for closing |
| 111 | 111 |
LogDriver logger.Logger `json:"-"` |
| 112 | 112 |
LogCopier *logger.Copier `json:"-"` |
| ... | ... |
@@ -1056,31 +1049,6 @@ func getSecretTargetPath(r *swarmtypes.SecretReference) string {
|
| 1056 | 1056 |
return filepath.Join(containerSecretMountPath, r.File.Name) |
| 1057 | 1057 |
} |
| 1058 | 1058 |
|
| 1059 |
-// ConfigsDirPath returns the path to the directory where configs are stored on |
|
| 1060 |
-// disk. |
|
| 1061 |
-func (container *Container) ConfigsDirPath() (string, error) {
|
|
| 1062 |
- return container.GetRootResourcePath("configs")
|
|
| 1063 |
-} |
|
| 1064 |
- |
|
| 1065 |
-// ConfigFilePath returns the path to the on-disk location of a config. |
|
| 1066 |
-func (container *Container) ConfigFilePath(configRef swarmtypes.ConfigReference) (string, error) {
|
|
| 1067 |
- configs, err := container.ConfigsDirPath() |
|
| 1068 |
- if err != nil {
|
|
| 1069 |
- return "", err |
|
| 1070 |
- } |
|
| 1071 |
- return filepath.Join(configs, configRef.ConfigID), nil |
|
| 1072 |
-} |
|
| 1073 |
- |
|
| 1074 |
-// SensitiveConfigFilePath returns the path to the location of a config mounted |
|
| 1075 |
-// as a secret. |
|
| 1076 |
-func (container *Container) SensitiveConfigFilePath(configRef swarmtypes.ConfigReference) (string, error) {
|
|
| 1077 |
- secretMountPath, err := container.SecretMountPath() |
|
| 1078 |
- if err != nil {
|
|
| 1079 |
- return "", err |
|
| 1080 |
- } |
|
| 1081 |
- return filepath.Join(secretMountPath, configRef.ConfigID+"c"), nil |
|
| 1082 |
-} |
|
| 1083 |
- |
|
| 1084 | 1059 |
// CreateDaemonEnvironment creates a new environment variable slice for this container. |
| 1085 | 1060 |
func (container *Container) CreateDaemonEnvironment(tty bool, linkedEnv []string) []string {
|
| 1086 | 1061 |
// Setup environment |
| ... | ... |
@@ -5,11 +5,13 @@ package container // import "github.com/docker/docker/container" |
| 5 | 5 |
import ( |
| 6 | 6 |
"io/ioutil" |
| 7 | 7 |
"os" |
| 8 |
+ "path/filepath" |
|
| 8 | 9 |
|
| 9 | 10 |
"github.com/containerd/continuity/fs" |
| 10 | 11 |
"github.com/docker/docker/api/types" |
| 11 | 12 |
containertypes "github.com/docker/docker/api/types/container" |
| 12 | 13 |
mounttypes "github.com/docker/docker/api/types/mount" |
| 14 |
+ swarmtypes "github.com/docker/docker/api/types/swarm" |
|
| 13 | 15 |
"github.com/docker/docker/pkg/mount" |
| 14 | 16 |
"github.com/docker/docker/pkg/stringid" |
| 15 | 17 |
"github.com/docker/docker/volume" |
| ... | ... |
@@ -234,10 +236,7 @@ func (container *Container) SecretMounts() ([]Mount, error) {
|
| 234 | 234 |
}) |
| 235 | 235 |
} |
| 236 | 236 |
for _, r := range container.ConfigReferences {
|
| 237 |
- if !r.Sensitive || r.File == nil {
|
|
| 238 |
- continue |
|
| 239 |
- } |
|
| 240 |
- fPath, err := container.SensitiveConfigFilePath(*r.ConfigReference) |
|
| 237 |
+ fPath, err := container.ConfigFilePath(*r) |
|
| 241 | 238 |
if err != nil {
|
| 242 | 239 |
return nil, err |
| 243 | 240 |
} |
| ... | ... |
@@ -267,27 +266,6 @@ func (container *Container) UnmountSecrets() error {
|
| 267 | 267 |
return mount.RecursiveUnmount(p) |
| 268 | 268 |
} |
| 269 | 269 |
|
| 270 |
-// ConfigMounts returns the mounts for configs. |
|
| 271 |
-func (container *Container) ConfigMounts() ([]Mount, error) {
|
|
| 272 |
- var mounts []Mount |
|
| 273 |
- for _, configRef := range container.ConfigReferences {
|
|
| 274 |
- if configRef.Sensitive || configRef.File == nil {
|
|
| 275 |
- continue |
|
| 276 |
- } |
|
| 277 |
- src, err := container.ConfigFilePath(*configRef.ConfigReference) |
|
| 278 |
- if err != nil {
|
|
| 279 |
- return nil, err |
|
| 280 |
- } |
|
| 281 |
- mounts = append(mounts, Mount{
|
|
| 282 |
- Source: src, |
|
| 283 |
- Destination: configRef.File.Name, |
|
| 284 |
- Writable: false, |
|
| 285 |
- }) |
|
| 286 |
- } |
|
| 287 |
- |
|
| 288 |
- return mounts, nil |
|
| 289 |
-} |
|
| 290 |
- |
|
| 291 | 270 |
type conflictingUpdateOptions string |
| 292 | 271 |
|
| 293 | 272 |
func (e conflictingUpdateOptions) Error() string {
|
| ... | ... |
@@ -471,3 +449,13 @@ func (container *Container) GetMountPoints() []types.MountPoint {
|
| 471 | 471 |
} |
| 472 | 472 |
return mountPoints |
| 473 | 473 |
} |
| 474 |
+ |
|
| 475 |
+// ConfigFilePath returns the path to the on-disk location of a config. |
|
| 476 |
+// On unix, configs are always considered secret |
|
| 477 |
+func (container *Container) ConfigFilePath(configRef swarmtypes.ConfigReference) (string, error) {
|
|
| 478 |
+ mounts, err := container.SecretMountPath() |
|
| 479 |
+ if err != nil {
|
|
| 480 |
+ return "", err |
|
| 481 |
+ } |
|
| 482 |
+ return filepath.Join(mounts, configRef.ConfigID), nil |
|
| 483 |
+} |
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
|
| 8 | 8 |
"github.com/docker/docker/api/types" |
| 9 | 9 |
containertypes "github.com/docker/docker/api/types/container" |
| 10 |
+ swarmtypes "github.com/docker/docker/api/types/swarm" |
|
| 10 | 11 |
"github.com/docker/docker/pkg/system" |
| 11 | 12 |
) |
| 12 | 13 |
|
| ... | ... |
@@ -102,23 +103,20 @@ func (container *Container) CreateConfigSymlinks() error {
|
| 102 | 102 |
} |
| 103 | 103 |
|
| 104 | 104 |
// ConfigMounts returns the mount for configs. |
| 105 |
-// All configs are stored in a single mount on Windows. Target symlinks are |
|
| 106 |
-// created for each config, pointing to the files in this mount. |
|
| 107 |
-func (container *Container) ConfigMounts() ([]Mount, error) {
|
|
| 105 |
+// TODO: Right now Windows doesn't really have a "secure" storage for secrets, |
|
| 106 |
+// however some configs may contain secrets. Once secure storage is worked out, |
|
| 107 |
+// configs and secret handling should be merged. |
|
| 108 |
+func (container *Container) ConfigMounts() []Mount {
|
|
| 108 | 109 |
var mounts []Mount |
| 109 | 110 |
if len(container.ConfigReferences) > 0 {
|
| 110 |
- src, err := container.ConfigsDirPath() |
|
| 111 |
- if err != nil {
|
|
| 112 |
- return nil, err |
|
| 113 |
- } |
|
| 114 | 111 |
mounts = append(mounts, Mount{
|
| 115 |
- Source: src, |
|
| 112 |
+ Source: container.ConfigsDirPath(), |
|
| 116 | 113 |
Destination: containerInternalConfigsDirPath, |
| 117 | 114 |
Writable: false, |
| 118 | 115 |
}) |
| 119 | 116 |
} |
| 120 | 117 |
|
| 121 |
- return mounts, nil |
|
| 118 |
+ return mounts |
|
| 122 | 119 |
} |
| 123 | 120 |
|
| 124 | 121 |
// DetachAndUnmount unmounts all volumes. |
| ... | ... |
@@ -204,3 +202,12 @@ func (container *Container) GetMountPoints() []types.MountPoint {
|
| 204 | 204 |
} |
| 205 | 205 |
return mountPoints |
| 206 | 206 |
} |
| 207 |
+ |
|
| 208 |
+func (container *Container) ConfigsDirPath() string {
|
|
| 209 |
+ return filepath.Join(container.Root, "configs") |
|
| 210 |
+} |
|
| 211 |
+ |
|
| 212 |
+// ConfigFilePath returns the path to the on-disk location of a config. |
|
| 213 |
+func (container *Container) ConfigFilePath(configRef swarmtypes.ConfigReference) string {
|
|
| 214 |
+ return filepath.Join(container.ConfigsDirPath(), configRef.ConfigID) |
|
| 215 |
+} |
| ... | ... |
@@ -2,7 +2,6 @@ package daemon // import "github.com/docker/docker/daemon" |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
swarmtypes "github.com/docker/docker/api/types/swarm" |
| 5 |
- "github.com/docker/docker/container" |
|
| 6 | 5 |
"github.com/sirupsen/logrus" |
| 7 | 6 |
) |
| 8 | 7 |
|
| ... | ... |
@@ -17,10 +16,6 @@ func (daemon *Daemon) SetContainerConfigReferences(name string, refs []*swarmtyp |
| 17 | 17 |
if err != nil {
|
| 18 | 18 |
return err |
| 19 | 19 |
} |
| 20 |
- |
|
| 21 |
- for _, ref := range refs {
|
|
| 22 |
- c.ConfigReferences = append(c.ConfigReferences, &container.ConfigReference{ConfigReference: ref})
|
|
| 23 |
- } |
|
| 24 |
- |
|
| 20 |
+ c.ConfigReferences = append(c.ConfigReferences, refs...) |
|
| 25 | 21 |
return nil |
| 26 | 22 |
} |
| ... | ... |
@@ -161,20 +161,16 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
|
| 161 | 161 |
} |
| 162 | 162 |
|
| 163 | 163 |
func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
|
| 164 |
- if len(c.SecretReferences) == 0 {
|
|
| 164 |
+ if len(c.SecretReferences) == 0 && len(c.ConfigReferences) == 0 {
|
|
| 165 | 165 |
return nil |
| 166 | 166 |
} |
| 167 | 167 |
|
| 168 |
- localMountPath, err := c.SecretMountPath() |
|
| 169 |
- if err != nil {
|
|
| 170 |
- return errors.Wrap(err, "error getting secrets mount path for container") |
|
| 171 |
- } |
|
| 172 |
- if err := daemon.createSecretsDir(localMountPath); err != nil {
|
|
| 168 |
+ if err := daemon.createSecretsDir(c); err != nil {
|
|
| 173 | 169 |
return err |
| 174 | 170 |
} |
| 175 | 171 |
defer func() {
|
| 176 | 172 |
if setupErr != nil {
|
| 177 |
- daemon.cleanupSecretDir(localMountPath) |
|
| 173 |
+ daemon.cleanupSecretDir(c) |
|
| 178 | 174 |
} |
| 179 | 175 |
}() |
| 180 | 176 |
|
| ... | ... |
@@ -231,88 +227,16 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
|
| 231 | 231 |
} |
| 232 | 232 |
} |
| 233 | 233 |
|
| 234 |
- return daemon.remountSecretDir(c.MountLabel, localMountPath) |
|
| 235 |
-} |
|
| 236 |
- |
|
| 237 |
-// createSecretsDir is used to create a dir suitable for storing container secrets. |
|
| 238 |
-// In practice this is using a tmpfs mount and is used for both "configs" and "secrets" |
|
| 239 |
-func (daemon *Daemon) createSecretsDir(dir string) error {
|
|
| 240 |
- // retrieve possible remapped range start for root UID, GID |
|
| 241 |
- rootIDs := daemon.idMappings.RootPair() |
|
| 242 |
- // create tmpfs |
|
| 243 |
- if err := idtools.MkdirAllAndChown(dir, 0700, rootIDs); err != nil {
|
|
| 244 |
- return errors.Wrap(err, "error creating secret local mount path") |
|
| 245 |
- } |
|
| 246 |
- |
|
| 247 |
- tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
|
|
| 248 |
- if err := mount.Mount("tmpfs", dir, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
|
|
| 249 |
- return errors.Wrap(err, "unable to setup secret mount") |
|
| 250 |
- } |
|
| 251 |
- |
|
| 252 |
- return nil |
|
| 253 |
-} |
|
| 254 |
- |
|
| 255 |
-func (daemon *Daemon) remountSecretDir(mountLabel, dir string) error {
|
|
| 256 |
- if err := label.Relabel(dir, mountLabel, false); err != nil {
|
|
| 257 |
- logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
|
|
| 258 |
- } |
|
| 259 |
- rootIDs := daemon.idMappings.RootPair() |
|
| 260 |
- tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
|
|
| 261 |
- |
|
| 262 |
- // remount secrets ro |
|
| 263 |
- if err := mount.Mount("tmpfs", dir, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
|
|
| 264 |
- return errors.Wrap(err, "unable to remount dir as readonly") |
|
| 265 |
- } |
|
| 266 |
- |
|
| 267 |
- return nil |
|
| 268 |
-} |
|
| 269 |
- |
|
| 270 |
-func (daemon *Daemon) cleanupSecretDir(dir string) {
|
|
| 271 |
- if err := mount.RecursiveUnmount(dir); err != nil {
|
|
| 272 |
- logrus.WithField("dir", dir).WithError(err).Warn("Error while attmepting to unmount dir, this may prevent removal of container.")
|
|
| 273 |
- } |
|
| 274 |
- if err := os.RemoveAll(dir); err != nil && !os.IsNotExist(err) {
|
|
| 275 |
- logrus.WithField("dir", dir).WithError(err).Error("Error removing dir.")
|
|
| 276 |
- } |
|
| 277 |
-} |
|
| 278 |
- |
|
| 279 |
-func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
|
|
| 280 |
- if len(c.ConfigReferences) == 0 {
|
|
| 281 |
- return nil |
|
| 282 |
- } |
|
| 283 |
- |
|
| 284 |
- localPath, err := c.ConfigsDirPath() |
|
| 285 |
- if err != nil {
|
|
| 286 |
- return err |
|
| 287 |
- } |
|
| 288 |
- logrus.Debugf("configs: setting up config dir: %s", localPath)
|
|
| 289 |
- if err := daemon.createSecretsDir(localPath); err != nil {
|
|
| 290 |
- return err |
|
| 291 |
- } |
|
| 292 |
- defer func() {
|
|
| 293 |
- if setupErr != nil {
|
|
| 294 |
- daemon.cleanupSecretDir(localPath) |
|
| 295 |
- } |
|
| 296 |
- }() |
|
| 297 |
- |
|
| 298 |
- if c.DependencyStore == nil {
|
|
| 299 |
- return errors.New("config store is not initialized")
|
|
| 300 |
- } |
|
| 301 |
- |
|
| 302 |
- // retrieve possible remapped range start for root UID, GID |
|
| 303 |
- rootIDs := daemon.idMappings.RootPair() |
|
| 304 |
- |
|
| 305 | 234 |
for _, ref := range c.ConfigReferences {
|
| 306 | 235 |
// TODO (ehazlett): use type switch when more are supported |
| 307 | 236 |
if ref.File == nil {
|
| 308 | 237 |
logrus.Error("config target type is not a file target")
|
| 309 | 238 |
continue |
| 310 | 239 |
} |
| 311 |
- // configs are created in the ConfigsDirPath on the host, at a |
|
| 312 |
- // single level |
|
| 313 |
- fPath, err := c.ConfigFilePath(*ref.ConfigReference) |
|
| 240 |
+ |
|
| 241 |
+ fPath, err := c.ConfigFilePath(*ref) |
|
| 314 | 242 |
if err != nil {
|
| 315 |
- return err |
|
| 243 |
+ return errors.Wrap(err, "error getting config file path for container") |
|
| 316 | 244 |
} |
| 317 | 245 |
if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
|
| 318 | 246 |
return errors.Wrap(err, "error creating config mount path") |
| ... | ... |
@@ -342,14 +266,67 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
|
| 342 | 342 |
if err := os.Chown(fPath, rootIDs.UID+uid, rootIDs.GID+gid); err != nil {
|
| 343 | 343 |
return errors.Wrap(err, "error setting ownership for config") |
| 344 | 344 |
} |
| 345 |
- if err := os.Chmod(fPath, configRef.File.Mode); err != nil {
|
|
| 345 |
+ if err := os.Chmod(fPath, ref.File.Mode); err != nil {
|
|
| 346 | 346 |
return errors.Wrap(err, "error setting file mode for config") |
| 347 | 347 |
} |
| 348 |
+ } |
|
| 349 |
+ |
|
| 350 |
+ return daemon.remountSecretDir(c) |
|
| 351 |
+} |
|
| 352 |
+ |
|
| 353 |
+// createSecretsDir is used to create a dir suitable for storing container secrets. |
|
| 354 |
+// In practice this is using a tmpfs mount and is used for both "configs" and "secrets" |
|
| 355 |
+func (daemon *Daemon) createSecretsDir(c *container.Container) error {
|
|
| 356 |
+ // retrieve possible remapped range start for root UID, GID |
|
| 357 |
+ rootIDs := daemon.idMappings.RootPair() |
|
| 358 |
+ dir, err := c.SecretMountPath() |
|
| 359 |
+ if err != nil {
|
|
| 360 |
+ return errors.Wrap(err, "error getting container secrets dir") |
|
| 361 |
+ } |
|
| 362 |
+ |
|
| 363 |
+ // create tmpfs |
|
| 364 |
+ if err := idtools.MkdirAllAndChown(dir, 0700, rootIDs); err != nil {
|
|
| 365 |
+ return errors.Wrap(err, "error creating secret local mount path") |
|
| 366 |
+ } |
|
| 367 |
+ |
|
| 368 |
+ tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
|
|
| 369 |
+ if err := mount.Mount("tmpfs", dir, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
|
|
| 370 |
+ return errors.Wrap(err, "unable to setup secret mount") |
|
| 371 |
+ } |
|
| 348 | 372 |
|
| 349 |
- label.Relabel(fPath, c.MountLabel, false) |
|
| 373 |
+ return nil |
|
| 374 |
+} |
|
| 375 |
+ |
|
| 376 |
+func (daemon *Daemon) remountSecretDir(c *container.Container) error {
|
|
| 377 |
+ dir, err := c.SecretMountPath() |
|
| 378 |
+ if err != nil {
|
|
| 379 |
+ return errors.Wrap(err, "error getting container secrets path") |
|
| 350 | 380 |
} |
| 381 |
+ if err := label.Relabel(dir, c.MountLabel, false); err != nil {
|
|
| 382 |
+ logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
|
|
| 383 |
+ } |
|
| 384 |
+ rootIDs := daemon.idMappings.RootPair() |
|
| 385 |
+ tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
|
|
| 351 | 386 |
|
| 352 |
- return daemon.remountSecretDir(c.MountLabel, localPath) |
|
| 387 |
+ // remount secrets ro |
|
| 388 |
+ if err := mount.Mount("tmpfs", dir, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
|
|
| 389 |
+ return errors.Wrap(err, "unable to remount dir as readonly") |
|
| 390 |
+ } |
|
| 391 |
+ |
|
| 392 |
+ return nil |
|
| 393 |
+} |
|
| 394 |
+ |
|
| 395 |
+func (daemon *Daemon) cleanupSecretDir(c *container.Container) {
|
|
| 396 |
+ dir, err := c.SecretMountPath() |
|
| 397 |
+ if err != nil {
|
|
| 398 |
+ logrus.WithError(err).WithField("container", c.ID).Warn("error getting secrets mount path for container")
|
|
| 399 |
+ } |
|
| 400 |
+ if err := mount.RecursiveUnmount(dir); err != nil {
|
|
| 401 |
+ logrus.WithField("dir", dir).WithError(err).Warn("Error while attmepting to unmount dir, this may prevent removal of container.")
|
|
| 402 |
+ } |
|
| 403 |
+ if err := os.RemoveAll(dir); err != nil && !os.IsNotExist(err) {
|
|
| 404 |
+ logrus.WithField("dir", dir).WithError(err).Error("Error removing dir.")
|
|
| 405 |
+ } |
|
| 353 | 406 |
} |
| 354 | 407 |
|
| 355 | 408 |
func killProcessDirectly(cntr *container.Container) error {
|
| ... | ... |
@@ -21,10 +21,7 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
|
| 21 | 21 |
return nil |
| 22 | 22 |
} |
| 23 | 23 |
|
| 24 |
- localPath, err := c.ConfigsDirPath() |
|
| 25 |
- if err != nil {
|
|
| 26 |
- return err |
|
| 27 |
- } |
|
| 24 |
+ localPath := c.ConfigsDirPath() |
|
| 28 | 25 |
logrus.Debugf("configs: setting up config dir: %s", localPath)
|
| 29 | 26 |
|
| 30 | 27 |
// create local config root |
| ... | ... |
@@ -51,11 +48,7 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
|
| 51 | 51 |
continue |
| 52 | 52 |
} |
| 53 | 53 |
|
| 54 |
- fPath, err := c.ConfigFilePath(*configRef.ConfigReference) |
|
| 55 |
- if err != nil {
|
|
| 56 |
- return err |
|
| 57 |
- } |
|
| 58 |
- |
|
| 54 |
+ fPath := c.ConfigFilePath(*configRef) |
|
| 59 | 55 |
log := logrus.WithFields(logrus.Fields{"name": configRef.File.Name, "path": fPath})
|
| 60 | 56 |
|
| 61 | 57 |
log.Debug("injecting config")
|
| ... | ... |
@@ -842,18 +842,9 @@ func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, e |
| 842 | 842 |
return nil, err |
| 843 | 843 |
} |
| 844 | 844 |
|
| 845 |
- secretMountPath, err := c.SecretMountPath() |
|
| 846 |
- if err != nil {
|
|
| 847 |
- return nil, err |
|
| 848 |
- } |
|
| 849 |
- configsMountPath, err := c.ConfigsDirPath() |
|
| 850 |
- if err != nil {
|
|
| 851 |
- return nil, err |
|
| 852 |
- } |
|
| 853 | 845 |
defer func() {
|
| 854 | 846 |
if err != nil {
|
| 855 |
- daemon.cleanupSecretDir(secretMountPath) |
|
| 856 |
- daemon.cleanupSecretDir(configsMountPath) |
|
| 847 |
+ daemon.cleanupSecretDir(c) |
|
| 857 | 848 |
} |
| 858 | 849 |
}() |
| 859 | 850 |
|
| ... | ... |
@@ -861,10 +852,6 @@ func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, e |
| 861 | 861 |
return nil, err |
| 862 | 862 |
} |
| 863 | 863 |
|
| 864 |
- if err := daemon.setupConfigDir(c); err != nil {
|
|
| 865 |
- return nil, err |
|
| 866 |
- } |
|
| 867 |
- |
|
| 868 | 864 |
ms, err := daemon.setupMounts(c) |
| 869 | 865 |
if err != nil {
|
| 870 | 866 |
return nil, err |
| ... | ... |
@@ -886,12 +873,6 @@ func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, e |
| 886 | 886 |
} |
| 887 | 887 |
ms = append(ms, secretMounts...) |
| 888 | 888 |
|
| 889 |
- configMounts, err := c.ConfigMounts() |
|
| 890 |
- if err != nil {
|
|
| 891 |
- return nil, err |
|
| 892 |
- } |
|
| 893 |
- ms = append(ms, configMounts...) |
|
| 894 |
- |
|
| 895 | 889 |
sort.Sort(mounts(ms)) |
| 896 | 890 |
if err := setMounts(daemon, &s, c, ms); err != nil {
|
| 897 | 891 |
return nil, fmt.Errorf("linux mounts: %v", err)
|
| ... | ... |
@@ -102,10 +102,7 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
| 102 | 102 |
mounts = append(mounts, secretMounts...) |
| 103 | 103 |
} |
| 104 | 104 |
|
| 105 |
- configMounts, err := c.ConfigMounts() |
|
| 106 |
- if err != nil {
|
|
| 107 |
- return nil, err |
|
| 108 |
- } |
|
| 105 |
+ configMounts := c.ConfigMounts() |
|
| 109 | 106 |
if configMounts != nil {
|
| 110 | 107 |
mounts = append(mounts, configMounts...) |
| 111 | 108 |
} |
| ... | ... |
@@ -292,15 +292,24 @@ func TestTemplatedConfig(t *testing.T) {
|
| 292 | 292 |
AttachStderr: true, |
| 293 | 293 |
}) |
| 294 | 294 |
|
| 295 |
- buf := bytes.NewBuffer(nil) |
|
| 296 |
- _, err = stdcopy.StdCopy(buf, buf, attach.Reader) |
|
| 297 |
- require.NoError(t, err) |
|
| 298 |
- |
|
| 299 | 295 |
expect := "SERVICE_NAME=svc\n" + |
| 300 | 296 |
"this is a secret\n" + |
| 301 | 297 |
"this is a config\n" |
| 298 |
+ assertAttachedStream(t, attach, expect) |
|
| 299 |
+ |
|
| 300 |
+ attach = swarm.ExecTask(t, d, task, types.ExecConfig{
|
|
| 301 |
+ Cmd: []string{"mount"},
|
|
| 302 |
+ AttachStdout: true, |
|
| 303 |
+ AttachStderr: true, |
|
| 304 |
+ }) |
|
| 305 |
+ assertAttachedStream(t, attach, "tmpfs on /templated_config type tmpfs") |
|
| 306 |
+} |
|
| 302 | 307 |
|
| 303 |
- assert.Equal(t, expect, buf.String()) |
|
| 308 |
+func assertAttachedStream(t *testing.T, attach types.HijackedResponse, expect string) {
|
|
| 309 |
+ buf := bytes.NewBuffer(nil) |
|
| 310 |
+ _, err := stdcopy.StdCopy(buf, buf, attach.Reader) |
|
| 311 |
+ require.NoError(t, err) |
|
| 312 |
+ assert.Contains(t, buf.String(), expect) |
|
| 304 | 313 |
} |
| 305 | 314 |
|
| 306 | 315 |
func waitAndAssert(t *testing.T, timeout time.Duration, f func(*testing.T) bool) {
|
| ... | ... |
@@ -336,15 +336,24 @@ func TestTemplatedSecret(t *testing.T) {
|
| 336 | 336 |
AttachStderr: true, |
| 337 | 337 |
}) |
| 338 | 338 |
|
| 339 |
- buf := bytes.NewBuffer(nil) |
|
| 340 |
- _, err = stdcopy.StdCopy(buf, buf, attach.Reader) |
|
| 341 |
- require.NoError(t, err) |
|
| 342 |
- |
|
| 343 | 339 |
expect := "SERVICE_NAME=svc\n" + |
| 344 | 340 |
"this is a secret\n" + |
| 345 | 341 |
"this is a config\n" |
| 342 |
+ assertAttachedStream(t, attach, expect) |
|
| 343 |
+ |
|
| 344 |
+ attach = swarm.ExecTask(t, d, task, types.ExecConfig{
|
|
| 345 |
+ Cmd: []string{"mount"},
|
|
| 346 |
+ AttachStdout: true, |
|
| 347 |
+ AttachStderr: true, |
|
| 348 |
+ }) |
|
| 349 |
+ assertAttachedStream(t, attach, "tmpfs on /run/secrets/templated_secret type tmpfs") |
|
| 350 |
+} |
|
| 346 | 351 |
|
| 347 |
- assert.Equal(t, expect, buf.String()) |
|
| 352 |
+func assertAttachedStream(t *testing.T, attach types.HijackedResponse, expect string) {
|
|
| 353 |
+ buf := bytes.NewBuffer(nil) |
|
| 354 |
+ _, err := stdcopy.StdCopy(buf, buf, attach.Reader) |
|
| 355 |
+ require.NoError(t, err) |
|
| 356 |
+ assert.Contains(t, buf.String(), expect) |
|
| 348 | 357 |
} |
| 349 | 358 |
|
| 350 | 359 |
func waitAndAssert(t *testing.T, timeout time.Duration, f func(*testing.T) bool) {
|