瀏覽代碼

Merge pull request #32392 from aluzzardi/revendor-swarmkit

[master] Re-vendor docker/swarmkit to d2e48a332063ccd4ea26b6262ee717de997de560
Akihiro Suda 8 年之前
父節點
當前提交
2aed764baf
共有 45 個文件被更改,包括 5014 次插入1359 次删除
  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 {
 		if s.File != nil {
 			ref.Target = &swarmapi.SecretReference_File{
 			ref.Target = &swarmapi.SecretReference_File{
-				File: &swarmapi.SecretReference_FileTarget{
+				File: &swarmapi.FileTarget{
 					Name: s.File.Name,
 					Name: s.File.Name,
 					UID:  s.File.UID,
 					UID:  s.File.UID,
 					GID:  s.File.GID,
 					GID:  s.File.GID,

+ 1 - 1
vendor.conf

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

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

@@ -1,6 +1,7 @@
 package agent
 package agent
 
 
 import (
 import (
+	"bytes"
 	"fmt"
 	"fmt"
 	"math/rand"
 	"math/rand"
 	"reflect"
 	"reflect"
@@ -44,6 +45,8 @@ type Agent struct {
 	stopOnce  sync.Once     // only allow stop to be called once
 	stopOnce  sync.Once     // only allow stop to be called once
 	closed    chan struct{} // only closed in run
 	closed    chan struct{} // only closed in run
 	err       error         // read only after closed is closed
 	err       error         // read only after closed is closed
+
+	nodeUpdatePeriod time.Duration
 }
 }
 
 
 // New returns a new agent, ready for task dispatch.
 // New returns a new agent, ready for task dispatch.
@@ -53,14 +56,15 @@ func New(config *Config) (*Agent, error) {
 	}
 	}
 
 
 	a := &Agent{
 	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)
 	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")
 	log.G(ctx).Debug("(*Agent).run")
 	defer log.G(ctx).Debug("(*Agent).run exited")
 	defer log.G(ctx).Debug("(*Agent).run exited")
 
 
+	nodeTLSInfo := a.config.NodeTLSInfo
+
 	// get the node description
 	// get the node description
-	nodeDescription, err := a.nodeDescriptionWithHostname(ctx)
+	nodeDescription, err := a.nodeDescriptionWithHostname(ctx, nodeTLSInfo)
 	if err != nil {
 	if err != nil {
 		log.G(ctx).WithError(err).WithField("agent", a.config.Executor).Error("agent: node description unavailable")
 		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 is used to periodically check for updates to node description
-	nodeUpdateTicker := time.NewTicker(nodeUpdatePeriod)
+	nodeUpdateTicker := time.NewTicker(a.nodeUpdatePeriod)
 	defer nodeUpdateTicker.Stop()
 	defer nodeUpdateTicker.Stop()
 
 
 	var (
 	var (
@@ -214,6 +220,35 @@ func (a *Agent) run(ctx context.Context) {
 
 
 	a.worker.Listen(ctx, reporter)
 	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 {
 	for {
 		select {
 		select {
 		case operation := <-sessionq:
 		case operation := <-sessionq:
@@ -237,7 +272,8 @@ func (a *Agent) run(ctx context.Context) {
 
 
 			switch msg.Type {
 			switch msg.Type {
 			case api.AssignmentsMessage_COMPLETE:
 			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 {
 				if err := a.worker.Assign(ctx, msg.Changes); err != nil {
 					log.G(ctx).WithError(err).Error("failed to synchronize worker assignments")
 					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:
 		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")
 				log.G(ctx).WithError(err).Error("session message handler failed")
 			}
 			}
 		case sub := <-session.subscriptions:
 		case sub := <-session.subscriptions:
@@ -305,33 +341,17 @@ func (a *Agent) run(ctx context.Context) {
 			}
 			}
 			session = newSession(ctx, a, delay, session.sessionID, nodeDescription)
 			session = newSession(ctx, a, delay, session.sessionID, nodeDescription)
 			registered = session.registered
 			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:
 		case <-a.stopped:
 			// TODO(stevvooe): Wait on shutdown and cleanup. May need to pump
 			// TODO(stevvooe): Wait on shutdown and cleanup. May need to pump
 			// this loop a few times.
 			// 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{}{}
 	seen := map[api.Peer]struct{}{}
 	for _, manager := range message.Managers {
 	for _, manager := range message.Managers {
 		if manager.Peer.Addr == "" {
 		if manager.Peer.Addr == "" {
@@ -358,18 +378,28 @@ func (a *Agent) handleSessionMessage(ctx context.Context, message *api.SessionMe
 		seen[*manager.Peer] = struct{}{}
 		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.
 	// prune managers not in list.
 	for peer := range a.config.ConnBroker.Remotes().Weights() {
 	for peer := range a.config.ConnBroker.Remotes().Weights() {
 		if _, ok := seen[peer]; !ok {
 		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
 // 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)
 	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
 	return desc, err
 }
 }

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

@@ -2,6 +2,7 @@ package agent
 
 
 import (
 import (
 	"github.com/boltdb/bolt"
 	"github.com/boltdb/bolt"
+	"github.com/docker/go-events"
 	"github.com/docker/swarmkit/agent/exec"
 	"github.com/docker/swarmkit/agent/exec"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/connectionbroker"
 	"github.com/docker/swarmkit/connectionbroker"
@@ -9,6 +10,13 @@ import (
 	"google.golang.org/grpc/credentials"
 	"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.
 // Config provides values for an Agent.
 type Config struct {
 type Config struct {
 	// Hostname the name of host for agent instance.
 	// Hostname the name of host for agent instance.
@@ -25,10 +33,16 @@ type Config struct {
 	DB *bolt.DB
 	DB *bolt.DB
 
 
 	// NotifyNodeChange channel receives new node changes from session messages.
 	// 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 is credentials for grpc connection to manager.
 	Credentials credentials.TransportCredentials
 	Credentials credentials.TransportCredentials
+
+	// NodeTLSInfo contains the starting node TLS info to bootstrap into the agent
+	NodeTLSInfo *api.NodeTLSInfo
 }
 }
 
 
 func (c *Config) validate() error {
 func (c *Config) validate() error {
@@ -44,5 +58,9 @@ func (c *Config) validate() error {
 		return errors.New("agent: database required")
 		return errors.New("agent: database required")
 	}
 	}
 
 
+	if c.NodeTLSInfo == nil {
+		return errors.New("agent: Node TLS info is required")
+	}
+
 	return nil
 	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
 	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.
 // SecretGetter contains secret data necessary for the Controller.
 type SecretGetter interface {
 type SecretGetter interface {
 	// Get returns the the secret with a specific secret ID, if available.
 	// 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
 	Remove(secrets []string)   // remove the secrets by ID
 	Reset()                    // remove all secrets
 	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.
 	// It is not safe to call any worker function after that.
 	Close()
 	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
 	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
 	Update(ctx context.Context, assignments []*api.AssignmentChange) error
 
 
 	// Listen to updates about tasks controlled by the worker. When first
 	// Listen to updates about tasks controlled by the worker. When first
@@ -119,11 +120,11 @@ func (w *worker) Close() {
 	w.taskevents.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
 // 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
 // and already running will be updated, if possible. Any tasks currently running on
 // the worker outside the task set will be terminated.
 // 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 {
 func (w *worker) Assign(ctx context.Context, assignments []*api.AssignmentChange) error {
 	w.mu.Lock()
 	w.mu.Lock()
 	defer w.mu.Unlock()
 	defer w.mu.Unlock()
@@ -136,20 +137,28 @@ func (w *worker) Assign(ctx context.Context, assignments []*api.AssignmentChange
 		"len(assignments)": len(assignments),
 		"len(assignments)": len(assignments),
 	}).Debug("(*worker).Assign")
 	}).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)
 	err := reconcileSecrets(ctx, w, assignments, true)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	err = reconcileConfigs(ctx, w, assignments, true)
+	if err != nil {
+		return err
+	}
+
 	return reconcileTaskState(ctx, w, assignments, true)
 	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
 // Tasks in the added set will be added to the worker, and tasks in the removed set
 // will be removed from the worker
 // will be removed from the worker
 // Secrets in the added set will be added to the worker, and secrets in the removed set
 // Secrets in the added set will be added to the worker, and secrets in the removed set
 // will be removed from the worker.
 // 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 {
 func (w *worker) Update(ctx context.Context, assignments []*api.AssignmentChange) error {
 	w.mu.Lock()
 	w.mu.Lock()
 	defer w.mu.Unlock()
 	defer w.mu.Unlock()
@@ -167,6 +176,11 @@ func (w *worker) Update(ctx context.Context, assignments []*api.AssignmentChange
 		return err
 		return err
 	}
 	}
 
 
+	err = reconcileConfigs(ctx, w, assignments, false)
+	if err != nil {
+		return err
+	}
+
 	return reconcileTaskState(ctx, w, assignments, false)
 	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 !ok {
 		if len(updatedSecrets) != 0 || len(removedSecrets) != 0 {
 		if len(updatedSecrets) != 0 || len(removedSecrets) != 0 {
 			log.G(ctx).Warn("secrets update ignored; executor does not support secrets")
 			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
 		return nil
 	}
 	}
 
 
-	secrets := provider.Secrets()
+	secrets := secretsProvider.Secrets()
 
 
 	log.G(ctx).WithFields(logrus.Fields{
 	log.G(ctx).WithFields(logrus.Fields{
 		"len(updatedSecrets)": len(updatedSecrets),
 		"len(updatedSecrets)": len(updatedSecrets),
@@ -344,6 +358,49 @@ func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.Assignm
 	return nil
 	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) {
 func (w *worker) Listen(ctx context.Context, reporter StatusReporter) {
 	w.mu.Lock()
 	w.mu.Lock()
 	defer w.mu.Unlock()
 	defer w.mu.Unlock()

文件差異過大導致無法顯示
+ 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" };
 		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
 	// managed, or all secrets matching any name in `ListSecretsRequest.Names`, any
 	// name prefix in `ListSecretsRequest.NamePrefixes`, any id in
 	// name prefix in `ListSecretsRequest.NamePrefixes`, any id in
 	// `ListSecretsRequest.SecretIDs`, or any id prefix in `ListSecretsRequest.IDPrefixes`.
 	// `ListSecretsRequest.SecretIDs`, or any id prefix in `ListSecretsRequest.IDPrefixes`.
@@ -116,6 +116,51 @@ service Control {
 	rpc RemoveSecret(RemoveSecretRequest) returns (RemoveSecretResponse) {
 	rpc RemoveSecret(RemoveSecretRequest) returns (RemoveSecretResponse) {
 		option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-manager" };
 		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 {
 message GetNodeRequest {
@@ -396,7 +441,6 @@ message UpdateSecretResponse {
 	Secret secret = 1;
 	Secret secret = 1;
 }
 }
 
 
-
 // ListSecretRequest is the request to list all non-internal secrets in the secret store,
 // 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.
 // or all secrets filtered by (name or name prefix or id prefix) and labels.
 message ListSecretsRequest {
 message ListSecretsRequest {
@@ -424,7 +468,7 @@ message CreateSecretRequest {
 	SecretSpec spec = 1;
 	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
 // name in `CreateSecretRequest`.  The `Secret.Spec.Data` field should be nil instead
 // of actually containing the secret bytes.
 // of actually containing the secret bytes.
 message CreateSecretResponse {
 message CreateSecretResponse {
@@ -440,3 +484,71 @@ message RemoveSecretRequest {
 // RemoveSecretResponse is an empty object indicating the successful removal of
 // RemoveSecretResponse is an empty object indicating the successful removal of
 // a secret.
 // a secret.
 message RemoveSecretResponse {}
 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{},
 		Resources: &api.ResourceRequirements{},
 		Restart: &api.RestartPolicy{
 		Restart: &api.RestartPolicy{
-			Delay: gogotypes.DurationProto(5 * time.Second),
+			Condition: api.RestartOnAny,
+			Delay:     gogotypes.DurationProto(5 * time.Second),
 		},
 		},
 		Placement: &api.Placement{},
 		Placement: &api.Placement{},
 	},
 	},
@@ -31,6 +32,12 @@ var Service = api.ServiceSpec{
 		Parallelism:   1,
 		Parallelism:   1,
 		Order:         api.UpdateConfig_STOP_FIRST,
 		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
 // 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
 	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
 	// Symmetric encryption key distributed by the lead manager. Used by agents
 	// for securing network bootstrapping and communication.
 	// for securing network bootstrapping and communication.
 	NetworkBootstrapKeys []*EncryptionKey `protobuf:"bytes,4,rep,name=network_bootstrap_keys,json=networkBootstrapKeys" json:"network_bootstrap_keys,omitempty"`
 	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{} }
 func (m *SessionMessage) Reset()                    { *m = SessionMessage{} }
@@ -244,6 +246,7 @@ type Assignment struct {
 	// Types that are valid to be assigned to Item:
 	// Types that are valid to be assigned to Item:
 	//	*Assignment_Task
 	//	*Assignment_Task
 	//	*Assignment_Secret
 	//	*Assignment_Secret
+	//	*Assignment_Config
 	Item isAssignment_Item `protobuf_oneof:"item"`
 	Item isAssignment_Item `protobuf_oneof:"item"`
 }
 }
 
 
@@ -263,9 +266,13 @@ type Assignment_Task struct {
 type Assignment_Secret struct {
 type Assignment_Secret struct {
 	Secret *Secret `protobuf:"bytes,2,opt,name=secret,oneof"`
 	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_Task) isAssignment_Item()   {}
 func (*Assignment_Secret) isAssignment_Item() {}
 func (*Assignment_Secret) isAssignment_Item() {}
+func (*Assignment_Config) isAssignment_Item() {}
 
 
 func (m *Assignment) GetItem() isAssignment_Item {
 func (m *Assignment) GetItem() isAssignment_Item {
 	if m != nil {
 	if m != nil {
@@ -288,11 +295,19 @@ func (m *Assignment) GetSecret() *Secret {
 	return nil
 	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.
 // 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{}) {
 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{}{
 	return _Assignment_OneofMarshaler, _Assignment_OneofUnmarshaler, _Assignment_OneofSizer, []interface{}{
 		(*Assignment_Task)(nil),
 		(*Assignment_Task)(nil),
 		(*Assignment_Secret)(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 {
 		if err := b.EncodeMessage(x.Secret); err != nil {
 			return err
 			return err
 		}
 		}
+	case *Assignment_Config:
+		_ = b.EncodeVarint(3<<3 | proto.WireBytes)
+		if err := b.EncodeMessage(x.Config); err != nil {
+			return err
+		}
 	case nil:
 	case nil:
 	default:
 	default:
 		return fmt.Errorf("Assignment.Item has unexpected type %T", x)
 		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)
 		err := b.DecodeMessage(msg)
 		m.Item = &Assignment_Secret{msg}
 		m.Item = &Assignment_Secret{msg}
 		return true, err
 		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:
 	default:
 		return false, nil
 		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(2<<3 | proto.WireBytes)
 		n += proto.SizeVarint(uint64(s))
 		n += proto.SizeVarint(uint64(s))
 		n += 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:
 	case nil:
 	default:
 	default:
 		panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
 		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 {
 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())
 			github_com_docker_swarmkit_api_deepcopy.Copy(v.Secret, o.GetSecret())
 			m.Item = &v
 			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
 			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
 	return i, nil
 }
 }
 
 
@@ -1420,6 +1469,20 @@ func (m *Assignment_Secret) MarshalTo(dAtA []byte) (int, error) {
 	}
 	}
 	return i, nil
 	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) {
 func (m *AssignmentChange) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	size := m.Size()
 	dAtA = make([]byte, size)
 	dAtA = make([]byte, size)
@@ -1439,11 +1502,11 @@ func (m *AssignmentChange) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0xa
 		dAtA[i] = 0xa
 		i++
 		i++
 		i = encodeVarintDispatcher(dAtA, i, uint64(m.Assignment.Size()))
 		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 {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n8
+		i += n9
 	}
 	}
 	if m.Action != 0 {
 	if m.Action != 0 {
 		dAtA[i] = 0x10
 		dAtA[i] = 0x10
@@ -1860,6 +1923,10 @@ func (m *SessionMessage) Size() (n int) {
 			n += 1 + l + sovDispatcher(uint64(l))
 			n += 1 + l + sovDispatcher(uint64(l))
 		}
 		}
 	}
 	}
+	l = len(m.RootCA)
+	if l > 0 {
+		n += 1 + l + sovDispatcher(uint64(l))
+	}
 	return n
 	return n
 }
 }
 
 
@@ -1976,6 +2043,15 @@ func (m *Assignment_Secret) Size() (n int) {
 	}
 	}
 	return n
 	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) {
 func (m *AssignmentChange) Size() (n int) {
 	var l int
 	var l int
 	_ = l
 	_ = l
@@ -2045,6 +2121,7 @@ func (this *SessionMessage) String() string {
 		`Node:` + strings.Replace(fmt.Sprintf("%v", this.Node), "Node", "Node", 1) + `,`,
 		`Node:` + strings.Replace(fmt.Sprintf("%v", this.Node), "Node", "Node", 1) + `,`,
 		`Managers:` + strings.Replace(fmt.Sprintf("%v", this.Managers), "WeightedPeer", "WeightedPeer", 1) + `,`,
 		`Managers:` + strings.Replace(fmt.Sprintf("%v", this.Managers), "WeightedPeer", "WeightedPeer", 1) + `,`,
 		`NetworkBootstrapKeys:` + strings.Replace(fmt.Sprintf("%v", this.NetworkBootstrapKeys), "EncryptionKey", "EncryptionKey", 1) + `,`,
 		`NetworkBootstrapKeys:` + strings.Replace(fmt.Sprintf("%v", this.NetworkBootstrapKeys), "EncryptionKey", "EncryptionKey", 1) + `,`,
+		`RootCA:` + fmt.Sprintf("%v", this.RootCA) + `,`,
 		`}`,
 		`}`,
 	}, "")
 	}, "")
 	return s
 	return s
@@ -2160,6 +2237,16 @@ func (this *Assignment_Secret) String() string {
 	}, "")
 	}, "")
 	return s
 	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 {
 func (this *AssignmentChange) String() string {
 	if this == nil {
 	if this == nil {
 		return "nil"
 		return "nil"
@@ -2457,6 +2544,37 @@ func (m *SessionMessage) Unmarshal(dAtA []byte) error {
 				return err
 				return err
 			}
 			}
 			iNdEx = postIndex
 			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:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
 			skippy, err := skipDispatcher(dAtA[iNdEx:])
 			skippy, err := skipDispatcher(dAtA[iNdEx:])
@@ -3241,6 +3359,38 @@ func (m *Assignment) Unmarshal(dAtA []byte) error {
 			}
 			}
 			m.Item = &Assignment_Secret{v}
 			m.Item = &Assignment_Secret{v}
 			iNdEx = postIndex
 			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:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
 			skippy, err := skipDispatcher(dAtA[iNdEx:])
 			skippy, err := skipDispatcher(dAtA[iNdEx:])
@@ -3630,65 +3780,67 @@ var (
 func init() { proto.RegisterFile("dispatcher.proto", fileDescriptorDispatcher) }
 func init() { proto.RegisterFile("dispatcher.proto", fileDescriptorDispatcher) }
 
 
 var fileDescriptorDispatcher = []byte{
 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
 	// Symmetric encryption key distributed by the lead manager. Used by agents
 	// for securing network bootstrapping and communication.
 	// for securing network bootstrapping and communication.
 	repeated EncryptionKey network_bootstrap_keys = 4;
 	repeated EncryptionKey network_bootstrap_keys = 4;
+
+	// Which root certificates to trust
+	bytes RootCA = 5;
 }
 }
 
 
 // HeartbeatRequest provides identifying properties for a single heartbeat.
 // HeartbeatRequest provides identifying properties for a single heartbeat.
@@ -174,6 +177,7 @@ message Assignment {
 	oneof item {
 	oneof item {
 		Task task = 1;
 		Task task = 1;
 		Secret secret = 2;
 		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} }
 func (*Cluster) Descriptor() ([]byte, []int) { return fileDescriptorObjects, []int{7} }
 
 
 // Secret represents a secret that should be passed to a container or a node,
 // 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 {
 type Secret struct {
 	ID   string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
 	ID   string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
 	Meta Meta   `protobuf:"bytes,2,opt,name=meta" json:"meta"`
 	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) ProtoMessage()               {}
 func (*Secret) Descriptor() ([]byte, []int) { return fileDescriptorObjects, []int{8} }
 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.
 // Resource is a top-level object with externally defined content and indexing.
 // SwarmKit can serve as a store for these objects without understanding their
 // SwarmKit can serve as a store for these objects without understanding their
 // meanings.
 // meanings.
@@ -304,7 +316,7 @@ type Resource struct {
 
 
 func (m *Resource) Reset()                    { *m = Resource{} }
 func (m *Resource) Reset()                    { *m = Resource{} }
 func (*Resource) ProtoMessage()               {}
 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
 // Extension declares a type of "resource" object. This message provides some
 // metadata about the objects.
 // metadata about the objects.
@@ -317,7 +329,7 @@ type Extension struct {
 
 
 func (m *Extension) Reset()                    { *m = Extension{} }
 func (m *Extension) Reset()                    { *m = Extension{} }
 func (*Extension) ProtoMessage()               {}
 func (*Extension) ProtoMessage()               {}
-func (*Extension) Descriptor() ([]byte, []int) { return fileDescriptorObjects, []int{10} }
+func (*Extension) Descriptor() ([]byte, []int) { return fileDescriptorObjects, []int{11} }
 
 
 func init() {
 func init() {
 	proto.RegisterType((*Meta)(nil), "docker.swarmkit.v1.Meta")
 	proto.RegisterType((*Meta)(nil), "docker.swarmkit.v1.Meta")
@@ -330,6 +342,7 @@ func init() {
 	proto.RegisterType((*Network)(nil), "docker.swarmkit.v1.Network")
 	proto.RegisterType((*Network)(nil), "docker.swarmkit.v1.Network")
 	proto.RegisterType((*Cluster)(nil), "docker.swarmkit.v1.Cluster")
 	proto.RegisterType((*Cluster)(nil), "docker.swarmkit.v1.Cluster")
 	proto.RegisterType((*Secret)(nil), "docker.swarmkit.v1.Secret")
 	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((*Resource)(nil), "docker.swarmkit.v1.Resource")
 	proto.RegisterType((*Extension)(nil), "docker.swarmkit.v1.Extension")
 	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)
 	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 {
 func (m *Resource) Copy() *Resource {
 	if m == nil {
 	if m == nil {
 		return nil
 		return nil
@@ -1377,7 +1407,7 @@ func (m *Secret) MarshalTo(dAtA []byte) (int, error) {
 	return i, nil
 	return i, nil
 }
 }
 
 
-func (m *Resource) Marshal() (dAtA []byte, err error) {
+func (m *Config) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	size := m.Size()
 	dAtA = make([]byte, size)
 	dAtA = make([]byte, size)
 	n, err := m.MarshalTo(dAtA)
 	n, err := m.MarshalTo(dAtA)
@@ -1387,7 +1417,7 @@ func (m *Resource) Marshal() (dAtA []byte, err error) {
 	return dAtA[:n], nil
 	return dAtA[:n], nil
 }
 }
 
 
-func (m *Resource) MarshalTo(dAtA []byte) (int, error) {
+func (m *Config) MarshalTo(dAtA []byte) (int, error) {
 	var i int
 	var i int
 	_ = i
 	_ = i
 	var l int
 	var l int
@@ -1408,12 +1438,52 @@ func (m *Resource) MarshalTo(dAtA []byte) (int, error) {
 	i += n38
 	i += n38
 	dAtA[i] = 0x1a
 	dAtA[i] = 0x1a
 	i++
 	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 {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
 	i += n39
 	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 {
 	if len(m.Kind) > 0 {
 		dAtA[i] = 0x22
 		dAtA[i] = 0x22
 		i++
 		i++
@@ -1424,11 +1494,11 @@ func (m *Resource) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x2a
 		dAtA[i] = 0x2a
 		i++
 		i++
 		i = encodeVarintObjects(dAtA, i, uint64(m.Payload.Size()))
 		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 {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n40
+		i += n42
 	}
 	}
 	return i, nil
 	return i, nil
 }
 }
@@ -1457,19 +1527,19 @@ func (m *Extension) MarshalTo(dAtA []byte) (int, error) {
 	dAtA[i] = 0x12
 	dAtA[i] = 0x12
 	i++
 	i++
 	i = encodeVarintObjects(dAtA, i, uint64(m.Meta.Size()))
 	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 {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
-	i += n41
+	i += n43
 	dAtA[i] = 0x1a
 	dAtA[i] = 0x1a
 	i++
 	i++
 	i = encodeVarintObjects(dAtA, i, uint64(m.Annotations.Size()))
 	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 {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
-	i += n42
+	i += n44
 	if len(m.Description) > 0 {
 	if len(m.Description) > 0 {
 		dAtA[i] = 0x22
 		dAtA[i] = 0x22
 		i++
 		i++
@@ -1783,6 +1853,20 @@ func (m *Secret) Size() (n int) {
 	return n
 	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) {
 func (m *Resource) Size() (n int) {
 	var l int
 	var l int
 	_ = l
 	_ = l
@@ -3212,6 +3296,223 @@ func (indexer SecretCustomIndexer) FromObject(obj interface{}) (bool, [][]byte,
 	return customIndexer("", &m.Spec.Annotations)
 	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 ResourceCheckFunc func(t1, t2 *Resource) bool
 
 
 type EventCreateResource struct {
 type EventCreateResource struct {
@@ -3708,6 +4009,15 @@ func NewStoreAction(c Event) (StoreAction, error) {
 	case EventDeleteSecret:
 	case EventDeleteSecret:
 		sa.Action = StoreActionKindRemove
 		sa.Action = StoreActionKindRemove
 		sa.Target = &StoreAction_Secret{Secret: v.Secret}
 		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:
 	case EventCreateResource:
 		sa.Action = StoreActionKindCreate
 		sa.Action = StoreActionKindCreate
 		sa.Target = &StoreAction_Resource{Resource: v.Resource}
 		sa.Target = &StoreAction_Resource{Resource: v.Resource}
@@ -3812,6 +4122,19 @@ func EventFromStoreAction(sa StoreAction, oldObject StoreObject) (Event, error)
 		case StoreActionKindRemove:
 		case StoreActionKindRemove:
 			return EventDeleteSecret{Secret: v.Secret}, nil
 			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:
 	case *StoreAction_Resource:
 		switch sa.Action {
 		switch sa.Action {
 		case StoreActionKindCreate:
 		case StoreActionKindCreate:
@@ -3904,6 +4227,16 @@ func WatchMessageEvent(c Event) *WatchMessage_Event {
 		}
 		}
 	case EventDeleteSecret:
 	case EventDeleteSecret:
 		return &WatchMessage_Event{Action: WatchActionKindRemove, Object: &Object{Object: &Object_Secret{Secret: v.Secret}}}
 		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:
 	case EventCreateResource:
 		return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_Resource{Resource: v.Resource}}}
 		return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_Resource{Resource: v.Resource}}}
 	case EventUpdateResource:
 	case EventUpdateResource:
@@ -3948,6 +4281,8 @@ func ConvertWatchArgs(entries []*WatchRequest_WatchEntry) ([]Event, error) {
 			newEvents, err = ConvertClusterWatch(entry.Action, entry.Filters)
 			newEvents, err = ConvertClusterWatch(entry.Action, entry.Filters)
 		case "secret":
 		case "secret":
 			newEvents, err = ConvertSecretWatch(entry.Action, entry.Filters)
 			newEvents, err = ConvertSecretWatch(entry.Action, entry.Filters)
+		case "config":
+			newEvents, err = ConvertConfigWatch(entry.Action, entry.Filters)
 		default:
 		default:
 			newEvents, err = ConvertResourceWatch(entry.Action, entry.Filters, entry.Kind)
 			newEvents, err = ConvertResourceWatch(entry.Action, entry.Filters, entry.Kind)
 		case "extension":
 		case "extension":
@@ -4120,6 +4455,18 @@ func (this *Secret) String() string {
 	}, "")
 	}, "")
 	return s
 	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 {
 func (this *Resource) String() string {
 	if this == nil {
 	if this == nil {
 		return "nil"
 		return "nil"
@@ -6506,6 +6853,145 @@ func (m *Secret) Unmarshal(dAtA []byte) error {
 	}
 	}
 	return nil
 	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 {
 func (m *Resource) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	l := len(dAtA)
 	iNdEx := 0
 	iNdEx := 0
@@ -6983,92 +7469,93 @@ var (
 func init() { proto.RegisterFile("objects.proto", fileDescriptorObjects) }
 func init() { proto.RegisterFile("objects.proto", fileDescriptorObjects) }
 
 
 var fileDescriptorObjects = []byte{
 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,
 	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,
 // 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 {
 message Secret {
 	option (docker.protobuf.plugin.store_object) = {
 	option (docker.protobuf.plugin.store_object) = {
 		watch_selectors: {
 		watch_selectors: {
@@ -355,6 +353,29 @@ message Secret {
 	bool internal = 4;
 	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.
 // Resource is a top-level object with externally defined content and indexing.
 // SwarmKit can serve as a store for these objects without understanding their
 // SwarmKit can serve as a store for these objects without understanding their
 // meanings.
 // meanings.

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

@@ -175,6 +175,7 @@ type StoreAction struct {
 	//	*StoreAction_Secret
 	//	*StoreAction_Secret
 	//	*StoreAction_Resource
 	//	*StoreAction_Resource
 	//	*StoreAction_Extension
 	//	*StoreAction_Extension
+	//	*StoreAction_Config
 	Target isStoreAction_Target `protobuf_oneof:"target"`
 	Target isStoreAction_Target `protobuf_oneof:"target"`
 }
 }
 
 
@@ -212,6 +213,9 @@ type StoreAction_Resource struct {
 type StoreAction_Extension struct {
 type StoreAction_Extension struct {
 	Extension *Extension `protobuf:"bytes,9,opt,name=extension,oneof"`
 	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_Node) isStoreAction_Target()      {}
 func (*StoreAction_Service) isStoreAction_Target()   {}
 func (*StoreAction_Service) isStoreAction_Target()   {}
@@ -221,6 +225,7 @@ func (*StoreAction_Cluster) isStoreAction_Target()   {}
 func (*StoreAction_Secret) isStoreAction_Target()    {}
 func (*StoreAction_Secret) isStoreAction_Target()    {}
 func (*StoreAction_Resource) isStoreAction_Target()  {}
 func (*StoreAction_Resource) isStoreAction_Target()  {}
 func (*StoreAction_Extension) isStoreAction_Target() {}
 func (*StoreAction_Extension) isStoreAction_Target() {}
+func (*StoreAction_Config) isStoreAction_Target()    {}
 
 
 func (m *StoreAction) GetTarget() isStoreAction_Target {
 func (m *StoreAction) GetTarget() isStoreAction_Target {
 	if m != nil {
 	if m != nil {
@@ -285,6 +290,13 @@ func (m *StoreAction) GetExtension() *Extension {
 	return nil
 	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.
 // 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{}) {
 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{}{
 	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_Secret)(nil),
 		(*StoreAction_Resource)(nil),
 		(*StoreAction_Resource)(nil),
 		(*StoreAction_Extension)(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 {
 		if err := b.EncodeMessage(x.Extension); err != nil {
 			return err
 			return err
 		}
 		}
+	case *StoreAction_Config:
+		_ = b.EncodeVarint(10<<3 | proto.WireBytes)
+		if err := b.EncodeMessage(x.Config); err != nil {
+			return err
+		}
 	case nil:
 	case nil:
 	default:
 	default:
 		return fmt.Errorf("StoreAction.Target has unexpected type %T", x)
 		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)
 		err := b.DecodeMessage(msg)
 		m.Target = &StoreAction_Extension{msg}
 		m.Target = &StoreAction_Extension{msg}
 		return true, err
 		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:
 	default:
 		return false, nil
 		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(9<<3 | proto.WireBytes)
 		n += proto.SizeVarint(uint64(s))
 		n += proto.SizeVarint(uint64(s))
 		n += 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:
 	case nil:
 	default:
 	default:
 		panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
 		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())
 			github_com_docker_swarmkit_api_deepcopy.Copy(v.Extension, o.GetExtension())
 			m.Target = &v
 			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
 	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 {
 func encodeFixed64Raft(dAtA []byte, offset int, v uint64) int {
 	dAtA[offset] = uint8(v)
 	dAtA[offset] = uint8(v)
 	dAtA[offset+1] = uint8(v >> 8)
 	dAtA[offset+1] = uint8(v >> 8)
@@ -1922,6 +1973,15 @@ func (m *StoreAction_Extension) Size() (n int) {
 	}
 	}
 	return n
 	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) {
 func sovRaft(x uint64) (n int) {
 	for {
 	for {
@@ -2131,6 +2191,16 @@ func (this *StoreAction_Extension) String() string {
 	}, "")
 	}, "")
 	return s
 	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 {
 func valueToStringRaft(v interface{}) string {
 	rv := reflect.ValueOf(v)
 	rv := reflect.ValueOf(v)
 	if rv.IsNil() {
 	if rv.IsNil() {
@@ -3355,6 +3425,38 @@ func (m *StoreAction) Unmarshal(dAtA []byte) error {
 			}
 			}
 			m.Target = &StoreAction_Extension{v}
 			m.Target = &StoreAction_Extension{v}
 			iNdEx = postIndex
 			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:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
 			skippy, err := skipRaft(dAtA[iNdEx:])
 			skippy, err := skipRaft(dAtA[iNdEx:])
@@ -3484,64 +3586,65 @@ var (
 func init() { proto.RegisterFile("raft.proto", fileDescriptorRaft) }
 func init() { proto.RegisterFile("raft.proto", fileDescriptorRaft) }
 
 
 var fileDescriptorRaft = []byte{
 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;
 		Secret secret = 7;
 		Resource resource = 8;
 		Resource resource = 8;
 		Extension extension = 9;
 		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"`
 	Secrets    []*Secret    `protobuf:"bytes,6,rep,name=secrets" json:"secrets,omitempty"`
 	Resources  []*Resource  `protobuf:"bytes,7,rep,name=resources" json:"resources,omitempty"`
 	Resources  []*Resource  `protobuf:"bytes,7,rep,name=resources" json:"resources,omitempty"`
 	Extensions []*Extension `protobuf:"bytes,8,rep,name=extensions" json:"extensions,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{} }
 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 {
 func (m *ClusterSnapshot) Copy() *ClusterSnapshot {
@@ -319,6 +328,18 @@ func (m *StoreSnapshot) MarshalTo(dAtA []byte) (int, error) {
 			i += n
 			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
 	return i, nil
 }
 }
 
 
@@ -487,6 +508,12 @@ func (m *StoreSnapshot) Size() (n int) {
 			n += 1 + l + sovSnapshot(uint64(l))
 			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
 	return n
 }
 }
 
 
@@ -548,6 +575,7 @@ func (this *StoreSnapshot) String() string {
 		`Secrets:` + strings.Replace(fmt.Sprintf("%v", this.Secrets), "Secret", "Secret", 1) + `,`,
 		`Secrets:` + strings.Replace(fmt.Sprintf("%v", this.Secrets), "Secret", "Secret", 1) + `,`,
 		`Resources:` + strings.Replace(fmt.Sprintf("%v", this.Resources), "Resource", "Resource", 1) + `,`,
 		`Resources:` + strings.Replace(fmt.Sprintf("%v", this.Resources), "Resource", "Resource", 1) + `,`,
 		`Extensions:` + strings.Replace(fmt.Sprintf("%v", this.Extensions), "Extension", "Extension", 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
 	return s
@@ -860,6 +888,37 @@ func (m *StoreSnapshot) Unmarshal(dAtA []byte) error {
 				return err
 				return err
 			}
 			}
 			iNdEx = postIndex
 			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:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
 			skippy, err := skipSnapshot(dAtA[iNdEx:])
 			skippy, err := skipSnapshot(dAtA[iNdEx:])
@@ -1261,34 +1320,35 @@ var (
 func init() { proto.RegisterFile("snapshot.proto", fileDescriptorSnapshot) }
 func init() { proto.RegisterFile("snapshot.proto", fileDescriptorSnapshot) }
 
 
 var fileDescriptorSnapshot = []byte{
 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 Secret secrets = 6;
 	repeated Resource resources = 7;
 	repeated Resource resources = 7;
 	repeated Extension extensions = 8;
 	repeated Extension extensions = 8;
+	repeated Config configs = 9;
 }
 }
 
 
 // ClusterSnapshot stores cluster membership information in snapshots.
 // 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"`
 	User string `protobuf:"bytes,7,opt,name=user,proto3" json:"user,omitempty"`
 	// Groups specifies supplementary groups available to the user.
 	// Groups specifies supplementary groups available to the user.
 	Groups []string `protobuf:"bytes,11,rep,name=groups" json:"groups,omitempty"`
 	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,
 	// TTY declares that a TTY should be attached to the standard streams,
 	// including stdin if it is still open.
 	// including stdin if it is still open.
 	TTY bool `protobuf:"varint,13,opt,name=tty,proto3" json:"tty,omitempty"`
 	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
 	// SecretReference contains references to zero or more secrets that
 	// will be exposed to the container.
 	// will be exposed to the container.
 	Secrets []*SecretReference `protobuf:"bytes,12,rep,name=secrets" json:"secrets,omitempty"`
 	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
 	// Hosts allow additional entries to be specified in /etc/hosts
 	// that associates IP addresses with hostnames.
 	// that associates IP addresses with hostnames.
 	// Detailed documentation is available in:
 	// Detailed documentation is available in:
@@ -679,6 +684,19 @@ func (m *SecretSpec) Reset()                    { *m = SecretSpec{} }
 func (*SecretSpec) ProtoMessage()               {}
 func (*SecretSpec) ProtoMessage()               {}
 func (*SecretSpec) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{11} }
 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() {
 func init() {
 	proto.RegisterType((*NodeSpec)(nil), "docker.swarmkit.v1.NodeSpec")
 	proto.RegisterType((*NodeSpec)(nil), "docker.swarmkit.v1.NodeSpec")
 	proto.RegisterType((*ServiceSpec)(nil), "docker.swarmkit.v1.ServiceSpec")
 	proto.RegisterType((*ServiceSpec)(nil), "docker.swarmkit.v1.ServiceSpec")
@@ -694,6 +712,7 @@ func init() {
 	proto.RegisterType((*NetworkSpec)(nil), "docker.swarmkit.v1.NetworkSpec")
 	proto.RegisterType((*NetworkSpec)(nil), "docker.swarmkit.v1.NetworkSpec")
 	proto.RegisterType((*ClusterSpec)(nil), "docker.swarmkit.v1.ClusterSpec")
 	proto.RegisterType((*ClusterSpec)(nil), "docker.swarmkit.v1.ClusterSpec")
 	proto.RegisterType((*SecretSpec)(nil), "docker.swarmkit.v1.SecretSpec")
 	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_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.NodeSpec_Availability", NodeSpec_Availability_name, NodeSpec_Availability_value)
 	proto.RegisterEnum("docker.swarmkit.v1.EndpointSpec_ResolutionMode", EndpointSpec_ResolutionMode_name, EndpointSpec_ResolutionMode_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)
 		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 {
 	if o.Mounts != nil {
 		m.Mounts = make([]Mount, len(o.Mounts))
 		m.Mounts = make([]Mount, len(o.Mounts))
 		for i := range m.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 {
 	if o.Hosts != nil {
 		m.Hosts = make([]string, len(o.Hosts))
 		m.Hosts = make([]string, len(o.Hosts))
 		copy(m.Hosts, 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) {
 func (m *NodeSpec) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	size := m.Size()
 	dAtA = make([]byte, 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 = encodeVarintSpecs(dAtA, i, uint64(len(m.StopSignal)))
 		i += copy(dAtA[i:], 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
 	return i, nil
 }
 }
 
 
@@ -1864,20 +1941,20 @@ func (m *NetworkSpec) MarshalTo(dAtA []byte) (int, error) {
 	dAtA[i] = 0xa
 	dAtA[i] = 0xa
 	i++
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.Annotations.Size()))
 	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 {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
-	i += n23
+	i += n24
 	if m.DriverConfig != nil {
 	if m.DriverConfig != nil {
 		dAtA[i] = 0x12
 		dAtA[i] = 0x12
 		i++
 		i++
 		i = encodeVarintSpecs(dAtA, i, uint64(m.DriverConfig.Size()))
 		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 {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n24
+		i += n25
 	}
 	}
 	if m.Ipv6Enabled {
 	if m.Ipv6Enabled {
 		dAtA[i] = 0x18
 		dAtA[i] = 0x18
@@ -1903,11 +1980,11 @@ func (m *NetworkSpec) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x2a
 		dAtA[i] = 0x2a
 		i++
 		i++
 		i = encodeVarintSpecs(dAtA, i, uint64(m.IPAM.Size()))
 		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 {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n25
+		i += n26
 	}
 	}
 	if m.Attachable {
 	if m.Attachable {
 		dAtA[i] = 0x30
 		dAtA[i] = 0x30
@@ -1950,67 +2027,67 @@ func (m *ClusterSpec) MarshalTo(dAtA []byte) (int, error) {
 	dAtA[i] = 0xa
 	dAtA[i] = 0xa
 	i++
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.Annotations.Size()))
 	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 {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
-	i += n26
+	i += n27
 	dAtA[i] = 0x12
 	dAtA[i] = 0x12
 	i++
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.AcceptancePolicy.Size()))
 	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 {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
-	i += n27
+	i += n28
 	dAtA[i] = 0x1a
 	dAtA[i] = 0x1a
 	i++
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.Orchestration.Size()))
 	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 {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
-	i += n28
+	i += n29
 	dAtA[i] = 0x22
 	dAtA[i] = 0x22
 	i++
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.Raft.Size()))
 	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 {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
-	i += n29
+	i += n30
 	dAtA[i] = 0x2a
 	dAtA[i] = 0x2a
 	i++
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.Dispatcher.Size()))
 	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 {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
-	i += n30
+	i += n31
 	dAtA[i] = 0x32
 	dAtA[i] = 0x32
 	i++
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.CAConfig.Size()))
 	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 {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
-	i += n31
+	i += n32
 	dAtA[i] = 0x3a
 	dAtA[i] = 0x3a
 	i++
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.TaskDefaults.Size()))
 	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 {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
-	i += n32
+	i += n33
 	dAtA[i] = 0x42
 	dAtA[i] = 0x42
 	i++
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.EncryptionConfig.Size()))
 	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 {
 	if err != nil {
 		return 0, err
 		return 0, err
 	}
 	}
-	i += n33
+	i += n34
 	return i, nil
 	return i, nil
 }
 }
 
 
@@ -2032,11 +2109,43 @@ func (m *SecretSpec) MarshalTo(dAtA []byte) (int, error) {
 	dAtA[i] = 0xa
 	dAtA[i] = 0xa
 	i++
 	i++
 	i = encodeVarintSpecs(dAtA, i, uint64(m.Annotations.Size()))
 	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 {
 	if err != nil {
 		return 0, err
 		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 {
 	if len(m.Data) > 0 {
 		dAtA[i] = 0x12
 		dAtA[i] = 0x12
 		i++
 		i++
@@ -2338,6 +2447,16 @@ func (m *ContainerSpec) Size() (n int) {
 	if l > 0 {
 	if l > 0 {
 		n += 2 + l + sovSpecs(uint64(l))
 		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
 	return n
 }
 }
 
 
@@ -2452,6 +2571,18 @@ func (m *SecretSpec) Size() (n int) {
 	return n
 	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) {
 func sovSpecs(x uint64) (n int) {
 	for {
 	for {
 		n++
 		n++
@@ -2635,6 +2766,8 @@ func (this *ContainerSpec) String() string {
 		`OpenStdin:` + fmt.Sprintf("%v", this.OpenStdin) + `,`,
 		`OpenStdin:` + fmt.Sprintf("%v", this.OpenStdin) + `,`,
 		`ReadOnly:` + fmt.Sprintf("%v", this.ReadOnly) + `,`,
 		`ReadOnly:` + fmt.Sprintf("%v", this.ReadOnly) + `,`,
 		`StopSignal:` + fmt.Sprintf("%v", this.StopSignal) + `,`,
 		`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
 	return s
@@ -2716,6 +2849,17 @@ func (this *SecretSpec) String() string {
 	}, "")
 	}, "")
 	return s
 	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 {
 func valueToStringSpecs(v interface{}) string {
 	rv := reflect.ValueOf(v)
 	rv := reflect.ValueOf(v)
 	if rv.IsNil() {
 	if rv.IsNil() {
@@ -4492,6 +4636,70 @@ func (m *ContainerSpec) Unmarshal(dAtA []byte) error {
 			}
 			}
 			m.StopSignal = string(dAtA[iNdEx:postIndex])
 			m.StopSignal = string(dAtA[iNdEx:postIndex])
 			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:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
 			skippy, err := skipSpecs(dAtA[iNdEx:])
 			skippy, err := skipSpecs(dAtA[iNdEx:])
@@ -5456,6 +5664,117 @@ func (m *SecretSpec) Unmarshal(dAtA []byte) error {
 	}
 	}
 	return nil
 	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) {
 func skipSpecs(dAtA []byte) (n int, err error) {
 	l := len(dAtA)
 	l := len(dAtA)
 	iNdEx := 0
 	iNdEx := 0
@@ -5564,117 +5883,119 @@ var (
 func init() { proto.RegisterFile("specs.proto", fileDescriptorSpecs) }
 func init() { proto.RegisterFile("specs.proto", fileDescriptorSpecs) }
 
 
 var fileDescriptorSpecs = []byte{
 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.
 	// Groups specifies supplementary groups available to the user.
 	repeated string groups = 11;
 	repeated string groups = 11;
 
 
+	// Privileges specifies security configuration/permissions.
+	Privileges privileges = 22;
+
 	// TTY declares that a TTY should be attached to the standard streams,
 	// TTY declares that a TTY should be attached to the standard streams,
 	// including stdin if it is still open.
 	// including stdin if it is still open.
 	bool tty = 13 [(gogoproto.customname) = "TTY"];
 	bool tty = 13 [(gogoproto.customname) = "TTY"];
@@ -236,6 +239,10 @@ message ContainerSpec {
 	// will be exposed to the container.
 	// will be exposed to the container.
 	repeated SecretReference secrets = 12;
 	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
 	// Hosts allow additional entries to be specified in /etc/hosts
 	// that associates IP addresses with hostnames.
 	// that associates IP addresses with hostnames.
 	// Detailed documentation is available in:
 	// 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)
 	// Data is the secret payload - the maximum size is 500KB (that is, 500*1024 bytes)
 	bytes data = 2;
 	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_Secret
 	//	*Object_Resource
 	//	*Object_Resource
 	//	*Object_Extension
 	//	*Object_Extension
+	//	*Object_Config
 	Object isObject_Object `protobuf_oneof:"Object"`
 	Object isObject_Object `protobuf_oneof:"Object"`
 }
 }
 
 
@@ -110,6 +111,9 @@ type Object_Resource struct {
 type Object_Extension struct {
 type Object_Extension struct {
 	Extension *Extension `protobuf:"bytes,8,opt,name=extension,oneof"`
 	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_Node) isObject_Object()      {}
 func (*Object_Service) isObject_Object()   {}
 func (*Object_Service) isObject_Object()   {}
@@ -119,6 +123,7 @@ func (*Object_Cluster) isObject_Object()   {}
 func (*Object_Secret) isObject_Object()    {}
 func (*Object_Secret) isObject_Object()    {}
 func (*Object_Resource) isObject_Object()  {}
 func (*Object_Resource) isObject_Object()  {}
 func (*Object_Extension) isObject_Object() {}
 func (*Object_Extension) isObject_Object() {}
+func (*Object_Config) isObject_Object()    {}
 
 
 func (m *Object) GetObject() isObject_Object {
 func (m *Object) GetObject() isObject_Object {
 	if m != nil {
 	if m != nil {
@@ -183,6 +188,13 @@ func (m *Object) GetExtension() *Extension {
 	return nil
 	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.
 // 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{}) {
 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{}{
 	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_Secret)(nil),
 		(*Object_Resource)(nil),
 		(*Object_Resource)(nil),
 		(*Object_Extension)(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 {
 		if err := b.EncodeMessage(x.Extension); err != nil {
 			return err
 			return err
 		}
 		}
+	case *Object_Config:
+		_ = b.EncodeVarint(9<<3 | proto.WireBytes)
+		if err := b.EncodeMessage(x.Config); err != nil {
+			return err
+		}
 	case nil:
 	case nil:
 	default:
 	default:
 		return fmt.Errorf("Object.Object has unexpected type %T", x)
 		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)
 		err := b.DecodeMessage(msg)
 		m.Object = &Object_Extension{msg}
 		m.Object = &Object_Extension{msg}
 		return true, err
 		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:
 	default:
 		return false, nil
 		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(8<<3 | proto.WireBytes)
 		n += proto.SizeVarint(uint64(s))
 		n += proto.SizeVarint(uint64(s))
 		n += 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:
 	case nil:
 	default:
 	default:
 		panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
 		panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
@@ -412,6 +443,7 @@ type SelectBy struct {
 	//	*SelectBy_Membership
 	//	*SelectBy_Membership
 	//	*SelectBy_ReferencedNetworkID
 	//	*SelectBy_ReferencedNetworkID
 	//	*SelectBy_ReferencedSecretID
 	//	*SelectBy_ReferencedSecretID
+	//	*SelectBy_ReferencedConfigID
 	//	*SelectBy_Kind
 	//	*SelectBy_Kind
 	By isSelectBy_By `protobuf_oneof:"By"`
 	By isSelectBy_By `protobuf_oneof:"By"`
 }
 }
@@ -468,6 +500,9 @@ type SelectBy_ReferencedNetworkID struct {
 type SelectBy_ReferencedSecretID struct {
 type SelectBy_ReferencedSecretID struct {
 	ReferencedSecretID string `protobuf:"bytes,14,opt,name=referenced_secret_id,json=referencedSecretId,proto3,oneof"`
 	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 {
 type SelectBy_Kind struct {
 	Kind string `protobuf:"bytes,15,opt,name=kind,proto3,oneof"`
 	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_Membership) isSelectBy_By()          {}
 func (*SelectBy_ReferencedNetworkID) isSelectBy_By() {}
 func (*SelectBy_ReferencedNetworkID) isSelectBy_By() {}
 func (*SelectBy_ReferencedSecretID) isSelectBy_By()  {}
 func (*SelectBy_ReferencedSecretID) isSelectBy_By()  {}
+func (*SelectBy_ReferencedConfigID) isSelectBy_By()  {}
 func (*SelectBy_Kind) isSelectBy_By()                {}
 func (*SelectBy_Kind) isSelectBy_By()                {}
 
 
 func (m *SelectBy) GetBy() isSelectBy_By {
 func (m *SelectBy) GetBy() isSelectBy_By {
@@ -593,6 +629,13 @@ func (m *SelectBy) GetReferencedSecretID() string {
 	return ""
 	return ""
 }
 }
 
 
+func (m *SelectBy) GetReferencedConfigID() string {
+	if x, ok := m.GetBy().(*SelectBy_ReferencedConfigID); ok {
+		return x.ReferencedConfigID
+	}
+	return ""
+}
+
 func (m *SelectBy) GetKind() string {
 func (m *SelectBy) GetKind() string {
 	if x, ok := m.GetBy().(*SelectBy_Kind); ok {
 	if x, ok := m.GetBy().(*SelectBy_Kind); ok {
 		return x.Kind
 		return x.Kind
@@ -617,6 +660,7 @@ func (*SelectBy) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) erro
 		(*SelectBy_Membership)(nil),
 		(*SelectBy_Membership)(nil),
 		(*SelectBy_ReferencedNetworkID)(nil),
 		(*SelectBy_ReferencedNetworkID)(nil),
 		(*SelectBy_ReferencedSecretID)(nil),
 		(*SelectBy_ReferencedSecretID)(nil),
+		(*SelectBy_ReferencedConfigID)(nil),
 		(*SelectBy_Kind)(nil),
 		(*SelectBy_Kind)(nil),
 	}
 	}
 }
 }
@@ -673,6 +717,9 @@ func _SelectBy_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
 	case *SelectBy_ReferencedSecretID:
 	case *SelectBy_ReferencedSecretID:
 		_ = b.EncodeVarint(14<<3 | proto.WireBytes)
 		_ = b.EncodeVarint(14<<3 | proto.WireBytes)
 		_ = b.EncodeStringBytes(x.ReferencedSecretID)
 		_ = b.EncodeStringBytes(x.ReferencedSecretID)
+	case *SelectBy_ReferencedConfigID:
+		_ = b.EncodeVarint(16<<3 | proto.WireBytes)
+		_ = b.EncodeStringBytes(x.ReferencedConfigID)
 	case *SelectBy_Kind:
 	case *SelectBy_Kind:
 		_ = b.EncodeVarint(15<<3 | proto.WireBytes)
 		_ = b.EncodeVarint(15<<3 | proto.WireBytes)
 		_ = b.EncodeStringBytes(x.Kind)
 		_ = b.EncodeStringBytes(x.Kind)
@@ -787,6 +834,13 @@ func _SelectBy_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffe
 		x, err := b.DecodeStringBytes()
 		x, err := b.DecodeStringBytes()
 		m.By = &SelectBy_ReferencedSecretID{x}
 		m.By = &SelectBy_ReferencedSecretID{x}
 		return true, err
 		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
 	case 15: // By.kind
 		if wire != proto.WireBytes {
 		if wire != proto.WireBytes {
 			return true, proto.ErrInternalBadWireType
 			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(14<<3 | proto.WireBytes)
 		n += proto.SizeVarint(uint64(len(x.ReferencedSecretID)))
 		n += proto.SizeVarint(uint64(len(x.ReferencedSecretID)))
 		n += 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:
 	case *SelectBy_Kind:
 		n += proto.SizeVarint(15<<3 | proto.WireBytes)
 		n += proto.SizeVarint(15<<3 | proto.WireBytes)
 		n += proto.SizeVarint(uint64(len(x.Kind)))
 		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())
 			github_com_docker_swarmkit_api_deepcopy.Copy(v.Extension, o.GetExtension())
 			m.Object = &v
 			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(),
 				ReferencedSecretID: o.GetReferencedSecretID(),
 			}
 			}
 			m.By = &v
 			m.By = &v
+		case *SelectBy_ReferencedConfigID:
+			v := SelectBy_ReferencedConfigID{
+				ReferencedConfigID: o.GetReferencedConfigID(),
+			}
+			m.By = &v
 		case *SelectBy_Kind:
 		case *SelectBy_Kind:
 			v := SelectBy_Kind{
 			v := SelectBy_Kind{
 				Kind: o.GetKind(),
 				Kind: o.GetKind(),
@@ -1513,6 +1582,20 @@ func (m *Object_Extension) MarshalTo(dAtA []byte) (int, error) {
 	}
 	}
 	return i, nil
 	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) {
 func (m *SelectBySlot) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	size := m.Size()
 	dAtA = make([]byte, size)
 	dAtA = make([]byte, size)
@@ -1594,11 +1677,11 @@ func (m *SelectBy) MarshalTo(dAtA []byte) (int, error) {
 	var l int
 	var l int
 	_ = l
 	_ = l
 	if m.By != nil {
 	if m.By != nil {
-		nn10, err := m.By.MarshalTo(dAtA[i:])
+		nn11, err := m.By.MarshalTo(dAtA[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += nn10
+		i += nn11
 	}
 	}
 	return i, nil
 	return i, nil
 }
 }
@@ -1641,11 +1724,11 @@ func (m *SelectBy_Custom) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x2a
 		dAtA[i] = 0x2a
 		i++
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.Custom.Size()))
 		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 {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n11
+		i += n12
 	}
 	}
 	return i, nil
 	return i, nil
 }
 }
@@ -1655,11 +1738,11 @@ func (m *SelectBy_CustomPrefix) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x32
 		dAtA[i] = 0x32
 		i++
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.CustomPrefix.Size()))
 		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 {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n12
+		i += n13
 	}
 	}
 	return i, nil
 	return i, nil
 }
 }
@@ -1685,11 +1768,11 @@ func (m *SelectBy_Slot) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x4a
 		dAtA[i] = 0x4a
 		i++
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.Slot.Size()))
 		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 {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n13
+		i += n14
 	}
 	}
 	return i, nil
 	return i, nil
 }
 }
@@ -1738,6 +1821,16 @@ func (m *SelectBy_Kind) MarshalTo(dAtA []byte) (int, error) {
 	i += copy(dAtA[i:], m.Kind)
 	i += copy(dAtA[i:], m.Kind)
 	return i, nil
 	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) {
 func (m *WatchRequest) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	size := m.Size()
 	dAtA = make([]byte, size)
 	dAtA = make([]byte, size)
@@ -1769,11 +1862,11 @@ func (m *WatchRequest) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x12
 		dAtA[i] = 0x12
 		i++
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.ResumeFrom.Size()))
 		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 {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n14
+		i += n15
 	}
 	}
 	if m.IncludeOldObject {
 	if m.IncludeOldObject {
 		dAtA[i] = 0x18
 		dAtA[i] = 0x18
@@ -1860,11 +1953,11 @@ func (m *WatchMessage) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x12
 		dAtA[i] = 0x12
 		i++
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.Version.Size()))
 		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 {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n15
+		i += n16
 	}
 	}
 	return i, nil
 	return i, nil
 }
 }
@@ -1893,21 +1986,21 @@ func (m *WatchMessage_Event) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x12
 		dAtA[i] = 0x12
 		i++
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.Object.Size()))
 		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 {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n16
+		i += n17
 	}
 	}
 	if m.OldObject != nil {
 	if m.OldObject != nil {
 		dAtA[i] = 0x1a
 		dAtA[i] = 0x1a
 		i++
 		i++
 		i = encodeVarintStore(dAtA, i, uint64(m.OldObject.Size()))
 		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 {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n17
+		i += n18
 	}
 	}
 	return i, nil
 	return i, nil
 }
 }
@@ -2144,6 +2237,15 @@ func (m *Object_Extension) Size() (n int) {
 	}
 	}
 	return n
 	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) {
 func (m *SelectBySlot) Size() (n int) {
 	var l int
 	var l int
 	_ = l
 	_ = l
@@ -2292,6 +2394,13 @@ func (m *SelectBy_Kind) Size() (n int) {
 	n += 1 + l + sovStore(uint64(l))
 	n += 1 + l + sovStore(uint64(l))
 	return n
 	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) {
 func (m *WatchRequest) Size() (n int) {
 	var l int
 	var l int
 	_ = l
 	_ = l
@@ -2466,6 +2575,16 @@ func (this *Object_Extension) String() string {
 	}, "")
 	}, "")
 	return s
 	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 {
 func (this *SelectBySlot) String() string {
 	if this == nil {
 	if this == nil {
 		return "nil"
 		return "nil"
@@ -2649,6 +2768,16 @@ func (this *SelectBy_Kind) String() string {
 	}, "")
 	}, "")
 	return s
 	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 {
 func (this *WatchRequest) String() string {
 	if this == nil {
 	if this == nil {
 		return "nil"
 		return "nil"
@@ -2989,6 +3118,38 @@ func (m *Object) Unmarshal(dAtA []byte) error {
 			}
 			}
 			m.Object = &Object_Extension{v}
 			m.Object = &Object_Extension{v}
 			iNdEx = postIndex
 			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:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
 			skippy, err := skipStore(dAtA[iNdEx:])
 			skippy, err := skipStore(dAtA[iNdEx:])
@@ -3691,6 +3852,35 @@ func (m *SelectBy) Unmarshal(dAtA []byte) error {
 			}
 			}
 			m.By = &SelectBy_Kind{string(dAtA[iNdEx:postIndex])}
 			m.By = &SelectBy_Kind{string(dAtA[iNdEx:postIndex])}
 			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:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
 			skippy, err := skipStore(dAtA[iNdEx:])
 			skippy, err := skipStore(dAtA[iNdEx:])
@@ -4332,76 +4522,78 @@ var (
 func init() { proto.RegisterFile("store.proto", fileDescriptorStore) }
 func init() { proto.RegisterFile("store.proto", fileDescriptorStore) }
 
 
 var fileDescriptorStore = []byte{
 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;
 		Secret secret = 6;
 		Resource resource = 7;
 		Resource resource = 7;
 		Extension extension = 8;
 		Extension extension = 8;
+		Config config = 9;
 	}
 	}
 }
 }
 
 
@@ -60,6 +61,7 @@ message SelectBy {
 		// supported by: service, task
 		// supported by: service, task
 		string referenced_network_id = 13 [(gogoproto.customname) = "ReferencedNetworkID"];
 		string referenced_network_id = 13 [(gogoproto.customname) = "ReferencedNetworkID"];
 		string referenced_secret_id = 14 [(gogoproto.customname) = "ReferencedSecretID"];
 		string referenced_secret_id = 14 [(gogoproto.customname) = "ReferencedSecretID"];
+		string referenced_config_id = 16 [(gogoproto.customname) = "ReferencedConfigID"];
 
 
 		// supported by: resource
 		// supported by: resource
 		string kind = 15;
 		string kind = 15;

文件差異過大導致無法顯示
+ 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.
 	// Information about the Docker Engine on the node.
 	EngineDescription engine = 4;
 	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 {
 message RaftMemberStatus {
@@ -853,6 +865,20 @@ message ManagerStatus {
 	RaftMemberStatus.Reachability reachability = 4;
 	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.
 // SecretReference is the linkage between a service and a secret that it uses.
 message SecretReference {
 message SecretReference {
@@ -865,20 +891,21 @@ message SecretReference {
 	// lookup/display purposes.  The secret in the reference will be identified by its ID.
 	// lookup/display purposes.  The secret in the reference will be identified by its ID.
 	string secret_name = 2;
 	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.
 	// Target specifies how this secret should be exposed to the task.
 	oneof target {
 	oneof target {
@@ -943,3 +970,26 @@ message RootRotation {
 	// cross-signed CA cert is the CACert that has been cross-signed by the previous root
 	// 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"];
 	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
 	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
 // LocalSigner is a signer that can sign CSRs
 type LocalSigner struct {
 type LocalSigner struct {
 	cfsigner.Signer
 	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
 // 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()
 	csr, key, err := GenerateNewCSR()
 	if err != nil {
 	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
 	// Obtain a signed Certificate
 	certChain, err := rca.ParseValidateAndSignCSR(csr, cn, ou, org)
 	certChain, err := rca.ParseValidateAndSignCSR(csr, cn, ou, org)
 	if err != nil {
 	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
 	// Create a valid TLSKeyPair out of the PEM encoded private key and certificate
 	tlsKeyPair, err := tls.X509KeyPair(certChain, key)
 	tlsKeyPair, err := tls.X509KeyPair(certChain, key)
 	if err != nil {
 	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
 // 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
 	// Create a new key/pair and CSR
 	csr, key, err := GenerateNewCSR()
 	csr, key, err := GenerateNewCSR()
 	if err != nil {
 	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
 	// 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
 		config.ForceRemote = true
 	}
 	}
 	if err != nil {
 	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
 	// 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()
 	// Create an X509Cert so we can .Verify()
 	// Check to see if this certificate was signed by our CA, and isn't expired
 	// 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 {
 	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
 	// Create a valid TLSKeyPair out of the PEM encoded private key and certificate
 	tlsKeyPair, err := tls.X509KeyPair(signedCert, key)
 	tlsKeyPair, err := tls.X509KeyPair(signedCert, key)
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	}
 
 
 	var kekUpdate *KEKData
 	var kekUpdate *KEKData
 	for i := 0; i < 5; i++ {
 	for i := 0; i < 5; i++ {
 		// ValidateCertChain will always return at least 1 cert, so indexing at 0 is safe
 		// 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 {
 		if err == nil {
 			break
 			break
 		}
 		}
 	}
 	}
 	if err != nil {
 	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) {
 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 intermediatePool *x509.CertPool
 	var parsedIntermediates []*x509.Certificate
 	var parsedIntermediates []*x509.Certificate
 	if len(intermediates) > 0 {
 	if len(intermediates) > 0 {
-		parsedIntermediates, err = ValidateCertChain(pool, intermediates, false)
+		parsedIntermediates, _, err = ValidateCertChain(pool, intermediates, false)
 		if err != nil {
 		if err != nil {
 			return RootCA{}, errors.Wrap(err, "invalid intermediate chain")
 			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
 // 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.
 // 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
 // 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
 	// Parse all the certificates in the cert bundle
 	parsedCerts, err := helpers.ParseCertificatesPEM(certs)
 	parsedCerts, err := helpers.ParseCertificatesPEM(certs)
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	}
 	if len(parsedCerts) == 0 {
 	if len(parsedCerts) == 0 {
-		return nil, errors.New("no certificates to validate")
+		return nil, nil, errors.New("no certificates to validate")
 	}
 	}
 	now := time.Now()
 	now := time.Now()
 	// ensure that they form a chain, each one being signed by the one after it
 	// 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
 		// 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.
 		// because this is an easier way to allow expired certs.
 		if now.Before(cert.NotBefore) {
 		if now.Before(cert.NotBefore) {
-			return nil, errors.Wrapf(
+			return nil, nil, errors.Wrapf(
 				x509.CertificateInvalidError{
 				x509.CertificateInvalidError{
 					Cert:   cert,
 					Cert:   cert,
 					Reason: x509.Expired,
 					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))
 				i+1, cert.Subject.CommonName, cert.NotBefore.UTC().Format(time.RFC1123), now.Format(time.RFC1123))
 		}
 		}
 		if !allowExpired && now.After(cert.NotAfter) {
 		if !allowExpired && now.After(cert.NotAfter) {
-			return nil, errors.Wrapf(
+			return nil, nil, errors.Wrapf(
 				x509.CertificateInvalidError{
 				x509.CertificateInvalidError{
 					Cert:   cert,
 					Cert:   cert,
 					Reason: x509.Expired,
 					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
 			// check that the previous cert was signed by this cert
 			prevCert := parsedCerts[i-1]
 			prevCert := parsedCerts[i-1]
 			if err := prevCert.CheckSignatureFrom(cert); err != nil {
 			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)
 					i, prevCert.Subject.CommonName, i+1, cert.Subject.CommonName)
 			}
 			}
 
 
@@ -526,6 +548,8 @@ func ValidateCertChain(rootPool *x509.CertPool, certs []byte, allowExpired bool)
 		CurrentTime:   now,
 		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
 	// 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
 	// 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.
 	// 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
 			verifyOpts.CurrentTime = cert.NotAfter
 
 
-			_, err = parsedCerts[0].Verify(verifyOpts)
+			chains, err = parsedCerts[0].Verify(verifyOpts)
 			if err == nil {
 			if err == nil {
-				return parsedCerts, nil
+				return parsedCerts, chains, nil
 			}
 			}
 		}
 		}
 		if invalid, ok := err.(x509.CertificateInvalidError); ok && invalid.Reason == x509.Expired {
 		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 {
 	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
 // 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
 	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/connectionbroker"
 	"github.com/docker/swarmkit/identity"
 	"github.com/docker/swarmkit/identity"
 	"github.com/docker/swarmkit/log"
 	"github.com/docker/swarmkit/log"
+	"github.com/docker/swarmkit/watch"
 	"github.com/opencontainers/go-digest"
 	"github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 	"google.golang.org/grpc/credentials"
 	"google.golang.org/grpc/credentials"
@@ -71,10 +72,16 @@ type SecurityConfig struct {
 	externalCA    *ExternalCA
 	externalCA    *ExternalCA
 	keyReadWriter *KeyReadWriter
 	keyReadWriter *KeyReadWriter
 
 
+	certificate *tls.Certificate
+	issuerInfo  *IssuerInfo
+
 	externalCAClientRootPool *x509.CertPool
 	externalCAClientRootPool *x509.CertPool
 
 
 	ServerTLSCreds *MutableTLSCreds
 	ServerTLSCreds *MutableTLSCreds
 	ClientTLSCreds *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
 // 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.
 // 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
 	// Make a new TLS config for the external CA client without a
 	// ServerName value set.
 	// ServerName value set.
-	clientTLSConfig := clientTLSCreds.Config()
-
 	externalCATLSConfig := &tls.Config{
 	externalCATLSConfig := &tls.Config{
-		Certificates: clientTLSConfig.Certificates,
-		RootCAs:      clientTLSConfig.RootCAs,
+		Certificates: []tls.Certificate{*tlsKeyPair},
+		RootCAs:      rootCA.Pool,
 		MinVersion:   tls.VersionTLS12,
 		MinVersion:   tls.VersionTLS12,
 	}
 	}
 
 
 	return &SecurityConfig{
 	return &SecurityConfig{
-		rootCA:                   rootCA,
-		keyReadWriter:            krw,
+		rootCA:        rootCA,
+		keyReadWriter: krw,
+
+		certificate: tlsKeyPair,
+		issuerInfo:  issuerInfo,
+
 		externalCA:               NewExternalCA(rootCA, externalCATLSConfig),
 		externalCA:               NewExternalCA(rootCA, externalCATLSConfig),
 		ClientTLSCreds:           clientTLSCreds,
 		ClientTLSCreds:           clientTLSCreds,
 		ServerTLSCreds:           serverTLSCreds,
 		ServerTLSCreds:           serverTLSCreds,
 		externalCAClientRootPool: rootCA.Pool,
 		externalCAClientRootPool: rootCA.Pool,
-	}
+	}, nil
 }
 }
 
 
 // RootCA returns the root CA.
 // RootCA returns the root CA.
@@ -136,19 +159,32 @@ func (s *SecurityConfig) UpdateRootCA(rootCA *RootCA, externalCARootPool *x509.C
 
 
 	s.rootCA = rootCA
 	s.rootCA = rootCA
 	s.externalCAClientRootPool = externalCARootPool
 	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 {
 	if err != nil {
 		return errors.Wrap(err, "failed to create a new client config using the new root CA")
 		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 {
 	if err != nil {
 		return errors.Wrap(err, "failed to create a new server config using the new root CA")
 		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
 	// Update the external CA to use the new client TLS
 	// config using a copy without a serverName specified.
 	// config using a copy without a serverName specified.
 	s.externalCA.UpdateTLSConfig(&tls.Config{
 	s.externalCA.UpdateTLSConfig(&tls.Config{
-		Certificates: certificates,
+		Certificates: certs,
 		RootCAs:      s.externalCAClientRootPool,
 		RootCAs:      s.externalCAClientRootPool,
 		MinVersion:   tls.VersionTLS12,
 		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")
 		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
 	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
 	// 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
 		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
 	// Now that we know this certificate is valid, create a TLS Certificate for our
 	// credentials
 	// credentials
@@ -311,26 +360,17 @@ func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter,
 		return nil, err
 		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
 // CertificateRequestConfig contains the information needed to request a
@@ -365,12 +405,12 @@ func (rootCA RootCA) CreateSecurityConfig(ctx context.Context, krw *KeyReadWrite
 	org := identity.NewID()
 	org := identity.NewID()
 
 
 	proposedRole := ManagerRole
 	proposedRole := ManagerRole
-	tlsKeyPair, err := rootCA.IssueAndSaveNewCertificates(krw, cn, proposedRole, org)
+	tlsKeyPair, issuerInfo, err := rootCA.IssueAndSaveNewCertificates(krw, cn, proposedRole, org)
 	switch errors.Cause(err) {
 	switch errors.Cause(err) {
 	case ErrNoValidSigner:
 	case ErrNoValidSigner:
 		// Request certificate issuance from a remote CA.
 		// Request certificate issuance from a remote CA.
 		// Last argument is nil because at this point we don't have any valid TLS creds
 		// 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 {
 		if err != nil {
 			log.G(ctx).WithError(err).Error("failed to request save new certificate")
 			log.G(ctx).WithError(err).Error("failed to request save new certificate")
 			return nil, err
 			return nil, err
@@ -388,24 +428,14 @@ func (rootCA RootCA) CreateSecurityConfig(ctx context.Context, krw *KeyReadWrite
 		return nil, err
 		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
 // 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.
 	// Let's request new certs. Renewals don't require a token.
 	rootCA := s.RootCA()
 	rootCA := s.RootCA()
-	tlsKeyPair, err := rootCA.RequestAndSaveNewCertificates(ctx,
+	tlsKeyPair, issuerInfo, err := rootCA.RequestAndSaveNewCertificates(ctx,
 		s.KeyWriter(),
 		s.KeyWriter(),
 		CertificateRequestConfig{
 		CertificateRequestConfig{
 			ConnBroker:  connBroker,
 			ConnBroker:  connBroker,
@@ -432,9 +462,10 @@ func RenewTLSConfigNow(ctx context.Context, s *SecurityConfig, connBroker *conne
 		log.WithError(err).Errorf("failed to renew the certificate")
 		log.WithError(err).Errorf("failed to renew the certificate")
 		return err
 		return err
 	}
 	}
+
 	s.mu.Lock()
 	s.mu.Lock()
 	defer s.mu.Unlock()
 	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
 // 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
 	lastSeenClusterRootCA *api.RootCA
 	lastSeenExternalCAs   []*api.ExternalCA
 	lastSeenExternalCAs   []*api.ExternalCA
 	secConfigMu           sync.Mutex
 	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.
 // DefaultCAConfig returns the default CA Config, with a default expiration.
@@ -70,13 +73,14 @@ func DefaultCAConfig() api.CAConfig {
 }
 }
 
 
 // NewServer creates a CA API server.
 // 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{
 	return &Server{
 		store:                       store,
 		store:                       store,
 		securityConfig:              securityConfig,
 		securityConfig:              securityConfig,
 		pending:                     make(map[string]*api.Node),
 		pending:                     make(map[string]*api.Node),
 		started:                     make(chan struct{}),
 		started:                     make(chan struct{}),
 		reconciliationRetryInterval: defaultReconciliationRetryInterval,
 		reconciliationRetryInterval: defaultReconciliationRetryInterval,
+		rootPaths:                   rootCAPaths,
 	}
 	}
 }
 }
 
 
@@ -582,6 +586,9 @@ func (s *Server) UpdateRootCA(ctx context.Context, cluster *api.Cluster) error {
 		if err != nil {
 		if err != nil {
 			return errors.Wrap(err, "invalid Root CA object in cluster")
 			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
 		externalCARootPool := updatedRootCA.Pool
 		if rCA.RootRotation != nil {
 		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
 			// we're rotating to a new root, so we only want external CAs with the new root cert
 			wantedExternalCACert = rCA.RootRotation.CACert
 			wantedExternalCACert = rCA.RootRotation.CACert
 		}
 		}
+		wantedExternalCACert = NormalizePEMs(wantedExternalCACert)
 		// Update our security config with the list of External CA URLs
 		// Update our security config with the list of External CA URLs
 		// from the new cluster state.
 		// from the new cluster state.
 
 
@@ -623,6 +631,7 @@ func (s *Server) UpdateRootCA(ctx context.Context, cluster *api.Cluster) error {
 			if len(certForExtCA) == 0 {
 			if len(certForExtCA) == 0 {
 				certForExtCA = rCA.CACert
 				certForExtCA = rCA.CACert
 			}
 			}
+			certForExtCA = NormalizePEMs(certForExtCA)
 			if extCA.Protocol != api.ExternalCA_CAProtocolCFSSL {
 			if extCA.Protocol != api.ExternalCA_CAProtocolCFSSL {
 				logger.Debugf("skipping external CA %d (url: %s) due to unknown protocol type", i, extCA.URL)
 				logger.Debugf("skipping external CA %d (url: %s) due to unknown protocol type", i, extCA.URL)
 				continue
 				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)
 // determines whether an api.RootCA, api.RootRotation, or api.CAConfig has a signing key (local signer)
 func hasSigningKey(a interface{}) bool {
 func hasSigningKey(a interface{}) bool {
 	switch b := a.(type) {
 	switch b := a.(type) {
-	case api.RootCA:
+	case *api.RootCA:
 		return len(b.CAKey) > 0
 		return len(b.CAKey) > 0
 	case *api.RootRotation:
 	case *api.RootRotation:
 		return b != nil && len(b.CAKey) > 0
 		return b != nil && len(b.CAKey) > 0
-	case api.CAConfig:
+	case *api.CAConfig:
 		return len(b.SigningCACert) > 0 && len(b.SigningCAKey) > 0
 		return len(b.SigningCACert) > 0 && len(b.SigningCAKey) > 0
 	default:
 	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.
 // 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.
 // 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 (
 	var (
 		rootCert, rootKey, crossSignedCert []byte
 		rootCert, rootKey, crossSignedCert []byte
 		newRootHasSigner                   bool
 		newRootHasSigner                   bool
 		err                                error
 		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
 		rootCert, rootKey = s.Cert, s.Key
 		newRootHasSigner = true
 		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
 	// 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)
 	// a root rotation is already in progress)
 	switch {
 	switch {
-	case hasSigningKey(cluster.RootCA):
+	case hasSigningKey(apiRootCA):
 		var oldRootCA ca.RootCA
 		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 {
 		if err == nil {
 			crossSignedCert, err = oldRootCA.CrossSignCACertificate(rootCert)
 			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)
 		// 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()
 		externalCA := securityConfig.ExternalCA().Copy()
 		var urls []string
 		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)
 				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")
 				"must provide an external CA for the current external root CA to generate a cross-signed certificate")
 		}
 		}
 		externalCA.UpdateURLs(urls...)
 		externalCA.UpdateURLs(urls...)
-		crossSignedCert, err = externalCA.CrossSignRootCA(ctx, newRootCA)
+		crossSignedCert, err = externalCA.CrossSignRootCA(ctx, newCARootCA)
 	}
 	}
 
 
 	if err != nil {
 	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")
 		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{
 	copied.RootRotation = &api.RootRotation{
 		CACert:            rootCert,
 		CACert:            rootCert,
 		CAKey:             rootKey,
 		CAKey:             rootKey,
-		CrossSignedCACert: crossSignedCert,
+		CrossSignedCACert: ca.NormalizePEMs(crossSignedCert),
 	}
 	}
 	copied.LastForcedRotation = version
 	copied.LastForcedRotation = version
 	return copied, nil
 	return copied, nil
@@ -120,58 +120,46 @@ func validateExternalCAURL(dialer *net.Dialer, tlsOpts *tls.Config, caURL string
 	return err
 	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
 // 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
 //    - 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.
 //      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) {
 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 {
 	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")
 		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
 		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
 	// 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
 	// the ForceRotate version has changed
 	if len(newConfig.SigningCACert) == 0 {
 	if len(newConfig.SigningCACert) == 0 {
@@ -214,8 +213,18 @@ func validateCAConfig(ctx context.Context, securityConfig *ca.SecurityConfig, cl
 			if err != nil {
 			if err != nil {
 				return nil, grpc.Errorf(codes.Internal, err.Error())
 				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
 		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")
 		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
 	// 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 := cluster.RootCA.Copy()
 		copied.CAKey = newConfig.SigningCAKey
 		copied.CAKey = newConfig.SigningCAKey
 		copied.RootRotation = nil
 		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
 	// 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 := cluster.RootCA.Copy()
 		copied.RootRotation.CAKey = newConfig.SigningCAKey
 		copied.RootRotation.CAKey = newConfig.SigningCAKey
 		copied.LastForcedRotation = newConfig.ForceRotate
 		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
 	// 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
 	// 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 {
 	if len(spec.AcceptancePolicy.Policies) > 0 {
 		for _, policy := range spec.AcceptancePolicy.Policies {
 		for _, policy := range spec.AcceptancePolicy.Policies {
 			if policy.Secret != nil && strings.ToLower(policy.Secret.Alg) != "bcrypt" {
 			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"
 	"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 {
 func buildFilters(by func(string) store.By, values []string) store.By {
 	filters := make([]store.By, 0, len(values))
 	filters := make([]store.By, 0, len(values))
@@ -68,7 +71,7 @@ func validateAnnotations(m api.Annotations) error {
 	if m.Name == "" {
 	if m.Name == "" {
 		return grpc.Errorf(codes.InvalidArgument, "meta: name must be provided")
 		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
 		// if the name doesn't match the regex
 		return grpc.Errorf(codes.InvalidArgument, "name must be valid as a DNS name component")
 		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
 	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 {
 func validateDriver(driver *api.Driver, pg plugingetter.PluginGetter, pluginType string) error {
 	if driver == nil {
 	if driver == nil {
 		// It is ok to not specify the driver. We will choose
 		// 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 (
 import (
 	"crypto/subtle"
 	"crypto/subtle"
-	"regexp"
 	"strings"
 	"strings"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
@@ -15,13 +14,9 @@ import (
 	"google.golang.org/grpc/codes"
 	"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.
 // MaxSecretSize is the maximum byte length of the `Secret.Spec.Data` field.
 const MaxSecretSize = 500 * 1024 // 500KB
 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
 // assumes spec is not nil
 func secretFromSecretSpec(spec *api.SecretSpec) *api.Secret {
 func secretFromSecretSpec(spec *api.SecretSpec) *api.Secret {
 	return &api.Secret{
 	return &api.Secret{
@@ -247,7 +242,7 @@ func validateSecretSpec(spec *api.SecretSpec) error {
 	if spec == nil {
 	if spec == nil {
 		return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
 		return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
 	}
 	}
-	if err := validateSecretAnnotations(spec.Annotations); err != nil {
+	if err := validateConfigOrSecretAnnotations(spec.Annotations); err != nil {
 		return err
 		return err
 	}
 	}
 
 
@@ -256,14 +251,3 @@ func validateSecretSpec(spec *api.SecretSpec) error {
 	}
 	}
 	return nil
 	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
 		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 {
 	if err := validateSecretRefsSpec(taskSpec); err != nil {
 		return err
 		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 {
 	if taskSpec.GetRuntime() == nil {
 		return grpc.Errorf(codes.InvalidArgument, "TaskSpec: missing runtime")
 		return grpc.Errorf(codes.InvalidArgument, "TaskSpec: missing runtime")
 	}
 	}
@@ -314,6 +319,48 @@ func validateSecretRefsSpec(spec api.TaskSpec) error {
 	return nil
 	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 {
 func (s *Server) validateNetworks(networks []*api.NetworkAttachmentConfig) error {
 	for _, na := range networks {
 	for _, na := range networks {
 		var network *api.Network
 		var network *api.Network
@@ -459,6 +506,35 @@ func (s *Server) checkSecretExistence(tx store.Tx, spec *api.ServiceSpec) error
 	return nil
 	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.
 // CreateService creates and returns a Service based on the provided ServiceSpec.
 // - Returns `InvalidArgument` if the ServiceSpec is malformed.
 // - Returns `InvalidArgument` if the ServiceSpec is malformed.
 // - Returns `Unimplemented` if the ServiceSpec references unimplemented features.
 // - 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 {
 		if err != nil {
 			return err
 			return err
 		}
 		}
+		err = s.checkConfigExistence(tx, request.Spec)
+		if err != nil {
+			return err
+		}
 
 
 		return store.CreateService(tx, service)
 		return store.CreateService(tx, service)
 	})
 	})
@@ -585,6 +665,11 @@ func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRe
 			return err
 			return err
 		}
 		}
 
 
+		err = s.checkConfigExistence(tx, request.Spec)
+		if err != nil {
+			return err
+		}
+
 		// orchestrator is designed to be stateless, so it should not deal
 		// orchestrator is designed to be stateless, so it should not deal
 		// with service mode change (comparing current config with previous config).
 		// with service mode change (comparing current config with previous config).
 		// proper way to change service mode is to delete and re-add.
 		// 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()
 			service.Spec = *request.Spec.Copy()
 			// Set spec version. Note that this will not match the
 			// Set spec version. Note that this will not match the
 			// service's Meta.Version after the store update. 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.
 			// meant to be directly comparable.
 			service.SpecVersion = service.Meta.Version.Copy()
 			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
 	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.
 // Dispatcher is responsible for dispatching tasks and tracking agent health.
 type Dispatcher struct {
 type Dispatcher struct {
 	mu                   sync.Mutex
 	mu                   sync.Mutex
 	wg                   sync.WaitGroup
 	wg                   sync.WaitGroup
 	nodes                *nodeStore
 	nodes                *nodeStore
 	store                *store.MemoryStore
 	store                *store.MemoryStore
-	mgrQueue             *watch.Queue
 	lastSeenManagers     []*api.WeightedPeer
 	lastSeenManagers     []*api.WeightedPeer
 	networkBootstrapKeys []*api.EncryptionKey
 	networkBootstrapKeys []*api.EncryptionKey
-	keyMgrQueue          *watch.Queue
+	lastSeenRootCert     []byte
 	config               *Config
 	config               *Config
 	cluster              Cluster
 	cluster              Cluster
 	ctx                  context.Context
 	ctx                  context.Context
 	cancel               context.CancelFunc
 	cancel               context.CancelFunc
+	clusterUpdateQueue   *watch.Queue
 
 
 	taskUpdates     map[string]*api.TaskStatus // indexed by task ID
 	taskUpdates     map[string]*api.TaskStatus // indexed by task ID
 	taskUpdatesLock sync.Mutex
 	taskUpdatesLock sync.Mutex
@@ -196,6 +205,7 @@ func (d *Dispatcher) Run(ctx context.Context) error {
 				if clusters[0].NetworkBootstrapKeys != nil {
 				if clusters[0].NetworkBootstrapKeys != nil {
 					d.networkBootstrapKeys = clusters[0].NetworkBootstrapKeys
 					d.networkBootstrapKeys = clusters[0].NetworkBootstrapKeys
 				}
 				}
+				d.lastSeenRootCert = clusters[0].RootCA.CACert
 			}
 			}
 			return nil
 			return nil
 		},
 		},
@@ -205,9 +215,8 @@ func (d *Dispatcher) Run(ctx context.Context) error {
 		d.mu.Unlock()
 		d.mu.Unlock()
 		return err
 		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()
 	peerWatcher, peerCancel := d.cluster.SubscribePeers()
 	defer peerCancel()
 	defer peerCancel()
@@ -231,7 +240,7 @@ func (d *Dispatcher) Run(ctx context.Context) error {
 		d.mu.Lock()
 		d.mu.Lock()
 		d.lastSeenManagers = mgrs
 		d.lastSeenManagers = mgrs
 		d.mu.Unlock()
 		d.mu.Unlock()
-		d.mgrQueue.Publish(mgrs)
+		d.clusterUpdateQueue.Publish(clusterUpdate{managerUpdate: &mgrs})
 	}
 	}
 
 
 	batchTimer := time.NewTimer(maxBatchInterval)
 	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.nodes.updatePeriod(d.config.HeartbeatPeriod, d.config.HeartbeatEpsilon, d.config.GracePeriodMultiplier)
 				}
 				}
 			}
 			}
+			d.lastSeenRootCert = cluster.Cluster.RootCA.CACert
 			d.networkBootstrapKeys = cluster.Cluster.NetworkBootstrapKeys
 			d.networkBootstrapKeys = cluster.Cluster.NetworkBootstrapKeys
 			d.mu.Unlock()
 			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():
 		case <-ctx.Done():
 			return nil
 			return nil
 		}
 		}
@@ -286,8 +299,7 @@ func (d *Dispatcher) Stop() error {
 	d.processUpdatesCond.Broadcast()
 	d.processUpdatesCond.Broadcast()
 	d.processUpdatesLock.Unlock()
 	d.processUpdatesLock.Unlock()
 
 
-	d.mgrQueue.Close()
-	d.keyMgrQueue.Close()
+	d.clusterUpdateQueue.Close()
 
 
 	d.wg.Wait()
 	d.wg.Wait()
 
 
@@ -812,12 +824,10 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 	}
 	}
 
 
 	var (
 	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 {
 	sendMessage := func(msg api.AssignmentsMessage, assignmentType api.AssignmentsMessage_Type) error {
 		sequence++
 		sequence++
@@ -832,39 +842,6 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 		return nil
 		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
 	// TODO(aaronl): Also send node secrets that should be exposed to
 	// this node.
 	// this node.
 	nodeTasks, cancel, err := store.ViewAndWatch(
 	nodeTasks, cancel, err := store.ViewAndWatch(
@@ -876,57 +853,22 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 			}
 			}
 
 
 			for _, t := range tasks {
 			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
 			return nil
 		},
 		},
 		api.EventUpdateTask{Task: &api.Task{NodeID: nodeID},
 		api.EventUpdateTask{Task: &api.Task{NodeID: nodeID},
 			Checks: []api.TaskCheckFunc{api.TaskCheckNodeID}},
 			Checks: []api.TaskCheckFunc{api.TaskCheckNodeID}},
 		api.EventDeleteTask{Task: &api.Task{NodeID: nodeID},
 		api.EventDeleteTask{Task: &api.Task{NodeID: nodeID},
 			Checks: []api.TaskCheckFunc{api.TaskCheckNodeID}},
 			Checks: []api.TaskCheckFunc{api.TaskCheckNodeID}},
-		api.EventUpdateSecret{},
-		api.EventDeleteSecret{},
 	)
 	)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 	defer cancel()
 	defer cancel()
 
 
-	if err := sendMessage(initial, api.AssignmentsMessage_COMPLETE); err != nil {
+	if err := sendMessage(assignments.message(), api.AssignmentsMessage_COMPLETE); err != nil {
 		return err
 		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
 		// bursty events should be processed in batches and sent out together
 		var (
 		var (
-			update          api.AssignmentsMessage
 			modificationCnt int
 			modificationCnt int
 			batchingTimer   *time.Timer
 			batchingTimer   *time.Timer
 			batchingTimeout <-chan time.Time
 			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() {
 		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
 		// The batching loop waits for 50 ms after the most recent
 		// change, or until modificationBatchLimit is reached. The
 		// change, or until modificationBatchLimit is reached. The
 		// worst case latency is modificationBatchLimit * batchingWaitTime,
 		// 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
 				// them to ASSIGNED. If this ever changes, we will need
 				// to monitor task creations as well.
 				// to monitor task creations as well.
 				case api.EventUpdateTask:
 				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:
 				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:
 			case <-batchingTimeout:
 				break batchingLoop
 				break batchingLoop
@@ -1083,72 +937,7 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 		}
 		}
 
 
 		if modificationCnt > 0 {
 		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
 				return err
 			}
 			}
 		}
 		}
@@ -1284,6 +1073,12 @@ func (d *Dispatcher) getNetworkBootstrapKeys() []*api.EncryptionKey {
 	return d.networkBootstrapKeys
 	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.
 // Session is a stream which controls agent connection.
 // Each message contains list of backup Managers with weights. Also there is
 // Each message contains list of backup Managers with weights. Also there is
 // a special boolean field Disconnect which if true indicates that node should
 // 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,
 		Node:                 nodeObj,
 		Managers:             d.getManagers(),
 		Managers:             d.getManagers(),
 		NetworkBootstrapKeys: d.getNetworkBootstrapKeys(),
 		NetworkBootstrapKeys: d.getNetworkBootstrapKeys(),
+		RootCA:               d.getRootCACert(),
 	}); err != nil {
 	}); err != nil {
 		return err
 		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 is a helper forcibly shutdown connection
 	disconnectNode := func() error {
 	disconnectNode := func() error {
@@ -1396,11 +1190,21 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 			disconnect bool
 			disconnect bool
 			mgrs       []*api.WeightedPeer
 			mgrs       []*api.WeightedPeer
 			netKeys    []*api.EncryptionKey
 			netKeys    []*api.EncryptionKey
+			rootCert   []byte
 		)
 		)
 
 
 		select {
 		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:
 		case ev := <-nodeUpdates:
 			nodeObj = ev.(api.EventUpdateNode).Node
 			nodeObj = ev.(api.EventUpdateNode).Node
 		case <-stream.Context().Done():
 		case <-stream.Context().Done():
@@ -1409,8 +1213,6 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 			disconnect = true
 			disconnect = true
 		case <-dctx.Done():
 		case <-dctx.Done():
 			disconnect = true
 			disconnect = true
-		case ev := <-keyMgrUpdates:
-			netKeys = ev.([]*api.EncryptionKey)
 		}
 		}
 		if mgrs == nil {
 		if mgrs == nil {
 			mgrs = d.getManagers()
 			mgrs = d.getManagers()
@@ -1418,12 +1220,16 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 		if netKeys == nil {
 		if netKeys == nil {
 			netKeys = d.getNetworkBootstrapKeys()
 			netKeys = d.getNetworkBootstrapKeys()
 		}
 		}
+		if rootCert == nil {
+			rootCert = d.getRootCACert()
+		}
 
 
 		if err := stream.Send(&api.SessionMessage{
 		if err := stream.Send(&api.SessionMessage{
 			SessionID:            sessionID,
 			SessionID:            sessionID,
 			Node:                 nodeObj,
 			Node:                 nodeObj,
 			Managers:             mgrs,
 			Managers:             mgrs,
 			NetworkBootstrapKeys: netKeys,
 			NetworkBootstrapKeys: netKeys,
+			RootCA:               rootCert,
 		}); err != nil {
 		}); err != nil {
 			return err
 			return err
 		}
 		}

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

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

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

@@ -5,6 +5,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/api"
+	"github.com/docker/swarmkit/api/defaults"
 	"github.com/docker/swarmkit/identity"
 	"github.com/docker/swarmkit/identity"
 	"github.com/docker/swarmkit/protobuf/ptypes"
 	"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.
 // RestartCondition returns the restart condition to apply to this task.
 func RestartCondition(task *api.Task) api.RestartPolicy_RestartCondition {
 func RestartCondition(task *api.Task) api.RestartPolicy_RestartCondition {
-	restartCondition := api.RestartOnAny
+	restartCondition := defaults.Service.Task.Restart.Condition
 	if task.Spec.Restart != nil {
 	if task.Spec.Restart != nil {
 		restartCondition = task.Spec.Restart.Condition
 		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)
 		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
 	updateConfig := service.Spec.Update
 	if service.UpdateStatus != nil && service.UpdateStatus.State == api.UpdateStatus_ROLLBACK_STARTED {
 	if service.UpdateStatus != nil && service.UpdateStatus.State == api.UpdateStatus_ROLLBACK_STARTED {
+		monitoringPeriod, _ = gogotypes.DurationFromProto(defaults.Service.Rollback.Monitor)
 		updateConfig = service.Spec.Rollback
 		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)
 	wg.Add(parallelism)
 	for i := 0; i < parallelism; i++ {
 	for i := 0; i < parallelism; i++ {
 		go func() {
 		go func() {
-			u.worker(ctx, slotQueue, delay, order)
+			u.worker(ctx, slotQueue, updateConfig)
 			wg.Done()
 			wg.Done()
 		}()
 		}()
 	}
 	}
 
 
 	var failedTaskWatch chan events.Event
 	var failedTaskWatch chan events.Event
 
 
-	if failureAction != api.UpdateConfig_CONTINUE {
+	if updateConfig.FailureAction != api.UpdateConfig_CONTINUE {
 		var cancelWatch func()
 		var cancelWatch func()
 		failedTaskWatch, cancelWatch = state.Watch(
 		failedTaskWatch, cancelWatch = state.Watch(
 			u.store.WatchQueue(),
 			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) {
 		if found && (startedAt.IsZero() || time.Since(startedAt) <= monitoringPeriod) {
 			failedTasks[failedTask.ID] = struct{}{}
 			failedTasks[failedTask.ID] = struct{}{}
 			totalFailures++
 			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:
 				case api.UpdateConfig_PAUSE:
 					stopped = true
 					stopped = true
 					message := fmt.Sprintf("update paused due to failure or early termination of task %s", failedTask.ID)
 					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 {
 	for slot := range queue {
 		// Do we have a task with the new spec in desired state = RUNNING?
 		// 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
 		// 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
 			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")
 				log.G(ctx).WithError(err).WithField("task.id", updated.ID).Error("update failed")
 			}
 			}
 		}
 		}
 
 
-		if delay != 0 {
+		if updateConfig.Delay != 0 {
 			select {
 			select {
-			case <-time.After(delay):
+			case <-time.After(updateConfig.Delay):
 			case <-u.stopChan:
 			case <-u.stopChan:
 				return
 				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)
 	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
 type byKind string
 
 
 func (b byKind) isBy() {
 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"
 	indexMembership   = "membership"
 	indexNetwork      = "network"
 	indexNetwork      = "network"
 	indexSecret       = "secret"
 	indexSecret       = "secret"
+	indexConfig       = "config"
 	indexKind         = "kind"
 	indexKind         = "kind"
 	indexCustom       = "custom"
 	indexCustom       = "custom"
 
 
@@ -696,6 +697,12 @@ func (tx readTx) findIterators(table string, by By, checkType func(By) error) ([
 			return nil, err
 			return nil, err
 		}
 		}
 		return []memdb.ResultIterator{it}, nil
 		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:
 	case byKind:
 		it, err := tx.memDBTx.Get(table, indexKind, string(v))
 		it, err := tx.memDBTx.Get(table, indexKind, string(v))
 		if err != nil {
 		if err != nil {

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

@@ -40,6 +40,11 @@ func init() {
 					AllowMissing: true,
 					AllowMissing: true,
 					Indexer:      serviceIndexerBySecret{},
 					Indexer:      serviceIndexerBySecret{},
 				},
 				},
+				indexConfig: {
+					Name:         indexConfig,
+					AllowMissing: true,
+					Indexer:      serviceIndexerByConfig{},
+				},
 				indexCustom: {
 				indexCustom: {
 					Name:         indexCustom,
 					Name:         indexCustom,
 					Indexer:      api.ServiceCustomIndexer{},
 					Indexer:      api.ServiceCustomIndexer{},
@@ -131,7 +136,7 @@ func GetService(tx ReadTx, id string) *api.Service {
 func FindServices(tx ReadTx, by By) ([]*api.Service, error) {
 func FindServices(tx ReadTx, by By) ([]*api.Service, error) {
 	checkType := func(by By) error {
 	checkType := func(by By) error {
 		switch by.(type) {
 		switch by.(type) {
-		case byName, byNamePrefix, byIDPrefix, byRuntime, byReferencedNetworkID, byReferencedSecretID, byCustom, byCustomPrefix:
+		case byName, byNamePrefix, byIDPrefix, byRuntime, byReferencedNetworkID, byReferencedSecretID, byReferencedConfigID, byCustom, byCustomPrefix:
 			return nil
 			return nil
 		default:
 		default:
 			return ErrInvalidFindBy
 			return ErrInvalidFindBy
@@ -214,3 +219,30 @@ func (si serviceIndexerBySecret) FromObject(obj interface{}) (bool, [][]byte, er
 
 
 	return len(secretIDs) != 0, secretIDs, nil
 	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,
 					AllowMissing: true,
 					Indexer:      taskIndexerBySecret{},
 					Indexer:      taskIndexerBySecret{},
 				},
 				},
+				indexConfig: {
+					Name:         indexConfig,
+					AllowMissing: true,
+					Indexer:      taskIndexerByConfig{},
+				},
 				indexCustom: {
 				indexCustom: {
 					Name:         indexCustom,
 					Name:         indexCustom,
 					Indexer:      api.TaskCustomIndexer{},
 					Indexer:      api.TaskCustomIndexer{},
@@ -143,7 +148,7 @@ func GetTask(tx ReadTx, id string) *api.Task {
 func FindTasks(tx ReadTx, by By) ([]*api.Task, error) {
 func FindTasks(tx ReadTx, by By) ([]*api.Task, error) {
 	checkType := func(by By) error {
 	checkType := func(by By) error {
 		switch by.(type) {
 		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
 			return nil
 		default:
 		default:
 			return ErrInvalidFindBy
 			return ErrInvalidFindBy
@@ -295,6 +300,33 @@ func (ti taskIndexerBySecret) FromObject(obj interface{}) (bool, [][]byte, error
 	return len(secretIDs) != 0, secretIDs, nil
 	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{}
 type taskIndexerByTaskState struct{}
 
 
 func (ts taskIndexerByTaskState) FromArgs(args ...interface{}) ([]byte, error) {
 func (ts taskIndexerByTaskState) FromArgs(args ...interface{}) ([]byte, error) {

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

@@ -1,6 +1,7 @@
 package node
 package node
 
 
 import (
 import (
+	"bytes"
 	"crypto/tls"
 	"crypto/tls"
 	"encoding/json"
 	"encoding/json"
 	"io/ioutil"
 	"io/ioutil"
@@ -25,6 +26,7 @@ import (
 	"github.com/docker/swarmkit/manager"
 	"github.com/docker/swarmkit/manager"
 	"github.com/docker/swarmkit/manager/encryption"
 	"github.com/docker/swarmkit/manager/encryption"
 	"github.com/docker/swarmkit/remotes"
 	"github.com/docker/swarmkit/remotes"
+	"github.com/docker/swarmkit/watch"
 	"github.com/docker/swarmkit/xnet"
 	"github.com/docker/swarmkit/xnet"
 	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
 	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
@@ -129,7 +131,7 @@ type Node struct {
 	err              error
 	err              error
 	agent            *agent.Agent
 	agent            *agent.Agent
 	manager          *manager.Manager
 	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
 	unlockKey        []byte
 }
 }
 
 
@@ -172,7 +174,7 @@ func New(c *Config) (*Node, error) {
 		stopped:          make(chan struct{}),
 		stopped:          make(chan struct{}),
 		closed:           make(chan struct{}),
 		closed:           make(chan struct{}),
 		ready:            make(chan struct{}),
 		ready:            make(chan struct{}),
-		notifyNodeChange: make(chan *api.Node, 1),
+		notifyNodeChange: make(chan *agent.NodeChanges, 1),
 		unlockKey:        c.UnlockKey,
 		unlockKey:        c.UnlockKey,
 	}
 	}
 
 
@@ -235,7 +237,8 @@ func (n *Node) run(ctx context.Context) (err error) {
 		}
 		}
 	}(ctx)
 	}(ctx)
 
 
-	securityConfig, err := n.loadSecurityConfig(ctx)
+	paths := ca.NewConfigPaths(filepath.Join(n.config.StateDir, certDirectory))
+	securityConfig, err := n.loadSecurityConfig(ctx, paths)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -274,24 +277,44 @@ func (n *Node) run(ctx context.Context) (err error) {
 			select {
 			select {
 			case <-agentDone:
 			case <-agentDone:
 				return
 				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()
 				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 managerErr error
 	var agentErr error
 	var agentErr error
 	go func() {
 	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()
 		wg.Done()
 		cancel()
 		cancel()
 	}()
 	}()
 	go func() {
 	go func() {
-		agentErr = n.runAgent(ctx, db, securityConfig.ClientTLSCreds, agentReady)
+		agentErr = n.runAgent(ctx, db, securityConfig, agentReady)
 		wg.Done()
 		wg.Done()
 		cancel()
 		cancel()
 		close(agentDone)
 		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)
 	waitCtx, waitCancel := context.WithCancel(ctx)
 	remotesCh := n.remotes.WaitSelect(ctx)
 	remotesCh := n.remotes.WaitSelect(ctx)
 	controlCh := n.ListenControlSocket(waitCtx)
 	controlCh := n.ListenControlSocket(waitCtx)
@@ -428,13 +451,28 @@ waitPeer:
 	default:
 	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{
 	a, err := agent.New(&agent.Config{
 		Hostname:         n.config.Hostname,
 		Hostname:         n.config.Hostname,
 		ConnBroker:       n.connBroker,
 		ConnBroker:       n.connBroker,
 		Executor:         n.config.Executor,
 		Executor:         n.config.Executor,
 		DB:               db,
 		DB:               db,
 		NotifyNodeChange: n.notifyNodeChange,
 		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 {
 	if err != nil {
 		return err
 		return err
@@ -565,8 +603,7 @@ func (n *Node) Remotes() []api.Peer {
 	return remotes
 	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
 	var securityConfig *ca.SecurityConfig
 
 
 	krw := ca.NewKeyReadWriter(paths.Node, n.unlockKey, &manager.RaftDEKData{})
 	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
 	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
 	var remoteAPI *manager.RemoteAddrs
 	if n.config.ListenRemoteAPI != "" {
 	if n.config.ListenRemoteAPI != "" {
 		remoteAPI = &manager.RemoteAddrs{
 		remoteAPI = &manager.RemoteAddrs{
@@ -741,6 +778,7 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
 		UnlockKey:        n.unlockKey,
 		UnlockKey:        n.unlockKey,
 		Availability:     n.config.Availability,
 		Availability:     n.config.Availability,
 		PluginGetter:     n.config.PluginGetter,
 		PluginGetter:     n.config.PluginGetter,
+		RootCAPaths:      rootPaths,
 	})
 	})
 	if err != nil {
 	if err != nil {
 		return false, err
 		return false, err
@@ -789,7 +827,7 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
 	return clearData, nil
 	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 {
 	for {
 		if err := n.waitRole(ctx, ca.ManagerRole); err != nil {
 		if err := n.waitRole(ctx, ca.ManagerRole); err != nil {
 			return err
 			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 {
 		if err != nil {
 			waitRoleCancel()
 			waitRoleCancel()
 			return errors.Wrap(err, "manager stopped")
 			return errors.Wrap(err, "manager stopped")

部分文件因文件數量過多而無法顯示