瀏覽代碼

Add config support to executor backend

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
Aaron Lehmann 8 年之前
父節點
當前提交
9e9fc7b57c

+ 13 - 1
container/container.go

@@ -87,8 +87,9 @@ type CommonContainer struct {
 	MountPoints            map[string]*volume.MountPoint
 	HostConfig             *containertypes.HostConfig `json:"-"` // do not serialize the host config in the json, otherwise we'll make the container unportable
 	ExecCommands           *exec.Store                `json:"-"`
-	SecretStore            agentexec.SecretGetter     `json:"-"`
+	DependencyStore        agentexec.DependencyGetter `json:"-"`
 	SecretReferences       []*swarmtypes.SecretReference
+	ConfigReferences       []*swarmtypes.ConfigReference
 	// logDriver for closing
 	LogDriver      logger.Logger  `json:"-"`
 	LogCopier      *logger.Copier `json:"-"`
@@ -966,3 +967,14 @@ func getSecretTargetPath(r *swarmtypes.SecretReference) string {
 
 	return filepath.Join(containerSecretMountPath, r.File.Name)
 }
+
+// ConfigsDirPath returns the path to the directory where configs are stored on
+// disk.
+func (container *Container) ConfigsDirPath() string {
+	return filepath.Join(container.Root, "configs")
+}
+
+// ConfigFilePath returns the path to the on-disk location of a config.
+func (container *Container) ConfigFilePath(configRef swarmtypes.ConfigReference) string {
+	return filepath.Join(container.ConfigsDirPath(), configRef.ConfigID)
+}

+ 17 - 0
container/container_unix.go

@@ -277,6 +277,23 @@ func (container *Container) UnmountSecrets() error {
 	return detachMounted(container.SecretMountPath())
 }
 
+// ConfigMounts returns the mounts for configs.
+func (container *Container) ConfigMounts() []Mount {
+	var mounts []Mount
+	for _, configRef := range container.ConfigReferences {
+		if configRef.File == nil {
+			continue
+		}
+		mounts = append(mounts, Mount{
+			Source:      container.ConfigFilePath(*configRef),
+			Destination: configRef.File.Name,
+			Writable:    false,
+		})
+	}
+
+	return mounts
+}
+
 // UpdateContainer updates configuration of a container.
 func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfig) error {
 	container.Lock()

+ 2 - 1
daemon/cluster/executor/backend.go

@@ -42,8 +42,9 @@ type Backend interface {
 	ContainerWaitWithContext(ctx context.Context, name string) error
 	ContainerRm(name string, config *types.ContainerRmConfig) error
 	ContainerKill(name string, sig uint64) error
-	SetContainerSecretStore(name string, store exec.SecretGetter) error
+	SetContainerDependencyStore(name string, store exec.DependencyGetter) error
 	SetContainerSecretReferences(name string, refs []*swarmtypes.SecretReference) error
+	SetContainerConfigReferences(name string, refs []*swarmtypes.ConfigReference) error
 	SystemInfo() (*types.Info, error)
 	VolumeCreate(name, driverName string, opts, labels map[string]string) (*types.Volume, error)
 	Containers(config *types.ContainerListOptions) ([]*types.Container, error)

+ 15 - 10
daemon/cluster/executor/container/adapter.go

@@ -33,21 +33,21 @@ import (
 // are mostly naked calls to the client API, seeded with information from
 // containerConfig.
 type containerAdapter struct {
-	backend   executorpkg.Backend
-	container *containerConfig
-	secrets   exec.SecretGetter
+	backend      executorpkg.Backend
+	container    *containerConfig
+	dependencies exec.DependencyGetter
 }
 
-func newContainerAdapter(b executorpkg.Backend, task *api.Task, secrets exec.SecretGetter) (*containerAdapter, error) {
+func newContainerAdapter(b executorpkg.Backend, task *api.Task, dependencies exec.DependencyGetter) (*containerAdapter, error) {
 	ctnr, err := newContainerConfig(task)
 	if err != nil {
 		return nil, err
 	}
 
 	return &containerAdapter{
-		container: ctnr,
-		backend:   b,
-		secrets:   secrets,
+		container:    ctnr,
+		backend:      b,
+		dependencies: dependencies,
 	}, nil
 }
 
@@ -243,13 +243,18 @@ func (c *containerAdapter) create(ctx context.Context) error {
 		return errors.New("unable to get container from task spec")
 	}
 
+	if err := c.backend.SetContainerDependencyStore(cr.ID, c.dependencies); err != nil {
+		return err
+	}
+
 	// configure secrets
-	if err := c.backend.SetContainerSecretStore(cr.ID, c.secrets); err != nil {
+	secretRefs := convert.SecretReferencesFromGRPC(container.Secrets)
+	if err := c.backend.SetContainerSecretReferences(cr.ID, secretRefs); err != nil {
 		return err
 	}
 
-	refs := convert.SecretReferencesFromGRPC(container.Secrets)
-	if err := c.backend.SetContainerSecretReferences(cr.ID, refs); err != nil {
+	configRefs := convert.ConfigReferencesFromGRPC(container.Configs)
+	if err := c.backend.SetContainerConfigReferences(cr.ID, configRefs); err != nil {
 		return err
 	}
 

+ 2 - 2
daemon/cluster/executor/container/attachment.go

@@ -20,8 +20,8 @@ type networkAttacherController struct {
 	closed  chan struct{}
 }
 
-func newNetworkAttacherController(b executorpkg.Backend, task *api.Task, secrets exec.SecretGetter) (*networkAttacherController, error) {
-	adapter, err := newContainerAdapter(b, task, secrets)
+func newNetworkAttacherController(b executorpkg.Backend, task *api.Task, dependencies exec.DependencyGetter) (*networkAttacherController, error) {
+	adapter, err := newContainerAdapter(b, task, dependencies)
 	if err != nil {
 		return nil, err
 	}

+ 2 - 2
daemon/cluster/executor/container/controller.go

@@ -39,8 +39,8 @@ type controller struct {
 var _ exec.Controller = &controller{}
 
 // NewController returns a docker exec runner for the provided task.
-func newController(b executorpkg.Backend, task *api.Task, secrets exec.SecretGetter) (*controller, error) {
-	adapter, err := newContainerAdapter(b, task, secrets)
+func newController(b executorpkg.Backend, task *api.Task, dependencies exec.DependencyGetter) (*controller, error) {
+	adapter, err := newContainerAdapter(b, task, dependencies)
 	if err != nil {
 		return nil, err
 	}

+ 14 - 8
daemon/cluster/executor/container/executor.go

@@ -14,23 +14,23 @@ import (
 	executorpkg "github.com/docker/docker/daemon/cluster/executor"
 	clustertypes "github.com/docker/docker/daemon/cluster/provider"
 	networktypes "github.com/docker/libnetwork/types"
+	"github.com/docker/swarmkit/agent"
 	"github.com/docker/swarmkit/agent/exec"
-	"github.com/docker/swarmkit/agent/secrets"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/api/naming"
 	"golang.org/x/net/context"
 )
 
 type executor struct {
-	backend executorpkg.Backend
-	secrets exec.SecretsManager
+	backend      executorpkg.Backend
+	dependencies exec.DependencyManager
 }
 
 // NewExecutor returns an executor from the docker client.
 func NewExecutor(b executorpkg.Backend) exec.Executor {
 	return &executor{
-		backend: b,
-		secrets: secrets.NewManager(),
+		backend:      b,
+		dependencies: agent.NewDependencyManager(),
 	}
 }
 
@@ -162,8 +162,10 @@ func (e *executor) Configure(ctx context.Context, node *api.Node) error {
 
 // Controller returns a docker container runner.
 func (e *executor) Controller(t *api.Task) (exec.Controller, error) {
+	dependencyGetter := agent.Restrict(e.dependencies, t)
+
 	if t.Spec.GetAttachment() != nil {
-		return newNetworkAttacherController(e.backend, t, e.secrets)
+		return newNetworkAttacherController(e.backend, t, dependencyGetter)
 	}
 
 	var ctlr exec.Controller
@@ -188,7 +190,7 @@ func (e *executor) Controller(t *api.Task) (exec.Controller, error) {
 			return ctlr, fmt.Errorf("unsupported runtime type: %q", r.Generic.Kind)
 		}
 	case *api.TaskSpec_Container:
-		c, err := newController(e.backend, t, secrets.Restrict(e.secrets, t))
+		c, err := newController(e.backend, t, dependencyGetter)
 		if err != nil {
 			return ctlr, err
 		}
@@ -218,7 +220,11 @@ func (e *executor) SetNetworkBootstrapKeys(keys []*api.EncryptionKey) error {
 }
 
 func (e *executor) Secrets() exec.SecretsManager {
-	return e.secrets
+	return e.dependencies.Secrets()
+}
+
+func (e *executor) Configs() exec.ConfigsManager {
+	return e.dependencies.Configs()
 }
 
 type sortedPlugins []api.PluginDescription

+ 23 - 0
daemon/configs.go

@@ -0,0 +1,23 @@
+package daemon
+
+import (
+	"github.com/Sirupsen/logrus"
+	swarmtypes "github.com/docker/docker/api/types/swarm"
+)
+
+// SetContainerConfigReferences sets the container config references needed
+func (daemon *Daemon) SetContainerConfigReferences(name string, refs []*swarmtypes.ConfigReference) error {
+	if !configsSupported() && len(refs) > 0 {
+		logrus.Warn("configs are not supported on this platform")
+		return nil
+	}
+
+	c, err := daemon.GetContainer(name)
+	if err != nil {
+		return err
+	}
+
+	c.ConfigReferences = refs
+
+	return nil
+}

+ 7 - 0
daemon/configs_linux.go

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

+ 7 - 0
daemon/configs_unsupported.go

@@ -0,0 +1,7 @@
+// +build !linux
+
+package daemon
+
+func configsSupported() bool {
+	return false
+}

+ 82 - 12
daemon/container_operations_unix.go

@@ -145,6 +145,13 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
 	localMountPath := c.SecretMountPath()
 	logrus.Debugf("secrets: setting up secret dir: %s", localMountPath)
 
+	// retrieve possible remapped range start for root UID, GID
+	rootUID, rootGID := daemon.GetRemappedUIDGID()
+	// create tmpfs
+	if err := idtools.MkdirAllAs(localMountPath, 0700, rootUID, rootGID); err != nil {
+		return errors.Wrap(err, "error creating secret local mount path")
+	}
+
 	defer func() {
 		if setupErr != nil {
 			// cleanup
@@ -156,25 +163,20 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
 		}
 	}()
 
-	// retrieve possible remapped range start for root UID, GID
-	rootUID, rootGID := daemon.GetRemappedUIDGID()
-	// create tmpfs
-	if err := idtools.MkdirAllAs(localMountPath, 0700, rootUID, rootGID); err != nil {
-		return errors.Wrap(err, "error creating secret local mount path")
-	}
 	tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootUID, rootGID)
 	if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
 		return errors.Wrap(err, "unable to setup secret mount")
 	}
 
-	for _, s := range c.SecretReferences {
-		if c.SecretStore == nil {
-			return fmt.Errorf("secret store is not initialized")
-		}
+	if c.DependencyStore == nil {
+		return fmt.Errorf("secret store is not initialized")
+	}
 
+	for _, s := range c.SecretReferences {
 		// TODO (ehazlett): use type switch when more are supported
 		if s.File == nil {
-			return fmt.Errorf("secret target type is not a file target")
+			logrus.Error("secret target type is not a file target")
+			continue
 		}
 
 		// secrets are created in the SecretMountPath on the host, at a
@@ -188,7 +190,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
 			"name": s.File.Name,
 			"path": fPath,
 		}).Debug("injecting secret")
-		secret := c.SecretStore.Get(s.SecretID)
+		secret := c.DependencyStore.Secrets().Get(s.SecretID)
 		if secret == nil {
 			return fmt.Errorf("unable to get secret from secret store")
 		}
@@ -220,6 +222,74 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
 	return 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)
+
+	// retrieve possible remapped range start for root UID, GID
+	rootUID, rootGID := daemon.GetRemappedUIDGID()
+	// create tmpfs
+	if err := idtools.MkdirAllAs(localPath, 0700, rootUID, rootGID); 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})
+
+		if err := idtools.MkdirAllAs(filepath.Dir(fPath), 0700, rootUID, rootGID); err != nil {
+			return errors.Wrap(err, "error creating config path")
+		}
+
+		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")
+		}
+
+		uid, err := strconv.Atoi(configRef.File.UID)
+		if err != nil {
+			return err
+		}
+		gid, err := strconv.Atoi(configRef.File.GID)
+		if err != nil {
+			return err
+		}
+
+		if err := os.Chown(fPath, rootUID+uid, rootGID+gid); err != nil {
+			return errors.Wrap(err, "error setting ownership for config")
+		}
+	}
+
+	return nil
+}
+
 func killProcessDirectly(container *container.Container) error {
 	if _, err := container.WaitStop(10 * time.Second); err != nil {
 		// Ensure that we don't kill ourselves

+ 17 - 0
daemon/dependency.go

@@ -0,0 +1,17 @@
+package daemon
+
+import (
+	"github.com/docker/swarmkit/agent/exec"
+)
+
+// SetContainerDependencyStore sets the dependency store backend for the container
+func (daemon *Daemon) SetContainerDependencyStore(name string, store exec.DependencyGetter) error {
+	c, err := daemon.GetContainer(name)
+	if err != nil {
+		return err
+	}
+
+	c.DependencyStore = store
+
+	return nil
+}

+ 6 - 0
daemon/oci_linux.go

@@ -737,6 +737,10 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
 		return nil, err
 	}
 
+	if err := daemon.setupConfigDir(c); err != nil {
+		return nil, err
+	}
+
 	ms, err := daemon.setupMounts(c)
 	if err != nil {
 		return nil, err
@@ -754,6 +758,8 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
 		ms = append(ms, m...)
 	}
 
+	ms = append(ms, c.ConfigMounts()...)
+
 	sort.Sort(mounts(ms))
 	if err := setMounts(daemon, &s, c, ms); err != nil {
 		return nil, fmt.Errorf("linux mounts: %v", err)

+ 0 - 13
daemon/secrets.go

@@ -3,21 +3,8 @@ package daemon
 import (
 	"github.com/Sirupsen/logrus"
 	swarmtypes "github.com/docker/docker/api/types/swarm"
-	"github.com/docker/swarmkit/agent/exec"
 )
 
-// SetContainerSecretStore sets the secret store backend for the container
-func (daemon *Daemon) SetContainerSecretStore(name string, store exec.SecretGetter) error {
-	c, err := daemon.GetContainer(name)
-	if err != nil {
-		return err
-	}
-
-	c.SecretStore = store
-
-	return nil
-}
-
 // SetContainerSecretReferences sets the container secret references needed
 func (daemon *Daemon) SetContainerSecretReferences(name string, refs []*swarmtypes.SecretReference) error {
 	if !secretsSupported() && len(refs) > 0 {