Merge pull request #33169 from johnstep/windows-configs
Add Windows configs support
This commit is contained in:
commit
7658851e74
5 changed files with 114 additions and 11 deletions
|
@ -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.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// +build !linux
|
// +build !linux,!windows
|
||||||
|
|
||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
|
|
7
daemon/configs_windows.go
Normal file
7
daemon/configs_windows.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package daemon
|
||||||
|
|
||||||
|
func configsSupported() bool {
|
||||||
|
return true
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue