Merge pull request #33169 from johnstep/windows-configs

Add Windows configs support
This commit is contained in:
John Stephens 2017-05-16 16:46:34 -07:00 committed by GitHub
commit 7658851e74
5 changed files with 114 additions and 11 deletions

View file

@ -14,6 +14,7 @@ import (
const ( const (
containerSecretMountPath = `C:\ProgramData\Docker\secrets` containerSecretMountPath = `C:\ProgramData\Docker\secrets`
containerInternalSecretMountPath = `C:\ProgramData\Docker\internal\secrets` containerInternalSecretMountPath = `C:\ProgramData\Docker\internal\secrets`
containerInternalConfigsDirPath = `C:\ProgramData\Docker\internal\configs`
) )
// Container holds fields specific to the Windows implementation. See // Container holds fields specific to the Windows implementation. See
@ -91,6 +92,43 @@ func (container *Container) UnmountSecrets() error {
return os.RemoveAll(container.SecretMountPath()) return os.RemoveAll(container.SecretMountPath())
} }
// CreateConfigSymlinks creates symlinks to files in the config mount.
func (container *Container) CreateConfigSymlinks() error {
for _, configRef := range container.ConfigReferences {
if configRef.File == nil {
continue
}
resolvedPath, _, err := container.ResolvePath(configRef.File.Name)
if err != nil {
return err
}
if err := system.MkdirAll(filepath.Dir(resolvedPath), 0); err != nil {
return err
}
if err := os.Symlink(filepath.Join(containerInternalConfigsDirPath, configRef.ConfigID), resolvedPath); err != nil {
return err
}
}
return nil
}
// ConfigMounts returns the mount for configs.
// All configs are stored in a single mount on Windows. Target symlinks are
// created for each config, pointing to the files in this mount.
func (container *Container) ConfigMounts() []Mount {
var mounts []Mount
if len(container.ConfigReferences) > 0 {
mounts = append(mounts, Mount{
Source: container.ConfigsDirPath(),
Destination: containerInternalConfigsDirPath,
Writable: false,
})
}
return mounts
}
// DetachAndUnmount unmounts all volumes. // DetachAndUnmount unmounts all volumes.
// On Windows it only delegates to `UnmountVolumes` since there is nothing to // On Windows it only delegates to `UnmountVolumes` since there is nothing to
// force unmount. // force unmount.

View file

@ -1,4 +1,4 @@
// +build !linux // +build !linux,!windows
package daemon package daemon

View file

@ -0,0 +1,7 @@
// +build windows
package daemon
func configsSupported() bool {
return true
}

View file

@ -16,6 +16,55 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s
return nil, nil return nil, nil
} }
func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
if len(c.ConfigReferences) == 0 {
return nil
}
localPath := c.ConfigsDirPath()
logrus.Debugf("configs: setting up config dir: %s", localPath)
// create local config root
if err := system.MkdirAllWithACL(localPath, 0); err != nil {
return errors.Wrap(err, "error creating config dir")
}
defer func() {
if setupErr != nil {
if err := os.RemoveAll(localPath); err != nil {
logrus.Errorf("error cleaning up config dir: %s", err)
}
}
}()
if c.DependencyStore == nil {
return fmt.Errorf("config store is not initialized")
}
for _, configRef := range c.ConfigReferences {
// TODO (ehazlett): use type switch when more are supported
if configRef.File == nil {
logrus.Error("config target type is not a file target")
continue
}
fPath := c.ConfigFilePath(*configRef)
log := logrus.WithFields(logrus.Fields{"name": configRef.File.Name, "path": fPath})
log.Debug("injecting config")
config := c.DependencyStore.Configs().Get(configRef.ConfigID)
if config == nil {
return fmt.Errorf("unable to get config from config store")
}
if err := ioutil.WriteFile(fPath, config.Spec.Data, configRef.File.Mode); err != nil {
return errors.Wrap(err, "error injecting config")
}
}
return nil
}
// getSize returns real size & virtual size // getSize returns real size & virtual size
func (daemon *Daemon) getSize(containerID string) (int64, int64) { func (daemon *Daemon) getSize(containerID string) (int64, int64) {
// TODO Windows // TODO Windows

View file

@ -29,6 +29,10 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
return nil, err return nil, err
} }
if err := daemon.setupConfigDir(c); err != nil {
return nil, err
}
// In s.Mounts // In s.Mounts
mounts, err := daemon.setupMounts(c) mounts, err := daemon.setupMounts(c)
if err != nil { if err != nil {
@ -44,24 +48,25 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
isHyperV = c.HostConfig.Isolation.IsHyperV() isHyperV = c.HostConfig.Isolation.IsHyperV()
} }
// If the container has not been started, and has secrets, create symlinks // If the container has not been started, and has configs or secrets
// to each secret. If it has been started before, the symlinks should have // secrets, create symlinks to each confing and secret. If it has been
// already been created. Also, it is important to not mount a Hyper-V // started before, the symlinks should have already been created. Also, it
// container that has been started before, to protect the host from the // is important to not mount a Hyper-V container that has been started
// container; for example, from malicious mutation of NTFS data structures. // before, to protect the host from the container; for example, from
if !c.HasBeenStartedBefore && len(c.SecretReferences) > 0 { // malicious mutation of NTFS data structures.
if !c.HasBeenStartedBefore && (len(c.SecretReferences) > 0 || len(c.ConfigReferences) > 0) {
// The container file system is mounted before this function is called, // The container file system is mounted before this function is called,
// except for Hyper-V containers, so mount it here in that case. // except for Hyper-V containers, so mount it here in that case.
if isHyperV { if isHyperV {
if err := daemon.Mount(c); err != nil { if err := daemon.Mount(c); err != nil {
return nil, err return nil, err
} }
defer daemon.Unmount(c)
} }
err := c.CreateSecretSymlinks() if err := c.CreateSecretSymlinks(); err != nil {
if isHyperV { return nil, err
daemon.Unmount(c)
} }
if err != nil { if err := c.CreateConfigSymlinks(); err != nil {
return nil, err return nil, err
} }
} }
@ -70,6 +75,10 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
mounts = append(mounts, m...) mounts = append(mounts, m...)
} }
if m := c.ConfigMounts(); m != nil {
mounts = append(mounts, m...)
}
for _, mount := range mounts { for _, mount := range mounts {
m := specs.Mount{ m := specs.Mount{
Source: mount.Source, Source: mount.Source,