Quellcode durchsuchen

vendor: update dependencies for go-digest

Signed-off-by: Stephen J Day <stephen.day@docker.com>
Stephen J Day vor 8 Jahren
Ursprung
Commit
083ad52f60
37 geänderte Dateien mit 681 neuen und 441 gelöschten Zeilen
  1. 3 2
      vendor.conf
  2. 1 1
      vendor/github.com/docker/distribution/blobs.go
  3. 16 14
      vendor/github.com/docker/distribution/digestset/set.go
  4. 1 1
      vendor/github.com/docker/distribution/errors.go
  5. 1 1
      vendor/github.com/docker/distribution/manifest/manifestlist/manifestlist.go
  6. 1 1
      vendor/github.com/docker/distribution/manifest/schema1/config_builder.go
  7. 1 1
      vendor/github.com/docker/distribution/manifest/schema1/manifest.go
  8. 1 1
      vendor/github.com/docker/distribution/manifest/schema1/reference_builder.go
  9. 1 1
      vendor/github.com/docker/distribution/manifest/schema2/builder.go
  10. 1 1
      vendor/github.com/docker/distribution/manifest/schema2/manifest.go
  11. 1 1
      vendor/github.com/docker/distribution/manifests.go
  12. 2 2
      vendor/github.com/docker/distribution/reference/reference.go
  13. 1 1
      vendor/github.com/docker/distribution/registry/api/v2/descriptors.go
  14. 5 5
      vendor/github.com/docker/distribution/registry/client/repository.go
  15. 1 1
      vendor/github.com/docker/distribution/registry/storage/cache/cachedblobdescriptorstore.go
  16. 1 1
      vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go
  17. 10 9
      vendor/github.com/docker/swarmkit/agent/worker.go
  18. 116 75
      vendor/github.com/docker/swarmkit/api/objects.pb.go
  19. 11 0
      vendor/github.com/docker/swarmkit/api/objects.proto
  20. 116 116
      vendor/github.com/docker/swarmkit/api/specs.pb.go
  21. 2 2
      vendor/github.com/docker/swarmkit/api/specs.proto
  22. 2 2
      vendor/github.com/docker/swarmkit/ca/certificates.go
  23. 2 2
      vendor/github.com/docker/swarmkit/ca/config.go
  24. 4 3
      vendor/github.com/docker/swarmkit/ca/server.go
  25. 1 1
      vendor/github.com/docker/swarmkit/manager/constraint/constraint.go
  26. 3 16
      vendor/github.com/docker/swarmkit/manager/controlapi/node.go
  27. 32 22
      vendor/github.com/docker/swarmkit/manager/manager.go
  28. 167 0
      vendor/github.com/docker/swarmkit/manager/role_manager.go
  29. 55 44
      vendor/github.com/docker/swarmkit/manager/state/raft/raft.go
  30. 6 2
      vendor/github.com/docker/swarmkit/manager/state/raft/wait.go
  31. 1 1
      vendor/github.com/docker/swarmkit/manager/state/store/nodes.go
  32. 52 40
      vendor/github.com/docker/swarmkit/node/node.go
  33. 15 31
      vendor/github.com/opencontainers/go-digest/algorithm.go
  34. 23 27
      vendor/github.com/opencontainers/go-digest/digest.go
  35. 25 0
      vendor/github.com/opencontainers/go-digest/digester.go
  36. 0 0
      vendor/github.com/opencontainers/go-digest/doc.go
  37. 0 13
      vendor/github.com/opencontainers/go-digest/verifiers.go

+ 3 - 2
vendor.conf

@@ -44,8 +44,9 @@ github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
 github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
 github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
 
 
 # get graph and distribution packages
 # get graph and distribution packages
-github.com/docker/distribution 28602af35aceda2f8d571bad7ca37a54cf0250bc
+github.com/docker/distribution 7dba427612198a11b161a27f9d40bb2dca1ccd20
 github.com/vbatts/tar-split v0.10.1
 github.com/vbatts/tar-split v0.10.1
+github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
 
 
 # get go-zfs packages
 # get go-zfs packages
 github.com/mistifyio/go-zfs 22c9b32c84eb0d0c6f4043b6e90fc94073de92fa
 github.com/mistifyio/go-zfs 22c9b32c84eb0d0c6f4043b6e90fc94073de92fa
@@ -102,7 +103,7 @@ github.com/docker/containerd 03e5862ec0d8d3b3f750e19fca3ee367e13c090e
 github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4
 github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4
 
 
 # cluster
 # cluster
-github.com/docker/swarmkit 2e956c40c02ad527c90ec85bdae25a0acac1bd87
+github.com/docker/swarmkit 4762d92234d286ae7c9e061470485e4d34ef8ebd
 github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9
 github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9
 github.com/gogo/protobuf v0.3
 github.com/gogo/protobuf v0.3
 github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
 github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a

+ 1 - 1
vendor/github.com/docker/distribution/blobs.go

@@ -8,8 +8,8 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/docker/distribution/context"
 	"github.com/docker/distribution/context"
-	"github.com/docker/distribution/digest"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/reference"
+	"github.com/opencontainers/go-digest"
 )
 )
 
 
 var (
 var (

+ 16 - 14
vendor/github.com/docker/distribution/digest/set.go → vendor/github.com/docker/distribution/digestset/set.go

@@ -1,10 +1,12 @@
-package digest
+package digestset
 
 
 import (
 import (
 	"errors"
 	"errors"
 	"sort"
 	"sort"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
+
+	digest "github.com/opencontainers/go-digest"
 )
 )
 
 
 var (
 var (
@@ -44,7 +46,7 @@ func NewSet() *Set {
 // values or short values. This function does not test equality,
 // values or short values. This function does not test equality,
 // rather whether the second value could match against the first
 // rather whether the second value could match against the first
 // value.
 // value.
-func checkShortMatch(alg Algorithm, hex, shortAlg, shortHex string) bool {
+func checkShortMatch(alg digest.Algorithm, hex, shortAlg, shortHex string) bool {
 	if len(hex) == len(shortHex) {
 	if len(hex) == len(shortHex) {
 		if hex != shortHex {
 		if hex != shortHex {
 			return false
 			return false
@@ -64,7 +66,7 @@ func checkShortMatch(alg Algorithm, hex, shortAlg, shortHex string) bool {
 // If no digests could be found ErrDigestNotFound will be returned
 // If no digests could be found ErrDigestNotFound will be returned
 // with an empty digest value. If multiple matches are found
 // with an empty digest value. If multiple matches are found
 // ErrDigestAmbiguous will be returned with an empty digest value.
 // ErrDigestAmbiguous will be returned with an empty digest value.
-func (dst *Set) Lookup(d string) (Digest, error) {
+func (dst *Set) Lookup(d string) (digest.Digest, error) {
 	dst.mutex.RLock()
 	dst.mutex.RLock()
 	defer dst.mutex.RUnlock()
 	defer dst.mutex.RUnlock()
 	if len(dst.entries) == 0 {
 	if len(dst.entries) == 0 {
@@ -72,11 +74,11 @@ func (dst *Set) Lookup(d string) (Digest, error) {
 	}
 	}
 	var (
 	var (
 		searchFunc func(int) bool
 		searchFunc func(int) bool
-		alg        Algorithm
+		alg        digest.Algorithm
 		hex        string
 		hex        string
 	)
 	)
-	dgst, err := ParseDigest(d)
-	if err == ErrDigestInvalidFormat {
+	dgst, err := digest.Parse(d)
+	if err == digest.ErrDigestInvalidFormat {
 		hex = d
 		hex = d
 		searchFunc = func(i int) bool {
 		searchFunc = func(i int) bool {
 			return dst.entries[i].val >= d
 			return dst.entries[i].val >= d
@@ -108,7 +110,7 @@ func (dst *Set) Lookup(d string) (Digest, error) {
 // Add adds the given digest to the set. An error will be returned
 // Add adds the given digest to the set. An error will be returned
 // if the given digest is invalid. If the digest already exists in the
 // if the given digest is invalid. If the digest already exists in the
 // set, this operation will be a no-op.
 // set, this operation will be a no-op.
-func (dst *Set) Add(d Digest) error {
+func (dst *Set) Add(d digest.Digest) error {
 	if err := d.Validate(); err != nil {
 	if err := d.Validate(); err != nil {
 		return err
 		return err
 	}
 	}
@@ -139,7 +141,7 @@ func (dst *Set) Add(d Digest) error {
 // Remove removes the given digest from the set. An err will be
 // Remove removes the given digest from the set. An err will be
 // returned if the given digest is invalid. If the digest does
 // returned if the given digest is invalid. If the digest does
 // not exist in the set, this operation will be a no-op.
 // not exist in the set, this operation will be a no-op.
-func (dst *Set) Remove(d Digest) error {
+func (dst *Set) Remove(d digest.Digest) error {
 	if err := d.Validate(); err != nil {
 	if err := d.Validate(); err != nil {
 		return err
 		return err
 	}
 	}
@@ -167,10 +169,10 @@ func (dst *Set) Remove(d Digest) error {
 }
 }
 
 
 // All returns all the digests in the set
 // All returns all the digests in the set
-func (dst *Set) All() []Digest {
+func (dst *Set) All() []digest.Digest {
 	dst.mutex.RLock()
 	dst.mutex.RLock()
 	defer dst.mutex.RUnlock()
 	defer dst.mutex.RUnlock()
-	retValues := make([]Digest, len(dst.entries))
+	retValues := make([]digest.Digest, len(dst.entries))
 	for i := range dst.entries {
 	for i := range dst.entries {
 		retValues[i] = dst.entries[i].digest
 		retValues[i] = dst.entries[i].digest
 	}
 	}
@@ -183,10 +185,10 @@ func (dst *Set) All() []Digest {
 // entire value of digest if uniqueness cannot be achieved without the
 // entire value of digest if uniqueness cannot be achieved without the
 // full value. This function will attempt to make short codes as short
 // full value. This function will attempt to make short codes as short
 // as possible to be unique.
 // as possible to be unique.
-func ShortCodeTable(dst *Set, length int) map[Digest]string {
+func ShortCodeTable(dst *Set, length int) map[digest.Digest]string {
 	dst.mutex.RLock()
 	dst.mutex.RLock()
 	defer dst.mutex.RUnlock()
 	defer dst.mutex.RUnlock()
-	m := make(map[Digest]string, len(dst.entries))
+	m := make(map[digest.Digest]string, len(dst.entries))
 	l := length
 	l := length
 	resetIdx := 0
 	resetIdx := 0
 	for i := 0; i < len(dst.entries); i++ {
 	for i := 0; i < len(dst.entries); i++ {
@@ -222,9 +224,9 @@ func ShortCodeTable(dst *Set, length int) map[Digest]string {
 }
 }
 
 
 type digestEntry struct {
 type digestEntry struct {
-	alg    Algorithm
+	alg    digest.Algorithm
 	val    string
 	val    string
-	digest Digest
+	digest digest.Digest
 }
 }
 
 
 type digestEntries []*digestEntry
 type digestEntries []*digestEntry

+ 1 - 1
vendor/github.com/docker/distribution/errors.go

@@ -5,7 +5,7 @@ import (
 	"fmt"
 	"fmt"
 	"strings"
 	"strings"
 
 
-	"github.com/docker/distribution/digest"
+	"github.com/opencontainers/go-digest"
 )
 )
 
 
 // ErrAccessDenied is returned when an access to a requested resource is
 // ErrAccessDenied is returned when an access to a requested resource is

+ 1 - 1
vendor/github.com/docker/distribution/manifest/manifestlist/manifestlist.go

@@ -6,8 +6,8 @@ import (
 	"fmt"
 	"fmt"
 
 
 	"github.com/docker/distribution"
 	"github.com/docker/distribution"
-	"github.com/docker/distribution/digest"
 	"github.com/docker/distribution/manifest"
 	"github.com/docker/distribution/manifest"
+	"github.com/opencontainers/go-digest"
 )
 )
 
 
 // MediaTypeManifestList specifies the mediaType for manifest lists.
 // MediaTypeManifestList specifies the mediaType for manifest lists.

+ 1 - 1
vendor/github.com/docker/distribution/manifest/schema1/config_builder.go

@@ -9,10 +9,10 @@ import (
 
 
 	"github.com/docker/distribution"
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/context"
 	"github.com/docker/distribution/context"
-	"github.com/docker/distribution/digest"
 	"github.com/docker/distribution/manifest"
 	"github.com/docker/distribution/manifest"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/libtrust"
 	"github.com/docker/libtrust"
+	"github.com/opencontainers/go-digest"
 )
 )
 
 
 type diffID digest.Digest
 type diffID digest.Digest

+ 1 - 1
vendor/github.com/docker/distribution/manifest/schema1/manifest.go

@@ -5,9 +5,9 @@ import (
 	"fmt"
 	"fmt"
 
 
 	"github.com/docker/distribution"
 	"github.com/docker/distribution"
-	"github.com/docker/distribution/digest"
 	"github.com/docker/distribution/manifest"
 	"github.com/docker/distribution/manifest"
 	"github.com/docker/libtrust"
 	"github.com/docker/libtrust"
+	"github.com/opencontainers/go-digest"
 )
 )
 
 
 const (
 const (

+ 1 - 1
vendor/github.com/docker/distribution/manifest/schema1/reference_builder.go

@@ -6,10 +6,10 @@ import (
 	"errors"
 	"errors"
 	"github.com/docker/distribution"
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/context"
 	"github.com/docker/distribution/context"
-	"github.com/docker/distribution/digest"
 	"github.com/docker/distribution/manifest"
 	"github.com/docker/distribution/manifest"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/libtrust"
 	"github.com/docker/libtrust"
+	"github.com/opencontainers/go-digest"
 )
 )
 
 
 // referenceManifestBuilder is a type for constructing manifests from schema1
 // referenceManifestBuilder is a type for constructing manifests from schema1

+ 1 - 1
vendor/github.com/docker/distribution/manifest/schema2/builder.go

@@ -3,7 +3,7 @@ package schema2
 import (
 import (
 	"github.com/docker/distribution"
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/context"
 	"github.com/docker/distribution/context"
-	"github.com/docker/distribution/digest"
+	"github.com/opencontainers/go-digest"
 )
 )
 
 
 // builder is a type for constructing manifests.
 // builder is a type for constructing manifests.

+ 1 - 1
vendor/github.com/docker/distribution/manifest/schema2/manifest.go

@@ -6,8 +6,8 @@ import (
 	"fmt"
 	"fmt"
 
 
 	"github.com/docker/distribution"
 	"github.com/docker/distribution"
-	"github.com/docker/distribution/digest"
 	"github.com/docker/distribution/manifest"
 	"github.com/docker/distribution/manifest"
+	"github.com/opencontainers/go-digest"
 )
 )
 
 
 const (
 const (

+ 1 - 1
vendor/github.com/docker/distribution/manifests.go

@@ -5,7 +5,7 @@ import (
 	"mime"
 	"mime"
 
 
 	"github.com/docker/distribution/context"
 	"github.com/docker/distribution/context"
-	"github.com/docker/distribution/digest"
+	"github.com/opencontainers/go-digest"
 )
 )
 
 
 // Manifest represents a registry object specifying a set of
 // Manifest represents a registry object specifying a set of

+ 2 - 2
vendor/github.com/docker/distribution/reference/reference.go

@@ -27,7 +27,7 @@ import (
 	"path"
 	"path"
 	"strings"
 	"strings"
 
 
-	"github.com/docker/distribution/digest"
+	"github.com/opencontainers/go-digest"
 )
 )
 
 
 const (
 const (
@@ -170,7 +170,7 @@ func Parse(s string) (Reference, error) {
 	}
 	}
 	if matches[3] != "" {
 	if matches[3] != "" {
 		var err error
 		var err error
-		ref.digest, err = digest.ParseDigest(matches[3])
+		ref.digest, err = digest.Parse(matches[3])
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}

+ 1 - 1
vendor/github.com/docker/distribution/registry/api/v2/descriptors.go

@@ -4,9 +4,9 @@ import (
 	"net/http"
 	"net/http"
 	"regexp"
 	"regexp"
 
 
-	"github.com/docker/distribution/digest"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/registry/api/errcode"
 	"github.com/docker/distribution/registry/api/errcode"
+	"github.com/opencontainers/go-digest"
 )
 )
 
 
 var (
 var (

+ 5 - 5
vendor/github.com/docker/distribution/registry/client/repository.go

@@ -15,12 +15,12 @@ import (
 
 
 	"github.com/docker/distribution"
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/context"
 	"github.com/docker/distribution/context"
-	"github.com/docker/distribution/digest"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/registry/api/v2"
 	"github.com/docker/distribution/registry/api/v2"
 	"github.com/docker/distribution/registry/client/transport"
 	"github.com/docker/distribution/registry/client/transport"
 	"github.com/docker/distribution/registry/storage/cache"
 	"github.com/docker/distribution/registry/storage/cache"
 	"github.com/docker/distribution/registry/storage/cache/memory"
 	"github.com/docker/distribution/registry/storage/cache/memory"
+	"github.com/opencontainers/go-digest"
 )
 )
 
 
 // Registry provides an interface for calling Repositories, which returns a catalog of repositories.
 // Registry provides an interface for calling Repositories, which returns a catalog of repositories.
@@ -268,7 +268,7 @@ func descriptorFromResponse(response *http.Response) (distribution.Descriptor, e
 		return desc, nil
 		return desc, nil
 	}
 	}
 
 
-	dgst, err := digest.ParseDigest(digestHeader)
+	dgst, err := digest.Parse(digestHeader)
 	if err != nil {
 	if err != nil {
 		return distribution.Descriptor{}, err
 		return distribution.Descriptor{}, err
 	}
 	}
@@ -475,7 +475,7 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis
 		return nil, distribution.ErrManifestNotModified
 		return nil, distribution.ErrManifestNotModified
 	} else if SuccessStatus(resp.StatusCode) {
 	} else if SuccessStatus(resp.StatusCode) {
 		if contentDgst != nil {
 		if contentDgst != nil {
-			dgst, err := digest.ParseDigest(resp.Header.Get("Docker-Content-Digest"))
+			dgst, err := digest.Parse(resp.Header.Get("Docker-Content-Digest"))
 			if err == nil {
 			if err == nil {
 				*contentDgst = dgst
 				*contentDgst = dgst
 			}
 			}
@@ -553,7 +553,7 @@ func (ms *manifests) Put(ctx context.Context, m distribution.Manifest, options .
 
 
 	if SuccessStatus(resp.StatusCode) {
 	if SuccessStatus(resp.StatusCode) {
 		dgstHeader := resp.Header.Get("Docker-Content-Digest")
 		dgstHeader := resp.Header.Get("Docker-Content-Digest")
-		dgst, err := digest.ParseDigest(dgstHeader)
+		dgst, err := digest.Parse(dgstHeader)
 		if err != nil {
 		if err != nil {
 			return "", err
 			return "", err
 		}
 		}
@@ -661,7 +661,7 @@ func (bs *blobs) Put(ctx context.Context, mediaType string, p []byte) (distribut
 	if err != nil {
 	if err != nil {
 		return distribution.Descriptor{}, err
 		return distribution.Descriptor{}, err
 	}
 	}
-	dgstr := digest.Canonical.New()
+	dgstr := digest.Canonical.Digester()
 	n, err := io.Copy(writer, io.TeeReader(bytes.NewReader(p), dgstr.Hash()))
 	n, err := io.Copy(writer, io.TeeReader(bytes.NewReader(p), dgstr.Hash()))
 	if err != nil {
 	if err != nil {
 		return distribution.Descriptor{}, err
 		return distribution.Descriptor{}, err

+ 1 - 1
vendor/github.com/docker/distribution/registry/storage/cache/cachedblobdescriptorstore.go

@@ -2,7 +2,7 @@ package cache
 
 
 import (
 import (
 	"github.com/docker/distribution/context"
 	"github.com/docker/distribution/context"
-	"github.com/docker/distribution/digest"
+	"github.com/opencontainers/go-digest"
 
 
 	"github.com/docker/distribution"
 	"github.com/docker/distribution"
 )
 )

+ 1 - 1
vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go

@@ -5,9 +5,9 @@ import (
 
 
 	"github.com/docker/distribution"
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/context"
 	"github.com/docker/distribution/context"
-	"github.com/docker/distribution/digest"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/registry/storage/cache"
 	"github.com/docker/distribution/registry/storage/cache"
+	"github.com/opencontainers/go-digest"
 )
 )
 
 
 type inMemoryBlobDescriptorCacheProvider struct {
 type inMemoryBlobDescriptorCacheProvider struct {

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

@@ -302,15 +302,6 @@ func reconcileTaskState(ctx context.Context, w *worker, assignments []*api.Assig
 }
 }
 
 
 func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.AssignmentChange, fullSnapshot bool) error {
 func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.AssignmentChange, fullSnapshot bool) error {
-	var secrets exec.SecretsManager
-	provider, ok := w.executor.(exec.SecretsProvider)
-	if !ok {
-		log.G(ctx).Warn("secrets update ignored; executor does not support secrets")
-		return nil
-	}
-
-	secrets = provider.Secrets()
-
 	var (
 	var (
 		updatedSecrets []api.Secret
 		updatedSecrets []api.Secret
 		removedSecrets []string
 		removedSecrets []string
@@ -327,6 +318,16 @@ func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.Assignm
 		}
 		}
 	}
 	}
 
 
+	provider, ok := w.executor.(exec.SecretsProvider)
+	if !ok {
+		if len(updatedSecrets) != 0 || len(removedSecrets) != 0 {
+			log.G(ctx).Warn("secrets update ignored; executor does not support secrets")
+		}
+		return nil
+	}
+
+	secrets := provider.Secrets()
+
 	log.G(ctx).WithFields(logrus.Fields{
 	log.G(ctx).WithFields(logrus.Fields{
 		"len(updatedSecrets)": len(updatedSecrets),
 		"len(updatedSecrets)": len(updatedSecrets),
 		"len(removedSecrets)": len(removedSecrets),
 		"len(removedSecrets)": len(removedSecrets),

+ 116 - 75
vendor/github.com/docker/swarmkit/api/objects.pb.go

@@ -57,6 +57,16 @@ type Node struct {
 	Attachment *NetworkAttachment `protobuf:"bytes,7,opt,name=attachment" json:"attachment,omitempty"`
 	Attachment *NetworkAttachment `protobuf:"bytes,7,opt,name=attachment" json:"attachment,omitempty"`
 	// Certificate is the TLS certificate issued for the node, if any.
 	// Certificate is the TLS certificate issued for the node, if any.
 	Certificate Certificate `protobuf:"bytes,8,opt,name=certificate" json:"certificate"`
 	Certificate Certificate `protobuf:"bytes,8,opt,name=certificate" json:"certificate"`
+	// Role is the *observed* role for this node. It differs from the
+	// desired role set in Node.Spec.Role because the role here is only
+	// updated after the Raft member list has been reconciled with the
+	// desired role from the spec.
+	//
+	// This field represents the current reconciled state. If an action is
+	// to be performed, first verify the role in the cert. This field only
+	// shows the privilege level that the CA would currently grant when
+	// issuing or renewing the node's certificate.
+	Role NodeRole `protobuf:"varint,9,opt,name=role,proto3,enum=docker.swarmkit.v1.NodeRole" json:"role,omitempty"`
 }
 }
 
 
 func (m *Node) Reset()                    { *m = Node{} }
 func (m *Node) Reset()                    { *m = Node{} }
@@ -303,6 +313,7 @@ func (m *Node) Copy() *Node {
 		ManagerStatus: m.ManagerStatus.Copy(),
 		ManagerStatus: m.ManagerStatus.Copy(),
 		Attachment:    m.Attachment.Copy(),
 		Attachment:    m.Attachment.Copy(),
 		Certificate:   *m.Certificate.Copy(),
 		Certificate:   *m.Certificate.Copy(),
+		Role:          m.Role,
 	}
 	}
 
 
 	return o
 	return o
@@ -504,7 +515,7 @@ func (this *Node) GoString() string {
 	if this == nil {
 	if this == nil {
 		return "nil"
 		return "nil"
 	}
 	}
-	s := make([]string, 0, 12)
+	s := make([]string, 0, 13)
 	s = append(s, "&api.Node{")
 	s = append(s, "&api.Node{")
 	s = append(s, "ID: "+fmt.Sprintf("%#v", this.ID)+",\n")
 	s = append(s, "ID: "+fmt.Sprintf("%#v", this.ID)+",\n")
 	s = append(s, "Meta: "+strings.Replace(this.Meta.GoString(), `&`, ``, 1)+",\n")
 	s = append(s, "Meta: "+strings.Replace(this.Meta.GoString(), `&`, ``, 1)+",\n")
@@ -520,6 +531,7 @@ func (this *Node) GoString() string {
 		s = append(s, "Attachment: "+fmt.Sprintf("%#v", this.Attachment)+",\n")
 		s = append(s, "Attachment: "+fmt.Sprintf("%#v", this.Attachment)+",\n")
 	}
 	}
 	s = append(s, "Certificate: "+strings.Replace(this.Certificate.GoString(), `&`, ``, 1)+",\n")
 	s = append(s, "Certificate: "+strings.Replace(this.Certificate.GoString(), `&`, ``, 1)+",\n")
+	s = append(s, "Role: "+fmt.Sprintf("%#v", this.Role)+",\n")
 	s = append(s, "}")
 	s = append(s, "}")
 	return strings.Join(s, "")
 	return strings.Join(s, "")
 }
 }
@@ -834,6 +846,11 @@ func (m *Node) MarshalTo(data []byte) (int, error) {
 		return 0, err
 		return 0, err
 	}
 	}
 	i += n10
 	i += n10
+	if m.Role != 0 {
+		data[i] = 0x48
+		i++
+		i = encodeVarintObjects(data, i, uint64(m.Role))
+	}
 	return i, nil
 	return i, nil
 }
 }
 
 
@@ -1451,6 +1468,9 @@ func (m *Node) Size() (n int) {
 	}
 	}
 	l = m.Certificate.Size()
 	l = m.Certificate.Size()
 	n += 1 + l + sovObjects(uint64(l))
 	n += 1 + l + sovObjects(uint64(l))
+	if m.Role != 0 {
+		n += 1 + sovObjects(uint64(m.Role))
+	}
 	return n
 	return n
 }
 }
 
 
@@ -1707,6 +1727,7 @@ func (this *Node) String() string {
 		`ManagerStatus:` + strings.Replace(fmt.Sprintf("%v", this.ManagerStatus), "ManagerStatus", "ManagerStatus", 1) + `,`,
 		`ManagerStatus:` + strings.Replace(fmt.Sprintf("%v", this.ManagerStatus), "ManagerStatus", "ManagerStatus", 1) + `,`,
 		`Attachment:` + strings.Replace(fmt.Sprintf("%v", this.Attachment), "NetworkAttachment", "NetworkAttachment", 1) + `,`,
 		`Attachment:` + strings.Replace(fmt.Sprintf("%v", this.Attachment), "NetworkAttachment", "NetworkAttachment", 1) + `,`,
 		`Certificate:` + strings.Replace(strings.Replace(this.Certificate.String(), "Certificate", "Certificate", 1), `&`, ``, 1) + `,`,
 		`Certificate:` + strings.Replace(strings.Replace(this.Certificate.String(), "Certificate", "Certificate", 1), `&`, ``, 1) + `,`,
+		`Role:` + fmt.Sprintf("%v", this.Role) + `,`,
 		`}`,
 		`}`,
 	}, "")
 	}, "")
 	return s
 	return s
@@ -2268,6 +2289,25 @@ func (m *Node) Unmarshal(data []byte) error {
 				return err
 				return err
 			}
 			}
 			iNdEx = postIndex
 			iNdEx = postIndex
+		case 9:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Role", wireType)
+			}
+			m.Role = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowObjects
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				m.Role |= (NodeRole(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
 		default:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
 			skippy, err := skipObjects(data[iNdEx:])
 			skippy, err := skipObjects(data[iNdEx:])
@@ -4186,78 +4226,79 @@ var (
 func init() { proto.RegisterFile("objects.proto", fileDescriptorObjects) }
 func init() { proto.RegisterFile("objects.proto", fileDescriptorObjects) }
 
 
 var fileDescriptorObjects = []byte{
 var fileDescriptorObjects = []byte{
-	// 1161 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x57, 0x4d, 0x8f, 0x1b, 0x35,
-	0x18, 0xee, 0x24, 0xb3, 0xf9, 0x78, 0xb3, 0x59, 0x81, 0xa9, 0xca, 0x34, 0x2c, 0xc9, 0x92, 0x0a,
-	0x54, 0xa1, 0x2a, 0x15, 0xa5, 0xa0, 0x2d, 0xb4, 0x82, 0x7c, 0x09, 0xa2, 0x52, 0xa8, 0xdc, 0xb2,
-	0x3d, 0x46, 0xde, 0x19, 0x37, 0x0c, 0x99, 0x8c, 0x47, 0xb6, 0x93, 0x2a, 0x37, 0xc4, 0x0f, 0xe0,
-	0x27, 0x20, 0xce, 0xfc, 0x09, 0xae, 0x7b, 0xe0, 0xc0, 0x0d, 0x4e, 0x11, 0x9b, 0x1b, 0x37, 0x7e,
-	0x02, 0xb2, 0xc7, 0x93, 0xcc, 0x2a, 0x93, 0x65, 0x2b, 0x55, 0x7b, 0xb3, 0xe3, 0xe7, 0x79, 0xde,
-	0xd7, 0xaf, 0x1f, 0xbf, 0xe3, 0x40, 0x95, 0x1d, 0x7f, 0x4f, 0x5d, 0x29, 0x5a, 0x11, 0x67, 0x92,
-	0x21, 0xe4, 0x31, 0x77, 0x4c, 0x79, 0x4b, 0xbc, 0x20, 0x7c, 0x32, 0xf6, 0x65, 0x6b, 0xf6, 0x41,
-	0xad, 0x22, 0xe7, 0x11, 0x35, 0x80, 0x5a, 0x45, 0x44, 0xd4, 0x4d, 0x26, 0xd7, 0xa5, 0x3f, 0xa1,
-	0x42, 0x92, 0x49, 0x74, 0x7b, 0x35, 0x32, 0x4b, 0x57, 0x47, 0x6c, 0xc4, 0xf4, 0xf0, 0xb6, 0x1a,
-	0xc5, 0xbf, 0x36, 0x7f, 0xb3, 0xc0, 0x7e, 0x44, 0x25, 0x41, 0x9f, 0x42, 0x71, 0x46, 0xb9, 0xf0,
-	0x59, 0xe8, 0x58, 0x07, 0xd6, 0xcd, 0xca, 0x9d, 0xb7, 0x5a, 0x9b, 0x91, 0x5b, 0x47, 0x31, 0xa4,
-	0x63, 0x9f, 0x2c, 0x1a, 0x57, 0x70, 0xc2, 0x40, 0xf7, 0x01, 0x5c, 0x4e, 0x89, 0xa4, 0xde, 0x90,
-	0x48, 0x27, 0xa7, 0xf9, 0x6f, 0x67, 0xf1, 0x9f, 0x26, 0x49, 0xe1, 0xb2, 0x21, 0xb4, 0xa5, 0x62,
-	0x4f, 0x23, 0x2f, 0x61, 0xe7, 0x2f, 0xc4, 0x36, 0x84, 0xb6, 0x6c, 0xfe, 0x93, 0x07, 0xfb, 0x6b,
-	0xe6, 0x51, 0x74, 0x0d, 0x72, 0xbe, 0xa7, 0x93, 0x2f, 0x77, 0x0a, 0xcb, 0x45, 0x23, 0x37, 0xe8,
-	0xe1, 0x9c, 0xef, 0xa1, 0x3b, 0x60, 0x4f, 0xa8, 0x24, 0x26, 0x2d, 0x27, 0x4b, 0x58, 0x55, 0xc0,
-	0xec, 0x49, 0x63, 0xd1, 0xc7, 0x60, 0xab, 0xb2, 0x9a, 0x64, 0xf6, 0xb3, 0x38, 0x2a, 0xe6, 0x93,
-	0x88, 0xba, 0x09, 0x4f, 0xe1, 0x51, 0x1f, 0x2a, 0x1e, 0x15, 0x2e, 0xf7, 0x23, 0xa9, 0x2a, 0x69,
-	0x6b, 0xfa, 0x8d, 0x6d, 0xf4, 0xde, 0x1a, 0x8a, 0xd3, 0x3c, 0x74, 0x1f, 0x0a, 0x42, 0x12, 0x39,
-	0x15, 0xce, 0x8e, 0x56, 0xa8, 0x6f, 0x4d, 0x40, 0xa3, 0x4c, 0x0a, 0x86, 0x83, 0xbe, 0x84, 0xbd,
-	0x09, 0x09, 0xc9, 0x88, 0xf2, 0xa1, 0x51, 0x29, 0x68, 0x95, 0x77, 0x32, 0xb7, 0x1e, 0x23, 0x63,
-	0x21, 0x5c, 0x9d, 0xa4, 0xa7, 0xa8, 0x0f, 0x40, 0xa4, 0x24, 0xee, 0x77, 0x13, 0x1a, 0x4a, 0xa7,
-	0xa8, 0x55, 0xde, 0xcd, 0xcc, 0x85, 0xca, 0x17, 0x8c, 0x8f, 0xdb, 0x2b, 0x30, 0x4e, 0x11, 0xd1,
-	0x17, 0x50, 0x71, 0x29, 0x97, 0xfe, 0x73, 0xdf, 0x25, 0x92, 0x3a, 0x25, 0xad, 0xd3, 0xc8, 0xd2,
-	0xe9, 0xae, 0x61, 0x66, 0x53, 0x69, 0x66, 0xf3, 0xcf, 0x1c, 0x14, 0x9f, 0x50, 0x3e, 0xf3, 0xdd,
-	0x57, 0x7b, 0xdc, 0xf7, 0xce, 0x1c, 0x77, 0x66, 0x66, 0x26, 0xec, 0xc6, 0x89, 0x1f, 0x42, 0x89,
-	0x86, 0x5e, 0xc4, 0xfc, 0x50, 0x9a, 0xe3, 0xce, 0x74, 0x4b, 0xdf, 0x60, 0xf0, 0x0a, 0x8d, 0xfa,
-	0x50, 0x8d, 0x5d, 0x3c, 0x3c, 0x73, 0xd6, 0x07, 0x59, 0xf4, 0x6f, 0x35, 0xd0, 0x1c, 0xd2, 0xee,
-	0x34, 0x35, 0x43, 0x3d, 0xa8, 0x46, 0x9c, 0xce, 0x7c, 0x36, 0x15, 0x43, 0xbd, 0x89, 0xc2, 0x85,
-	0x36, 0x81, 0x77, 0x13, 0x96, 0x9a, 0x35, 0x7f, 0xce, 0x41, 0x29, 0xc9, 0x11, 0xdd, 0x35, 0xe5,
-	0xb0, 0xb6, 0x27, 0x94, 0x60, 0xb5, 0x54, 0x5c, 0x89, 0xbb, 0xb0, 0x13, 0x31, 0x2e, 0x85, 0x93,
-	0x3b, 0xc8, 0x6f, 0xf3, 0xec, 0x63, 0xc6, 0x65, 0x97, 0x85, 0xcf, 0xfd, 0x11, 0x8e, 0xc1, 0xe8,
-	0x19, 0x54, 0x66, 0x3e, 0x97, 0x53, 0x12, 0x0c, 0xfd, 0x48, 0x38, 0x79, 0xcd, 0x7d, 0xef, 0xbc,
-	0x90, 0xad, 0xa3, 0x18, 0x3f, 0x78, 0xdc, 0xd9, 0x5b, 0x2e, 0x1a, 0xb0, 0x9a, 0x0a, 0x0c, 0x46,
-	0x6a, 0x10, 0x89, 0xda, 0x23, 0x28, 0xaf, 0x56, 0xd0, 0x2d, 0x80, 0x30, 0xb6, 0xe8, 0x70, 0x65,
-	0x9a, 0xea, 0x72, 0xd1, 0x28, 0x1b, 0xe3, 0x0e, 0x7a, 0xb8, 0x6c, 0x00, 0x03, 0x0f, 0x21, 0xb0,
-	0x89, 0xe7, 0x71, 0x6d, 0xa1, 0x32, 0xd6, 0xe3, 0xe6, 0xef, 0x3b, 0x60, 0x3f, 0x25, 0x62, 0x7c,
-	0xd9, 0x6d, 0x46, 0xc5, 0xdc, 0x30, 0xdd, 0x2d, 0x00, 0x11, 0x1f, 0xa5, 0xda, 0x8e, 0xbd, 0xde,
-	0x8e, 0x39, 0x60, 0xb5, 0x1d, 0x03, 0x88, 0xb7, 0x23, 0x02, 0x26, 0xb5, 0xbf, 0x6c, 0xac, 0xc7,
-	0xe8, 0x06, 0x14, 0x43, 0xe6, 0x69, 0x7a, 0x41, 0xd3, 0x61, 0xb9, 0x68, 0x14, 0x54, 0x4b, 0x19,
-	0xf4, 0x70, 0x41, 0x2d, 0x0d, 0x3c, 0x75, 0x6f, 0x49, 0x18, 0x32, 0x49, 0x54, 0x53, 0x12, 0xe6,
-	0xfe, 0x67, 0x1a, 0xab, 0xbd, 0x86, 0x25, 0xf7, 0x36, 0xc5, 0x44, 0x47, 0xf0, 0x46, 0x92, 0x6f,
-	0x5a, 0xb0, 0xf4, 0x32, 0x82, 0xc8, 0x28, 0xa4, 0x56, 0x52, 0x7d, 0xb2, 0xbc, 0xbd, 0x4f, 0xea,
-	0x0a, 0x66, 0xf5, 0xc9, 0x0e, 0x54, 0x3d, 0x2a, 0x7c, 0x4e, 0x3d, 0x7d, 0x03, 0xa9, 0x03, 0x07,
-	0xd6, 0xcd, 0xbd, 0x2d, 0x9f, 0x1e, 0x23, 0x42, 0xf1, 0xae, 0xe1, 0xe8, 0x19, 0x6a, 0x43, 0xc9,
-	0xf8, 0x46, 0x38, 0x15, 0xed, 0xdd, 0x0b, 0xf6, 0xc7, 0x15, 0xed, 0x4c, 0x07, 0xd9, 0x7d, 0xa9,
-	0x0e, 0x72, 0x0f, 0x20, 0x60, 0xa3, 0xa1, 0xc7, 0xfd, 0x19, 0xe5, 0x4e, 0x55, 0x73, 0x6b, 0x59,
-	0xdc, 0x9e, 0x46, 0xe0, 0x72, 0xc0, 0x46, 0xf1, 0xb0, 0xf9, 0xa3, 0x05, 0xaf, 0x6f, 0x24, 0x85,
-	0x3e, 0x82, 0xa2, 0x49, 0xeb, 0xbc, 0x47, 0x80, 0xe1, 0xe1, 0x04, 0x8b, 0xf6, 0xa1, 0xac, 0xee,
-	0x08, 0x15, 0x82, 0xc6, 0xb7, 0xbf, 0x8c, 0xd7, 0x3f, 0x20, 0x07, 0x8a, 0x24, 0xf0, 0x89, 0x5a,
-	0xcb, 0xeb, 0xb5, 0x64, 0xda, 0xfc, 0x29, 0x07, 0x45, 0x23, 0x76, 0xd9, 0xed, 0xdc, 0x84, 0xdd,
-	0xb8, 0x59, 0x0f, 0x60, 0x37, 0x2e, 0xa7, 0xb1, 0x84, 0xfd, 0xbf, 0x45, 0xad, 0xc4, 0xf8, 0xd8,
-	0x0e, 0x0f, 0xc0, 0xf6, 0x23, 0x32, 0x31, 0xad, 0x3c, 0x33, 0xf2, 0xe0, 0x71, 0xfb, 0xd1, 0x37,
-	0x51, 0xec, 0xec, 0xd2, 0x72, 0xd1, 0xb0, 0xd5, 0x0f, 0x58, 0xd3, 0x9a, 0xbf, 0xec, 0x40, 0xb1,
-	0x1b, 0x4c, 0x85, 0xa4, 0xfc, 0xb2, 0x0b, 0x62, 0xc2, 0x6e, 0x14, 0xa4, 0x0b, 0x45, 0xce, 0x98,
-	0x1c, 0xba, 0xe4, 0xbc, 0x5a, 0x60, 0xc6, 0x64, 0xb7, 0xdd, 0xd9, 0x53, 0x44, 0xd5, 0x48, 0xe2,
-	0x39, 0x2e, 0x28, 0x6a, 0x97, 0xa0, 0x67, 0x70, 0x2d, 0x69, 0xbf, 0xc7, 0x8c, 0x49, 0x21, 0x39,
-	0x89, 0x86, 0x63, 0x3a, 0x57, 0xdf, 0xbc, 0xfc, 0xb6, 0x97, 0x49, 0x3f, 0x74, 0xf9, 0x5c, 0x17,
-	0xea, 0x21, 0x9d, 0xe3, 0xab, 0x46, 0xa0, 0x93, 0xf0, 0x1f, 0xd2, 0xb9, 0x40, 0x9f, 0xc1, 0x3e,
-	0x5d, 0xc1, 0x94, 0xe2, 0x30, 0x20, 0x13, 0xf5, 0x61, 0x19, 0xba, 0x01, 0x73, 0xc7, 0xba, 0xb7,
-	0xd9, 0xf8, 0x3a, 0x4d, 0x4b, 0x7d, 0x15, 0x23, 0xba, 0x0a, 0x80, 0x04, 0x38, 0xc7, 0x01, 0x71,
-	0xc7, 0x81, 0x2f, 0xd4, 0xfb, 0x33, 0xf5, 0xd8, 0x50, 0xed, 0x49, 0xe5, 0x76, 0x78, 0x4e, 0xb5,
-	0x5a, 0x9d, 0x35, 0x37, 0xf5, 0x74, 0x11, 0xfd, 0x50, 0xf2, 0x39, 0x7e, 0xf3, 0x38, 0x7b, 0x15,
-	0x75, 0xa0, 0x32, 0x0d, 0x55, 0xf8, 0xb8, 0x06, 0xe5, 0x8b, 0xd6, 0x00, 0x62, 0x96, 0xda, 0x79,
-	0x6d, 0x06, 0xfb, 0xe7, 0x05, 0x47, 0xaf, 0x41, 0x7e, 0x4c, 0xe7, 0xb1, 0x7f, 0xb0, 0x1a, 0xa2,
-	0xcf, 0x61, 0x67, 0x46, 0x82, 0x29, 0x35, 0xce, 0x79, 0x3f, 0x2b, 0x5e, 0xb6, 0x24, 0x8e, 0x89,
-	0x9f, 0xe4, 0x0e, 0xad, 0xe6, 0xaf, 0x16, 0x14, 0x9e, 0x50, 0x97, 0x53, 0xf9, 0x4a, 0x1d, 0x7a,
-	0x78, 0xc6, 0xa1, 0xf5, 0xec, 0xc7, 0x8b, 0x8a, 0xba, 0x61, 0xd0, 0x1a, 0x94, 0xfc, 0x50, 0x52,
-	0x1e, 0x92, 0x40, 0x3b, 0xb4, 0x84, 0x57, 0xf3, 0xce, 0xfe, 0xc9, 0x69, 0xfd, 0xca, 0x5f, 0xa7,
-	0xf5, 0x2b, 0xff, 0x9e, 0xd6, 0xad, 0x1f, 0x96, 0x75, 0xeb, 0x64, 0x59, 0xb7, 0xfe, 0x58, 0xd6,
-	0xad, 0xbf, 0x97, 0x75, 0xeb, 0xb8, 0xa0, 0xff, 0x02, 0x7d, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0xff,
-	0xff, 0x38, 0xf8, 0x23, 0xac, 0x72, 0x0d, 0x00, 0x00,
+	// 1176 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x57, 0xcf, 0x8e, 0x1b, 0x35,
+	0x1c, 0xee, 0x64, 0x67, 0x93, 0xcc, 0x2f, 0x9b, 0x15, 0x98, 0xaa, 0x4c, 0x97, 0x6d, 0xb2, 0xa4,
+	0x02, 0x55, 0xa8, 0x4a, 0xa1, 0x14, 0xb4, 0x85, 0x56, 0x90, 0x7f, 0x82, 0xa8, 0x14, 0x2a, 0xb7,
+	0xb4, 0xc7, 0xc8, 0x3b, 0xe3, 0x86, 0x21, 0x93, 0xf1, 0xc8, 0x76, 0x52, 0xe5, 0x86, 0x78, 0x00,
+	0x5e, 0x00, 0x09, 0x71, 0xe6, 0x25, 0xb8, 0xf6, 0xc0, 0x81, 0x1b, 0x9c, 0x22, 0x9a, 0x27, 0xe0,
+	0x11, 0x90, 0x3d, 0x9e, 0x64, 0x56, 0x99, 0x84, 0xad, 0x54, 0xed, 0xcd, 0x8e, 0xbf, 0xef, 0xfb,
+	0xfd, 0x99, 0xcf, 0xbf, 0xf5, 0x42, 0x95, 0x9d, 0x7c, 0x4f, 0x3d, 0x29, 0x9a, 0x31, 0x67, 0x92,
+	0x21, 0xe4, 0x33, 0x6f, 0x44, 0x79, 0x53, 0x3c, 0x23, 0x7c, 0x3c, 0x0a, 0x64, 0x73, 0xfa, 0xc1,
+	0x41, 0x45, 0xce, 0x62, 0x6a, 0x00, 0x07, 0x15, 0x11, 0x53, 0x2f, 0xdd, 0x5c, 0x96, 0xc1, 0x98,
+	0x0a, 0x49, 0xc6, 0xf1, 0x8d, 0xe5, 0xca, 0x1c, 0x5d, 0x1c, 0xb2, 0x21, 0xd3, 0xcb, 0x1b, 0x6a,
+	0x95, 0xfc, 0xda, 0xf8, 0xdd, 0x02, 0xfb, 0x3e, 0x95, 0x04, 0x7d, 0x0a, 0xa5, 0x29, 0xe5, 0x22,
+	0x60, 0x91, 0x6b, 0x1d, 0x59, 0xd7, 0x2a, 0x37, 0xdf, 0x6a, 0xae, 0x47, 0x6e, 0x3e, 0x4e, 0x20,
+	0x6d, 0xfb, 0xf9, 0xbc, 0x7e, 0x01, 0xa7, 0x0c, 0x74, 0x07, 0xc0, 0xe3, 0x94, 0x48, 0xea, 0x0f,
+	0x88, 0x74, 0x0b, 0x9a, 0x7f, 0x25, 0x8f, 0xff, 0x28, 0x4d, 0x0a, 0x3b, 0x86, 0xd0, 0x92, 0x8a,
+	0x3d, 0x89, 0xfd, 0x94, 0xbd, 0x73, 0x26, 0xb6, 0x21, 0xb4, 0x64, 0xe3, 0x67, 0x1b, 0xec, 0xaf,
+	0x99, 0x4f, 0xd1, 0x25, 0x28, 0x04, 0xbe, 0x4e, 0xde, 0x69, 0x17, 0x17, 0xf3, 0x7a, 0xa1, 0xdf,
+	0xc5, 0x85, 0xc0, 0x47, 0x37, 0xc1, 0x1e, 0x53, 0x49, 0x4c, 0x5a, 0x6e, 0x9e, 0xb0, 0xea, 0x80,
+	0xa9, 0x49, 0x63, 0xd1, 0xc7, 0x60, 0xab, 0xb6, 0x9a, 0x64, 0x0e, 0xf3, 0x38, 0x2a, 0xe6, 0xc3,
+	0x98, 0x7a, 0x29, 0x4f, 0xe1, 0x51, 0x0f, 0x2a, 0x3e, 0x15, 0x1e, 0x0f, 0x62, 0xa9, 0x3a, 0x69,
+	0x6b, 0xfa, 0xd5, 0x4d, 0xf4, 0xee, 0x0a, 0x8a, 0xb3, 0x3c, 0x74, 0x07, 0x8a, 0x42, 0x12, 0x39,
+	0x11, 0xee, 0xae, 0x56, 0xa8, 0x6d, 0x4c, 0x40, 0xa3, 0x4c, 0x0a, 0x86, 0x83, 0xbe, 0x84, 0xfd,
+	0x31, 0x89, 0xc8, 0x90, 0xf2, 0x81, 0x51, 0x29, 0x6a, 0x95, 0xb7, 0x73, 0x4b, 0x4f, 0x90, 0x89,
+	0x10, 0xae, 0x8e, 0xb3, 0x5b, 0xd4, 0x03, 0x20, 0x52, 0x12, 0xef, 0xbb, 0x31, 0x8d, 0xa4, 0x5b,
+	0xd2, 0x2a, 0xef, 0xe4, 0xe6, 0x42, 0xe5, 0x33, 0xc6, 0x47, 0xad, 0x25, 0x18, 0x67, 0x88, 0xe8,
+	0x0b, 0xa8, 0x78, 0x94, 0xcb, 0xe0, 0x69, 0xe0, 0x11, 0x49, 0xdd, 0xb2, 0xd6, 0xa9, 0xe7, 0xe9,
+	0x74, 0x56, 0x30, 0x53, 0x54, 0x96, 0x89, 0xde, 0x07, 0x9b, 0xb3, 0x90, 0xba, 0xce, 0x91, 0x75,
+	0x6d, 0x7f, 0xf3, 0x67, 0xc1, 0x2c, 0xa4, 0x58, 0x23, 0x1b, 0x7f, 0x15, 0xa0, 0xf4, 0x90, 0xf2,
+	0x69, 0xe0, 0xbd, 0x5a, 0x83, 0xdc, 0x3e, 0x65, 0x90, 0xdc, 0x5a, 0x4c, 0xd8, 0x35, 0x8f, 0x1c,
+	0x43, 0x99, 0x46, 0x7e, 0xcc, 0x82, 0x48, 0x1a, 0x83, 0xe4, 0x16, 0xd2, 0x33, 0x18, 0xbc, 0x44,
+	0xa3, 0x1e, 0x54, 0x13, 0xdf, 0x0f, 0x4e, 0xb9, 0xe3, 0x28, 0x8f, 0xfe, 0xad, 0x06, 0x9a, 0xcf,
+	0xba, 0x37, 0xc9, 0xec, 0x50, 0x17, 0xaa, 0x31, 0xa7, 0xd3, 0x80, 0x4d, 0xc4, 0x40, 0x17, 0x51,
+	0x3c, 0x53, 0x11, 0x78, 0x2f, 0x65, 0xa9, 0x5d, 0xe3, 0x97, 0x02, 0x94, 0xd3, 0x1c, 0xd1, 0x2d,
+	0xd3, 0x0e, 0x6b, 0x73, 0x42, 0x29, 0x56, 0x4b, 0x25, 0x9d, 0xb8, 0x05, 0xbb, 0x31, 0xe3, 0x52,
+	0xb8, 0x85, 0xa3, 0x9d, 0x4d, 0x2e, 0x7f, 0xc0, 0xb8, 0xec, 0xb0, 0xe8, 0x69, 0x30, 0xc4, 0x09,
+	0x18, 0x3d, 0x81, 0xca, 0x34, 0xe0, 0x72, 0x42, 0xc2, 0x41, 0x10, 0x0b, 0x77, 0x47, 0x73, 0xdf,
+	0xdd, 0x16, 0xb2, 0xf9, 0x38, 0xc1, 0xf7, 0x1f, 0xb4, 0xf7, 0x17, 0xf3, 0x3a, 0x2c, 0xb7, 0x02,
+	0x83, 0x91, 0xea, 0xc7, 0xe2, 0xe0, 0x3e, 0x38, 0xcb, 0x13, 0x74, 0x1d, 0x20, 0x4a, 0x4c, 0x3d,
+	0x58, 0x9a, 0xa6, 0xba, 0x98, 0xd7, 0x1d, 0x63, 0xf5, 0x7e, 0x17, 0x3b, 0x06, 0xd0, 0xf7, 0x11,
+	0x02, 0x9b, 0xf8, 0x3e, 0xd7, 0x16, 0x72, 0xb0, 0x5e, 0x37, 0xfe, 0xd8, 0x05, 0xfb, 0x11, 0x11,
+	0xa3, 0xf3, 0x1e, 0x4c, 0x2a, 0xe6, 0x9a, 0xe9, 0xae, 0x03, 0x88, 0xe4, 0x53, 0xaa, 0x72, 0xec,
+	0x55, 0x39, 0xe6, 0x03, 0xab, 0x72, 0x0c, 0x20, 0x29, 0x47, 0x84, 0x4c, 0x6a, 0x7f, 0xd9, 0x58,
+	0xaf, 0xd1, 0x55, 0x28, 0x45, 0xcc, 0xd7, 0xf4, 0xa2, 0xa6, 0xc3, 0x62, 0x5e, 0x2f, 0xaa, 0xeb,
+	0xd6, 0xef, 0xe2, 0xa2, 0x3a, 0xea, 0xfb, 0xea, 0xa6, 0x93, 0x28, 0x62, 0x92, 0xa8, 0x31, 0x26,
+	0xcc, 0xc4, 0xc8, 0x35, 0x56, 0x6b, 0x05, 0x4b, 0x6f, 0x7a, 0x86, 0x89, 0x1e, 0xc3, 0x1b, 0x69,
+	0xbe, 0x59, 0xc1, 0xf2, 0xcb, 0x08, 0x22, 0xa3, 0x90, 0x39, 0xc9, 0x4c, 0x56, 0x67, 0xf3, 0x64,
+	0xd5, 0x1d, 0xcc, 0x9b, 0xac, 0x6d, 0xa8, 0xfa, 0x54, 0x04, 0x9c, 0xfa, 0xfa, 0x06, 0x52, 0x17,
+	0xf4, 0x20, 0xba, 0xb2, 0x4d, 0x84, 0xe2, 0x3d, 0xc3, 0xd1, 0x3b, 0xd4, 0x82, 0xb2, 0xf1, 0x8d,
+	0x70, 0x2b, 0xda, 0xbb, 0x67, 0x9c, 0xa8, 0x4b, 0xda, 0xa9, 0x09, 0xb2, 0xf7, 0x52, 0x13, 0xe4,
+	0x36, 0x40, 0xc8, 0x86, 0x03, 0x9f, 0x07, 0x53, 0xca, 0xdd, 0xaa, 0xe6, 0x1e, 0xe4, 0x71, 0xbb,
+	0x1a, 0x81, 0x9d, 0x90, 0x0d, 0x93, 0x65, 0xe3, 0x47, 0x0b, 0x5e, 0x5f, 0x4b, 0x0a, 0x7d, 0x04,
+	0x25, 0x93, 0xd6, 0xb6, 0x67, 0x83, 0xe1, 0xe1, 0x14, 0x8b, 0x0e, 0xc1, 0x51, 0x77, 0x84, 0x0a,
+	0x41, 0x93, 0xdb, 0xef, 0xe0, 0xd5, 0x0f, 0xc8, 0x85, 0x12, 0x09, 0x03, 0xa2, 0xce, 0x76, 0xf4,
+	0x59, 0xba, 0x6d, 0xfc, 0x54, 0x80, 0x92, 0x11, 0x3b, 0xef, 0x71, 0x6e, 0xc2, 0xae, 0xdd, 0xac,
+	0xbb, 0xb0, 0x97, 0xb4, 0xd3, 0x58, 0xc2, 0xfe, 0xdf, 0xa6, 0x56, 0x12, 0x7c, 0x62, 0x87, 0xbb,
+	0x60, 0x07, 0x31, 0x19, 0x9b, 0x51, 0x9e, 0x1b, 0xb9, 0xff, 0xa0, 0x75, 0xff, 0x9b, 0x38, 0x71,
+	0x76, 0x79, 0x31, 0xaf, 0xdb, 0xea, 0x07, 0xac, 0x69, 0x8d, 0x5f, 0x77, 0xa1, 0xd4, 0x09, 0x27,
+	0x42, 0x52, 0x7e, 0xde, 0x0d, 0x31, 0x61, 0xd7, 0x1a, 0xd2, 0x81, 0x12, 0x67, 0x4c, 0x0e, 0x3c,
+	0xb2, 0xad, 0x17, 0x98, 0x31, 0xd9, 0x69, 0xb5, 0xf7, 0x15, 0x51, 0x0d, 0x92, 0x64, 0x8f, 0x8b,
+	0x8a, 0xda, 0x21, 0xe8, 0x09, 0x5c, 0x4a, 0xc7, 0xef, 0x09, 0x63, 0x52, 0x48, 0x4e, 0xe2, 0xc1,
+	0x88, 0xce, 0xd4, 0xdf, 0xbc, 0x9d, 0x4d, 0x6f, 0x99, 0x5e, 0xe4, 0xf1, 0x99, 0x6e, 0xd4, 0x3d,
+	0x3a, 0xc3, 0x17, 0x8d, 0x40, 0x3b, 0xe5, 0xdf, 0xa3, 0x33, 0x81, 0x3e, 0x83, 0x43, 0xba, 0x84,
+	0x29, 0xc5, 0x41, 0x48, 0xc6, 0xea, 0x0f, 0xcb, 0xc0, 0x0b, 0x99, 0x37, 0xd2, 0xb3, 0xcd, 0xc6,
+	0x97, 0x69, 0x56, 0xea, 0xab, 0x04, 0xd1, 0x51, 0x00, 0x24, 0xc0, 0x3d, 0x09, 0x89, 0x37, 0x0a,
+	0x03, 0xa1, 0x5e, 0xac, 0x99, 0xe7, 0x89, 0x1a, 0x4f, 0x2a, 0xb7, 0xe3, 0x2d, 0xdd, 0x6a, 0xb6,
+	0x57, 0xdc, 0xcc, 0x63, 0x47, 0xf4, 0x22, 0xc9, 0x67, 0xf8, 0xcd, 0x93, 0xfc, 0x53, 0xd4, 0x86,
+	0xca, 0x24, 0x52, 0xe1, 0x93, 0x1e, 0x38, 0x67, 0xed, 0x01, 0x24, 0x2c, 0x55, 0xf9, 0xc1, 0x14,
+	0x0e, 0xb7, 0x05, 0x47, 0xaf, 0xc1, 0xce, 0x88, 0xce, 0x12, 0xff, 0x60, 0xb5, 0x44, 0x9f, 0xc3,
+	0xee, 0x94, 0x84, 0x13, 0x6a, 0x9c, 0xf3, 0x5e, 0x5e, 0xbc, 0x7c, 0x49, 0x9c, 0x10, 0x3f, 0x29,
+	0x1c, 0x5b, 0x8d, 0xdf, 0x2c, 0x28, 0x3e, 0xa4, 0x1e, 0xa7, 0xf2, 0x95, 0x3a, 0xf4, 0xf8, 0x94,
+	0x43, 0x6b, 0xf9, 0x8f, 0x17, 0x15, 0x75, 0xcd, 0xa0, 0x07, 0x50, 0x0e, 0x22, 0x49, 0x79, 0x44,
+	0x42, 0xed, 0xd0, 0x32, 0x5e, 0xee, 0xdb, 0x87, 0xcf, 0x5f, 0xd4, 0x2e, 0xfc, 0xfd, 0xa2, 0x76,
+	0xe1, 0xdf, 0x17, 0x35, 0xeb, 0x87, 0x45, 0xcd, 0x7a, 0xbe, 0xa8, 0x59, 0x7f, 0x2e, 0x6a, 0xd6,
+	0x3f, 0x8b, 0x9a, 0x75, 0x52, 0xd4, 0xff, 0x34, 0x7d, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff,
+	0x9f, 0x52, 0xfb, 0x4a, 0xa4, 0x0d, 0x00, 0x00,
 }
 }

+ 11 - 0
vendor/github.com/docker/swarmkit/api/objects.proto

@@ -48,6 +48,17 @@ message Node {
 
 
 	// Certificate is the TLS certificate issued for the node, if any.
 	// Certificate is the TLS certificate issued for the node, if any.
 	Certificate certificate = 8 [(gogoproto.nullable) = false];
 	Certificate certificate = 8 [(gogoproto.nullable) = false];
+
+	// Role is the *observed* role for this node. It differs from the
+	// desired role set in Node.Spec.Role because the role here is only
+	// updated after the Raft member list has been reconciled with the
+	// desired role from the spec.
+	//
+	// This field represents the current reconciled state. If an action is
+	// to be performed, first verify the role in the cert. This field only
+	// shows the privilege level that the CA would currently grant when
+	// issuing or renewing the node's certificate.
+	NodeRole role = 9;
 }
 }
 
 
 message Service {
 message Service {

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

@@ -112,8 +112,8 @@ func (EndpointSpec_ResolutionMode) EnumDescriptor() ([]byte, []int) {
 
 
 type NodeSpec struct {
 type NodeSpec struct {
 	Annotations Annotations `protobuf:"bytes,1,opt,name=annotations" json:"annotations"`
 	Annotations Annotations `protobuf:"bytes,1,opt,name=annotations" json:"annotations"`
-	// Role defines the role the node should have.
-	Role NodeRole `protobuf:"varint,2,opt,name=role,proto3,enum=docker.swarmkit.v1.NodeRole" json:"role,omitempty"`
+	// DesiredRole defines the role the node should have.
+	DesiredRole NodeRole `protobuf:"varint,2,opt,name=desired_role,json=desiredRole,proto3,enum=docker.swarmkit.v1.NodeRole" json:"desired_role,omitempty"`
 	// Membership controls the admission of the node into the cluster.
 	// Membership controls the admission of the node into the cluster.
 	Membership NodeSpec_Membership `protobuf:"varint,3,opt,name=membership,proto3,enum=docker.swarmkit.v1.NodeSpec_Membership" json:"membership,omitempty"`
 	Membership NodeSpec_Membership `protobuf:"varint,3,opt,name=membership,proto3,enum=docker.swarmkit.v1.NodeSpec_Membership" json:"membership,omitempty"`
 	// Availability allows a user to control the current scheduling status of a
 	// Availability allows a user to control the current scheduling status of a
@@ -645,7 +645,7 @@ func (m *NodeSpec) Copy() *NodeSpec {
 
 
 	o := &NodeSpec{
 	o := &NodeSpec{
 		Annotations:  *m.Annotations.Copy(),
 		Annotations:  *m.Annotations.Copy(),
-		Role:         m.Role,
+		DesiredRole:  m.DesiredRole,
 		Membership:   m.Membership,
 		Membership:   m.Membership,
 		Availability: m.Availability,
 		Availability: m.Availability,
 	}
 	}
@@ -941,7 +941,7 @@ func (this *NodeSpec) GoString() string {
 	s := make([]string, 0, 8)
 	s := make([]string, 0, 8)
 	s = append(s, "&api.NodeSpec{")
 	s = append(s, "&api.NodeSpec{")
 	s = append(s, "Annotations: "+strings.Replace(this.Annotations.GoString(), `&`, ``, 1)+",\n")
 	s = append(s, "Annotations: "+strings.Replace(this.Annotations.GoString(), `&`, ``, 1)+",\n")
-	s = append(s, "Role: "+fmt.Sprintf("%#v", this.Role)+",\n")
+	s = append(s, "DesiredRole: "+fmt.Sprintf("%#v", this.DesiredRole)+",\n")
 	s = append(s, "Membership: "+fmt.Sprintf("%#v", this.Membership)+",\n")
 	s = append(s, "Membership: "+fmt.Sprintf("%#v", this.Membership)+",\n")
 	s = append(s, "Availability: "+fmt.Sprintf("%#v", this.Availability)+",\n")
 	s = append(s, "Availability: "+fmt.Sprintf("%#v", this.Availability)+",\n")
 	s = append(s, "}")
 	s = append(s, "}")
@@ -1241,10 +1241,10 @@ func (m *NodeSpec) MarshalTo(data []byte) (int, error) {
 		return 0, err
 		return 0, err
 	}
 	}
 	i += n1
 	i += n1
-	if m.Role != 0 {
+	if m.DesiredRole != 0 {
 		data[i] = 0x10
 		data[i] = 0x10
 		i++
 		i++
-		i = encodeVarintSpecs(data, i, uint64(m.Role))
+		i = encodeVarintSpecs(data, i, uint64(m.DesiredRole))
 	}
 	}
 	if m.Membership != 0 {
 	if m.Membership != 0 {
 		data[i] = 0x18
 		data[i] = 0x18
@@ -2106,8 +2106,8 @@ func (m *NodeSpec) Size() (n int) {
 	_ = l
 	_ = l
 	l = m.Annotations.Size()
 	l = m.Annotations.Size()
 	n += 1 + l + sovSpecs(uint64(l))
 	n += 1 + l + sovSpecs(uint64(l))
-	if m.Role != 0 {
-		n += 1 + sovSpecs(uint64(m.Role))
+	if m.DesiredRole != 0 {
+		n += 1 + sovSpecs(uint64(m.DesiredRole))
 	}
 	}
 	if m.Membership != 0 {
 	if m.Membership != 0 {
 		n += 1 + sovSpecs(uint64(m.Membership))
 		n += 1 + sovSpecs(uint64(m.Membership))
@@ -2461,7 +2461,7 @@ func (this *NodeSpec) String() string {
 	}
 	}
 	s := strings.Join([]string{`&NodeSpec{`,
 	s := strings.Join([]string{`&NodeSpec{`,
 		`Annotations:` + strings.Replace(strings.Replace(this.Annotations.String(), "Annotations", "Annotations", 1), `&`, ``, 1) + `,`,
 		`Annotations:` + strings.Replace(strings.Replace(this.Annotations.String(), "Annotations", "Annotations", 1), `&`, ``, 1) + `,`,
-		`Role:` + fmt.Sprintf("%v", this.Role) + `,`,
+		`DesiredRole:` + fmt.Sprintf("%v", this.DesiredRole) + `,`,
 		`Membership:` + fmt.Sprintf("%v", this.Membership) + `,`,
 		`Membership:` + fmt.Sprintf("%v", this.Membership) + `,`,
 		`Availability:` + fmt.Sprintf("%v", this.Availability) + `,`,
 		`Availability:` + fmt.Sprintf("%v", this.Availability) + `,`,
 		`}`,
 		`}`,
@@ -2750,9 +2750,9 @@ func (m *NodeSpec) Unmarshal(data []byte) error {
 			iNdEx = postIndex
 			iNdEx = postIndex
 		case 2:
 		case 2:
 			if wireType != 0 {
 			if wireType != 0 {
-				return fmt.Errorf("proto: wrong wireType = %d for field Role", wireType)
+				return fmt.Errorf("proto: wrong wireType = %d for field DesiredRole", wireType)
 			}
 			}
-			m.Role = 0
+			m.DesiredRole = 0
 			for shift := uint(0); ; shift += 7 {
 			for shift := uint(0); ; shift += 7 {
 				if shift >= 64 {
 				if shift >= 64 {
 					return ErrIntOverflowSpecs
 					return ErrIntOverflowSpecs
@@ -2762,7 +2762,7 @@ func (m *NodeSpec) Unmarshal(data []byte) error {
 				}
 				}
 				b := data[iNdEx]
 				b := data[iNdEx]
 				iNdEx++
 				iNdEx++
-				m.Role |= (NodeRole(b) & 0x7F) << shift
+				m.DesiredRole |= (NodeRole(b) & 0x7F) << shift
 				if b < 0x80 {
 				if b < 0x80 {
 					break
 					break
 				}
 				}
@@ -5283,108 +5283,108 @@ var (
 func init() { proto.RegisterFile("specs.proto", fileDescriptorSpecs) }
 func init() { proto.RegisterFile("specs.proto", fileDescriptorSpecs) }
 
 
 var fileDescriptorSpecs = []byte{
 var fileDescriptorSpecs = []byte{
-	// 1640 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x57, 0xdd, 0x72, 0xdb, 0xc6,
-	0x15, 0x26, 0x24, 0x8a, 0x3f, 0x07, 0x94, 0x4d, 0xed, 0xe4, 0x07, 0x66, 0x12, 0x8a, 0x66, 0xdc,
-	0x54, 0x69, 0xa6, 0x72, 0xab, 0x76, 0x52, 0xa7, 0x6e, 0xa6, 0x25, 0x45, 0x56, 0x56, 0x55, 0x29,
-	0x9c, 0x95, 0xe2, 0x8e, 0xaf, 0x38, 0x2b, 0x60, 0x45, 0x62, 0x04, 0x62, 0xd1, 0xdd, 0x05, 0x33,
-	0xbc, 0xeb, 0x65, 0xc6, 0x17, 0x7d, 0x03, 0x5f, 0xf5, 0x19, 0xfa, 0x0e, 0xbe, 0xec, 0x65, 0x7b,
-	0xa3, 0xa9, 0xf9, 0x04, 0x9d, 0xe9, 0x03, 0xb4, 0xb3, 0x8b, 0x05, 0x08, 0x26, 0x50, 0x9c, 0x99,
-	0xf8, 0x6e, 0xf7, 0xe0, 0xfb, 0x0e, 0xce, 0x9e, 0xfd, 0x70, 0xce, 0x01, 0xd8, 0x22, 0xa2, 0xae,
-	0xd8, 0x8f, 0x38, 0x93, 0x0c, 0x21, 0x8f, 0xb9, 0xd7, 0x94, 0xef, 0x8b, 0xaf, 0x08, 0x9f, 0x5d,
-	0xfb, 0x72, 0x7f, 0xfe, 0xf3, 0x96, 0x2d, 0x17, 0x11, 0x35, 0x80, 0xd6, 0x5b, 0x13, 0x36, 0x61,
-	0x7a, 0xf9, 0x50, 0xad, 0x8c, 0xf5, 0x5d, 0x2f, 0xe6, 0x44, 0xfa, 0x2c, 0x7c, 0x98, 0x2e, 0x92,
-	0x07, 0xdd, 0xbf, 0x96, 0xa1, 0x76, 0xc6, 0x3c, 0x7a, 0x1e, 0x51, 0x17, 0x1d, 0x81, 0x4d, 0xc2,
-	0x90, 0x49, 0x0d, 0x10, 0x8e, 0xd5, 0xb1, 0xf6, 0xec, 0x83, 0xdd, 0xfd, 0x6f, 0xbf, 0x72, 0xbf,
-	0xb7, 0x82, 0xf5, 0xcb, 0x2f, 0x6f, 0x76, 0x4b, 0x38, 0xcf, 0x44, 0x3f, 0x83, 0x32, 0x67, 0x01,
-	0x75, 0x36, 0x3a, 0xd6, 0xde, 0x9d, 0x83, 0xf7, 0x8b, 0x3c, 0xa8, 0x97, 0x62, 0x16, 0x50, 0xac,
-	0x91, 0xe8, 0x08, 0x60, 0x46, 0x67, 0x97, 0x94, 0x8b, 0xa9, 0x1f, 0x39, 0x9b, 0x9a, 0xf7, 0xe3,
-	0xdb, 0x78, 0x2a, 0xd8, 0xfd, 0xd3, 0x0c, 0x8e, 0x73, 0x54, 0x74, 0x0a, 0x0d, 0x32, 0x27, 0x7e,
-	0x40, 0x2e, 0xfd, 0xc0, 0x97, 0x0b, 0xa7, 0xac, 0x5d, 0x7d, 0xfc, 0x9d, 0xae, 0x7a, 0x39, 0x02,
-	0x5e, 0xa3, 0x77, 0x3d, 0x80, 0xd5, 0x8b, 0xd0, 0x47, 0x50, 0x1d, 0x0d, 0xcf, 0x06, 0xc7, 0x67,
-	0x47, 0xcd, 0x52, 0xeb, 0xde, 0xf3, 0x17, 0x9d, 0xb7, 0x95, 0x8f, 0x15, 0x60, 0x44, 0x43, 0xcf,
-	0x0f, 0x27, 0x68, 0x0f, 0x6a, 0xbd, 0xc3, 0xc3, 0xe1, 0xe8, 0x62, 0x38, 0x68, 0x5a, 0xad, 0xd6,
-	0xf3, 0x17, 0x9d, 0x77, 0xd6, 0x81, 0x3d, 0xd7, 0xa5, 0x91, 0xa4, 0x5e, 0xab, 0xfc, 0xf5, 0xdf,
-	0xda, 0xa5, 0xee, 0xd7, 0x16, 0x34, 0xf2, 0x41, 0xa0, 0x8f, 0xa0, 0xd2, 0x3b, 0xbc, 0x38, 0x7e,
-	0x3a, 0x6c, 0x96, 0x56, 0xf4, 0x3c, 0xa2, 0xe7, 0x4a, 0x7f, 0x4e, 0xd1, 0x03, 0xd8, 0x1a, 0xf5,
-	0xbe, 0x3c, 0x1f, 0x36, 0xad, 0x55, 0x38, 0x79, 0xd8, 0x88, 0xc4, 0x42, 0xa3, 0x06, 0xb8, 0x77,
-	0x7c, 0xd6, 0xdc, 0x28, 0x46, 0x0d, 0x38, 0xf1, 0x43, 0x13, 0xca, 0xab, 0x4d, 0xb0, 0xcf, 0x29,
-	0x9f, 0xfb, 0xee, 0x1b, 0xd6, 0xc4, 0xa7, 0x50, 0x96, 0x44, 0x5c, 0x6b, 0x4d, 0xd8, 0xc5, 0x9a,
-	0xb8, 0x20, 0xe2, 0x5a, 0xbd, 0xd4, 0xd0, 0x35, 0x5e, 0x29, 0x83, 0xd3, 0x28, 0xf0, 0x5d, 0x22,
-	0xa9, 0xa7, 0x95, 0x61, 0x1f, 0xfc, 0xa8, 0x88, 0x8d, 0x33, 0x94, 0x89, 0xff, 0x49, 0x09, 0xe7,
-	0xa8, 0xe8, 0x31, 0x54, 0x26, 0x01, 0xbb, 0x24, 0x81, 0xd6, 0x84, 0x7d, 0x70, 0xbf, 0xc8, 0xc9,
-	0x91, 0x46, 0xac, 0x1c, 0x18, 0x0a, 0x7a, 0x04, 0x95, 0x38, 0xf2, 0x88, 0xa4, 0x4e, 0x45, 0x93,
-	0x3b, 0x45, 0xe4, 0x2f, 0x35, 0xe2, 0x90, 0x85, 0x57, 0xfe, 0x04, 0x1b, 0x3c, 0x3a, 0x81, 0x5a,
-	0x48, 0xe5, 0x57, 0x8c, 0x5f, 0x0b, 0xa7, 0xda, 0xd9, 0xdc, 0xb3, 0x0f, 0x3e, 0x29, 0x14, 0x63,
-	0x82, 0xe9, 0x49, 0x49, 0xdc, 0xe9, 0x8c, 0x86, 0x32, 0x71, 0xd3, 0xdf, 0x70, 0x2c, 0x9c, 0x39,
-	0x40, 0xbf, 0x81, 0x1a, 0x0d, 0xbd, 0x88, 0xf9, 0xa1, 0x74, 0x6a, 0xb7, 0x07, 0x32, 0x34, 0x18,
-	0x95, 0x4c, 0x9c, 0x31, 0xfa, 0x15, 0x28, 0xcf, 0x98, 0x47, 0xbb, 0x0f, 0x61, 0xe7, 0x5b, 0xc9,
-	0x42, 0x2d, 0xa8, 0x99, 0x64, 0x25, 0xb7, 0x5c, 0xc6, 0xd9, 0xbe, 0x7b, 0x17, 0xb6, 0xd7, 0x12,
-	0xa3, 0xcb, 0x46, 0x7a, 0x5b, 0xa8, 0x07, 0x75, 0x97, 0x85, 0x92, 0xf8, 0x21, 0xe5, 0x46, 0x20,
-	0x85, 0xb9, 0x3d, 0x4c, 0x41, 0x8a, 0xf5, 0xa4, 0x84, 0x57, 0x2c, 0xf4, 0x7b, 0xa8, 0x73, 0x2a,
-	0x58, 0xcc, 0x5d, 0x2a, 0x8c, 0x42, 0xf6, 0x8a, 0xef, 0x38, 0x01, 0x61, 0xfa, 0xe7, 0xd8, 0xe7,
-	0x54, 0xe5, 0x49, 0xe0, 0x15, 0x15, 0x3d, 0x86, 0x2a, 0xa7, 0x42, 0x12, 0x2e, 0xbf, 0xeb, 0x92,
-	0x71, 0x02, 0x19, 0xb1, 0xc0, 0x77, 0x17, 0x38, 0x65, 0xa0, 0xc7, 0x50, 0x8f, 0x02, 0xe2, 0x6a,
-	0xaf, 0xce, 0x96, 0xa6, 0x7f, 0x50, 0x44, 0x1f, 0xa5, 0x20, 0xbc, 0xc2, 0xa3, 0xcf, 0x00, 0x02,
-	0x36, 0x19, 0x7b, 0xdc, 0x9f, 0x53, 0x6e, 0x44, 0xd2, 0x2a, 0x62, 0x0f, 0x34, 0x02, 0xd7, 0x03,
-	0x36, 0x49, 0x96, 0xe8, 0xe8, 0x07, 0x29, 0x24, 0xa7, 0x8e, 0x13, 0x00, 0x92, 0x3d, 0x35, 0xfa,
-	0xf8, 0xf8, 0x7b, 0xb9, 0x32, 0x37, 0x92, 0xa3, 0xa3, 0xfb, 0xd0, 0xb8, 0x62, 0xdc, 0xa5, 0x63,
-	0xa3, 0xfb, 0xba, 0xd6, 0x84, 0xad, 0x6d, 0x89, 0xd0, 0xfb, 0x75, 0xa8, 0xf2, 0x38, 0x94, 0xfe,
-	0x8c, 0x76, 0x4f, 0xe0, 0xed, 0x42, 0xa7, 0xe8, 0x00, 0x1a, 0xd9, 0x35, 0x8f, 0x7d, 0x4f, 0xeb,
-	0xa3, 0xde, 0xbf, 0xbb, 0xbc, 0xd9, 0xb5, 0x33, 0x3d, 0x1c, 0x0f, 0xb0, 0x9d, 0x81, 0x8e, 0xbd,
-	0xee, 0xbf, 0xaa, 0xb0, 0xbd, 0x26, 0x16, 0xf4, 0x16, 0x6c, 0xf9, 0x33, 0x32, 0xa1, 0x09, 0x1d,
-	0x27, 0x1b, 0x34, 0x84, 0x4a, 0x40, 0x2e, 0x69, 0xa0, 0x24, 0xa3, 0xd2, 0xf6, 0xd3, 0xd7, 0xaa,
-	0x6e, 0xff, 0x8f, 0x1a, 0x3f, 0x0c, 0x25, 0x5f, 0x60, 0x43, 0x46, 0x0e, 0x54, 0x5d, 0x36, 0x9b,
-	0x91, 0x50, 0x95, 0x97, 0xcd, 0xbd, 0x3a, 0x4e, 0xb7, 0x08, 0x41, 0x99, 0xf0, 0x89, 0x70, 0xca,
-	0xda, 0xac, 0xd7, 0xa8, 0x09, 0x9b, 0x34, 0x9c, 0x3b, 0x5b, 0xda, 0xa4, 0x96, 0xca, 0xe2, 0xf9,
-	0xc9, 0x9d, 0xd7, 0xb1, 0x5a, 0x2a, 0x5e, 0x2c, 0x28, 0x77, 0xaa, 0xda, 0xa4, 0xd7, 0xe8, 0x57,
-	0x50, 0x99, 0xb1, 0x38, 0x94, 0xc2, 0xa9, 0xe9, 0x60, 0xef, 0x15, 0x05, 0x7b, 0xaa, 0x10, 0xa6,
-	0xfc, 0x19, 0x38, 0x7a, 0x02, 0x3b, 0x42, 0xb2, 0x68, 0x3c, 0xe1, 0xc4, 0xa5, 0xe3, 0x88, 0x72,
-	0x9f, 0x79, 0xfa, 0x36, 0x6e, 0xa9, 0xa2, 0x03, 0xd3, 0xe1, 0xf1, 0x5d, 0x45, 0x3b, 0x52, 0xac,
-	0x91, 0x26, 0xa1, 0x11, 0x34, 0xa2, 0x38, 0x08, 0xc6, 0x2c, 0x4a, 0x8a, 0x39, 0x68, 0x27, 0xdf,
-	0x23, 0x6b, 0xa3, 0x38, 0x08, 0xbe, 0x48, 0x48, 0xd8, 0x8e, 0x56, 0x1b, 0xf4, 0x0e, 0x54, 0x26,
-	0x9c, 0xc5, 0x91, 0x70, 0x6c, 0x9d, 0x0f, 0xb3, 0x43, 0x9f, 0x43, 0x55, 0x50, 0x97, 0x53, 0x29,
-	0x9c, 0x86, 0x3e, 0xed, 0x87, 0x45, 0x2f, 0x39, 0xd7, 0x10, 0x4c, 0xaf, 0x28, 0xa7, 0xa1, 0x4b,
-	0x71, 0xca, 0x41, 0xf7, 0x60, 0x53, 0xca, 0x85, 0xb3, 0xdd, 0xb1, 0xf6, 0x6a, 0xfd, 0xea, 0xf2,
-	0x66, 0x77, 0xf3, 0xe2, 0xe2, 0x19, 0x56, 0x36, 0x55, 0xa6, 0xa6, 0x4c, 0xc8, 0x90, 0xcc, 0xa8,
-	0x73, 0x47, 0xa7, 0x37, 0xdb, 0xa3, 0x67, 0x00, 0x5e, 0x28, 0xc6, 0xae, 0xfe, 0x2e, 0x9c, 0xbb,
-	0xfa, 0x74, 0x9f, 0xbc, 0xfe, 0x74, 0x83, 0xb3, 0x73, 0x53, 0x6c, 0xb7, 0x97, 0x37, 0xbb, 0xf5,
-	0x6c, 0x8b, 0xeb, 0x5e, 0x28, 0x92, 0x25, 0xea, 0x83, 0x3d, 0xa5, 0x24, 0x90, 0x53, 0x77, 0x4a,
-	0xdd, 0x6b, 0xa7, 0x79, 0x7b, 0xed, 0x7d, 0xa2, 0x61, 0xc6, 0x43, 0x9e, 0xa4, 0x44, 0xac, 0x42,
-	0x15, 0xce, 0x8e, 0xce, 0x55, 0xb2, 0x41, 0x1f, 0x00, 0xb0, 0x88, 0x86, 0x63, 0x21, 0x3d, 0x3f,
-	0x74, 0x90, 0x3a, 0x32, 0xae, 0x2b, 0xcb, 0xb9, 0x32, 0xb4, 0x3e, 0x03, 0x3b, 0xa7, 0x59, 0xa5,
-	0xb5, 0x6b, 0xba, 0x30, 0x9f, 0x81, 0x5a, 0x2a, 0xaf, 0x73, 0x12, 0xc4, 0xc9, 0xb0, 0x55, 0xc7,
-	0xc9, 0xe6, 0xd7, 0x1b, 0x8f, 0xac, 0xd6, 0x01, 0xd8, 0xb9, 0x8b, 0x43, 0x1f, 0xc2, 0x36, 0xa7,
-	0x13, 0x5f, 0x48, 0xbe, 0x18, 0x93, 0x58, 0x4e, 0x9d, 0xdf, 0x69, 0x42, 0x23, 0x35, 0xf6, 0x62,
-	0x39, 0x6d, 0x8d, 0x61, 0x75, 0x7e, 0xd4, 0x01, 0x5b, 0xe5, 0x55, 0x50, 0x3e, 0xa7, 0x5c, 0x75,
-	0x05, 0x15, 0x76, 0xde, 0xa4, 0xee, 0x5f, 0x50, 0xc2, 0xdd, 0xa9, 0xfe, 0x02, 0xeb, 0xd8, 0xec,
-	0xd4, 0x27, 0x95, 0x8a, 0xcc, 0x7c, 0x52, 0x66, 0xdb, 0xfd, 0xaf, 0x05, 0x8d, 0x7c, 0x7b, 0x42,
-	0x87, 0x49, 0x53, 0xd2, 0x47, 0xba, 0x73, 0xf0, 0xf0, 0x75, 0xed, 0x4c, 0xb7, 0x80, 0x20, 0x56,
-	0xce, 0x4e, 0xd5, 0x08, 0xa9, 0xc9, 0xe8, 0x97, 0xb0, 0x15, 0x31, 0x2e, 0xd3, 0x42, 0xd0, 0x2e,
-	0x2c, 0xdb, 0x8c, 0xa7, 0x25, 0x33, 0x01, 0x77, 0xa7, 0x70, 0x67, 0xdd, 0x1b, 0x7a, 0x00, 0x9b,
-	0x4f, 0x8f, 0x47, 0xcd, 0x52, 0xeb, 0xbd, 0xe7, 0x2f, 0x3a, 0xef, 0xae, 0x3f, 0x7c, 0xea, 0x73,
-	0x19, 0x93, 0xe0, 0x78, 0x84, 0x7e, 0x02, 0x5b, 0x83, 0xb3, 0x73, 0x8c, 0x9b, 0x56, 0x6b, 0xf7,
-	0xf9, 0x8b, 0xce, 0x7b, 0xeb, 0x38, 0xf5, 0x88, 0xc5, 0xa1, 0x87, 0xd9, 0x65, 0x36, 0x55, 0xfd,
-	0x7d, 0x03, 0x6c, 0x53, 0x1f, 0xdf, 0xec, 0x54, 0xf5, 0x5b, 0xd8, 0x4e, 0x5a, 0x4e, 0xaa, 0xfa,
-	0x8d, 0xd7, 0x76, 0x9e, 0x46, 0x42, 0x30, 0x77, 0x7c, 0x1f, 0x1a, 0x7e, 0x34, 0xff, 0x74, 0x4c,
-	0x43, 0x72, 0x19, 0x98, 0x01, 0xab, 0x86, 0x6d, 0x65, 0x1b, 0x26, 0x26, 0xf5, 0xc9, 0xf9, 0xa1,
-	0xa4, 0x3c, 0x34, 0xa3, 0x53, 0x0d, 0x67, 0x7b, 0xf4, 0x39, 0x94, 0xfd, 0x88, 0xcc, 0x4c, 0xbb,
-	0x2c, 0x3c, 0xc1, 0xf1, 0xa8, 0x77, 0x6a, 0x34, 0xd8, 0xaf, 0x2d, 0x6f, 0x76, 0xcb, 0xca, 0x80,
-	0x35, 0x0d, 0xb5, 0xd3, 0x8e, 0xa5, 0xde, 0xa4, 0x2b, 0x68, 0x0d, 0xe7, 0x2c, 0xdd, 0xff, 0x95,
-	0xc1, 0x3e, 0x0c, 0x62, 0x21, 0x4d, 0x1f, 0x78, 0x63, 0x79, 0x7b, 0x06, 0x3b, 0x44, 0xcf, 0xe0,
-	0x24, 0x54, 0x45, 0x55, 0x4f, 0x02, 0x26, 0x77, 0x0f, 0x0a, 0xdd, 0x65, 0xe0, 0x64, 0x6a, 0xe8,
-	0x57, 0x94, 0x4f, 0xc7, 0xc2, 0x4d, 0xf2, 0x8d, 0x27, 0xe8, 0x1c, 0xb6, 0x19, 0x77, 0xa7, 0x54,
-	0xc8, 0xa4, 0x0e, 0x9b, 0x99, 0xb5, 0xf0, 0x6f, 0xe6, 0x8b, 0x3c, 0xd0, 0x14, 0xa1, 0x24, 0xda,
-	0x75, 0x1f, 0xe8, 0x11, 0x94, 0x39, 0xb9, 0x4a, 0xa7, 0x9a, 0x42, 0x7d, 0x63, 0x72, 0x25, 0xd7,
-	0x5c, 0x68, 0x06, 0xfa, 0x03, 0x80, 0xe7, 0x8b, 0x88, 0x48, 0x77, 0x4a, 0xb9, 0xb9, 0xa7, 0xc2,
-	0x23, 0x0e, 0x32, 0xd4, 0x9a, 0x97, 0x1c, 0x1b, 0x9d, 0x40, 0xdd, 0x25, 0xa9, 0xd2, 0x2a, 0xb7,
-	0xb7, 0xa0, 0xc3, 0x9e, 0x71, 0xd1, 0x54, 0x2e, 0x96, 0x37, 0xbb, 0xb5, 0xd4, 0x82, 0x6b, 0x2e,
-	0x31, 0xca, 0x3b, 0x81, 0x6d, 0x35, 0xe0, 0x8f, 0x3d, 0x7a, 0x45, 0xe2, 0x40, 0x0a, 0xdd, 0x2d,
-	0x6f, 0x29, 0xaa, 0x6a, 0xd6, 0x1c, 0x18, 0x9c, 0x89, 0xab, 0x21, 0x73, 0x36, 0xf4, 0x27, 0xd8,
-	0xa1, 0xa1, 0xcb, 0x17, 0x5a, 0x67, 0x69, 0x84, 0xb5, 0xdb, 0x0f, 0x3b, 0xcc, 0xc0, 0x6b, 0x87,
-	0x6d, 0xd2, 0x6f, 0xd8, 0xbb, 0x3e, 0x40, 0xd2, 0xa6, 0xde, 0xac, 0xfe, 0x10, 0x94, 0x3d, 0x22,
-	0x89, 0x96, 0x5c, 0x03, 0xeb, 0x75, 0xff, 0xfd, 0x97, 0xaf, 0xda, 0xa5, 0x7f, 0xbe, 0x6a, 0x97,
-	0xfe, 0xf3, 0xaa, 0x6d, 0xfd, 0x65, 0xd9, 0xb6, 0x5e, 0x2e, 0xdb, 0xd6, 0x3f, 0x96, 0x6d, 0xeb,
-	0xdf, 0xcb, 0xb6, 0x75, 0x59, 0xd1, 0x3f, 0xec, 0xbf, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff,
-	0xab, 0x02, 0x96, 0x72, 0x0f, 0x10, 0x00, 0x00,
+	// 1647 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x57, 0xdd, 0x6e, 0xe3, 0xc6,
+	0x15, 0x16, 0x6d, 0x59, 0x3f, 0x87, 0xf2, 0xae, 0x3c, 0xc8, 0x0f, 0x57, 0x49, 0x64, 0xad, 0xb2,
+	0x4d, 0x9d, 0x06, 0xf5, 0xa2, 0x6e, 0x91, 0x6e, 0xba, 0x0d, 0x5a, 0xc9, 0x52, 0xbd, 0xae, 0x6b,
+	0x47, 0x18, 0x3b, 0x5b, 0xec, 0x95, 0x30, 0x26, 0xc7, 0x12, 0x61, 0x8a, 0xc3, 0xce, 0x0c, 0x15,
+	0xf8, 0xae, 0x97, 0xc1, 0x5e, 0xf4, 0x0d, 0x7c, 0xd5, 0x67, 0xe8, 0x3b, 0xec, 0x65, 0x2f, 0xdb,
+	0x1b, 0xa3, 0xab, 0x27, 0x28, 0xd0, 0x07, 0x68, 0x31, 0xc3, 0x21, 0x45, 0x25, 0x74, 0x76, 0x81,
+	0xfa, 0x6e, 0xe6, 0xf0, 0xfb, 0x0e, 0xcf, 0x9c, 0xf9, 0x78, 0xce, 0x21, 0xd8, 0x22, 0xa2, 0xae,
+	0xd8, 0x8d, 0x38, 0x93, 0x0c, 0x21, 0x8f, 0xb9, 0x97, 0x94, 0xef, 0x8a, 0x6f, 0x08, 0x9f, 0x5d,
+	0xfa, 0x72, 0x77, 0xfe, 0xb3, 0x96, 0x2d, 0xaf, 0x22, 0x6a, 0x00, 0xad, 0x77, 0x26, 0x6c, 0xc2,
+	0xf4, 0xf2, 0xb1, 0x5a, 0x19, 0xeb, 0xfb, 0x5e, 0xcc, 0x89, 0xf4, 0x59, 0xf8, 0x38, 0x5d, 0x24,
+	0x0f, 0xba, 0xd7, 0x65, 0xa8, 0x9d, 0x30, 0x8f, 0x9e, 0x46, 0xd4, 0x45, 0x07, 0x60, 0x93, 0x30,
+	0x64, 0x52, 0x03, 0x84, 0x63, 0x75, 0xac, 0x1d, 0x7b, 0x6f, 0x7b, 0xf7, 0xfb, 0xaf, 0xdc, 0xed,
+	0x2d, 0x61, 0xfd, 0xf2, 0xab, 0x9b, 0xed, 0x12, 0xce, 0x33, 0xd1, 0x6f, 0xa0, 0xe1, 0x51, 0xe1,
+	0x73, 0xea, 0x8d, 0x39, 0x0b, 0xa8, 0xb3, 0xd6, 0xb1, 0x76, 0xee, 0xed, 0x7d, 0x58, 0xe4, 0x49,
+	0xbd, 0x1c, 0xb3, 0x80, 0x62, 0xdb, 0x30, 0xd4, 0x06, 0x1d, 0x00, 0xcc, 0xe8, 0xec, 0x9c, 0x72,
+	0x31, 0xf5, 0x23, 0x67, 0x5d, 0xd3, 0x7f, 0x7c, 0x1b, 0x5d, 0xc5, 0xbe, 0x7b, 0x9c, 0xc1, 0x71,
+	0x8e, 0x8a, 0x8e, 0xa1, 0x41, 0xe6, 0xc4, 0x0f, 0xc8, 0xb9, 0x1f, 0xf8, 0xf2, 0xca, 0x29, 0x6b,
+	0x57, 0x9f, 0xfe, 0xa0, 0xab, 0x5e, 0x8e, 0x80, 0x57, 0xe8, 0x5d, 0x0f, 0x60, 0xf9, 0x22, 0xf4,
+	0x09, 0x54, 0x47, 0xc3, 0x93, 0xc1, 0xe1, 0xc9, 0x41, 0xb3, 0xd4, 0x7a, 0xf0, 0xf2, 0xba, 0xf3,
+	0xae, 0xf2, 0xb1, 0x04, 0x8c, 0x68, 0xe8, 0xf9, 0xe1, 0x04, 0xed, 0x40, 0xad, 0xb7, 0xbf, 0x3f,
+	0x1c, 0x9d, 0x0d, 0x07, 0x4d, 0xab, 0xd5, 0x7a, 0x79, 0xdd, 0x79, 0x6f, 0x15, 0xd8, 0x73, 0x5d,
+	0x1a, 0x49, 0xea, 0xb5, 0xca, 0xdf, 0xfe, 0xb5, 0x5d, 0xea, 0x7e, 0x6b, 0x41, 0x23, 0x1f, 0x04,
+	0xfa, 0x04, 0x2a, 0xbd, 0xfd, 0xb3, 0xc3, 0xe7, 0xc3, 0x66, 0x69, 0x49, 0xcf, 0x23, 0x7a, 0xae,
+	0xf4, 0xe7, 0x14, 0x3d, 0x82, 0x8d, 0x51, 0xef, 0xeb, 0xd3, 0x61, 0xd3, 0x5a, 0x86, 0x93, 0x87,
+	0x8d, 0x48, 0x2c, 0x34, 0x6a, 0x80, 0x7b, 0x87, 0x27, 0xcd, 0xb5, 0x62, 0xd4, 0x80, 0x13, 0x3f,
+	0x34, 0xa1, 0xbc, 0x5e, 0x07, 0xfb, 0x94, 0xf2, 0xb9, 0xef, 0xde, 0xb1, 0x44, 0x3e, 0x87, 0xb2,
+	0x24, 0xe2, 0x52, 0x4b, 0xc3, 0x2e, 0x96, 0xc6, 0x19, 0x11, 0x97, 0xea, 0xa5, 0x86, 0xae, 0xf1,
+	0x4a, 0x19, 0x9c, 0x46, 0x81, 0xef, 0x12, 0x49, 0x3d, 0xad, 0x0c, 0x7b, 0xef, 0x47, 0x45, 0x6c,
+	0x9c, 0xa1, 0x4c, 0xfc, 0xcf, 0x4a, 0x38, 0x47, 0x45, 0x4f, 0xa1, 0x32, 0x09, 0xd8, 0x39, 0x09,
+	0xb4, 0x26, 0xec, 0xbd, 0x87, 0x45, 0x4e, 0x0e, 0x34, 0x62, 0xe9, 0xc0, 0x50, 0xd0, 0x13, 0xa8,
+	0xc4, 0x91, 0x47, 0x24, 0x75, 0x2a, 0x9a, 0xdc, 0x29, 0x22, 0x7f, 0xad, 0x11, 0xfb, 0x2c, 0xbc,
+	0xf0, 0x27, 0xd8, 0xe0, 0xd1, 0x11, 0xd4, 0x42, 0x2a, 0xbf, 0x61, 0xfc, 0x52, 0x38, 0xd5, 0xce,
+	0xfa, 0x8e, 0xbd, 0xf7, 0x59, 0xa1, 0x18, 0x13, 0x4c, 0x4f, 0x4a, 0xe2, 0x4e, 0x67, 0x34, 0x94,
+	0x89, 0x9b, 0xfe, 0x9a, 0x63, 0xe1, 0xcc, 0x01, 0xfa, 0x35, 0xd4, 0x68, 0xe8, 0x45, 0xcc, 0x0f,
+	0xa5, 0x53, 0xbb, 0x3d, 0x90, 0xa1, 0xc1, 0xa8, 0x64, 0xe2, 0x8c, 0xd1, 0xaf, 0x40, 0x79, 0xc6,
+	0x3c, 0xda, 0x7d, 0x0c, 0x5b, 0xdf, 0x4b, 0x16, 0x6a, 0x41, 0xcd, 0x24, 0x2b, 0xb9, 0xe5, 0x32,
+	0xce, 0xf6, 0xdd, 0xfb, 0xb0, 0xb9, 0x92, 0x98, 0xee, 0x5f, 0xca, 0x50, 0x4b, 0x6f, 0x0b, 0xf5,
+	0xa0, 0xee, 0xb2, 0x50, 0x12, 0x3f, 0xa4, 0xdc, 0x08, 0xa4, 0x30, 0xb7, 0xfb, 0x29, 0x48, 0xb1,
+	0x9e, 0x95, 0xf0, 0x92, 0x85, 0x7e, 0x07, 0x75, 0x4e, 0x05, 0x8b, 0xb9, 0x4b, 0x85, 0x51, 0xc8,
+	0x4e, 0xf1, 0x1d, 0x27, 0x20, 0x4c, 0xff, 0x14, 0xfb, 0x9c, 0xaa, 0x3c, 0x09, 0xbc, 0xa4, 0xa2,
+	0xa7, 0x50, 0xe5, 0x54, 0x48, 0xc2, 0xe5, 0x0f, 0x5d, 0x32, 0x4e, 0x20, 0x23, 0x16, 0xf8, 0xee,
+	0x15, 0x4e, 0x19, 0xe8, 0x29, 0xd4, 0xa3, 0x80, 0xb8, 0xda, 0xab, 0xb3, 0xa1, 0xe9, 0x1f, 0x15,
+	0xd1, 0x47, 0x29, 0x08, 0x2f, 0xf1, 0xe8, 0x0b, 0x80, 0x80, 0x4d, 0xc6, 0x1e, 0xf7, 0xe7, 0x94,
+	0x1b, 0x91, 0xb4, 0x8a, 0xd8, 0x03, 0x8d, 0xc0, 0xf5, 0x80, 0x4d, 0x92, 0x25, 0x3a, 0xf8, 0xbf,
+	0x14, 0x92, 0x53, 0xc7, 0x11, 0x00, 0xc9, 0x9e, 0x1a, 0x7d, 0x7c, 0xfa, 0x56, 0xae, 0xcc, 0x8d,
+	0xe4, 0xe8, 0xe8, 0x21, 0x34, 0x2e, 0x18, 0x77, 0xe9, 0xd8, 0xe8, 0xbe, 0xae, 0x35, 0x61, 0x6b,
+	0x5b, 0x22, 0xf4, 0x7e, 0x1d, 0xaa, 0x3c, 0x0e, 0xa5, 0x3f, 0xa3, 0xdd, 0x23, 0x78, 0xb7, 0xd0,
+	0x29, 0xda, 0x83, 0x46, 0x76, 0xcd, 0x63, 0xdf, 0xd3, 0xfa, 0xa8, 0xf7, 0xef, 0x2f, 0x6e, 0xb6,
+	0xed, 0x4c, 0x0f, 0x87, 0x03, 0x6c, 0x67, 0xa0, 0x43, 0xaf, 0xfb, 0xcf, 0x2a, 0x6c, 0xae, 0x88,
+	0x05, 0xbd, 0x03, 0x1b, 0xfe, 0x8c, 0x4c, 0x68, 0x42, 0xc7, 0xc9, 0x06, 0x0d, 0xa1, 0x12, 0x90,
+	0x73, 0x1a, 0x28, 0xc9, 0xa8, 0xb4, 0xfd, 0xf4, 0x8d, 0xaa, 0xdb, 0xfd, 0x83, 0xc6, 0x0f, 0x43,
+	0xc9, 0xaf, 0xb0, 0x21, 0x23, 0x07, 0xaa, 0x2e, 0x9b, 0xcd, 0x48, 0xa8, 0xca, 0xcb, 0xfa, 0x4e,
+	0x1d, 0xa7, 0x5b, 0x84, 0xa0, 0x4c, 0xf8, 0x44, 0x38, 0x65, 0x6d, 0xd6, 0x6b, 0xd4, 0x84, 0x75,
+	0x1a, 0xce, 0x9d, 0x0d, 0x6d, 0x52, 0x4b, 0x65, 0xf1, 0xfc, 0xe4, 0xce, 0xeb, 0x58, 0x2d, 0x15,
+	0x2f, 0x16, 0x94, 0x3b, 0x55, 0x6d, 0xd2, 0x6b, 0xf4, 0x4b, 0xa8, 0xcc, 0x58, 0x1c, 0x4a, 0xe1,
+	0xd4, 0x74, 0xb0, 0x0f, 0x8a, 0x82, 0x3d, 0x56, 0x08, 0x53, 0xfe, 0x0c, 0x1c, 0x3d, 0x83, 0x2d,
+	0x21, 0x59, 0x34, 0x9e, 0x70, 0xe2, 0xd2, 0x71, 0x44, 0xb9, 0xcf, 0x3c, 0x7d, 0x1b, 0xb7, 0x54,
+	0xd1, 0x81, 0x69, 0xf8, 0xf8, 0xbe, 0xa2, 0x1d, 0x28, 0xd6, 0x48, 0x93, 0xd0, 0x08, 0x1a, 0x51,
+	0x1c, 0x04, 0x63, 0x16, 0x25, 0xc5, 0x1c, 0xb4, 0x93, 0xb7, 0xc8, 0xda, 0x28, 0x0e, 0x82, 0xaf,
+	0x12, 0x12, 0xb6, 0xa3, 0xe5, 0x06, 0xbd, 0x07, 0x95, 0x09, 0x67, 0x71, 0x24, 0x1c, 0x5b, 0xe7,
+	0xc3, 0xec, 0xd0, 0x97, 0x50, 0x15, 0xd4, 0xe5, 0x54, 0x0a, 0xa7, 0xa1, 0x4f, 0xfb, 0x71, 0xd1,
+	0x4b, 0x4e, 0x35, 0x04, 0xd3, 0x0b, 0xca, 0x69, 0xe8, 0x52, 0x9c, 0x72, 0xd0, 0x03, 0x58, 0x97,
+	0xf2, 0xca, 0xd9, 0xec, 0x58, 0x3b, 0xb5, 0x7e, 0x75, 0x71, 0xb3, 0xbd, 0x7e, 0x76, 0xf6, 0x02,
+	0x2b, 0x9b, 0x2a, 0x53, 0x53, 0x26, 0x64, 0x48, 0x66, 0xd4, 0xb9, 0xa7, 0xd3, 0x9b, 0xed, 0xd1,
+	0x0b, 0x00, 0x2f, 0x14, 0x63, 0x57, 0x7f, 0x17, 0xce, 0x7d, 0x7d, 0xba, 0xcf, 0xde, 0x7c, 0xba,
+	0xc1, 0xc9, 0xa9, 0x29, 0xb6, 0x9b, 0x8b, 0x9b, 0xed, 0x7a, 0xb6, 0xc5, 0x75, 0x2f, 0x14, 0xc9,
+	0x12, 0xf5, 0xc1, 0x9e, 0x52, 0x12, 0xc8, 0xa9, 0x3b, 0xa5, 0xee, 0xa5, 0xd3, 0xbc, 0xbd, 0xf6,
+	0x3e, 0xd3, 0x30, 0xe3, 0x21, 0x4f, 0x52, 0x22, 0x56, 0xa1, 0x0a, 0x67, 0x4b, 0xe7, 0x2a, 0xd9,
+	0xa0, 0x8f, 0x00, 0x58, 0x44, 0xc3, 0xb1, 0x90, 0x9e, 0x1f, 0x3a, 0x48, 0x1d, 0x19, 0xd7, 0x95,
+	0xe5, 0x54, 0x19, 0x5a, 0x5f, 0x80, 0x9d, 0xd3, 0xac, 0xd2, 0xda, 0x25, 0xbd, 0x32, 0x9f, 0x81,
+	0x5a, 0x2a, 0xaf, 0x73, 0x12, 0xc4, 0xc9, 0xcc, 0x55, 0xc7, 0xc9, 0xe6, 0x57, 0x6b, 0x4f, 0xac,
+	0xd6, 0x1e, 0xd8, 0xb9, 0x8b, 0x43, 0x1f, 0xc3, 0x26, 0xa7, 0x13, 0x5f, 0x48, 0x7e, 0x35, 0x26,
+	0xb1, 0x9c, 0x3a, 0xbf, 0xd5, 0x84, 0x46, 0x6a, 0xec, 0xc5, 0x72, 0xda, 0x1a, 0xc3, 0xf2, 0xfc,
+	0xa8, 0x03, 0xb6, 0xca, 0xab, 0xa0, 0x7c, 0x4e, 0xb9, 0xea, 0x0a, 0x2a, 0xec, 0xbc, 0x49, 0xdd,
+	0xbf, 0xa0, 0x84, 0xbb, 0x53, 0xfd, 0x05, 0xd6, 0xb1, 0xd9, 0xa9, 0x4f, 0x2a, 0x15, 0x99, 0xf9,
+	0xa4, 0xcc, 0xb6, 0xfb, 0x1f, 0x0b, 0x1a, 0xf9, 0xf6, 0x84, 0xf6, 0x93, 0xa6, 0xa4, 0x8f, 0x74,
+	0x6f, 0xef, 0xf1, 0x9b, 0xda, 0x99, 0x6e, 0x01, 0x41, 0xac, 0x9c, 0x1d, 0xab, 0x49, 0x52, 0x93,
+	0xd1, 0x2f, 0x60, 0x23, 0x62, 0x5c, 0xa6, 0x85, 0xa0, 0x5d, 0x58, 0xb6, 0x19, 0x4f, 0x4b, 0x66,
+	0x02, 0xee, 0x4e, 0xe1, 0xde, 0xaa, 0x37, 0xf4, 0x08, 0xd6, 0x9f, 0x1f, 0x8e, 0x9a, 0xa5, 0xd6,
+	0x07, 0x2f, 0xaf, 0x3b, 0xef, 0xaf, 0x3e, 0x7c, 0xee, 0x73, 0x19, 0x93, 0xe0, 0x70, 0x84, 0x7e,
+	0x02, 0x1b, 0x83, 0x93, 0x53, 0x8c, 0x9b, 0x56, 0x6b, 0xfb, 0xe5, 0x75, 0xe7, 0x83, 0x55, 0x9c,
+	0x7a, 0xc4, 0xe2, 0xd0, 0xc3, 0xec, 0x3c, 0x9b, 0xaa, 0xfe, 0xb6, 0x06, 0xb6, 0xa9, 0x8f, 0x77,
+	0x3d, 0x78, 0x6f, 0x26, 0x2d, 0x27, 0x55, 0xfd, 0xda, 0x1b, 0x3b, 0x4f, 0x23, 0x21, 0x98, 0x3b,
+	0x7e, 0x08, 0x0d, 0x3f, 0x9a, 0x7f, 0x3e, 0xa6, 0x21, 0x39, 0x0f, 0xcc, 0x80, 0x55, 0xc3, 0xb6,
+	0xb2, 0x0d, 0x13, 0x93, 0xfa, 0xe4, 0xfc, 0x50, 0x52, 0x1e, 0x9a, 0xd1, 0xa9, 0x86, 0xb3, 0x3d,
+	0xfa, 0x12, 0xca, 0x7e, 0x44, 0x66, 0xa6, 0x5d, 0x16, 0x9e, 0xe0, 0x70, 0xd4, 0x3b, 0x36, 0x1a,
+	0xec, 0xd7, 0x16, 0x37, 0xdb, 0x65, 0x65, 0xc0, 0x9a, 0x86, 0xda, 0x69, 0xc7, 0x52, 0x6f, 0xd2,
+	0x15, 0xb4, 0x86, 0x73, 0x96, 0xee, 0x7f, 0xcb, 0x60, 0xef, 0x07, 0xb1, 0x90, 0xa6, 0x0f, 0xdc,
+	0x59, 0xde, 0x5e, 0xc0, 0x16, 0xd1, 0x33, 0x38, 0x09, 0x55, 0x51, 0xd5, 0x93, 0x80, 0xc9, 0xdd,
+	0xa3, 0x42, 0x77, 0x19, 0x38, 0x99, 0x1a, 0xfa, 0x15, 0xe5, 0xd3, 0xb1, 0x70, 0x93, 0x7c, 0xe7,
+	0x09, 0x3a, 0x85, 0x4d, 0xc6, 0xdd, 0x29, 0x15, 0x32, 0xa9, 0xc3, 0x66, 0x66, 0x2d, 0xfc, 0x9b,
+	0xf9, 0x2a, 0x0f, 0x34, 0x45, 0x28, 0x89, 0x76, 0xd5, 0x07, 0x7a, 0x02, 0x65, 0x4e, 0x2e, 0xd2,
+	0xa9, 0xa6, 0x50, 0xdf, 0x98, 0x5c, 0xc8, 0x15, 0x17, 0x9a, 0x81, 0x7e, 0x0f, 0xe0, 0xf9, 0x22,
+	0x22, 0xd2, 0x9d, 0x52, 0x6e, 0xee, 0xa9, 0xf0, 0x88, 0x83, 0x0c, 0xb5, 0xe2, 0x25, 0xc7, 0x46,
+	0x47, 0x50, 0x77, 0x49, 0xaa, 0xb4, 0xca, 0xed, 0x2d, 0x68, 0xbf, 0x67, 0x5c, 0x34, 0x95, 0x8b,
+	0xc5, 0xcd, 0x76, 0x2d, 0xb5, 0xe0, 0x9a, 0x4b, 0x8c, 0xf2, 0x8e, 0x60, 0x53, 0x0d, 0xf8, 0x63,
+	0x8f, 0x5e, 0x90, 0x38, 0x90, 0x42, 0x77, 0xcb, 0x5b, 0x8a, 0xaa, 0x9a, 0x35, 0x07, 0x06, 0x67,
+	0xe2, 0x6a, 0xc8, 0x9c, 0x0d, 0xfd, 0x11, 0xb6, 0x68, 0xe8, 0xf2, 0x2b, 0xad, 0xb3, 0x34, 0xc2,
+	0xda, 0xed, 0x87, 0x1d, 0x66, 0xe0, 0x95, 0xc3, 0x36, 0xe9, 0x77, 0xec, 0x5d, 0x1f, 0x20, 0x69,
+	0x53, 0x77, 0xab, 0x3f, 0x04, 0x65, 0x8f, 0x48, 0xa2, 0x25, 0xd7, 0xc0, 0x7a, 0xdd, 0xff, 0xf0,
+	0xd5, 0xeb, 0x76, 0xe9, 0x1f, 0xaf, 0xdb, 0xa5, 0x7f, 0xbf, 0x6e, 0x5b, 0x7f, 0x5e, 0xb4, 0xad,
+	0x57, 0x8b, 0xb6, 0xf5, 0xf7, 0x45, 0xdb, 0xfa, 0xd7, 0xa2, 0x6d, 0x9d, 0x57, 0xf4, 0xff, 0xfb,
+	0xcf, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0x66, 0xb4, 0xcd, 0xfe, 0x1e, 0x10, 0x00, 0x00,
 }
 }

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

@@ -41,8 +41,8 @@ message NodeSpec {
 		DRAIN = 2 [(gogoproto.enumvalue_customname) = "NodeAvailabilityDrain"];
 		DRAIN = 2 [(gogoproto.enumvalue_customname) = "NodeAvailabilityDrain"];
 	}
 	}
 
 
-	// Role defines the role the node should have.
-	NodeRole role = 2;
+	// DesiredRole defines the role the node should have.
+	NodeRole desired_role = 2;
 
 
 	// Membership controls the admission of the node into the cluster.
 	// Membership controls the admission of the node into the cluster.
 	Membership membership = 3;
 	Membership membership = 3;

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

@@ -20,11 +20,11 @@ import (
 	cflog "github.com/cloudflare/cfssl/log"
 	cflog "github.com/cloudflare/cfssl/log"
 	cfsigner "github.com/cloudflare/cfssl/signer"
 	cfsigner "github.com/cloudflare/cfssl/signer"
 	"github.com/cloudflare/cfssl/signer/local"
 	"github.com/cloudflare/cfssl/signer/local"
-	"github.com/docker/distribution/digest"
 	"github.com/docker/go-events"
 	"github.com/docker/go-events"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/ioutils"
 	"github.com/docker/swarmkit/ioutils"
 	"github.com/docker/swarmkit/remotes"
 	"github.com/docker/swarmkit/remotes"
+	"github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc"
@@ -486,7 +486,7 @@ func GetRemoteCA(ctx context.Context, d digest.Digest, r remotes.Remotes) (RootC
 	}
 	}
 
 
 	if d != "" {
 	if d != "" {
-		verifier, err := digest.NewDigestVerifier(d)
+		verifier := d.Verifier()
 		if err != nil {
 		if err != nil {
 			return RootCA{}, errors.Wrap(err, "unexpected error getting digest verifier")
 			return RootCA{}, errors.Wrap(err, "unexpected error getting digest verifier")
 		}
 		}

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

@@ -15,11 +15,11 @@ import (
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	cfconfig "github.com/cloudflare/cfssl/config"
 	cfconfig "github.com/cloudflare/cfssl/config"
-	"github.com/docker/distribution/digest"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/identity"
 	"github.com/docker/swarmkit/identity"
 	"github.com/docker/swarmkit/log"
 	"github.com/docker/swarmkit/log"
 	"github.com/docker/swarmkit/remotes"
 	"github.com/docker/swarmkit/remotes"
+	"github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 	"google.golang.org/grpc/credentials"
 	"google.golang.org/grpc/credentials"
 
 
@@ -196,7 +196,7 @@ func getCAHashFromToken(token string) (digest.Digest, error) {
 	var digestInt big.Int
 	var digestInt big.Int
 	digestInt.SetString(split[2], joinTokenBase)
 	digestInt.SetString(split[2], joinTokenBase)
 
 
-	return digest.ParseDigest(fmt.Sprintf("sha256:%0[1]*s", 64, digestInt.Text(16)))
+	return digest.Parse(fmt.Sprintf("sha256:%0[1]*s", 64, digestInt.Text(16)))
 }
 }
 
 
 // DownloadRootCA tries to retrieve a remote root CA and matches the digest against the provided token.
 // DownloadRootCA tries to retrieve a remote root CA and matches the digest against the provided token.

+ 4 - 3
vendor/github.com/docker/swarmkit/ca/server.go

@@ -250,7 +250,8 @@ func (s *Server) IssueNodeCertificate(ctx context.Context, request *api.IssueNod
 		// Create a new node
 		// Create a new node
 		err := s.store.Update(func(tx store.Tx) error {
 		err := s.store.Update(func(tx store.Tx) error {
 			node := &api.Node{
 			node := &api.Node{
-				ID: nodeID,
+				Role: role,
+				ID:   nodeID,
 				Certificate: api.Certificate{
 				Certificate: api.Certificate{
 					CSR:  request.CSR,
 					CSR:  request.CSR,
 					CN:   nodeID,
 					CN:   nodeID,
@@ -260,7 +261,7 @@ func (s *Server) IssueNodeCertificate(ctx context.Context, request *api.IssueNod
 					},
 					},
 				},
 				},
 				Spec: api.NodeSpec{
 				Spec: api.NodeSpec{
-					Role:         role,
+					DesiredRole:  role,
 					Membership:   api.NodeMembershipAccepted,
 					Membership:   api.NodeMembershipAccepted,
 					Availability: request.Availability,
 					Availability: request.Availability,
 				},
 				},
@@ -318,7 +319,7 @@ func (s *Server) issueRenewCertificate(ctx context.Context, nodeID string, csr [
 		cert = api.Certificate{
 		cert = api.Certificate{
 			CSR:  csr,
 			CSR:  csr,
 			CN:   node.ID,
 			CN:   node.ID,
-			Role: node.Spec.Role,
+			Role: node.Role,
 			Status: api.IssuanceStatus{
 			Status: api.IssuanceStatus{
 				State: api.IssuanceStateRenew,
 				State: api.IssuanceStateRenew,
 			},
 			},

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

@@ -122,7 +122,7 @@ func NodeMatches(constraints []Constraint, n *api.Node) bool {
 				return false
 				return false
 			}
 			}
 		case strings.EqualFold(constraint.key, "node.role"):
 		case strings.EqualFold(constraint.key, "node.role"):
-			if !constraint.Match(n.Spec.Role.String()) {
+			if !constraint.Match(n.Role.String()) {
 				return false
 				return false
 			}
 			}
 		case strings.EqualFold(constraint.key, "node.platform.os"):
 		case strings.EqualFold(constraint.key, "node.platform.os"):

+ 3 - 16
vendor/github.com/docker/swarmkit/manager/controlapi/node.go

@@ -146,7 +146,7 @@ func (s *Server) ListNodes(ctx context.Context, request *api.ListNodesRequest) (
 					return true
 					return true
 				}
 				}
 				for _, c := range request.Filters.Roles {
 				for _, c := range request.Filters.Roles {
-					if c == e.Spec.Role {
+					if c == e.Role {
 						return true
 						return true
 					}
 					}
 				}
 				}
@@ -205,7 +205,6 @@ func (s *Server) UpdateNode(ctx context.Context, request *api.UpdateNodeRequest)
 	var (
 	var (
 		node   *api.Node
 		node   *api.Node
 		member *membership.Member
 		member *membership.Member
-		demote bool
 	)
 	)
 
 
 	err := s.store.Update(func(tx store.Tx) error {
 	err := s.store.Update(func(tx store.Tx) error {
@@ -215,9 +214,7 @@ func (s *Server) UpdateNode(ctx context.Context, request *api.UpdateNodeRequest)
 		}
 		}
 
 
 		// Demotion sanity checks.
 		// Demotion sanity checks.
-		if node.Spec.Role == api.NodeRoleManager && request.Spec.Role == api.NodeRoleWorker {
-			demote = true
-
+		if node.Spec.DesiredRole == api.NodeRoleManager && request.Spec.DesiredRole == api.NodeRoleWorker {
 			// Check for manager entries in Store.
 			// Check for manager entries in Store.
 			managers, err := store.FindNodes(tx, store.ByRole(api.NodeRoleManager))
 			managers, err := store.FindNodes(tx, store.ByRole(api.NodeRoleManager))
 			if err != nil {
 			if err != nil {
@@ -246,16 +243,6 @@ func (s *Server) UpdateNode(ctx context.Context, request *api.UpdateNodeRequest)
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	if demote && s.raft != nil {
-		// TODO(abronan): the remove can potentially fail and leave the node with
-		// an incorrect role (worker rather than manager), we need to reconcile the
-		// memberlist with the desired state rather than attempting to remove the
-		// member once.
-		if err := s.raft.RemoveMember(ctx, member.RaftID); err != nil {
-			return nil, grpc.Errorf(codes.Internal, "cannot demote manager to worker: %v", err)
-		}
-	}
-
 	return &api.UpdateNodeResponse{
 	return &api.UpdateNodeResponse{
 		Node: node,
 		Node: node,
 	}, nil
 	}, nil
@@ -276,7 +263,7 @@ func (s *Server) RemoveNode(ctx context.Context, request *api.RemoveNodeRequest)
 		if node == nil {
 		if node == nil {
 			return grpc.Errorf(codes.NotFound, "node %s not found", request.NodeID)
 			return grpc.Errorf(codes.NotFound, "node %s not found", request.NodeID)
 		}
 		}
-		if node.Spec.Role == api.NodeRoleManager {
+		if node.Spec.DesiredRole == api.NodeRoleManager {
 			if s.raft == nil {
 			if s.raft == nil {
 				return grpc.Errorf(codes.FailedPrecondition, "node %s is a manager but cannot access node information from the raft memberlist", request.NodeID)
 				return grpc.Errorf(codes.FailedPrecondition, "node %s is a manager but cannot access node information from the raft memberlist", request.NodeID)
 			}
 			}

+ 32 - 22
vendor/github.com/docker/swarmkit/manager/manager.go

@@ -125,6 +125,7 @@ type Manager struct {
 	localserver            *grpc.Server
 	localserver            *grpc.Server
 	raftNode               *raft.Node
 	raftNode               *raft.Node
 	dekRotator             *RaftDEKManager
 	dekRotator             *RaftDEKManager
+	roleManager            *roleManager
 
 
 	cancelFunc context.CancelFunc
 	cancelFunc context.CancelFunc
 
 
@@ -270,6 +271,12 @@ func New(config *Config) (*Manager, error) {
 	return m, nil
 	return m, nil
 }
 }
 
 
+// RemovedFromRaft returns a channel that's closed if the manager is removed
+// from the raft cluster. This should be used to trigger a manager shutdown.
+func (m *Manager) RemovedFromRaft() <-chan struct{} {
+	return m.raftNode.RemovedFromRaft
+}
+
 // Addr returns tcp address on which remote api listens.
 // Addr returns tcp address on which remote api listens.
 func (m *Manager) Addr() string {
 func (m *Manager) Addr() string {
 	return m.config.RemoteAPI.ListenAddr
 	return m.config.RemoteAPI.ListenAddr
@@ -388,39 +395,26 @@ func (m *Manager) Run(parent context.Context) error {
 
 
 	close(m.started)
 	close(m.started)
 
 
-	errCh := make(chan error, 1)
 	go func() {
 	go func() {
 		err := m.raftNode.Run(ctx)
 		err := m.raftNode.Run(ctx)
 		if err != nil {
 		if err != nil {
-			errCh <- err
 			log.G(ctx).WithError(err).Error("raft node stopped")
 			log.G(ctx).WithError(err).Error("raft node stopped")
-			m.Stop(ctx)
+			m.Stop(ctx, false)
 		}
 		}
 	}()
 	}()
 
 
-	returnErr := func(err error) error {
-		select {
-		case runErr := <-errCh:
-			if runErr == raft.ErrMemberRemoved {
-				return runErr
-			}
-		default:
-		}
-		return err
-	}
-
 	if err := raft.WaitForLeader(ctx, m.raftNode); err != nil {
 	if err := raft.WaitForLeader(ctx, m.raftNode); err != nil {
-		return returnErr(err)
+		return err
 	}
 	}
 
 
 	c, err := raft.WaitForCluster(ctx, m.raftNode)
 	c, err := raft.WaitForCluster(ctx, m.raftNode)
 	if err != nil {
 	if err != nil {
-		return returnErr(err)
+		return err
 	}
 	}
 	raftConfig := c.Spec.Raft
 	raftConfig := c.Spec.Raft
 
 
 	if err := m.watchForKEKChanges(ctx); err != nil {
 	if err := m.watchForKEKChanges(ctx); err != nil {
-		return returnErr(err)
+		return err
 	}
 	}
 
 
 	if int(raftConfig.ElectionTick) != m.raftNode.Config.ElectionTick {
 	if int(raftConfig.ElectionTick) != m.raftNode.Config.ElectionTick {
@@ -438,16 +432,17 @@ func (m *Manager) Run(parent context.Context) error {
 		return nil
 		return nil
 	}
 	}
 	m.mu.Unlock()
 	m.mu.Unlock()
-	m.Stop(ctx)
+	m.Stop(ctx, false)
 
 
-	return returnErr(err)
+	return err
 }
 }
 
 
 const stopTimeout = 8 * time.Second
 const stopTimeout = 8 * time.Second
 
 
 // Stop stops the manager. It immediately closes all open connections and
 // Stop stops the manager. It immediately closes all open connections and
-// active RPCs as well as stopping the scheduler.
-func (m *Manager) Stop(ctx context.Context) {
+// active RPCs as well as stopping the scheduler. If clearData is set, the
+// raft logs, snapshots, and keys will be erased.
+func (m *Manager) Stop(ctx context.Context, clearData bool) {
 	log.G(ctx).Info("Stopping manager")
 	log.G(ctx).Info("Stopping manager")
 	// It's not safe to start shutting down while the manager is still
 	// It's not safe to start shutting down while the manager is still
 	// starting up.
 	// starting up.
@@ -472,6 +467,8 @@ func (m *Manager) Stop(ctx context.Context) {
 		close(localSrvDone)
 		close(localSrvDone)
 	}()
 	}()
 
 
+	m.raftNode.Cancel()
+
 	m.dispatcher.Stop()
 	m.dispatcher.Stop()
 	m.logbroker.Stop()
 	m.logbroker.Stop()
 	m.caserver.Stop()
 	m.caserver.Stop()
@@ -494,10 +491,16 @@ func (m *Manager) Stop(ctx context.Context) {
 	if m.scheduler != nil {
 	if m.scheduler != nil {
 		m.scheduler.Stop()
 		m.scheduler.Stop()
 	}
 	}
+	if m.roleManager != nil {
+		m.roleManager.Stop()
+	}
 	if m.keyManager != nil {
 	if m.keyManager != nil {
 		m.keyManager.Stop()
 		m.keyManager.Stop()
 	}
 	}
 
 
+	if clearData {
+		m.raftNode.ClearData()
+	}
 	m.cancelFunc()
 	m.cancelFunc()
 	<-m.raftNode.Done()
 	<-m.raftNode.Done()
 
 
@@ -778,6 +781,7 @@ func (m *Manager) becomeLeader(ctx context.Context) {
 	m.taskReaper = taskreaper.New(s)
 	m.taskReaper = taskreaper.New(s)
 	m.scheduler = scheduler.New(s)
 	m.scheduler = scheduler.New(s)
 	m.keyManager = keymanager.New(s, keymanager.DefaultConfig())
 	m.keyManager = keymanager.New(s, keymanager.DefaultConfig())
+	m.roleManager = newRoleManager(s, m.raftNode)
 
 
 	// TODO(stevvooe): Allocate a context that can be used to
 	// TODO(stevvooe): Allocate a context that can be used to
 	// shutdown underlying manager processes when leadership is
 	// shutdown underlying manager processes when leadership is
@@ -853,6 +857,9 @@ func (m *Manager) becomeLeader(ctx context.Context) {
 		}
 		}
 	}(m.globalOrchestrator)
 	}(m.globalOrchestrator)
 
 
+	go func(roleManager *roleManager) {
+		roleManager.Run()
+	}(m.roleManager)
 }
 }
 
 
 // becomeFollower shuts down the subsystems that are only run by the leader.
 // becomeFollower shuts down the subsystems that are only run by the leader.
@@ -881,6 +888,9 @@ func (m *Manager) becomeFollower() {
 	m.scheduler.Stop()
 	m.scheduler.Stop()
 	m.scheduler = nil
 	m.scheduler = nil
 
 
+	m.roleManager.Stop()
+	m.roleManager = nil
+
 	if m.keyManager != nil {
 	if m.keyManager != nil {
 		m.keyManager.Stop()
 		m.keyManager.Stop()
 		m.keyManager = nil
 		m.keyManager = nil
@@ -937,7 +947,7 @@ func managerNode(nodeID string, availability api.NodeSpec_Availability) *api.Nod
 			},
 			},
 		},
 		},
 		Spec: api.NodeSpec{
 		Spec: api.NodeSpec{
-			Role:         api.NodeRoleManager,
+			DesiredRole:  api.NodeRoleManager,
 			Membership:   api.NodeMembershipAccepted,
 			Membership:   api.NodeMembershipAccepted,
 			Availability: availability,
 			Availability: availability,
 		},
 		},

+ 167 - 0
vendor/github.com/docker/swarmkit/manager/role_manager.go

@@ -0,0 +1,167 @@
+package manager
+
+import (
+	"time"
+
+	"github.com/docker/swarmkit/api"
+	"github.com/docker/swarmkit/log"
+	"github.com/docker/swarmkit/manager/state"
+	"github.com/docker/swarmkit/manager/state/raft"
+	"github.com/docker/swarmkit/manager/state/store"
+	"golang.org/x/net/context"
+)
+
+const roleReconcileInterval = 5 * time.Second
+
+// roleManager reconciles the raft member list with desired role changes.
+type roleManager struct {
+	ctx    context.Context
+	cancel func()
+
+	store    *store.MemoryStore
+	raft     *raft.Node
+	doneChan chan struct{}
+
+	// pending contains changed nodes that have not yet been reconciled in
+	// the raft member list.
+	pending map[string]*api.Node
+}
+
+// newRoleManager creates a new roleManager.
+func newRoleManager(store *store.MemoryStore, raftNode *raft.Node) *roleManager {
+	ctx, cancel := context.WithCancel(context.Background())
+	return &roleManager{
+		ctx:      ctx,
+		cancel:   cancel,
+		store:    store,
+		raft:     raftNode,
+		doneChan: make(chan struct{}),
+		pending:  make(map[string]*api.Node),
+	}
+}
+
+// Run is roleManager's main loop.
+func (rm *roleManager) Run() {
+	defer close(rm.doneChan)
+
+	var (
+		nodes    []*api.Node
+		ticker   *time.Ticker
+		tickerCh <-chan time.Time
+	)
+
+	watcher, cancelWatch, err := store.ViewAndWatch(rm.store,
+		func(readTx store.ReadTx) error {
+			var err error
+			nodes, err = store.FindNodes(readTx, store.All)
+			return err
+		},
+		state.EventUpdateNode{})
+	defer cancelWatch()
+
+	if err != nil {
+		log.L.WithError(err).Error("failed to check nodes for role changes")
+	} else {
+		for _, node := range nodes {
+			rm.pending[node.ID] = node
+			rm.reconcileRole(node)
+		}
+		if len(rm.pending) != 0 {
+			ticker = time.NewTicker(roleReconcileInterval)
+			tickerCh = ticker.C
+		}
+	}
+
+	for {
+		select {
+		case event := <-watcher:
+			node := event.(state.EventUpdateNode).Node
+			rm.pending[node.ID] = node
+			rm.reconcileRole(node)
+			if len(rm.pending) != 0 && ticker == nil {
+				ticker = time.NewTicker(roleReconcileInterval)
+				tickerCh = ticker.C
+			}
+		case <-tickerCh:
+			for _, node := range rm.pending {
+				rm.reconcileRole(node)
+			}
+			if len(rm.pending) == 0 {
+				ticker.Stop()
+				ticker = nil
+				tickerCh = nil
+			}
+		case <-rm.ctx.Done():
+			if ticker != nil {
+				ticker.Stop()
+			}
+			return
+		}
+	}
+}
+
+func (rm *roleManager) reconcileRole(node *api.Node) {
+	if node.Role == node.Spec.DesiredRole {
+		// Nothing to do.
+		delete(rm.pending, node.ID)
+		return
+	}
+
+	// Promotion can proceed right away.
+	if node.Spec.DesiredRole == api.NodeRoleManager && node.Role == api.NodeRoleWorker {
+		err := rm.store.Update(func(tx store.Tx) error {
+			updatedNode := store.GetNode(tx, node.ID)
+			if updatedNode == nil || updatedNode.Spec.DesiredRole != node.Spec.DesiredRole || updatedNode.Role != node.Role {
+				return nil
+			}
+			updatedNode.Role = api.NodeRoleManager
+			return store.UpdateNode(tx, updatedNode)
+		})
+		if err != nil {
+			log.L.WithError(err).Errorf("failed to promote node %s", node.ID)
+		} else {
+			delete(rm.pending, node.ID)
+		}
+	} else if node.Spec.DesiredRole == api.NodeRoleWorker && node.Role == api.NodeRoleManager {
+		// Check for node in memberlist
+		member := rm.raft.GetMemberByNodeID(node.ID)
+		if member != nil {
+			// Quorum safeguard
+			if !rm.raft.CanRemoveMember(member.RaftID) {
+				// TODO(aaronl): Retry later
+				log.L.Debugf("can't demote node %s at this time: removing member from raft would result in a loss of quorum", node.ID)
+				return
+			}
+
+			rmCtx, rmCancel := context.WithTimeout(rm.ctx, 5*time.Second)
+			defer rmCancel()
+
+			if err := rm.raft.RemoveMember(rmCtx, member.RaftID); err != nil {
+				// TODO(aaronl): Retry later
+				log.L.WithError(err).Debugf("can't demote node %s at this time", node.ID)
+				return
+			}
+		}
+
+		err := rm.store.Update(func(tx store.Tx) error {
+			updatedNode := store.GetNode(tx, node.ID)
+			if updatedNode == nil || updatedNode.Spec.DesiredRole != node.Spec.DesiredRole || updatedNode.Role != node.Role {
+				return nil
+			}
+			updatedNode.Role = api.NodeRoleWorker
+
+			return store.UpdateNode(tx, updatedNode)
+		})
+		if err != nil {
+			log.L.WithError(err).Errorf("failed to demote node %s", node.ID)
+		} else {
+			delete(rm.pending, node.ID)
+		}
+	}
+}
+
+// Stop stops the roleManager and waits for the main loop to exit.
+func (rm *roleManager) Stop() {
+	rm.cancel()
+	<-rm.doneChan
+}

+ 55 - 44
vendor/github.com/docker/swarmkit/manager/state/raft/raft.go

@@ -112,9 +112,10 @@ type Node struct {
 
 
 	ticker clock.Ticker
 	ticker clock.Ticker
 	doneCh chan struct{}
 	doneCh chan struct{}
-	// removeRaftCh notifies about node deletion from raft cluster
-	removeRaftCh        chan struct{}
+	// RemovedFromRaft notifies about node deletion from raft cluster
+	RemovedFromRaft     chan struct{}
 	removeRaftFunc      func()
 	removeRaftFunc      func()
+	cancelFunc          func()
 	leadershipBroadcast *watch.Queue
 	leadershipBroadcast *watch.Queue
 
 
 	// used to coordinate shutdown
 	// used to coordinate shutdown
@@ -134,6 +135,7 @@ type Node struct {
 	raftLogger          *storage.EncryptedRaftLogger
 	raftLogger          *storage.EncryptedRaftLogger
 	keyRotator          EncryptionKeyRotator
 	keyRotator          EncryptionKeyRotator
 	rotationQueued      bool
 	rotationQueued      bool
+	clearData           bool
 	waitForAppliedIndex uint64
 	waitForAppliedIndex uint64
 }
 }
 
 
@@ -199,7 +201,7 @@ func NewNode(opts NodeOptions) *Node {
 			Logger:          cfg.Logger,
 			Logger:          cfg.Logger,
 		},
 		},
 		doneCh:              make(chan struct{}),
 		doneCh:              make(chan struct{}),
-		removeRaftCh:        make(chan struct{}),
+		RemovedFromRaft:     make(chan struct{}),
 		stopped:             make(chan struct{}),
 		stopped:             make(chan struct{}),
 		leadershipBroadcast: watch.NewQueue(),
 		leadershipBroadcast: watch.NewQueue(),
 		lastSendToMember:    make(map[uint64]chan struct{}),
 		lastSendToMember:    make(map[uint64]chan struct{}),
@@ -220,7 +222,17 @@ func NewNode(opts NodeOptions) *Node {
 		var removeRaftOnce sync.Once
 		var removeRaftOnce sync.Once
 		return func() {
 		return func() {
 			removeRaftOnce.Do(func() {
 			removeRaftOnce.Do(func() {
-				close(n.removeRaftCh)
+				atomic.StoreUint32(&n.isMember, 0)
+				close(n.RemovedFromRaft)
+			})
+		}
+	}(n)
+
+	n.cancelFunc = func(n *Node) func() {
+		var cancelOnce sync.Once
+		return func() {
+			cancelOnce.Do(func() {
+				close(n.stopped)
 			})
 			})
 		}
 		}
 	}(n)
 	}(n)
@@ -364,6 +376,12 @@ func (n *Node) done() {
 	close(n.doneCh)
 	close(n.doneCh)
 }
 }
 
 
+// ClearData tells the raft node to delete its WALs, snapshots, and keys on
+// shutdown.
+func (n *Node) ClearData() {
+	n.clearData = true
+}
+
 // Run is the main loop for a Raft node, it goes along the state machine,
 // Run is the main loop for a Raft node, it goes along the state machine,
 // acting on the messages received from other Raft nodes in the cluster.
 // acting on the messages received from other Raft nodes in the cluster.
 //
 //
@@ -373,13 +391,10 @@ func (n *Node) Run(ctx context.Context) error {
 	ctx = log.WithLogger(ctx, logrus.WithField("raft_id", fmt.Sprintf("%x", n.Config.ID)))
 	ctx = log.WithLogger(ctx, logrus.WithField("raft_id", fmt.Sprintf("%x", n.Config.ID)))
 	ctx, cancel := context.WithCancel(ctx)
 	ctx, cancel := context.WithCancel(ctx)
 
 
-	// nodeRemoved indicates that node was stopped due its removal.
-	nodeRemoved := false
-
 	defer func() {
 	defer func() {
 		cancel()
 		cancel()
 		n.stop(ctx)
 		n.stop(ctx)
-		if nodeRemoved {
+		if n.clearData {
 			// Delete WAL and snapshots, since they are no longer
 			// Delete WAL and snapshots, since they are no longer
 			// usable.
 			// usable.
 			if err := n.raftLogger.Clear(ctx); err != nil {
 			if err := n.raftLogger.Clear(ctx); err != nil {
@@ -501,9 +516,7 @@ func (n *Node) Run(ctx context.Context) error {
 					n.campaignWhenAble = false
 					n.campaignWhenAble = false
 				}
 				}
 				if len(members) == 1 && members[n.Config.ID] != nil {
 				if len(members) == 1 && members[n.Config.ID] != nil {
-					if err := n.raftNode.Campaign(ctx); err != nil {
-						panic("raft: cannot campaign to be the leader on node restore")
-					}
+					n.raftNode.Campaign(ctx)
 				}
 				}
 			}
 			}
 
 
@@ -536,12 +549,6 @@ func (n *Node) Run(ctx context.Context) error {
 			case n.needsSnapshot(ctx):
 			case n.needsSnapshot(ctx):
 				n.doSnapshot(ctx, n.getCurrentRaftConfig())
 				n.doSnapshot(ctx, n.getCurrentRaftConfig())
 			}
 			}
-		case <-n.removeRaftCh:
-			nodeRemoved = true
-			// If the node was removed from other members,
-			// send back an error to the caller to start
-			// the shutdown process.
-			return ErrMemberRemoved
 		case <-ctx.Done():
 		case <-ctx.Done():
 			return nil
 			return nil
 		}
 		}
@@ -605,6 +612,15 @@ func (n *Node) getCurrentRaftConfig() api.RaftConfig {
 	return raftConfig
 	return raftConfig
 }
 }
 
 
+// Cancel interrupts all ongoing proposals, and prevents new ones from
+// starting. This is useful for the shutdown sequence because it allows
+// the manager to shut down raft-dependent services that might otherwise
+// block on shutdown if quorum isn't met. Then the raft node can be completely
+// shut down once no more code is using it.
+func (n *Node) Cancel() {
+	n.cancelFunc()
+}
+
 // Done returns channel which is closed when raft node is fully stopped.
 // Done returns channel which is closed when raft node is fully stopped.
 func (n *Node) Done() <-chan struct{} {
 func (n *Node) Done() <-chan struct{} {
 	return n.doneCh
 	return n.doneCh
@@ -614,8 +630,7 @@ func (n *Node) stop(ctx context.Context) {
 	n.stopMu.Lock()
 	n.stopMu.Lock()
 	defer n.stopMu.Unlock()
 	defer n.stopMu.Unlock()
 
 
-	close(n.stopped)
-
+	n.Cancel()
 	n.waitProp.Wait()
 	n.waitProp.Wait()
 	n.asyncTasks.Wait()
 	n.asyncTasks.Wait()
 
 
@@ -1240,17 +1255,6 @@ func (n *Node) IsMember() bool {
 	return atomic.LoadUint32(&n.isMember) == 1
 	return atomic.LoadUint32(&n.isMember) == 1
 }
 }
 
 
-// canSubmitProposal defines if any more proposals
-// could be submitted and processed.
-func (n *Node) canSubmitProposal() bool {
-	select {
-	case <-n.stopped:
-		return false
-	default:
-		return true
-	}
-}
-
 // Saves a log entry to our Store
 // Saves a log entry to our Store
 func (n *Node) saveToStorage(
 func (n *Node) saveToStorage(
 	ctx context.Context,
 	ctx context.Context,
@@ -1467,11 +1471,6 @@ func (n *Node) handleAddressChange(ctx context.Context, member *membership.Membe
 	return nil
 	return nil
 }
 }
 
 
-type applyResult struct {
-	resp proto.Message
-	err  error
-}
-
 // processInternalRaftRequest sends a message to nodes participating
 // processInternalRaftRequest sends a message to nodes participating
 // in the raft to apply a log entry and then waits for it to be applied
 // in the raft to apply a log entry and then waits for it to be applied
 // on the server. It will block until the update is performed, there is
 // on the server. It will block until the update is performed, there is
@@ -1479,7 +1478,7 @@ type applyResult struct {
 // shutdown.
 // shutdown.
 func (n *Node) processInternalRaftRequest(ctx context.Context, r *api.InternalRaftRequest, cb func()) (proto.Message, error) {
 func (n *Node) processInternalRaftRequest(ctx context.Context, r *api.InternalRaftRequest, cb func()) (proto.Message, error) {
 	n.stopMu.RLock()
 	n.stopMu.RLock()
-	if !n.canSubmitProposal() {
+	if !n.IsMember() {
 		n.stopMu.RUnlock()
 		n.stopMu.RUnlock()
 		return nil, ErrStopped
 		return nil, ErrStopped
 	}
 	}
@@ -1519,15 +1518,27 @@ func (n *Node) processInternalRaftRequest(ctx context.Context, r *api.InternalRa
 	}
 	}
 
 
 	select {
 	select {
-	case x := <-ch:
-		res := x.(*applyResult)
-		return res.resp, res.err
+	case x, ok := <-ch:
+		if !ok {
+			return nil, ErrLostLeadership
+		}
+		return x.(proto.Message), nil
 	case <-waitCtx.Done():
 	case <-waitCtx.Done():
 		n.wait.cancel(r.ID)
 		n.wait.cancel(r.ID)
-		return nil, ErrLostLeadership
+		// if channel is closed, wait item was canceled, otherwise it was triggered
+		x, ok := <-ch
+		if !ok {
+			return nil, ErrLostLeadership
+		}
+		return x.(proto.Message), nil
 	case <-ctx.Done():
 	case <-ctx.Done():
 		n.wait.cancel(r.ID)
 		n.wait.cancel(r.ID)
-		return nil, ctx.Err()
+		// if channel is closed, wait item was canceled, otherwise it was triggered
+		x, ok := <-ch
+		if !ok {
+			return nil, ctx.Err()
+		}
+		return x.(proto.Message), nil
 	}
 	}
 }
 }
 
 
@@ -1588,7 +1599,7 @@ func (n *Node) processEntry(ctx context.Context, entry raftpb.Entry) error {
 		return nil
 		return nil
 	}
 	}
 
 
-	if !n.wait.trigger(r.ID, &applyResult{resp: r, err: nil}) {
+	if !n.wait.trigger(r.ID, r) {
 		// There was no wait on this ID, meaning we don't have a
 		// There was no wait on this ID, meaning we don't have a
 		// transaction in progress that would be committed to the
 		// transaction in progress that would be committed to the
 		// memory store by the "trigger" call. Either a different node
 		// memory store by the "trigger" call. Either a different node
@@ -1713,11 +1724,11 @@ func (n *Node) applyRemoveNode(ctx context.Context, cc raftpb.ConfChange) (err e
 	}
 	}
 
 
 	if cc.NodeID == n.Config.ID {
 	if cc.NodeID == n.Config.ID {
-		n.removeRaftFunc()
-
 		// wait the commit ack to be sent before closing connection
 		// wait the commit ack to be sent before closing connection
 		n.asyncTasks.Wait()
 		n.asyncTasks.Wait()
 
 
+		n.removeRaftFunc()
+
 		// if there are only 2 nodes in the cluster, and leader is leaving
 		// if there are only 2 nodes in the cluster, and leader is leaving
 		// before closing the connection, leader has to ensure that follower gets
 		// before closing the connection, leader has to ensure that follower gets
 		// noticed about this raft conf change commit. Otherwise, follower would
 		// noticed about this raft conf change commit. Otherwise, follower would

+ 6 - 2
vendor/github.com/docker/swarmkit/manager/state/raft/wait.go

@@ -55,8 +55,11 @@ func (w *wait) cancel(id uint64) {
 	waitItem, ok := w.m[id]
 	waitItem, ok := w.m[id]
 	delete(w.m, id)
 	delete(w.m, id)
 	w.l.Unlock()
 	w.l.Unlock()
-	if ok && waitItem.cancel != nil {
-		waitItem.cancel()
+	if ok {
+		if waitItem.cancel != nil {
+			waitItem.cancel()
+		}
+		close(waitItem.ch)
 	}
 	}
 }
 }
 
 
@@ -69,5 +72,6 @@ func (w *wait) cancelAll() {
 		if waitItem.cancel != nil {
 		if waitItem.cancel != nil {
 			waitItem.cancel()
 			waitItem.cancel()
 		}
 		}
+		close(waitItem.ch)
 	}
 	}
 }
 }

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

@@ -238,7 +238,7 @@ func (ni nodeIndexerByRole) FromObject(obj interface{}) (bool, []byte, error) {
 	}
 	}
 
 
 	// Add the null character as a terminator
 	// Add the null character as a terminator
-	return true, []byte(strconv.FormatInt(int64(n.Spec.Role), 10) + "\x00"), nil
+	return true, []byte(strconv.FormatInt(int64(n.Role), 10) + "\x00"), nil
 }
 }
 
 
 type nodeIndexerByMembership struct{}
 type nodeIndexerByMembership struct{}

+ 52 - 40
vendor/github.com/docker/swarmkit/node/node.go

@@ -22,7 +22,6 @@ import (
 	"github.com/docker/swarmkit/log"
 	"github.com/docker/swarmkit/log"
 	"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/manager/state/raft"
 	"github.com/docker/swarmkit/remotes"
 	"github.com/docker/swarmkit/remotes"
 	"github.com/docker/swarmkit/xnet"
 	"github.com/docker/swarmkit/xnet"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
@@ -249,18 +248,13 @@ func (n *Node) run(ctx context.Context) (err error) {
 				// If we got a role change, renew
 				// If we got a role change, renew
 				lastRole := n.role
 				lastRole := n.role
 				role := ca.WorkerRole
 				role := ca.WorkerRole
-				if node.Spec.Role == api.NodeRoleManager {
+				if node.Role == api.NodeRoleManager {
 					role = ca.ManagerRole
 					role = ca.ManagerRole
 				}
 				}
 				if lastRole == role {
 				if lastRole == role {
 					n.Unlock()
 					n.Unlock()
 					continue
 					continue
 				}
 				}
-				// switch role to agent immediately to shutdown manager early
-				if role == ca.WorkerRole {
-					n.role = role
-					n.roleCond.Broadcast()
-				}
 				n.Unlock()
 				n.Unlock()
 				renewCert()
 				renewCert()
 			}
 			}
@@ -308,7 +302,18 @@ func (n *Node) run(ctx context.Context) (err error) {
 	go func() {
 	go func() {
 		<-agentReady
 		<-agentReady
 		if role == ca.ManagerRole {
 		if role == ca.ManagerRole {
-			<-managerReady
+			workerRole := make(chan struct{})
+			waitRoleCtx, waitRoleCancel := context.WithCancel(ctx)
+			go func() {
+				if n.waitRole(waitRoleCtx, ca.WorkerRole) == nil {
+					close(workerRole)
+				}
+			}()
+			select {
+			case <-managerReady:
+			case <-workerRole:
+			}
+			waitRoleCancel()
 		}
 		}
 		close(n.ready)
 		close(n.ready)
 	}()
 	}()
@@ -632,7 +637,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{}) error {
+func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig, ready chan struct{}, workerRole <-chan struct{}) error {
 	remoteAddr, _ := n.remotes.Select(n.NodeID())
 	remoteAddr, _ := n.remotes.Select(n.NodeID())
 	m, err := manager.New(&manager.Config{
 	m, err := manager.New(&manager.Config{
 		ForceNewCluster: n.config.ForceNewCluster,
 		ForceNewCluster: n.config.ForceNewCluster,
@@ -657,25 +662,18 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
 	done := make(chan struct{})
 	done := make(chan struct{})
 	var runErr error
 	var runErr error
 	go func() {
 	go func() {
-		if err := m.Run(context.Background()); err != nil && err != raft.ErrMemberRemoved {
+		if err := m.Run(context.Background()); err != nil {
 			runErr = err
 			runErr = err
 		}
 		}
 		close(done)
 		close(done)
 	}()
 	}()
 
 
-	workerRole := make(chan struct{})
-	waitRoleCtx, waitRoleCancel := context.WithCancel(ctx)
-	defer waitRoleCancel()
-	go func() {
-		n.waitRole(waitRoleCtx, ca.WorkerRole)
-		close(workerRole)
-	}()
-
+	var clearData bool
 	defer func() {
 	defer func() {
 		n.Lock()
 		n.Lock()
 		n.manager = nil
 		n.manager = nil
 		n.Unlock()
 		n.Unlock()
-		m.Stop(ctx)
+		m.Stop(ctx, clearData)
 		<-done
 		<-done
 		n.setControlSocket(nil)
 		n.setControlSocket(nil)
 	}()
 	}()
@@ -706,33 +704,19 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
 	}
 	}
 
 
 	// wait for manager stop or for role change
 	// wait for manager stop or for role change
-	// if manager stopped before role change, wait for new role for 16 seconds,
-	// then just restart manager, we might just miss that event.
-	// we need to wait for role to prevent manager to start again with wrong
-	// certificate
 	select {
 	select {
 	case <-done:
 	case <-done:
-		timer := time.NewTimer(16 * time.Second)
-		defer timer.Stop()
-		select {
-		case <-timer.C:
-			log.G(ctx).Warn("failed to get worker role after manager stop, restart manager")
-		case <-workerRole:
-		case <-ctx.Done():
-			return ctx.Err()
-		}
 		return runErr
 		return runErr
 	case <-workerRole:
 	case <-workerRole:
-		log.G(ctx).Info("role changed to worker, wait for manager to stop")
-		select {
-		case <-done:
-			return runErr
-		case <-ctx.Done():
-			return ctx.Err()
-		}
+		log.G(ctx).Info("role changed to worker, stopping manager")
+		clearData = true
+	case <-m.RemovedFromRaft():
+		log.G(ctx).Info("manager removed from raft cluster, stopping manager")
+		clearData = true
 	case <-ctx.Done():
 	case <-ctx.Done():
 		return ctx.Err()
 		return ctx.Err()
 	}
 	}
+	return nil
 }
 }
 
 
 func (n *Node) superviseManager(ctx context.Context, securityConfig *ca.SecurityConfig, ready chan struct{}) error {
 func (n *Node) superviseManager(ctx context.Context, securityConfig *ca.SecurityConfig, ready chan struct{}) error {
@@ -740,9 +724,37 @@ func (n *Node) superviseManager(ctx context.Context, securityConfig *ca.Security
 		if err := n.waitRole(ctx, ca.ManagerRole); err != nil {
 		if err := n.waitRole(ctx, ca.ManagerRole); err != nil {
 			return err
 			return err
 		}
 		}
-		if err := n.runManager(ctx, securityConfig, ready); err != nil {
+
+		workerRole := make(chan struct{})
+		waitRoleCtx, waitRoleCancel := context.WithCancel(ctx)
+		go func() {
+			if n.waitRole(waitRoleCtx, ca.WorkerRole) == nil {
+				close(workerRole)
+			}
+		}()
+
+		if err := n.runManager(ctx, securityConfig, ready, workerRole); err != nil {
+			waitRoleCancel()
 			return errors.Wrap(err, "manager stopped")
 			return errors.Wrap(err, "manager stopped")
 		}
 		}
+
+		// If the manager stopped running and our role is still
+		// "manager", it's possible that the manager was demoted and
+		// the agent hasn't realized this yet. We should wait for the
+		// role to change instead of restarting the manager immediately.
+		timer := time.NewTimer(16 * time.Second)
+		select {
+		case <-timer.C:
+			log.G(ctx).Warn("failed to get worker role after manager stop, restarting manager")
+		case <-workerRole:
+		case <-ctx.Done():
+			timer.Stop()
+			waitRoleCancel()
+			return ctx.Err()
+		}
+		timer.Stop()
+		waitRoleCancel()
+
 		ready = nil
 		ready = nil
 	}
 	}
 }
 }

+ 15 - 31
vendor/github.com/docker/distribution/digest/digester.go → vendor/github.com/opencontainers/go-digest/algorithm.go

@@ -39,7 +39,7 @@ var (
 )
 )
 
 
 // Available returns true if the digest type is available for use. If this
 // Available returns true if the digest type is available for use. If this
-// returns false, New and Hash will return nil.
+// returns false, Digester and Hash will return nil.
 func (a Algorithm) Available() bool {
 func (a Algorithm) Available() bool {
 	h, ok := algorithms[a]
 	h, ok := algorithms[a]
 	if !ok {
 	if !ok {
@@ -72,13 +72,17 @@ func (a *Algorithm) Set(value string) error {
 		*a = Algorithm(value)
 		*a = Algorithm(value)
 	}
 	}
 
 
+	if !a.Available() {
+		return ErrDigestUnsupported
+	}
+
 	return nil
 	return nil
 }
 }
 
 
-// New returns a new digester for the specified algorithm. If the algorithm
+// Digester returns a new digester for the specified algorithm. If the algorithm
 // does not have a digester implementation, nil will be returned. This can be
 // does not have a digester implementation, nil will be returned. This can be
-// checked by calling Available before calling New.
-func (a Algorithm) New() Digester {
+// checked by calling Available before calling Digester.
+func (a Algorithm) Digester() Digester {
 	return &digester{
 	return &digester{
 		alg:  a,
 		alg:  a,
 		hash: a.Hash(),
 		hash: a.Hash(),
@@ -89,6 +93,11 @@ func (a Algorithm) New() Digester {
 // method will panic. Check Algorithm.Available() before calling.
 // method will panic. Check Algorithm.Available() before calling.
 func (a Algorithm) Hash() hash.Hash {
 func (a Algorithm) Hash() hash.Hash {
 	if !a.Available() {
 	if !a.Available() {
+		// Empty algorithm string is invalid
+		if a == "" {
+			panic(fmt.Sprintf("empty digest algorithm, validate before calling Algorithm.Hash()"))
+		}
+
 		// NOTE(stevvooe): A missing hash is usually a programming error that
 		// NOTE(stevvooe): A missing hash is usually a programming error that
 		// must be resolved at compile time. We don't import in the digest
 		// must be resolved at compile time. We don't import in the digest
 		// package to allow users to choose their hash implementation (such as
 		// package to allow users to choose their hash implementation (such as
@@ -104,7 +113,7 @@ func (a Algorithm) Hash() hash.Hash {
 
 
 // FromReader returns the digest of the reader using the algorithm.
 // FromReader returns the digest of the reader using the algorithm.
 func (a Algorithm) FromReader(rd io.Reader) (Digest, error) {
 func (a Algorithm) FromReader(rd io.Reader) (Digest, error) {
-	digester := a.New()
+	digester := a.Digester()
 
 
 	if _, err := io.Copy(digester.Hash(), rd); err != nil {
 	if _, err := io.Copy(digester.Hash(), rd); err != nil {
 		return "", err
 		return "", err
@@ -115,7 +124,7 @@ func (a Algorithm) FromReader(rd io.Reader) (Digest, error) {
 
 
 // FromBytes digests the input and returns a Digest.
 // FromBytes digests the input and returns a Digest.
 func (a Algorithm) FromBytes(p []byte) Digest {
 func (a Algorithm) FromBytes(p []byte) Digest {
-	digester := a.New()
+	digester := a.Digester()
 
 
 	if _, err := digester.Hash().Write(p); err != nil {
 	if _, err := digester.Hash().Write(p); err != nil {
 		// Writes to a Hash should never fail. None of the existing
 		// Writes to a Hash should never fail. None of the existing
@@ -133,28 +142,3 @@ func (a Algorithm) FromBytes(p []byte) Digest {
 func (a Algorithm) FromString(s string) Digest {
 func (a Algorithm) FromString(s string) Digest {
 	return a.FromBytes([]byte(s))
 	return a.FromBytes([]byte(s))
 }
 }
-
-// TODO(stevvooe): Allow resolution of verifiers using the digest type and
-// this registration system.
-
-// Digester calculates the digest of written data. Writes should go directly
-// to the return value of Hash, while calling Digest will return the current
-// value of the digest.
-type Digester interface {
-	Hash() hash.Hash // provides direct access to underlying hash instance.
-	Digest() Digest
-}
-
-// digester provides a simple digester definition that embeds a hasher.
-type digester struct {
-	alg  Algorithm
-	hash hash.Hash
-}
-
-func (d *digester) Hash() hash.Hash {
-	return d.hash
-}
-
-func (d *digester) Digest() Digest {
-	return NewDigest(d.alg, d.hash)
-}

+ 23 - 27
vendor/github.com/docker/distribution/digest/digest.go → vendor/github.com/opencontainers/go-digest/digest.go

@@ -8,11 +8,6 @@ import (
 	"strings"
 	"strings"
 )
 )
 
 
-const (
-	// DigestSha256EmptyTar is the canonical sha256 digest of empty data
-	DigestSha256EmptyTar = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-)
-
 // Digest allows simple protection of hex formatted digest strings, prefixed
 // Digest allows simple protection of hex formatted digest strings, prefixed
 // by their algorithm. Strings of type Digest have some guarantee of being in
 // by their algorithm. Strings of type Digest have some guarantee of being in
 // the correct format and it provides quick access to the components of a
 // the correct format and it provides quick access to the components of a
@@ -61,16 +56,14 @@ var (
 	ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm")
 	ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm")
 )
 )
 
 
-// ParseDigest parses s and returns the validated digest object. An error will
+// Parse parses s and returns the validated digest object. An error will
 // be returned if the format is invalid.
 // be returned if the format is invalid.
-func ParseDigest(s string) (Digest, error) {
+func Parse(s string) (Digest, error) {
 	d := Digest(s)
 	d := Digest(s)
-
 	return d, d.Validate()
 	return d, d.Validate()
 }
 }
 
 
-// FromReader returns the most valid digest for the underlying content using
-// the canonical digest algorithm.
+// FromReader consumes the content of rd until io.EOF, returning canonical digest.
 func FromReader(rd io.Reader) (Digest, error) {
 func FromReader(rd io.Reader) (Digest, error) {
 	return Canonical.FromReader(rd)
 	return Canonical.FromReader(rd)
 }
 }
@@ -90,30 +83,24 @@ func FromString(s string) Digest {
 func (d Digest) Validate() error {
 func (d Digest) Validate() error {
 	s := string(d)
 	s := string(d)
 
 
-	if !DigestRegexpAnchored.MatchString(s) {
-		return ErrDigestInvalidFormat
-	}
-
 	i := strings.Index(s, ":")
 	i := strings.Index(s, ":")
-	if i < 0 {
-		return ErrDigestInvalidFormat
-	}
 
 
-	// case: "sha256:" with no hex.
-	if i+1 == len(s) {
+	// validate i then run through regexp
+	if i < 0 || i+1 == len(s) || !DigestRegexpAnchored.MatchString(s) {
 		return ErrDigestInvalidFormat
 		return ErrDigestInvalidFormat
 	}
 	}
 
 
-	switch algorithm := Algorithm(s[:i]); algorithm {
-	case SHA256, SHA384, SHA512:
-		if algorithm.Size()*2 != len(s[i+1:]) {
-			return ErrDigestInvalidLength
-		}
-		break
-	default:
+	algorithm := Algorithm(s[:i])
+	if !algorithm.Available() {
 		return ErrDigestUnsupported
 		return ErrDigestUnsupported
 	}
 	}
 
 
+	// Digests much always be hex-encoded, ensuring that their hex portion will
+	// always be size*2
+	if algorithm.Size()*2 != len(s[i+1:]) {
+		return ErrDigestInvalidLength
+	}
+
 	return nil
 	return nil
 }
 }
 
 
@@ -123,6 +110,15 @@ func (d Digest) Algorithm() Algorithm {
 	return Algorithm(d[:d.sepIndex()])
 	return Algorithm(d[:d.sepIndex()])
 }
 }
 
 
+// Verifier returns a writer object that can be used to verify a stream of
+// content against the digest. If the digest is invalid, the method will panic.
+func (d Digest) Verifier() Verifier {
+	return hashVerifier{
+		hash:   d.Algorithm().Hash(),
+		digest: d,
+	}
+}
+
 // Hex returns the hex digest portion of the digest. This will panic if the
 // Hex returns the hex digest portion of the digest. This will panic if the
 // underlying digest is not in a valid format.
 // underlying digest is not in a valid format.
 func (d Digest) Hex() string {
 func (d Digest) Hex() string {
@@ -137,7 +133,7 @@ func (d Digest) sepIndex() int {
 	i := strings.Index(string(d), ":")
 	i := strings.Index(string(d), ":")
 
 
 	if i < 0 {
 	if i < 0 {
-		panic("could not find ':' in digest: " + d)
+		panic(fmt.Sprintf("no ':' separator in digest %q", d))
 	}
 	}
 
 
 	return i
 	return i

+ 25 - 0
vendor/github.com/opencontainers/go-digest/digester.go

@@ -0,0 +1,25 @@
+package digest
+
+import "hash"
+
+// Digester calculates the digest of written data. Writes should go directly
+// to the return value of Hash, while calling Digest will return the current
+// value of the digest.
+type Digester interface {
+	Hash() hash.Hash // provides direct access to underlying hash instance.
+	Digest() Digest
+}
+
+// digester provides a simple digester definition that embeds a hasher.
+type digester struct {
+	alg  Algorithm
+	hash hash.Hash
+}
+
+func (d *digester) Hash() hash.Hash {
+	return d.hash
+}
+
+func (d *digester) Digest() Digest {
+	return NewDigest(d.alg, d.hash)
+}

+ 0 - 0
vendor/github.com/docker/distribution/digest/doc.go → vendor/github.com/opencontainers/go-digest/doc.go


+ 0 - 13
vendor/github.com/docker/distribution/digest/verifiers.go → vendor/github.com/opencontainers/go-digest/verifiers.go

@@ -17,19 +17,6 @@ type Verifier interface {
 	Verified() bool
 	Verified() bool
 }
 }
 
 
-// NewDigestVerifier returns a verifier that compares the written bytes
-// against a passed in digest.
-func NewDigestVerifier(d Digest) (Verifier, error) {
-	if err := d.Validate(); err != nil {
-		return nil, err
-	}
-
-	return hashVerifier{
-		hash:   d.Algorithm().Hash(),
-		digest: d,
-	}, nil
-}
-
 type hashVerifier struct {
 type hashVerifier struct {
 	digest Digest
 	digest Digest
 	hash   hash.Hash
 	hash   hash.Hash