Ver Fonte

Merge pull request #32392 from aluzzardi/revendor-swarmkit

[master] Re-vendor docker/swarmkit to d2e48a332063ccd4ea26b6262ee717de997de560
Akihiro Suda há 8 anos atrás
pai
commit
2aed764baf
45 ficheiros alterados com 5014 adições e 1359 exclusões
  1. 1 1
      daemon/cluster/convert/container.go
  2. 1 1
      vendor.conf
  3. 85 52
      vendor/github.com/docker/swarmkit/agent/agent.go
  4. 19 1
      vendor/github.com/docker/swarmkit/agent/config.go
  5. 87 0
      vendor/github.com/docker/swarmkit/agent/configs/configs.go
  6. 52 0
      vendor/github.com/docker/swarmkit/agent/dependency.go
  7. 36 0
      vendor/github.com/docker/swarmkit/agent/exec/executor.go
  8. 67 10
      vendor/github.com/docker/swarmkit/agent/worker.go
  9. 1008 228
      vendor/github.com/docker/swarmkit/api/control.pb.go
  10. 115 3
      vendor/github.com/docker/swarmkit/api/control.proto
  11. 17 1
      vendor/github.com/docker/swarmkit/api/defaults/service.go
  12. 215 63
      vendor/github.com/docker/swarmkit/api/dispatcher.pb.go
  13. 4 0
      vendor/github.com/docker/swarmkit/api/dispatcher.proto
  14. 589 102
      vendor/github.com/docker/swarmkit/api/objects.pb.go
  15. 24 3
      vendor/github.com/docker/swarmkit/api/objects.proto
  16. 163 60
      vendor/github.com/docker/swarmkit/api/raft.pb.go
  17. 1 0
      vendor/github.com/docker/swarmkit/api/raft.proto
  18. 90 30
      vendor/github.com/docker/swarmkit/api/snapshot.pb.go
  19. 1 0
      vendor/github.com/docker/swarmkit/api/snapshot.proto
  20. 458 137
      vendor/github.com/docker/swarmkit/api/specs.pb.go
  21. 17 0
      vendor/github.com/docker/swarmkit/api/specs.proto
  22. 280 88
      vendor/github.com/docker/swarmkit/api/store.pb.go
  23. 2 0
      vendor/github.com/docker/swarmkit/api/store.proto
  24. 398 77
      vendor/github.com/docker/swarmkit/api/types.pb.go
  25. 62 12
      vendor/github.com/docker/swarmkit/api/types.proto
  26. 78 35
      vendor/github.com/docker/swarmkit/ca/certificates.go
  27. 88 57
      vendor/github.com/docker/swarmkit/ca/config.go
  28. 10 1
      vendor/github.com/docker/swarmkit/ca/server.go
  29. 77 62
      vendor/github.com/docker/swarmkit/manager/controlapi/ca_rotation.go
  30. 1 1
      vendor/github.com/docker/swarmkit/manager/controlapi/cluster.go
  31. 16 2
      vendor/github.com/docker/swarmkit/manager/controlapi/common.go
  32. 248 0
      vendor/github.com/docker/swarmkit/manager/controlapi/config.go
  33. 1 17
      vendor/github.com/docker/swarmkit/manager/controlapi/secret.go
  34. 87 2
      vendor/github.com/docker/swarmkit/manager/controlapi/service.go
  35. 247 0
      vendor/github.com/docker/swarmkit/manager/dispatcher/assignments.go
  36. 61 255
      vendor/github.com/docker/swarmkit/manager/dispatcher/dispatcher.go
  37. 4 1
      vendor/github.com/docker/swarmkit/manager/manager.go
  38. 2 1
      vendor/github.com/docker/swarmkit/manager/orchestrator/task.go
  39. 21 27
      vendor/github.com/docker/swarmkit/manager/orchestrator/update/updater.go
  40. 11 0
      vendor/github.com/docker/swarmkit/manager/state/store/by.go
  41. 132 0
      vendor/github.com/docker/swarmkit/manager/state/store/configs.go
  42. 7 0
      vendor/github.com/docker/swarmkit/manager/state/store/memory.go
  43. 33 1
      vendor/github.com/docker/swarmkit/manager/state/store/services.go
  44. 33 1
      vendor/github.com/docker/swarmkit/manager/state/store/tasks.go
  45. 65 27
      vendor/github.com/docker/swarmkit/node/node.go

+ 1 - 1
daemon/cluster/convert/container.go

@@ -97,7 +97,7 @@ func secretReferencesToGRPC(sr []*types.SecretReference) []*swarmapi.SecretRefer
 		}
 		if s.File != nil {
 			ref.Target = &swarmapi.SecretReference_File{
-				File: &swarmapi.SecretReference_FileTarget{
+				File: &swarmapi.FileTarget{
 					Name: s.File.Name,
 					UID:  s.File.UID,
 					GID:  s.File.GID,

+ 1 - 1
vendor.conf

@@ -105,7 +105,7 @@ github.com/docker/containerd 9048e5e50717ea4497b757314bad98ea3763c145
 github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4
 
 # cluster
-github.com/docker/swarmkit b74ec2b81bb1d4a998f461bb2dc59b9408b7790f
+github.com/docker/swarmkit d2e48a332063ccd4ea26b6262ee717de997de560
 github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9
 github.com/gogo/protobuf 8d70fb3182befc465c4a1eac8ad4d38ff49778e2
 github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a

+ 85 - 52
vendor/github.com/docker/swarmkit/agent/agent.go

@@ -1,6 +1,7 @@
 package agent
 
 import (
+	"bytes"
 	"fmt"
 	"math/rand"
 	"reflect"
@@ -44,6 +45,8 @@ type Agent struct {
 	stopOnce  sync.Once     // only allow stop to be called once
 	closed    chan struct{} // only closed in run
 	err       error         // read only after closed is closed
+
+	nodeUpdatePeriod time.Duration
 }
 
 // New returns a new agent, ready for task dispatch.
@@ -53,14 +56,15 @@ func New(config *Config) (*Agent, error) {
 	}
 
 	a := &Agent{
-		config:   config,
-		sessionq: make(chan sessionOperation),
-		started:  make(chan struct{}),
-		leaving:  make(chan struct{}),
-		left:     make(chan struct{}),
-		stopped:  make(chan struct{}),
-		closed:   make(chan struct{}),
-		ready:    make(chan struct{}),
+		config:           config,
+		sessionq:         make(chan sessionOperation),
+		started:          make(chan struct{}),
+		leaving:          make(chan struct{}),
+		left:             make(chan struct{}),
+		stopped:          make(chan struct{}),
+		closed:           make(chan struct{}),
+		ready:            make(chan struct{}),
+		nodeUpdatePeriod: nodeUpdatePeriod,
 	}
 
 	a.worker = newWorker(config.DB, config.Executor, a)
@@ -182,13 +186,15 @@ func (a *Agent) run(ctx context.Context) {
 	log.G(ctx).Debug("(*Agent).run")
 	defer log.G(ctx).Debug("(*Agent).run exited")
 
+	nodeTLSInfo := a.config.NodeTLSInfo
+
 	// get the node description
-	nodeDescription, err := a.nodeDescriptionWithHostname(ctx)
+	nodeDescription, err := a.nodeDescriptionWithHostname(ctx, nodeTLSInfo)
 	if err != nil {
 		log.G(ctx).WithError(err).WithField("agent", a.config.Executor).Error("agent: node description unavailable")
 	}
 	// nodeUpdateTicker is used to periodically check for updates to node description
-	nodeUpdateTicker := time.NewTicker(nodeUpdatePeriod)
+	nodeUpdateTicker := time.NewTicker(a.nodeUpdatePeriod)
 	defer nodeUpdateTicker.Stop()
 
 	var (
@@ -214,6 +220,35 @@ func (a *Agent) run(ctx context.Context) {
 
 	a.worker.Listen(ctx, reporter)
 
+	updateNode := func() {
+		// skip updating if the registration isn't finished
+		if registered != nil {
+			return
+		}
+		// get the current node description
+		newNodeDescription, err := a.nodeDescriptionWithHostname(ctx, nodeTLSInfo)
+		if err != nil {
+			log.G(ctx).WithError(err).WithField("agent", a.config.Executor).Error("agent: updated node description unavailable")
+		}
+
+		// if newNodeDescription is nil, it will cause a panic when
+		// trying to create a session. Typically this can happen
+		// if the engine goes down
+		if newNodeDescription == nil {
+			return
+		}
+
+		// if the node description has changed, update it to the new one
+		// and close the session. The old session will be stopped and a
+		// new one will be created with the updated description
+		if !reflect.DeepEqual(nodeDescription, newNodeDescription) {
+			nodeDescription = newNodeDescription
+			// close the session
+			log.G(ctx).Info("agent: found node update")
+			session.sendError(nil)
+		}
+	}
+
 	for {
 		select {
 		case operation := <-sessionq:
@@ -237,7 +272,8 @@ func (a *Agent) run(ctx context.Context) {
 
 			switch msg.Type {
 			case api.AssignmentsMessage_COMPLETE:
-				// Need to assign secrets before tasks, because tasks might depend on new secrets
+				// Need to assign secrets and configs before tasks,
+				// because tasks might depend on new secrets or configs
 				if err := a.worker.Assign(ctx, msg.Changes); err != nil {
 					log.G(ctx).WithError(err).Error("failed to synchronize worker assignments")
 				}
@@ -247,7 +283,7 @@ func (a *Agent) run(ctx context.Context) {
 				}
 			}
 		case msg := <-session.messages:
-			if err := a.handleSessionMessage(ctx, msg); err != nil {
+			if err := a.handleSessionMessage(ctx, msg, nodeTLSInfo); err != nil {
 				log.G(ctx).WithError(err).Error("session message handler failed")
 			}
 		case sub := <-session.subscriptions:
@@ -305,33 +341,17 @@ func (a *Agent) run(ctx context.Context) {
 			}
 			session = newSession(ctx, a, delay, session.sessionID, nodeDescription)
 			registered = session.registered
-		case <-nodeUpdateTicker.C:
-			// skip this case if the registration isn't finished
-			if registered != nil {
-				continue
-			}
-			// get the current node description
-			newNodeDescription, err := a.nodeDescriptionWithHostname(ctx)
-			if err != nil {
-				log.G(ctx).WithError(err).WithField("agent", a.config.Executor).Error("agent: updated node description unavailable")
-			}
-
-			// if newNodeDescription is nil, it will cause a panic when
-			// trying to create a session. Typically this can happen
-			// if the engine goes down
-			if newNodeDescription == nil {
-				continue
-			}
-
-			// if the node description has changed, update it to the new one
-			// and close the session. The old session will be stopped and a
-			// new one will be created with the updated description
-			if !reflect.DeepEqual(nodeDescription, newNodeDescription) {
-				nodeDescription = newNodeDescription
-				// close the session
-				log.G(ctx).Info("agent: found node update")
-				session.sendError(nil)
+		case ev := <-a.config.NotifyTLSChange:
+			// the TLS info has changed, so force a check to see if we need to restart the session
+			if tlsInfo, ok := ev.(*api.NodeTLSInfo); ok {
+				nodeTLSInfo = tlsInfo
+				updateNode()
+				nodeUpdateTicker.Stop()
+				nodeUpdateTicker = time.NewTicker(a.nodeUpdatePeriod)
 			}
+		case <-nodeUpdateTicker.C:
+			// periodically check to see whether the node information has changed, and if so, restart the session
+			updateNode()
 		case <-a.stopped:
 			// TODO(stevvooe): Wait on shutdown and cleanup. May need to pump
 			// this loop a few times.
@@ -347,7 +367,7 @@ func (a *Agent) run(ctx context.Context) {
 	}
 }
 
-func (a *Agent) handleSessionMessage(ctx context.Context, message *api.SessionMessage) error {
+func (a *Agent) handleSessionMessage(ctx context.Context, message *api.SessionMessage, nti *api.NodeTLSInfo) error {
 	seen := map[api.Peer]struct{}{}
 	for _, manager := range message.Managers {
 		if manager.Peer.Addr == "" {
@@ -358,18 +378,28 @@ func (a *Agent) handleSessionMessage(ctx context.Context, message *api.SessionMe
 		seen[*manager.Peer] = struct{}{}
 	}
 
-	if message.Node != nil {
-		if a.node == nil || !nodesEqual(a.node, message.Node) {
-			if a.config.NotifyNodeChange != nil {
-				a.config.NotifyNodeChange <- message.Node.Copy()
-			}
-			a.node = message.Node.Copy()
-			if err := a.config.Executor.Configure(ctx, a.node); err != nil {
-				log.G(ctx).WithError(err).Error("node configure failed")
-			}
+	var changes *NodeChanges
+	if message.Node != nil && (a.node == nil || !nodesEqual(a.node, message.Node)) {
+		if a.config.NotifyNodeChange != nil {
+			changes = &NodeChanges{Node: message.Node.Copy()}
+		}
+		a.node = message.Node.Copy()
+		if err := a.config.Executor.Configure(ctx, a.node); err != nil {
+			log.G(ctx).WithError(err).Error("node configure failed")
+		}
+	}
+	if len(message.RootCA) > 0 && !bytes.Equal(message.RootCA, nti.TrustRoot) {
+		if changes == nil {
+			changes = &NodeChanges{RootCert: message.RootCA}
+		} else {
+			changes.RootCert = message.RootCA
 		}
 	}
 
+	if changes != nil {
+		a.config.NotifyNodeChange <- changes
+	}
+
 	// prune managers not in list.
 	for peer := range a.config.ConnBroker.Remotes().Weights() {
 		if _, ok := seen[peer]; !ok {
@@ -517,12 +547,15 @@ func (a *Agent) Publisher(ctx context.Context, subscriptionID string) (exec.LogP
 }
 
 // nodeDescriptionWithHostname retrieves node description, and overrides hostname if available
-func (a *Agent) nodeDescriptionWithHostname(ctx context.Context) (*api.NodeDescription, error) {
+func (a *Agent) nodeDescriptionWithHostname(ctx context.Context, tlsInfo *api.NodeTLSInfo) (*api.NodeDescription, error) {
 	desc, err := a.config.Executor.Describe(ctx)
 
-	// Override hostname
-	if a.config.Hostname != "" && desc != nil {
-		desc.Hostname = a.config.Hostname
+	// Override hostname and TLS info
+	if desc != nil {
+		if a.config.Hostname != "" && desc != nil {
+			desc.Hostname = a.config.Hostname
+		}
+		desc.TLSInfo = tlsInfo
 	}
 	return desc, err
 }

+ 19 - 1
vendor/github.com/docker/swarmkit/agent/config.go

@@ -2,6 +2,7 @@ package agent
 
 import (
 	"github.com/boltdb/bolt"
+	"github.com/docker/go-events"
 	"github.com/docker/swarmkit/agent/exec"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/connectionbroker"
@@ -9,6 +10,13 @@ import (
 	"google.golang.org/grpc/credentials"
 )
 
+// NodeChanges encapsulates changes that should be made to the node as per session messages
+// from the dispatcher
+type NodeChanges struct {
+	Node     *api.Node
+	RootCert []byte
+}
+
 // Config provides values for an Agent.
 type Config struct {
 	// Hostname the name of host for agent instance.
@@ -25,10 +33,16 @@ type Config struct {
 	DB *bolt.DB
 
 	// NotifyNodeChange channel receives new node changes from session messages.
-	NotifyNodeChange chan<- *api.Node
+	NotifyNodeChange chan<- *NodeChanges
+
+	// NotifyTLSChange channel sends new TLS information changes, which can cause a session to restart
+	NotifyTLSChange <-chan events.Event
 
 	// Credentials is credentials for grpc connection to manager.
 	Credentials credentials.TransportCredentials
+
+	// NodeTLSInfo contains the starting node TLS info to bootstrap into the agent
+	NodeTLSInfo *api.NodeTLSInfo
 }
 
 func (c *Config) validate() error {
@@ -44,5 +58,9 @@ func (c *Config) validate() error {
 		return errors.New("agent: database required")
 	}
 
+	if c.NodeTLSInfo == nil {
+		return errors.New("agent: Node TLS info is required")
+	}
+
 	return nil
 }

+ 87 - 0
vendor/github.com/docker/swarmkit/agent/configs/configs.go

@@ -0,0 +1,87 @@
+package configs
+
+import (
+	"sync"
+
+	"github.com/docker/swarmkit/agent/exec"
+	"github.com/docker/swarmkit/api"
+)
+
+// configs is a map that keeps all the currently available configs to the agent
+// mapped by config ID.
+type configs struct {
+	mu sync.RWMutex
+	m  map[string]*api.Config
+}
+
+// NewManager returns a place to store configs.
+func NewManager() exec.ConfigsManager {
+	return &configs{
+		m: make(map[string]*api.Config),
+	}
+}
+
+// Get returns a config by ID.  If the config doesn't exist, returns nil.
+func (r *configs) Get(configID string) *api.Config {
+	r.mu.RLock()
+	defer r.mu.RUnlock()
+	if r, ok := r.m[configID]; ok {
+		return r
+	}
+	return nil
+}
+
+// Add adds one or more configs to the config map.
+func (r *configs) Add(configs ...api.Config) {
+	r.mu.Lock()
+	defer r.mu.Unlock()
+	for _, config := range configs {
+		r.m[config.ID] = config.Copy()
+	}
+}
+
+// Remove removes one or more configs by ID from the config map. Succeeds
+// whether or not the given IDs are in the map.
+func (r *configs) Remove(configs []string) {
+	r.mu.Lock()
+	defer r.mu.Unlock()
+	for _, config := range configs {
+		delete(r.m, config)
+	}
+}
+
+// Reset removes all the configs.
+func (r *configs) Reset() {
+	r.mu.Lock()
+	defer r.mu.Unlock()
+	r.m = make(map[string]*api.Config)
+}
+
+// taskRestrictedConfigsProvider restricts the ids to the task.
+type taskRestrictedConfigsProvider struct {
+	configs   exec.ConfigGetter
+	configIDs map[string]struct{} // allow list of config ids
+}
+
+func (sp *taskRestrictedConfigsProvider) Get(configID string) *api.Config {
+	if _, ok := sp.configIDs[configID]; !ok {
+		return nil
+	}
+
+	return sp.configs.Get(configID)
+}
+
+// Restrict provides a getter that only allows access to the configs
+// referenced by the task.
+func Restrict(configs exec.ConfigGetter, t *api.Task) exec.ConfigGetter {
+	cids := map[string]struct{}{}
+
+	container := t.Spec.GetContainer()
+	if container != nil {
+		for _, configRef := range container.Configs {
+			cids[configRef.ConfigID] = struct{}{}
+		}
+	}
+
+	return &taskRestrictedConfigsProvider{configs: configs, configIDs: cids}
+}

+ 52 - 0
vendor/github.com/docker/swarmkit/agent/dependency.go

@@ -0,0 +1,52 @@
+package agent
+
+import (
+	"github.com/docker/swarmkit/agent/configs"
+	"github.com/docker/swarmkit/agent/exec"
+	"github.com/docker/swarmkit/agent/secrets"
+	"github.com/docker/swarmkit/api"
+)
+
+type dependencyManager struct {
+	secrets exec.SecretsManager
+	configs exec.ConfigsManager
+}
+
+// NewDependencyManager creates a dependency manager object that wraps
+// objects which provide access to various dependency types.
+func NewDependencyManager() exec.DependencyManager {
+	return &dependencyManager{
+		secrets: secrets.NewManager(),
+		configs: configs.NewManager(),
+	}
+}
+
+func (d *dependencyManager) Secrets() exec.SecretsManager {
+	return d.secrets
+}
+
+func (d *dependencyManager) Configs() exec.ConfigsManager {
+	return d.configs
+}
+
+type dependencyGetter struct {
+	secrets exec.SecretGetter
+	configs exec.ConfigGetter
+}
+
+func (d *dependencyGetter) Secrets() exec.SecretGetter {
+	return d.secrets
+}
+
+func (d *dependencyGetter) Configs() exec.ConfigGetter {
+	return d.configs
+}
+
+// Restrict provides getters that only allows access to the dependencies
+// referenced by the task.
+func Restrict(dependencies exec.DependencyManager, t *api.Task) exec.DependencyGetter {
+	return &dependencyGetter{
+		secrets: secrets.Restrict(dependencies.Secrets(), t),
+		configs: configs.Restrict(dependencies.Configs(), t),
+	}
+}

+ 36 - 0
vendor/github.com/docker/swarmkit/agent/exec/executor.go

@@ -28,6 +28,26 @@ type SecretsProvider interface {
 	Secrets() SecretsManager
 }
 
+// ConfigsProvider is implemented by objects that can store configs,
+// typically an executor.
+type ConfigsProvider interface {
+	Configs() ConfigsManager
+}
+
+// DependencyManager is a meta-object that can keep track of typed objects
+// such as secrets and configs.
+type DependencyManager interface {
+	SecretsProvider
+	ConfigsProvider
+}
+
+// DependencyGetter is a meta-object that can provide access to typed objects
+// such as secrets and configs.
+type DependencyGetter interface {
+	Secrets() SecretGetter
+	Configs() ConfigGetter
+}
+
 // SecretGetter contains secret data necessary for the Controller.
 type SecretGetter interface {
 	// Get returns the the secret with a specific secret ID, if available.
@@ -43,3 +63,19 @@ type SecretsManager interface {
 	Remove(secrets []string)   // remove the secrets by ID
 	Reset()                    // remove all secrets
 }
+
+// ConfigGetter contains config data necessary for the Controller.
+type ConfigGetter interface {
+	// Get returns the the config with a specific config ID, if available.
+	// When the config is not available, the return will be nil.
+	Get(configID string) *api.Config
+}
+
+// ConfigsManager is the interface for config storage and updates.
+type ConfigsManager interface {
+	ConfigGetter
+
+	Add(configs ...api.Config) // add one or more configs
+	Remove(configs []string)   // remove the configs by ID
+	Reset()                    // remove all configs
+}

+ 67 - 10
vendor/github.com/docker/swarmkit/agent/worker.go

@@ -23,12 +23,13 @@ type Worker interface {
 	// It is not safe to call any worker function after that.
 	Close()
 
-	// Assign assigns a complete set of tasks and secrets to a worker. Any task or secrets not included in
-	// this set will be removed.
+	// Assign assigns a complete set of tasks and configs/secrets to a
+	// worker. Any items not included in this set will be removed.
 	Assign(ctx context.Context, assignments []*api.AssignmentChange) error
 
-	// Updates updates an incremental set of tasks or secrets of the worker. Any task/secret not included
-	// either in added or removed will remain untouched.
+	// Updates updates an incremental set of tasks or configs/secrets of
+	// the worker. Any items not included either in added or removed will
+	// remain untouched.
 	Update(ctx context.Context, assignments []*api.AssignmentChange) error
 
 	// Listen to updates about tasks controlled by the worker. When first
@@ -119,11 +120,11 @@ func (w *worker) Close() {
 	w.taskevents.Close()
 }
 
-// Assign assigns a full set of tasks and secrets to the worker.
+// Assign assigns a full set of tasks, configs, and secrets to the worker.
 // Any tasks not previously known will be started. Any tasks that are in the task set
 // and already running will be updated, if possible. Any tasks currently running on
 // the worker outside the task set will be terminated.
-// Any secrets not in the set of assignments will be removed.
+// Anything not in the set of assignments will be removed.
 func (w *worker) Assign(ctx context.Context, assignments []*api.AssignmentChange) error {
 	w.mu.Lock()
 	defer w.mu.Unlock()
@@ -136,20 +137,28 @@ func (w *worker) Assign(ctx context.Context, assignments []*api.AssignmentChange
 		"len(assignments)": len(assignments),
 	}).Debug("(*worker).Assign")
 
-	// Need to update secrets before tasks, because tasks might depend on new secrets
+	// Need to update dependencies before tasks
+
 	err := reconcileSecrets(ctx, w, assignments, true)
 	if err != nil {
 		return err
 	}
 
+	err = reconcileConfigs(ctx, w, assignments, true)
+	if err != nil {
+		return err
+	}
+
 	return reconcileTaskState(ctx, w, assignments, true)
 }
 
-// Update updates the set of tasks and secret for the worker.
+// Update updates the set of tasks, configs, and secrets for the worker.
 // Tasks in the added set will be added to the worker, and tasks in the removed set
 // will be removed from the worker
 // Secrets in the added set will be added to the worker, and secrets in the removed set
 // will be removed from the worker.
+// Configs in the added set will be added to the worker, and configs in the removed set
+// will be removed from the worker.
 func (w *worker) Update(ctx context.Context, assignments []*api.AssignmentChange) error {
 	w.mu.Lock()
 	defer w.mu.Unlock()
@@ -167,6 +176,11 @@ func (w *worker) Update(ctx context.Context, assignments []*api.AssignmentChange
 		return err
 	}
 
+	err = reconcileConfigs(ctx, w, assignments, false)
+	if err != nil {
+		return err
+	}
+
 	return reconcileTaskState(ctx, w, assignments, false)
 }
 
@@ -318,7 +332,7 @@ func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.Assignm
 		}
 	}
 
-	provider, ok := w.executor.(exec.SecretsProvider)
+	secretsProvider, ok := w.executor.(exec.SecretsProvider)
 	if !ok {
 		if len(updatedSecrets) != 0 || len(removedSecrets) != 0 {
 			log.G(ctx).Warn("secrets update ignored; executor does not support secrets")
@@ -326,7 +340,7 @@ func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.Assignm
 		return nil
 	}
 
-	secrets := provider.Secrets()
+	secrets := secretsProvider.Secrets()
 
 	log.G(ctx).WithFields(logrus.Fields{
 		"len(updatedSecrets)": len(updatedSecrets),
@@ -344,6 +358,49 @@ func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.Assignm
 	return nil
 }
 
+func reconcileConfigs(ctx context.Context, w *worker, assignments []*api.AssignmentChange, fullSnapshot bool) error {
+	var (
+		updatedConfigs []api.Config
+		removedConfigs []string
+	)
+	for _, a := range assignments {
+		if r := a.Assignment.GetConfig(); r != nil {
+			switch a.Action {
+			case api.AssignmentChange_AssignmentActionUpdate:
+				updatedConfigs = append(updatedConfigs, *r)
+			case api.AssignmentChange_AssignmentActionRemove:
+				removedConfigs = append(removedConfigs, r.ID)
+			}
+
+		}
+	}
+
+	configsProvider, ok := w.executor.(exec.ConfigsProvider)
+	if !ok {
+		if len(updatedConfigs) != 0 || len(removedConfigs) != 0 {
+			log.G(ctx).Warn("configs update ignored; executor does not support configs")
+		}
+		return nil
+	}
+
+	configs := configsProvider.Configs()
+
+	log.G(ctx).WithFields(logrus.Fields{
+		"len(updatedConfigs)": len(updatedConfigs),
+		"len(removedConfigs)": len(removedConfigs),
+	}).Debug("(*worker).reconcileConfigs")
+
+	// If this was a complete set of configs, we're going to clear the configs map and add all of them
+	if fullSnapshot {
+		configs.Reset()
+	} else {
+		configs.Remove(removedConfigs)
+	}
+	configs.Add(updatedConfigs...)
+
+	return nil
+}
+
 func (w *worker) Listen(ctx context.Context, reporter StatusReporter) {
 	w.mu.Lock()
 	defer w.mu.Unlock()

Diff do ficheiro suprimidas por serem muito extensas
+ 1008 - 228
vendor/github.com/docker/swarmkit/api/control.pb.go


+ 115 - 3
vendor/github.com/docker/swarmkit/api/control.proto

@@ -92,7 +92,7 @@ service Control {
 		option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-manager" };
 	};
 
-	// ListSecrets returns a `ListSecretResponse` with a list all non-internal `Secret`s being
+	// ListSecrets returns a `ListSecretResponse` with a list of all non-internal `Secret`s being
 	// managed, or all secrets matching any name in `ListSecretsRequest.Names`, any
 	// name prefix in `ListSecretsRequest.NamePrefixes`, any id in
 	// `ListSecretsRequest.SecretIDs`, or any id prefix in `ListSecretsRequest.IDPrefixes`.
@@ -116,6 +116,51 @@ service Control {
 	rpc RemoveSecret(RemoveSecretRequest) returns (RemoveSecretResponse) {
 		option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-manager" };
 	}
+
+	// --- config APIs ---
+
+	// GetConfig returns a `GetConfigResponse` with a `Config` with the same
+	// id as `GetConfigRequest.ConfigID`
+	// - Returns `NotFound` if the Config with the given id is not found.
+	// - Returns `InvalidArgument` if the `GetConfigRequest.ConfigID` is empty.
+	// - Returns an error if getting fails.
+	rpc GetConfig(GetConfigRequest) returns (GetConfigResponse) {
+		option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-manager" };
+	}
+
+	// UpdateConfig returns a `UpdateConfigResponse` with a `Config` with the same
+	// id as `GetConfigRequest.ConfigID`
+	// - Returns `NotFound` if the Config with the given id is not found.
+	// - Returns `InvalidArgument` if the `GetConfigRequest.ConfigID` is empty.
+	// - Returns an error if updating fails.
+	rpc UpdateConfig(UpdateConfigRequest) returns (UpdateConfigResponse) {
+		option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-manager" };
+	};
+
+	// ListConfigs returns a `ListConfigResponse` with a list of `Config`s being
+	// managed, or all configs matching any name in `ListConfigsRequest.Names`, any
+	// name prefix in `ListConfigsRequest.NamePrefixes`, any id in
+	// `ListConfigsRequest.ConfigIDs`, or any id prefix in `ListConfigsRequest.IDPrefixes`.
+	// - Returns an error if listing fails.
+	rpc ListConfigs(ListConfigsRequest) returns (ListConfigsResponse) {
+		option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-manager" };
+	}
+	// CreateConfig creates and return a `CreateConfigResponse` with a `Config` based
+	// on the provided `CreateConfigRequest.ConfigSpec`.
+	// - Returns `InvalidArgument` if the `CreateConfigRequest.ConfigSpec` is malformed,
+	//   or if the config data is too long or contains invalid characters.
+	// - Returns an error if the creation fails.
+	rpc CreateConfig(CreateConfigRequest) returns (CreateConfigResponse) {
+		option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-manager" };
+	}
+
+	// RemoveConfig removes the config referenced by `RemoveConfigRequest.ID`.
+	// - Returns `InvalidArgument` if `RemoveConfigRequest.ID` is empty.
+	// - Returns `NotFound` if the a config named `RemoveConfigRequest.ID` is not found.
+	// - Returns an error if the deletion fails.
+	rpc RemoveConfig(RemoveConfigRequest) returns (RemoveConfigResponse) {
+		option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-manager" };
+	}
 }
 
 message GetNodeRequest {
@@ -396,7 +441,6 @@ message UpdateSecretResponse {
 	Secret secret = 1;
 }
 
-
 // ListSecretRequest is the request to list all non-internal secrets in the secret store,
 // or all secrets filtered by (name or name prefix or id prefix) and labels.
 message ListSecretsRequest {
@@ -424,7 +468,7 @@ message CreateSecretRequest {
 	SecretSpec spec = 1;
 }
 
-// CreateSecretResponse contains the newly created `Secret`` corresponding to the
+// CreateSecretResponse contains the newly created `Secret` corresponding to the
 // name in `CreateSecretRequest`.  The `Secret.Spec.Data` field should be nil instead
 // of actually containing the secret bytes.
 message CreateSecretResponse {
@@ -440,3 +484,71 @@ message RemoveSecretRequest {
 // RemoveSecretResponse is an empty object indicating the successful removal of
 // a secret.
 message RemoveSecretResponse {}
+
+// GetConfigRequest is the request to get a `Config` object given a config id.
+message GetConfigRequest {
+	string config_id = 1;
+}
+
+// GetConfigResponse contains the Config corresponding to the id in
+// `GetConfigRequest`.
+message GetConfigResponse {
+	Config config = 1;
+}
+
+message UpdateConfigRequest {
+	// ConfigID is the config ID to update.
+	string config_id = 1;
+
+	// ConfigVersion is the version of the config being updated.
+	Version config_version = 2;
+
+	// Spec is the new spec to apply to the Config
+	// Only some fields are allowed to be updated.
+	ConfigSpec spec = 3;
+}
+
+message UpdateConfigResponse {
+	Config config = 1;
+}
+
+// ListConfigRequest is the request to list all configs in the config store,
+// or all configs filtered by (name or name prefix or id prefix) and labels.
+message ListConfigsRequest {
+	message Filters {
+		repeated string names = 1;
+		repeated string id_prefixes = 2;
+		map<string, string> labels = 3;
+		repeated string name_prefixes = 4;
+	}
+
+	Filters filters = 1;
+}
+
+// ListConfigResponse contains a list of all the configs that match the name or
+// name prefix filters provided in `ListConfigRequest`.
+message ListConfigsResponse {
+	repeated Config configs = 1;
+}
+
+// CreateConfigRequest specifies a new config (it will not update an existing
+// config) to create.
+message CreateConfigRequest {
+	ConfigSpec spec = 1;
+}
+
+// CreateConfigResponse contains the newly created `Config` corresponding to the
+// name in `CreateConfigRequest`.
+message CreateConfigResponse {
+	Config config = 1;
+}
+
+// RemoveConfigRequest contains the ID of the config that should be removed.  This
+// removes all versions of the config.
+message RemoveConfigRequest {
+	string config_id = 1;
+}
+
+// RemoveConfigResponse is an empty object indicating the successful removal of
+// a config.
+message RemoveConfigResponse {}

+ 17 - 1
vendor/github.com/docker/swarmkit/api/defaults/service.go

@@ -21,7 +21,8 @@ var Service = api.ServiceSpec{
 		},
 		Resources: &api.ResourceRequirements{},
 		Restart: &api.RestartPolicy{
-			Delay: gogotypes.DurationProto(5 * time.Second),
+			Condition: api.RestartOnAny,
+			Delay:     gogotypes.DurationProto(5 * time.Second),
 		},
 		Placement: &api.Placement{},
 	},
@@ -31,6 +32,12 @@ var Service = api.ServiceSpec{
 		Parallelism:   1,
 		Order:         api.UpdateConfig_STOP_FIRST,
 	},
+	Rollback: &api.UpdateConfig{
+		FailureAction: api.UpdateConfig_PAUSE,
+		Monitor:       gogotypes.DurationProto(5 * time.Second),
+		Parallelism:   1,
+		Order:         api.UpdateConfig_STOP_FIRST,
+	},
 }
 
 // InterpolateService returns a ServiceSpec based on the provided spec, which
@@ -79,5 +86,14 @@ func InterpolateService(origSpec *api.ServiceSpec) *api.ServiceSpec {
 		}
 	}
 
+	if spec.Rollback == nil {
+		spec.Rollback = Service.Rollback.Copy()
+	} else {
+		if spec.Rollback.Monitor == nil {
+			spec.Rollback.Monitor = &gogotypes.Duration{}
+			deepcopy.Copy(spec.Rollback.Monitor, Service.Rollback.Monitor)
+		}
+	}
+
 	return spec
 }

+ 215 - 63
vendor/github.com/docker/swarmkit/api/dispatcher.pb.go

@@ -154,6 +154,8 @@ type SessionMessage struct {
 	// Symmetric encryption key distributed by the lead manager. Used by agents
 	// for securing network bootstrapping and communication.
 	NetworkBootstrapKeys []*EncryptionKey `protobuf:"bytes,4,rep,name=network_bootstrap_keys,json=networkBootstrapKeys" json:"network_bootstrap_keys,omitempty"`
+	// Which root certificates to trust
+	RootCA []byte `protobuf:"bytes,5,opt,name=RootCA,proto3" json:"RootCA,omitempty"`
 }
 
 func (m *SessionMessage) Reset()                    { *m = SessionMessage{} }
@@ -244,6 +246,7 @@ type Assignment struct {
 	// Types that are valid to be assigned to Item:
 	//	*Assignment_Task
 	//	*Assignment_Secret
+	//	*Assignment_Config
 	Item isAssignment_Item `protobuf_oneof:"item"`
 }
 
@@ -263,9 +266,13 @@ type Assignment_Task struct {
 type Assignment_Secret struct {
 	Secret *Secret `protobuf:"bytes,2,opt,name=secret,oneof"`
 }
+type Assignment_Config struct {
+	Config *Config `protobuf:"bytes,3,opt,name=config,oneof"`
+}
 
 func (*Assignment_Task) isAssignment_Item()   {}
 func (*Assignment_Secret) isAssignment_Item() {}
+func (*Assignment_Config) isAssignment_Item() {}
 
 func (m *Assignment) GetItem() isAssignment_Item {
 	if m != nil {
@@ -288,11 +295,19 @@ func (m *Assignment) GetSecret() *Secret {
 	return nil
 }
 
+func (m *Assignment) GetConfig() *Config {
+	if x, ok := m.GetItem().(*Assignment_Config); ok {
+		return x.Config
+	}
+	return nil
+}
+
 // XXX_OneofFuncs is for the internal use of the proto package.
 func (*Assignment) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
 	return _Assignment_OneofMarshaler, _Assignment_OneofUnmarshaler, _Assignment_OneofSizer, []interface{}{
 		(*Assignment_Task)(nil),
 		(*Assignment_Secret)(nil),
+		(*Assignment_Config)(nil),
 	}
 }
 
@@ -310,6 +325,11 @@ func _Assignment_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
 		if err := b.EncodeMessage(x.Secret); err != nil {
 			return err
 		}
+	case *Assignment_Config:
+		_ = b.EncodeVarint(3<<3 | proto.WireBytes)
+		if err := b.EncodeMessage(x.Config); err != nil {
+			return err
+		}
 	case nil:
 	default:
 		return fmt.Errorf("Assignment.Item has unexpected type %T", x)
@@ -336,6 +356,14 @@ func _Assignment_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buf
 		err := b.DecodeMessage(msg)
 		m.Item = &Assignment_Secret{msg}
 		return true, err
+	case 3: // item.config
+		if wire != proto.WireBytes {
+			return true, proto.ErrInternalBadWireType
+		}
+		msg := new(Config)
+		err := b.DecodeMessage(msg)
+		m.Item = &Assignment_Config{msg}
+		return true, err
 	default:
 		return false, nil
 	}
@@ -355,6 +383,11 @@ func _Assignment_OneofSizer(msg proto.Message) (n int) {
 		n += proto.SizeVarint(2<<3 | proto.WireBytes)
 		n += proto.SizeVarint(uint64(s))
 		n += s
+	case *Assignment_Config:
+		s := proto.Size(x.Config)
+		n += proto.SizeVarint(3<<3 | proto.WireBytes)
+		n += proto.SizeVarint(uint64(s))
+		n += s
 	case nil:
 	default:
 		panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
@@ -513,6 +546,10 @@ func (m *SessionMessage) CopyFrom(src interface{}) {
 		}
 	}
 
+	if o.RootCA != nil {
+		m.RootCA = make([]byte, len(o.RootCA))
+		copy(m.RootCA, o.RootCA)
+	}
 }
 
 func (m *HeartbeatRequest) Copy() *HeartbeatRequest {
@@ -678,6 +715,12 @@ func (m *Assignment) CopyFrom(src interface{}) {
 			}
 			github_com_docker_swarmkit_api_deepcopy.Copy(v.Secret, o.GetSecret())
 			m.Item = &v
+		case *Assignment_Config:
+			v := Assignment_Config{
+				Config: &Config{},
+			}
+			github_com_docker_swarmkit_api_deepcopy.Copy(v.Config, o.GetConfig())
+			m.Item = &v
 		}
 	}
 
@@ -1148,6 +1191,12 @@ func (m *SessionMessage) MarshalTo(dAtA []byte) (int, error) {
 			i += n
 		}
 	}
+	if len(m.RootCA) > 0 {
+		dAtA[i] = 0x2a
+		i++
+		i = encodeVarintDispatcher(dAtA, i, uint64(len(m.RootCA)))
+		i += copy(dAtA[i:], m.RootCA)
+	}
 	return i, nil
 }
 
@@ -1420,6 +1469,20 @@ func (m *Assignment_Secret) MarshalTo(dAtA []byte) (int, error) {
 	}
 	return i, nil
 }
+func (m *Assignment_Config) MarshalTo(dAtA []byte) (int, error) {
+	i := 0
+	if m.Config != nil {
+		dAtA[i] = 0x1a
+		i++
+		i = encodeVarintDispatcher(dAtA, i, uint64(m.Config.Size()))
+		n8, err := m.Config.MarshalTo(dAtA[i:])
+		if err != nil {
+			return 0, err
+		}
+		i += n8
+	}
+	return i, nil
+}
 func (m *AssignmentChange) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	dAtA = make([]byte, size)
@@ -1439,11 +1502,11 @@ func (m *AssignmentChange) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0xa
 		i++
 		i = encodeVarintDispatcher(dAtA, i, uint64(m.Assignment.Size()))
-		n8, err := m.Assignment.MarshalTo(dAtA[i:])
+		n9, err := m.Assignment.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n8
+		i += n9
 	}
 	if m.Action != 0 {
 		dAtA[i] = 0x10
@@ -1860,6 +1923,10 @@ func (m *SessionMessage) Size() (n int) {
 			n += 1 + l + sovDispatcher(uint64(l))
 		}
 	}
+	l = len(m.RootCA)
+	if l > 0 {
+		n += 1 + l + sovDispatcher(uint64(l))
+	}
 	return n
 }
 
@@ -1976,6 +2043,15 @@ func (m *Assignment_Secret) Size() (n int) {
 	}
 	return n
 }
+func (m *Assignment_Config) Size() (n int) {
+	var l int
+	_ = l
+	if m.Config != nil {
+		l = m.Config.Size()
+		n += 1 + l + sovDispatcher(uint64(l))
+	}
+	return n
+}
 func (m *AssignmentChange) Size() (n int) {
 	var l int
 	_ = l
@@ -2045,6 +2121,7 @@ func (this *SessionMessage) String() string {
 		`Node:` + strings.Replace(fmt.Sprintf("%v", this.Node), "Node", "Node", 1) + `,`,
 		`Managers:` + strings.Replace(fmt.Sprintf("%v", this.Managers), "WeightedPeer", "WeightedPeer", 1) + `,`,
 		`NetworkBootstrapKeys:` + strings.Replace(fmt.Sprintf("%v", this.NetworkBootstrapKeys), "EncryptionKey", "EncryptionKey", 1) + `,`,
+		`RootCA:` + fmt.Sprintf("%v", this.RootCA) + `,`,
 		`}`,
 	}, "")
 	return s
@@ -2160,6 +2237,16 @@ func (this *Assignment_Secret) String() string {
 	}, "")
 	return s
 }
+func (this *Assignment_Config) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&Assignment_Config{`,
+		`Config:` + strings.Replace(fmt.Sprintf("%v", this.Config), "Config", "Config", 1) + `,`,
+		`}`,
+	}, "")
+	return s
+}
 func (this *AssignmentChange) String() string {
 	if this == nil {
 		return "nil"
@@ -2457,6 +2544,37 @@ func (m *SessionMessage) Unmarshal(dAtA []byte) error {
 				return err
 			}
 			iNdEx = postIndex
+		case 5:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field RootCA", wireType)
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowDispatcher
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				byteLen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if byteLen < 0 {
+				return ErrInvalidLengthDispatcher
+			}
+			postIndex := iNdEx + byteLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.RootCA = append(m.RootCA[:0], dAtA[iNdEx:postIndex]...)
+			if m.RootCA == nil {
+				m.RootCA = []byte{}
+			}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipDispatcher(dAtA[iNdEx:])
@@ -3241,6 +3359,38 @@ func (m *Assignment) Unmarshal(dAtA []byte) error {
 			}
 			m.Item = &Assignment_Secret{v}
 			iNdEx = postIndex
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Config", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowDispatcher
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthDispatcher
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			v := &Config{}
+			if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			m.Item = &Assignment_Config{v}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipDispatcher(dAtA[iNdEx:])
@@ -3630,65 +3780,67 @@ var (
 func init() { proto.RegisterFile("dispatcher.proto", fileDescriptorDispatcher) }
 
 var fileDescriptorDispatcher = []byte{
-	// 949 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x55, 0xcd, 0x6e, 0xe3, 0x54,
-	0x14, 0x8e, 0xd3, 0xd4, 0x6d, 0x4f, 0xda, 0x12, 0x2e, 0xa3, 0xc1, 0x58, 0x9a, 0x34, 0xb8, 0x4c,
-	0x54, 0x69, 0x8a, 0x3b, 0x84, 0x9f, 0x0d, 0x55, 0xa1, 0x69, 0x22, 0x35, 0x9a, 0x49, 0xa7, 0xba,
-	0xcd, 0xcc, 0x2c, 0x23, 0x27, 0x3e, 0xb8, 0x26, 0x8d, 0xaf, 0xf1, 0xbd, 0x99, 0x21, 0x48, 0x48,
-	0x48, 0x30, 0x12, 0x62, 0x85, 0x58, 0x75, 0xc3, 0x2b, 0xf0, 0x1c, 0x15, 0x2b, 0x96, 0xac, 0x0a,
-	0x93, 0x07, 0xe0, 0x01, 0x58, 0x21, 0xdb, 0xd7, 0x49, 0xc8, 0x24, 0x9d, 0xb4, 0xab, 0xc4, 0xe7,
-	0x7c, 0xdf, 0x39, 0x9f, 0xbf, 0x7b, 0x7c, 0x2e, 0xe4, 0x6c, 0x97, 0xfb, 0x96, 0x68, 0x9f, 0x62,
-	0x60, 0xfa, 0x01, 0x13, 0x8c, 0x10, 0x9b, 0xb5, 0x3b, 0x18, 0x98, 0xfc, 0xb9, 0x15, 0x74, 0x3b,
-	0xae, 0x30, 0x9f, 0x7d, 0xa0, 0x67, 0x45, 0xdf, 0x47, 0x1e, 0x03, 0xf4, 0x35, 0xd6, 0xfa, 0x12,
-	0xdb, 0x22, 0x79, 0xbc, 0xe5, 0x30, 0x87, 0x45, 0x7f, 0x77, 0xc2, 0x7f, 0x32, 0xfa, 0x96, 0x7f,
-	0xd6, 0x73, 0x5c, 0x6f, 0x27, 0xfe, 0x91, 0xc1, 0xbc, 0xc3, 0x98, 0x73, 0x86, 0x3b, 0xd1, 0x53,
-	0xab, 0xf7, 0xc5, 0x8e, 0xdd, 0x0b, 0x2c, 0xe1, 0x32, 0x99, 0x37, 0x5e, 0x28, 0xb0, 0x7e, 0x82,
-	0x9c, 0xbb, 0xcc, 0xa3, 0xf8, 0x55, 0x0f, 0xb9, 0x20, 0x55, 0xc8, 0xda, 0xc8, 0xdb, 0x81, 0xeb,
-	0x87, 0x38, 0x4d, 0x29, 0x28, 0x5b, 0xd9, 0xd2, 0xa6, 0xf9, 0xaa, 0x46, 0xf3, 0x88, 0xd9, 0x58,
-	0x19, 0x41, 0xe9, 0x38, 0x8f, 0x6c, 0x03, 0xf0, 0xb8, 0x70, 0xd3, 0xb5, 0xb5, 0x74, 0x41, 0xd9,
-	0x5a, 0x29, 0xaf, 0x0d, 0x2e, 0x37, 0x56, 0x64, 0xbb, 0x5a, 0x85, 0xae, 0x48, 0x40, 0xcd, 0x36,
-	0xbe, 0x4f, 0x0f, 0x75, 0xd4, 0x91, 0x73, 0xcb, 0xc1, 0x89, 0x02, 0xca, 0xd5, 0x05, 0xc8, 0x36,
-	0x64, 0x3c, 0x66, 0x63, 0xd4, 0x28, 0x5b, 0xd2, 0x66, 0xc9, 0xa5, 0x11, 0x8a, 0xec, 0xc2, 0x72,
-	0xd7, 0xf2, 0x2c, 0x07, 0x03, 0xae, 0x2d, 0x14, 0x16, 0xb6, 0xb2, 0xa5, 0xc2, 0x34, 0xc6, 0x53,
-	0x74, 0x9d, 0x53, 0x81, 0xf6, 0x31, 0x62, 0x40, 0x87, 0x0c, 0xf2, 0x14, 0x6e, 0x7b, 0x28, 0x9e,
-	0xb3, 0xa0, 0xd3, 0x6c, 0x31, 0x26, 0xb8, 0x08, 0x2c, 0xbf, 0xd9, 0xc1, 0x3e, 0xd7, 0x32, 0x51,
-	0xad, 0x77, 0xa7, 0xd5, 0xaa, 0x7a, 0xed, 0xa0, 0x1f, 0x59, 0xf3, 0x00, 0xfb, 0xf4, 0x96, 0x2c,
-	0x50, 0x4e, 0xf8, 0x0f, 0xb0, 0xcf, 0x8d, 0xcf, 0x21, 0x77, 0x88, 0x56, 0x20, 0x5a, 0x68, 0x89,
-	0xe4, 0x38, 0xae, 0x65, 0x83, 0x71, 0x0c, 0x6f, 0x8e, 0x55, 0xe0, 0x3e, 0xf3, 0x38, 0x92, 0x4f,
-	0x41, 0xf5, 0x31, 0x70, 0x99, 0x2d, 0x0f, 0xf3, 0x1d, 0x33, 0x9e, 0x0a, 0x33, 0x99, 0x0a, 0xb3,
-	0x22, 0xa7, 0xa2, 0xbc, 0x7c, 0x71, 0xb9, 0x91, 0x3a, 0xff, 0x6b, 0x43, 0xa1, 0x92, 0x62, 0xfc,
-	0x9c, 0x86, 0xb7, 0x1f, 0xfb, 0xb6, 0x25, 0xb0, 0x61, 0xf1, 0xce, 0x89, 0xb0, 0x44, 0x8f, 0xdf,
-	0x48, 0x1b, 0x79, 0x02, 0x4b, 0xbd, 0xa8, 0x50, 0xe2, 0xf9, 0xee, 0x34, 0x9f, 0x66, 0xf4, 0x32,
-	0x47, 0x91, 0x18, 0x41, 0x93, 0x62, 0x3a, 0x83, 0xdc, 0x64, 0x92, 0x6c, 0xc2, 0x92, 0xb0, 0x78,
-	0x67, 0x24, 0x0b, 0x06, 0x97, 0x1b, 0x6a, 0x08, 0xab, 0x55, 0xa8, 0x1a, 0xa6, 0x6a, 0x36, 0xf9,
-	0x04, 0x54, 0x1e, 0x91, 0xe4, 0xd4, 0xe4, 0xa7, 0xe9, 0x19, 0x53, 0x22, 0xd1, 0x86, 0x0e, 0xda,
-	0xab, 0x2a, 0x63, 0xaf, 0x8d, 0x5d, 0x58, 0x0d, 0xa3, 0x37, 0xb3, 0xc8, 0xd8, 0x93, 0xec, 0xe4,
-	0x1b, 0x30, 0x61, 0x31, 0xd4, 0xca, 0x35, 0x25, 0x32, 0x4c, 0x9b, 0x25, 0x90, 0xc6, 0x30, 0xa3,
-	0x0c, 0x64, 0x9f, 0x73, 0xd7, 0xf1, 0xba, 0xe8, 0x89, 0x1b, 0x6a, 0xf8, 0x06, 0x60, 0x54, 0x83,
-	0x98, 0x90, 0x09, 0x4b, 0xcb, 0xc9, 0x99, 0x29, 0xe0, 0x30, 0x45, 0x23, 0x1c, 0xf9, 0x08, 0x54,
-	0x8e, 0xed, 0x00, 0x85, 0xf4, 0x54, 0x9f, 0xc6, 0x38, 0x89, 0x10, 0x87, 0x29, 0x2a, 0xb1, 0x65,
-	0x15, 0x32, 0xae, 0xc0, 0xae, 0xf1, 0x22, 0x0d, 0xb9, 0x51, 0xf3, 0x83, 0x53, 0xcb, 0x73, 0x90,
-	0xec, 0x01, 0x58, 0xc3, 0x98, 0x14, 0x32, 0xf5, 0xa8, 0x46, 0x4c, 0x3a, 0xc6, 0x20, 0x75, 0x50,
-	0xad, 0x76, 0xb4, 0xcb, 0x42, 0x49, 0xeb, 0xa5, 0x8f, 0xaf, 0xe6, 0xc6, 0x5d, 0xc7, 0x02, 0xfb,
-	0x11, 0x99, 0xca, 0x22, 0x46, 0x6b, 0x5c, 0x62, 0x9c, 0x23, 0x45, 0x50, 0x1f, 0x1f, 0x57, 0xf6,
-	0x1b, 0xd5, 0x5c, 0x4a, 0xd7, 0x7f, 0xfa, 0xb5, 0x70, 0x7b, 0x12, 0x21, 0xc7, 0xb2, 0x08, 0x2a,
-	0xad, 0xd6, 0x1f, 0x3d, 0xa9, 0xe6, 0x94, 0xe9, 0x38, 0x8a, 0x5d, 0xf6, 0x0c, 0x8d, 0x7f, 0x95,
-	0xff, 0x1d, 0x64, 0x32, 0x0e, 0x9f, 0x41, 0x26, 0xbc, 0x16, 0x22, 0x0f, 0xd6, 0x4b, 0xf7, 0xae,
-	0x7e, 0x8f, 0x84, 0x65, 0x36, 0xfa, 0x3e, 0xd2, 0x88, 0x48, 0xee, 0x00, 0x58, 0xbe, 0x7f, 0xe6,
-	0x22, 0x6f, 0x0a, 0x16, 0x2f, 0x65, 0xba, 0x22, 0x23, 0x0d, 0x16, 0xa6, 0x03, 0xe4, 0xbd, 0x33,
-	0xc1, 0x9b, 0xae, 0xa7, 0x2d, 0xc4, 0x69, 0x19, 0xa9, 0x79, 0x64, 0x0f, 0x96, 0xda, 0x91, 0x39,
-	0xc9, 0xa2, 0x7b, 0x6f, 0x1e, 0x27, 0x69, 0x42, 0x32, 0xee, 0x42, 0x26, 0xd4, 0x42, 0x56, 0x61,
-	0xf9, 0xe0, 0x51, 0xfd, 0xf8, 0x61, 0x35, 0xf4, 0x8b, 0xbc, 0x01, 0xd9, 0xda, 0xd1, 0x01, 0xad,
-	0xd6, 0xab, 0x47, 0x8d, 0xfd, 0x87, 0x39, 0xa5, 0x74, 0xbe, 0x08, 0x50, 0x19, 0xde, 0x91, 0xe4,
-	0x6b, 0x58, 0x92, 0x73, 0x4a, 0x8c, 0xe9, 0xc3, 0x34, 0x7e, 0x7d, 0xe9, 0x57, 0x61, 0xa4, 0x23,
-	0xc6, 0xe6, 0xef, 0xbf, 0xfd, 0x73, 0x9e, 0xbe, 0x03, 0xab, 0x11, 0xe6, 0xfd, 0x70, 0x11, 0x63,
-	0x00, 0x6b, 0xf1, 0x93, 0x5c, 0xf3, 0xf7, 0x15, 0xf2, 0x2d, 0xac, 0x0c, 0x97, 0x29, 0x99, 0xfa,
-	0xae, 0x93, 0xdb, 0x5a, 0xbf, 0xfb, 0x1a, 0x94, 0xdc, 0x12, 0xf3, 0x08, 0x20, 0xbf, 0x28, 0x90,
-	0x9b, 0xdc, 0x33, 0xe4, 0xde, 0x35, 0x76, 0xa6, 0xbe, 0x3d, 0x1f, 0xf8, 0x3a, 0xa2, 0x7a, 0xb0,
-	0x18, 0x6d, 0x28, 0x52, 0x98, 0xb5, 0x0a, 0x86, 0xdd, 0x67, 0x23, 0x92, 0x73, 0x28, 0xce, 0xd1,
-	0xf1, 0xc7, 0xb4, 0x72, 0x5f, 0x21, 0x3f, 0x28, 0x90, 0x1d, 0x1b, 0x6d, 0x52, 0x7c, 0xcd, 0xec,
-	0x27, 0x1a, 0x8a, 0xf3, 0x7d, 0x23, 0x73, 0x4e, 0x44, 0x59, 0xbb, 0x78, 0x99, 0x4f, 0xfd, 0xf9,
-	0x32, 0x9f, 0xfa, 0x6e, 0x90, 0x57, 0x2e, 0x06, 0x79, 0xe5, 0x8f, 0x41, 0x5e, 0xf9, 0x7b, 0x90,
-	0x57, 0x5a, 0x6a, 0x74, 0x97, 0x7e, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x70, 0xa6, 0xd5,
-	0x2c, 0xde, 0x09, 0x00, 0x00,
+	// 983 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x55, 0x4f, 0x6f, 0x1b, 0x45,
+	0x14, 0xf7, 0x38, 0xce, 0x26, 0x7e, 0x4e, 0x82, 0x19, 0xaa, 0xb0, 0xac, 0x54, 0xc7, 0x6c, 0x68,
+	0x14, 0xa9, 0x61, 0x53, 0xcc, 0x9f, 0x0b, 0x51, 0x20, 0x8e, 0x2d, 0xc5, 0x6a, 0x93, 0x46, 0x13,
+	0xb7, 0x3d, 0x5a, 0x6b, 0xef, 0x74, 0xb3, 0x38, 0xde, 0x59, 0x76, 0xc6, 0x2d, 0x3e, 0x20, 0x71,
+	0xa0, 0x12, 0xe2, 0x84, 0x38, 0x45, 0x42, 0x7c, 0x05, 0xc4, 0xc7, 0x88, 0x38, 0x71, 0xe4, 0x14,
+	0xa8, 0x3f, 0x00, 0x1f, 0x80, 0x13, 0xda, 0xd9, 0x59, 0xdb, 0x75, 0xed, 0xd4, 0xc9, 0xc9, 0x9e,
+	0x37, 0xbf, 0xdf, 0x9b, 0xdf, 0xbc, 0xf7, 0xdb, 0x37, 0x90, 0x77, 0x3c, 0x1e, 0xd8, 0xa2, 0x75,
+	0x4a, 0x43, 0x2b, 0x08, 0x99, 0x60, 0x18, 0x3b, 0xac, 0xd5, 0xa6, 0xa1, 0xc5, 0x9f, 0xdb, 0x61,
+	0xa7, 0xed, 0x09, 0xeb, 0xd9, 0x47, 0x46, 0x4e, 0xf4, 0x02, 0xca, 0x63, 0x80, 0xb1, 0xcc, 0x9a,
+	0x5f, 0xd1, 0x96, 0x48, 0x96, 0xb7, 0x5c, 0xe6, 0x32, 0xf9, 0x77, 0x3b, 0xfa, 0xa7, 0xa2, 0xef,
+	0x04, 0x67, 0x5d, 0xd7, 0xf3, 0xb7, 0xe3, 0x1f, 0x15, 0x2c, 0xb8, 0x8c, 0xb9, 0x67, 0x74, 0x5b,
+	0xae, 0x9a, 0xdd, 0xa7, 0xdb, 0x4e, 0x37, 0xb4, 0x85, 0xc7, 0xd4, 0xbe, 0xf9, 0x02, 0xc1, 0xca,
+	0x09, 0xe5, 0xdc, 0x63, 0x3e, 0xa1, 0x5f, 0x77, 0x29, 0x17, 0xb8, 0x0a, 0x39, 0x87, 0xf2, 0x56,
+	0xe8, 0x05, 0x11, 0x4e, 0x47, 0x45, 0xb4, 0x99, 0x2b, 0xad, 0x5b, 0xaf, 0x6b, 0xb4, 0x8e, 0x98,
+	0x43, 0x2b, 0x43, 0x28, 0x19, 0xe5, 0xe1, 0x2d, 0x00, 0x1e, 0x27, 0x6e, 0x78, 0x8e, 0x9e, 0x2e,
+	0xa2, 0xcd, 0x6c, 0x79, 0xb9, 0x7f, 0xb9, 0x96, 0x55, 0xc7, 0xd5, 0x2a, 0x24, 0xab, 0x00, 0x35,
+	0xc7, 0xfc, 0x25, 0x3d, 0xd0, 0x71, 0x48, 0x39, 0xb7, 0x5d, 0x3a, 0x96, 0x00, 0x5d, 0x9d, 0x00,
+	0x6f, 0x41, 0xc6, 0x67, 0x0e, 0x95, 0x07, 0xe5, 0x4a, 0xfa, 0x34, 0xb9, 0x44, 0xa2, 0xf0, 0x0e,
+	0x2c, 0x76, 0x6c, 0xdf, 0x76, 0x69, 0xc8, 0xf5, 0xb9, 0xe2, 0xdc, 0x66, 0xae, 0x54, 0x9c, 0xc4,
+	0x78, 0x42, 0x3d, 0xf7, 0x54, 0x50, 0xe7, 0x98, 0xd2, 0x90, 0x0c, 0x18, 0xf8, 0x09, 0xac, 0xfa,
+	0x54, 0x3c, 0x67, 0x61, 0xbb, 0xd1, 0x64, 0x4c, 0x70, 0x11, 0xda, 0x41, 0xa3, 0x4d, 0x7b, 0x5c,
+	0xcf, 0xc8, 0x5c, 0xef, 0x4f, 0xca, 0x55, 0xf5, 0x5b, 0x61, 0x4f, 0x96, 0xe6, 0x3e, 0xed, 0x91,
+	0x5b, 0x2a, 0x41, 0x39, 0xe1, 0xdf, 0xa7, 0x3d, 0x8e, 0x57, 0x41, 0x23, 0x8c, 0x89, 0xfd, 0x3d,
+	0x7d, 0xbe, 0x88, 0x36, 0x97, 0x88, 0x5a, 0x99, 0x5f, 0x42, 0xfe, 0x80, 0xda, 0xa1, 0x68, 0x52,
+	0x5b, 0x24, 0x6d, 0xba, 0x56, 0x79, 0xcc, 0x63, 0x78, 0x7b, 0x24, 0x03, 0x0f, 0x98, 0xcf, 0x29,
+	0xfe, 0x1c, 0xb4, 0x80, 0x86, 0x1e, 0x73, 0x54, 0x93, 0xdf, 0xb3, 0x62, 0xb7, 0x58, 0x89, 0x5b,
+	0xac, 0x8a, 0x72, 0x4b, 0x79, 0xf1, 0xe2, 0x72, 0x2d, 0x75, 0xfe, 0xf7, 0x1a, 0x22, 0x8a, 0x62,
+	0xfe, 0x94, 0x86, 0x77, 0x1f, 0x05, 0x8e, 0x2d, 0x68, 0xdd, 0xe6, 0xed, 0x13, 0x61, 0x8b, 0x2e,
+	0xbf, 0x91, 0x36, 0xfc, 0x18, 0x16, 0xba, 0x32, 0x51, 0xd2, 0x8b, 0x9d, 0x49, 0xf5, 0x9b, 0x72,
+	0x96, 0x35, 0x8c, 0xc4, 0x08, 0x92, 0x24, 0x33, 0x18, 0xe4, 0xc7, 0x37, 0xf1, 0x3a, 0x2c, 0x08,
+	0x9b, 0xb7, 0x87, 0xb2, 0xa0, 0x7f, 0xb9, 0xa6, 0x45, 0xb0, 0x5a, 0x85, 0x68, 0xd1, 0x56, 0xcd,
+	0xc1, 0x9f, 0x81, 0xc6, 0x25, 0x49, 0xb9, 0xa9, 0x30, 0x49, 0xcf, 0x88, 0x12, 0x85, 0x36, 0x0d,
+	0xd0, 0x5f, 0x57, 0x19, 0xd7, 0xda, 0xdc, 0x81, 0xa5, 0x28, 0x7a, 0xb3, 0x12, 0x99, 0xbb, 0x8a,
+	0x9d, 0x7c, 0x1b, 0x16, 0xcc, 0x47, 0x5a, 0xb9, 0x8e, 0x64, 0xc1, 0xf4, 0x69, 0x02, 0x49, 0x0c,
+	0x33, 0xcb, 0x80, 0xf7, 0x38, 0xf7, 0x5c, 0xbf, 0x43, 0x7d, 0x71, 0x43, 0x0d, 0xbf, 0x23, 0x80,
+	0x61, 0x12, 0x6c, 0x41, 0x26, 0xca, 0xad, 0xac, 0x33, 0x55, 0xc1, 0x41, 0x8a, 0x48, 0x1c, 0xfe,
+	0x04, 0x34, 0x4e, 0x5b, 0x21, 0x15, 0xaa, 0xa8, 0xc6, 0x24, 0xc6, 0x89, 0x44, 0x1c, 0xa4, 0x88,
+	0xc2, 0x46, 0xac, 0x16, 0xf3, 0x9f, 0x7a, 0xae, 0x3e, 0x37, 0x9d, 0xb5, 0x2f, 0x11, 0x11, 0x2b,
+	0xc6, 0x96, 0x35, 0xc8, 0x78, 0x82, 0x76, 0xcc, 0x17, 0x69, 0xc8, 0x0f, 0x25, 0xef, 0x9f, 0xda,
+	0xbe, 0x4b, 0xf1, 0x2e, 0x80, 0x3d, 0x88, 0x29, 0xf9, 0x13, 0x3b, 0x3c, 0x64, 0x92, 0x11, 0x06,
+	0x3e, 0x04, 0xcd, 0x6e, 0xc9, 0xd1, 0x18, 0x5d, 0x64, 0xa5, 0xf4, 0xe9, 0xd5, 0xdc, 0xf8, 0xd4,
+	0x91, 0xc0, 0x9e, 0x24, 0x13, 0x95, 0xc4, 0x6c, 0x8e, 0x4a, 0x8c, 0xf7, 0xf0, 0x06, 0x68, 0x8f,
+	0x8e, 0x2b, 0x7b, 0xf5, 0x6a, 0x3e, 0x65, 0x18, 0x3f, 0xfe, 0x5a, 0x5c, 0x1d, 0x47, 0x28, 0x37,
+	0x6f, 0x80, 0x46, 0xaa, 0x87, 0x0f, 0x1f, 0x57, 0xf3, 0x68, 0x32, 0x8e, 0xd0, 0x0e, 0x7b, 0x46,
+	0xcd, 0xff, 0xd0, 0x2b, 0xfd, 0x4f, 0x5c, 0xf4, 0x05, 0x64, 0xa2, 0x57, 0x46, 0xd6, 0x60, 0xa5,
+	0x74, 0xf7, 0xea, 0x7b, 0x24, 0x2c, 0xab, 0xde, 0x0b, 0x28, 0x91, 0x44, 0x7c, 0x1b, 0xc0, 0x0e,
+	0x82, 0x33, 0x8f, 0xf2, 0x86, 0x60, 0xf1, 0x8c, 0x27, 0x59, 0x15, 0xa9, 0xb3, 0x68, 0x3b, 0xa4,
+	0xbc, 0x7b, 0x26, 0x78, 0xc3, 0xf3, 0x65, 0x03, 0xb3, 0x24, 0xab, 0x22, 0x35, 0x1f, 0xef, 0xc2,
+	0x42, 0x4b, 0x16, 0x27, 0x99, 0x9b, 0x1f, 0xcc, 0x52, 0x49, 0x92, 0x90, 0xcc, 0x3b, 0x90, 0x89,
+	0xb4, 0xe0, 0x25, 0x58, 0xdc, 0x7f, 0x78, 0x78, 0xfc, 0xa0, 0x1a, 0xd5, 0x0b, 0xbf, 0x05, 0xb9,
+	0xda, 0xd1, 0x3e, 0xa9, 0x1e, 0x56, 0x8f, 0xea, 0x7b, 0x0f, 0xf2, 0xa8, 0x74, 0x3e, 0x0f, 0x50,
+	0x19, 0x3c, 0xb9, 0xf8, 0x1b, 0x58, 0x50, 0xf6, 0xc6, 0xe6, 0x64, 0x0b, 0x8e, 0xbe, 0x86, 0xc6,
+	0x55, 0x18, 0x55, 0x11, 0x73, 0xfd, 0x8f, 0xdf, 0xfe, 0x3d, 0x4f, 0xdf, 0x86, 0x25, 0x89, 0xf9,
+	0x30, 0x9a, 0xeb, 0x34, 0x84, 0xe5, 0x78, 0xa5, 0x5e, 0x8d, 0x7b, 0x08, 0x7f, 0x0b, 0xd9, 0xc1,
+	0x0c, 0xc6, 0x13, 0xef, 0x3a, 0x3e, 0xe4, 0x8d, 0x3b, 0x6f, 0x40, 0xa9, 0xe1, 0x32, 0x8b, 0x00,
+	0xfc, 0x33, 0x82, 0xfc, 0xf8, 0x78, 0xc2, 0x77, 0xaf, 0x31, 0x6a, 0x8d, 0xad, 0xd9, 0xc0, 0xd7,
+	0x11, 0xd5, 0x85, 0x79, 0x39, 0xd8, 0x70, 0x71, 0xda, 0x00, 0x19, 0x9c, 0x3e, 0x1d, 0x91, 0xf4,
+	0x61, 0x63, 0x86, 0x13, 0x7f, 0x48, 0xa3, 0x7b, 0x08, 0x7f, 0x8f, 0x20, 0x37, 0x62, 0x6d, 0xbc,
+	0xf1, 0x06, 0xef, 0x27, 0x1a, 0x36, 0x66, 0xfb, 0x46, 0x66, 0x74, 0x44, 0x59, 0xbf, 0x78, 0x59,
+	0x48, 0xfd, 0xf5, 0xb2, 0x90, 0xfa, 0xae, 0x5f, 0x40, 0x17, 0xfd, 0x02, 0xfa, 0xb3, 0x5f, 0x40,
+	0xff, 0xf4, 0x0b, 0xa8, 0xa9, 0xc9, 0x27, 0xf8, 0xe3, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x6c,
+	0xba, 0x38, 0xbd, 0x2d, 0x0a, 0x00, 0x00,
 }

+ 4 - 0
vendor/github.com/docker/swarmkit/api/dispatcher.proto

@@ -126,6 +126,9 @@ message SessionMessage {
 	// Symmetric encryption key distributed by the lead manager. Used by agents
 	// for securing network bootstrapping and communication.
 	repeated EncryptionKey network_bootstrap_keys = 4;
+
+	// Which root certificates to trust
+	bytes RootCA = 5;
 }
 
 // HeartbeatRequest provides identifying properties for a single heartbeat.
@@ -174,6 +177,7 @@ message Assignment {
 	oneof item {
 		Task task = 1;
 		Secret secret = 2;
+		Config config = 3;
 	}
 }
 

+ 589 - 102
vendor/github.com/docker/swarmkit/api/objects.pb.go

@@ -269,9 +269,7 @@ func (*Cluster) ProtoMessage()               {}
 func (*Cluster) Descriptor() ([]byte, []int) { return fileDescriptorObjects, []int{7} }
 
 // Secret represents a secret that should be passed to a container or a node,
-// and is immutable. It wraps the `spec` provided by the user with useful
-// information that is generated from the secret data in the `spec`, such as
-// the digest and size of the secret data.
+// and is immutable.
 type Secret struct {
 	ID   string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
 	Meta Meta   `protobuf:"bytes,2,opt,name=meta" json:"meta"`
@@ -286,6 +284,20 @@ func (m *Secret) Reset()                    { *m = Secret{} }
 func (*Secret) ProtoMessage()               {}
 func (*Secret) Descriptor() ([]byte, []int) { return fileDescriptorObjects, []int{8} }
 
+// Config represents a set of configuration files that should be passed to a
+// container.
+type Config struct {
+	ID   string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+	Meta Meta   `protobuf:"bytes,2,opt,name=meta" json:"meta"`
+	// Spec contains the actual config data, as well as any context around the
+	// config data that the user provides.
+	Spec ConfigSpec `protobuf:"bytes,3,opt,name=spec" json:"spec"`
+}
+
+func (m *Config) Reset()                    { *m = Config{} }
+func (*Config) ProtoMessage()               {}
+func (*Config) Descriptor() ([]byte, []int) { return fileDescriptorObjects, []int{9} }
+
 // Resource is a top-level object with externally defined content and indexing.
 // SwarmKit can serve as a store for these objects without understanding their
 // meanings.
@@ -304,7 +316,7 @@ type Resource struct {
 
 func (m *Resource) Reset()                    { *m = Resource{} }
 func (*Resource) ProtoMessage()               {}
-func (*Resource) Descriptor() ([]byte, []int) { return fileDescriptorObjects, []int{9} }
+func (*Resource) Descriptor() ([]byte, []int) { return fileDescriptorObjects, []int{10} }
 
 // Extension declares a type of "resource" object. This message provides some
 // metadata about the objects.
@@ -317,7 +329,7 @@ type Extension struct {
 
 func (m *Extension) Reset()                    { *m = Extension{} }
 func (*Extension) ProtoMessage()               {}
-func (*Extension) Descriptor() ([]byte, []int) { return fileDescriptorObjects, []int{10} }
+func (*Extension) Descriptor() ([]byte, []int) { return fileDescriptorObjects, []int{11} }
 
 func init() {
 	proto.RegisterType((*Meta)(nil), "docker.swarmkit.v1.Meta")
@@ -330,6 +342,7 @@ func init() {
 	proto.RegisterType((*Network)(nil), "docker.swarmkit.v1.Network")
 	proto.RegisterType((*Cluster)(nil), "docker.swarmkit.v1.Cluster")
 	proto.RegisterType((*Secret)(nil), "docker.swarmkit.v1.Secret")
+	proto.RegisterType((*Config)(nil), "docker.swarmkit.v1.Config")
 	proto.RegisterType((*Resource)(nil), "docker.swarmkit.v1.Resource")
 	proto.RegisterType((*Extension)(nil), "docker.swarmkit.v1.Extension")
 }
@@ -629,6 +642,23 @@ func (m *Secret) CopyFrom(src interface{}) {
 	github_com_docker_swarmkit_api_deepcopy.Copy(&m.Spec, &o.Spec)
 }
 
+func (m *Config) Copy() *Config {
+	if m == nil {
+		return nil
+	}
+	o := &Config{}
+	o.CopyFrom(m)
+	return o
+}
+
+func (m *Config) CopyFrom(src interface{}) {
+
+	o := src.(*Config)
+	*m = *o
+	github_com_docker_swarmkit_api_deepcopy.Copy(&m.Meta, &o.Meta)
+	github_com_docker_swarmkit_api_deepcopy.Copy(&m.Spec, &o.Spec)
+}
+
 func (m *Resource) Copy() *Resource {
 	if m == nil {
 		return nil
@@ -1377,7 +1407,7 @@ func (m *Secret) MarshalTo(dAtA []byte) (int, error) {
 	return i, nil
 }
 
-func (m *Resource) Marshal() (dAtA []byte, err error) {
+func (m *Config) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	dAtA = make([]byte, size)
 	n, err := m.MarshalTo(dAtA)
@@ -1387,7 +1417,7 @@ func (m *Resource) Marshal() (dAtA []byte, err error) {
 	return dAtA[:n], nil
 }
 
-func (m *Resource) MarshalTo(dAtA []byte) (int, error) {
+func (m *Config) MarshalTo(dAtA []byte) (int, error) {
 	var i int
 	_ = i
 	var l int
@@ -1408,12 +1438,52 @@ func (m *Resource) MarshalTo(dAtA []byte) (int, error) {
 	i += n38
 	dAtA[i] = 0x1a
 	i++
-	i = encodeVarintObjects(dAtA, i, uint64(m.Annotations.Size()))
-	n39, err := m.Annotations.MarshalTo(dAtA[i:])
+	i = encodeVarintObjects(dAtA, i, uint64(m.Spec.Size()))
+	n39, err := m.Spec.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
 	i += n39
+	return i, nil
+}
+
+func (m *Resource) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalTo(dAtA)
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *Resource) MarshalTo(dAtA []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if len(m.ID) > 0 {
+		dAtA[i] = 0xa
+		i++
+		i = encodeVarintObjects(dAtA, i, uint64(len(m.ID)))
+		i += copy(dAtA[i:], m.ID)
+	}
+	dAtA[i] = 0x12
+	i++
+	i = encodeVarintObjects(dAtA, i, uint64(m.Meta.Size()))
+	n40, err := m.Meta.MarshalTo(dAtA[i:])
+	if err != nil {
+		return 0, err
+	}
+	i += n40
+	dAtA[i] = 0x1a
+	i++
+	i = encodeVarintObjects(dAtA, i, uint64(m.Annotations.Size()))
+	n41, err := m.Annotations.MarshalTo(dAtA[i:])
+	if err != nil {
+		return 0, err
+	}
+	i += n41
 	if len(m.Kind) > 0 {
 		dAtA[i] = 0x22
 		i++
@@ -1424,11 +1494,11 @@ func (m *Resource) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x2a
 		i++
 		i = encodeVarintObjects(dAtA, i, uint64(m.Payload.Size()))
-		n40, err := m.Payload.MarshalTo(dAtA[i:])
+		n42, err := m.Payload.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n40
+		i += n42
 	}
 	return i, nil
 }
@@ -1457,19 +1527,19 @@ func (m *Extension) MarshalTo(dAtA []byte) (int, error) {
 	dAtA[i] = 0x12
 	i++
 	i = encodeVarintObjects(dAtA, i, uint64(m.Meta.Size()))
-	n41, err := m.Meta.MarshalTo(dAtA[i:])
+	n43, err := m.Meta.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n41
+	i += n43
 	dAtA[i] = 0x1a
 	i++
 	i = encodeVarintObjects(dAtA, i, uint64(m.Annotations.Size()))
-	n42, err := m.Annotations.MarshalTo(dAtA[i:])
+	n44, err := m.Annotations.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n42
+	i += n44
 	if len(m.Description) > 0 {
 		dAtA[i] = 0x22
 		i++
@@ -1783,6 +1853,20 @@ func (m *Secret) Size() (n int) {
 	return n
 }
 
+func (m *Config) Size() (n int) {
+	var l int
+	_ = l
+	l = len(m.ID)
+	if l > 0 {
+		n += 1 + l + sovObjects(uint64(l))
+	}
+	l = m.Meta.Size()
+	n += 1 + l + sovObjects(uint64(l))
+	l = m.Spec.Size()
+	n += 1 + l + sovObjects(uint64(l))
+	return n
+}
+
 func (m *Resource) Size() (n int) {
 	var l int
 	_ = l
@@ -3212,6 +3296,223 @@ func (indexer SecretCustomIndexer) FromObject(obj interface{}) (bool, [][]byte,
 	return customIndexer("", &m.Spec.Annotations)
 }
 
+type ConfigCheckFunc func(t1, t2 *Config) bool
+
+type EventCreateConfig struct {
+	Config *Config
+	Checks []ConfigCheckFunc
+}
+
+func (e EventCreateConfig) Matches(apiEvent github_com_docker_go_events.Event) bool {
+	typedEvent, ok := apiEvent.(EventCreateConfig)
+	if !ok {
+		return false
+	}
+
+	for _, check := range e.Checks {
+		if !check(e.Config, typedEvent.Config) {
+			return false
+		}
+	}
+	return true
+}
+
+type EventUpdateConfig struct {
+	Config    *Config
+	OldConfig *Config
+	Checks    []ConfigCheckFunc
+}
+
+func (e EventUpdateConfig) Matches(apiEvent github_com_docker_go_events.Event) bool {
+	typedEvent, ok := apiEvent.(EventUpdateConfig)
+	if !ok {
+		return false
+	}
+
+	for _, check := range e.Checks {
+		if !check(e.Config, typedEvent.Config) {
+			return false
+		}
+	}
+	return true
+}
+
+type EventDeleteConfig struct {
+	Config *Config
+	Checks []ConfigCheckFunc
+}
+
+func (e EventDeleteConfig) Matches(apiEvent github_com_docker_go_events.Event) bool {
+	typedEvent, ok := apiEvent.(EventDeleteConfig)
+	if !ok {
+		return false
+	}
+
+	for _, check := range e.Checks {
+		if !check(e.Config, typedEvent.Config) {
+			return false
+		}
+	}
+	return true
+}
+func (m *Config) CopyStoreObject() StoreObject {
+	return m.Copy()
+}
+
+func (m *Config) GetMeta() Meta {
+	return m.Meta
+}
+
+func (m *Config) SetMeta(meta Meta) {
+	m.Meta = meta
+}
+
+func (m *Config) GetID() string {
+	return m.ID
+}
+
+func (m *Config) EventCreate() Event {
+	return EventCreateConfig{Config: m}
+}
+
+func (m *Config) EventUpdate(oldObject StoreObject) Event {
+	if oldObject != nil {
+		return EventUpdateConfig{Config: m, OldConfig: oldObject.(*Config)}
+	} else {
+		return EventUpdateConfig{Config: m}
+	}
+}
+
+func (m *Config) EventDelete() Event {
+	return EventDeleteConfig{Config: m}
+}
+
+func ConfigCheckID(v1, v2 *Config) bool {
+	return v1.ID == v2.ID
+}
+
+func ConfigCheckIDPrefix(v1, v2 *Config) bool {
+	return strings.HasPrefix(v2.ID, v1.ID)
+}
+
+func ConfigCheckName(v1, v2 *Config) bool {
+	return v1.Spec.Annotations.Name == v2.Spec.Annotations.Name
+}
+
+func ConfigCheckNamePrefix(v1, v2 *Config) bool {
+	return strings.HasPrefix(v2.Spec.Annotations.Name, v1.Spec.Annotations.Name)
+}
+
+func ConfigCheckCustom(v1, v2 *Config) bool {
+	return checkCustom(v1.Spec.Annotations, v2.Spec.Annotations)
+}
+
+func ConfigCheckCustomPrefix(v1, v2 *Config) bool {
+	return checkCustomPrefix(v1.Spec.Annotations, v2.Spec.Annotations)
+}
+
+func ConvertConfigWatch(action WatchActionKind, filters []*SelectBy) ([]Event, error) {
+	var (
+		m          Config
+		checkFuncs []ConfigCheckFunc
+	)
+
+	for _, filter := range filters {
+		switch v := filter.By.(type) {
+		case *SelectBy_ID:
+			if m.ID != "" {
+				return nil, errConflictingFilters
+			}
+			m.ID = v.ID
+			checkFuncs = append(checkFuncs, ConfigCheckID)
+		case *SelectBy_IDPrefix:
+			if m.ID != "" {
+				return nil, errConflictingFilters
+			}
+			m.ID = v.IDPrefix
+			checkFuncs = append(checkFuncs, ConfigCheckIDPrefix)
+		case *SelectBy_Name:
+			if m.Spec.Annotations.Name != "" {
+				return nil, errConflictingFilters
+			}
+			m.Spec.Annotations.Name = v.Name
+			checkFuncs = append(checkFuncs, ConfigCheckName)
+		case *SelectBy_NamePrefix:
+			if m.Spec.Annotations.Name != "" {
+				return nil, errConflictingFilters
+			}
+			m.Spec.Annotations.Name = v.NamePrefix
+			checkFuncs = append(checkFuncs, ConfigCheckNamePrefix)
+		case *SelectBy_Custom:
+			if len(m.Spec.Annotations.Indices) != 0 {
+				return nil, errConflictingFilters
+			}
+			m.Spec.Annotations.Indices = []IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}}
+			checkFuncs = append(checkFuncs, ConfigCheckCustom)
+		case *SelectBy_CustomPrefix:
+			if len(m.Spec.Annotations.Indices) != 0 {
+				return nil, errConflictingFilters
+			}
+			m.Spec.Annotations.Indices = []IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}}
+			checkFuncs = append(checkFuncs, ConfigCheckCustomPrefix)
+		}
+	}
+	var events []Event
+	if (action & WatchActionKindCreate) != 0 {
+		events = append(events, EventCreateConfig{Config: &m, Checks: checkFuncs})
+	}
+	if (action & WatchActionKindUpdate) != 0 {
+		events = append(events, EventUpdateConfig{Config: &m, Checks: checkFuncs})
+	}
+	if (action & WatchActionKindRemove) != 0 {
+		events = append(events, EventDeleteConfig{Config: &m, Checks: checkFuncs})
+	}
+	if len(events) == 0 {
+		return nil, errUnrecognizedAction
+	}
+	return events, nil
+}
+
+type ConfigIndexerByID struct{}
+
+func (indexer ConfigIndexerByID) FromArgs(args ...interface{}) ([]byte, error) {
+	return fromArgs(args...)
+}
+func (indexer ConfigIndexerByID) PrefixFromArgs(args ...interface{}) ([]byte, error) {
+	return prefixFromArgs(args...)
+}
+func (indexer ConfigIndexerByID) FromObject(obj interface{}) (bool, []byte, error) {
+	m := obj.(*Config)
+	return true, []byte(m.ID + "\x00"), nil
+}
+
+type ConfigIndexerByName struct{}
+
+func (indexer ConfigIndexerByName) FromArgs(args ...interface{}) ([]byte, error) {
+	return fromArgs(args...)
+}
+func (indexer ConfigIndexerByName) PrefixFromArgs(args ...interface{}) ([]byte, error) {
+	return prefixFromArgs(args...)
+}
+func (indexer ConfigIndexerByName) FromObject(obj interface{}) (bool, []byte, error) {
+	m := obj.(*Config)
+	val := m.Spec.Annotations.Name
+	return true, []byte(strings.ToLower(val) + "\x00"), nil
+}
+
+type ConfigCustomIndexer struct{}
+
+func (indexer ConfigCustomIndexer) FromArgs(args ...interface{}) ([]byte, error) {
+	return fromArgs(args...)
+}
+func (indexer ConfigCustomIndexer) PrefixFromArgs(args ...interface{}) ([]byte, error) {
+	return prefixFromArgs(args...)
+}
+func (indexer ConfigCustomIndexer) FromObject(obj interface{}) (bool, [][]byte, error) {
+	m := obj.(*Config)
+	return customIndexer("", &m.Spec.Annotations)
+}
+
 type ResourceCheckFunc func(t1, t2 *Resource) bool
 
 type EventCreateResource struct {
@@ -3708,6 +4009,15 @@ func NewStoreAction(c Event) (StoreAction, error) {
 	case EventDeleteSecret:
 		sa.Action = StoreActionKindRemove
 		sa.Target = &StoreAction_Secret{Secret: v.Secret}
+	case EventCreateConfig:
+		sa.Action = StoreActionKindCreate
+		sa.Target = &StoreAction_Config{Config: v.Config}
+	case EventUpdateConfig:
+		sa.Action = StoreActionKindUpdate
+		sa.Target = &StoreAction_Config{Config: v.Config}
+	case EventDeleteConfig:
+		sa.Action = StoreActionKindRemove
+		sa.Target = &StoreAction_Config{Config: v.Config}
 	case EventCreateResource:
 		sa.Action = StoreActionKindCreate
 		sa.Target = &StoreAction_Resource{Resource: v.Resource}
@@ -3812,6 +4122,19 @@ func EventFromStoreAction(sa StoreAction, oldObject StoreObject) (Event, error)
 		case StoreActionKindRemove:
 			return EventDeleteSecret{Secret: v.Secret}, nil
 		}
+	case *StoreAction_Config:
+		switch sa.Action {
+		case StoreActionKindCreate:
+			return EventCreateConfig{Config: v.Config}, nil
+		case StoreActionKindUpdate:
+			if oldObject != nil {
+				return EventUpdateConfig{Config: v.Config, OldConfig: oldObject.(*Config)}, nil
+			} else {
+				return EventUpdateConfig{Config: v.Config}, nil
+			}
+		case StoreActionKindRemove:
+			return EventDeleteConfig{Config: v.Config}, nil
+		}
 	case *StoreAction_Resource:
 		switch sa.Action {
 		case StoreActionKindCreate:
@@ -3904,6 +4227,16 @@ func WatchMessageEvent(c Event) *WatchMessage_Event {
 		}
 	case EventDeleteSecret:
 		return &WatchMessage_Event{Action: WatchActionKindRemove, Object: &Object{Object: &Object_Secret{Secret: v.Secret}}}
+	case EventCreateConfig:
+		return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_Config{Config: v.Config}}}
+	case EventUpdateConfig:
+		if v.OldConfig != nil {
+			return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Config{Config: v.Config}}, OldObject: &Object{Object: &Object_Config{Config: v.OldConfig}}}
+		} else {
+			return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_Config{Config: v.Config}}}
+		}
+	case EventDeleteConfig:
+		return &WatchMessage_Event{Action: WatchActionKindRemove, Object: &Object{Object: &Object_Config{Config: v.Config}}}
 	case EventCreateResource:
 		return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_Resource{Resource: v.Resource}}}
 	case EventUpdateResource:
@@ -3948,6 +4281,8 @@ func ConvertWatchArgs(entries []*WatchRequest_WatchEntry) ([]Event, error) {
 			newEvents, err = ConvertClusterWatch(entry.Action, entry.Filters)
 		case "secret":
 			newEvents, err = ConvertSecretWatch(entry.Action, entry.Filters)
+		case "config":
+			newEvents, err = ConvertConfigWatch(entry.Action, entry.Filters)
 		default:
 			newEvents, err = ConvertResourceWatch(entry.Action, entry.Filters, entry.Kind)
 		case "extension":
@@ -4120,6 +4455,18 @@ func (this *Secret) String() string {
 	}, "")
 	return s
 }
+func (this *Config) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&Config{`,
+		`ID:` + fmt.Sprintf("%v", this.ID) + `,`,
+		`Meta:` + strings.Replace(strings.Replace(this.Meta.String(), "Meta", "Meta", 1), `&`, ``, 1) + `,`,
+		`Spec:` + strings.Replace(strings.Replace(this.Spec.String(), "ConfigSpec", "ConfigSpec", 1), `&`, ``, 1) + `,`,
+		`}`,
+	}, "")
+	return s
+}
 func (this *Resource) String() string {
 	if this == nil {
 		return "nil"
@@ -6506,6 +6853,145 @@ func (m *Secret) Unmarshal(dAtA []byte) error {
 	}
 	return nil
 }
+func (m *Config) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowObjects
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: Config: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: Config: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowObjects
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthObjects
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.ID = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Meta", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowObjects
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthObjects
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.Meta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Spec", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowObjects
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthObjects
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipObjects(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthObjects
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
 func (m *Resource) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	iNdEx := 0
@@ -6983,92 +7469,93 @@ var (
 func init() { proto.RegisterFile("objects.proto", fileDescriptorObjects) }
 
 var fileDescriptorObjects = []byte{
-	// 1390 bytes of a gzipped FileDescriptorProto
+	// 1405 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x57, 0xc1, 0x6f, 0x1b, 0x45,
-	0x17, 0xef, 0xda, 0x1b, 0xdb, 0xfb, 0x9c, 0x58, 0xf9, 0xa6, 0xf9, 0xf2, 0x6d, 0xf3, 0xe5, 0xb3,
-	0xf3, 0xb9, 0x02, 0x55, 0xa8, 0x72, 0x4a, 0x29, 0x28, 0x0d, 0x14, 0x6a, 0x27, 0x16, 0xb5, 0x4a,
-	0x69, 0x34, 0x2d, 0x2d, 0x37, 0x33, 0xd9, 0x9d, 0xba, 0x8b, 0xd7, 0x3b, 0xab, 0x9d, 0xb1, 0x8b,
-	0x6f, 0x88, 0x63, 0xfe, 0x81, 0xdc, 0x38, 0x70, 0xe2, 0x0e, 0x17, 0x2e, 0x9c, 0x7b, 0xe4, 0x84,
-	0x38, 0x45, 0xd4, 0xff, 0x05, 0x12, 0x07, 0x34, 0xb3, 0xb3, 0xce, 0xa6, 0x5e, 0x27, 0x2d, 0xaa,
-	0x2a, 0x4e, 0x9e, 0xd9, 0xf9, 0xfd, 0xde, 0xbc, 0xf7, 0xe6, 0x37, 0x6f, 0x9e, 0x61, 0x89, 0xed,
-	0x7f, 0x49, 0x1d, 0xc1, 0x1b, 0x61, 0xc4, 0x04, 0x43, 0xc8, 0x65, 0x4e, 0x9f, 0x46, 0x0d, 0xfe,
-	0x84, 0x44, 0x83, 0xbe, 0x27, 0x1a, 0xa3, 0xb7, 0xd7, 0xca, 0x62, 0x1c, 0x52, 0x0d, 0x58, 0x2b,
-	0xf3, 0x90, 0x3a, 0xc9, 0xa4, 0xd6, 0x63, 0xac, 0xe7, 0xd3, 0x4d, 0x35, 0xdb, 0x1f, 0x3e, 0xda,
-	0x14, 0xde, 0x80, 0x72, 0x41, 0x06, 0xa1, 0x06, 0xac, 0xf4, 0x58, 0x8f, 0xa9, 0xe1, 0xa6, 0x1c,
-	0xe9, 0xaf, 0x17, 0x9e, 0xa7, 0x91, 0x60, 0xac, 0x97, 0xce, 0x87, 0xfe, 0xb0, 0xe7, 0x05, 0x9b,
-	0xf1, 0x4f, 0xfc, 0xb1, 0xfe, 0x93, 0x01, 0xe6, 0x1d, 0x2a, 0x08, 0x7a, 0x1f, 0x8a, 0x23, 0x1a,
-	0x71, 0x8f, 0x05, 0xb6, 0xb1, 0x61, 0x5c, 0x2a, 0x5f, 0xfd, 0x6f, 0x63, 0xd6, 0xdf, 0xc6, 0x83,
-	0x18, 0xd2, 0x32, 0x9f, 0x1e, 0xd5, 0xce, 0xe1, 0x84, 0x81, 0xae, 0x03, 0x38, 0x11, 0x25, 0x82,
-	0xba, 0x5d, 0x22, 0xec, 0x9c, 0xe2, 0xaf, 0x35, 0x62, 0x57, 0x1a, 0x89, 0x2b, 0x8d, 0xfb, 0x49,
-	0x04, 0xd8, 0xd2, 0xe8, 0xa6, 0x90, 0xd4, 0x61, 0xe8, 0x26, 0xd4, 0xfc, 0xd9, 0x54, 0x8d, 0x6e,
-	0x8a, 0xfa, 0x0f, 0x26, 0x98, 0x9f, 0x32, 0x97, 0xa2, 0x55, 0xc8, 0x79, 0xae, 0x72, 0xdb, 0x6a,
-	0x15, 0x26, 0x47, 0xb5, 0x5c, 0x67, 0x17, 0xe7, 0x3c, 0x17, 0x5d, 0x05, 0x73, 0x40, 0x05, 0xd1,
-	0x0e, 0xd9, 0x59, 0x01, 0xc9, 0xd8, 0x75, 0x34, 0x0a, 0x8b, 0xde, 0x03, 0x53, 0x1e, 0x83, 0xf6,
-	0x64, 0x3d, 0x8b, 0x23, 0xf7, 0xbc, 0x17, 0x52, 0x27, 0xe1, 0x49, 0x3c, 0x6a, 0x43, 0xd9, 0xa5,
-	0xdc, 0x89, 0xbc, 0x50, 0xc8, 0x1c, 0x9a, 0x8a, 0x7e, 0x71, 0x1e, 0x7d, 0xf7, 0x18, 0x8a, 0xd3,
-	0x3c, 0xf4, 0x01, 0x14, 0xb8, 0x20, 0x62, 0xc8, 0xed, 0x05, 0x65, 0xa1, 0x3a, 0xd7, 0x01, 0x85,
-	0xd2, 0x2e, 0x68, 0x0e, 0xba, 0x05, 0x95, 0x01, 0x09, 0x48, 0x8f, 0x46, 0x5d, 0x6d, 0xa5, 0xa0,
-	0xac, 0xfc, 0x3f, 0x33, 0xf4, 0x18, 0x19, 0x1b, 0xc2, 0x4b, 0x83, 0xf4, 0x14, 0xb5, 0x01, 0x88,
-	0x10, 0xc4, 0x79, 0x3c, 0xa0, 0x81, 0xb0, 0x8b, 0xca, 0xca, 0x1b, 0x99, 0xbe, 0x50, 0xf1, 0x84,
-	0x45, 0xfd, 0xe6, 0x14, 0x8c, 0x53, 0x44, 0xf4, 0x31, 0x94, 0x1d, 0x1a, 0x09, 0xef, 0x91, 0xe7,
-	0x10, 0x41, 0xed, 0x92, 0xb2, 0x53, 0xcb, 0xb2, 0xb3, 0x73, 0x0c, 0xd3, 0x41, 0xa5, 0x99, 0xe8,
-	0x0a, 0x98, 0x11, 0xf3, 0xa9, 0x6d, 0x6d, 0x18, 0x97, 0x2a, 0xf3, 0x8f, 0x05, 0x33, 0x9f, 0x62,
-	0x85, 0xdc, 0x5e, 0x3d, 0x38, 0xac, 0x23, 0x58, 0x2e, 0x19, 0xcb, 0x86, 0x92, 0x86, 0x71, 0xc5,
-	0xf8, 0xdc, 0xf8, 0xc2, 0xa8, 0xff, 0x99, 0x87, 0xe2, 0x3d, 0x1a, 0x8d, 0x3c, 0xe7, 0xd5, 0x0a,
-	0xe7, 0xfa, 0x09, 0xe1, 0x64, 0xc6, 0xa8, 0xb7, 0x9d, 0xd1, 0xce, 0x16, 0x94, 0x68, 0xe0, 0x86,
-	0xcc, 0x0b, 0x84, 0x16, 0x4e, 0x66, 0x80, 0x6d, 0x8d, 0xc1, 0x53, 0x34, 0x6a, 0xc3, 0x52, 0x7c,
-	0x1f, 0xba, 0x27, 0x54, 0xb3, 0x91, 0x45, 0xff, 0x4c, 0x01, 0xf5, 0x71, 0x2f, 0x0e, 0x53, 0x33,
-	0xb4, 0x0b, 0x4b, 0x61, 0x44, 0x47, 0x1e, 0x1b, 0xf2, 0xae, 0x0a, 0xa2, 0xf0, 0x42, 0x41, 0xe0,
-	0xc5, 0x84, 0x25, 0x67, 0xe8, 0x43, 0x58, 0x94, 0xe4, 0x6e, 0x52, 0x47, 0xe0, 0xcc, 0x3a, 0x82,
-	0x55, 0xc9, 0xd3, 0x13, 0x74, 0x17, 0xfe, 0x7d, 0xc2, 0x8b, 0xa9, 0xa1, 0xf2, 0xd9, 0x86, 0xce,
-	0xa7, 0x3d, 0xd1, 0x1f, 0xb7, 0xd1, 0xc1, 0x61, 0xbd, 0x02, 0x8b, 0x69, 0x09, 0xd4, 0xbf, 0xcd,
-	0x41, 0x29, 0x49, 0x24, 0xba, 0xa6, 0xcf, 0xcc, 0x98, 0x9f, 0xb5, 0x04, 0xab, 0xe2, 0x8d, 0x8f,
-	0xeb, 0x1a, 0x2c, 0x84, 0x2c, 0x12, 0xdc, 0xce, 0x6d, 0xe4, 0xe7, 0x5d, 0xd1, 0x3d, 0x16, 0x89,
-	0x1d, 0x16, 0x3c, 0xf2, 0x7a, 0x38, 0x06, 0xa3, 0x87, 0x50, 0x1e, 0x79, 0x91, 0x18, 0x12, 0xbf,
-	0xeb, 0x85, 0xdc, 0xce, 0x2b, 0xee, 0x9b, 0xa7, 0x6d, 0xd9, 0x78, 0x10, 0xe3, 0x3b, 0x7b, 0xad,
-	0xca, 0xe4, 0xa8, 0x06, 0xd3, 0x29, 0xc7, 0xa0, 0x4d, 0x75, 0x42, 0xbe, 0x76, 0x07, 0xac, 0xe9,
-	0x0a, 0xba, 0x0c, 0x10, 0xc4, 0x37, 0xb2, 0x3b, 0x55, 0xf6, 0xd2, 0xe4, 0xa8, 0x66, 0xe9, 0x7b,
-	0xda, 0xd9, 0xc5, 0x96, 0x06, 0x74, 0x5c, 0x84, 0xc0, 0x24, 0xae, 0x1b, 0x29, 0x9d, 0x5b, 0x58,
-	0x8d, 0xeb, 0xdf, 0x17, 0xc0, 0xbc, 0x4f, 0x78, 0xff, 0x75, 0x57, 0x55, 0xb9, 0xe7, 0xcc, 0xcd,
-	0xb8, 0x0c, 0xc0, 0x63, 0xbd, 0xc9, 0x70, 0xcc, 0xe3, 0x70, 0xb4, 0x0a, 0x65, 0x38, 0x1a, 0x10,
-	0x87, 0xc3, 0x7d, 0x26, 0xd4, 0x25, 0x30, 0xb1, 0x1a, 0xa3, 0x8b, 0x50, 0x0c, 0x98, 0xab, 0xe8,
-	0x05, 0x45, 0x87, 0xc9, 0x51, 0xad, 0x20, 0x6b, 0x45, 0x67, 0x17, 0x17, 0xe4, 0x52, 0xc7, 0x95,
-	0x65, 0x8a, 0x04, 0x01, 0x13, 0x44, 0xd6, 0x60, 0xae, 0xcb, 0x5d, 0xa6, 0xfa, 0x9b, 0xc7, 0xb0,
-	0xa4, 0x4c, 0xa5, 0x98, 0xe8, 0x01, 0x9c, 0x4f, 0xfc, 0x4d, 0x1b, 0x2c, 0xbd, 0x8c, 0x41, 0xa4,
-	0x2d, 0xa4, 0x56, 0x52, 0xcf, 0x82, 0x35, 0xff, 0x59, 0x50, 0x19, 0xcc, 0x7a, 0x16, 0x5a, 0xb0,
-	0xe4, 0x52, 0xee, 0x45, 0xd4, 0x55, 0x65, 0x82, 0xaa, 0x9b, 0x59, 0xb9, 0xfa, 0xbf, 0xd3, 0x8c,
-	0x50, 0xbc, 0xa8, 0x39, 0x6a, 0x86, 0x9a, 0x50, 0xd2, 0xba, 0xe1, 0x76, 0x59, 0x69, 0xf7, 0x05,
-	0x9f, 0x83, 0x29, 0xed, 0x44, 0x99, 0x5b, 0x7c, 0xa9, 0x32, 0x77, 0x1d, 0xc0, 0x67, 0xbd, 0xae,
-	0x1b, 0x79, 0x23, 0x1a, 0xd9, 0x4b, 0xba, 0x49, 0xc8, 0xe0, 0xee, 0x2a, 0x04, 0xb6, 0x7c, 0xd6,
-	0x8b, 0x87, 0x33, 0x45, 0xa9, 0xf2, 0x72, 0x45, 0x69, 0x7b, 0xed, 0xe0, 0xb0, 0xbe, 0x0a, 0x2b,
-	0xe9, 0x1a, 0xb2, 0x65, 0xdc, 0x34, 0x6e, 0x19, 0x7b, 0x46, 0xfd, 0x1b, 0x03, 0xfe, 0x35, 0x13,
-	0x30, 0x7a, 0x17, 0x8a, 0x3a, 0xe4, 0xd3, 0x3a, 0x29, 0xcd, 0xc3, 0x09, 0x16, 0xad, 0x83, 0x25,
-	0xef, 0x1f, 0xe5, 0x9c, 0xc6, 0x95, 0xc5, 0xc2, 0xc7, 0x1f, 0x90, 0x0d, 0x45, 0xe2, 0x7b, 0x44,
-	0xae, 0xe5, 0xd5, 0x5a, 0x32, 0xad, 0x7f, 0x97, 0x83, 0xa2, 0x36, 0xf6, 0xba, 0xdf, 0x33, 0xbd,
-	0xed, 0xcc, 0xad, 0xbd, 0x01, 0x8b, 0xf1, 0x51, 0x69, 0xb9, 0x99, 0x67, 0x1e, 0x58, 0x39, 0xc6,
-	0xc7, 0x52, 0xbb, 0x01, 0xa6, 0x17, 0x92, 0x81, 0x7e, 0xcb, 0x32, 0x77, 0xee, 0xec, 0x35, 0xef,
-	0xdc, 0x0d, 0xe3, 0x5b, 0x53, 0x9a, 0x1c, 0xd5, 0x4c, 0xf9, 0x01, 0x2b, 0x5a, 0x66, 0xd5, 0xff,
-	0x71, 0x01, 0x8a, 0x3b, 0xfe, 0x90, 0x0b, 0x1a, 0xbd, 0xee, 0x24, 0xe9, 0x6d, 0x67, 0x92, 0xb4,
-	0x03, 0xc5, 0x88, 0x31, 0xd1, 0x75, 0xc8, 0x69, 0xf9, 0xc1, 0x8c, 0x89, 0x9d, 0x66, 0xab, 0x22,
-	0x89, 0xb2, 0x70, 0xc5, 0x73, 0x5c, 0x90, 0xd4, 0x1d, 0x82, 0x1e, 0xc2, 0x6a, 0x52, 0xee, 0xf7,
-	0x19, 0x13, 0x5c, 0x44, 0x24, 0xec, 0xf6, 0xe9, 0x58, 0x36, 0x02, 0xf9, 0x79, 0x8d, 0x5f, 0x3b,
-	0x70, 0xa2, 0xb1, 0x4a, 0xde, 0x6d, 0x3a, 0xc6, 0x2b, 0xda, 0x40, 0x2b, 0xe1, 0xdf, 0xa6, 0x63,
-	0x8e, 0x3e, 0x82, 0x75, 0x3a, 0x85, 0x49, 0x8b, 0x5d, 0x9f, 0x0c, 0xe4, 0x43, 0xd6, 0x75, 0x7c,
-	0xe6, 0xf4, 0x55, 0x2d, 0x35, 0xf1, 0x05, 0x9a, 0x36, 0xf5, 0x49, 0x8c, 0xd8, 0x91, 0x00, 0xc4,
-	0xc1, 0xde, 0xf7, 0x89, 0xd3, 0xf7, 0x3d, 0x2e, 0x7b, 0xfb, 0x54, 0x2f, 0x27, 0xcb, 0xa1, 0xf4,
-	0x6d, 0xeb, 0x94, 0x6c, 0x35, 0x5a, 0xc7, 0xdc, 0x54, 0x67, 0xc8, 0xdb, 0x81, 0x88, 0xc6, 0xf8,
-	0x3f, 0xfb, 0xd9, 0xab, 0xa8, 0x05, 0xe5, 0x61, 0x20, 0xb7, 0x8f, 0x73, 0x60, 0xbd, 0x68, 0x0e,
-	0x20, 0x66, 0xc9, 0xc8, 0xd7, 0x46, 0xb0, 0x7e, 0xda, 0xe6, 0x68, 0x19, 0xf2, 0x7d, 0x3a, 0x8e,
-	0xf5, 0x83, 0xe5, 0x10, 0xdd, 0x84, 0x85, 0x11, 0xf1, 0x87, 0x54, 0x2b, 0xe7, 0xad, 0xac, 0xfd,
-	0xb2, 0x4d, 0xe2, 0x98, 0xb8, 0x9d, 0xdb, 0x32, 0x32, 0x65, 0xfb, 0xb3, 0x01, 0x85, 0x7b, 0xd4,
-	0x89, 0xa8, 0x78, 0xa5, 0xaa, 0xdd, 0x3a, 0xa1, 0xda, 0x6a, 0x76, 0x97, 0x27, 0x77, 0x9d, 0x11,
-	0xed, 0x1a, 0x94, 0xbc, 0x40, 0xd0, 0x28, 0x20, 0xbe, 0x52, 0x6d, 0x09, 0x4f, 0xe7, 0x99, 0x01,
-	0xfc, 0x61, 0x40, 0x09, 0x53, 0xce, 0x86, 0xd1, 0x2b, 0xee, 0xb6, 0x9f, 0x7b, 0xb1, 0xf3, 0x7f,
-	0xfb, 0xc5, 0x46, 0x60, 0xf6, 0xbd, 0x40, 0xf7, 0x16, 0x58, 0x8d, 0x51, 0x03, 0x8a, 0x21, 0x19,
-	0xfb, 0x8c, 0xb8, 0xba, 0x06, 0xad, 0xcc, 0xfc, 0x21, 0x6d, 0x06, 0x63, 0x9c, 0x80, 0xb6, 0x57,
-	0x0e, 0x0e, 0xeb, 0xcb, 0x50, 0x49, 0x47, 0xfe, 0xd8, 0xa8, 0xff, 0x6a, 0x80, 0xd5, 0xfe, 0x4a,
-	0xd0, 0x40, 0x35, 0xb7, 0xff, 0xc8, 0xe0, 0x37, 0x66, 0xff, 0xb4, 0x5a, 0x27, 0xfe, 0x8f, 0x66,
-	0x1d, 0x6a, 0xcb, 0x7e, 0xfa, 0xac, 0x7a, 0xee, 0xb7, 0x67, 0xd5, 0x73, 0x5f, 0x4f, 0xaa, 0xc6,
-	0xd3, 0x49, 0xd5, 0xf8, 0x65, 0x52, 0x35, 0x7e, 0x9f, 0x54, 0x8d, 0xfd, 0x82, 0xca, 0xcf, 0x3b,
-	0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x01, 0x4f, 0xd2, 0x2a, 0xfa, 0x10, 0x00, 0x00,
+	0x17, 0xef, 0xda, 0x1b, 0xdb, 0xfb, 0x9c, 0x58, 0xf9, 0xa6, 0xf9, 0xf2, 0x6d, 0xf3, 0x05, 0x3b,
+	0xb8, 0x02, 0x55, 0xa8, 0x72, 0x4a, 0x29, 0x28, 0x0d, 0x14, 0x6a, 0x27, 0x11, 0xb5, 0x4a, 0x69,
+	0x34, 0x2d, 0x2d, 0x37, 0x33, 0xd9, 0x9d, 0xba, 0x8b, 0xd7, 0x3b, 0xab, 0x9d, 0xb1, 0x8b, 0x6f,
+	0x88, 0x63, 0xfe, 0x81, 0xdc, 0x38, 0xf4, 0xc4, 0x1d, 0x2e, 0x5c, 0x38, 0xf7, 0xc8, 0x09, 0x71,
+	0x8a, 0xa8, 0xff, 0x0b, 0x24, 0x0e, 0x68, 0x66, 0x67, 0x9d, 0x4d, 0xbd, 0x4e, 0x5a, 0x54, 0x45,
+	0x9c, 0x3c, 0xb3, 0xf3, 0xfb, 0xbd, 0x79, 0xef, 0xcd, 0x6f, 0xde, 0x3c, 0xc3, 0x02, 0xdb, 0xfb,
+	0x9a, 0x3a, 0x82, 0x37, 0xc2, 0x88, 0x09, 0x86, 0x90, 0xcb, 0x9c, 0x1e, 0x8d, 0x1a, 0xfc, 0x09,
+	0x89, 0xfa, 0x3d, 0x4f, 0x34, 0x86, 0xef, 0xae, 0x94, 0xc5, 0x28, 0xa4, 0x1a, 0xb0, 0x52, 0xe6,
+	0x21, 0x75, 0x92, 0x49, 0xad, 0xcb, 0x58, 0xd7, 0xa7, 0xeb, 0x6a, 0xb6, 0x37, 0x78, 0xb4, 0x2e,
+	0xbc, 0x3e, 0xe5, 0x82, 0xf4, 0x43, 0x0d, 0x58, 0xea, 0xb2, 0x2e, 0x53, 0xc3, 0x75, 0x39, 0xd2,
+	0x5f, 0x2f, 0xbc, 0x48, 0x23, 0xc1, 0x48, 0x2f, 0x9d, 0x0f, 0xfd, 0x41, 0xd7, 0x0b, 0xd6, 0xe3,
+	0x9f, 0xf8, 0x63, 0xfd, 0x67, 0x03, 0xcc, 0x3b, 0x54, 0x10, 0xf4, 0x21, 0x14, 0x87, 0x34, 0xe2,
+	0x1e, 0x0b, 0x6c, 0x63, 0xcd, 0xb8, 0x54, 0xbe, 0xfa, 0xff, 0xc6, 0xb4, 0xbf, 0x8d, 0x07, 0x31,
+	0xa4, 0x65, 0x3e, 0x3b, 0xac, 0x9d, 0xc3, 0x09, 0x03, 0x5d, 0x07, 0x70, 0x22, 0x4a, 0x04, 0x75,
+	0x3b, 0x44, 0xd8, 0x39, 0xc5, 0x5f, 0x69, 0xc4, 0xae, 0x34, 0x12, 0x57, 0x1a, 0xf7, 0x93, 0x08,
+	0xb0, 0xa5, 0xd1, 0x4d, 0x21, 0xa9, 0x83, 0xd0, 0x4d, 0xa8, 0xf9, 0xd3, 0xa9, 0x1a, 0xdd, 0x14,
+	0xf5, 0x1f, 0x4d, 0x30, 0x3f, 0x67, 0x2e, 0x45, 0xcb, 0x90, 0xf3, 0x5c, 0xe5, 0xb6, 0xd5, 0x2a,
+	0x8c, 0x0f, 0x6b, 0xb9, 0xf6, 0x36, 0xce, 0x79, 0x2e, 0xba, 0x0a, 0x66, 0x9f, 0x0a, 0xa2, 0x1d,
+	0xb2, 0xb3, 0x02, 0x92, 0xb1, 0xeb, 0x68, 0x14, 0x16, 0x7d, 0x00, 0xa6, 0x3c, 0x06, 0xed, 0xc9,
+	0x6a, 0x16, 0x47, 0xee, 0x79, 0x2f, 0xa4, 0x4e, 0xc2, 0x93, 0x78, 0xb4, 0x03, 0x65, 0x97, 0x72,
+	0x27, 0xf2, 0x42, 0x21, 0x73, 0x68, 0x2a, 0xfa, 0xc5, 0x59, 0xf4, 0xed, 0x23, 0x28, 0x4e, 0xf3,
+	0xd0, 0x47, 0x50, 0xe0, 0x82, 0x88, 0x01, 0xb7, 0xe7, 0x94, 0x85, 0xea, 0x4c, 0x07, 0x14, 0x4a,
+	0xbb, 0xa0, 0x39, 0xe8, 0x16, 0x54, 0xfa, 0x24, 0x20, 0x5d, 0x1a, 0x75, 0xb4, 0x95, 0x82, 0xb2,
+	0xf2, 0x66, 0x66, 0xe8, 0x31, 0x32, 0x36, 0x84, 0x17, 0xfa, 0xe9, 0x29, 0xda, 0x01, 0x20, 0x42,
+	0x10, 0xe7, 0x71, 0x9f, 0x06, 0xc2, 0x2e, 0x2a, 0x2b, 0x6f, 0x65, 0xfa, 0x42, 0xc5, 0x13, 0x16,
+	0xf5, 0x9a, 0x13, 0x30, 0x4e, 0x11, 0xd1, 0xa7, 0x50, 0x76, 0x68, 0x24, 0xbc, 0x47, 0x9e, 0x43,
+	0x04, 0xb5, 0x4b, 0xca, 0x4e, 0x2d, 0xcb, 0xce, 0xd6, 0x11, 0x4c, 0x07, 0x95, 0x66, 0xa2, 0x2b,
+	0x60, 0x46, 0xcc, 0xa7, 0xb6, 0xb5, 0x66, 0x5c, 0xaa, 0xcc, 0x3e, 0x16, 0xcc, 0x7c, 0x8a, 0x15,
+	0x72, 0x73, 0x79, 0xff, 0xa0, 0x8e, 0x60, 0xb1, 0x64, 0x2c, 0x1a, 0x4a, 0x1a, 0xc6, 0x15, 0xe3,
+	0x4b, 0xe3, 0x2b, 0xa3, 0xfe, 0x57, 0x1e, 0x8a, 0xf7, 0x68, 0x34, 0xf4, 0x9c, 0xd7, 0x2b, 0x9c,
+	0xeb, 0xc7, 0x84, 0x93, 0x19, 0xa3, 0xde, 0x76, 0x4a, 0x3b, 0x1b, 0x50, 0xa2, 0x81, 0x1b, 0x32,
+	0x2f, 0x10, 0x5a, 0x38, 0x99, 0x01, 0xee, 0x68, 0x0c, 0x9e, 0xa0, 0xd1, 0x0e, 0x2c, 0xc4, 0xf7,
+	0xa1, 0x73, 0x4c, 0x35, 0x6b, 0x59, 0xf4, 0x2f, 0x14, 0x50, 0x1f, 0xf7, 0xfc, 0x20, 0x35, 0x43,
+	0xdb, 0xb0, 0x10, 0x46, 0x74, 0xe8, 0xb1, 0x01, 0xef, 0xa8, 0x20, 0x0a, 0x2f, 0x15, 0x04, 0x9e,
+	0x4f, 0x58, 0x72, 0x86, 0x3e, 0x86, 0x79, 0x49, 0xee, 0x24, 0x75, 0x04, 0x4e, 0xad, 0x23, 0x58,
+	0x95, 0x3c, 0x3d, 0x41, 0x77, 0xe1, 0xbf, 0xc7, 0xbc, 0x98, 0x18, 0x2a, 0x9f, 0x6e, 0xe8, 0x7c,
+	0xda, 0x13, 0xfd, 0x71, 0x13, 0xed, 0x1f, 0xd4, 0x2b, 0x30, 0x9f, 0x96, 0x40, 0xfd, 0xfb, 0x1c,
+	0x94, 0x92, 0x44, 0xa2, 0x6b, 0xfa, 0xcc, 0x8c, 0xd9, 0x59, 0x4b, 0xb0, 0x2a, 0xde, 0xf8, 0xb8,
+	0xae, 0xc1, 0x5c, 0xc8, 0x22, 0xc1, 0xed, 0xdc, 0x5a, 0x7e, 0xd6, 0x15, 0xdd, 0x65, 0x91, 0xd8,
+	0x62, 0xc1, 0x23, 0xaf, 0x8b, 0x63, 0x30, 0x7a, 0x08, 0xe5, 0xa1, 0x17, 0x89, 0x01, 0xf1, 0x3b,
+	0x5e, 0xc8, 0xed, 0xbc, 0xe2, 0xbe, 0x7d, 0xd2, 0x96, 0x8d, 0x07, 0x31, 0xbe, 0xbd, 0xdb, 0xaa,
+	0x8c, 0x0f, 0x6b, 0x30, 0x99, 0x72, 0x0c, 0xda, 0x54, 0x3b, 0xe4, 0x2b, 0x77, 0xc0, 0x9a, 0xac,
+	0xa0, 0xcb, 0x00, 0x41, 0x7c, 0x23, 0x3b, 0x13, 0x65, 0x2f, 0x8c, 0x0f, 0x6b, 0x96, 0xbe, 0xa7,
+	0xed, 0x6d, 0x6c, 0x69, 0x40, 0xdb, 0x45, 0x08, 0x4c, 0xe2, 0xba, 0x91, 0xd2, 0xb9, 0x85, 0xd5,
+	0xb8, 0xfe, 0x43, 0x01, 0xcc, 0xfb, 0x84, 0xf7, 0xce, 0xba, 0xaa, 0xca, 0x3d, 0xa7, 0x6e, 0xc6,
+	0x65, 0x00, 0x1e, 0xeb, 0x4d, 0x86, 0x63, 0x1e, 0x85, 0xa3, 0x55, 0x28, 0xc3, 0xd1, 0x80, 0x38,
+	0x1c, 0xee, 0x33, 0xa1, 0x2e, 0x81, 0x89, 0xd5, 0x18, 0x5d, 0x84, 0x62, 0xc0, 0x5c, 0x45, 0x2f,
+	0x28, 0x3a, 0x8c, 0x0f, 0x6b, 0x05, 0x59, 0x2b, 0xda, 0xdb, 0xb8, 0x20, 0x97, 0xda, 0xae, 0x2c,
+	0x53, 0x24, 0x08, 0x98, 0x20, 0xb2, 0x06, 0x73, 0x5d, 0xee, 0x32, 0xd5, 0xdf, 0x3c, 0x82, 0x25,
+	0x65, 0x2a, 0xc5, 0x44, 0x0f, 0xe0, 0x7c, 0xe2, 0x6f, 0xda, 0x60, 0xe9, 0x55, 0x0c, 0x22, 0x6d,
+	0x21, 0xb5, 0x92, 0x7a, 0x16, 0xac, 0xd9, 0xcf, 0x82, 0xca, 0x60, 0xd6, 0xb3, 0xd0, 0x82, 0x05,
+	0x97, 0x72, 0x2f, 0xa2, 0xae, 0x2a, 0x13, 0x54, 0xdd, 0xcc, 0xca, 0xd5, 0x37, 0x4e, 0x32, 0x42,
+	0xf1, 0xbc, 0xe6, 0xa8, 0x19, 0x6a, 0x42, 0x49, 0xeb, 0x86, 0xdb, 0x65, 0xa5, 0xdd, 0x97, 0x7c,
+	0x0e, 0x26, 0xb4, 0x63, 0x65, 0x6e, 0xfe, 0x95, 0xca, 0xdc, 0x75, 0x00, 0x9f, 0x75, 0x3b, 0x6e,
+	0xe4, 0x0d, 0x69, 0x64, 0x2f, 0xe8, 0x26, 0x21, 0x83, 0xbb, 0xad, 0x10, 0xd8, 0xf2, 0x59, 0x37,
+	0x1e, 0x4e, 0x15, 0xa5, 0xca, 0xab, 0x15, 0xa5, 0xcd, 0x95, 0xfd, 0x83, 0xfa, 0x32, 0x2c, 0xa5,
+	0x6b, 0xc8, 0x86, 0x71, 0xd3, 0xb8, 0x65, 0xec, 0x1a, 0xf5, 0xef, 0x0c, 0xf8, 0xcf, 0x54, 0xc0,
+	0xe8, 0x7d, 0x28, 0xea, 0x90, 0x4f, 0xea, 0xa4, 0x34, 0x0f, 0x27, 0x58, 0xb4, 0x0a, 0x96, 0xbc,
+	0x7f, 0x94, 0x73, 0x1a, 0x57, 0x16, 0x0b, 0x1f, 0x7d, 0x40, 0x36, 0x14, 0x89, 0xef, 0x11, 0xb9,
+	0x96, 0x57, 0x6b, 0xc9, 0xb4, 0xfe, 0x34, 0x07, 0x45, 0x6d, 0xec, 0xac, 0xdf, 0x33, 0xbd, 0xed,
+	0xd4, 0xad, 0xbd, 0x01, 0xf3, 0xf1, 0x51, 0x69, 0xb9, 0x99, 0xa7, 0x1e, 0x58, 0x39, 0xc6, 0xc7,
+	0x52, 0xbb, 0x01, 0xa6, 0x17, 0x92, 0xbe, 0x7e, 0xcb, 0x32, 0x77, 0x6e, 0xef, 0x36, 0xef, 0xdc,
+	0x0d, 0xe3, 0x5b, 0x53, 0x1a, 0x1f, 0xd6, 0x4c, 0xf9, 0x01, 0x2b, 0x5a, 0x66, 0xd5, 0xff, 0x69,
+	0x0e, 0x8a, 0x5b, 0xfe, 0x80, 0x0b, 0x1a, 0x9d, 0x75, 0x92, 0xf4, 0xb6, 0x53, 0x49, 0xda, 0x82,
+	0x62, 0xc4, 0x98, 0xe8, 0x38, 0xe4, 0xa4, 0xfc, 0x60, 0xc6, 0xc4, 0x56, 0xb3, 0x55, 0x91, 0x44,
+	0x59, 0xb8, 0xe2, 0x39, 0x2e, 0x48, 0xea, 0x16, 0x41, 0x0f, 0x61, 0x39, 0x29, 0xf7, 0x7b, 0x8c,
+	0x09, 0x2e, 0x22, 0x12, 0x76, 0x7a, 0x74, 0x24, 0x1b, 0x81, 0xfc, 0xac, 0xc6, 0x6f, 0x27, 0x70,
+	0xa2, 0x91, 0x4a, 0xde, 0x6d, 0x3a, 0xc2, 0x4b, 0xda, 0x40, 0x2b, 0xe1, 0xdf, 0xa6, 0x23, 0x8e,
+	0x3e, 0x81, 0x55, 0x3a, 0x81, 0x49, 0x8b, 0x1d, 0x9f, 0xf4, 0xe5, 0x43, 0xd6, 0x71, 0x7c, 0xe6,
+	0xf4, 0x54, 0x2d, 0x35, 0xf1, 0x05, 0x9a, 0x36, 0xf5, 0x59, 0x8c, 0xd8, 0x92, 0x00, 0xc4, 0xc1,
+	0xde, 0xf3, 0x89, 0xd3, 0xf3, 0x3d, 0x2e, 0x7b, 0xfb, 0x54, 0x2f, 0x27, 0xcb, 0xa1, 0xf4, 0x6d,
+	0xe3, 0x84, 0x6c, 0x35, 0x5a, 0x47, 0xdc, 0x54, 0x67, 0xc8, 0x77, 0x02, 0x11, 0x8d, 0xf0, 0xff,
+	0xf6, 0xb2, 0x57, 0x51, 0x0b, 0xca, 0x83, 0x40, 0x6e, 0x1f, 0xe7, 0xc0, 0x7a, 0xd9, 0x1c, 0x40,
+	0xcc, 0x92, 0x91, 0xaf, 0x0c, 0x61, 0xf5, 0xa4, 0xcd, 0xd1, 0x22, 0xe4, 0x7b, 0x74, 0x14, 0xeb,
+	0x07, 0xcb, 0x21, 0xba, 0x09, 0x73, 0x43, 0xe2, 0x0f, 0xa8, 0x56, 0xce, 0x3b, 0x59, 0xfb, 0x65,
+	0x9b, 0xc4, 0x31, 0x71, 0x33, 0xb7, 0x61, 0x64, 0xca, 0xf6, 0x17, 0x03, 0x0a, 0xf7, 0xa8, 0x13,
+	0x51, 0xf1, 0x5a, 0x55, 0xbb, 0x71, 0x4c, 0xb5, 0xd5, 0xec, 0x2e, 0x4f, 0xee, 0x3a, 0x25, 0xda,
+	0x15, 0x28, 0x79, 0x81, 0xa0, 0x51, 0x40, 0x7c, 0xa5, 0xda, 0x12, 0x9e, 0xcc, 0x33, 0x03, 0x78,
+	0x6a, 0x40, 0x21, 0x6e, 0x83, 0xce, 0x3a, 0x80, 0x78, 0xd7, 0x17, 0x03, 0xc8, 0x74, 0xf2, 0x4f,
+	0x03, 0x4a, 0x98, 0x72, 0x36, 0x88, 0x5e, 0xf3, 0x5f, 0x82, 0x17, 0xda, 0x8a, 0xfc, 0x3f, 0x6e,
+	0x2b, 0x10, 0x98, 0x3d, 0x2f, 0xd0, 0x0d, 0x10, 0x56, 0x63, 0xd4, 0x80, 0x62, 0x48, 0x46, 0x3e,
+	0x23, 0xae, 0x2e, 0x94, 0x4b, 0x53, 0xff, 0x9a, 0x9b, 0xc1, 0x08, 0x27, 0xa0, 0xcd, 0xa5, 0xfd,
+	0x83, 0xfa, 0x22, 0x54, 0xd2, 0x91, 0x3f, 0x36, 0xea, 0xbf, 0x19, 0x60, 0xed, 0x7c, 0x23, 0x68,
+	0xa0, 0x3a, 0xf0, 0x7f, 0x65, 0xf0, 0x6b, 0xd3, 0xff, 0xac, 0xad, 0x63, 0x7f, 0x9a, 0xb3, 0x0e,
+	0xb5, 0x65, 0x3f, 0x7b, 0x5e, 0x3d, 0xf7, 0xfb, 0xf3, 0xea, 0xb9, 0x6f, 0xc7, 0x55, 0xe3, 0xd9,
+	0xb8, 0x6a, 0xfc, 0x3a, 0xae, 0x1a, 0x7f, 0x8c, 0xab, 0xc6, 0x5e, 0x41, 0xe5, 0xe7, 0xbd, 0xbf,
+	0x03, 0x00, 0x00, 0xff, 0xff, 0xa3, 0x7d, 0xca, 0x6a, 0x9f, 0x11, 0x00, 0x00,
 }

+ 24 - 3
vendor/github.com/docker/swarmkit/api/objects.proto

@@ -328,9 +328,7 @@ message Cluster {
 }
 
 // Secret represents a secret that should be passed to a container or a node,
-// and is immutable. It wraps the `spec` provided by the user with useful
-// information that is generated from the secret data in the `spec`, such as
-// the digest and size of the secret data.
+// and is immutable.
 message Secret {
 	option (docker.protobuf.plugin.store_object) = {
 		watch_selectors: {
@@ -355,6 +353,29 @@ message Secret {
 	bool internal = 4;
 }
 
+// Config represents a set of configuration files that should be passed to a
+// container.
+message Config {
+	option (docker.protobuf.plugin.store_object) = {
+		watch_selectors: {
+			id: true
+			id_prefix: true
+			name: true
+			name_prefix: true
+			custom: true
+			custom_prefix: true
+		}
+	};
+
+	string id = 1;
+
+	Meta meta = 2 [(gogoproto.nullable) = false];
+
+	// Spec contains the actual config data, as well as any context around the
+	// config data that the user provides.
+	ConfigSpec spec = 3  [(gogoproto.nullable) = false];
+}
+
 // Resource is a top-level object with externally defined content and indexing.
 // SwarmKit can serve as a store for these objects without understanding their
 // meanings.

+ 163 - 60
vendor/github.com/docker/swarmkit/api/raft.pb.go

@@ -175,6 +175,7 @@ type StoreAction struct {
 	//	*StoreAction_Secret
 	//	*StoreAction_Resource
 	//	*StoreAction_Extension
+	//	*StoreAction_Config
 	Target isStoreAction_Target `protobuf_oneof:"target"`
 }
 
@@ -212,6 +213,9 @@ type StoreAction_Resource struct {
 type StoreAction_Extension struct {
 	Extension *Extension `protobuf:"bytes,9,opt,name=extension,oneof"`
 }
+type StoreAction_Config struct {
+	Config *Config `protobuf:"bytes,10,opt,name=config,oneof"`
+}
 
 func (*StoreAction_Node) isStoreAction_Target()      {}
 func (*StoreAction_Service) isStoreAction_Target()   {}
@@ -221,6 +225,7 @@ func (*StoreAction_Cluster) isStoreAction_Target()   {}
 func (*StoreAction_Secret) isStoreAction_Target()    {}
 func (*StoreAction_Resource) isStoreAction_Target()  {}
 func (*StoreAction_Extension) isStoreAction_Target() {}
+func (*StoreAction_Config) isStoreAction_Target()    {}
 
 func (m *StoreAction) GetTarget() isStoreAction_Target {
 	if m != nil {
@@ -285,6 +290,13 @@ func (m *StoreAction) GetExtension() *Extension {
 	return nil
 }
 
+func (m *StoreAction) GetConfig() *Config {
+	if x, ok := m.GetTarget().(*StoreAction_Config); ok {
+		return x.Config
+	}
+	return nil
+}
+
 // XXX_OneofFuncs is for the internal use of the proto package.
 func (*StoreAction) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
 	return _StoreAction_OneofMarshaler, _StoreAction_OneofUnmarshaler, _StoreAction_OneofSizer, []interface{}{
@@ -296,6 +308,7 @@ func (*StoreAction) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) e
 		(*StoreAction_Secret)(nil),
 		(*StoreAction_Resource)(nil),
 		(*StoreAction_Extension)(nil),
+		(*StoreAction_Config)(nil),
 	}
 }
 
@@ -343,6 +356,11 @@ func _StoreAction_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
 		if err := b.EncodeMessage(x.Extension); err != nil {
 			return err
 		}
+	case *StoreAction_Config:
+		_ = b.EncodeVarint(10<<3 | proto.WireBytes)
+		if err := b.EncodeMessage(x.Config); err != nil {
+			return err
+		}
 	case nil:
 	default:
 		return fmt.Errorf("StoreAction.Target has unexpected type %T", x)
@@ -417,6 +435,14 @@ func _StoreAction_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Bu
 		err := b.DecodeMessage(msg)
 		m.Target = &StoreAction_Extension{msg}
 		return true, err
+	case 10: // target.config
+		if wire != proto.WireBytes {
+			return true, proto.ErrInternalBadWireType
+		}
+		msg := new(Config)
+		err := b.DecodeMessage(msg)
+		m.Target = &StoreAction_Config{msg}
+		return true, err
 	default:
 		return false, nil
 	}
@@ -466,6 +492,11 @@ func _StoreAction_OneofSizer(msg proto.Message) (n int) {
 		n += proto.SizeVarint(9<<3 | proto.WireBytes)
 		n += proto.SizeVarint(uint64(s))
 		n += s
+	case *StoreAction_Config:
+		s := proto.Size(x.Config)
+		n += proto.SizeVarint(10<<3 | proto.WireBytes)
+		n += proto.SizeVarint(uint64(s))
+		n += s
 	case nil:
 	default:
 		panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
@@ -757,6 +788,12 @@ func (m *StoreAction) CopyFrom(src interface{}) {
 			}
 			github_com_docker_swarmkit_api_deepcopy.Copy(v.Extension, o.GetExtension())
 			m.Target = &v
+		case *StoreAction_Config:
+			v := StoreAction_Config{
+				Config: &Config{},
+			}
+			github_com_docker_swarmkit_api_deepcopy.Copy(v.Config, o.GetConfig())
+			m.Target = &v
 		}
 	}
 
@@ -1409,6 +1446,20 @@ func (m *StoreAction_Extension) MarshalTo(dAtA []byte) (int, error) {
 	}
 	return i, nil
 }
+func (m *StoreAction_Config) MarshalTo(dAtA []byte) (int, error) {
+	i := 0
+	if m.Config != nil {
+		dAtA[i] = 0x52
+		i++
+		i = encodeVarintRaft(dAtA, i, uint64(m.Config.Size()))
+		n15, err := m.Config.MarshalTo(dAtA[i:])
+		if err != nil {
+			return 0, err
+		}
+		i += n15
+	}
+	return i, nil
+}
 func encodeFixed64Raft(dAtA []byte, offset int, v uint64) int {
 	dAtA[offset] = uint8(v)
 	dAtA[offset+1] = uint8(v >> 8)
@@ -1922,6 +1973,15 @@ func (m *StoreAction_Extension) Size() (n int) {
 	}
 	return n
 }
+func (m *StoreAction_Config) Size() (n int) {
+	var l int
+	_ = l
+	if m.Config != nil {
+		l = m.Config.Size()
+		n += 1 + l + sovRaft(uint64(l))
+	}
+	return n
+}
 
 func sovRaft(x uint64) (n int) {
 	for {
@@ -2131,6 +2191,16 @@ func (this *StoreAction_Extension) String() string {
 	}, "")
 	return s
 }
+func (this *StoreAction_Config) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&StoreAction_Config{`,
+		`Config:` + strings.Replace(fmt.Sprintf("%v", this.Config), "Config", "Config", 1) + `,`,
+		`}`,
+	}, "")
+	return s
+}
 func valueToStringRaft(v interface{}) string {
 	rv := reflect.ValueOf(v)
 	if rv.IsNil() {
@@ -3355,6 +3425,38 @@ func (m *StoreAction) Unmarshal(dAtA []byte) error {
 			}
 			m.Target = &StoreAction_Extension{v}
 			iNdEx = postIndex
+		case 10:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Config", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRaft
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthRaft
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			v := &Config{}
+			if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			m.Target = &StoreAction_Config{v}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipRaft(dAtA[iNdEx:])
@@ -3484,64 +3586,65 @@ var (
 func init() { proto.RegisterFile("raft.proto", fileDescriptorRaft) }
 
 var fileDescriptorRaft = []byte{
-	// 933 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x96, 0x41, 0x73, 0xdb, 0x44,
-	0x14, 0xc7, 0x25, 0x5b, 0xb5, 0x9b, 0xe7, 0x26, 0xce, 0x6c, 0x48, 0x50, 0x45, 0x51, 0x5c, 0x95,
-	0x99, 0xba, 0x1d, 0x22, 0x0f, 0x86, 0x19, 0x98, 0x42, 0x0f, 0x71, 0xe2, 0x19, 0x9b, 0xb6, 0x4e,
-	0x47, 0x49, 0xa0, 0xb7, 0x20, 0x4b, 0x5b, 0x57, 0xd8, 0xd6, 0x9a, 0xdd, 0xb5, 0x03, 0x17, 0xa6,
-	0x47, 0x26, 0x27, 0x66, 0x98, 0x01, 0x2e, 0x3d, 0xc1, 0xb9, 0x1f, 0x80, 0x4f, 0x90, 0xe1, 0xc4,
-	0x0d, 0x4e, 0x19, 0xea, 0x0f, 0x00, 0x5f, 0x81, 0xd9, 0x95, 0x64, 0x07, 0x47, 0x76, 0x73, 0xb1,
-	0xd7, 0xbb, 0xbf, 0xff, 0xfb, 0xef, 0xee, 0xd3, 0x7b, 0x32, 0x00, 0x75, 0x9f, 0x72, 0x7b, 0x40,
-	0x09, 0x27, 0x08, 0xf9, 0xc4, 0xeb, 0x62, 0x6a, 0xb3, 0x63, 0x97, 0xf6, 0xbb, 0x01, 0xb7, 0x47,
-	0xef, 0x19, 0xcb, 0xa4, 0xfd, 0x25, 0xf6, 0x38, 0x8b, 0x10, 0xa3, 0xc0, 0xbf, 0x19, 0xe0, 0xe4,
-	0xc7, 0x56, 0x27, 0xe0, 0xcf, 0x86, 0x6d, 0xdb, 0x23, 0xfd, 0x8a, 0x47, 0x28, 0x26, 0xac, 0x82,
-	0xb9, 0xe7, 0x57, 0x44, 0x48, 0xf9, 0x31, 0x68, 0x57, 0xa6, 0xe1, 0x8d, 0x37, 0x3a, 0xa4, 0x43,
-	0xe4, 0xb0, 0x22, 0x46, 0xf1, 0xec, 0xda, 0xa0, 0x37, 0xec, 0x04, 0x61, 0x25, 0xfa, 0x8a, 0x26,
-	0xad, 0x97, 0x2a, 0x80, 0xe3, 0x3e, 0xe5, 0x8f, 0x70, 0xbf, 0x8d, 0x29, 0xba, 0x05, 0x79, 0x11,
-	0xe7, 0x28, 0xf0, 0x75, 0xb5, 0xa4, 0x96, 0xb5, 0x1a, 0x8c, 0xcf, 0x36, 0x73, 0x02, 0x68, 0xee,
-	0x3a, 0x39, 0xb1, 0xd4, 0xf4, 0x05, 0x14, 0x12, 0x1f, 0x0b, 0x28, 0x53, 0x52, 0xcb, 0x4b, 0x11,
-	0xd4, 0x22, 0x3e, 0x16, 0x90, 0x58, 0x6a, 0xfa, 0x08, 0x81, 0xe6, 0xfa, 0x3e, 0xd5, 0xb3, 0x82,
-	0x70, 0xe4, 0x18, 0xd5, 0x20, 0xc7, 0xb8, 0xcb, 0x87, 0x4c, 0xd7, 0x4a, 0x6a, 0xb9, 0x50, 0x7d,
-	0xc7, 0xbe, 0x78, 0x0f, 0xf6, 0x74, 0x37, 0xfb, 0x92, 0xad, 0x69, 0xa7, 0x67, 0x9b, 0x8a, 0x13,
-	0x2b, 0xad, 0x9b, 0x50, 0xf8, 0x94, 0x04, 0xa1, 0x83, 0xbf, 0x1a, 0x62, 0xc6, 0x27, 0x36, 0xea,
-	0xd4, 0xc6, 0xfa, 0x51, 0x85, 0x6b, 0x11, 0xc3, 0x06, 0x24, 0x64, 0xf8, 0x72, 0xa7, 0xfa, 0x08,
-	0xf2, 0x7d, 0x69, 0xcb, 0xf4, 0x4c, 0x29, 0x5b, 0x2e, 0x54, 0xcd, 0xc5, 0xbb, 0x73, 0x12, 0x1c,
-	0xdd, 0x86, 0x22, 0xc5, 0x7d, 0x32, 0xc2, 0xfe, 0x51, 0x12, 0x21, 0x5b, 0xca, 0x96, 0x35, 0x67,
-	0x25, 0x9e, 0x8e, 0x04, 0xcc, 0xaa, 0xc1, 0xb5, 0x87, 0xd8, 0x1d, 0xe1, 0x64, 0xf3, 0x55, 0xd0,
-	0xc4, 0x6d, 0xc9, 0x4d, 0xbd, 0xde, 0x4f, 0xb2, 0x56, 0x11, 0x96, 0xe3, 0x18, 0xd1, 0xe1, 0xac,
-	0x87, 0x70, 0xfd, 0x31, 0x25, 0x1e, 0x66, 0x2c, 0x62, 0x19, 0x73, 0x3b, 0x13, 0x87, 0x3b, 0xe2,
-	0x50, 0x72, 0x26, 0x36, 0x29, 0xda, 0xd1, 0xe3, 0x62, 0x27, 0x60, 0xb2, 0x7e, 0x4f, 0x7b, 0xfe,
-	0x93, 0xa5, 0x58, 0x37, 0xc0, 0x48, 0x8b, 0x16, 0x7b, 0x7d, 0x02, 0xeb, 0x0e, 0x66, 0xa4, 0x37,
-	0xc2, 0xdb, 0xbe, 0x4f, 0x05, 0x14, 0xfb, 0x5c, 0xe6, 0x86, 0xad, 0x77, 0x61, 0x63, 0x56, 0x1d,
-	0x27, 0x28, 0x2d, 0x8b, 0x3d, 0x58, 0x6b, 0x86, 0x1c, 0xd3, 0xd0, 0xed, 0x89, 0x38, 0x89, 0xd3,
-	0x06, 0x64, 0x26, 0x26, 0xb9, 0xf1, 0xd9, 0x66, 0xa6, 0xb9, 0xeb, 0x64, 0x02, 0x1f, 0xdd, 0x87,
-	0x9c, 0xeb, 0xf1, 0x80, 0x84, 0x71, 0xf6, 0x36, 0xd3, 0x6e, 0x73, 0x9f, 0x13, 0x8a, 0xb7, 0x25,
-	0x96, 0x3c, 0x56, 0x91, 0xc8, 0xfa, 0x5e, 0x83, 0xc2, 0xb9, 0x55, 0xf4, 0xf1, 0x24, 0x9c, 0xb0,
-	0x5a, 0xa9, 0xde, 0x7a, 0x4d, 0xb8, 0x07, 0x41, 0xe8, 0x27, 0xc1, 0x90, 0x1d, 0xe7, 0x35, 0x23,
-	0xaf, 0x5c, 0x4f, 0x93, 0x8a, 0x6a, 0x69, 0x28, 0x51, 0x4e, 0xd1, 0x87, 0x90, 0x67, 0x98, 0x8e,
-	0x02, 0x0f, 0xcb, 0x72, 0x29, 0x54, 0xdf, 0x4a, 0x75, 0x8b, 0x90, 0x86, 0xe2, 0x24, 0xb4, 0x30,
-	0xe2, 0x2e, 0xeb, 0xc6, 0xe5, 0x94, 0x6a, 0x74, 0xe0, 0xb2, 0xae, 0x30, 0x12, 0x9c, 0x30, 0x0a,
-	0x31, 0x3f, 0x26, 0xb4, 0xab, 0x5f, 0x99, 0x6f, 0xd4, 0x8a, 0x10, 0x61, 0x14, 0xd3, 0x42, 0xe8,
-	0xf5, 0x86, 0x8c, 0x63, 0xaa, 0xe7, 0xe6, 0x0b, 0x77, 0x22, 0x44, 0x08, 0x63, 0x1a, 0x7d, 0x00,
-	0x39, 0x86, 0x3d, 0x8a, 0xb9, 0x9e, 0x97, 0x3a, 0x23, 0xfd, 0x64, 0x82, 0x68, 0x88, 0x22, 0x97,
-	0x23, 0x74, 0x0f, 0xae, 0x52, 0xcc, 0xc8, 0x90, 0x7a, 0x58, 0xbf, 0x2a, 0x75, 0x37, 0x52, 0x8b,
-	0x23, 0x66, 0x1a, 0x8a, 0x33, 0xe1, 0xd1, 0x7d, 0x58, 0xc2, 0x5f, 0x73, 0x1c, 0x32, 0x91, 0xbc,
-	0x25, 0x29, 0x7e, 0x3b, 0x4d, 0x5c, 0x4f, 0xa0, 0x86, 0xe2, 0x4c, 0x15, 0xb5, 0xab, 0x90, 0xe3,
-	0x2e, 0xed, 0x60, 0x7e, 0xf7, 0x5f, 0x15, 0x8a, 0x33, 0x19, 0x46, 0xb7, 0x21, 0x7f, 0xd8, 0x7a,
-	0xd0, 0xda, 0xfb, 0xbc, 0xb5, 0xaa, 0x18, 0xc6, 0xc9, 0x8b, 0xd2, 0xc6, 0x0c, 0x71, 0x18, 0x76,
-	0x43, 0x72, 0x1c, 0xa2, 0x2a, 0xac, 0xed, 0x1f, 0xec, 0x39, 0xf5, 0xa3, 0xed, 0x9d, 0x83, 0xe6,
-	0x5e, 0xeb, 0x68, 0xc7, 0xa9, 0x6f, 0x1f, 0xd4, 0x57, 0x55, 0xe3, 0xfa, 0xc9, 0x8b, 0xd2, 0xfa,
-	0x8c, 0x68, 0x87, 0x62, 0x97, 0xe3, 0x0b, 0x9a, 0xc3, 0xc7, 0xbb, 0x42, 0x93, 0x49, 0xd5, 0x1c,
-	0x0e, 0xfc, 0x34, 0x8d, 0x53, 0x7f, 0xb4, 0xf7, 0x59, 0x7d, 0x35, 0x9b, 0xaa, 0x71, 0x64, 0x3b,
-	0x32, 0xde, 0xfc, 0xee, 0x17, 0x53, 0xf9, 0xed, 0x57, 0x73, 0xf6, 0x74, 0xd5, 0x1f, 0x32, 0xa0,
-	0x89, 0x5a, 0x43, 0x27, 0x2a, 0xa0, 0x8b, 0x6d, 0x00, 0x6d, 0xa5, 0xdd, 0xe3, 0xdc, 0xe6, 0x63,
-	0xd8, 0x97, 0xc5, 0xe3, 0xee, 0xb2, 0xfe, 0xfb, 0xcb, 0x7f, 0x7e, 0xce, 0x14, 0x61, 0x59, 0xf2,
-	0x5b, 0x7d, 0x37, 0x74, 0x3b, 0x98, 0xa2, 0x6f, 0x61, 0xe5, 0xff, 0x6d, 0x03, 0xdd, 0x99, 0xf7,
-	0x30, 0x5c, 0x68, 0x4c, 0xc6, 0xdd, 0xcb, 0xa0, 0x0b, 0xfd, 0xab, 0x7f, 0xaa, 0xb0, 0x32, 0x6d,
-	0xc3, 0xec, 0x59, 0x30, 0x40, 0x5f, 0x80, 0x26, 0x5e, 0x30, 0x28, 0xb5, 0xc9, 0x9c, 0x7b, 0x3d,
-	0x19, 0xa5, 0xf9, 0xc0, 0xe2, 0x43, 0x7b, 0x70, 0x45, 0xb6, 0x79, 0x94, 0x1a, 0xe1, 0xfc, 0x5b,
-	0xc4, 0xb8, 0xb9, 0x80, 0x58, 0x68, 0x52, 0xd3, 0x4f, 0x5f, 0x99, 0xca, 0x5f, 0xaf, 0x4c, 0xe5,
-	0xf9, 0xd8, 0x54, 0x4f, 0xc7, 0xa6, 0xfa, 0xc7, 0xd8, 0x54, 0xff, 0x1e, 0x9b, 0xea, 0x93, 0xec,
-	0x13, 0xad, 0x9d, 0x93, 0xff, 0x10, 0xde, 0xff, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x98, 0x55, 0x8d,
-	0x81, 0xb9, 0x08, 0x00, 0x00,
+	// 949 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x96, 0x4f, 0x6f, 0x1b, 0x45,
+	0x18, 0xc6, 0x77, 0xed, 0xad, 0x9d, 0xbc, 0x6e, 0xe2, 0x68, 0x42, 0xc2, 0x76, 0x29, 0x8e, 0xbb,
+	0x45, 0xaa, 0x5b, 0x91, 0xb5, 0x30, 0x48, 0xa0, 0x42, 0x0f, 0xb1, 0x63, 0xc9, 0xa6, 0xad, 0x53,
+	0x6d, 0x12, 0xe8, 0x2d, 0xac, 0x77, 0x27, 0xee, 0x62, 0x7b, 0xc7, 0xcc, 0x8c, 0x1d, 0xb8, 0xa0,
+	0x1e, 0x51, 0xae, 0x48, 0xc0, 0xa5, 0x27, 0x38, 0xf7, 0x03, 0xf0, 0x01, 0x50, 0xc4, 0x89, 0x1b,
+	0x9c, 0x22, 0xea, 0x0f, 0x00, 0x5f, 0x01, 0xcd, 0xec, 0xae, 0x1d, 0x9c, 0xb5, 0x9b, 0x8b, 0x3d,
+	0x9e, 0xf9, 0x3d, 0xef, 0xf3, 0xce, 0xbf, 0x77, 0x0c, 0x40, 0x9d, 0x63, 0x6e, 0x0d, 0x28, 0xe1,
+	0x04, 0x21, 0x8f, 0xb8, 0x5d, 0x4c, 0x2d, 0x76, 0xe2, 0xd0, 0x7e, 0xd7, 0xe7, 0xd6, 0xe8, 0x3d,
+	0x63, 0x85, 0xb4, 0xbf, 0xc4, 0x2e, 0x67, 0x21, 0x62, 0xe4, 0xf8, 0x37, 0x03, 0x1c, 0xff, 0xd8,
+	0xee, 0xf8, 0xfc, 0xd9, 0xb0, 0x6d, 0xb9, 0xa4, 0x5f, 0x76, 0x09, 0xc5, 0x84, 0x95, 0x31, 0x77,
+	0xbd, 0xb2, 0x08, 0x29, 0x3f, 0x06, 0xed, 0xf2, 0x34, 0xbc, 0xf1, 0x46, 0x87, 0x74, 0x88, 0x6c,
+	0x96, 0x45, 0x2b, 0xea, 0x5d, 0x1f, 0xf4, 0x86, 0x1d, 0x3f, 0x28, 0x87, 0x5f, 0x61, 0xa7, 0xf9,
+	0x52, 0x05, 0xb0, 0x9d, 0x63, 0xfe, 0x18, 0xf7, 0xdb, 0x98, 0xa2, 0xdb, 0x90, 0x15, 0x71, 0x8e,
+	0x7c, 0x4f, 0x57, 0x8b, 0x6a, 0x49, 0xab, 0xc2, 0xf8, 0x7c, 0x2b, 0x23, 0x80, 0xe6, 0xae, 0x9d,
+	0x11, 0x43, 0x4d, 0x4f, 0x40, 0x01, 0xf1, 0xb0, 0x80, 0x52, 0x45, 0xb5, 0xb4, 0x1c, 0x42, 0x2d,
+	0xe2, 0x61, 0x01, 0x89, 0xa1, 0xa6, 0x87, 0x10, 0x68, 0x8e, 0xe7, 0x51, 0x3d, 0x2d, 0x08, 0x5b,
+	0xb6, 0x51, 0x15, 0x32, 0x8c, 0x3b, 0x7c, 0xc8, 0x74, 0xad, 0xa8, 0x96, 0x72, 0x95, 0x77, 0xac,
+	0xcb, 0xeb, 0x60, 0x4d, 0xb3, 0xd9, 0x97, 0x6c, 0x55, 0x3b, 0x3b, 0xdf, 0x52, 0xec, 0x48, 0x69,
+	0xde, 0x82, 0xdc, 0xa7, 0xc4, 0x0f, 0x6c, 0xfc, 0xd5, 0x10, 0x33, 0x3e, 0xb1, 0x51, 0xa7, 0x36,
+	0xe6, 0x0f, 0x2a, 0x5c, 0x0f, 0x19, 0x36, 0x20, 0x01, 0xc3, 0x57, 0x9b, 0xd5, 0x47, 0x90, 0xed,
+	0x4b, 0x5b, 0xa6, 0xa7, 0x8a, 0xe9, 0x52, 0xae, 0x52, 0x58, 0x9c, 0x9d, 0x1d, 0xe3, 0xe8, 0x0e,
+	0xe4, 0x29, 0xee, 0x93, 0x11, 0xf6, 0x8e, 0xe2, 0x08, 0xe9, 0x62, 0xba, 0xa4, 0xd9, 0xab, 0x51,
+	0x77, 0x28, 0x60, 0x66, 0x15, 0xae, 0x3f, 0xc2, 0xce, 0x08, 0xc7, 0xc9, 0x57, 0x40, 0x13, 0xab,
+	0x25, 0x93, 0x7a, 0xbd, 0x9f, 0x64, 0xcd, 0x3c, 0xac, 0x44, 0x31, 0xc2, 0xc9, 0x99, 0x8f, 0xe0,
+	0xc6, 0x13, 0x4a, 0x5c, 0xcc, 0x58, 0xc8, 0x32, 0xe6, 0x74, 0x26, 0x0e, 0x77, 0xc5, 0xa4, 0x64,
+	0x4f, 0x64, 0x92, 0xb7, 0xc2, 0xe3, 0x62, 0xc5, 0x60, 0x3c, 0x7e, 0x5f, 0x7b, 0xfe, 0xa3, 0xa9,
+	0x98, 0x37, 0xc1, 0x48, 0x8a, 0x16, 0x79, 0x7d, 0x02, 0x1b, 0x36, 0x66, 0xa4, 0x37, 0xc2, 0x3b,
+	0x9e, 0x47, 0x05, 0x14, 0xf9, 0x5c, 0x65, 0x85, 0xcd, 0x77, 0x61, 0x73, 0x56, 0x1d, 0x6d, 0x50,
+	0xd2, 0x2e, 0xf6, 0x60, 0xbd, 0x19, 0x70, 0x4c, 0x03, 0xa7, 0x27, 0xe2, 0xc4, 0x4e, 0x9b, 0x90,
+	0x9a, 0x98, 0x64, 0xc6, 0xe7, 0x5b, 0xa9, 0xe6, 0xae, 0x9d, 0xf2, 0x3d, 0xf4, 0x00, 0x32, 0x8e,
+	0xcb, 0x7d, 0x12, 0x44, 0xbb, 0xb7, 0x95, 0xb4, 0x9a, 0xfb, 0x9c, 0x50, 0xbc, 0x23, 0xb1, 0xf8,
+	0x58, 0x85, 0x22, 0xf3, 0x37, 0x0d, 0x72, 0x17, 0x46, 0xd1, 0xc7, 0x93, 0x70, 0xc2, 0x6a, 0xb5,
+	0x72, 0xfb, 0x35, 0xe1, 0x1e, 0xfa, 0x81, 0x17, 0x07, 0x43, 0x56, 0xb4, 0xaf, 0x29, 0xb9, 0xe4,
+	0x7a, 0x92, 0x54, 0xdc, 0x96, 0x86, 0x12, 0xee, 0x29, 0xfa, 0x10, 0xb2, 0x0c, 0xd3, 0x91, 0xef,
+	0x62, 0x79, 0x5d, 0x72, 0x95, 0xb7, 0x12, 0xdd, 0x42, 0xa4, 0xa1, 0xd8, 0x31, 0x2d, 0x8c, 0xb8,
+	0xc3, 0xba, 0xd1, 0x75, 0x4a, 0x34, 0x3a, 0x70, 0x58, 0x57, 0x18, 0x09, 0x4e, 0x18, 0x05, 0x98,
+	0x9f, 0x10, 0xda, 0xd5, 0xaf, 0xcd, 0x37, 0x6a, 0x85, 0x88, 0x30, 0x8a, 0x68, 0x21, 0x74, 0x7b,
+	0x43, 0xc6, 0x31, 0xd5, 0x33, 0xf3, 0x85, 0xb5, 0x10, 0x11, 0xc2, 0x88, 0x46, 0x1f, 0x40, 0x86,
+	0x61, 0x97, 0x62, 0xae, 0x67, 0xa5, 0xce, 0x48, 0x9e, 0x99, 0x20, 0x1a, 0xe2, 0x92, 0xcb, 0x16,
+	0xba, 0x0f, 0x4b, 0x14, 0x33, 0x32, 0xa4, 0x2e, 0xd6, 0x97, 0xa4, 0xee, 0x66, 0xe2, 0xe5, 0x88,
+	0x98, 0x86, 0x62, 0x4f, 0x78, 0xf4, 0x00, 0x96, 0xf1, 0xd7, 0x1c, 0x07, 0x4c, 0x6c, 0xde, 0xb2,
+	0x14, 0xbf, 0x9d, 0x24, 0xae, 0xc7, 0x50, 0x43, 0xb1, 0xa7, 0x0a, 0x91, 0xb0, 0x4b, 0x82, 0x63,
+	0xbf, 0xa3, 0xc3, 0xfc, 0x84, 0x6b, 0x92, 0x10, 0x09, 0x87, 0x6c, 0x75, 0x09, 0x32, 0xdc, 0xa1,
+	0x1d, 0xcc, 0xef, 0xfd, 0xab, 0x42, 0x7e, 0xe6, 0x5c, 0xa0, 0x3b, 0x90, 0x3d, 0x6c, 0x3d, 0x6c,
+	0xed, 0x7d, 0xde, 0x5a, 0x53, 0x0c, 0xe3, 0xf4, 0x45, 0x71, 0x73, 0x86, 0x38, 0x0c, 0xba, 0x01,
+	0x39, 0x09, 0x50, 0x05, 0xd6, 0xf7, 0x0f, 0xf6, 0xec, 0xfa, 0xd1, 0x4e, 0xed, 0xa0, 0xb9, 0xd7,
+	0x3a, 0xaa, 0xd9, 0xf5, 0x9d, 0x83, 0xfa, 0x9a, 0x6a, 0xdc, 0x38, 0x7d, 0x51, 0xdc, 0x98, 0x11,
+	0xd5, 0x28, 0x76, 0x38, 0xbe, 0xa4, 0x39, 0x7c, 0xb2, 0x2b, 0x34, 0xa9, 0x44, 0xcd, 0xe1, 0xc0,
+	0x4b, 0xd2, 0xd8, 0xf5, 0xc7, 0x7b, 0x9f, 0xd5, 0xd7, 0xd2, 0x89, 0x1a, 0x5b, 0x16, 0x31, 0xe3,
+	0xcd, 0xef, 0x7e, 0x2e, 0x28, 0xbf, 0xfe, 0x52, 0x98, 0x9d, 0x5d, 0xe5, 0xfb, 0x14, 0x68, 0xe2,
+	0x86, 0xa2, 0x53, 0x15, 0xd0, 0xe5, 0xe2, 0x81, 0xb6, 0x93, 0x56, 0x70, 0x6e, 0xc9, 0x32, 0xac,
+	0xab, 0xe2, 0x51, 0x4d, 0xda, 0xf8, 0xfd, 0xe5, 0x3f, 0x3f, 0xa5, 0xf2, 0xb0, 0x22, 0xf9, 0xed,
+	0xbe, 0x13, 0x38, 0x1d, 0x4c, 0xd1, 0xb7, 0xb0, 0xfa, 0xff, 0x62, 0x83, 0xee, 0xce, 0x3b, 0x42,
+	0x97, 0xca, 0x99, 0x71, 0xef, 0x2a, 0xe8, 0x42, 0xff, 0xca, 0x9f, 0x2a, 0xac, 0x4e, 0x8b, 0x37,
+	0x7b, 0xe6, 0x0f, 0xd0, 0x17, 0xa0, 0x89, 0x67, 0x09, 0x25, 0x96, 0xa6, 0x0b, 0x8f, 0x9a, 0x51,
+	0x9c, 0x0f, 0x2c, 0x9e, 0xb4, 0x0b, 0xd7, 0xe4, 0xe3, 0x80, 0x12, 0x23, 0x5c, 0x7c, 0x7b, 0x8c,
+	0x5b, 0x0b, 0x88, 0x85, 0x26, 0x55, 0xfd, 0xec, 0x55, 0x41, 0xf9, 0xeb, 0x55, 0x41, 0x79, 0x3e,
+	0x2e, 0xa8, 0x67, 0xe3, 0x82, 0xfa, 0xc7, 0xb8, 0xa0, 0xfe, 0x3d, 0x2e, 0xa8, 0x4f, 0xd3, 0x4f,
+	0xb5, 0x76, 0x46, 0xfe, 0xaf, 0x78, 0xff, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x70, 0x31, 0xfd,
+	0xe7, 0xef, 0x08, 0x00, 0x00,
 }

+ 1 - 0
vendor/github.com/docker/swarmkit/api/raft.proto

@@ -127,5 +127,6 @@ message StoreAction {
 		Secret secret = 7;
 		Resource resource = 8;
 		Extension extension = 9;
+		Config config = 10;
 	}
 }

+ 90 - 30
vendor/github.com/docker/swarmkit/api/snapshot.pb.go

@@ -51,6 +51,7 @@ type StoreSnapshot struct {
 	Secrets    []*Secret    `protobuf:"bytes,6,rep,name=secrets" json:"secrets,omitempty"`
 	Resources  []*Resource  `protobuf:"bytes,7,rep,name=resources" json:"resources,omitempty"`
 	Extensions []*Extension `protobuf:"bytes,8,rep,name=extensions" json:"extensions,omitempty"`
+	Configs    []*Config    `protobuf:"bytes,9,rep,name=configs" json:"configs,omitempty"`
 }
 
 func (m *StoreSnapshot) Reset()                    { *m = StoreSnapshot{} }
@@ -161,6 +162,14 @@ func (m *StoreSnapshot) CopyFrom(src interface{}) {
 		}
 	}
 
+	if o.Configs != nil {
+		m.Configs = make([]*Config, len(o.Configs))
+		for i := range m.Configs {
+			m.Configs[i] = &Config{}
+			github_com_docker_swarmkit_api_deepcopy.Copy(m.Configs[i], o.Configs[i])
+		}
+	}
+
 }
 
 func (m *ClusterSnapshot) Copy() *ClusterSnapshot {
@@ -319,6 +328,18 @@ func (m *StoreSnapshot) MarshalTo(dAtA []byte) (int, error) {
 			i += n
 		}
 	}
+	if len(m.Configs) > 0 {
+		for _, msg := range m.Configs {
+			dAtA[i] = 0x4a
+			i++
+			i = encodeVarintSnapshot(dAtA, i, uint64(msg.Size()))
+			n, err := msg.MarshalTo(dAtA[i:])
+			if err != nil {
+				return 0, err
+			}
+			i += n
+		}
+	}
 	return i, nil
 }
 
@@ -487,6 +508,12 @@ func (m *StoreSnapshot) Size() (n int) {
 			n += 1 + l + sovSnapshot(uint64(l))
 		}
 	}
+	if len(m.Configs) > 0 {
+		for _, e := range m.Configs {
+			l = e.Size()
+			n += 1 + l + sovSnapshot(uint64(l))
+		}
+	}
 	return n
 }
 
@@ -548,6 +575,7 @@ func (this *StoreSnapshot) String() string {
 		`Secrets:` + strings.Replace(fmt.Sprintf("%v", this.Secrets), "Secret", "Secret", 1) + `,`,
 		`Resources:` + strings.Replace(fmt.Sprintf("%v", this.Resources), "Resource", "Resource", 1) + `,`,
 		`Extensions:` + strings.Replace(fmt.Sprintf("%v", this.Extensions), "Extension", "Extension", 1) + `,`,
+		`Configs:` + strings.Replace(fmt.Sprintf("%v", this.Configs), "Config", "Config", 1) + `,`,
 		`}`,
 	}, "")
 	return s
@@ -860,6 +888,37 @@ func (m *StoreSnapshot) Unmarshal(dAtA []byte) error {
 				return err
 			}
 			iNdEx = postIndex
+		case 9:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Configs", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowSnapshot
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthSnapshot
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Configs = append(m.Configs, &Config{})
+			if err := m.Configs[len(m.Configs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipSnapshot(dAtA[iNdEx:])
@@ -1261,34 +1320,35 @@ var (
 func init() { proto.RegisterFile("snapshot.proto", fileDescriptorSnapshot) }
 
 var fileDescriptorSnapshot = []byte{
-	// 449 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x7c, 0x93, 0xbf, 0x6f, 0xd3, 0x40,
-	0x14, 0xc7, 0x73, 0xf9, 0xe5, 0xf0, 0xaa, 0x16, 0x38, 0x31, 0x9c, 0x02, 0x98, 0x10, 0x18, 0x32,
-	0x19, 0x08, 0x48, 0x20, 0xa4, 0x32, 0x14, 0x31, 0x30, 0xd0, 0xe1, 0x82, 0x2a, 0x56, 0xc7, 0x79,
-	0x6d, 0x83, 0x89, 0x2f, 0xba, 0x77, 0x75, 0x19, 0xf9, 0xf3, 0x22, 0xb1, 0x30, 0x32, 0x21, 0xea,
-	0x85, 0x7f, 0x03, 0xdd, 0x9d, 0x6d, 0x22, 0xe1, 0x74, 0xbb, 0x44, 0x9f, 0xcf, 0xfb, 0xbe, 0xbb,
-	0xf7, 0x0c, 0x07, 0x94, 0xc5, 0x6b, 0x3a, 0x57, 0x26, 0x5a, 0x6b, 0x65, 0x14, 0xe7, 0x0b, 0x95,
-	0xa4, 0xa8, 0x23, 0xba, 0x8c, 0xf5, 0x2a, 0x5d, 0x9a, 0x28, 0x7f, 0x36, 0xdc, 0x57, 0xf3, 0xcf,
-	0x98, 0x18, 0xf2, 0xc8, 0x10, 0x74, 0x7c, 0x5a, 0xe2, 0xc3, 0x3b, 0x67, 0xea, 0x4c, 0xb9, 0xe3,
-	0x13, 0x7b, 0xf2, 0xff, 0x8e, 0xbf, 0x77, 0x60, 0x7f, 0x66, 0x94, 0xc6, 0x59, 0x59, 0x9c, 0x47,
-	0xd0, 0xcb, 0xd4, 0x02, 0x49, 0xb0, 0x51, 0x67, 0xb2, 0x37, 0x15, 0xd1, 0xff, 0x31, 0xd1, 0xb1,
-	0x5a, 0xa0, 0xf4, 0x18, 0x7f, 0x09, 0x03, 0x42, 0x9d, 0x2f, 0x13, 0x24, 0xd1, 0x76, 0xca, 0xdd,
-	0x26, 0x65, 0xe6, 0x19, 0x59, 0xc3, 0x56, 0xcc, 0xd0, 0x5c, 0x2a, 0x9d, 0x92, 0xe8, 0xec, 0x16,
-	0x8f, 0x3d, 0x23, 0x6b, 0xd8, 0x76, 0x68, 0x62, 0x4a, 0x49, 0x74, 0x77, 0x77, 0xf8, 0x31, 0xa6,
-	0x54, 0x7a, 0xcc, 0x06, 0x25, 0x5f, 0x2e, 0xc8, 0xa0, 0x26, 0xd1, 0xdb, 0x1d, 0xf4, 0xd6, 0x33,
-	0xb2, 0x86, 0xf9, 0x0b, 0x08, 0x08, 0x13, 0x8d, 0x86, 0x44, 0xdf, 0x79, 0xc3, 0xe6, 0x9b, 0x59,
-	0x44, 0x56, 0x28, 0x7f, 0x0d, 0x37, 0x34, 0x92, 0xba, 0xd0, 0xf6, 0x45, 0x02, 0xe7, 0xdd, 0x6b,
-	0xf2, 0x64, 0x09, 0xc9, 0x7f, 0x38, 0x3f, 0x04, 0xc0, 0xaf, 0x06, 0x33, 0x5a, 0xaa, 0x8c, 0xc4,
-	0xc0, 0xc9, 0xf7, 0x9b, 0xe4, 0x77, 0x15, 0x25, 0xb7, 0x84, 0x31, 0xc2, 0xcd, 0xf2, 0x16, 0xf5,
-	0x38, 0x5f, 0x41, 0xb0, 0xc2, 0xd5, 0xdc, 0xde, 0xdd, 0x0f, 0x34, 0x6c, 0xec, 0x25, 0x3e, 0x35,
-	0x1f, 0x1c, 0x26, 0x2b, 0x9c, 0x0b, 0x08, 0x34, 0xae, 0x54, 0x8e, 0x0b, 0x37, 0xd7, 0xae, 0xac,
-	0x7e, 0x8e, 0xff, 0x30, 0x18, 0xd4, 0x01, 0x6f, 0x20, 0xc8, 0x51, 0xdb, 0x7c, 0xc1, 0x46, 0x6c,
-	0x72, 0x30, 0x7d, 0xdc, 0xf8, 0x48, 0xd5, 0xee, 0x9e, 0x78, 0x56, 0x56, 0x12, 0x7f, 0x0f, 0x50,
-	0x26, 0x9e, 0x2f, 0xd7, 0xa2, 0x3d, 0x62, 0x93, 0xbd, 0xe9, 0xa3, 0x6b, 0xe6, 0x53, 0x55, 0x3a,
-	0xea, 0x6e, 0x7e, 0x3d, 0x68, 0xc9, 0x2d, 0x99, 0x1f, 0x42, 0x8f, 0xec, 0x2e, 0x8b, 0x8e, 0xab,
-	0xf2, 0xb0, 0xb1, 0x91, 0xed, 0x65, 0x2f, 0x6b, 0x78, 0x6b, 0x7c, 0x1b, 0x82, 0xb2, 0x3b, 0xde,
-	0x87, 0xf6, 0xc9, 0xd3, 0x5b, 0xad, 0x23, 0xb1, 0xb9, 0x0a, 0x5b, 0x3f, 0xaf, 0xc2, 0xd6, 0xb7,
-	0x22, 0x64, 0x9b, 0x22, 0x64, 0x3f, 0x8a, 0x90, 0xfd, 0x2e, 0x42, 0xf6, 0xa9, 0x3d, 0xef, 0xbb,
-	0x2f, 0xe8, 0xf9, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x91, 0xfe, 0xed, 0x18, 0x98, 0x03, 0x00,
-	0x00,
+	// 466 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x7c, 0x93, 0x3f, 0x6f, 0x13, 0x4d,
+	0x10, 0x87, 0xbd, 0xfe, 0x77, 0xce, 0x44, 0xc9, 0xfb, 0xb2, 0xa2, 0x58, 0x19, 0x38, 0x8c, 0xa1,
+	0x70, 0x75, 0x80, 0x41, 0x02, 0x21, 0x85, 0x22, 0x11, 0x05, 0x05, 0x29, 0xd6, 0x28, 0xa2, 0x3d,
+	0x9f, 0xc7, 0xce, 0x71, 0xf8, 0xd6, 0xda, 0xd9, 0x38, 0x94, 0xf0, 0xed, 0x5c, 0x52, 0x52, 0x21,
+	0xe2, 0x86, 0xaf, 0x81, 0x76, 0xf7, 0xee, 0xb0, 0xc4, 0x99, 0x6e, 0x6d, 0x3d, 0xcf, 0xcc, 0x6f,
+	0xf7, 0x66, 0xe0, 0x98, 0xf2, 0x78, 0x45, 0x97, 0xca, 0x44, 0x2b, 0xad, 0x8c, 0xe2, 0x7c, 0xa6,
+	0x92, 0x0c, 0x75, 0x44, 0xd7, 0xb1, 0x5e, 0x66, 0xa9, 0x89, 0xd6, 0x4f, 0xfb, 0x47, 0x6a, 0xfa,
+	0x11, 0x13, 0x43, 0x1e, 0xe9, 0x83, 0x8e, 0xe7, 0x05, 0xde, 0xbf, 0xbd, 0x50, 0x0b, 0xe5, 0x8e,
+	0x8f, 0xed, 0xc9, 0xff, 0x3b, 0xfc, 0xda, 0x86, 0xa3, 0x89, 0x51, 0x1a, 0x27, 0x45, 0x71, 0x1e,
+	0x41, 0x27, 0x57, 0x33, 0x24, 0xc1, 0x06, 0xad, 0xd1, 0xe1, 0x58, 0x44, 0x7f, 0xb7, 0x89, 0xce,
+	0xd5, 0x0c, 0xa5, 0xc7, 0xf8, 0x0b, 0xe8, 0x11, 0xea, 0x75, 0x9a, 0x20, 0x89, 0xa6, 0x53, 0xee,
+	0xd4, 0x29, 0x13, 0xcf, 0xc8, 0x0a, 0xb6, 0x62, 0x8e, 0xe6, 0x5a, 0xe9, 0x8c, 0x44, 0x6b, 0xbf,
+	0x78, 0xee, 0x19, 0x59, 0xc1, 0x36, 0xa1, 0x89, 0x29, 0x23, 0xd1, 0xde, 0x9f, 0xf0, 0x7d, 0x4c,
+	0x99, 0xf4, 0x98, 0x6d, 0x94, 0x7c, 0xba, 0x22, 0x83, 0x9a, 0x44, 0x67, 0x7f, 0xa3, 0x33, 0xcf,
+	0xc8, 0x0a, 0xe6, 0xcf, 0x21, 0x20, 0x4c, 0x34, 0x1a, 0x12, 0x5d, 0xe7, 0xf5, 0xeb, 0x6f, 0x66,
+	0x11, 0x59, 0xa2, 0xfc, 0x15, 0x1c, 0x68, 0x24, 0x75, 0xa5, 0xed, 0x8b, 0x04, 0xce, 0xbb, 0x5b,
+	0xe7, 0xc9, 0x02, 0x92, 0x7f, 0x70, 0x7e, 0x02, 0x80, 0x9f, 0x0d, 0xe6, 0x94, 0xaa, 0x9c, 0x44,
+	0xcf, 0xc9, 0xf7, 0xea, 0xe4, 0x37, 0x25, 0x25, 0x77, 0x04, 0x1b, 0x38, 0x51, 0xf9, 0x3c, 0x5d,
+	0x90, 0x38, 0xd8, 0x1f, 0xf8, 0xcc, 0x21, 0xb2, 0x44, 0x87, 0x08, 0xff, 0x15, 0x77, 0xaf, 0x86,
+	0xe0, 0x25, 0x04, 0x4b, 0x5c, 0x4e, 0xed, 0x8b, 0xf9, 0x31, 0x08, 0x6b, 0x6f, 0x10, 0xcf, 0xcd,
+	0x3b, 0x87, 0xc9, 0x12, 0xe7, 0x02, 0x02, 0x8d, 0x4b, 0xb5, 0xc6, 0x99, 0x9b, 0x86, 0xb6, 0x2c,
+	0x7f, 0x0e, 0x7f, 0x31, 0xe8, 0x55, 0x0d, 0x5e, 0x43, 0xb0, 0x46, 0x6d, 0x53, 0x0b, 0x36, 0x60,
+	0xa3, 0xe3, 0xf1, 0xa3, 0xda, 0xa7, 0x2d, 0x27, 0xfe, 0xc2, 0xb3, 0xb2, 0x94, 0xf8, 0x5b, 0x80,
+	0xa2, 0xe3, 0x65, 0xba, 0x12, 0xcd, 0x01, 0x1b, 0x1d, 0x8e, 0x1f, 0xfe, 0xe3, 0xab, 0x96, 0x95,
+	0x4e, 0xdb, 0x9b, 0x1f, 0xf7, 0x1b, 0x72, 0x47, 0xe6, 0x27, 0xd0, 0x21, 0xbb, 0x01, 0xa2, 0xe5,
+	0xaa, 0x3c, 0xa8, 0x0d, 0xb2, 0xbb, 0x22, 0x45, 0x0d, 0x6f, 0x0d, 0x6f, 0x41, 0x50, 0xa4, 0xe3,
+	0x5d, 0x68, 0x5e, 0x3c, 0xf9, 0xbf, 0x71, 0x2a, 0x36, 0x37, 0x61, 0xe3, 0xfb, 0x4d, 0xd8, 0xf8,
+	0xb2, 0x0d, 0xd9, 0x66, 0x1b, 0xb2, 0x6f, 0xdb, 0x90, 0xfd, 0xdc, 0x86, 0xec, 0x43, 0x73, 0xda,
+	0x75, 0x7b, 0xf7, 0xec, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8f, 0x41, 0x5b, 0x51, 0xce, 0x03,
+	0x00, 0x00,
 }

+ 1 - 0
vendor/github.com/docker/swarmkit/api/snapshot.proto

@@ -22,6 +22,7 @@ message StoreSnapshot {
 	repeated Secret secrets = 6;
 	repeated Resource resources = 7;
 	repeated Extension extensions = 8;
+	repeated Config configs = 9;
 }
 
 // ClusterSnapshot stores cluster membership information in snapshots.

+ 458 - 137
vendor/github.com/docker/swarmkit/api/specs.pb.go

@@ -522,6 +522,8 @@ type ContainerSpec struct {
 	User string `protobuf:"bytes,7,opt,name=user,proto3" json:"user,omitempty"`
 	// Groups specifies supplementary groups available to the user.
 	Groups []string `protobuf:"bytes,11,rep,name=groups" json:"groups,omitempty"`
+	// Privileges specifies security configuration/permissions.
+	Privileges *Privileges `protobuf:"bytes,22,opt,name=privileges" json:"privileges,omitempty"`
 	// TTY declares that a TTY should be attached to the standard streams,
 	// including stdin if it is still open.
 	TTY bool `protobuf:"varint,13,opt,name=tty,proto3" json:"tty,omitempty"`
@@ -544,6 +546,9 @@ type ContainerSpec struct {
 	// SecretReference contains references to zero or more secrets that
 	// will be exposed to the container.
 	Secrets []*SecretReference `protobuf:"bytes,12,rep,name=secrets" json:"secrets,omitempty"`
+	// ConfigReference contains references to zero or more configs that
+	// will be exposed to the container.
+	Configs []*ConfigReference `protobuf:"bytes,21,rep,name=configs" json:"configs,omitempty"`
 	// Hosts allow additional entries to be specified in /etc/hosts
 	// that associates IP addresses with hostnames.
 	// Detailed documentation is available in:
@@ -679,6 +684,19 @@ func (m *SecretSpec) Reset()                    { *m = SecretSpec{} }
 func (*SecretSpec) ProtoMessage()               {}
 func (*SecretSpec) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{11} }
 
+// ConfigSpec specifies user-provided configuration files.
+type ConfigSpec struct {
+	Annotations Annotations `protobuf:"bytes,1,opt,name=annotations" json:"annotations"`
+	// Data is the config payload - the maximum size is 500KB (that is, 500*1024 bytes)
+	// TODO(aaronl): Do we want to revise this to include multiple payloads in a single
+	// ConfigSpec? Define this to be a tar? etc...
+	Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+}
+
+func (m *ConfigSpec) Reset()                    { *m = ConfigSpec{} }
+func (*ConfigSpec) ProtoMessage()               {}
+func (*ConfigSpec) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{12} }
+
 func init() {
 	proto.RegisterType((*NodeSpec)(nil), "docker.swarmkit.v1.NodeSpec")
 	proto.RegisterType((*ServiceSpec)(nil), "docker.swarmkit.v1.ServiceSpec")
@@ -694,6 +712,7 @@ func init() {
 	proto.RegisterType((*NetworkSpec)(nil), "docker.swarmkit.v1.NetworkSpec")
 	proto.RegisterType((*ClusterSpec)(nil), "docker.swarmkit.v1.ClusterSpec")
 	proto.RegisterType((*SecretSpec)(nil), "docker.swarmkit.v1.SecretSpec")
+	proto.RegisterType((*ConfigSpec)(nil), "docker.swarmkit.v1.ConfigSpec")
 	proto.RegisterEnum("docker.swarmkit.v1.NodeSpec_Membership", NodeSpec_Membership_name, NodeSpec_Membership_value)
 	proto.RegisterEnum("docker.swarmkit.v1.NodeSpec_Availability", NodeSpec_Availability_name, NodeSpec_Availability_value)
 	proto.RegisterEnum("docker.swarmkit.v1.EndpointSpec_ResolutionMode", EndpointSpec_ResolutionMode_name, EndpointSpec_ResolutionMode_value)
@@ -930,6 +949,10 @@ func (m *ContainerSpec) CopyFrom(src interface{}) {
 		copy(m.Groups, o.Groups)
 	}
 
+	if o.Privileges != nil {
+		m.Privileges = &Privileges{}
+		github_com_docker_swarmkit_api_deepcopy.Copy(m.Privileges, o.Privileges)
+	}
 	if o.Mounts != nil {
 		m.Mounts = make([]Mount, len(o.Mounts))
 		for i := range m.Mounts {
@@ -953,6 +976,14 @@ func (m *ContainerSpec) CopyFrom(src interface{}) {
 		}
 	}
 
+	if o.Configs != nil {
+		m.Configs = make([]*ConfigReference, len(o.Configs))
+		for i := range m.Configs {
+			m.Configs[i] = &ConfigReference{}
+			github_com_docker_swarmkit_api_deepcopy.Copy(m.Configs[i], o.Configs[i])
+		}
+	}
+
 	if o.Hosts != nil {
 		m.Hosts = make([]string, len(o.Hosts))
 		copy(m.Hosts, o.Hosts)
@@ -1103,6 +1134,26 @@ func (m *SecretSpec) CopyFrom(src interface{}) {
 	}
 }
 
+func (m *ConfigSpec) Copy() *ConfigSpec {
+	if m == nil {
+		return nil
+	}
+	o := &ConfigSpec{}
+	o.CopyFrom(m)
+	return o
+}
+
+func (m *ConfigSpec) CopyFrom(src interface{}) {
+
+	o := src.(*ConfigSpec)
+	*m = *o
+	github_com_docker_swarmkit_api_deepcopy.Copy(&m.Annotations, &o.Annotations)
+	if o.Data != nil {
+		m.Data = make([]byte, len(o.Data))
+		copy(m.Data, o.Data)
+	}
+}
+
 func (m *NodeSpec) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	dAtA = make([]byte, size)
@@ -1719,6 +1770,32 @@ func (m *ContainerSpec) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintSpecs(dAtA, i, uint64(len(m.StopSignal)))
 		i += copy(dAtA[i:], m.StopSignal)
 	}
+	if len(m.Configs) > 0 {
+		for _, msg := range m.Configs {
+			dAtA[i] = 0xaa
+			i++
+			dAtA[i] = 0x1
+			i++
+			i = encodeVarintSpecs(dAtA, i, uint64(msg.Size()))
+			n, err := msg.MarshalTo(dAtA[i:])
+			if err != nil {
+				return 0, err
+			}
+			i += n
+		}
+	}
+	if m.Privileges != nil {
+		dAtA[i] = 0xb2
+		i++
+		dAtA[i] = 0x1
+		i++
+		i = encodeVarintSpecs(dAtA, i, uint64(m.Privileges.Size()))
+		n23, err := m.Privileges.MarshalTo(dAtA[i:])
+		if err != nil {
+			return 0, err
+		}
+		i += n23
+	}
 	return i, nil
 }
 
@@ -1864,20 +1941,20 @@ func (m *NetworkSpec) MarshalTo(dAtA []byte) (int, error) {
 	dAtA[i] = 0xa
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.Annotations.Size()))
-	n23, err := m.Annotations.MarshalTo(dAtA[i:])
+	n24, err := m.Annotations.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n23
+	i += n24
 	if m.DriverConfig != nil {
 		dAtA[i] = 0x12
 		i++
 		i = encodeVarintSpecs(dAtA, i, uint64(m.DriverConfig.Size()))
-		n24, err := m.DriverConfig.MarshalTo(dAtA[i:])
+		n25, err := m.DriverConfig.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n24
+		i += n25
 	}
 	if m.Ipv6Enabled {
 		dAtA[i] = 0x18
@@ -1903,11 +1980,11 @@ func (m *NetworkSpec) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x2a
 		i++
 		i = encodeVarintSpecs(dAtA, i, uint64(m.IPAM.Size()))
-		n25, err := m.IPAM.MarshalTo(dAtA[i:])
+		n26, err := m.IPAM.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n25
+		i += n26
 	}
 	if m.Attachable {
 		dAtA[i] = 0x30
@@ -1950,67 +2027,67 @@ func (m *ClusterSpec) MarshalTo(dAtA []byte) (int, error) {
 	dAtA[i] = 0xa
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.Annotations.Size()))
-	n26, err := m.Annotations.MarshalTo(dAtA[i:])
+	n27, err := m.Annotations.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n26
+	i += n27
 	dAtA[i] = 0x12
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.AcceptancePolicy.Size()))
-	n27, err := m.AcceptancePolicy.MarshalTo(dAtA[i:])
+	n28, err := m.AcceptancePolicy.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n27
+	i += n28
 	dAtA[i] = 0x1a
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.Orchestration.Size()))
-	n28, err := m.Orchestration.MarshalTo(dAtA[i:])
+	n29, err := m.Orchestration.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n28
+	i += n29
 	dAtA[i] = 0x22
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.Raft.Size()))
-	n29, err := m.Raft.MarshalTo(dAtA[i:])
+	n30, err := m.Raft.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n29
+	i += n30
 	dAtA[i] = 0x2a
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.Dispatcher.Size()))
-	n30, err := m.Dispatcher.MarshalTo(dAtA[i:])
+	n31, err := m.Dispatcher.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n30
+	i += n31
 	dAtA[i] = 0x32
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.CAConfig.Size()))
-	n31, err := m.CAConfig.MarshalTo(dAtA[i:])
+	n32, err := m.CAConfig.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n31
+	i += n32
 	dAtA[i] = 0x3a
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.TaskDefaults.Size()))
-	n32, err := m.TaskDefaults.MarshalTo(dAtA[i:])
+	n33, err := m.TaskDefaults.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n32
+	i += n33
 	dAtA[i] = 0x42
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.EncryptionConfig.Size()))
-	n33, err := m.EncryptionConfig.MarshalTo(dAtA[i:])
+	n34, err := m.EncryptionConfig.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n33
+	i += n34
 	return i, nil
 }
 
@@ -2032,11 +2109,43 @@ func (m *SecretSpec) MarshalTo(dAtA []byte) (int, error) {
 	dAtA[i] = 0xa
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.Annotations.Size()))
-	n34, err := m.Annotations.MarshalTo(dAtA[i:])
+	n35, err := m.Annotations.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n34
+	i += n35
+	if len(m.Data) > 0 {
+		dAtA[i] = 0x12
+		i++
+		i = encodeVarintSpecs(dAtA, i, uint64(len(m.Data)))
+		i += copy(dAtA[i:], m.Data)
+	}
+	return i, nil
+}
+
+func (m *ConfigSpec) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalTo(dAtA)
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *ConfigSpec) MarshalTo(dAtA []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	dAtA[i] = 0xa
+	i++
+	i = encodeVarintSpecs(dAtA, i, uint64(m.Annotations.Size()))
+	n36, err := m.Annotations.MarshalTo(dAtA[i:])
+	if err != nil {
+		return 0, err
+	}
+	i += n36
 	if len(m.Data) > 0 {
 		dAtA[i] = 0x12
 		i++
@@ -2338,6 +2447,16 @@ func (m *ContainerSpec) Size() (n int) {
 	if l > 0 {
 		n += 2 + l + sovSpecs(uint64(l))
 	}
+	if len(m.Configs) > 0 {
+		for _, e := range m.Configs {
+			l = e.Size()
+			n += 2 + l + sovSpecs(uint64(l))
+		}
+	}
+	if m.Privileges != nil {
+		l = m.Privileges.Size()
+		n += 2 + l + sovSpecs(uint64(l))
+	}
 	return n
 }
 
@@ -2452,6 +2571,18 @@ func (m *SecretSpec) Size() (n int) {
 	return n
 }
 
+func (m *ConfigSpec) Size() (n int) {
+	var l int
+	_ = l
+	l = m.Annotations.Size()
+	n += 1 + l + sovSpecs(uint64(l))
+	l = len(m.Data)
+	if l > 0 {
+		n += 1 + l + sovSpecs(uint64(l))
+	}
+	return n
+}
+
 func sovSpecs(x uint64) (n int) {
 	for {
 		n++
@@ -2635,6 +2766,8 @@ func (this *ContainerSpec) String() string {
 		`OpenStdin:` + fmt.Sprintf("%v", this.OpenStdin) + `,`,
 		`ReadOnly:` + fmt.Sprintf("%v", this.ReadOnly) + `,`,
 		`StopSignal:` + fmt.Sprintf("%v", this.StopSignal) + `,`,
+		`Configs:` + strings.Replace(fmt.Sprintf("%v", this.Configs), "ConfigReference", "ConfigReference", 1) + `,`,
+		`Privileges:` + strings.Replace(fmt.Sprintf("%v", this.Privileges), "Privileges", "Privileges", 1) + `,`,
 		`}`,
 	}, "")
 	return s
@@ -2716,6 +2849,17 @@ func (this *SecretSpec) String() string {
 	}, "")
 	return s
 }
+func (this *ConfigSpec) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&ConfigSpec{`,
+		`Annotations:` + strings.Replace(strings.Replace(this.Annotations.String(), "Annotations", "Annotations", 1), `&`, ``, 1) + `,`,
+		`Data:` + fmt.Sprintf("%v", this.Data) + `,`,
+		`}`,
+	}, "")
+	return s
+}
 func valueToStringSpecs(v interface{}) string {
 	rv := reflect.ValueOf(v)
 	if rv.IsNil() {
@@ -4492,6 +4636,70 @@ func (m *ContainerSpec) Unmarshal(dAtA []byte) error {
 			}
 			m.StopSignal = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
+		case 21:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Configs", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowSpecs
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthSpecs
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Configs = append(m.Configs, &ConfigReference{})
+			if err := m.Configs[len(m.Configs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 22:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Privileges", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowSpecs
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthSpecs
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.Privileges == nil {
+				m.Privileges = &Privileges{}
+			}
+			if err := m.Privileges.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipSpecs(dAtA[iNdEx:])
@@ -5456,6 +5664,117 @@ func (m *SecretSpec) Unmarshal(dAtA []byte) error {
 	}
 	return nil
 }
+func (m *ConfigSpec) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowSpecs
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: ConfigSpec: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: ConfigSpec: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Annotations", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowSpecs
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthSpecs
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.Annotations.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType)
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowSpecs
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				byteLen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if byteLen < 0 {
+				return ErrInvalidLengthSpecs
+			}
+			postIndex := iNdEx + byteLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...)
+			if m.Data == nil {
+				m.Data = []byte{}
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipSpecs(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthSpecs
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
 func skipSpecs(dAtA []byte) (n int, err error) {
 	l := len(dAtA)
 	iNdEx := 0
@@ -5564,117 +5883,119 @@ var (
 func init() { proto.RegisterFile("specs.proto", fileDescriptorSpecs) }
 
 var fileDescriptorSpecs = []byte{
-	// 1779 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x57, 0x41, 0x73, 0x1b, 0x49,
-	0x15, 0xb6, 0x6c, 0x59, 0x1a, 0xbd, 0x91, 0x13, 0xb9, 0xc9, 0x2e, 0x63, 0x85, 0x95, 0x15, 0x6d,
-	0x08, 0x5e, 0xb6, 0x90, 0x0b, 0x43, 0x2d, 0x59, 0xc2, 0x16, 0x48, 0x96, 0x70, 0x8c, 0xb1, 0xa3,
-	0x6a, 0x7b, 0x03, 0x39, 0xa9, 0xda, 0x33, 0x6d, 0x69, 0xca, 0xa3, 0xee, 0xa1, 0xa7, 0xc7, 0x5b,
-	0xba, 0x71, 0xdc, 0xca, 0x99, 0xab, 0x8b, 0x03, 0x7f, 0x26, 0x37, 0x28, 0x4e, 0x9c, 0x5c, 0xac,
-	0xfe, 0x02, 0x3f, 0x00, 0xaa, 0x7b, 0x7a, 0xa4, 0x51, 0x32, 0x4e, 0x52, 0x45, 0x6e, 0xfd, 0x5e,
-	0x7f, 0xdf, 0x9b, 0xd7, 0xaf, 0xbf, 0xee, 0xd7, 0x03, 0x76, 0x14, 0x52, 0x37, 0x6a, 0x87, 0x82,
-	0x4b, 0x8e, 0x90, 0xc7, 0xdd, 0x4b, 0x2a, 0xda, 0xd1, 0x37, 0x44, 0x4c, 0x2e, 0x7d, 0xd9, 0xbe,
-	0xfa, 0x69, 0xdd, 0x96, 0xd3, 0x90, 0x1a, 0x40, 0xfd, 0xde, 0x88, 0x8f, 0xb8, 0x1e, 0xee, 0xaa,
-	0x91, 0xf1, 0x36, 0x46, 0x9c, 0x8f, 0x02, 0xba, 0xab, 0xad, 0xf3, 0xf8, 0x62, 0xd7, 0x8b, 0x05,
-	0x91, 0x3e, 0x67, 0x66, 0x7e, 0xeb, 0xf5, 0x79, 0xc2, 0xa6, 0xc9, 0x54, 0xeb, 0xba, 0x08, 0xd6,
-	0x09, 0xf7, 0xe8, 0x69, 0x48, 0x5d, 0x74, 0x00, 0x36, 0x61, 0x8c, 0x4b, 0xcd, 0x8d, 0x9c, 0x42,
-	0xb3, 0xb0, 0x63, 0xef, 0x6d, 0xb7, 0xdf, 0x4c, 0xaa, 0xdd, 0x59, 0xc0, 0xba, 0xc5, 0x57, 0x37,
-	0xdb, 0x2b, 0x38, 0xcb, 0x44, 0xbf, 0x86, 0xaa, 0x47, 0x23, 0x5f, 0x50, 0x6f, 0x28, 0x78, 0x40,
-	0x9d, 0xd5, 0x66, 0x61, 0xe7, 0xce, 0xde, 0x0f, 0xf2, 0x22, 0xa9, 0x8f, 0x63, 0x1e, 0x50, 0x6c,
-	0x1b, 0x86, 0x32, 0xd0, 0x01, 0xc0, 0x84, 0x4e, 0xce, 0xa9, 0x88, 0xc6, 0x7e, 0xe8, 0xac, 0x69,
-	0xfa, 0x8f, 0x6e, 0xa3, 0xab, 0xdc, 0xdb, 0xc7, 0x73, 0x38, 0xce, 0x50, 0xd1, 0x31, 0x54, 0xc9,
-	0x15, 0xf1, 0x03, 0x72, 0xee, 0x07, 0xbe, 0x9c, 0x3a, 0x45, 0x1d, 0xea, 0xb3, 0xb7, 0x86, 0xea,
-	0x64, 0x08, 0x78, 0x89, 0xde, 0xf2, 0x00, 0x16, 0x1f, 0x42, 0x8f, 0xa0, 0x3c, 0xe8, 0x9f, 0xf4,
-	0x0e, 0x4f, 0x0e, 0x6a, 0x2b, 0xf5, 0xad, 0x97, 0xd7, 0xcd, 0x8f, 0x54, 0x8c, 0x05, 0x60, 0x40,
-	0x99, 0xe7, 0xb3, 0x11, 0xda, 0x01, 0xab, 0xb3, 0xbf, 0xdf, 0x1f, 0x9c, 0xf5, 0x7b, 0xb5, 0x42,
-	0xbd, 0xfe, 0xf2, 0xba, 0xf9, 0xf1, 0x32, 0xb0, 0xe3, 0xba, 0x34, 0x94, 0xd4, 0xab, 0x17, 0xbf,
-	0xfd, 0x5b, 0x63, 0xa5, 0xf5, 0x6d, 0x01, 0xaa, 0xd9, 0x24, 0xd0, 0x23, 0x28, 0x75, 0xf6, 0xcf,
-	0x0e, 0x9f, 0xf7, 0x6b, 0x2b, 0x0b, 0x7a, 0x16, 0xd1, 0x71, 0xa5, 0x7f, 0x45, 0xd1, 0x43, 0x58,
-	0x1f, 0x74, 0xbe, 0x3e, 0xed, 0xd7, 0x0a, 0x8b, 0x74, 0xb2, 0xb0, 0x01, 0x89, 0x23, 0x8d, 0xea,
-	0xe1, 0xce, 0xe1, 0x49, 0x6d, 0x35, 0x1f, 0xd5, 0x13, 0xc4, 0x67, 0x26, 0x95, 0xbf, 0x16, 0xc1,
-	0x3e, 0xa5, 0xe2, 0xca, 0x77, 0x3f, 0xb0, 0x44, 0xbe, 0x80, 0xa2, 0x24, 0xd1, 0xa5, 0x96, 0x86,
-	0x9d, 0x2f, 0x8d, 0x33, 0x12, 0x5d, 0xaa, 0x8f, 0x1a, 0xba, 0xc6, 0x2b, 0x65, 0x08, 0x1a, 0x06,
-	0xbe, 0x4b, 0x24, 0xf5, 0xb4, 0x32, 0xec, 0xbd, 0x1f, 0xe6, 0xb1, 0xf1, 0x1c, 0x65, 0xf2, 0x7f,
-	0xba, 0x82, 0x33, 0x54, 0xf4, 0x04, 0x4a, 0xa3, 0x80, 0x9f, 0x93, 0x40, 0x6b, 0xc2, 0xde, 0x7b,
-	0x90, 0x17, 0xe4, 0x40, 0x23, 0x16, 0x01, 0x0c, 0x05, 0x3d, 0x86, 0x52, 0x1c, 0x7a, 0x44, 0x52,
-	0xa7, 0xa4, 0xc9, 0xcd, 0x3c, 0xf2, 0xd7, 0x1a, 0xb1, 0xcf, 0xd9, 0x85, 0x3f, 0xc2, 0x06, 0x8f,
-	0x8e, 0xc0, 0x62, 0x54, 0x7e, 0xc3, 0xc5, 0x65, 0xe4, 0x94, 0x9b, 0x6b, 0x3b, 0xf6, 0xde, 0xe7,
-	0xb9, 0x62, 0x4c, 0x30, 0x1d, 0x29, 0x89, 0x3b, 0x9e, 0x50, 0x26, 0x93, 0x30, 0xdd, 0x55, 0xa7,
-	0x80, 0xe7, 0x01, 0xd0, 0xaf, 0xc0, 0xa2, 0xcc, 0x0b, 0xb9, 0xcf, 0xa4, 0x63, 0xdd, 0x9e, 0x48,
-	0xdf, 0x60, 0x54, 0x31, 0xf1, 0x9c, 0xa1, 0xd8, 0x82, 0x07, 0xc1, 0x39, 0x71, 0x2f, 0x9d, 0xca,
-	0x7b, 0x2e, 0x63, 0xce, 0xe8, 0x96, 0xa0, 0x38, 0xe1, 0x1e, 0x6d, 0xed, 0xc2, 0xe6, 0x1b, 0xa5,
-	0x46, 0x75, 0xb0, 0x4c, 0xa9, 0x13, 0x8d, 0x14, 0xf1, 0xdc, 0x6e, 0xdd, 0x85, 0x8d, 0xa5, 0xb2,
-	0xb6, 0xfe, 0x59, 0x04, 0x2b, 0xdd, 0x6b, 0xd4, 0x81, 0x8a, 0xcb, 0x99, 0x24, 0x3e, 0xa3, 0xc2,
-	0xc8, 0x2b, 0x77, 0x67, 0xf6, 0x53, 0x90, 0x62, 0x3d, 0x5d, 0xc1, 0x0b, 0x16, 0xfa, 0x2d, 0x54,
-	0x04, 0x8d, 0x78, 0x2c, 0x5c, 0x1a, 0x19, 0x7d, 0xed, 0xe4, 0x2b, 0x24, 0x01, 0x61, 0xfa, 0xa7,
-	0xd8, 0x17, 0x54, 0x55, 0x39, 0xc2, 0x0b, 0x2a, 0x7a, 0x02, 0x65, 0x41, 0x23, 0x49, 0x84, 0x7c,
-	0x9b, 0x44, 0x70, 0x02, 0x19, 0xf0, 0xc0, 0x77, 0xa7, 0x38, 0x65, 0xa0, 0x27, 0x50, 0x09, 0x03,
-	0xe2, 0xea, 0xa8, 0xce, 0xba, 0xa6, 0x7f, 0x92, 0x47, 0x1f, 0xa4, 0x20, 0xbc, 0xc0, 0xa3, 0x2f,
-	0x01, 0x02, 0x3e, 0x1a, 0x7a, 0xc2, 0xbf, 0xa2, 0xc2, 0x48, 0xac, 0x9e, 0xc7, 0xee, 0x69, 0x04,
-	0xae, 0x04, 0x7c, 0x94, 0x0c, 0xd1, 0xc1, 0xff, 0xa5, 0xaf, 0x8c, 0xb6, 0x8e, 0x00, 0xc8, 0x7c,
-	0xd6, 0xa8, 0xeb, 0xb3, 0xf7, 0x0a, 0x65, 0x76, 0x24, 0x43, 0x47, 0x0f, 0xa0, 0x7a, 0xc1, 0x85,
-	0x4b, 0x87, 0xe6, 0xd4, 0x54, 0xb4, 0x26, 0x6c, 0xed, 0x4b, 0xf4, 0x85, 0xba, 0x50, 0x1e, 0x51,
-	0x46, 0x85, 0xef, 0x3a, 0xa0, 0x3f, 0xf6, 0x28, 0xf7, 0x40, 0x26, 0x10, 0x1c, 0x33, 0xe9, 0x4f,
-	0xa8, 0xf9, 0x52, 0x4a, 0xec, 0x56, 0xa0, 0x2c, 0x92, 0x99, 0xd6, 0x1f, 0x01, 0xbd, 0x89, 0x45,
-	0x08, 0x8a, 0x97, 0x3e, 0xf3, 0xb4, 0xb0, 0x2a, 0x58, 0x8f, 0x51, 0x1b, 0xca, 0x21, 0x99, 0x06,
-	0x9c, 0x78, 0x46, 0x2c, 0xf7, 0xda, 0x49, 0xbf, 0x6c, 0xa7, 0xfd, 0xb2, 0xdd, 0x61, 0x53, 0x9c,
-	0x82, 0x5a, 0x47, 0xf0, 0x51, 0xee, 0x92, 0xd1, 0x1e, 0x54, 0xe7, 0x22, 0x1c, 0xfa, 0xe6, 0x23,
-	0xdd, 0xbb, 0xb3, 0x9b, 0x6d, 0x7b, 0xae, 0xd6, 0xc3, 0x1e, 0xb6, 0xe7, 0xa0, 0x43, 0xaf, 0xf5,
-	0x17, 0x0b, 0x36, 0x96, 0xa4, 0x8c, 0xee, 0xc1, 0xba, 0x3f, 0x21, 0x23, 0x6a, 0x72, 0x4c, 0x0c,
-	0xd4, 0x87, 0x52, 0x40, 0xce, 0x69, 0xa0, 0x04, 0xad, 0x36, 0xf5, 0x27, 0xef, 0x3c, 0x13, 0xed,
-	0xdf, 0x6b, 0x7c, 0x9f, 0x49, 0x31, 0xc5, 0x86, 0x8c, 0x1c, 0x28, 0xbb, 0x7c, 0x32, 0x21, 0x4c,
-	0x5d, 0x9d, 0x6b, 0x3b, 0x15, 0x9c, 0x9a, 0xaa, 0x32, 0x44, 0x8c, 0x22, 0xa7, 0xa8, 0xdd, 0x7a,
-	0x8c, 0x6a, 0xb0, 0x46, 0xd9, 0x95, 0xb3, 0xae, 0x5d, 0x6a, 0xa8, 0x3c, 0x9e, 0x9f, 0x28, 0xb2,
-	0x82, 0xd5, 0x50, 0xf1, 0xe2, 0x88, 0x0a, 0xa7, 0x9c, 0x54, 0x54, 0x8d, 0xd1, 0x2f, 0xa0, 0x34,
-	0xe1, 0x31, 0x93, 0x91, 0x63, 0xe9, 0x64, 0xb7, 0xf2, 0x92, 0x3d, 0x56, 0x08, 0x73, 0xb5, 0x1b,
-	0x38, 0xea, 0xc3, 0x66, 0x24, 0x79, 0x38, 0x1c, 0x09, 0xe2, 0xd2, 0x61, 0x48, 0x85, 0xcf, 0x3d,
-	0x73, 0x35, 0x6d, 0xbd, 0xb1, 0x29, 0x3d, 0xf3, 0xc8, 0xc1, 0x77, 0x15, 0xe7, 0x40, 0x51, 0x06,
-	0x9a, 0x81, 0x06, 0x50, 0x0d, 0xe3, 0x20, 0x18, 0xf2, 0x30, 0xe9, 0x52, 0x89, 0x9e, 0xde, 0xa3,
-	0x64, 0x83, 0x38, 0x08, 0x9e, 0x25, 0x24, 0x6c, 0x87, 0x0b, 0x03, 0x7d, 0x0c, 0xa5, 0x91, 0xe0,
-	0x71, 0x18, 0x39, 0xb6, 0x2e, 0x86, 0xb1, 0xd0, 0x57, 0x50, 0x8e, 0xa8, 0x2b, 0xa8, 0x8c, 0x9c,
-	0xaa, 0x5e, 0xea, 0xa7, 0x79, 0x1f, 0x39, 0xd5, 0x10, 0x4c, 0x2f, 0xa8, 0xa0, 0xcc, 0xa5, 0x38,
-	0xe5, 0xa0, 0x2d, 0x58, 0x93, 0x72, 0xea, 0x6c, 0x34, 0x0b, 0x3b, 0x56, 0xb7, 0x3c, 0xbb, 0xd9,
-	0x5e, 0x3b, 0x3b, 0x7b, 0x81, 0x95, 0x4f, 0xdd, 0xa0, 0x63, 0x1e, 0x49, 0x46, 0x26, 0xd4, 0xb9,
-	0xa3, 0x6b, 0x3b, 0xb7, 0xd1, 0x0b, 0x00, 0x8f, 0x45, 0x43, 0x57, 0x1f, 0x59, 0xe7, 0xae, 0x5e,
-	0xdd, 0xe7, 0xef, 0x5e, 0x5d, 0xef, 0xe4, 0xd4, 0x74, 0x91, 0x8d, 0xd9, 0xcd, 0x76, 0x65, 0x6e,
-	0xe2, 0x8a, 0xc7, 0xa2, 0x64, 0x88, 0xba, 0x60, 0x8f, 0x29, 0x09, 0xe4, 0xd8, 0x1d, 0x53, 0xf7,
-	0xd2, 0xa9, 0xdd, 0xde, 0x16, 0x9e, 0x6a, 0x98, 0x89, 0x90, 0x25, 0x29, 0x05, 0xab, 0x54, 0x23,
-	0x67, 0x53, 0xd7, 0x2a, 0x31, 0xd0, 0x27, 0x00, 0x3c, 0xa4, 0x6c, 0x18, 0x49, 0xcf, 0x67, 0x0e,
-	0x52, 0x4b, 0xc6, 0x15, 0xe5, 0x39, 0x55, 0x0e, 0x74, 0x5f, 0x5d, 0xda, 0xc4, 0x1b, 0x72, 0x16,
-	0x4c, 0x9d, 0xef, 0xe9, 0x59, 0x4b, 0x39, 0x9e, 0xb1, 0x60, 0x8a, 0xb6, 0xc1, 0xd6, 0xba, 0x88,
-	0xfc, 0x11, 0x23, 0x81, 0x73, 0x4f, 0xd7, 0x03, 0x94, 0xeb, 0x54, 0x7b, 0xea, 0x5f, 0x82, 0x9d,
-	0x91, 0xbb, 0x92, 0xe9, 0x25, 0x9d, 0x9a, 0x13, 0xa4, 0x86, 0x2a, 0xa7, 0x2b, 0x12, 0xc4, 0xc9,
-	0x53, 0xb4, 0x82, 0x13, 0xe3, 0x97, 0xab, 0x8f, 0x0b, 0xf5, 0x3d, 0xb0, 0x33, 0xdb, 0x8e, 0x3e,
-	0x85, 0x0d, 0x41, 0x47, 0x7e, 0x24, 0xc5, 0x74, 0x48, 0x62, 0x39, 0x76, 0x7e, 0xa3, 0x09, 0xd5,
-	0xd4, 0xd9, 0x89, 0xe5, 0xb8, 0x3e, 0x84, 0x45, 0xf5, 0x50, 0x13, 0x6c, 0xb5, 0x2b, 0x11, 0x15,
-	0x57, 0x54, 0xa8, 0x76, 0xa7, 0x16, 0x9d, 0x75, 0x29, 0xf5, 0x44, 0x94, 0x08, 0x77, 0xac, 0x0f,
-	0x6f, 0x05, 0x1b, 0x4b, 0x9d, 0xc6, 0x54, 0xa2, 0xe6, 0x34, 0x1a, 0xb3, 0xf5, 0x9f, 0x02, 0x54,
-	0xb3, 0x5d, 0x1b, 0xed, 0x27, 0xdd, 0x56, 0x2f, 0xe9, 0xce, 0xde, 0xee, 0xbb, 0xba, 0xbc, 0xee,
-	0x6d, 0x41, 0xac, 0x82, 0x1d, 0xab, 0x07, 0xb6, 0x26, 0xa3, 0x9f, 0xc3, 0x7a, 0xc8, 0x85, 0x4c,
-	0xef, 0x90, 0x46, 0x6e, 0x3f, 0xe2, 0x22, 0xed, 0x05, 0x09, 0xb8, 0x35, 0x86, 0x3b, 0xcb, 0xd1,
-	0xd0, 0x43, 0x58, 0x7b, 0x7e, 0x38, 0xa8, 0xad, 0xd4, 0xef, 0xbf, 0xbc, 0x6e, 0x7e, 0x7f, 0x79,
-	0xf2, 0xb9, 0x2f, 0x64, 0x4c, 0x82, 0xc3, 0x01, 0xfa, 0x31, 0xac, 0xf7, 0x4e, 0x4e, 0x31, 0xae,
-	0x15, 0xea, 0xdb, 0x2f, 0xaf, 0x9b, 0xf7, 0x97, 0x71, 0x6a, 0x8a, 0xc7, 0xcc, 0xc3, 0xfc, 0x7c,
-	0xfe, 0xd8, 0xfc, 0xfb, 0x2a, 0xd8, 0xe6, 0x6a, 0xfd, 0xd0, 0xff, 0x23, 0x1b, 0x49, 0x2f, 0x4d,
-	0xcf, 0xcc, 0xea, 0x3b, 0x5b, 0x6a, 0x35, 0x21, 0x98, 0x3d, 0x7e, 0x00, 0x55, 0x3f, 0xbc, 0xfa,
-	0x62, 0x48, 0x19, 0x39, 0x0f, 0xcc, 0xbb, 0xd3, 0xc2, 0xb6, 0xf2, 0xf5, 0x13, 0x97, 0x3a, 0xb0,
-	0x3e, 0x93, 0x54, 0x30, 0xf3, 0xa2, 0xb4, 0xf0, 0xdc, 0x46, 0x5f, 0x41, 0xd1, 0x0f, 0xc9, 0xc4,
-	0xbc, 0x03, 0x72, 0x57, 0x70, 0x38, 0xe8, 0x1c, 0x1b, 0x0d, 0x76, 0xad, 0xd9, 0xcd, 0x76, 0x51,
-	0x39, 0xb0, 0xa6, 0xa1, 0x46, 0xda, 0x8a, 0xd5, 0x97, 0xf4, 0xe5, 0x6b, 0xe1, 0x8c, 0x47, 0xe9,
-	0xc8, 0x67, 0x23, 0x41, 0xa3, 0x48, 0x5f, 0xc3, 0x16, 0x4e, 0xcd, 0xd6, 0x7f, 0x8b, 0x60, 0xef,
-	0x07, 0x71, 0x24, 0x4d, 0x73, 0xf9, 0x60, 0x15, 0x7d, 0x01, 0x9b, 0x44, 0xff, 0xb4, 0x10, 0xa6,
-	0x6e, 0x6a, 0xfd, 0xf8, 0x31, 0x55, 0x7d, 0x98, 0x1b, 0x6e, 0x0e, 0x4e, 0x1e, 0x4a, 0xdd, 0x92,
-	0x8a, 0xe9, 0x14, 0x70, 0x8d, 0xbc, 0x36, 0x83, 0x4e, 0x61, 0x83, 0x0b, 0x77, 0x4c, 0x23, 0x99,
-	0xdc, 0xef, 0xe6, 0x91, 0x9f, 0xfb, 0xfb, 0xf7, 0x2c, 0x0b, 0x34, 0x97, 0x5b, 0x92, 0xed, 0x72,
-	0x0c, 0xf4, 0x18, 0x8a, 0x82, 0x5c, 0xa4, 0x0f, 0xb9, 0x5c, 0xe5, 0x63, 0x72, 0x21, 0x97, 0x42,
-	0x68, 0x06, 0xfa, 0x1d, 0x80, 0xe7, 0x47, 0x21, 0x91, 0xee, 0x98, 0x0a, 0xb3, 0x83, 0xb9, 0x4b,
-	0xec, 0xcd, 0x51, 0x4b, 0x51, 0x32, 0x6c, 0x74, 0x04, 0x15, 0x97, 0xa4, 0x1a, 0x2c, 0xdd, 0xfe,
-	0xe7, 0xb3, 0xdf, 0x31, 0x21, 0x6a, 0x2a, 0xc4, 0xec, 0x66, 0xdb, 0x4a, 0x3d, 0xd8, 0x72, 0x89,
-	0xd1, 0xe4, 0x11, 0x6c, 0xa8, 0x3f, 0xa2, 0xa1, 0x47, 0x2f, 0x48, 0x1c, 0xc8, 0x64, 0xef, 0x6f,
-	0xb9, 0xac, 0xd5, 0xf3, 0xba, 0x67, 0x70, 0x26, 0xaf, 0xaa, 0xcc, 0xf8, 0xd0, 0x1f, 0x60, 0x93,
-	0x32, 0x57, 0x4c, 0xb5, 0x02, 0xd3, 0x0c, 0xad, 0xdb, 0x17, 0xdb, 0x9f, 0x83, 0x97, 0x16, 0x5b,
-	0xa3, 0xaf, 0xf9, 0x5b, 0x3e, 0x40, 0xd2, 0xfe, 0x3e, 0xac, 0xfe, 0x10, 0x14, 0x3d, 0x22, 0x89,
-	0x96, 0x5c, 0x15, 0xeb, 0x71, 0xd7, 0x79, 0xf5, 0x5d, 0x63, 0xe5, 0x5f, 0xdf, 0x35, 0x56, 0xfe,
-	0x3c, 0x6b, 0x14, 0x5e, 0xcd, 0x1a, 0x85, 0x7f, 0xcc, 0x1a, 0x85, 0x7f, 0xcf, 0x1a, 0x85, 0xf3,
-	0x92, 0x7e, 0x34, 0xfc, 0xec, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbe, 0x3e, 0xe8, 0xcb, 0x6d,
-	0x11, 0x00, 0x00,
+	// 1824 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x57, 0x4f, 0x73, 0x1b, 0x49,
+	0x15, 0xb7, 0x6c, 0x59, 0x7f, 0xde, 0xc8, 0x89, 0xd2, 0x24, 0x61, 0xac, 0xb0, 0xb2, 0xa2, 0x0d,
+	0xc1, 0xcb, 0x16, 0x72, 0x61, 0xa8, 0x25, 0x4b, 0x58, 0x40, 0xb2, 0x84, 0x63, 0x8c, 0x1d, 0x55,
+	0xdb, 0x1b, 0xc8, 0x49, 0xd5, 0x9e, 0x69, 0x4b, 0x53, 0x1e, 0x75, 0x0f, 0xdd, 0x3d, 0xda, 0xd2,
+	0x8d, 0xe3, 0x56, 0xae, 0x9c, 0x5d, 0x1c, 0xf8, 0x32, 0xb9, 0x41, 0x71, 0xe2, 0xe4, 0x62, 0xfd,
+	0x15, 0xf8, 0x00, 0x50, 0xdd, 0xd3, 0xa3, 0x3f, 0xc9, 0x78, 0x93, 0x2a, 0xc2, 0xad, 0xfb, 0xcd,
+	0xef, 0xf7, 0xfa, 0xf5, 0xeb, 0x5f, 0xf7, 0x7b, 0x03, 0x8e, 0x8c, 0xa8, 0x27, 0x5b, 0x91, 0xe0,
+	0x8a, 0x23, 0xe4, 0x73, 0xef, 0x82, 0x8a, 0x96, 0xfc, 0x8a, 0x88, 0xf1, 0x45, 0xa0, 0x5a, 0x93,
+	0x1f, 0xd7, 0x1c, 0x35, 0x8d, 0xa8, 0x05, 0xd4, 0xee, 0x0e, 0xf9, 0x90, 0x9b, 0xe1, 0x8e, 0x1e,
+	0x59, 0x6b, 0x7d, 0xc8, 0xf9, 0x30, 0xa4, 0x3b, 0x66, 0x76, 0x16, 0x9f, 0xef, 0xf8, 0xb1, 0x20,
+	0x2a, 0xe0, 0xcc, 0x7e, 0xdf, 0x7c, 0xf3, 0x3b, 0x61, 0xd3, 0xe4, 0x53, 0xf3, 0x32, 0x0f, 0xa5,
+	0x63, 0xee, 0xd3, 0x93, 0x88, 0x7a, 0x68, 0x1f, 0x1c, 0xc2, 0x18, 0x57, 0x86, 0x2b, 0xdd, 0x5c,
+	0x23, 0xb7, 0xed, 0xec, 0x6e, 0xb5, 0xde, 0x0e, 0xaa, 0xd5, 0x9e, 0xc3, 0x3a, 0xf9, 0xd7, 0x57,
+	0x5b, 0x2b, 0x78, 0x91, 0x89, 0x7e, 0x05, 0x15, 0x9f, 0xca, 0x40, 0x50, 0x7f, 0x20, 0x78, 0x48,
+	0xdd, 0xd5, 0x46, 0x6e, 0xfb, 0xd6, 0xee, 0xf7, 0xb2, 0x3c, 0xe9, 0xc5, 0x31, 0x0f, 0x29, 0x76,
+	0x2c, 0x43, 0x4f, 0xd0, 0x3e, 0xc0, 0x98, 0x8e, 0xcf, 0xa8, 0x90, 0xa3, 0x20, 0x72, 0xd7, 0x0c,
+	0xfd, 0x07, 0x37, 0xd1, 0x75, 0xec, 0xad, 0xa3, 0x19, 0x1c, 0x2f, 0x50, 0xd1, 0x11, 0x54, 0xc8,
+	0x84, 0x04, 0x21, 0x39, 0x0b, 0xc2, 0x40, 0x4d, 0xdd, 0xbc, 0x71, 0xf5, 0xc9, 0xb7, 0xba, 0x6a,
+	0x2f, 0x10, 0xf0, 0x12, 0xbd, 0xe9, 0x03, 0xcc, 0x17, 0x42, 0x8f, 0xa1, 0xd8, 0xef, 0x1d, 0x77,
+	0x0f, 0x8e, 0xf7, 0xab, 0x2b, 0xb5, 0xcd, 0x57, 0x97, 0x8d, 0x7b, 0xda, 0xc7, 0x1c, 0xd0, 0xa7,
+	0xcc, 0x0f, 0xd8, 0x10, 0x6d, 0x43, 0xa9, 0xbd, 0xb7, 0xd7, 0xeb, 0x9f, 0xf6, 0xba, 0xd5, 0x5c,
+	0xad, 0xf6, 0xea, 0xb2, 0x71, 0x7f, 0x19, 0xd8, 0xf6, 0x3c, 0x1a, 0x29, 0xea, 0xd7, 0xf2, 0x5f,
+	0xff, 0xb5, 0xbe, 0xd2, 0xfc, 0x3a, 0x07, 0x95, 0xc5, 0x20, 0xd0, 0x63, 0x28, 0xb4, 0xf7, 0x4e,
+	0x0f, 0x5e, 0xf4, 0xaa, 0x2b, 0x73, 0xfa, 0x22, 0xa2, 0xed, 0xa9, 0x60, 0x42, 0xd1, 0x23, 0x58,
+	0xef, 0xb7, 0xbf, 0x3c, 0xe9, 0x55, 0x73, 0xf3, 0x70, 0x16, 0x61, 0x7d, 0x12, 0x4b, 0x83, 0xea,
+	0xe2, 0xf6, 0xc1, 0x71, 0x75, 0x35, 0x1b, 0xd5, 0x15, 0x24, 0x60, 0x36, 0x94, 0xbf, 0xe4, 0xc1,
+	0x39, 0xa1, 0x62, 0x12, 0x78, 0x1f, 0x58, 0x22, 0x9f, 0x41, 0x5e, 0x11, 0x79, 0x61, 0xa4, 0xe1,
+	0x64, 0x4b, 0xe3, 0x94, 0xc8, 0x0b, 0xbd, 0xa8, 0xa5, 0x1b, 0xbc, 0x56, 0x86, 0xa0, 0x51, 0x18,
+	0x78, 0x44, 0x51, 0xdf, 0x28, 0xc3, 0xd9, 0xfd, 0x7e, 0x16, 0x1b, 0xcf, 0x50, 0x36, 0xfe, 0x67,
+	0x2b, 0x78, 0x81, 0x8a, 0x9e, 0x42, 0x61, 0x18, 0xf2, 0x33, 0x12, 0x1a, 0x4d, 0x38, 0xbb, 0x0f,
+	0xb3, 0x9c, 0xec, 0x1b, 0xc4, 0xdc, 0x81, 0xa5, 0xa0, 0x27, 0x50, 0x88, 0x23, 0x9f, 0x28, 0xea,
+	0x16, 0x0c, 0xb9, 0x91, 0x45, 0xfe, 0xd2, 0x20, 0xf6, 0x38, 0x3b, 0x0f, 0x86, 0xd8, 0xe2, 0xd1,
+	0x21, 0x94, 0x18, 0x55, 0x5f, 0x71, 0x71, 0x21, 0xdd, 0x62, 0x63, 0x6d, 0xdb, 0xd9, 0xfd, 0x34,
+	0x53, 0x8c, 0x09, 0xa6, 0xad, 0x14, 0xf1, 0x46, 0x63, 0xca, 0x54, 0xe2, 0xa6, 0xb3, 0xea, 0xe6,
+	0xf0, 0xcc, 0x01, 0xfa, 0x05, 0x94, 0x28, 0xf3, 0x23, 0x1e, 0x30, 0xe5, 0x96, 0x6e, 0x0e, 0xa4,
+	0x67, 0x31, 0x3a, 0x99, 0x78, 0xc6, 0xd0, 0x6c, 0xc1, 0xc3, 0xf0, 0x8c, 0x78, 0x17, 0x6e, 0xf9,
+	0x3d, 0xb7, 0x31, 0x63, 0x74, 0x0a, 0x90, 0x1f, 0x73, 0x9f, 0x36, 0x77, 0xe0, 0xce, 0x5b, 0xa9,
+	0x46, 0x35, 0x28, 0xd9, 0x54, 0x27, 0x1a, 0xc9, 0xe3, 0xd9, 0xbc, 0x79, 0x1b, 0x36, 0x96, 0xd2,
+	0xda, 0xfc, 0x47, 0x1e, 0x4a, 0xe9, 0x59, 0xa3, 0x36, 0x94, 0x3d, 0xce, 0x14, 0x09, 0x18, 0x15,
+	0x56, 0x5e, 0x99, 0x27, 0xb3, 0x97, 0x82, 0x34, 0xeb, 0xd9, 0x0a, 0x9e, 0xb3, 0xd0, 0x6f, 0xa0,
+	0x2c, 0xa8, 0xe4, 0xb1, 0xf0, 0xa8, 0xb4, 0xfa, 0xda, 0xce, 0x56, 0x48, 0x02, 0xc2, 0xf4, 0x8f,
+	0x71, 0x20, 0xa8, 0xce, 0xb2, 0xc4, 0x73, 0x2a, 0x7a, 0x0a, 0x45, 0x41, 0xa5, 0x22, 0x42, 0x7d,
+	0x9b, 0x44, 0x70, 0x02, 0xe9, 0xf3, 0x30, 0xf0, 0xa6, 0x38, 0x65, 0xa0, 0xa7, 0x50, 0x8e, 0x42,
+	0xe2, 0x19, 0xaf, 0xee, 0xba, 0xa1, 0x7f, 0x94, 0x45, 0xef, 0xa7, 0x20, 0x3c, 0xc7, 0xa3, 0xcf,
+	0x01, 0x42, 0x3e, 0x1c, 0xf8, 0x22, 0x98, 0x50, 0x61, 0x25, 0x56, 0xcb, 0x62, 0x77, 0x0d, 0x02,
+	0x97, 0x43, 0x3e, 0x4c, 0x86, 0x68, 0xff, 0x7f, 0xd2, 0xd7, 0x82, 0xb6, 0x0e, 0x01, 0xc8, 0xec,
+	0xab, 0x55, 0xd7, 0x27, 0xef, 0xe5, 0xca, 0x9e, 0xc8, 0x02, 0x1d, 0x3d, 0x84, 0xca, 0x39, 0x17,
+	0x1e, 0x1d, 0xd8, 0x5b, 0x53, 0x36, 0x9a, 0x70, 0x8c, 0x2d, 0xd1, 0x17, 0xea, 0x40, 0x71, 0x48,
+	0x19, 0x15, 0x81, 0xe7, 0x82, 0x59, 0xec, 0x71, 0xe6, 0x85, 0x4c, 0x20, 0x38, 0x66, 0x2a, 0x18,
+	0x53, 0xbb, 0x52, 0x4a, 0xec, 0x94, 0xa1, 0x28, 0x92, 0x2f, 0xcd, 0x3f, 0x00, 0x7a, 0x1b, 0x8b,
+	0x10, 0xe4, 0x2f, 0x02, 0xe6, 0x1b, 0x61, 0x95, 0xb1, 0x19, 0xa3, 0x16, 0x14, 0x23, 0x32, 0x0d,
+	0x39, 0xf1, 0xad, 0x58, 0xee, 0xb6, 0x92, 0x7a, 0xd9, 0x4a, 0xeb, 0x65, 0xab, 0xcd, 0xa6, 0x38,
+	0x05, 0x35, 0x0f, 0xe1, 0x5e, 0xe6, 0x96, 0xd1, 0x2e, 0x54, 0x66, 0x22, 0x1c, 0x04, 0x76, 0x91,
+	0xce, 0xed, 0xeb, 0xab, 0x2d, 0x67, 0xa6, 0xd6, 0x83, 0x2e, 0x76, 0x66, 0xa0, 0x03, 0xbf, 0xf9,
+	0xe7, 0x32, 0x6c, 0x2c, 0x49, 0x19, 0xdd, 0x85, 0xf5, 0x60, 0x4c, 0x86, 0xd4, 0xc6, 0x98, 0x4c,
+	0x50, 0x0f, 0x0a, 0x21, 0x39, 0xa3, 0xa1, 0x16, 0xb4, 0x3e, 0xd4, 0x1f, 0xbd, 0xf3, 0x4e, 0xb4,
+	0x7e, 0x67, 0xf0, 0x3d, 0xa6, 0xc4, 0x14, 0x5b, 0x32, 0x72, 0xa1, 0xe8, 0xf1, 0xf1, 0x98, 0x30,
+	0xfd, 0x74, 0xae, 0x6d, 0x97, 0x71, 0x3a, 0xd5, 0x99, 0x21, 0x62, 0x28, 0xdd, 0xbc, 0x31, 0x9b,
+	0x31, 0xaa, 0xc2, 0x1a, 0x65, 0x13, 0x77, 0xdd, 0x98, 0xf4, 0x50, 0x5b, 0xfc, 0x20, 0x51, 0x64,
+	0x19, 0xeb, 0xa1, 0xe6, 0xc5, 0x92, 0x0a, 0xb7, 0x98, 0x64, 0x54, 0x8f, 0xd1, 0xcf, 0xa0, 0x30,
+	0xe6, 0x31, 0x53, 0xd2, 0x2d, 0x99, 0x60, 0x37, 0xb3, 0x82, 0x3d, 0xd2, 0x08, 0xfb, 0xb4, 0x5b,
+	0x38, 0xea, 0xc1, 0x1d, 0xa9, 0x78, 0x34, 0x18, 0x0a, 0xe2, 0xd1, 0x41, 0x44, 0x45, 0xc0, 0x7d,
+	0xfb, 0x34, 0x6d, 0xbe, 0x75, 0x28, 0x5d, 0xdb, 0xe4, 0xe0, 0xdb, 0x9a, 0xb3, 0xaf, 0x29, 0x7d,
+	0xc3, 0x40, 0x7d, 0xa8, 0x44, 0x71, 0x18, 0x0e, 0x78, 0x94, 0x54, 0xa9, 0x44, 0x4f, 0xef, 0x91,
+	0xb2, 0x7e, 0x1c, 0x86, 0xcf, 0x13, 0x12, 0x76, 0xa2, 0xf9, 0x04, 0xdd, 0x87, 0xc2, 0x50, 0xf0,
+	0x38, 0x92, 0xae, 0x63, 0x92, 0x61, 0x67, 0xe8, 0x0b, 0x28, 0x4a, 0xea, 0x09, 0xaa, 0xa4, 0x5b,
+	0x31, 0x5b, 0xfd, 0x38, 0x6b, 0x91, 0x13, 0x03, 0xc1, 0xf4, 0x9c, 0x0a, 0xca, 0x3c, 0x8a, 0x53,
+	0x0e, 0xda, 0x84, 0x35, 0xa5, 0xa6, 0xee, 0x46, 0x23, 0xb7, 0x5d, 0xea, 0x14, 0xaf, 0xaf, 0xb6,
+	0xd6, 0x4e, 0x4f, 0x5f, 0x62, 0x6d, 0xd3, 0x2f, 0xe8, 0x88, 0x4b, 0xc5, 0xc8, 0x98, 0xba, 0xb7,
+	0x4c, 0x6e, 0x67, 0x73, 0xf4, 0x12, 0xc0, 0x67, 0x72, 0xe0, 0x99, 0x2b, 0xeb, 0xde, 0x36, 0xbb,
+	0xfb, 0xf4, 0xdd, 0xbb, 0xeb, 0x1e, 0x9f, 0xd8, 0x2a, 0xb2, 0x71, 0x7d, 0xb5, 0x55, 0x9e, 0x4d,
+	0x71, 0xd9, 0x67, 0x32, 0x19, 0xa2, 0x0e, 0x38, 0x23, 0x4a, 0x42, 0x35, 0xf2, 0x46, 0xd4, 0xbb,
+	0x70, 0xab, 0x37, 0x97, 0x85, 0x67, 0x06, 0x66, 0x3d, 0x2c, 0x92, 0xb4, 0x82, 0x75, 0xa8, 0xd2,
+	0xbd, 0x63, 0x72, 0x95, 0x4c, 0xd0, 0x47, 0x00, 0x3c, 0xa2, 0x6c, 0x20, 0x95, 0x1f, 0x30, 0x17,
+	0xe9, 0x2d, 0xe3, 0xb2, 0xb6, 0x9c, 0x68, 0x03, 0x7a, 0xa0, 0x1f, 0x6d, 0xe2, 0x0f, 0x38, 0x0b,
+	0xa7, 0xee, 0x77, 0xcc, 0xd7, 0x92, 0x36, 0x3c, 0x67, 0xe1, 0x14, 0x6d, 0x81, 0x63, 0x74, 0x21,
+	0x83, 0x21, 0x23, 0xa1, 0x7b, 0xd7, 0xe4, 0x03, 0xb4, 0xe9, 0xc4, 0x58, 0xf4, 0x39, 0x24, 0xd9,
+	0x90, 0xee, 0xbd, 0x9b, 0xcf, 0xc1, 0x06, 0x3b, 0x3f, 0x07, 0xcb, 0x41, 0xbf, 0x04, 0x88, 0x44,
+	0x30, 0x09, 0x42, 0x3a, 0xa4, 0xd2, 0xbd, 0x6f, 0x36, 0x5d, 0xcf, 0x7c, 0xad, 0x67, 0x28, 0xbc,
+	0xc0, 0xa8, 0x7d, 0x0e, 0xce, 0xc2, 0x6d, 0xd3, 0xb7, 0xe4, 0x82, 0x4e, 0xed, 0x05, 0xd6, 0x43,
+	0x9d, 0x92, 0x09, 0x09, 0xe3, 0xa4, 0x13, 0x2e, 0xe3, 0x64, 0xf2, 0xf3, 0xd5, 0x27, 0xb9, 0xda,
+	0x2e, 0x38, 0x0b, 0xaa, 0x43, 0x1f, 0xc3, 0x86, 0xa0, 0xc3, 0x40, 0x2a, 0x31, 0x1d, 0x90, 0x58,
+	0x8d, 0xdc, 0x5f, 0x1b, 0x42, 0x25, 0x35, 0xb6, 0x63, 0x35, 0xaa, 0x0d, 0x60, 0x7e, 0x78, 0xa8,
+	0x01, 0x8e, 0x16, 0x85, 0xa4, 0x62, 0x42, 0x85, 0xae, 0xb6, 0x3a, 0xe7, 0x8b, 0x26, 0x2d, 0x5e,
+	0x49, 0x89, 0xf0, 0x46, 0xe6, 0xed, 0x28, 0x63, 0x3b, 0xd3, 0x8f, 0x41, 0x7a, 0x43, 0xec, 0x63,
+	0x60, 0xa7, 0xcd, 0x7f, 0xe7, 0xa0, 0xb2, 0xd8, 0x34, 0xa0, 0xbd, 0xa4, 0xd8, 0x9b, 0x2d, 0xdd,
+	0xda, 0xdd, 0x79, 0x57, 0x93, 0x61, 0x4a, 0x6b, 0x18, 0x6b, 0x67, 0x47, 0xba, 0xbf, 0x37, 0x64,
+	0xf4, 0x53, 0x58, 0x8f, 0xb8, 0x50, 0xe9, 0x13, 0x96, 0x9d, 0x60, 0x2e, 0xd2, 0x52, 0x94, 0x80,
+	0x9b, 0x23, 0xb8, 0xb5, 0xec, 0x0d, 0x3d, 0x82, 0xb5, 0x17, 0x07, 0xfd, 0xea, 0x4a, 0xed, 0xc1,
+	0xab, 0xcb, 0xc6, 0x77, 0x97, 0x3f, 0xbe, 0x08, 0x84, 0x8a, 0x49, 0x78, 0xd0, 0x47, 0x3f, 0x84,
+	0xf5, 0xee, 0xf1, 0x09, 0xc6, 0xd5, 0x5c, 0x6d, 0xeb, 0xd5, 0x65, 0xe3, 0xc1, 0x32, 0x4e, 0x7f,
+	0xe2, 0x31, 0xf3, 0x31, 0x3f, 0x9b, 0xf5, 0xba, 0x7f, 0x5b, 0x05, 0xc7, 0xbe, 0xec, 0x1f, 0xfa,
+	0x77, 0x68, 0x23, 0x29, 0xe5, 0xe9, 0x95, 0x5d, 0x7d, 0x67, 0x45, 0xaf, 0x24, 0x04, 0x7b, 0xc6,
+	0x0f, 0xa1, 0x12, 0x44, 0x93, 0xcf, 0x06, 0x94, 0x91, 0xb3, 0xd0, 0xb6, 0xbd, 0x25, 0xec, 0x68,
+	0x5b, 0x2f, 0x31, 0xe9, 0xf7, 0x22, 0x60, 0x8a, 0x0a, 0x66, 0x1b, 0xda, 0x12, 0x9e, 0xcd, 0xd1,
+	0x17, 0x90, 0x0f, 0x22, 0x32, 0xb6, 0x6d, 0x48, 0xe6, 0x0e, 0x0e, 0xfa, 0xed, 0x23, 0xab, 0xc1,
+	0x4e, 0xe9, 0xfa, 0x6a, 0x2b, 0xaf, 0x0d, 0xd8, 0xd0, 0x50, 0x3d, 0xed, 0x04, 0xf4, 0x4a, 0xe6,
+	0xed, 0x2f, 0xe1, 0x05, 0x8b, 0xd6, 0x51, 0xc0, 0x86, 0x82, 0x4a, 0x69, 0xaa, 0x40, 0x09, 0xa7,
+	0xd3, 0xe6, 0x7f, 0xf2, 0xe0, 0xec, 0x85, 0xb1, 0x54, 0xb6, 0xb6, 0x7d, 0xb0, 0x8c, 0xbe, 0x84,
+	0x3b, 0xc4, 0xfc, 0x33, 0x11, 0xa6, 0x0b, 0x85, 0xe9, 0xbd, 0x6c, 0x56, 0x1f, 0x65, 0xba, 0x9b,
+	0x81, 0x93, 0x3e, 0xad, 0x53, 0xd0, 0x3e, 0xdd, 0x1c, 0xae, 0x92, 0x37, 0xbe, 0xa0, 0x13, 0xd8,
+	0xe0, 0xc2, 0x1b, 0x51, 0xa9, 0x92, 0xf2, 0x62, 0xff, 0x31, 0x32, 0xff, 0x3e, 0x9f, 0x2f, 0x02,
+	0xed, 0xdb, 0x9a, 0x44, 0xbb, 0xec, 0x03, 0x3d, 0x81, 0xbc, 0x20, 0xe7, 0x69, 0x1f, 0x99, 0xa9,
+	0x7c, 0x4c, 0xce, 0xd5, 0x92, 0x0b, 0xc3, 0x40, 0xbf, 0x05, 0xf0, 0x03, 0x19, 0x11, 0xe5, 0x8d,
+	0xa8, 0xb0, 0x27, 0x98, 0xb9, 0xc5, 0xee, 0x0c, 0xb5, 0xe4, 0x65, 0x81, 0x8d, 0x0e, 0xa1, 0xec,
+	0x91, 0x54, 0x83, 0x85, 0x9b, 0x7f, 0xbc, 0xf6, 0xda, 0xd6, 0x45, 0x55, 0xbb, 0xb8, 0xbe, 0xda,
+	0x2a, 0xa5, 0x16, 0x5c, 0xf2, 0x88, 0xd5, 0xe4, 0x21, 0x6c, 0xe8, 0x1f, 0xb2, 0x81, 0x4f, 0xcf,
+	0x49, 0x1c, 0xaa, 0xe4, 0xec, 0x6f, 0xa8, 0x15, 0xba, 0xbb, 0xef, 0x5a, 0x9c, 0x8d, 0xab, 0xa2,
+	0x16, 0x6c, 0xe8, 0xf7, 0x70, 0x87, 0x32, 0x4f, 0x4c, 0x8d, 0x02, 0xd3, 0x08, 0x4b, 0x37, 0x6f,
+	0xb6, 0x37, 0x03, 0x2f, 0x6d, 0xb6, 0x4a, 0xdf, 0xb0, 0x37, 0x03, 0x80, 0xa4, 0xfa, 0x7e, 0x58,
+	0xfd, 0x21, 0xc8, 0xfb, 0x44, 0x11, 0x23, 0xb9, 0x0a, 0x36, 0x63, 0xbd, 0x54, 0xb2, 0xe8, 0xff,
+	0x7d, 0xa9, 0x8e, 0xfb, 0xfa, 0x9b, 0xfa, 0xca, 0x3f, 0xbf, 0xa9, 0xaf, 0xfc, 0xe9, 0xba, 0x9e,
+	0x7b, 0x7d, 0x5d, 0xcf, 0xfd, 0xfd, 0xba, 0x9e, 0xfb, 0xd7, 0x75, 0x3d, 0x77, 0x56, 0x30, 0xed,
+	0xd1, 0x4f, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x90, 0x54, 0x3b, 0xfc, 0x57, 0x12, 0x00, 0x00,
 }

+ 17 - 0
vendor/github.com/docker/swarmkit/api/specs.proto

@@ -197,6 +197,9 @@ message ContainerSpec {
 	// Groups specifies supplementary groups available to the user.
 	repeated string groups = 11;
 
+	// Privileges specifies security configuration/permissions.
+	Privileges privileges = 22;
+
 	// TTY declares that a TTY should be attached to the standard streams,
 	// including stdin if it is still open.
 	bool tty = 13 [(gogoproto.customname) = "TTY"];
@@ -236,6 +239,10 @@ message ContainerSpec {
 	// will be exposed to the container.
 	repeated SecretReference secrets = 12;
 
+	// ConfigReference contains references to zero or more configs that
+	// will be exposed to the container.
+	repeated ConfigReference configs = 21;
+
 	// Hosts allow additional entries to be specified in /etc/hosts
 	// that associates IP addresses with hostnames.
 	// Detailed documentation is available in:
@@ -371,3 +378,13 @@ message SecretSpec {
 	// Data is the secret payload - the maximum size is 500KB (that is, 500*1024 bytes)
 	bytes data = 2;
 }
+
+// ConfigSpec specifies user-provided configuration files.
+message ConfigSpec {
+	Annotations annotations = 1 [(gogoproto.nullable) = false];
+
+	// Data is the config payload - the maximum size is 500KB (that is, 500*1024 bytes)
+	// TODO(aaronl): Do we want to revise this to include multiple payloads in a single
+	// ConfigSpec? Define this to be a tar? etc...
+	bytes data = 2;
+}

+ 280 - 88
vendor/github.com/docker/swarmkit/api/store.pb.go

@@ -73,6 +73,7 @@ type Object struct {
 	//	*Object_Secret
 	//	*Object_Resource
 	//	*Object_Extension
+	//	*Object_Config
 	Object isObject_Object `protobuf_oneof:"Object"`
 }
 
@@ -110,6 +111,9 @@ type Object_Resource struct {
 type Object_Extension struct {
 	Extension *Extension `protobuf:"bytes,8,opt,name=extension,oneof"`
 }
+type Object_Config struct {
+	Config *Config `protobuf:"bytes,9,opt,name=config,oneof"`
+}
 
 func (*Object_Node) isObject_Object()      {}
 func (*Object_Service) isObject_Object()   {}
@@ -119,6 +123,7 @@ func (*Object_Cluster) isObject_Object()   {}
 func (*Object_Secret) isObject_Object()    {}
 func (*Object_Resource) isObject_Object()  {}
 func (*Object_Extension) isObject_Object() {}
+func (*Object_Config) isObject_Object()    {}
 
 func (m *Object) GetObject() isObject_Object {
 	if m != nil {
@@ -183,6 +188,13 @@ func (m *Object) GetExtension() *Extension {
 	return nil
 }
 
+func (m *Object) GetConfig() *Config {
+	if x, ok := m.GetObject().(*Object_Config); ok {
+		return x.Config
+	}
+	return nil
+}
+
 // XXX_OneofFuncs is for the internal use of the proto package.
 func (*Object) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
 	return _Object_OneofMarshaler, _Object_OneofUnmarshaler, _Object_OneofSizer, []interface{}{
@@ -194,6 +206,7 @@ func (*Object) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error,
 		(*Object_Secret)(nil),
 		(*Object_Resource)(nil),
 		(*Object_Extension)(nil),
+		(*Object_Config)(nil),
 	}
 }
 
@@ -241,6 +254,11 @@ func _Object_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
 		if err := b.EncodeMessage(x.Extension); err != nil {
 			return err
 		}
+	case *Object_Config:
+		_ = b.EncodeVarint(9<<3 | proto.WireBytes)
+		if err := b.EncodeMessage(x.Config); err != nil {
+			return err
+		}
 	case nil:
 	default:
 		return fmt.Errorf("Object.Object has unexpected type %T", x)
@@ -315,6 +333,14 @@ func _Object_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer)
 		err := b.DecodeMessage(msg)
 		m.Object = &Object_Extension{msg}
 		return true, err
+	case 9: // Object.config
+		if wire != proto.WireBytes {
+			return true, proto.ErrInternalBadWireType
+		}
+		msg := new(Config)
+		err := b.DecodeMessage(msg)
+		m.Object = &Object_Config{msg}
+		return true, err
 	default:
 		return false, nil
 	}
@@ -364,6 +390,11 @@ func _Object_OneofSizer(msg proto.Message) (n int) {
 		n += proto.SizeVarint(8<<3 | proto.WireBytes)
 		n += proto.SizeVarint(uint64(s))
 		n += s
+	case *Object_Config:
+		s := proto.Size(x.Config)
+		n += proto.SizeVarint(9<<3 | proto.WireBytes)
+		n += proto.SizeVarint(uint64(s))
+		n += s
 	case nil:
 	default:
 		panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
@@ -412,6 +443,7 @@ type SelectBy struct {
 	//	*SelectBy_Membership
 	//	*SelectBy_ReferencedNetworkID
 	//	*SelectBy_ReferencedSecretID
+	//	*SelectBy_ReferencedConfigID
 	//	*SelectBy_Kind
 	By isSelectBy_By `protobuf_oneof:"By"`
 }
@@ -468,6 +500,9 @@ type SelectBy_ReferencedNetworkID struct {
 type SelectBy_ReferencedSecretID struct {
 	ReferencedSecretID string `protobuf:"bytes,14,opt,name=referenced_secret_id,json=referencedSecretId,proto3,oneof"`
 }
+type SelectBy_ReferencedConfigID struct {
+	ReferencedConfigID string `protobuf:"bytes,16,opt,name=referenced_config_id,json=referencedConfigId,proto3,oneof"`
+}
 type SelectBy_Kind struct {
 	Kind string `protobuf:"bytes,15,opt,name=kind,proto3,oneof"`
 }
@@ -486,6 +521,7 @@ func (*SelectBy_Role) isSelectBy_By()                {}
 func (*SelectBy_Membership) isSelectBy_By()          {}
 func (*SelectBy_ReferencedNetworkID) isSelectBy_By() {}
 func (*SelectBy_ReferencedSecretID) isSelectBy_By()  {}
+func (*SelectBy_ReferencedConfigID) isSelectBy_By()  {}
 func (*SelectBy_Kind) isSelectBy_By()                {}
 
 func (m *SelectBy) GetBy() isSelectBy_By {
@@ -593,6 +629,13 @@ func (m *SelectBy) GetReferencedSecretID() string {
 	return ""
 }
 
+func (m *SelectBy) GetReferencedConfigID() string {
+	if x, ok := m.GetBy().(*SelectBy_ReferencedConfigID); ok {
+		return x.ReferencedConfigID
+	}
+	return ""
+}
+
 func (m *SelectBy) GetKind() string {
 	if x, ok := m.GetBy().(*SelectBy_Kind); ok {
 		return x.Kind
@@ -617,6 +660,7 @@ func (*SelectBy) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) erro
 		(*SelectBy_Membership)(nil),
 		(*SelectBy_ReferencedNetworkID)(nil),
 		(*SelectBy_ReferencedSecretID)(nil),
+		(*SelectBy_ReferencedConfigID)(nil),
 		(*SelectBy_Kind)(nil),
 	}
 }
@@ -673,6 +717,9 @@ func _SelectBy_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
 	case *SelectBy_ReferencedSecretID:
 		_ = b.EncodeVarint(14<<3 | proto.WireBytes)
 		_ = b.EncodeStringBytes(x.ReferencedSecretID)
+	case *SelectBy_ReferencedConfigID:
+		_ = b.EncodeVarint(16<<3 | proto.WireBytes)
+		_ = b.EncodeStringBytes(x.ReferencedConfigID)
 	case *SelectBy_Kind:
 		_ = b.EncodeVarint(15<<3 | proto.WireBytes)
 		_ = b.EncodeStringBytes(x.Kind)
@@ -787,6 +834,13 @@ func _SelectBy_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffe
 		x, err := b.DecodeStringBytes()
 		m.By = &SelectBy_ReferencedSecretID{x}
 		return true, err
+	case 16: // By.referenced_config_id
+		if wire != proto.WireBytes {
+			return true, proto.ErrInternalBadWireType
+		}
+		x, err := b.DecodeStringBytes()
+		m.By = &SelectBy_ReferencedConfigID{x}
+		return true, err
 	case 15: // By.kind
 		if wire != proto.WireBytes {
 			return true, proto.ErrInternalBadWireType
@@ -859,6 +913,10 @@ func _SelectBy_OneofSizer(msg proto.Message) (n int) {
 		n += proto.SizeVarint(14<<3 | proto.WireBytes)
 		n += proto.SizeVarint(uint64(len(x.ReferencedSecretID)))
 		n += len(x.ReferencedSecretID)
+	case *SelectBy_ReferencedConfigID:
+		n += proto.SizeVarint(16<<3 | proto.WireBytes)
+		n += proto.SizeVarint(uint64(len(x.ReferencedConfigID)))
+		n += len(x.ReferencedConfigID)
 	case *SelectBy_Kind:
 		n += proto.SizeVarint(15<<3 | proto.WireBytes)
 		n += proto.SizeVarint(uint64(len(x.Kind)))
@@ -1034,6 +1092,12 @@ func (m *Object) CopyFrom(src interface{}) {
 			}
 			github_com_docker_swarmkit_api_deepcopy.Copy(v.Extension, o.GetExtension())
 			m.Object = &v
+		case *Object_Config:
+			v := Object_Config{
+				Config: &Config{},
+			}
+			github_com_docker_swarmkit_api_deepcopy.Copy(v.Config, o.GetConfig())
+			m.Object = &v
 		}
 	}
 
@@ -1157,6 +1221,11 @@ func (m *SelectBy) CopyFrom(src interface{}) {
 				ReferencedSecretID: o.GetReferencedSecretID(),
 			}
 			m.By = &v
+		case *SelectBy_ReferencedConfigID:
+			v := SelectBy_ReferencedConfigID{
+				ReferencedConfigID: o.GetReferencedConfigID(),
+			}
+			m.By = &v
 		case *SelectBy_Kind:
 			v := SelectBy_Kind{
 				Kind: o.GetKind(),
@@ -1513,6 +1582,20 @@ func (m *Object_Extension) MarshalTo(dAtA []byte) (int, error) {
 	}
 	return i, nil
 }
+func (m *Object_Config) MarshalTo(dAtA []byte) (int, error) {
+	i := 0
+	if m.Config != nil {
+		dAtA[i] = 0x4a
+		i++
+		i = encodeVarintStore(dAtA, i, uint64(m.Config.Size()))
+		n10, err := m.Config.MarshalTo(dAtA[i:])
+		if err != nil {
+			return 0, err
+		}
+		i += n10
+	}
+	return i, nil
+}
 func (m *SelectBySlot) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	dAtA = make([]byte, size)
@@ -1594,11 +1677,11 @@ func (m *SelectBy) MarshalTo(dAtA []byte) (int, error) {
 	var l int
 	_ = l
 	if m.By != nil {
-		nn10, err := m.By.MarshalTo(dAtA[i:])
+		nn11, err := m.By.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += nn10
+		i += nn11
 	}
 	return i, nil
 }
@@ -1641,11 +1724,11 @@ func (m *SelectBy_Custom) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x2a
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.Custom.Size()))
-		n11, err := m.Custom.MarshalTo(dAtA[i:])
+		n12, err := m.Custom.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n11
+		i += n12
 	}
 	return i, nil
 }
@@ -1655,11 +1738,11 @@ func (m *SelectBy_CustomPrefix) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x32
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.CustomPrefix.Size()))
-		n12, err := m.CustomPrefix.MarshalTo(dAtA[i:])
+		n13, err := m.CustomPrefix.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n12
+		i += n13
 	}
 	return i, nil
 }
@@ -1685,11 +1768,11 @@ func (m *SelectBy_Slot) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x4a
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.Slot.Size()))
-		n13, err := m.Slot.MarshalTo(dAtA[i:])
+		n14, err := m.Slot.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n13
+		i += n14
 	}
 	return i, nil
 }
@@ -1738,6 +1821,16 @@ func (m *SelectBy_Kind) MarshalTo(dAtA []byte) (int, error) {
 	i += copy(dAtA[i:], m.Kind)
 	return i, nil
 }
+func (m *SelectBy_ReferencedConfigID) MarshalTo(dAtA []byte) (int, error) {
+	i := 0
+	dAtA[i] = 0x82
+	i++
+	dAtA[i] = 0x1
+	i++
+	i = encodeVarintStore(dAtA, i, uint64(len(m.ReferencedConfigID)))
+	i += copy(dAtA[i:], m.ReferencedConfigID)
+	return i, nil
+}
 func (m *WatchRequest) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	dAtA = make([]byte, size)
@@ -1769,11 +1862,11 @@ func (m *WatchRequest) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x12
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.ResumeFrom.Size()))
-		n14, err := m.ResumeFrom.MarshalTo(dAtA[i:])
+		n15, err := m.ResumeFrom.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n14
+		i += n15
 	}
 	if m.IncludeOldObject {
 		dAtA[i] = 0x18
@@ -1860,11 +1953,11 @@ func (m *WatchMessage) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x12
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.Version.Size()))
-		n15, err := m.Version.MarshalTo(dAtA[i:])
+		n16, err := m.Version.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n15
+		i += n16
 	}
 	return i, nil
 }
@@ -1893,21 +1986,21 @@ func (m *WatchMessage_Event) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x12
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.Object.Size()))
-		n16, err := m.Object.MarshalTo(dAtA[i:])
+		n17, err := m.Object.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n16
+		i += n17
 	}
 	if m.OldObject != nil {
 		dAtA[i] = 0x1a
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.OldObject.Size()))
-		n17, err := m.OldObject.MarshalTo(dAtA[i:])
+		n18, err := m.OldObject.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n17
+		i += n18
 	}
 	return i, nil
 }
@@ -2144,6 +2237,15 @@ func (m *Object_Extension) Size() (n int) {
 	}
 	return n
 }
+func (m *Object_Config) Size() (n int) {
+	var l int
+	_ = l
+	if m.Config != nil {
+		l = m.Config.Size()
+		n += 1 + l + sovStore(uint64(l))
+	}
+	return n
+}
 func (m *SelectBySlot) Size() (n int) {
 	var l int
 	_ = l
@@ -2292,6 +2394,13 @@ func (m *SelectBy_Kind) Size() (n int) {
 	n += 1 + l + sovStore(uint64(l))
 	return n
 }
+func (m *SelectBy_ReferencedConfigID) Size() (n int) {
+	var l int
+	_ = l
+	l = len(m.ReferencedConfigID)
+	n += 2 + l + sovStore(uint64(l))
+	return n
+}
 func (m *WatchRequest) Size() (n int) {
 	var l int
 	_ = l
@@ -2466,6 +2575,16 @@ func (this *Object_Extension) String() string {
 	}, "")
 	return s
 }
+func (this *Object_Config) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&Object_Config{`,
+		`Config:` + strings.Replace(fmt.Sprintf("%v", this.Config), "Config", "Config", 1) + `,`,
+		`}`,
+	}, "")
+	return s
+}
 func (this *SelectBySlot) String() string {
 	if this == nil {
 		return "nil"
@@ -2649,6 +2768,16 @@ func (this *SelectBy_Kind) String() string {
 	}, "")
 	return s
 }
+func (this *SelectBy_ReferencedConfigID) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&SelectBy_ReferencedConfigID{`,
+		`ReferencedConfigID:` + fmt.Sprintf("%v", this.ReferencedConfigID) + `,`,
+		`}`,
+	}, "")
+	return s
+}
 func (this *WatchRequest) String() string {
 	if this == nil {
 		return "nil"
@@ -2989,6 +3118,38 @@ func (m *Object) Unmarshal(dAtA []byte) error {
 			}
 			m.Object = &Object_Extension{v}
 			iNdEx = postIndex
+		case 9:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Config", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowStore
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthStore
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			v := &Config{}
+			if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			m.Object = &Object_Config{v}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipStore(dAtA[iNdEx:])
@@ -3691,6 +3852,35 @@ func (m *SelectBy) Unmarshal(dAtA []byte) error {
 			}
 			m.By = &SelectBy_Kind{string(dAtA[iNdEx:postIndex])}
 			iNdEx = postIndex
+		case 16:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ReferencedConfigID", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowStore
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthStore
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.By = &SelectBy_ReferencedConfigID{string(dAtA[iNdEx:postIndex])}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipStore(dAtA[iNdEx:])
@@ -4332,76 +4522,78 @@ var (
 func init() { proto.RegisterFile("store.proto", fileDescriptorStore) }
 
 var fileDescriptorStore = []byte{
-	// 1127 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x96, 0x4f, 0x6f, 0x1b, 0xc5,
-	0x1b, 0xc7, 0xbd, 0x8e, 0xb3, 0xb6, 0x1f, 0xc7, 0x6d, 0x34, 0x49, 0xdb, 0xfd, 0xf9, 0x57, 0x6c,
-	0x63, 0x04, 0x54, 0xb4, 0xb8, 0x10, 0x4a, 0x11, 0x50, 0x90, 0x62, 0xc7, 0xc8, 0xa6, 0x8a, 0x13,
-	0x8d, 0x93, 0xe6, 0x68, 0x6d, 0x76, 0x9f, 0xa4, 0x8b, 0xf7, 0x8f, 0x99, 0x1d, 0x3b, 0xcd, 0x8d,
-	0x23, 0xea, 0x1d, 0x89, 0x4b, 0xb9, 0xc0, 0x99, 0x0b, 0x37, 0x78, 0x03, 0x15, 0x07, 0xc4, 0x11,
-	0x2e, 0x16, 0xf5, 0x0b, 0xe0, 0x15, 0x70, 0x40, 0x33, 0x3b, 0x9b, 0x3f, 0xee, 0x3a, 0xa5, 0x27,
-	0xcf, 0xcc, 0x7e, 0x3f, 0xcf, 0x3e, 0xf3, 0x7c, 0x67, 0x1e, 0x2f, 0x14, 0x42, 0x1e, 0x30, 0xac,
-	0x0f, 0x59, 0xc0, 0x03, 0x42, 0xec, 0xc0, 0x1a, 0x20, 0xab, 0x87, 0x47, 0x26, 0xf3, 0x06, 0x0e,
-	0xaf, 0x8f, 0xdf, 0x2d, 0x15, 0xc2, 0x21, 0x5a, 0x61, 0x24, 0x28, 0x15, 0x83, 0xfd, 0x2f, 0xd0,
-	0xe2, 0xf1, 0xb4, 0xc0, 0x8f, 0x87, 0x18, 0x4f, 0x56, 0x0f, 0x83, 0xc3, 0x40, 0x0e, 0x6f, 0x8b,
-	0x91, 0x5a, 0x5d, 0x19, 0xba, 0xa3, 0x43, 0xc7, 0xbf, 0x1d, 0xfd, 0x44, 0x8b, 0xb5, 0xdf, 0x16,
-	0x40, 0xdf, 0x92, 0x91, 0x48, 0x1d, 0x32, 0x7e, 0x60, 0xa3, 0xa1, 0x55, 0xb5, 0x1b, 0x85, 0x35,
-	0xa3, 0xfe, 0x7c, 0x06, 0xf5, 0x6e, 0x60, 0x63, 0x3b, 0x45, 0xa5, 0x8e, 0x7c, 0x00, 0xd9, 0x10,
-	0xd9, 0xd8, 0xb1, 0xd0, 0x48, 0x4b, 0xe4, 0xff, 0x49, 0x48, 0x2f, 0x92, 0xb4, 0x53, 0x34, 0x56,
-	0x0b, 0xd0, 0x47, 0x7e, 0x14, 0xb0, 0x81, 0xb1, 0x30, 0x1f, 0xec, 0x46, 0x12, 0x01, 0x2a, 0xb5,
-	0xc8, 0x90, 0x9b, 0xe1, 0xc0, 0xc8, 0xcc, 0xcf, 0x70, 0xc7, 0x0c, 0x05, 0x22, 0x75, 0xe2, 0x45,
-	0x96, 0x3b, 0x0a, 0x39, 0x32, 0x63, 0x71, 0xfe, 0x8b, 0x9a, 0x91, 0x44, 0xbc, 0x48, 0xa9, 0xc9,
-	0x1d, 0xd0, 0x43, 0xb4, 0x18, 0x72, 0x43, 0x97, 0x5c, 0x29, 0x79, 0x67, 0x42, 0xd1, 0x4e, 0x51,
-	0xa5, 0x25, 0x1f, 0x41, 0x8e, 0x61, 0x18, 0x8c, 0x98, 0x85, 0x46, 0x56, 0x72, 0xd7, 0x93, 0x38,
-	0xaa, 0x34, 0xed, 0x14, 0x3d, 0xd1, 0x93, 0x4f, 0x20, 0x8f, 0x8f, 0x38, 0xfa, 0xa1, 0x13, 0xf8,
-	0x46, 0x4e, 0xc2, 0xaf, 0x24, 0xc1, 0xad, 0x58, 0xd4, 0x4e, 0xd1, 0x53, 0xa2, 0x91, 0x8b, 0x5d,
-	0xac, 0x6d, 0xc3, 0x52, 0x0f, 0x5d, 0xb4, 0x78, 0xe3, 0xb8, 0xe7, 0x06, 0x9c, 0xdc, 0x02, 0x50,
-	0x75, 0xef, 0x3b, 0xb6, 0xf4, 0x36, 0xdf, 0x28, 0x4e, 0x27, 0x95, 0xbc, 0x32, 0xa6, 0xb3, 0x41,
-	0xf3, 0x4a, 0xd0, 0xb1, 0x09, 0x81, 0x4c, 0xe8, 0x06, 0x5c, 0x1a, 0x9a, 0xa1, 0x72, 0x5c, 0xdb,
-	0x86, 0x4b, 0x71, 0xc4, 0xe6, 0x28, 0xe4, 0x81, 0x27, 0x54, 0x03, 0xc7, 0x57, 0xd1, 0xa8, 0x1c,
-	0x93, 0x55, 0x58, 0x74, 0x7c, 0x1b, 0x1f, 0x49, 0x34, 0x4f, 0xa3, 0x89, 0x58, 0x1d, 0x9b, 0xee,
-	0x08, 0xa5, 0xd1, 0x79, 0x1a, 0x4d, 0x6a, 0xdf, 0xe9, 0x90, 0x8b, 0x43, 0x12, 0x03, 0xd2, 0x27,
-	0x89, 0xe9, 0xd3, 0x49, 0x25, 0xdd, 0xd9, 0x68, 0xa7, 0x68, 0xda, 0xb1, 0xc9, 0x4d, 0xc8, 0x3b,
-	0x76, 0x7f, 0xc8, 0xf0, 0xc0, 0x51, 0x61, 0x1b, 0x4b, 0xd3, 0x49, 0x25, 0xd7, 0xd9, 0xd8, 0x96,
-	0x6b, 0xa2, 0x80, 0x8e, 0x1d, 0x8d, 0xc9, 0x2a, 0x64, 0x7c, 0xd3, 0x53, 0x2f, 0x92, 0x67, 0xd4,
-	0xf4, 0x90, 0xbc, 0x0a, 0x05, 0xf1, 0x1b, 0x07, 0xc9, 0xa8, 0x87, 0x20, 0x16, 0x15, 0x78, 0x0f,
-	0x74, 0x4b, 0x6e, 0x4b, 0x9d, 0x91, 0x5a, 0xb2, 0xd7, 0x67, 0x0b, 0x20, 0x3c, 0x8f, 0x18, 0xd2,
-	0x81, 0x62, 0x34, 0x8a, 0x5f, 0xa1, 0xbf, 0x44, 0x90, 0xa5, 0x08, 0x55, 0x89, 0xd4, 0xcf, 0x39,
-	0x95, 0x4d, 0x70, 0x4a, 0x78, 0x7e, 0xea, 0xd5, 0xeb, 0x90, 0x15, 0xf7, 0x50, 0x88, 0x73, 0x52,
-	0x0c, 0xd3, 0x49, 0x45, 0x17, 0x57, 0x54, 0x2a, 0x75, 0xf1, 0xb0, 0x63, 0x93, 0xbb, 0xca, 0xd2,
-	0xbc, 0x4c, 0xac, 0x7a, 0x51, 0x62, 0xe2, 0xc0, 0x88, 0xd2, 0x09, 0x3d, 0xd9, 0x80, 0xa2, 0x8d,
-	0xa1, 0xc3, 0xd0, 0xee, 0x87, 0xdc, 0xe4, 0x68, 0x40, 0x55, 0xbb, 0x71, 0x29, 0xf9, 0x54, 0x8a,
-	0x5b, 0xd7, 0x13, 0x22, 0xb1, 0x29, 0x45, 0xc9, 0x39, 0x59, 0x83, 0x0c, 0x0b, 0x5c, 0x34, 0x0a,
-	0x12, 0xbe, 0x3e, 0xaf, 0xa9, 0xd0, 0xc0, 0x95, 0x8d, 0x45, 0x68, 0x49, 0x07, 0xc0, 0x43, 0x6f,
-	0x1f, 0x59, 0xf8, 0xd0, 0x19, 0x1a, 0x4b, 0x92, 0x7c, 0x73, 0x1e, 0xd9, 0x1b, 0xa2, 0x55, 0xdf,
-	0x3c, 0x91, 0x0b, 0x73, 0x4f, 0x61, 0xb2, 0x09, 0x57, 0x18, 0x1e, 0x20, 0x43, 0xdf, 0x42, 0xbb,
-	0xaf, 0xfa, 0x88, 0xa8, 0x58, 0x51, 0x56, 0xec, 0xda, 0x74, 0x52, 0x59, 0xa1, 0x27, 0x02, 0xd5,
-	0x72, 0x64, 0xf9, 0x56, 0xd8, 0x73, 0xcb, 0x36, 0xf9, 0x1c, 0x56, 0xcf, 0x84, 0x8b, 0xae, 0xbd,
-	0x88, 0x76, 0x49, 0x46, 0xbb, 0x3a, 0x9d, 0x54, 0xc8, 0x69, 0xb4, 0xa8, 0x3f, 0xc8, 0x60, 0x84,
-	0xcd, 0xae, 0x8a, 0x0b, 0x13, 0x5d, 0xa2, 0xcb, 0xf1, 0x81, 0x15, 0xb3, 0x46, 0x06, 0xd2, 0x8d,
-	0xe3, 0xda, 0x9f, 0x69, 0x58, 0xda, 0x33, 0xb9, 0xf5, 0x90, 0xe2, 0x97, 0x23, 0x0c, 0x39, 0x69,
-	0x41, 0x16, 0x7d, 0xce, 0x1c, 0x0c, 0x0d, 0xad, 0xba, 0x70, 0xa3, 0xb0, 0x76, 0x33, 0xa9, 0x1e,
-	0x67, 0x91, 0x68, 0xd2, 0xf2, 0x39, 0x3b, 0xa6, 0x31, 0x4b, 0xee, 0x41, 0x81, 0x61, 0x38, 0xf2,
-	0xb0, 0x7f, 0xc0, 0x02, 0xef, 0xa2, 0xb6, 0xfd, 0x00, 0x99, 0x68, 0x2c, 0x14, 0x22, 0xfd, 0x67,
-	0x2c, 0xf0, 0xc8, 0x2d, 0x20, 0x8e, 0x6f, 0xb9, 0x23, 0x1b, 0xfb, 0x81, 0x6b, 0xf7, 0xa3, 0x3f,
-	0x20, 0x79, 0xe1, 0x72, 0x74, 0x59, 0x3d, 0xd9, 0x72, 0xed, 0xa8, 0x11, 0x95, 0xbe, 0xd1, 0x00,
-	0x4e, 0x73, 0x48, 0xec, 0x19, 0x1f, 0x83, 0x6e, 0x5a, 0x5c, 0x74, 0xbc, 0xb4, 0x34, 0xf9, 0xb5,
-	0xb9, 0x9b, 0x5a, 0x97, 0xb2, 0xfb, 0x8e, 0x6f, 0x53, 0x85, 0x90, 0xbb, 0x90, 0x3d, 0x70, 0x5c,
-	0x8e, 0x2c, 0x34, 0x16, 0x64, 0x49, 0xae, 0x5f, 0x74, 0xb4, 0x69, 0x2c, 0xae, 0xfd, 0x12, 0xd7,
-	0x76, 0x13, 0xc3, 0xd0, 0x3c, 0x44, 0xf2, 0x29, 0xe8, 0x38, 0x46, 0x9f, 0xc7, 0xa5, 0x7d, 0x63,
-	0x6e, 0x16, 0x8a, 0xa8, 0xb7, 0x84, 0x9c, 0x2a, 0x8a, 0xbc, 0x0f, 0xd9, 0x71, 0x54, 0xad, 0xff,
-	0x52, 0xd0, 0x58, 0x5b, 0xfa, 0x49, 0x83, 0x45, 0x19, 0xe8, 0x4c, 0x19, 0xb4, 0x97, 0x2f, 0xc3,
-	0x1a, 0xe8, 0xca, 0x88, 0xf4, 0xfc, 0xbf, 0xaa, 0xc8, 0x12, 0xaa, 0x94, 0xe4, 0x43, 0x80, 0x19,
-	0x03, 0x2f, 0xe6, 0xf2, 0x41, 0xec, 0xea, 0x5b, 0xff, 0x68, 0x70, 0x79, 0x26, 0x15, 0x72, 0x07,
-	0x56, 0xf7, 0xd6, 0x77, 0x9a, 0xed, 0xfe, 0x7a, 0x73, 0xa7, 0xb3, 0xd5, 0xed, 0xef, 0x76, 0xef,
-	0x77, 0xb7, 0xf6, 0xba, 0xcb, 0xa9, 0x52, 0xe9, 0xf1, 0x93, 0xea, 0xd5, 0x19, 0xf9, 0xae, 0x3f,
-	0xf0, 0x83, 0x23, 0x91, 0xf8, 0xca, 0x39, 0xaa, 0x49, 0x5b, 0xeb, 0x3b, 0xad, 0x65, 0xad, 0xf4,
-	0xbf, 0xc7, 0x4f, 0xaa, 0x57, 0x66, 0xa0, 0x26, 0xc3, 0xa8, 0x9b, 0x9c, 0x67, 0x76, 0xb7, 0x37,
-	0x04, 0x93, 0x4e, 0x64, 0x76, 0x87, 0x76, 0x12, 0x43, 0x5b, 0x9b, 0x5b, 0x0f, 0x5a, 0xcb, 0x99,
-	0x44, 0x86, 0xa2, 0x17, 0x8c, 0xb1, 0x74, 0xed, 0xeb, 0xef, 0xcb, 0xa9, 0x9f, 0x7f, 0x28, 0xcf,
-	0x6e, 0x75, 0xcd, 0x83, 0xc5, 0x9e, 0xf8, 0x4a, 0x23, 0x36, 0x2c, 0xca, 0x67, 0xa4, 0xfa, 0xa2,
-	0x8b, 0x58, 0xaa, 0xbe, 0xe8, 0x3c, 0xd5, 0xae, 0xfc, 0xfa, 0xe3, 0xdf, 0xdf, 0xa6, 0x2f, 0x43,
-	0x51, 0x2a, 0xde, 0xf6, 0x4c, 0xdf, 0x3c, 0x44, 0xf6, 0x8e, 0xd6, 0x30, 0x9e, 0x3e, 0x2b, 0xa7,
-	0xfe, 0x78, 0x56, 0x4e, 0x7d, 0x35, 0x2d, 0x6b, 0x4f, 0xa7, 0x65, 0xed, 0xf7, 0x69, 0x59, 0xfb,
-	0x6b, 0x5a, 0xd6, 0xf6, 0x75, 0xf9, 0xf9, 0xf6, 0xde, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa9,
-	0xa5, 0x8e, 0xe6, 0x35, 0x0a, 0x00, 0x00,
+	// 1160 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x96, 0xbd, 0x73, 0x1b, 0xc5,
+	0x1b, 0xc7, 0x75, 0x8a, 0x7c, 0x92, 0x1e, 0xd9, 0x89, 0x67, 0xed, 0x24, 0xf7, 0xd3, 0x2f, 0xc8,
+	0x42, 0x0c, 0x90, 0x21, 0x41, 0x01, 0x13, 0xc2, 0x00, 0x81, 0x19, 0x4b, 0x16, 0x23, 0x91, 0xf1,
+	0xcb, 0xac, 0xec, 0xa4, 0xd4, 0x5c, 0xee, 0x1e, 0x2b, 0x87, 0xee, 0x6e, 0xc5, 0xde, 0x49, 0x89,
+	0x3b, 0x0a, 0x0a, 0x26, 0x3d, 0x33, 0x34, 0xa9, 0xa0, 0xa6, 0xa1, 0x83, 0x7f, 0x20, 0x43, 0x45,
+	0x09, 0x8d, 0x86, 0xa8, 0xa4, 0xe0, 0x2f, 0xa0, 0x60, 0xf6, 0xe5, 0xfc, 0xa2, 0x9c, 0x1c, 0x52,
+	0x69, 0x77, 0xef, 0xf3, 0x7d, 0xf6, 0xb9, 0xe7, 0xed, 0x04, 0xa5, 0x28, 0x66, 0x1c, 0xeb, 0x43,
+	0xce, 0x62, 0x46, 0x88, 0xcb, 0x9c, 0x01, 0xf2, 0x7a, 0xf4, 0xd0, 0xe6, 0xc1, 0xc0, 0x8b, 0xeb,
+	0xe3, 0x77, 0xcb, 0xa5, 0x68, 0x88, 0x4e, 0xa4, 0x80, 0xf2, 0x12, 0xbb, 0xff, 0x05, 0x3a, 0x71,
+	0xb2, 0x2d, 0xc5, 0x87, 0x43, 0x4c, 0x36, 0xab, 0x7d, 0xd6, 0x67, 0x72, 0x79, 0x43, 0xac, 0xf4,
+	0xe9, 0xca, 0xd0, 0x1f, 0xf5, 0xbd, 0xf0, 0x86, 0xfa, 0x51, 0x87, 0xb5, 0xaf, 0x73, 0x60, 0xee,
+	0x48, 0x4b, 0xa4, 0x0e, 0xb9, 0x90, 0xb9, 0x68, 0x19, 0x55, 0xe3, 0x6a, 0x69, 0xdd, 0xaa, 0x3f,
+	0xef, 0x41, 0x7d, 0x9b, 0xb9, 0xd8, 0xce, 0x50, 0xc9, 0x91, 0x0f, 0x20, 0x1f, 0x21, 0x1f, 0x7b,
+	0x0e, 0x5a, 0x59, 0x29, 0xf9, 0x7f, 0x9a, 0xa4, 0xab, 0x90, 0x76, 0x86, 0x26, 0xb4, 0x10, 0x86,
+	0x18, 0x3f, 0x64, 0x7c, 0x60, 0x9d, 0x9b, 0x2f, 0xdc, 0x56, 0x88, 0x10, 0x6a, 0x5a, 0x78, 0x18,
+	0xdb, 0xd1, 0xc0, 0xca, 0xcd, 0xf7, 0x70, 0xcf, 0x8e, 0x84, 0x44, 0x72, 0xe2, 0x22, 0xc7, 0x1f,
+	0x45, 0x31, 0x72, 0x6b, 0x61, 0xfe, 0x45, 0x4d, 0x85, 0x88, 0x8b, 0x34, 0x4d, 0x6e, 0x82, 0x19,
+	0xa1, 0xc3, 0x31, 0xb6, 0x4c, 0xa9, 0x2b, 0xa7, 0xbf, 0x99, 0x20, 0xda, 0x19, 0xaa, 0x59, 0xf2,
+	0x11, 0x14, 0x38, 0x46, 0x6c, 0xc4, 0x1d, 0xb4, 0xf2, 0x52, 0x77, 0x25, 0x4d, 0x47, 0x35, 0xd3,
+	0xce, 0xd0, 0x23, 0x9e, 0x7c, 0x02, 0x45, 0x7c, 0x14, 0x63, 0x18, 0x79, 0x2c, 0xb4, 0x0a, 0x52,
+	0xfc, 0x4a, 0x9a, 0xb8, 0x95, 0x40, 0xed, 0x0c, 0x3d, 0x56, 0x08, 0x87, 0x1d, 0x16, 0x1e, 0x78,
+	0x7d, 0xab, 0x38, 0xdf, 0xe1, 0xa6, 0x24, 0x84, 0xc3, 0x8a, 0x6d, 0x14, 0x92, 0xdc, 0xd7, 0x76,
+	0x61, 0xb1, 0x8b, 0x3e, 0x3a, 0x71, 0xe3, 0xb0, 0xeb, 0xb3, 0x98, 0x5c, 0x07, 0xd0, 0xd9, 0xea,
+	0x79, 0xae, 0xac, 0x88, 0x62, 0x63, 0x69, 0x3a, 0x59, 0x2b, 0xea, 0x74, 0x76, 0x36, 0x69, 0x51,
+	0x03, 0x1d, 0x97, 0x10, 0xc8, 0x45, 0x3e, 0x8b, 0x65, 0x19, 0xe4, 0xa8, 0x5c, 0xd7, 0x76, 0xe1,
+	0x7c, 0x62, 0xb1, 0x39, 0x8a, 0x62, 0x16, 0x08, 0x6a, 0xe0, 0x85, 0xda, 0x1a, 0x95, 0x6b, 0xb2,
+	0x0a, 0x0b, 0x5e, 0xe8, 0xe2, 0x23, 0x29, 0x2d, 0x52, 0xb5, 0x11, 0xa7, 0x63, 0xdb, 0x1f, 0xa1,
+	0x2c, 0x8f, 0x22, 0x55, 0x9b, 0xda, 0x5f, 0x26, 0x14, 0x12, 0x93, 0xc4, 0x82, 0xec, 0x91, 0x63,
+	0xe6, 0x74, 0xb2, 0x96, 0xed, 0x6c, 0xb6, 0x33, 0x34, 0xeb, 0xb9, 0xe4, 0x1a, 0x14, 0x3d, 0xb7,
+	0x37, 0xe4, 0x78, 0xe0, 0x69, 0xb3, 0x8d, 0xc5, 0xe9, 0x64, 0xad, 0xd0, 0xd9, 0xdc, 0x95, 0x67,
+	0x22, 0xec, 0x9e, 0xab, 0xd6, 0x64, 0x15, 0x72, 0xa1, 0x1d, 0xe8, 0x8b, 0x64, 0x65, 0xdb, 0x01,
+	0x92, 0x57, 0xa1, 0x24, 0x7e, 0x13, 0x23, 0x39, 0xfd, 0x10, 0xc4, 0xa1, 0x16, 0xde, 0x06, 0xd3,
+	0x91, 0xaf, 0xa5, 0x2b, 0xab, 0x96, 0x5e, 0x21, 0x27, 0x03, 0x20, 0x03, 0xaf, 0x42, 0xd1, 0x81,
+	0x25, 0xb5, 0x4a, 0xae, 0x30, 0x5f, 0xc2, 0xc8, 0xa2, 0x92, 0x6a, 0x47, 0xea, 0xa7, 0x32, 0x95,
+	0x4f, 0xc9, 0x94, 0xa8, 0x94, 0xe3, 0x5c, 0xbd, 0x0e, 0x79, 0xd1, 0xbd, 0x02, 0x2e, 0x48, 0x18,
+	0xa6, 0x93, 0x35, 0x53, 0x34, 0xb6, 0x24, 0x4d, 0xf1, 0xb0, 0xe3, 0x92, 0x5b, 0x3a, 0xa5, 0xaa,
+	0x9c, 0xaa, 0x67, 0x39, 0x26, 0x0a, 0x46, 0x84, 0x4e, 0xf0, 0x64, 0x13, 0x96, 0x5c, 0x8c, 0x3c,
+	0x8e, 0x6e, 0x2f, 0x8a, 0xed, 0x18, 0x2d, 0xa8, 0x1a, 0x57, 0xcf, 0xa7, 0xd7, 0xb2, 0xe8, 0xd5,
+	0xae, 0x80, 0xc4, 0x4b, 0x69, 0x95, 0xdc, 0x93, 0x75, 0xc8, 0x71, 0xe6, 0xa3, 0x55, 0x92, 0xe2,
+	0x2b, 0xf3, 0x46, 0x11, 0x65, 0xbe, 0x1c, 0x47, 0x82, 0x25, 0x1d, 0x80, 0x00, 0x83, 0xfb, 0xc8,
+	0xa3, 0x07, 0xde, 0xd0, 0x5a, 0x94, 0xca, 0x37, 0xe7, 0x29, 0xbb, 0x43, 0x74, 0xea, 0x5b, 0x47,
+	0xb8, 0x48, 0xee, 0xb1, 0x98, 0x6c, 0xc1, 0x45, 0x8e, 0x07, 0xc8, 0x31, 0x74, 0xd0, 0xed, 0xe9,
+	0xe9, 0x23, 0x22, 0xb6, 0x24, 0x23, 0x76, 0x79, 0x3a, 0x59, 0x5b, 0xa1, 0x47, 0x80, 0x1e, 0x54,
+	0x32, 0x7c, 0x2b, 0xfc, 0xb9, 0x63, 0x97, 0x7c, 0x0e, 0xab, 0x27, 0xcc, 0xa9, 0x61, 0x21, 0xac,
+	0x9d, 0x97, 0xd6, 0x2e, 0x4d, 0x27, 0x6b, 0xe4, 0xd8, 0x9a, 0x9a, 0x2a, 0xd2, 0x18, 0xe1, 0xb3,
+	0xa7, 0xa2, 0x61, 0x54, 0x13, 0x5d, 0x48, 0x0a, 0x56, 0xb6, 0xd1, 0xe9, 0x1b, 0x54, 0x77, 0x8b,
+	0x1b, 0x96, 0xd3, 0x6e, 0x50, 0x63, 0x60, 0xf6, 0x06, 0x7d, 0xea, 0x36, 0x72, 0x90, 0x6d, 0x1c,
+	0xd6, 0xfe, 0xc8, 0xc2, 0xe2, 0x3d, 0x3b, 0x76, 0x1e, 0x50, 0xfc, 0x72, 0x84, 0x51, 0x4c, 0x5a,
+	0x90, 0xc7, 0x30, 0xe6, 0x1e, 0x46, 0x96, 0x51, 0x3d, 0x77, 0xb5, 0xb4, 0x7e, 0x2d, 0x2d, 0xb6,
+	0x27, 0x25, 0x6a, 0xd3, 0x0a, 0x63, 0x7e, 0x48, 0x13, 0x2d, 0xb9, 0x0d, 0x25, 0x8e, 0xd1, 0x28,
+	0xc0, 0xde, 0x01, 0x67, 0xc1, 0x59, 0x1f, 0x8e, 0xbb, 0xc8, 0xc5, 0x68, 0xa3, 0xa0, 0xf8, 0xcf,
+	0x38, 0x0b, 0xc8, 0x75, 0x20, 0x5e, 0xe8, 0xf8, 0x23, 0x17, 0x7b, 0xcc, 0x77, 0x7b, 0xea, 0x13,
+	0x28, 0x9b, 0xb7, 0x40, 0x97, 0xf5, 0x93, 0x1d, 0xdf, 0x55, 0x43, 0xad, 0xfc, 0xad, 0x01, 0x70,
+	0xec, 0x43, 0xea, 0xfc, 0xf9, 0x18, 0x4c, 0xdb, 0x89, 0xc5, 0xcc, 0xcd, 0xca, 0x82, 0x79, 0x6d,
+	0xee, 0x4b, 0x6d, 0x48, 0xec, 0x8e, 0x17, 0xba, 0x54, 0x4b, 0xc8, 0x2d, 0xc8, 0x1f, 0x78, 0x7e,
+	0x8c, 0x3c, 0xb2, 0xce, 0xc9, 0x90, 0x5c, 0x39, 0xab, 0x4d, 0x68, 0x02, 0xd7, 0x7e, 0x49, 0x62,
+	0xbb, 0x85, 0x51, 0x64, 0xf7, 0x91, 0x7c, 0x0a, 0x26, 0x8e, 0x31, 0x8c, 0x93, 0xd0, 0xbe, 0x31,
+	0xd7, 0x0b, 0xad, 0xa8, 0xb7, 0x04, 0x4e, 0xb5, 0x8a, 0xbc, 0x0f, 0xf9, 0xb1, 0x8a, 0xd6, 0x7f,
+	0x09, 0x68, 0xc2, 0x96, 0x7f, 0x32, 0x60, 0x41, 0x1a, 0x3a, 0x11, 0x06, 0xe3, 0xe5, 0xc3, 0xb0,
+	0x0e, 0xa6, 0x4e, 0x44, 0x76, 0xfe, 0xb7, 0x47, 0xa5, 0x84, 0x6a, 0x92, 0x7c, 0x08, 0x30, 0x93,
+	0xc0, 0xb3, 0x75, 0x45, 0x96, 0x64, 0xf5, 0xad, 0x7f, 0x0c, 0xb8, 0x30, 0xe3, 0x0a, 0xb9, 0x09,
+	0xab, 0xf7, 0x36, 0xf6, 0x9a, 0xed, 0xde, 0x46, 0x73, 0xaf, 0xb3, 0xb3, 0xdd, 0xdb, 0xdf, 0xbe,
+	0xb3, 0xbd, 0x73, 0x6f, 0x7b, 0x39, 0x53, 0x2e, 0x3f, 0x7e, 0x52, 0xbd, 0x34, 0x83, 0xef, 0x87,
+	0x83, 0x90, 0x3d, 0x14, 0x8e, 0xaf, 0x9c, 0x52, 0x35, 0x69, 0x6b, 0x63, 0xaf, 0xb5, 0x6c, 0x94,
+	0xff, 0xf7, 0xf8, 0x49, 0xf5, 0xe2, 0x8c, 0xa8, 0xc9, 0x51, 0x4d, 0xa6, 0xd3, 0x9a, 0xfd, 0xdd,
+	0x4d, 0xa1, 0xc9, 0xa6, 0x6a, 0xf6, 0x87, 0x6e, 0x9a, 0x86, 0xb6, 0xb6, 0x76, 0xee, 0xb6, 0x96,
+	0x73, 0xa9, 0x1a, 0x8a, 0x01, 0x1b, 0x63, 0xf9, 0xf2, 0x37, 0xdf, 0x57, 0x32, 0x3f, 0xff, 0x50,
+	0x99, 0x7d, 0xd5, 0xf5, 0x00, 0x16, 0xba, 0xe2, 0x7f, 0x22, 0x71, 0x61, 0x41, 0x3e, 0x23, 0xd5,
+	0x17, 0x35, 0x62, 0xb9, 0xfa, 0xa2, 0x7a, 0xaa, 0x5d, 0xfc, 0xf5, 0xc7, 0xbf, 0xbf, 0xcb, 0x5e,
+	0x80, 0x25, 0x49, 0xbc, 0x1d, 0xd8, 0xa1, 0xdd, 0x47, 0xfe, 0x8e, 0xd1, 0xb0, 0x9e, 0x3e, 0xab,
+	0x64, 0x7e, 0x7f, 0x56, 0xc9, 0x7c, 0x35, 0xad, 0x18, 0x4f, 0xa7, 0x15, 0xe3, 0xb7, 0x69, 0xc5,
+	0xf8, 0x73, 0x5a, 0x31, 0xee, 0x9b, 0xf2, 0x0f, 0xe4, 0x7b, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff,
+	0x9d, 0xb1, 0x59, 0x21, 0xb7, 0x0a, 0x00, 0x00,
 }

+ 2 - 0
vendor/github.com/docker/swarmkit/api/store.proto

@@ -18,6 +18,7 @@ message Object {
 		Secret secret = 6;
 		Resource resource = 7;
 		Extension extension = 8;
+		Config config = 9;
 	}
 }
 
@@ -60,6 +61,7 @@ message SelectBy {
 		// supported by: service, task
 		string referenced_network_id = 13 [(gogoproto.customname) = "ReferencedNetworkID"];
 		string referenced_secret_id = 14 [(gogoproto.customname) = "ReferencedSecretID"];
+		string referenced_config_id = 16 [(gogoproto.customname) = "ReferencedConfigID"];
 
 		// supported by: resource
 		string kind = 15;

Diff do ficheiro suprimidas por serem muito extensas
+ 398 - 77
vendor/github.com/docker/swarmkit/api/types.pb.go


+ 62 - 12
vendor/github.com/docker/swarmkit/api/types.proto

@@ -86,6 +86,18 @@ message NodeDescription {
 
 	// Information about the Docker Engine on the node.
 	EngineDescription engine = 4;
+
+	// Information on the node's TLS setup
+	NodeTLSInfo tls_info = 5 [(gogoproto.customname) = "TLSInfo"];
+}
+
+message NodeTLSInfo {
+	// Information about which root certs the node trusts
+	bytes trust_root = 1;
+
+	// Information about the node's current TLS certificate
+	bytes cert_issuer_subject = 2;
+	bytes cert_issuer_public_key = 3;
 }
 
 message RaftMemberStatus {
@@ -853,6 +865,20 @@ message ManagerStatus {
 	RaftMemberStatus.Reachability reachability = 4;
 }
 
+// FileTarget represents a specific target that is backed by a file
+message FileTarget {
+	// Name represents the final filename in the filesystem
+	string name = 1;
+
+	// UID represents the file UID
+	string uid = 2 [(gogoproto.customname) = "UID"];
+
+	// GID represents the file GID
+	string gid = 3 [(gogoproto.customname) = "GID"];
+
+	// Mode represents the FileMode of the file
+	uint32 mode = 4 [(gogoproto.customtype) = "os.FileMode", (gogoproto.nullable) = false];
+}
 
 // SecretReference is the linkage between a service and a secret that it uses.
 message SecretReference {
@@ -865,20 +891,21 @@ message SecretReference {
 	// lookup/display purposes.  The secret in the reference will be identified by its ID.
 	string secret_name = 2;
 
-	// FileTarget represents a specific target that is backed by a file
-	message FileTarget {
-		// Name represents the final filename in the filesystem
-		string name = 1;
-
-		// UID represents the file UID
-		string uid = 2 [(gogoproto.customname) = "UID"];
+	// Target specifies how this secret should be exposed to the task.
+	oneof target {
+		FileTarget file = 3;
+	}
+}
 
-		// GID represents the file GID
-		string gid = 3 [(gogoproto.customname) = "GID"];
+// ConfigReference is the linkage between a service and a config that it uses.
+message ConfigReference {
+	// ConfigID represents the ID of the specific Config that we're
+	// referencing.
+	string config_id = 1;
 
-		// Mode represents the FileMode of the file
-		uint32 mode = 4 [(gogoproto.customtype) = "os.FileMode", (gogoproto.nullable) = false];
-	}
+	// ConfigName is the name of the config that this references, but this is just provided for
+	// lookup/display purposes. The config in the reference will be identified by its ID.
+	string config_name = 2;
 
 	// Target specifies how this secret should be exposed to the task.
 	oneof target {
@@ -943,3 +970,26 @@ message RootRotation {
 	// cross-signed CA cert is the CACert that has been cross-signed by the previous root
 	bytes cross_signed_ca_cert = 3 [(gogoproto.customname) = "CrossSignedCACert"];
 }
+
+// Privileges specifies security configuration/permissions.
+message Privileges {
+	// CredentialSpec for managed service account (Windows only).
+	message CredentialSpec {
+		oneof source {
+			string file = 1;
+			string registry = 2;
+		}
+	}
+	CredentialSpec credential_spec = 1;
+
+	// SELinuxContext contains the SELinux labels for the container.
+	message SELinuxContext {
+		bool disable = 1;
+
+		string user = 2;
+		string role = 3;
+		string type = 4;
+		string level = 5;
+	}
+	SELinuxContext selinux_context = 2 [(gogoproto.customname) = "SELinuxContext"];
+}

+ 78 - 35
vendor/github.com/docker/swarmkit/ca/certificates.go

@@ -104,6 +104,12 @@ type CertPaths struct {
 	Cert, Key string
 }
 
+// IssuerInfo contains the subject and public key of the issuer of a certificate
+type IssuerInfo struct {
+	Subject   []byte
+	PublicKey []byte
+}
+
 // LocalSigner is a signer that can sign CSRs
 type LocalSigner struct {
 	cfsigner.Signer
@@ -192,39 +198,47 @@ func (rca *RootCA) Signer() (*LocalSigner, error) {
 }
 
 // IssueAndSaveNewCertificates generates a new key-pair, signs it with the local root-ca, and returns a
-// tls certificate
-func (rca *RootCA) IssueAndSaveNewCertificates(kw KeyWriter, cn, ou, org string) (*tls.Certificate, error) {
+// TLS certificate and the issuer information for the certificate.
+func (rca *RootCA) IssueAndSaveNewCertificates(kw KeyWriter, cn, ou, org string) (*tls.Certificate, *IssuerInfo, error) {
 	csr, key, err := GenerateNewCSR()
 	if err != nil {
-		return nil, errors.Wrap(err, "error when generating new node certs")
+		return nil, nil, errors.Wrap(err, "error when generating new node certs")
 	}
 
 	// Obtain a signed Certificate
 	certChain, err := rca.ParseValidateAndSignCSR(csr, cn, ou, org)
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to sign node certificate")
+		return nil, nil, errors.Wrap(err, "failed to sign node certificate")
+	}
+	signer, err := rca.Signer()
+	if err != nil { // should never happen, since if ParseValidateAndSignCSR did not fail this root CA must have a signer
+		return nil, nil, err
 	}
 
 	// Create a valid TLSKeyPair out of the PEM encoded private key and certificate
 	tlsKeyPair, err := tls.X509KeyPair(certChain, key)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	if err := kw.Write(certChain, key, nil); err != nil {
-		return nil, err
+	if err := kw.Write(NormalizePEMs(certChain), key, nil); err != nil {
+		return nil, nil, err
 	}
 
-	return &tlsKeyPair, nil
+	return &tlsKeyPair, &IssuerInfo{
+		PublicKey: signer.parsedCert.RawSubjectPublicKeyInfo,
+		Subject:   signer.parsedCert.RawSubject,
+	}, nil
 }
 
 // RequestAndSaveNewCertificates gets new certificates issued, either by signing them locally if a signer is
-// available, or by requesting them from the remote server at remoteAddr.
-func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, kw KeyWriter, config CertificateRequestConfig) (*tls.Certificate, error) {
+// available, or by requesting them from the remote server at remoteAddr.  This function returns the TLS
+// certificate and the issuer information for the certificate.
+func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, kw KeyWriter, config CertificateRequestConfig) (*tls.Certificate, *IssuerInfo, error) {
 	// Create a new key/pair and CSR
 	csr, key, err := GenerateNewCSR()
 	if err != nil {
-		return nil, errors.Wrap(err, "error when generating new node certs")
+		return nil, nil, errors.Wrap(err, "error when generating new node certs")
 	}
 
 	// Get the remote manager to issue a CA signed certificate for this node
@@ -246,41 +260,49 @@ func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, kw KeyWrit
 		config.ForceRemote = true
 	}
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
 	// Доверяй, но проверяй.
 	// Before we overwrite our local key + certificate, let's make sure the server gave us one that is valid
 	// Create an X509Cert so we can .Verify()
 	// Check to see if this certificate was signed by our CA, and isn't expired
-	parsedCerts, err := ValidateCertChain(rca.Pool, signedCert, false)
+	parsedCerts, chains, err := ValidateCertChain(rca.Pool, signedCert, false)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
+	// ValidateChain, if successful, will always return at least 1 parsed cert and at least 1 chain containing
+	// at least 2 certificates:  the leaf and the root.
+	leafCert := parsedCerts[0]
+	issuer := chains[0][1]
+
 	// Create a valid TLSKeyPair out of the PEM encoded private key and certificate
 	tlsKeyPair, err := tls.X509KeyPair(signedCert, key)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
 	var kekUpdate *KEKData
 	for i := 0; i < 5; i++ {
 		// ValidateCertChain will always return at least 1 cert, so indexing at 0 is safe
-		kekUpdate, err = rca.getKEKUpdate(ctx, parsedCerts[0], tlsKeyPair, config.ConnBroker)
+		kekUpdate, err = rca.getKEKUpdate(ctx, leafCert, tlsKeyPair, config.ConnBroker)
 		if err == nil {
 			break
 		}
 	}
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	if err := kw.Write(signedCert, key, kekUpdate); err != nil {
-		return nil, err
+	if err := kw.Write(NormalizePEMs(signedCert), key, kekUpdate); err != nil {
+		return nil, nil, err
 	}
 
-	return &tlsKeyPair, nil
+	return &tlsKeyPair, &IssuerInfo{
+		PublicKey: issuer.RawSubjectPublicKeyInfo,
+		Subject:   issuer.RawSubject,
+	}, nil
 }
 
 func (rca *RootCA) getKEKUpdate(ctx context.Context, leafCert *x509.Certificate, keypair tls.Certificate, connBroker *connectionbroker.Broker) (*KEKData, error) {
@@ -430,7 +452,7 @@ func NewRootCA(rootCertBytes, signCertBytes, signKeyBytes []byte, certExpiry tim
 	var intermediatePool *x509.CertPool
 	var parsedIntermediates []*x509.Certificate
 	if len(intermediates) > 0 {
-		parsedIntermediates, err = ValidateCertChain(pool, intermediates, false)
+		parsedIntermediates, _, err = ValidateCertChain(pool, intermediates, false)
 		if err != nil {
 			return RootCA{}, errors.Wrap(err, "invalid intermediate chain")
 		}
@@ -469,15 +491,15 @@ func NewRootCA(rootCertBytes, signCertBytes, signKeyBytes []byte, certExpiry tim
 // intermediate pool), because this function is intended to be used when reading certs from untrusted locations such as
 // from disk or over a network when a CSR is signed, so it is extra pedantic.
 // This function always returns all the parsed certificates in the bundle in order, which means there will always be
-// at least 1 certificate if there is no error.
-func ValidateCertChain(rootPool *x509.CertPool, certs []byte, allowExpired bool) ([]*x509.Certificate, error) {
+// at least 1 certificate if there is no error, and the valid chains found by Certificate.Verify
+func ValidateCertChain(rootPool *x509.CertPool, certs []byte, allowExpired bool) ([]*x509.Certificate, [][]*x509.Certificate, error) {
 	// Parse all the certificates in the cert bundle
 	parsedCerts, err := helpers.ParseCertificatesPEM(certs)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	if len(parsedCerts) == 0 {
-		return nil, errors.New("no certificates to validate")
+		return nil, nil, errors.New("no certificates to validate")
 	}
 	now := time.Now()
 	// ensure that they form a chain, each one being signed by the one after it
@@ -486,7 +508,7 @@ func ValidateCertChain(rootPool *x509.CertPool, certs []byte, allowExpired bool)
 		// Manual expiry validation because we want more information on which certificate in the chain is expired, and
 		// because this is an easier way to allow expired certs.
 		if now.Before(cert.NotBefore) {
-			return nil, errors.Wrapf(
+			return nil, nil, errors.Wrapf(
 				x509.CertificateInvalidError{
 					Cert:   cert,
 					Reason: x509.Expired,
@@ -495,7 +517,7 @@ func ValidateCertChain(rootPool *x509.CertPool, certs []byte, allowExpired bool)
 				i+1, cert.Subject.CommonName, cert.NotBefore.UTC().Format(time.RFC1123), now.Format(time.RFC1123))
 		}
 		if !allowExpired && now.After(cert.NotAfter) {
-			return nil, errors.Wrapf(
+			return nil, nil, errors.Wrapf(
 				x509.CertificateInvalidError{
 					Cert:   cert,
 					Reason: x509.Expired,
@@ -508,7 +530,7 @@ func ValidateCertChain(rootPool *x509.CertPool, certs []byte, allowExpired bool)
 			// check that the previous cert was signed by this cert
 			prevCert := parsedCerts[i-1]
 			if err := prevCert.CheckSignatureFrom(cert); err != nil {
-				return nil, errors.Wrapf(err, "certificates do not form a chain: (%d - %s) is not signed by (%d - %s)",
+				return nil, nil, errors.Wrapf(err, "certificates do not form a chain: (%d - %s) is not signed by (%d - %s)",
 					i, prevCert.Subject.CommonName, i+1, cert.Subject.CommonName)
 			}
 
@@ -526,6 +548,8 @@ func ValidateCertChain(rootPool *x509.CertPool, certs []byte, allowExpired bool)
 		CurrentTime:   now,
 	}
 
+	var chains [][]*x509.Certificate
+
 	// If we accept expired certs, try to build a valid cert chain using some subset of the certs.  We start off using the
 	// first certificate's NotAfter as the current time, thus ensuring that the first cert is not expired. If the chain
 	// still fails to validate due to expiry issues, continue iterating over the rest of the certs.
@@ -540,22 +564,22 @@ func ValidateCertChain(rootPool *x509.CertPool, certs []byte, allowExpired bool)
 			}
 			verifyOpts.CurrentTime = cert.NotAfter
 
-			_, err = parsedCerts[0].Verify(verifyOpts)
+			chains, err = parsedCerts[0].Verify(verifyOpts)
 			if err == nil {
-				return parsedCerts, nil
+				return parsedCerts, chains, nil
 			}
 		}
 		if invalid, ok := err.(x509.CertificateInvalidError); ok && invalid.Reason == x509.Expired {
-			return nil, errors.New("there is no time span for which all of the certificates, including a root, are valid")
+			return nil, nil, errors.New("there is no time span for which all of the certificates, including a root, are valid")
 		}
-		return nil, err
+		return nil, nil, err
 	}
 
-	_, err = parsedCerts[0].Verify(verifyOpts)
+	chains, err = parsedCerts[0].Verify(verifyOpts)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return parsedCerts, nil
+	return parsedCerts, chains, nil
 }
 
 // newLocalSigner validates the signing cert and signing key to create a local signer, which accepts a crypto signer and a cert
@@ -930,3 +954,22 @@ func EncryptECPrivateKey(key []byte, passphraseStr string) ([]byte, error) {
 
 	return pem.EncodeToMemory(encryptedPEMBlock), nil
 }
+
+// NormalizePEMs takes a bundle of PEM-encoded certificates in a certificate bundle,
+// decodes them, removes headers, and re-encodes them to make sure that they have
+// consistent whitespace.  Note that this is intended to normalize x509 certificates
+// in PEM format, hence the stripping out of headers.
+func NormalizePEMs(certs []byte) []byte {
+	var (
+		results  []byte
+		pemBlock *pem.Block
+	)
+	for {
+		pemBlock, certs = pem.Decode(bytes.TrimSpace(certs))
+		if pemBlock == nil {
+			return results
+		}
+		pemBlock.Headers = nil
+		results = append(results, pem.EncodeToMemory(pemBlock)...)
+	}
+}

+ 88 - 57
vendor/github.com/docker/swarmkit/ca/config.go

@@ -19,6 +19,7 @@ import (
 	"github.com/docker/swarmkit/connectionbroker"
 	"github.com/docker/swarmkit/identity"
 	"github.com/docker/swarmkit/log"
+	"github.com/docker/swarmkit/watch"
 	"github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
 	"google.golang.org/grpc/credentials"
@@ -71,10 +72,16 @@ type SecurityConfig struct {
 	externalCA    *ExternalCA
 	keyReadWriter *KeyReadWriter
 
+	certificate *tls.Certificate
+	issuerInfo  *IssuerInfo
+
 	externalCAClientRootPool *x509.CertPool
 
 	ServerTLSCreds *MutableTLSCreds
 	ClientTLSCreds *MutableTLSCreds
+
+	// An optional queue for anyone interested in subscribing to SecurityConfig updates
+	queue *watch.Queue
 }
 
 // CertificateUpdate represents a change in the underlying TLS configuration being returned by
@@ -85,25 +92,41 @@ type CertificateUpdate struct {
 }
 
 // NewSecurityConfig initializes and returns a new SecurityConfig.
-func NewSecurityConfig(rootCA *RootCA, krw *KeyReadWriter, clientTLSCreds, serverTLSCreds *MutableTLSCreds) *SecurityConfig {
+func NewSecurityConfig(rootCA *RootCA, krw *KeyReadWriter, tlsKeyPair *tls.Certificate, issuerInfo *IssuerInfo) (*SecurityConfig, error) {
+	// Create the Server TLS Credentials for this node. These will not be used by workers.
+	serverTLSCreds, err := rootCA.NewServerTLSCredentials(tlsKeyPair)
+	if err != nil {
+		return nil, err
+	}
+
+	// Create a TLSConfig to be used when this node connects as a client to another remote node.
+	// We're using ManagerRole as remote serverName for TLS host verification because both workers
+	// and managers always connect to remote managers.
+	clientTLSCreds, err := rootCA.NewClientTLSCredentials(tlsKeyPair, ManagerRole)
+	if err != nil {
+		return nil, err
+	}
+
 	// Make a new TLS config for the external CA client without a
 	// ServerName value set.
-	clientTLSConfig := clientTLSCreds.Config()
-
 	externalCATLSConfig := &tls.Config{
-		Certificates: clientTLSConfig.Certificates,
-		RootCAs:      clientTLSConfig.RootCAs,
+		Certificates: []tls.Certificate{*tlsKeyPair},
+		RootCAs:      rootCA.Pool,
 		MinVersion:   tls.VersionTLS12,
 	}
 
 	return &SecurityConfig{
-		rootCA:                   rootCA,
-		keyReadWriter:            krw,
+		rootCA:        rootCA,
+		keyReadWriter: krw,
+
+		certificate: tlsKeyPair,
+		issuerInfo:  issuerInfo,
+
 		externalCA:               NewExternalCA(rootCA, externalCATLSConfig),
 		ClientTLSCreds:           clientTLSCreds,
 		ServerTLSCreds:           serverTLSCreds,
 		externalCAClientRootPool: rootCA.Pool,
-	}
+	}, nil
 }
 
 // RootCA returns the root CA.
@@ -136,19 +159,32 @@ func (s *SecurityConfig) UpdateRootCA(rootCA *RootCA, externalCARootPool *x509.C
 
 	s.rootCA = rootCA
 	s.externalCAClientRootPool = externalCARootPool
-	clientTLSConfig := s.ClientTLSCreds.Config()
-	return s.updateTLSCredentials(clientTLSConfig.Certificates)
+	return s.updateTLSCredentials(s.certificate, s.issuerInfo)
+}
+
+// SetWatch allows you to set a watch on the security config, in order to be notified of any changes
+func (s *SecurityConfig) SetWatch(q *watch.Queue) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	s.queue = q
+}
+
+// IssuerInfo returns the issuer subject and issuer public key
+func (s *SecurityConfig) IssuerInfo() *IssuerInfo {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	return s.issuerInfo
 }
 
-// updateTLSCredentials updates the client, server, and TLS credentials on a security config.  This function expects
-// something else to have taken out a lock on the SecurityConfig.
-func (s *SecurityConfig) updateTLSCredentials(certificates []tls.Certificate) error {
-	clientConfig, err := NewClientTLSConfig(certificates, s.rootCA.Pool, ManagerRole)
+// This function expects something else to have taken out a lock on the SecurityConfig.
+func (s *SecurityConfig) updateTLSCredentials(certificate *tls.Certificate, issuerInfo *IssuerInfo) error {
+	certs := []tls.Certificate{*certificate}
+	clientConfig, err := NewClientTLSConfig(certs, s.rootCA.Pool, ManagerRole)
 	if err != nil {
 		return errors.Wrap(err, "failed to create a new client config using the new root CA")
 	}
 
-	serverConfig, err := NewServerTLSConfig(certificates, s.rootCA.Pool)
+	serverConfig, err := NewServerTLSConfig(certs, s.rootCA.Pool)
 	if err != nil {
 		return errors.Wrap(err, "failed to create a new server config using the new root CA")
 	}
@@ -160,7 +196,7 @@ func (s *SecurityConfig) updateTLSCredentials(certificates []tls.Certificate) er
 	// Update the external CA to use the new client TLS
 	// config using a copy without a serverName specified.
 	s.externalCA.UpdateTLSConfig(&tls.Config{
-		Certificates: certificates,
+		Certificates: certs,
 		RootCAs:      s.externalCAClientRootPool,
 		MinVersion:   tls.VersionTLS12,
 	})
@@ -169,6 +205,15 @@ func (s *SecurityConfig) updateTLSCredentials(certificates []tls.Certificate) er
 		return errors.Wrap(err, "failed to update the server TLS credentials")
 	}
 
+	s.certificate = certificate
+	s.issuerInfo = issuerInfo
+	if s.queue != nil {
+		s.queue.Publish(&api.NodeTLSInfo{
+			TrustRoot:           s.rootCA.Certs,
+			CertIssuerPublicKey: s.issuerInfo.PublicKey,
+			CertIssuerSubject:   s.issuerInfo.Subject,
+		})
+	}
 	return nil
 }
 
@@ -300,9 +345,13 @@ func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter,
 	}
 
 	// Check to see if this certificate was signed by our CA, and isn't expired
-	if _, err := ValidateCertChain(rootCA.Pool, cert, allowExpired); err != nil {
+	_, chains, err := ValidateCertChain(rootCA.Pool, cert, allowExpired)
+	if err != nil {
 		return nil, err
 	}
+	// ValidateChain, if successful, will always return at least 1 chain containing
+	// at least 2 certificates:  the leaf and the root.
+	issuer := chains[0][1]
 
 	// Now that we know this certificate is valid, create a TLS Certificate for our
 	// credentials
@@ -311,26 +360,17 @@ func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter,
 		return nil, err
 	}
 
-	// Load the Certificates as server credentials
-	serverTLSCreds, err := rootCA.NewServerTLSCredentials(&keyPair)
-	if err != nil {
-		return nil, err
-	}
-
-	// Load the Certificates also as client credentials.
-	// Both workers and managers always connect to remote managers,
-	// so ServerName is always set to ManagerRole here.
-	clientTLSCreds, err := rootCA.NewClientTLSCredentials(&keyPair, ManagerRole)
-	if err != nil {
-		return nil, err
+	secConfig, err := NewSecurityConfig(&rootCA, krw, &keyPair, &IssuerInfo{
+		Subject:   issuer.RawSubject,
+		PublicKey: issuer.RawSubjectPublicKeyInfo,
+	})
+	if err == nil {
+		log.G(ctx).WithFields(logrus.Fields{
+			"node.id":   secConfig.ClientTLSCreds.NodeID(),
+			"node.role": secConfig.ClientTLSCreds.Role(),
+		}).Debug("loaded node credentials")
 	}
-
-	log.G(ctx).WithFields(logrus.Fields{
-		"node.id":   clientTLSCreds.NodeID(),
-		"node.role": clientTLSCreds.Role(),
-	}).Debug("loaded node credentials")
-
-	return NewSecurityConfig(&rootCA, krw, clientTLSCreds, serverTLSCreds), nil
+	return secConfig, err
 }
 
 // CertificateRequestConfig contains the information needed to request a
@@ -365,12 +405,12 @@ func (rootCA RootCA) CreateSecurityConfig(ctx context.Context, krw *KeyReadWrite
 	org := identity.NewID()
 
 	proposedRole := ManagerRole
-	tlsKeyPair, err := rootCA.IssueAndSaveNewCertificates(krw, cn, proposedRole, org)
+	tlsKeyPair, issuerInfo, err := rootCA.IssueAndSaveNewCertificates(krw, cn, proposedRole, org)
 	switch errors.Cause(err) {
 	case ErrNoValidSigner:
 		// Request certificate issuance from a remote CA.
 		// Last argument is nil because at this point we don't have any valid TLS creds
-		tlsKeyPair, err = rootCA.RequestAndSaveNewCertificates(ctx, krw, config)
+		tlsKeyPair, issuerInfo, err = rootCA.RequestAndSaveNewCertificates(ctx, krw, config)
 		if err != nil {
 			log.G(ctx).WithError(err).Error("failed to request save new certificate")
 			return nil, err
@@ -388,24 +428,14 @@ func (rootCA RootCA) CreateSecurityConfig(ctx context.Context, krw *KeyReadWrite
 		return nil, err
 	}
 
-	// Create the Server TLS Credentials for this node. These will not be used by workers.
-	serverTLSCreds, err := rootCA.NewServerTLSCredentials(tlsKeyPair)
-	if err != nil {
-		return nil, err
-	}
-
-	// Create a TLSConfig to be used when this node connects as a client to another remote node.
-	// We're using ManagerRole as remote serverName for TLS host verification
-	clientTLSCreds, err := rootCA.NewClientTLSCredentials(tlsKeyPair, ManagerRole)
-	if err != nil {
-		return nil, err
+	secConfig, err := NewSecurityConfig(&rootCA, krw, tlsKeyPair, issuerInfo)
+	if err == nil {
+		log.G(ctx).WithFields(logrus.Fields{
+			"node.id":   secConfig.ClientTLSCreds.NodeID(),
+			"node.role": secConfig.ClientTLSCreds.Role(),
+		}).Debugf("new node credentials generated: %s", krw.Target())
 	}
-	log.G(ctx).WithFields(logrus.Fields{
-		"node.id":   clientTLSCreds.NodeID(),
-		"node.role": clientTLSCreds.Role(),
-	}).Debugf("new node credentials generated: %s", krw.Target())
-
-	return NewSecurityConfig(&rootCA, krw, clientTLSCreds, serverTLSCreds), nil
+	return secConfig, err
 }
 
 // RenewTLSConfigNow gets a new TLS cert and key, and updates the security config if provided.  This is similar to
@@ -422,7 +452,7 @@ func RenewTLSConfigNow(ctx context.Context, s *SecurityConfig, connBroker *conne
 
 	// Let's request new certs. Renewals don't require a token.
 	rootCA := s.RootCA()
-	tlsKeyPair, err := rootCA.RequestAndSaveNewCertificates(ctx,
+	tlsKeyPair, issuerInfo, err := rootCA.RequestAndSaveNewCertificates(ctx,
 		s.KeyWriter(),
 		CertificateRequestConfig{
 			ConnBroker:  connBroker,
@@ -432,9 +462,10 @@ func RenewTLSConfigNow(ctx context.Context, s *SecurityConfig, connBroker *conne
 		log.WithError(err).Errorf("failed to renew the certificate")
 		return err
 	}
+
 	s.mu.Lock()
 	defer s.mu.Unlock()
-	return s.updateTLSCredentials([]tls.Certificate{*tlsKeyPair})
+	return s.updateTLSCredentials(tlsKeyPair, issuerInfo)
 }
 
 // RenewTLSConfig will continuously monitor for the necessity of renewing the local certificates, either by

+ 10 - 1
vendor/github.com/docker/swarmkit/ca/server.go

@@ -60,6 +60,9 @@ type Server struct {
 	lastSeenClusterRootCA *api.RootCA
 	lastSeenExternalCAs   []*api.ExternalCA
 	secConfigMu           sync.Mutex
+
+	// before we update the security config with the new root CA, we need to be able to save the root certs
+	rootPaths CertPaths
 }
 
 // DefaultCAConfig returns the default CA Config, with a default expiration.
@@ -70,13 +73,14 @@ func DefaultCAConfig() api.CAConfig {
 }
 
 // NewServer creates a CA API server.
-func NewServer(store *store.MemoryStore, securityConfig *SecurityConfig) *Server {
+func NewServer(store *store.MemoryStore, securityConfig *SecurityConfig, rootCAPaths CertPaths) *Server {
 	return &Server{
 		store:                       store,
 		securityConfig:              securityConfig,
 		pending:                     make(map[string]*api.Node),
 		started:                     make(chan struct{}),
 		reconciliationRetryInterval: defaultReconciliationRetryInterval,
+		rootPaths:                   rootCAPaths,
 	}
 }
 
@@ -582,6 +586,9 @@ func (s *Server) UpdateRootCA(ctx context.Context, cluster *api.Cluster) error {
 		if err != nil {
 			return errors.Wrap(err, "invalid Root CA object in cluster")
 		}
+		if err := SaveRootCA(updatedRootCA, s.rootPaths); err != nil {
+			return errors.Wrap(err, "unable to save new root CA certificates")
+		}
 
 		externalCARootPool := updatedRootCA.Pool
 		if rCA.RootRotation != nil {
@@ -609,6 +616,7 @@ func (s *Server) UpdateRootCA(ctx context.Context, cluster *api.Cluster) error {
 			// we're rotating to a new root, so we only want external CAs with the new root cert
 			wantedExternalCACert = rCA.RootRotation.CACert
 		}
+		wantedExternalCACert = NormalizePEMs(wantedExternalCACert)
 		// Update our security config with the list of External CA URLs
 		// from the new cluster state.
 
@@ -623,6 +631,7 @@ func (s *Server) UpdateRootCA(ctx context.Context, cluster *api.Cluster) error {
 			if len(certForExtCA) == 0 {
 				certForExtCA = rCA.CACert
 			}
+			certForExtCA = NormalizePEMs(certForExtCA)
 			if extCA.Protocol != api.ExternalCA_CAProtocolCFSSL {
 				logger.Debugf("skipping external CA %d (url: %s) due to unknown protocol type", i, extCA.URL)
 				continue

+ 77 - 62
vendor/github.com/docker/swarmkit/manager/controlapi/ca_rotation.go

@@ -24,28 +24,28 @@ var minRootExpiration = 1 * helpers.OneYear
 // determines whether an api.RootCA, api.RootRotation, or api.CAConfig has a signing key (local signer)
 func hasSigningKey(a interface{}) bool {
 	switch b := a.(type) {
-	case api.RootCA:
+	case *api.RootCA:
 		return len(b.CAKey) > 0
 	case *api.RootRotation:
 		return b != nil && len(b.CAKey) > 0
-	case api.CAConfig:
+	case *api.CAConfig:
 		return len(b.SigningCACert) > 0 && len(b.SigningCAKey) > 0
 	default:
-		panic("needsExternalCAs should be called something of type api.RootCA, *api.RootRotation, or api.CAConfig")
+		panic("needsExternalCAs should be called something of type *api.RootCA, *api.RootRotation, or *api.CAConfig")
 	}
 }
 
 // Creates a cross-signed intermediate and new api.RootRotation object.
 // This function assumes that the root cert and key and the external CAs have already been validated.
-func newRootRotationObject(ctx context.Context, securityConfig *ca.SecurityConfig, cluster *api.Cluster, newRootCA ca.RootCA, version uint64) (*api.RootCA, error) {
+func newRootRotationObject(ctx context.Context, securityConfig *ca.SecurityConfig, apiRootCA *api.RootCA, newCARootCA ca.RootCA, extCAs []*api.ExternalCA, version uint64) (*api.RootCA, error) {
 	var (
 		rootCert, rootKey, crossSignedCert []byte
 		newRootHasSigner                   bool
 		err                                error
 	)
 
-	rootCert = newRootCA.Certs
-	if s, err := newRootCA.Signer(); err == nil {
+	rootCert = newCARootCA.Certs
+	if s, err := newCARootCA.Signer(); err == nil {
 		rootCert, rootKey = s.Cert, s.Key
 		newRootHasSigner = true
 	}
@@ -53,9 +53,9 @@ func newRootRotationObject(ctx context.Context, securityConfig *ca.SecurityConfi
 	// we have to sign with the original signer, not whatever is in the SecurityConfig's RootCA (which may have an intermediate signer, if
 	// a root rotation is already in progress)
 	switch {
-	case hasSigningKey(cluster.RootCA):
+	case hasSigningKey(apiRootCA):
 		var oldRootCA ca.RootCA
-		oldRootCA, err = ca.NewRootCA(cluster.RootCA.CACert, cluster.RootCA.CACert, cluster.RootCA.CAKey, ca.DefaultNodeCertExpiration, nil)
+		oldRootCA, err = ca.NewRootCA(apiRootCA.CACert, apiRootCA.CACert, apiRootCA.CAKey, ca.DefaultNodeCertExpiration, nil)
 		if err == nil {
 			crossSignedCert, err = oldRootCA.CrossSignCACertificate(rootCert)
 		}
@@ -65,8 +65,8 @@ func newRootRotationObject(ctx context.Context, securityConfig *ca.SecurityConfi
 		// We need the same credentials but to connect to the original URLs (in case we are in the middle of a root rotation already)
 		externalCA := securityConfig.ExternalCA().Copy()
 		var urls []string
-		for _, c := range cluster.Spec.CAConfig.ExternalCAs {
-			if c.Protocol == api.ExternalCA_CAProtocolCFSSL && bytes.Equal(c.CACert, cluster.RootCA.CACert) {
+		for _, c := range extCAs {
+			if c.Protocol == api.ExternalCA_CAProtocolCFSSL {
 				urls = append(urls, c.URL)
 			}
 		}
@@ -75,7 +75,7 @@ func newRootRotationObject(ctx context.Context, securityConfig *ca.SecurityConfi
 				"must provide an external CA for the current external root CA to generate a cross-signed certificate")
 		}
 		externalCA.UpdateURLs(urls...)
-		crossSignedCert, err = externalCA.CrossSignRootCA(ctx, newRootCA)
+		crossSignedCert, err = externalCA.CrossSignRootCA(ctx, newCARootCA)
 	}
 
 	if err != nil {
@@ -83,11 +83,11 @@ func newRootRotationObject(ctx context.Context, securityConfig *ca.SecurityConfi
 		return nil, grpc.Errorf(codes.Internal, "unable to generate a cross-signed certificate for root rotation")
 	}
 
-	copied := cluster.RootCA.Copy()
+	copied := apiRootCA.Copy()
 	copied.RootRotation = &api.RootRotation{
 		CACert:            rootCert,
 		CAKey:             rootKey,
-		CrossSignedCACert: crossSignedCert,
+		CrossSignedCACert: ca.NormalizePEMs(crossSignedCert),
 	}
 	copied.LastForcedRotation = version
 	return copied, nil
@@ -120,58 +120,46 @@ func validateExternalCAURL(dialer *net.Dialer, tlsOpts *tls.Config, caURL string
 	return err
 }
 
-// Iterates over all the external CAs, and validates that there is at least 1 reachable, valid external CA for the
-// given CA certificate.  Returns true if there is, false otherwise.
-func hasAtLeastOneExternalCA(ctx context.Context, externalCAs []*api.ExternalCA, securityConfig *ca.SecurityConfig, wantedCert []byte) bool {
-	pool := x509.NewCertPool()
-	pool.AppendCertsFromPEM(wantedCert)
-	dialer := net.Dialer{Timeout: 5 * time.Second}
-	opts := tls.Config{
-		RootCAs:      pool,
-		Certificates: securityConfig.ClientTLSCreds.Config().Certificates,
-	}
-	for i, ca := range externalCAs {
-		if ca.Protocol == api.ExternalCA_CAProtocolCFSSL && bytes.Equal(wantedCert, ca.CACert) {
-			err := validateExternalCAURL(&dialer, &opts, ca.URL)
-			if err == nil {
-				return true
+// Validates that there is at least 1 reachable, valid external CA for the given CA certificate.  Returns true if there is, false otherwise.
+// Requires that the wanted cert is already normalized.
+func validateHasAtLeastOneExternalCA(ctx context.Context, externalCAs map[string][]*api.ExternalCA, securityConfig *ca.SecurityConfig,
+	wantedCert []byte, desc string) ([]*api.ExternalCA, error) {
+	specific, ok := externalCAs[string(wantedCert)]
+	if ok {
+		pool := x509.NewCertPool()
+		pool.AppendCertsFromPEM(wantedCert)
+		dialer := net.Dialer{Timeout: 5 * time.Second}
+		opts := tls.Config{
+			RootCAs:      pool,
+			Certificates: securityConfig.ClientTLSCreds.Config().Certificates,
+		}
+		for i, ca := range specific {
+			if ca.Protocol == api.ExternalCA_CAProtocolCFSSL {
+				if err := validateExternalCAURL(&dialer, &opts, ca.URL); err != nil {
+					log.G(ctx).WithError(err).Warnf("external CA # %d is unreachable or invalid", i+1)
+				} else {
+					return specific, nil
+				}
 			}
-			log.G(ctx).WithError(err).Warnf("external CA # %d is unreachable or invalid", i+1)
 		}
 	}
-	return false
+	return nil, grpc.Errorf(codes.InvalidArgument, "there must be at least one valid, reachable external CA corresponding to the %s CA certificate", desc)
 }
 
-// All new external CA definitions must include the CA cert associated with the external CA.
-// If the current root CA requires an external CA, then at least one, reachable valid external CA must be provided that
-// corresponds with the current RootCA's certificate.
-//
-// Similarly for the desired CA certificate, if one is specified.  Similarly for the current outstanding root CA rotation,
-// if one is specified and will not be replaced with the desired CA.
-func validateHasRequiredExternalCAs(ctx context.Context, securityConfig *ca.SecurityConfig, cluster *api.Cluster) error {
-	config := cluster.Spec.CAConfig
-	for _, ca := range config.ExternalCAs {
-		if len(ca.CACert) == 0 {
-			return grpc.Errorf(codes.InvalidArgument, "must specify CA certificate for each external CA")
-		}
-	}
-
-	if !hasSigningKey(cluster.RootCA) && !hasAtLeastOneExternalCA(ctx, config.ExternalCAs, securityConfig, cluster.RootCA.CACert) {
-		return grpc.Errorf(codes.InvalidArgument, "there must be at least one valid, reachable external CA corresponding to the current CA certificate")
-	}
+// validates that the list of external CAs have valid certs associated with them, and produce a mapping of subject/pubkey:external
+// for later validation of required external CAs
+func getNormalizedExtCAs(caConfig *api.CAConfig) (map[string][]*api.ExternalCA, error) {
+	extCAs := make(map[string][]*api.ExternalCA)
 
-	if len(config.SigningCACert) > 0 { // a signing cert is specified
-		if !hasSigningKey(config) && !hasAtLeastOneExternalCA(ctx, config.ExternalCAs, securityConfig, config.SigningCACert) {
-			return grpc.Errorf(codes.InvalidArgument, "there must be at least one valid, reachable external CA corresponding to the desired CA certificate")
-		}
-	} else if config.ForceRotate == cluster.RootCA.LastForcedRotation && cluster.RootCA.RootRotation != nil {
-		// no cert is specified but force rotation hasn't changed (so we are happy with the current configuration) and there's an outstanding root rotation
-		if !hasSigningKey(cluster.RootCA.RootRotation) && !hasAtLeastOneExternalCA(ctx, config.ExternalCAs, securityConfig, cluster.RootCA.RootRotation.CACert) {
-			return grpc.Errorf(codes.InvalidArgument, "there must be at least one valid, reachable external CA corresponding to the next CA certificate")
+	for _, extCA := range caConfig.ExternalCAs {
+		if len(extCA.CACert) == 0 {
+			return nil, grpc.Errorf(codes.InvalidArgument, "must specify CA certificate for each external CA")
 		}
+		certKey := string(ca.NormalizePEMs(extCA.CACert))
+		extCAs[certKey] = append(extCAs[certKey], extCA)
 	}
 
-	return nil
+	return extCAs, nil
 }
 
 // validateAndUpdateCA validates a cluster's desired CA configuration spec, and returns a RootCA value on success representing
@@ -196,16 +184,27 @@ func validateHasRequiredExternalCAs(ctx context.Context, securityConfig *ca.Secu
 //    - Otherwise, start a new root rotation using the desired signing cert and desired signing key as the root rotation
 //      signing cert and key.  If a root rotation is already in progress, just replace it and start over.
 func validateCAConfig(ctx context.Context, securityConfig *ca.SecurityConfig, cluster *api.Cluster) (*api.RootCA, error) {
-	newConfig := cluster.Spec.CAConfig
+	newConfig := cluster.Spec.CAConfig.Copy()
+	newConfig.SigningCACert = ca.NormalizePEMs(newConfig.SigningCACert) // ensure this is normalized before we use it
 
 	if len(newConfig.SigningCAKey) > 0 && len(newConfig.SigningCACert) == 0 {
 		return nil, grpc.Errorf(codes.InvalidArgument, "if a signing CA key is provided, the signing CA cert must also be provided")
 	}
 
-	if err := validateHasRequiredExternalCAs(ctx, securityConfig, cluster); err != nil {
+	extCAs, err := getNormalizedExtCAs(newConfig) // validate that the list of external CAs is not malformed
+	if err != nil {
 		return nil, err
 	}
 
+	normalizedRootCA := ca.NormalizePEMs(cluster.RootCA.CACert)
+	var oldCertExtCAs []*api.ExternalCA
+	if !hasSigningKey(&cluster.RootCA) {
+		oldCertExtCAs, err = validateHasAtLeastOneExternalCA(ctx, extCAs, securityConfig, normalizedRootCA, "current")
+		if err != nil {
+			return nil, err
+		}
+	}
+
 	// if the desired CA cert and key are not set, then we are happy with the current root CA configuration, unless
 	// the ForceRotate version has changed
 	if len(newConfig.SigningCACert) == 0 {
@@ -214,8 +213,18 @@ func validateCAConfig(ctx context.Context, securityConfig *ca.SecurityConfig, cl
 			if err != nil {
 				return nil, grpc.Errorf(codes.Internal, err.Error())
 			}
-			return newRootRotationObject(ctx, securityConfig, cluster, newRootCA, newConfig.ForceRotate)
+			return newRootRotationObject(ctx, securityConfig, &cluster.RootCA, newRootCA, oldCertExtCAs, newConfig.ForceRotate)
+		}
+
+		// we also need to make sure that if the current root rotation requires an external CA, those external CAs are
+		// still valid
+		if cluster.RootCA.RootRotation != nil && !hasSigningKey(cluster.RootCA.RootRotation) {
+			_, err := validateHasAtLeastOneExternalCA(ctx, extCAs, securityConfig, ca.NormalizePEMs(cluster.RootCA.RootRotation.CACert), "next")
+			if err != nil {
+				return nil, err
+			}
 		}
+
 		return &cluster.RootCA, nil // no change, return as is
 	}
 
@@ -243,8 +252,14 @@ func validateCAConfig(ctx context.Context, securityConfig *ca.SecurityConfig, cl
 		return nil, grpc.Errorf(codes.InvalidArgument, "CA certificate expires too soon")
 	}
 
+	if !hasSigningKey(newConfig) {
+		if _, err := validateHasAtLeastOneExternalCA(ctx, extCAs, securityConfig, newConfig.SigningCACert, "desired"); err != nil {
+			return nil, err
+		}
+	}
+
 	// check if we can abort any existing root rotations
-	if bytes.Equal(cluster.RootCA.CACert, cluster.Spec.CAConfig.SigningCACert) {
+	if bytes.Equal(normalizedRootCA, newConfig.SigningCACert) {
 		copied := cluster.RootCA.Copy()
 		copied.CAKey = newConfig.SigningCAKey
 		copied.RootRotation = nil
@@ -253,7 +268,7 @@ func validateCAConfig(ctx context.Context, securityConfig *ca.SecurityConfig, cl
 	}
 
 	// check if this is the same desired cert as an existing root rotation
-	if r := cluster.RootCA.RootRotation; r != nil && bytes.Equal(r.CACert, cluster.Spec.CAConfig.SigningCACert) {
+	if r := cluster.RootCA.RootRotation; r != nil && bytes.Equal(ca.NormalizePEMs(r.CACert), newConfig.SigningCACert) {
 		copied := cluster.RootCA.Copy()
 		copied.RootRotation.CAKey = newConfig.SigningCAKey
 		copied.LastForcedRotation = newConfig.ForceRotate
@@ -261,5 +276,5 @@ func validateCAConfig(ctx context.Context, securityConfig *ca.SecurityConfig, cl
 	}
 
 	// ok, everything's different; we have to begin a new root rotation which means generating a new cross-signed cert
-	return newRootRotationObject(ctx, securityConfig, cluster, newRootCA, newConfig.ForceRotate)
+	return newRootRotationObject(ctx, securityConfig, &cluster.RootCA, newRootCA, oldCertExtCAs, newConfig.ForceRotate)
 }

+ 1 - 1
vendor/github.com/docker/swarmkit/manager/controlapi/cluster.go

@@ -38,7 +38,7 @@ func validateClusterSpec(spec *api.ClusterSpec) error {
 	}
 
 	// Validate that AcceptancePolicies only include Secrets that are bcrypted
-	// TODO(diogo): Add a global list of acceptace algorithms. We only support bcrypt for now.
+	// TODO(diogo): Add a global list of acceptance algorithms. We only support bcrypt for now.
 	if len(spec.AcceptancePolicy.Policies) > 0 {
 		for _, policy := range spec.AcceptancePolicy.Policies {
 			if policy.Secret != nil && strings.ToLower(policy.Secret.Alg) != "bcrypt" {

+ 16 - 2
vendor/github.com/docker/swarmkit/manager/controlapi/common.go

@@ -13,7 +13,10 @@ import (
 	"google.golang.org/grpc/codes"
 )
 
-var isValidName = regexp.MustCompile(`^[a-zA-Z0-9](?:[-_]*[A-Za-z0-9]+)*$`)
+var isValidDNSName = regexp.MustCompile(`^[a-zA-Z0-9](?:[-_]*[A-Za-z0-9]+)*$`)
+
+// configs and secrets have different naming requirements from tasks and services
+var isValidConfigOrSecretName = regexp.MustCompile(`^[a-zA-Z0-9]+(?:[a-zA-Z0-9-_.]*[a-zA-Z0-9])?$`)
 
 func buildFilters(by func(string) store.By, values []string) store.By {
 	filters := make([]store.By, 0, len(values))
@@ -68,7 +71,7 @@ func validateAnnotations(m api.Annotations) error {
 	if m.Name == "" {
 		return grpc.Errorf(codes.InvalidArgument, "meta: name must be provided")
 	}
-	if !isValidName.MatchString(m.Name) {
+	if !isValidDNSName.MatchString(m.Name) {
 		// if the name doesn't match the regex
 		return grpc.Errorf(codes.InvalidArgument, "name must be valid as a DNS name component")
 	}
@@ -79,6 +82,17 @@ func validateAnnotations(m api.Annotations) error {
 	return nil
 }
 
+func validateConfigOrSecretAnnotations(m api.Annotations) error {
+	if m.Name == "" {
+		return grpc.Errorf(codes.InvalidArgument, "name must be provided")
+	} else if len(m.Name) > 64 || !isValidConfigOrSecretName.MatchString(m.Name) {
+		// if the name doesn't match the regex
+		return grpc.Errorf(codes.InvalidArgument,
+			"invalid name, only 64 [a-zA-Z0-9-_.] characters allowed, and the start and end character must be [a-zA-Z0-9]")
+	}
+	return nil
+}
+
 func validateDriver(driver *api.Driver, pg plugingetter.PluginGetter, pluginType string) error {
 	if driver == nil {
 		// It is ok to not specify the driver. We will choose

+ 248 - 0
vendor/github.com/docker/swarmkit/manager/controlapi/config.go

@@ -0,0 +1,248 @@
+package controlapi
+
+import (
+	"bytes"
+	"strings"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/swarmkit/api"
+	"github.com/docker/swarmkit/identity"
+	"github.com/docker/swarmkit/log"
+	"github.com/docker/swarmkit/manager/state/store"
+	"golang.org/x/net/context"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+)
+
+// MaxConfigSize is the maximum byte length of the `Config.Spec.Data` field.
+const MaxConfigSize = 500 * 1024 // 500KB
+
+// assumes spec is not nil
+func configFromConfigSpec(spec *api.ConfigSpec) *api.Config {
+	return &api.Config{
+		ID:   identity.NewID(),
+		Spec: *spec,
+	}
+}
+
+// GetConfig returns a `GetConfigResponse` with a `Config` with the same
+// id as `GetConfigRequest.ConfigID`
+// - Returns `NotFound` if the Config with the given id is not found.
+// - Returns `InvalidArgument` if the `GetConfigRequest.ConfigID` is empty.
+// - Returns an error if getting fails.
+func (s *Server) GetConfig(ctx context.Context, request *api.GetConfigRequest) (*api.GetConfigResponse, error) {
+	if request.ConfigID == "" {
+		return nil, grpc.Errorf(codes.InvalidArgument, "config ID must be provided")
+	}
+
+	var config *api.Config
+	s.store.View(func(tx store.ReadTx) {
+		config = store.GetConfig(tx, request.ConfigID)
+	})
+
+	if config == nil {
+		return nil, grpc.Errorf(codes.NotFound, "config %s not found", request.ConfigID)
+	}
+
+	return &api.GetConfigResponse{Config: config}, nil
+}
+
+// UpdateConfig updates a Config referenced by ConfigID with the given ConfigSpec.
+// - Returns `NotFound` if the Config is not found.
+// - Returns `InvalidArgument` if the ConfigSpec is malformed or anything other than Labels is changed
+// - Returns an error if the update fails.
+func (s *Server) UpdateConfig(ctx context.Context, request *api.UpdateConfigRequest) (*api.UpdateConfigResponse, error) {
+	if request.ConfigID == "" || request.ConfigVersion == nil {
+		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
+	}
+
+	var config *api.Config
+	err := s.store.Update(func(tx store.Tx) error {
+		config = store.GetConfig(tx, request.ConfigID)
+		if config == nil {
+			return grpc.Errorf(codes.NotFound, "config %s not found", request.ConfigID)
+		}
+
+		// Check if the Name is different than the current name, or the config is non-nil and different
+		// than the current config
+		if config.Spec.Annotations.Name != request.Spec.Annotations.Name ||
+			(request.Spec.Data != nil && !bytes.Equal(request.Spec.Data, config.Spec.Data)) {
+			return grpc.Errorf(codes.InvalidArgument, "only updates to Labels are allowed")
+		}
+
+		// We only allow updating Labels
+		config.Meta.Version = *request.ConfigVersion
+		config.Spec.Annotations.Labels = request.Spec.Annotations.Labels
+
+		return store.UpdateConfig(tx, config)
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	log.G(ctx).WithFields(logrus.Fields{
+		"config.ID":   request.ConfigID,
+		"config.Name": request.Spec.Annotations.Name,
+		"method":      "UpdateConfig",
+	}).Debugf("config updated")
+
+	return &api.UpdateConfigResponse{
+		Config: config,
+	}, nil
+}
+
+// ListConfigs returns a `ListConfigResponse` with a list all non-internal `Config`s being
+// managed, or all configs matching any name in `ListConfigsRequest.Names`, any
+// name prefix in `ListConfigsRequest.NamePrefixes`, any id in
+// `ListConfigsRequest.ConfigIDs`, or any id prefix in `ListConfigsRequest.IDPrefixes`.
+// - Returns an error if listing fails.
+func (s *Server) ListConfigs(ctx context.Context, request *api.ListConfigsRequest) (*api.ListConfigsResponse, error) {
+	var (
+		configs     []*api.Config
+		respConfigs []*api.Config
+		err         error
+		byFilters   []store.By
+		by          store.By
+		labels      map[string]string
+	)
+
+	// return all configs that match either any of the names or any of the name prefixes (why would you give both?)
+	if request.Filters != nil {
+		for _, name := range request.Filters.Names {
+			byFilters = append(byFilters, store.ByName(name))
+		}
+		for _, prefix := range request.Filters.NamePrefixes {
+			byFilters = append(byFilters, store.ByNamePrefix(prefix))
+		}
+		for _, prefix := range request.Filters.IDPrefixes {
+			byFilters = append(byFilters, store.ByIDPrefix(prefix))
+		}
+		labels = request.Filters.Labels
+	}
+
+	switch len(byFilters) {
+	case 0:
+		by = store.All
+	case 1:
+		by = byFilters[0]
+	default:
+		by = store.Or(byFilters...)
+	}
+
+	s.store.View(func(tx store.ReadTx) {
+		configs, err = store.FindConfigs(tx, by)
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	// filter by label
+	for _, config := range configs {
+		if !filterMatchLabels(config.Spec.Annotations.Labels, labels) {
+			continue
+		}
+		respConfigs = append(respConfigs, config)
+	}
+
+	return &api.ListConfigsResponse{Configs: respConfigs}, nil
+}
+
+// CreateConfig creates and returns a `CreateConfigResponse` with a `Config` based
+// on the provided `CreateConfigRequest.ConfigSpec`.
+// - Returns `InvalidArgument` if the `CreateConfigRequest.ConfigSpec` is malformed,
+//   or if the config data is too long or contains invalid characters.
+// - Returns an error if the creation fails.
+func (s *Server) CreateConfig(ctx context.Context, request *api.CreateConfigRequest) (*api.CreateConfigResponse, error) {
+	if err := validateConfigSpec(request.Spec); err != nil {
+		return nil, err
+	}
+
+	config := configFromConfigSpec(request.Spec) // the store will handle name conflicts
+	err := s.store.Update(func(tx store.Tx) error {
+		return store.CreateConfig(tx, config)
+	})
+
+	switch err {
+	case store.ErrNameConflict:
+		return nil, grpc.Errorf(codes.AlreadyExists, "config %s already exists", request.Spec.Annotations.Name)
+	case nil:
+		log.G(ctx).WithFields(logrus.Fields{
+			"config.Name": request.Spec.Annotations.Name,
+			"method":      "CreateConfig",
+		}).Debugf("config created")
+
+		return &api.CreateConfigResponse{Config: config}, nil
+	default:
+		return nil, err
+	}
+}
+
+// RemoveConfig removes the config referenced by `RemoveConfigRequest.ID`.
+// - Returns `InvalidArgument` if `RemoveConfigRequest.ID` is empty.
+// - Returns `NotFound` if the a config named `RemoveConfigRequest.ID` is not found.
+// - Returns `ConfigInUse` if the config is currently in use
+// - Returns an error if the deletion fails.
+func (s *Server) RemoveConfig(ctx context.Context, request *api.RemoveConfigRequest) (*api.RemoveConfigResponse, error) {
+	if request.ConfigID == "" {
+		return nil, grpc.Errorf(codes.InvalidArgument, "config ID must be provided")
+	}
+
+	err := s.store.Update(func(tx store.Tx) error {
+		// Check if the config exists
+		config := store.GetConfig(tx, request.ConfigID)
+		if config == nil {
+			return grpc.Errorf(codes.NotFound, "could not find config %s", request.ConfigID)
+		}
+
+		// Check if any services currently reference this config, return error if so
+		services, err := store.FindServices(tx, store.ByReferencedConfigID(request.ConfigID))
+		if err != nil {
+			return grpc.Errorf(codes.Internal, "could not find services using config %s: %v", request.ConfigID, err)
+		}
+
+		if len(services) != 0 {
+			serviceNames := make([]string, 0, len(services))
+			for _, service := range services {
+				serviceNames = append(serviceNames, service.Spec.Annotations.Name)
+			}
+
+			configName := config.Spec.Annotations.Name
+			serviceNameStr := strings.Join(serviceNames, ", ")
+			serviceStr := "services"
+			if len(serviceNames) == 1 {
+				serviceStr = "service"
+			}
+
+			return grpc.Errorf(codes.InvalidArgument, "config '%s' is in use by the following %s: %v", configName, serviceStr, serviceNameStr)
+		}
+
+		return store.DeleteConfig(tx, request.ConfigID)
+	})
+	switch err {
+	case store.ErrNotExist:
+		return nil, grpc.Errorf(codes.NotFound, "config %s not found", request.ConfigID)
+	case nil:
+		log.G(ctx).WithFields(logrus.Fields{
+			"config.ID": request.ConfigID,
+			"method":    "RemoveConfig",
+		}).Debugf("config removed")
+
+		return &api.RemoveConfigResponse{}, nil
+	default:
+		return nil, err
+	}
+}
+
+func validateConfigSpec(spec *api.ConfigSpec) error {
+	if spec == nil {
+		return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
+	}
+	if err := validateConfigOrSecretAnnotations(spec.Annotations); err != nil {
+		return err
+	}
+
+	if len(spec.Data) >= MaxConfigSize || len(spec.Data) < 1 {
+		return grpc.Errorf(codes.InvalidArgument, "config data must be larger than 0 and less than %d bytes", MaxConfigSize)
+	}
+	return nil
+}

+ 1 - 17
vendor/github.com/docker/swarmkit/manager/controlapi/secret.go

@@ -2,7 +2,6 @@ package controlapi
 
 import (
 	"crypto/subtle"
-	"regexp"
 	"strings"
 
 	"github.com/Sirupsen/logrus"
@@ -15,13 +14,9 @@ import (
 	"google.golang.org/grpc/codes"
 )
 
-// Currently this is contains the unimplemented secret functions in order to satisfy the interface
-
 // MaxSecretSize is the maximum byte length of the `Secret.Spec.Data` field.
 const MaxSecretSize = 500 * 1024 // 500KB
 
-var validSecretNameRegexp = regexp.MustCompile(`^[a-zA-Z0-9]+(?:[a-zA-Z0-9-_.]*[a-zA-Z0-9])?$`)
-
 // assumes spec is not nil
 func secretFromSecretSpec(spec *api.SecretSpec) *api.Secret {
 	return &api.Secret{
@@ -247,7 +242,7 @@ func validateSecretSpec(spec *api.SecretSpec) error {
 	if spec == nil {
 		return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
 	}
-	if err := validateSecretAnnotations(spec.Annotations); err != nil {
+	if err := validateConfigOrSecretAnnotations(spec.Annotations); err != nil {
 		return err
 	}
 
@@ -256,14 +251,3 @@ func validateSecretSpec(spec *api.SecretSpec) error {
 	}
 	return nil
 }
-
-func validateSecretAnnotations(m api.Annotations) error {
-	if m.Name == "" {
-		return grpc.Errorf(codes.InvalidArgument, "name must be provided")
-	} else if len(m.Name) > 64 || !validSecretNameRegexp.MatchString(m.Name) {
-		// if the name doesn't match the regex
-		return grpc.Errorf(codes.InvalidArgument,
-			"invalid name, only 64 [a-zA-Z0-9-_.] characters allowed, and the start and end character must be [a-zA-Z0-9]")
-	}
-	return nil
-}

+ 87 - 2
vendor/github.com/docker/swarmkit/manager/controlapi/service.go

@@ -206,11 +206,16 @@ func validateTaskSpec(taskSpec api.TaskSpec) error {
 		return err
 	}
 
-	// Check to see if the Secret Reference portion of the spec is valid
+	// Check to see if the secret reference portion of the spec is valid
 	if err := validateSecretRefsSpec(taskSpec); err != nil {
 		return err
 	}
 
+	// Check to see if the config reference portion of the spec is valid
+	if err := validateConfigRefsSpec(taskSpec); err != nil {
+		return err
+	}
+
 	if taskSpec.GetRuntime() == nil {
 		return grpc.Errorf(codes.InvalidArgument, "TaskSpec: missing runtime")
 	}
@@ -314,6 +319,48 @@ func validateSecretRefsSpec(spec api.TaskSpec) error {
 	return nil
 }
 
+// validateConfigRefsSpec finds if the configs passed in spec are valid and have no
+// conflicting targets.
+func validateConfigRefsSpec(spec api.TaskSpec) error {
+	container := spec.GetContainer()
+	if container == nil {
+		return nil
+	}
+
+	// Keep a map to track all the targets that will be exposed
+	// The string returned is only used for logging. It could as well be struct{}{}
+	existingTargets := make(map[string]string)
+	for _, configRef := range container.Configs {
+		// ConfigID and ConfigName are mandatory, we have invalid references without them
+		if configRef.ConfigID == "" || configRef.ConfigName == "" {
+			return grpc.Errorf(codes.InvalidArgument, "malformed config reference")
+		}
+
+		// Every config reference requires a Target
+		if configRef.GetTarget() == nil {
+			return grpc.Errorf(codes.InvalidArgument, "malformed config reference, no target provided")
+		}
+
+		// If this is a file target, we will ensure filename uniqueness
+		if configRef.GetFile() != nil {
+			fileName := configRef.GetFile().Name
+			// Validate the file name
+			if fileName == "" {
+				return grpc.Errorf(codes.InvalidArgument, "malformed file config reference, invalid target file name provided")
+			}
+
+			// If this target is already in use, we have conflicting targets
+			if prevConfigName, ok := existingTargets[fileName]; ok {
+				return grpc.Errorf(codes.InvalidArgument, "config references '%s' and '%s' have a conflicting target: '%s'", prevConfigName, configRef.ConfigName, fileName)
+			}
+
+			existingTargets[fileName] = configRef.ConfigName
+		}
+	}
+
+	return nil
+}
+
 func (s *Server) validateNetworks(networks []*api.NetworkAttachmentConfig) error {
 	for _, na := range networks {
 		var network *api.Network
@@ -459,6 +506,35 @@ func (s *Server) checkSecretExistence(tx store.Tx, spec *api.ServiceSpec) error
 	return nil
 }
 
+// checkConfigExistence finds if the config exists
+func (s *Server) checkConfigExistence(tx store.Tx, spec *api.ServiceSpec) error {
+	container := spec.Task.GetContainer()
+	if container == nil {
+		return nil
+	}
+
+	var failedConfigs []string
+	for _, configRef := range container.Configs {
+		config := store.GetConfig(tx, configRef.ConfigID)
+		// Check to see if the config exists and configRef.ConfigName matches the actual configName
+		if config == nil || config.Spec.Annotations.Name != configRef.ConfigName {
+			failedConfigs = append(failedConfigs, configRef.ConfigName)
+		}
+	}
+
+	if len(failedConfigs) > 0 {
+		configStr := "configs"
+		if len(failedConfigs) == 1 {
+			configStr = "config"
+		}
+
+		return grpc.Errorf(codes.InvalidArgument, "%s not found: %v", configStr, strings.Join(failedConfigs, ", "))
+
+	}
+
+	return nil
+}
+
 // CreateService creates and returns a Service based on the provided ServiceSpec.
 // - Returns `InvalidArgument` if the ServiceSpec is malformed.
 // - Returns `Unimplemented` if the ServiceSpec references unimplemented features.
@@ -498,6 +574,10 @@ func (s *Server) CreateService(ctx context.Context, request *api.CreateServiceRe
 		if err != nil {
 			return err
 		}
+		err = s.checkConfigExistence(tx, request.Spec)
+		if err != nil {
+			return err
+		}
 
 		return store.CreateService(tx, service)
 	})
@@ -585,6 +665,11 @@ func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRe
 			return err
 		}
 
+		err = s.checkConfigExistence(tx, request.Spec)
+		if err != nil {
+			return err
+		}
+
 		// orchestrator is designed to be stateless, so it should not deal
 		// with service mode change (comparing current config with previous config).
 		// proper way to change service mode is to delete and re-add.
@@ -621,7 +706,7 @@ func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRe
 			service.Spec = *request.Spec.Copy()
 			// Set spec version. Note that this will not match the
 			// service's Meta.Version after the store update. The
-			// versionsfor the spec and the service itself are not
+			// versions for the spec and the service itself are not
 			// meant to be directly comparable.
 			service.SpecVersion = service.Meta.Version.Copy()
 

+ 247 - 0
vendor/github.com/docker/swarmkit/manager/dispatcher/assignments.go

@@ -0,0 +1,247 @@
+package dispatcher
+
+import (
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/swarmkit/api"
+	"github.com/docker/swarmkit/api/equality"
+	"github.com/docker/swarmkit/manager/state/store"
+)
+
+// Used as a key in tasksUsingDependency and changes. Only using the
+// ID could cause (rare) collisions between different types of
+// objects, so we also include the type of object in the key.
+type objectType int
+
+const (
+	typeTask objectType = iota
+	typeSecret
+	typeConfig
+)
+
+type typeAndID struct {
+	id      string
+	objType objectType
+}
+
+type assignmentSet struct {
+	tasksMap             map[string]*api.Task
+	tasksUsingDependency map[typeAndID]map[string]struct{}
+	changes              map[typeAndID]*api.AssignmentChange
+
+	log *logrus.Entry
+}
+
+func newAssignmentSet(log *logrus.Entry) *assignmentSet {
+	return &assignmentSet{
+		changes:              make(map[typeAndID]*api.AssignmentChange),
+		tasksMap:             make(map[string]*api.Task),
+		tasksUsingDependency: make(map[typeAndID]map[string]struct{}),
+		log:                  log,
+	}
+}
+
+func (a *assignmentSet) addTaskDependencies(readTx store.ReadTx, t *api.Task) {
+	var secrets []*api.SecretReference
+	container := t.Spec.GetContainer()
+	if container != nil {
+		secrets = container.Secrets
+	}
+	for _, secretRef := range secrets {
+		secretID := secretRef.SecretID
+		mapKey := typeAndID{objType: typeSecret, id: secretID}
+
+		if len(a.tasksUsingDependency[mapKey]) == 0 {
+			a.tasksUsingDependency[mapKey] = make(map[string]struct{})
+
+			secret := store.GetSecret(readTx, secretID)
+			if secret == nil {
+				a.log.WithFields(logrus.Fields{
+					"secret.id":   secretID,
+					"secret.name": secretRef.SecretName,
+				}).Debug("secret not found")
+				continue
+			}
+
+			// If the secret was found, add this secret to
+			// our set that we send down.
+			a.changes[mapKey] = &api.AssignmentChange{
+				Assignment: &api.Assignment{
+					Item: &api.Assignment_Secret{
+						Secret: secret,
+					},
+				},
+				Action: api.AssignmentChange_AssignmentActionUpdate,
+			}
+		}
+		a.tasksUsingDependency[mapKey][t.ID] = struct{}{}
+	}
+
+	var configs []*api.ConfigReference
+	if container != nil {
+		configs = container.Configs
+	}
+	for _, configRef := range configs {
+		configID := configRef.ConfigID
+		mapKey := typeAndID{objType: typeConfig, id: configID}
+
+		if len(a.tasksUsingDependency[mapKey]) == 0 {
+			a.tasksUsingDependency[mapKey] = make(map[string]struct{})
+
+			config := store.GetConfig(readTx, configID)
+			if config == nil {
+				a.log.WithFields(logrus.Fields{
+					"config.id":   configID,
+					"config.name": configRef.ConfigName,
+				}).Debug("config not found")
+				continue
+			}
+
+			// If the config was found, add this config to
+			// our set that we send down.
+			a.changes[mapKey] = &api.AssignmentChange{
+				Assignment: &api.Assignment{
+					Item: &api.Assignment_Config{
+						Config: config,
+					},
+				},
+				Action: api.AssignmentChange_AssignmentActionUpdate,
+			}
+		}
+		a.tasksUsingDependency[mapKey][t.ID] = struct{}{}
+	}
+}
+
+func (a *assignmentSet) releaseDependency(mapKey typeAndID, assignment *api.Assignment, taskID string) bool {
+	delete(a.tasksUsingDependency[mapKey], taskID)
+	if len(a.tasksUsingDependency[mapKey]) != 0 {
+		return false
+	}
+	// No tasks are using the dependency anymore
+	delete(a.tasksUsingDependency, mapKey)
+	a.changes[mapKey] = &api.AssignmentChange{
+		Assignment: assignment,
+		Action:     api.AssignmentChange_AssignmentActionRemove,
+	}
+	return true
+}
+
+func (a *assignmentSet) releaseTaskDependencies(t *api.Task) bool {
+	var modified bool
+	container := t.Spec.GetContainer()
+
+	var secrets []*api.SecretReference
+	if container != nil {
+		secrets = container.Secrets
+	}
+
+	for _, secretRef := range secrets {
+		secretID := secretRef.SecretID
+		mapKey := typeAndID{objType: typeSecret, id: secretID}
+		assignment := &api.Assignment{
+			Item: &api.Assignment_Secret{
+				Secret: &api.Secret{ID: secretID},
+			},
+		}
+		if a.releaseDependency(mapKey, assignment, t.ID) {
+			modified = true
+		}
+	}
+
+	var configs []*api.ConfigReference
+	if container != nil {
+		configs = container.Configs
+	}
+
+	for _, configRef := range configs {
+		configID := configRef.ConfigID
+		mapKey := typeAndID{objType: typeConfig, id: configID}
+		assignment := &api.Assignment{
+			Item: &api.Assignment_Config{
+				Config: &api.Config{ID: configID},
+			},
+		}
+		if a.releaseDependency(mapKey, assignment, t.ID) {
+			modified = true
+		}
+	}
+
+	return modified
+}
+
+func (a *assignmentSet) addOrUpdateTask(readTx store.ReadTx, t *api.Task) bool {
+	// We only care about tasks that are ASSIGNED or higher.
+	if t.Status.State < api.TaskStateAssigned {
+		return false
+	}
+
+	if oldTask, exists := a.tasksMap[t.ID]; exists {
+		// States ASSIGNED and below are set by the orchestrator/scheduler,
+		// not the agent, so tasks in these states need to be sent to the
+		// agent even if nothing else has changed.
+		if equality.TasksEqualStable(oldTask, t) && t.Status.State > api.TaskStateAssigned {
+			// this update should not trigger a task change for the agent
+			a.tasksMap[t.ID] = t
+			// If this task got updated to a final state, let's release
+			// the dependencies that are being used by the task
+			if t.Status.State > api.TaskStateRunning {
+				// If releasing the dependencies caused us to
+				// remove something from the assignment set,
+				// mark one modification.
+				return a.releaseTaskDependencies(t)
+			}
+			return false
+		}
+	} else if t.Status.State <= api.TaskStateRunning {
+		// If this task wasn't part of the assignment set before, and it's <= RUNNING
+		// add the dependencies it references to the assignment.
+		// Task states > RUNNING are worker reported only, are never created in
+		// a > RUNNING state.
+		a.addTaskDependencies(readTx, t)
+	}
+	a.tasksMap[t.ID] = t
+	a.changes[typeAndID{objType: typeTask, id: t.ID}] = &api.AssignmentChange{
+		Assignment: &api.Assignment{
+			Item: &api.Assignment_Task{
+				Task: t,
+			},
+		},
+		Action: api.AssignmentChange_AssignmentActionUpdate,
+	}
+	return true
+}
+
+func (a *assignmentSet) removeTask(t *api.Task) bool {
+	if _, exists := a.tasksMap[t.ID]; !exists {
+		return false
+	}
+
+	a.changes[typeAndID{objType: typeTask, id: t.ID}] = &api.AssignmentChange{
+		Assignment: &api.Assignment{
+			Item: &api.Assignment_Task{
+				Task: &api.Task{ID: t.ID},
+			},
+		},
+		Action: api.AssignmentChange_AssignmentActionRemove,
+	}
+
+	delete(a.tasksMap, t.ID)
+
+	// Release the dependencies being used by this task.
+	// Ignoring the return here. We will always mark this as a
+	// modification, since a task is being removed.
+	a.releaseTaskDependencies(t)
+	return true
+}
+
+func (a *assignmentSet) message() api.AssignmentsMessage {
+	var message api.AssignmentsMessage
+	for _, change := range a.changes {
+		message.Changes = append(message.Changes, change)
+	}
+
+	// The the set of changes is reinitialized to prepare for formation
+	// of the next message.
+	a.changes = make(map[typeAndID]*api.AssignmentChange)
+
+	return message
+}

+ 61 - 255
vendor/github.com/docker/swarmkit/manager/dispatcher/dispatcher.go

@@ -102,20 +102,29 @@ type nodeUpdate struct {
 	description *api.NodeDescription
 }
 
+// clusterUpdate is an object that stores an update to the cluster that should trigger
+// a new session message.  These are pointers to indicate the difference between
+// "there is no update" and "update this to nil"
+type clusterUpdate struct {
+	managerUpdate      *[]*api.WeightedPeer
+	bootstrapKeyUpdate *[]*api.EncryptionKey
+	rootCAUpdate       *[]byte
+}
+
 // Dispatcher is responsible for dispatching tasks and tracking agent health.
 type Dispatcher struct {
 	mu                   sync.Mutex
 	wg                   sync.WaitGroup
 	nodes                *nodeStore
 	store                *store.MemoryStore
-	mgrQueue             *watch.Queue
 	lastSeenManagers     []*api.WeightedPeer
 	networkBootstrapKeys []*api.EncryptionKey
-	keyMgrQueue          *watch.Queue
+	lastSeenRootCert     []byte
 	config               *Config
 	cluster              Cluster
 	ctx                  context.Context
 	cancel               context.CancelFunc
+	clusterUpdateQueue   *watch.Queue
 
 	taskUpdates     map[string]*api.TaskStatus // indexed by task ID
 	taskUpdatesLock sync.Mutex
@@ -196,6 +205,7 @@ func (d *Dispatcher) Run(ctx context.Context) error {
 				if clusters[0].NetworkBootstrapKeys != nil {
 					d.networkBootstrapKeys = clusters[0].NetworkBootstrapKeys
 				}
+				d.lastSeenRootCert = clusters[0].RootCA.CACert
 			}
 			return nil
 		},
@@ -205,9 +215,8 @@ func (d *Dispatcher) Run(ctx context.Context) error {
 		d.mu.Unlock()
 		return err
 	}
-	// set queues here to guarantee that Close will close them
-	d.mgrQueue = watch.NewQueue()
-	d.keyMgrQueue = watch.NewQueue()
+	// set queue here to guarantee that Close will close it
+	d.clusterUpdateQueue = watch.NewQueue()
 
 	peerWatcher, peerCancel := d.cluster.SubscribePeers()
 	defer peerCancel()
@@ -231,7 +240,7 @@ func (d *Dispatcher) Run(ctx context.Context) error {
 		d.mu.Lock()
 		d.lastSeenManagers = mgrs
 		d.mu.Unlock()
-		d.mgrQueue.Publish(mgrs)
+		d.clusterUpdateQueue.Publish(clusterUpdate{managerUpdate: &mgrs})
 	}
 
 	batchTimer := time.NewTimer(maxBatchInterval)
@@ -259,9 +268,13 @@ func (d *Dispatcher) Run(ctx context.Context) error {
 					d.nodes.updatePeriod(d.config.HeartbeatPeriod, d.config.HeartbeatEpsilon, d.config.GracePeriodMultiplier)
 				}
 			}
+			d.lastSeenRootCert = cluster.Cluster.RootCA.CACert
 			d.networkBootstrapKeys = cluster.Cluster.NetworkBootstrapKeys
 			d.mu.Unlock()
-			d.keyMgrQueue.Publish(cluster.Cluster.NetworkBootstrapKeys)
+			d.clusterUpdateQueue.Publish(clusterUpdate{
+				bootstrapKeyUpdate: &cluster.Cluster.NetworkBootstrapKeys,
+				rootCAUpdate:       &cluster.Cluster.RootCA.CACert,
+			})
 		case <-ctx.Done():
 			return nil
 		}
@@ -286,8 +299,7 @@ func (d *Dispatcher) Stop() error {
 	d.processUpdatesCond.Broadcast()
 	d.processUpdatesLock.Unlock()
 
-	d.mgrQueue.Close()
-	d.keyMgrQueue.Close()
+	d.clusterUpdateQueue.Close()
 
 	d.wg.Wait()
 
@@ -812,12 +824,10 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 	}
 
 	var (
-		sequence  int64
-		appliesTo string
-		initial   api.AssignmentsMessage
+		sequence    int64
+		appliesTo   string
+		assignments = newAssignmentSet(log)
 	)
-	tasksMap := make(map[string]*api.Task)
-	tasksUsingSecret := make(map[string]map[string]struct{})
 
 	sendMessage := func(msg api.AssignmentsMessage, assignmentType api.AssignmentsMessage_Type) error {
 		sequence++
@@ -832,39 +842,6 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 		return nil
 	}
 
-	// returns a slice of new secrets to send down
-	addSecretsForTask := func(readTx store.ReadTx, t *api.Task) []*api.Secret {
-		container := t.Spec.GetContainer()
-		if container == nil {
-			return nil
-		}
-		var newSecrets []*api.Secret
-		for _, secretRef := range container.Secrets {
-			secretID := secretRef.SecretID
-			log := log.WithFields(logrus.Fields{
-				"secret.id":   secretID,
-				"secret.name": secretRef.SecretName,
-			})
-
-			if len(tasksUsingSecret[secretID]) == 0 {
-				tasksUsingSecret[secretID] = make(map[string]struct{})
-
-				secret := store.GetSecret(readTx, secretID)
-				if secret == nil {
-					log.Debug("secret not found")
-					continue
-				}
-
-				// If the secret was found, add this secret to
-				// our set that we send down.
-				newSecrets = append(newSecrets, secret)
-			}
-			tasksUsingSecret[secretID][t.ID] = struct{}{}
-		}
-
-		return newSecrets
-	}
-
 	// TODO(aaronl): Also send node secrets that should be exposed to
 	// this node.
 	nodeTasks, cancel, err := store.ViewAndWatch(
@@ -876,57 +853,22 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 			}
 
 			for _, t := range tasks {
-				// We only care about tasks that are ASSIGNED or
-				// higher. If the state is below ASSIGNED, the
-				// task may not meet the constraints for this
-				// node, so we have to be careful about sending
-				// secrets associated with it.
-				if t.Status.State < api.TaskStateAssigned {
-					continue
-				}
-
-				tasksMap[t.ID] = t
-				taskChange := &api.AssignmentChange{
-					Assignment: &api.Assignment{
-						Item: &api.Assignment_Task{
-							Task: t,
-						},
-					},
-					Action: api.AssignmentChange_AssignmentActionUpdate,
-				}
-				initial.Changes = append(initial.Changes, taskChange)
-				// Only send secrets down if these tasks are in < RUNNING
-				if t.Status.State <= api.TaskStateRunning {
-					newSecrets := addSecretsForTask(readTx, t)
-					for _, secret := range newSecrets {
-						secretChange := &api.AssignmentChange{
-							Assignment: &api.Assignment{
-								Item: &api.Assignment_Secret{
-									Secret: secret,
-								},
-							},
-							Action: api.AssignmentChange_AssignmentActionUpdate,
-						}
-
-						initial.Changes = append(initial.Changes, secretChange)
-					}
-				}
+				assignments.addOrUpdateTask(readTx, t)
 			}
+
 			return nil
 		},
 		api.EventUpdateTask{Task: &api.Task{NodeID: nodeID},
 			Checks: []api.TaskCheckFunc{api.TaskCheckNodeID}},
 		api.EventDeleteTask{Task: &api.Task{NodeID: nodeID},
 			Checks: []api.TaskCheckFunc{api.TaskCheckNodeID}},
-		api.EventUpdateSecret{},
-		api.EventDeleteSecret{},
 	)
 	if err != nil {
 		return err
 	}
 	defer cancel()
 
-	if err := sendMessage(initial, api.AssignmentsMessage_COMPLETE); err != nil {
+	if err := sendMessage(assignments.message(), api.AssignmentsMessage_COMPLETE); err != nil {
 		return err
 	}
 
@@ -938,14 +880,9 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 
 		// bursty events should be processed in batches and sent out together
 		var (
-			update          api.AssignmentsMessage
 			modificationCnt int
 			batchingTimer   *time.Timer
 			batchingTimeout <-chan time.Time
-			updateTasks     = make(map[string]*api.Task)
-			updateSecrets   = make(map[string]*api.Secret)
-			removeTasks     = make(map[string]struct{})
-			removeSecrets   = make(map[string]struct{})
 		)
 
 		oneModification := func() {
@@ -959,28 +896,6 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 			}
 		}
 
-		// Release the secrets references from this task
-		releaseSecretsForTask := func(t *api.Task) bool {
-			var modified bool
-			container := t.Spec.GetContainer()
-			if container == nil {
-				return modified
-			}
-
-			for _, secretRef := range container.Secrets {
-				secretID := secretRef.SecretID
-				delete(tasksUsingSecret[secretID], t.ID)
-				if len(tasksUsingSecret[secretID]) == 0 {
-					// No tasks are using the secret anymore
-					delete(tasksUsingSecret, secretID)
-					removeSecrets[secretID] = struct{}{}
-					modified = true
-				}
-			}
-
-			return modified
-		}
-
 		// The batching loop waits for 50 ms after the most recent
 		// change, or until modificationBatchLimit is reached. The
 		// worst case latency is modificationBatchLimit * batchingWaitTime,
@@ -996,78 +911,17 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 				// them to ASSIGNED. If this ever changes, we will need
 				// to monitor task creations as well.
 				case api.EventUpdateTask:
-					// We only care about tasks that are ASSIGNED or
-					// higher.
-					if v.Task.Status.State < api.TaskStateAssigned {
-						continue
-					}
-
-					if oldTask, exists := tasksMap[v.Task.ID]; exists {
-						// States ASSIGNED and below are set by the orchestrator/scheduler,
-						// not the agent, so tasks in these states need to be sent to the
-						// agent even if nothing else has changed.
-						if equality.TasksEqualStable(oldTask, v.Task) && v.Task.Status.State > api.TaskStateAssigned {
-							// this update should not trigger a task change for the agent
-							tasksMap[v.Task.ID] = v.Task
-							// If this task got updated to a final state, let's release
-							// the secrets that are being used by the task
-							if v.Task.Status.State > api.TaskStateRunning {
-								// If releasing the secrets caused a secret to be
-								// removed from an agent, mark one modification
-								if releaseSecretsForTask(v.Task) {
-									oneModification()
-								}
-							}
-							continue
-						}
-					} else if v.Task.Status.State <= api.TaskStateRunning {
-						// If this task wasn't part of the assignment set before, and it's <= RUNNING
-						// add the secrets it references to the secrets assignment.
-						// Task states > RUNNING are worker reported only, are never created in
-						// a > RUNNING state.
-						var newSecrets []*api.Secret
-						d.store.View(func(readTx store.ReadTx) {
-							newSecrets = addSecretsForTask(readTx, v.Task)
-						})
-						for _, secret := range newSecrets {
-							updateSecrets[secret.ID] = secret
+					d.store.View(func(readTx store.ReadTx) {
+						if assignments.addOrUpdateTask(readTx, v.Task) {
+							oneModification()
 						}
-					}
-					tasksMap[v.Task.ID] = v.Task
-					updateTasks[v.Task.ID] = v.Task
-
-					oneModification()
+					})
 				case api.EventDeleteTask:
-					if _, exists := tasksMap[v.Task.ID]; !exists {
-						continue
+					if assignments.removeTask(v.Task) {
+						oneModification()
 					}
-
-					removeTasks[v.Task.ID] = struct{}{}
-
-					delete(tasksMap, v.Task.ID)
-
-					// Release the secrets being used by this task
-					// Ignoring the return here. We will always mark
-					// this as a modification, since a task is being
-					// removed.
-					releaseSecretsForTask(v.Task)
-
-					oneModification()
-				// TODO(aaronl): For node secrets, we'll need to handle
-				// EventCreateSecret.
-				case api.EventUpdateSecret:
-					if _, exists := tasksUsingSecret[v.Secret.ID]; !exists {
-						continue
-					}
-					log.Debugf("Secret %s (ID: %d) was updated though it was still referenced by one or more tasks",
-						v.Secret.Spec.Annotations.Name, v.Secret.ID)
-
-				case api.EventDeleteSecret:
-					if _, exists := tasksUsingSecret[v.Secret.ID]; !exists {
-						continue
-					}
-					log.Debugf("Secret %s (ID: %d) was deleted though it was still referenced by one or more tasks",
-						v.Secret.Spec.Annotations.Name, v.Secret.ID)
+					// TODO(aaronl): For node secrets, we'll need to handle
+					// EventCreateSecret.
 				}
 			case <-batchingTimeout:
 				break batchingLoop
@@ -1083,72 +937,7 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 		}
 
 		if modificationCnt > 0 {
-			for id, task := range updateTasks {
-				if _, ok := removeTasks[id]; !ok {
-					taskChange := &api.AssignmentChange{
-						Assignment: &api.Assignment{
-							Item: &api.Assignment_Task{
-								Task: task,
-							},
-						},
-						Action: api.AssignmentChange_AssignmentActionUpdate,
-					}
-
-					update.Changes = append(update.Changes, taskChange)
-				}
-			}
-			for id, secret := range updateSecrets {
-				// If, due to multiple updates, this secret is no longer in use,
-				// don't send it down.
-				if len(tasksUsingSecret[id]) == 0 {
-					// delete this secret for the secrets to be updated
-					// so that deleteSecrets knows the current list
-					delete(updateSecrets, id)
-					continue
-				}
-				secretChange := &api.AssignmentChange{
-					Assignment: &api.Assignment{
-						Item: &api.Assignment_Secret{
-							Secret: secret,
-						},
-					},
-					Action: api.AssignmentChange_AssignmentActionUpdate,
-				}
-
-				update.Changes = append(update.Changes, secretChange)
-			}
-			for id := range removeTasks {
-				taskChange := &api.AssignmentChange{
-					Assignment: &api.Assignment{
-						Item: &api.Assignment_Task{
-							Task: &api.Task{ID: id},
-						},
-					},
-					Action: api.AssignmentChange_AssignmentActionRemove,
-				}
-
-				update.Changes = append(update.Changes, taskChange)
-			}
-			for id := range removeSecrets {
-				// If this secret is also being sent on the updated set
-				// don't also add it to the removed set
-				if _, ok := updateSecrets[id]; ok {
-					continue
-				}
-
-				secretChange := &api.AssignmentChange{
-					Assignment: &api.Assignment{
-						Item: &api.Assignment_Secret{
-							Secret: &api.Secret{ID: id},
-						},
-					},
-					Action: api.AssignmentChange_AssignmentActionRemove,
-				}
-
-				update.Changes = append(update.Changes, secretChange)
-			}
-
-			if err := sendMessage(update, api.AssignmentsMessage_INCREMENTAL); err != nil {
+			if err := sendMessage(assignments.message(), api.AssignmentsMessage_INCREMENTAL); err != nil {
 				return err
 			}
 		}
@@ -1284,6 +1073,12 @@ func (d *Dispatcher) getNetworkBootstrapKeys() []*api.EncryptionKey {
 	return d.networkBootstrapKeys
 }
 
+func (d *Dispatcher) getRootCACert() []byte {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+	return d.lastSeenRootCert
+}
+
 // Session is a stream which controls agent connection.
 // Each message contains list of backup Managers with weights. Also there is
 // a special boolean field Disconnect which if true indicates that node should
@@ -1355,14 +1150,13 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 		Node:                 nodeObj,
 		Managers:             d.getManagers(),
 		NetworkBootstrapKeys: d.getNetworkBootstrapKeys(),
+		RootCA:               d.getRootCACert(),
 	}); err != nil {
 		return err
 	}
 
-	managerUpdates, mgrCancel := d.mgrQueue.Watch()
-	defer mgrCancel()
-	keyMgrUpdates, keyMgrCancel := d.keyMgrQueue.Watch()
-	defer keyMgrCancel()
+	clusterUpdatesCh, clusterCancel := d.clusterUpdateQueue.Watch()
+	defer clusterCancel()
 
 	// disconnectNode is a helper forcibly shutdown connection
 	disconnectNode := func() error {
@@ -1396,11 +1190,21 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 			disconnect bool
 			mgrs       []*api.WeightedPeer
 			netKeys    []*api.EncryptionKey
+			rootCert   []byte
 		)
 
 		select {
-		case ev := <-managerUpdates:
-			mgrs = ev.([]*api.WeightedPeer)
+		case ev := <-clusterUpdatesCh:
+			update := ev.(clusterUpdate)
+			if update.managerUpdate != nil {
+				mgrs = *update.managerUpdate
+			}
+			if update.bootstrapKeyUpdate != nil {
+				netKeys = *update.bootstrapKeyUpdate
+			}
+			if update.rootCAUpdate != nil {
+				rootCert = *update.rootCAUpdate
+			}
 		case ev := <-nodeUpdates:
 			nodeObj = ev.(api.EventUpdateNode).Node
 		case <-stream.Context().Done():
@@ -1409,8 +1213,6 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 			disconnect = true
 		case <-dctx.Done():
 			disconnect = true
-		case ev := <-keyMgrUpdates:
-			netKeys = ev.([]*api.EncryptionKey)
 		}
 		if mgrs == nil {
 			mgrs = d.getManagers()
@@ -1418,12 +1220,16 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 		if netKeys == nil {
 			netKeys = d.getNetworkBootstrapKeys()
 		}
+		if rootCert == nil {
+			rootCert = d.getRootCACert()
+		}
 
 		if err := stream.Send(&api.SessionMessage{
 			SessionID:            sessionID,
 			Node:                 nodeObj,
 			Managers:             mgrs,
 			NetworkBootstrapKeys: netKeys,
+			RootCA:               rootCert,
 		}); err != nil {
 			return err
 		}

+ 4 - 1
vendor/github.com/docker/swarmkit/manager/manager.go

@@ -65,6 +65,9 @@ type RemoteAddrs struct {
 type Config struct {
 	SecurityConfig *ca.SecurityConfig
 
+	// RootCAPaths is the path to which new root certs should be save
+	RootCAPaths ca.CertPaths
+
 	// ExternalCAs is a list of initial CAs to which a manager node
 	// will make certificate signing requests for node certificates.
 	ExternalCAs []*api.ExternalCA
@@ -210,7 +213,7 @@ func New(config *Config) (*Manager, error) {
 
 	m := &Manager{
 		config:          *config,
-		caserver:        ca.NewServer(raftNode.MemoryStore(), config.SecurityConfig),
+		caserver:        ca.NewServer(raftNode.MemoryStore(), config.SecurityConfig, config.RootCAPaths),
 		dispatcher:      dispatcher.New(raftNode, dispatcher.DefaultConfig()),
 		logbroker:       logbroker.New(raftNode.MemoryStore()),
 		server:          grpc.NewServer(opts...),

+ 2 - 1
vendor/github.com/docker/swarmkit/manager/orchestrator/task.go

@@ -5,6 +5,7 @@ import (
 	"time"
 
 	"github.com/docker/swarmkit/api"
+	"github.com/docker/swarmkit/api/defaults"
 	"github.com/docker/swarmkit/identity"
 	"github.com/docker/swarmkit/protobuf/ptypes"
 )
@@ -50,7 +51,7 @@ func NewTask(cluster *api.Cluster, service *api.Service, slot uint64, nodeID str
 
 // RestartCondition returns the restart condition to apply to this task.
 func RestartCondition(task *api.Task) api.RestartPolicy_RestartCondition {
-	restartCondition := api.RestartOnAny
+	restartCondition := defaults.Service.Task.Restart.Condition
 	if task.Spec.Restart != nil {
 		restartCondition = task.Spec.Restart.Condition
 	}

+ 21 - 27
vendor/github.com/docker/swarmkit/manager/orchestrator/update/updater.go

@@ -155,31 +155,25 @@ func (u *Updater) Run(ctx context.Context, slots []orchestrator.Slot) {
 		u.startUpdate(ctx, service.ID)
 	}
 
-	delay := defaults.Service.Update.Delay
-	parallelism := int(defaults.Service.Update.Parallelism)
-	failureAction := defaults.Service.Update.FailureAction
-	allowedFailureFraction := defaults.Service.Update.MaxFailureRatio
-	monitoringPeriod, _ := gogotypes.DurationFromProto(defaults.Service.Update.Monitor)
-	order := defaults.Service.Update.Order
+	var monitoringPeriod time.Duration
 
 	updateConfig := service.Spec.Update
 	if service.UpdateStatus != nil && service.UpdateStatus.State == api.UpdateStatus_ROLLBACK_STARTED {
+		monitoringPeriod, _ = gogotypes.DurationFromProto(defaults.Service.Rollback.Monitor)
 		updateConfig = service.Spec.Rollback
+		if updateConfig == nil {
+			updateConfig = defaults.Service.Rollback
+		}
+	} else if updateConfig == nil {
+		monitoringPeriod, _ = gogotypes.DurationFromProto(defaults.Service.Update.Monitor)
+		updateConfig = defaults.Service.Update
 	}
 
-	if updateConfig != nil {
-		failureAction = updateConfig.FailureAction
-		allowedFailureFraction = updateConfig.MaxFailureRatio
-		parallelism = int(updateConfig.Parallelism)
-		delay = updateConfig.Delay
-		order = updateConfig.Order
-
-		var err error
-		if updateConfig.Monitor != nil {
-			monitoringPeriod, err = gogotypes.DurationFromProto(updateConfig.Monitor)
-			if err != nil {
-				monitoringPeriod, _ = gogotypes.DurationFromProto(defaults.Service.Update.Monitor)
-			}
+	parallelism := int(updateConfig.Parallelism)
+	if updateConfig.Monitor != nil {
+		newMonitoringPeriod, err := gogotypes.DurationFromProto(updateConfig.Monitor)
+		if err == nil {
+			monitoringPeriod = newMonitoringPeriod
 		}
 	}
 
@@ -195,14 +189,14 @@ func (u *Updater) Run(ctx context.Context, slots []orchestrator.Slot) {
 	wg.Add(parallelism)
 	for i := 0; i < parallelism; i++ {
 		go func() {
-			u.worker(ctx, slotQueue, delay, order)
+			u.worker(ctx, slotQueue, updateConfig)
 			wg.Done()
 		}()
 	}
 
 	var failedTaskWatch chan events.Event
 
-	if failureAction != api.UpdateConfig_CONTINUE {
+	if updateConfig.FailureAction != api.UpdateConfig_CONTINUE {
 		var cancelWatch func()
 		failedTaskWatch, cancelWatch = state.Watch(
 			u.store.WatchQueue(),
@@ -234,8 +228,8 @@ func (u *Updater) Run(ctx context.Context, slots []orchestrator.Slot) {
 		if found && (startedAt.IsZero() || time.Since(startedAt) <= monitoringPeriod) {
 			failedTasks[failedTask.ID] = struct{}{}
 			totalFailures++
-			if float32(totalFailures)/float32(len(dirtySlots)) > allowedFailureFraction {
-				switch failureAction {
+			if float32(totalFailures)/float32(len(dirtySlots)) > updateConfig.MaxFailureRatio {
+				switch updateConfig.FailureAction {
 				case api.UpdateConfig_PAUSE:
 					stopped = true
 					message := fmt.Sprintf("update paused due to failure or early termination of task %s", failedTask.ID)
@@ -309,7 +303,7 @@ slotsLoop:
 	}
 }
 
-func (u *Updater) worker(ctx context.Context, queue <-chan orchestrator.Slot, delay time.Duration, order api.UpdateConfig_UpdateOrder) {
+func (u *Updater) worker(ctx context.Context, queue <-chan orchestrator.Slot, updateConfig *api.UpdateConfig) {
 	for slot := range queue {
 		// Do we have a task with the new spec in desired state = RUNNING?
 		// If so, all we have to do to complete the update is remove the
@@ -346,14 +340,14 @@ func (u *Updater) worker(ctx context.Context, queue <-chan orchestrator.Slot, de
 			}
 			updated.DesiredState = api.TaskStateReady
 
-			if err := u.updateTask(ctx, slot, updated, order); err != nil {
+			if err := u.updateTask(ctx, slot, updated, updateConfig.Order); err != nil {
 				log.G(ctx).WithError(err).WithField("task.id", updated.ID).Error("update failed")
 			}
 		}
 
-		if delay != 0 {
+		if updateConfig.Delay != 0 {
 			select {
-			case <-time.After(delay):
+			case <-time.After(updateConfig.Delay):
 			case <-u.stopChan:
 				return
 			}

+ 11 - 0
vendor/github.com/docker/swarmkit/manager/state/store/by.go

@@ -154,6 +154,17 @@ func ByReferencedSecretID(secretID string) By {
 	return byReferencedSecretID(secretID)
 }
 
+type byReferencedConfigID string
+
+func (b byReferencedConfigID) isBy() {
+}
+
+// ByReferencedConfigID creates an object to pass to Find to search for a
+// service or task that references a config with the given ID.
+func ByReferencedConfigID(configID string) By {
+	return byReferencedConfigID(configID)
+}
+
 type byKind string
 
 func (b byKind) isBy() {

+ 132 - 0
vendor/github.com/docker/swarmkit/manager/state/store/configs.go

@@ -0,0 +1,132 @@
+package store
+
+import (
+	"strings"
+
+	"github.com/docker/swarmkit/api"
+	memdb "github.com/hashicorp/go-memdb"
+)
+
+const tableConfig = "config"
+
+func init() {
+	register(ObjectStoreConfig{
+		Table: &memdb.TableSchema{
+			Name: tableConfig,
+			Indexes: map[string]*memdb.IndexSchema{
+				indexID: {
+					Name:    indexID,
+					Unique:  true,
+					Indexer: api.ConfigIndexerByID{},
+				},
+				indexName: {
+					Name:    indexName,
+					Unique:  true,
+					Indexer: api.ConfigIndexerByName{},
+				},
+				indexCustom: {
+					Name:         indexCustom,
+					Indexer:      api.ConfigCustomIndexer{},
+					AllowMissing: true,
+				},
+			},
+		},
+		Save: func(tx ReadTx, snapshot *api.StoreSnapshot) error {
+			var err error
+			snapshot.Configs, err = FindConfigs(tx, All)
+			return err
+		},
+		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
+			configs, err := FindConfigs(tx, All)
+			if err != nil {
+				return err
+			}
+			for _, s := range configs {
+				if err := DeleteConfig(tx, s.ID); err != nil {
+					return err
+				}
+			}
+			for _, s := range snapshot.Configs {
+				if err := CreateConfig(tx, s); err != nil {
+					return err
+				}
+			}
+			return nil
+		},
+		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
+			switch v := sa.Target.(type) {
+			case *api.StoreAction_Config:
+				obj := v.Config
+				switch sa.Action {
+				case api.StoreActionKindCreate:
+					return CreateConfig(tx, obj)
+				case api.StoreActionKindUpdate:
+					return UpdateConfig(tx, obj)
+				case api.StoreActionKindRemove:
+					return DeleteConfig(tx, obj.ID)
+				}
+			}
+			return errUnknownStoreAction
+		},
+	})
+}
+
+// CreateConfig adds a new config to the store.
+// Returns ErrExist if the ID is already taken.
+func CreateConfig(tx Tx, c *api.Config) error {
+	// Ensure the name is not already in use.
+	if tx.lookup(tableConfig, indexName, strings.ToLower(c.Spec.Annotations.Name)) != nil {
+		return ErrNameConflict
+	}
+
+	return tx.create(tableConfig, c)
+}
+
+// UpdateConfig updates an existing config in the store.
+// Returns ErrNotExist if the config doesn't exist.
+func UpdateConfig(tx Tx, c *api.Config) error {
+	// Ensure the name is either not in use or already used by this same Config.
+	if existing := tx.lookup(tableConfig, indexName, strings.ToLower(c.Spec.Annotations.Name)); existing != nil {
+		if existing.GetID() != c.ID {
+			return ErrNameConflict
+		}
+	}
+
+	return tx.update(tableConfig, c)
+}
+
+// DeleteConfig removes a config from the store.
+// Returns ErrNotExist if the config doesn't exist.
+func DeleteConfig(tx Tx, id string) error {
+	return tx.delete(tableConfig, id)
+}
+
+// GetConfig looks up a config by ID.
+// Returns nil if the config doesn't exist.
+func GetConfig(tx ReadTx, id string) *api.Config {
+	c := tx.get(tableConfig, id)
+	if c == nil {
+		return nil
+	}
+	return c.(*api.Config)
+}
+
+// FindConfigs selects a set of configs and returns them.
+func FindConfigs(tx ReadTx, by By) ([]*api.Config, error) {
+	checkType := func(by By) error {
+		switch by.(type) {
+		case byName, byNamePrefix, byIDPrefix, byCustom, byCustomPrefix:
+			return nil
+		default:
+			return ErrInvalidFindBy
+		}
+	}
+
+	configList := []*api.Config{}
+	appendResult := func(o api.StoreObject) {
+		configList = append(configList, o.(*api.Config))
+	}
+
+	err := tx.find(tableConfig, by, checkType, appendResult)
+	return configList, err
+}

+ 7 - 0
vendor/github.com/docker/swarmkit/manager/state/store/memory.go

@@ -33,6 +33,7 @@ const (
 	indexMembership   = "membership"
 	indexNetwork      = "network"
 	indexSecret       = "secret"
+	indexConfig       = "config"
 	indexKind         = "kind"
 	indexCustom       = "custom"
 
@@ -696,6 +697,12 @@ func (tx readTx) findIterators(table string, by By, checkType func(By) error) ([
 			return nil, err
 		}
 		return []memdb.ResultIterator{it}, nil
+	case byReferencedConfigID:
+		it, err := tx.memDBTx.Get(table, indexConfig, string(v))
+		if err != nil {
+			return nil, err
+		}
+		return []memdb.ResultIterator{it}, nil
 	case byKind:
 		it, err := tx.memDBTx.Get(table, indexKind, string(v))
 		if err != nil {

+ 33 - 1
vendor/github.com/docker/swarmkit/manager/state/store/services.go

@@ -40,6 +40,11 @@ func init() {
 					AllowMissing: true,
 					Indexer:      serviceIndexerBySecret{},
 				},
+				indexConfig: {
+					Name:         indexConfig,
+					AllowMissing: true,
+					Indexer:      serviceIndexerByConfig{},
+				},
 				indexCustom: {
 					Name:         indexCustom,
 					Indexer:      api.ServiceCustomIndexer{},
@@ -131,7 +136,7 @@ func GetService(tx ReadTx, id string) *api.Service {
 func FindServices(tx ReadTx, by By) ([]*api.Service, error) {
 	checkType := func(by By) error {
 		switch by.(type) {
-		case byName, byNamePrefix, byIDPrefix, byRuntime, byReferencedNetworkID, byReferencedSecretID, byCustom, byCustomPrefix:
+		case byName, byNamePrefix, byIDPrefix, byRuntime, byReferencedNetworkID, byReferencedSecretID, byReferencedConfigID, byCustom, byCustomPrefix:
 			return nil
 		default:
 			return ErrInvalidFindBy
@@ -214,3 +219,30 @@ func (si serviceIndexerBySecret) FromObject(obj interface{}) (bool, [][]byte, er
 
 	return len(secretIDs) != 0, secretIDs, nil
 }
+
+type serviceIndexerByConfig struct{}
+
+func (si serviceIndexerByConfig) FromArgs(args ...interface{}) ([]byte, error) {
+	return fromArgs(args...)
+}
+
+func (si serviceIndexerByConfig) FromObject(obj interface{}) (bool, [][]byte, error) {
+	s, ok := obj.(*api.Service)
+	if !ok {
+		panic("unexpected type passed to FromObject")
+	}
+
+	container := s.Spec.Task.GetContainer()
+	if container == nil {
+		return false, nil, nil
+	}
+
+	var configIDs [][]byte
+
+	for _, configRef := range container.Configs {
+		// Add the null character as a terminator
+		configIDs = append(configIDs, []byte(configRef.ConfigID+"\x00"))
+	}
+
+	return len(configIDs) != 0, configIDs, nil
+}

+ 33 - 1
vendor/github.com/docker/swarmkit/manager/state/store/tasks.go

@@ -64,6 +64,11 @@ func init() {
 					AllowMissing: true,
 					Indexer:      taskIndexerBySecret{},
 				},
+				indexConfig: {
+					Name:         indexConfig,
+					AllowMissing: true,
+					Indexer:      taskIndexerByConfig{},
+				},
 				indexCustom: {
 					Name:         indexCustom,
 					Indexer:      api.TaskCustomIndexer{},
@@ -143,7 +148,7 @@ func GetTask(tx ReadTx, id string) *api.Task {
 func FindTasks(tx ReadTx, by By) ([]*api.Task, error) {
 	checkType := func(by By) error {
 		switch by.(type) {
-		case byName, byNamePrefix, byIDPrefix, byRuntime, byDesiredState, byTaskState, byNode, byService, bySlot, byReferencedNetworkID, byReferencedSecretID, byCustom, byCustomPrefix:
+		case byName, byNamePrefix, byIDPrefix, byRuntime, byDesiredState, byTaskState, byNode, byService, bySlot, byReferencedNetworkID, byReferencedSecretID, byReferencedConfigID, byCustom, byCustomPrefix:
 			return nil
 		default:
 			return ErrInvalidFindBy
@@ -295,6 +300,33 @@ func (ti taskIndexerBySecret) FromObject(obj interface{}) (bool, [][]byte, error
 	return len(secretIDs) != 0, secretIDs, nil
 }
 
+type taskIndexerByConfig struct{}
+
+func (ti taskIndexerByConfig) FromArgs(args ...interface{}) ([]byte, error) {
+	return fromArgs(args...)
+}
+
+func (ti taskIndexerByConfig) FromObject(obj interface{}) (bool, [][]byte, error) {
+	t, ok := obj.(*api.Task)
+	if !ok {
+		panic("unexpected type passed to FromObject")
+	}
+
+	container := t.Spec.GetContainer()
+	if container == nil {
+		return false, nil, nil
+	}
+
+	var configIDs [][]byte
+
+	for _, configRef := range container.Configs {
+		// Add the null character as a terminator
+		configIDs = append(configIDs, []byte(configRef.ConfigID+"\x00"))
+	}
+
+	return len(configIDs) != 0, configIDs, nil
+}
+
 type taskIndexerByTaskState struct{}
 
 func (ts taskIndexerByTaskState) FromArgs(args ...interface{}) ([]byte, error) {

+ 65 - 27
vendor/github.com/docker/swarmkit/node/node.go

@@ -1,6 +1,7 @@
 package node
 
 import (
+	"bytes"
 	"crypto/tls"
 	"encoding/json"
 	"io/ioutil"
@@ -25,6 +26,7 @@ import (
 	"github.com/docker/swarmkit/manager"
 	"github.com/docker/swarmkit/manager/encryption"
 	"github.com/docker/swarmkit/remotes"
+	"github.com/docker/swarmkit/watch"
 	"github.com/docker/swarmkit/xnet"
 	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
 	"github.com/pkg/errors"
@@ -129,7 +131,7 @@ type Node struct {
 	err              error
 	agent            *agent.Agent
 	manager          *manager.Manager
-	notifyNodeChange chan *api.Node // used to send role updates from the dispatcher api on promotion/demotion
+	notifyNodeChange chan *agent.NodeChanges // used by the agent to relay node updates from the dispatcher Session stream to (*Node).run
 	unlockKey        []byte
 }
 
@@ -172,7 +174,7 @@ func New(c *Config) (*Node, error) {
 		stopped:          make(chan struct{}),
 		closed:           make(chan struct{}),
 		ready:            make(chan struct{}),
-		notifyNodeChange: make(chan *api.Node, 1),
+		notifyNodeChange: make(chan *agent.NodeChanges, 1),
 		unlockKey:        c.UnlockKey,
 	}
 
@@ -235,7 +237,8 @@ func (n *Node) run(ctx context.Context) (err error) {
 		}
 	}(ctx)
 
-	securityConfig, err := n.loadSecurityConfig(ctx)
+	paths := ca.NewConfigPaths(filepath.Join(n.config.StateDir, certDirectory))
+	securityConfig, err := n.loadSecurityConfig(ctx, paths)
 	if err != nil {
 		return err
 	}
@@ -274,24 +277,44 @@ func (n *Node) run(ctx context.Context) (err error) {
 			select {
 			case <-agentDone:
 				return
-			case node := <-n.notifyNodeChange:
-				// If the server is sending us a ForceRenewal State, renew
-				if node.Certificate.Status.State == api.IssuanceStateRotate {
-					renewCert()
-					continue
-				}
+			case nodeChanges := <-n.notifyNodeChange:
 				n.Lock()
-				// If we got a role change, renew
-				role := ca.WorkerRole
-				if node.Role == api.NodeRoleManager {
-					role = ca.ManagerRole
+				currentRole := n.role
+				n.Unlock()
+
+				if nodeChanges.Node != nil {
+					role := ca.WorkerRole
+					if nodeChanges.Node.Role == api.NodeRoleManager {
+						role = ca.ManagerRole
+					}
+
+					// If the server is sending us a ForceRenewal State, or if the new node role doesn't match our current role, renew
+					if currentRole != role || nodeChanges.Node.Certificate.Status.State == api.IssuanceStateRotate {
+						renewCert()
+					}
 				}
-				if n.role == role {
-					n.Unlock()
-					continue
+
+				if nodeChanges.RootCert != nil {
+					// We only want to update the root CA if this is a worker node.  Manager nodes directly watch the raft
+					// store and update the root CA, with the necessary signer, from the raft store (since the managers
+					// need the CA key as well to potentially issue new TLS certificates).
+					if currentRole == ca.ManagerRole || bytes.Equal(nodeChanges.RootCert, securityConfig.RootCA().Certs) {
+						continue
+					}
+					newRootCA, err := ca.NewRootCA(nodeChanges.RootCert, nil, nil, ca.DefaultNodeCertExpiration, nil)
+					if err != nil {
+						log.G(ctx).WithError(err).Error("invalid new root certificate from the dispatcher")
+						continue
+					}
+					if err := ca.SaveRootCA(newRootCA, paths.RootCA); err != nil {
+						log.G(ctx).WithError(err).Error("could not save new root certificate from the dispatcher")
+						continue
+					}
+					if err := securityConfig.UpdateRootCA(&newRootCA, newRootCA.Pool); err != nil {
+						log.G(ctx).WithError(err).Error("could not use new root CA from dispatcher")
+						continue
+					}
 				}
-				n.Unlock()
-				renewCert()
 			}
 		}
 	}()
@@ -322,12 +345,12 @@ func (n *Node) run(ctx context.Context) (err error) {
 	var managerErr error
 	var agentErr error
 	go func() {
-		managerErr = n.superviseManager(ctx, securityConfig, managerReady, forceCertRenewal) // store err and loop
+		managerErr = n.superviseManager(ctx, securityConfig, paths.RootCA, managerReady, forceCertRenewal) // store err and loop
 		wg.Done()
 		cancel()
 	}()
 	go func() {
-		agentErr = n.runAgent(ctx, db, securityConfig.ClientTLSCreds, agentReady)
+		agentErr = n.runAgent(ctx, db, securityConfig, agentReady)
 		wg.Done()
 		cancel()
 		close(agentDone)
@@ -401,7 +424,7 @@ func (n *Node) Err(ctx context.Context) error {
 	}
 }
 
-func (n *Node) runAgent(ctx context.Context, db *bolt.DB, creds credentials.TransportCredentials, ready chan<- struct{}) error {
+func (n *Node) runAgent(ctx context.Context, db *bolt.DB, securityConfig *ca.SecurityConfig, ready chan<- struct{}) error {
 	waitCtx, waitCancel := context.WithCancel(ctx)
 	remotesCh := n.remotes.WaitSelect(ctx)
 	controlCh := n.ListenControlSocket(waitCtx)
@@ -428,13 +451,28 @@ waitPeer:
 	default:
 	}
 
+	secChangeQueue := watch.NewQueue()
+	defer secChangeQueue.Close()
+	secChangesCh, secChangesCancel := secChangeQueue.Watch()
+	defer secChangesCancel()
+	securityConfig.SetWatch(secChangeQueue)
+
+	rootCA := securityConfig.RootCA()
+	issuer := securityConfig.IssuerInfo()
+
 	a, err := agent.New(&agent.Config{
 		Hostname:         n.config.Hostname,
 		ConnBroker:       n.connBroker,
 		Executor:         n.config.Executor,
 		DB:               db,
 		NotifyNodeChange: n.notifyNodeChange,
-		Credentials:      creds,
+		NotifyTLSChange:  secChangesCh,
+		Credentials:      securityConfig.ClientTLSCreds,
+		NodeTLSInfo: &api.NodeTLSInfo{
+			TrustRoot:           rootCA.Certs,
+			CertIssuerPublicKey: issuer.PublicKey,
+			CertIssuerSubject:   issuer.Subject,
+		},
 	})
 	if err != nil {
 		return err
@@ -565,8 +603,7 @@ func (n *Node) Remotes() []api.Peer {
 	return remotes
 }
 
-func (n *Node) loadSecurityConfig(ctx context.Context) (*ca.SecurityConfig, error) {
-	paths := ca.NewConfigPaths(filepath.Join(n.config.StateDir, certDirectory))
+func (n *Node) loadSecurityConfig(ctx context.Context, paths *ca.SecurityConfigPaths) (*ca.SecurityConfig, error) {
 	var securityConfig *ca.SecurityConfig
 
 	krw := ca.NewKeyReadWriter(paths.Node, n.unlockKey, &manager.RaftDEKData{})
@@ -717,7 +754,7 @@ func (n *Node) waitRole(ctx context.Context, role string) error {
 	return nil
 }
 
-func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig, ready chan struct{}, workerRole <-chan struct{}) (bool, error) {
+func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig, rootPaths ca.CertPaths, ready chan struct{}, workerRole <-chan struct{}) (bool, error) {
 	var remoteAPI *manager.RemoteAddrs
 	if n.config.ListenRemoteAPI != "" {
 		remoteAPI = &manager.RemoteAddrs{
@@ -741,6 +778,7 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
 		UnlockKey:        n.unlockKey,
 		Availability:     n.config.Availability,
 		PluginGetter:     n.config.PluginGetter,
+		RootCAPaths:      rootPaths,
 	})
 	if err != nil {
 		return false, err
@@ -789,7 +827,7 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
 	return clearData, nil
 }
 
-func (n *Node) superviseManager(ctx context.Context, securityConfig *ca.SecurityConfig, ready chan struct{}, forceCertRenewal chan struct{}) error {
+func (n *Node) superviseManager(ctx context.Context, securityConfig *ca.SecurityConfig, rootPaths ca.CertPaths, ready chan struct{}, forceCertRenewal chan struct{}) error {
 	for {
 		if err := n.waitRole(ctx, ca.ManagerRole); err != nil {
 			return err
@@ -803,7 +841,7 @@ func (n *Node) superviseManager(ctx context.Context, securityConfig *ca.Security
 			}
 		}()
 
-		wasRemoved, err := n.runManager(ctx, securityConfig, ready, workerRole)
+		wasRemoved, err := n.runManager(ctx, securityConfig, rootPaths, ready, workerRole)
 		if err != nil {
 			waitRoleCancel()
 			return errors.Wrap(err, "manager stopped")

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff