Browse code

vendor: update dependencies for go-digest

Signed-off-by: Stephen J Day <stephen.day@docker.com>

Stephen J Day authored on 2017/01/07 10:30:33
Showing 42 changed files
... ...
@@ -44,8 +44,9 @@ github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
44 44
 github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
45 45
 
46 46
 # get graph and distribution packages
47
-github.com/docker/distribution 28602af35aceda2f8d571bad7ca37a54cf0250bc
47
+github.com/docker/distribution 7dba427612198a11b161a27f9d40bb2dca1ccd20
48 48
 github.com/vbatts/tar-split v0.10.1
49
+github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
49 50
 
50 51
 # get go-zfs packages
51 52
 github.com/mistifyio/go-zfs 22c9b32c84eb0d0c6f4043b6e90fc94073de92fa
... ...
@@ -102,7 +103,7 @@ github.com/docker/containerd 03e5862ec0d8d3b3f750e19fca3ee367e13c090e
102 102
 github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4
103 103
 
104 104
 # cluster
105
-github.com/docker/swarmkit 2e956c40c02ad527c90ec85bdae25a0acac1bd87
105
+github.com/docker/swarmkit 4762d92234d286ae7c9e061470485e4d34ef8ebd
106 106
 github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9
107 107
 github.com/gogo/protobuf v0.3
108 108
 github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
... ...
@@ -8,8 +8,8 @@ import (
8 8
 	"time"
9 9
 
10 10
 	"github.com/docker/distribution/context"
11
-	"github.com/docker/distribution/digest"
12 11
 	"github.com/docker/distribution/reference"
12
+	"github.com/opencontainers/go-digest"
13 13
 )
14 14
 
15 15
 var (
16 16
deleted file mode 100644
... ...
@@ -1,144 +0,0 @@
1
-package digest
2
-
3
-import (
4
-	"fmt"
5
-	"hash"
6
-	"io"
7
-	"regexp"
8
-	"strings"
9
-)
10
-
11
-const (
12
-	// DigestSha256EmptyTar is the canonical sha256 digest of empty data
13
-	DigestSha256EmptyTar = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
14
-)
15
-
16
-// Digest allows simple protection of hex formatted digest strings, prefixed
17
-// by their algorithm. Strings of type Digest have some guarantee of being in
18
-// the correct format and it provides quick access to the components of a
19
-// digest string.
20
-//
21
-// The following is an example of the contents of Digest types:
22
-//
23
-// 	sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc
24
-//
25
-// This allows to abstract the digest behind this type and work only in those
26
-// terms.
27
-type Digest string
28
-
29
-// NewDigest returns a Digest from alg and a hash.Hash object.
30
-func NewDigest(alg Algorithm, h hash.Hash) Digest {
31
-	return NewDigestFromBytes(alg, h.Sum(nil))
32
-}
33
-
34
-// NewDigestFromBytes returns a new digest from the byte contents of p.
35
-// Typically, this can come from hash.Hash.Sum(...) or xxx.SumXXX(...)
36
-// functions. This is also useful for rebuilding digests from binary
37
-// serializations.
38
-func NewDigestFromBytes(alg Algorithm, p []byte) Digest {
39
-	return Digest(fmt.Sprintf("%s:%x", alg, p))
40
-}
41
-
42
-// NewDigestFromHex returns a Digest from alg and a the hex encoded digest.
43
-func NewDigestFromHex(alg, hex string) Digest {
44
-	return Digest(fmt.Sprintf("%s:%s", alg, hex))
45
-}
46
-
47
-// DigestRegexp matches valid digest types.
48
-var DigestRegexp = regexp.MustCompile(`[a-zA-Z0-9-_+.]+:[a-fA-F0-9]+`)
49
-
50
-// DigestRegexpAnchored matches valid digest types, anchored to the start and end of the match.
51
-var DigestRegexpAnchored = regexp.MustCompile(`^` + DigestRegexp.String() + `$`)
52
-
53
-var (
54
-	// ErrDigestInvalidFormat returned when digest format invalid.
55
-	ErrDigestInvalidFormat = fmt.Errorf("invalid checksum digest format")
56
-
57
-	// ErrDigestInvalidLength returned when digest has invalid length.
58
-	ErrDigestInvalidLength = fmt.Errorf("invalid checksum digest length")
59
-
60
-	// ErrDigestUnsupported returned when the digest algorithm is unsupported.
61
-	ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm")
62
-)
63
-
64
-// ParseDigest parses s and returns the validated digest object. An error will
65
-// be returned if the format is invalid.
66
-func ParseDigest(s string) (Digest, error) {
67
-	d := Digest(s)
68
-
69
-	return d, d.Validate()
70
-}
71
-
72
-// FromReader returns the most valid digest for the underlying content using
73
-// the canonical digest algorithm.
74
-func FromReader(rd io.Reader) (Digest, error) {
75
-	return Canonical.FromReader(rd)
76
-}
77
-
78
-// FromBytes digests the input and returns a Digest.
79
-func FromBytes(p []byte) Digest {
80
-	return Canonical.FromBytes(p)
81
-}
82
-
83
-// FromString digests the input and returns a Digest.
84
-func FromString(s string) Digest {
85
-	return Canonical.FromString(s)
86
-}
87
-
88
-// Validate checks that the contents of d is a valid digest, returning an
89
-// error if not.
90
-func (d Digest) Validate() error {
91
-	s := string(d)
92
-
93
-	if !DigestRegexpAnchored.MatchString(s) {
94
-		return ErrDigestInvalidFormat
95
-	}
96
-
97
-	i := strings.Index(s, ":")
98
-	if i < 0 {
99
-		return ErrDigestInvalidFormat
100
-	}
101
-
102
-	// case: "sha256:" with no hex.
103
-	if i+1 == len(s) {
104
-		return ErrDigestInvalidFormat
105
-	}
106
-
107
-	switch algorithm := Algorithm(s[:i]); algorithm {
108
-	case SHA256, SHA384, SHA512:
109
-		if algorithm.Size()*2 != len(s[i+1:]) {
110
-			return ErrDigestInvalidLength
111
-		}
112
-		break
113
-	default:
114
-		return ErrDigestUnsupported
115
-	}
116
-
117
-	return nil
118
-}
119
-
120
-// Algorithm returns the algorithm portion of the digest. This will panic if
121
-// the underlying digest is not in a valid format.
122
-func (d Digest) Algorithm() Algorithm {
123
-	return Algorithm(d[:d.sepIndex()])
124
-}
125
-
126
-// Hex returns the hex digest portion of the digest. This will panic if the
127
-// underlying digest is not in a valid format.
128
-func (d Digest) Hex() string {
129
-	return string(d[d.sepIndex()+1:])
130
-}
131
-
132
-func (d Digest) String() string {
133
-	return string(d)
134
-}
135
-
136
-func (d Digest) sepIndex() int {
137
-	i := strings.Index(string(d), ":")
138
-
139
-	if i < 0 {
140
-		panic("could not find ':' in digest: " + d)
141
-	}
142
-
143
-	return i
144
-}
145 1
deleted file mode 100644
... ...
@@ -1,160 +0,0 @@
1
-package digest
2
-
3
-import (
4
-	"crypto"
5
-	"fmt"
6
-	"hash"
7
-	"io"
8
-)
9
-
10
-// Algorithm identifies and implementation of a digester by an identifier.
11
-// Note the that this defines both the hash algorithm used and the string
12
-// encoding.
13
-type Algorithm string
14
-
15
-// supported digest types
16
-const (
17
-	SHA256 Algorithm = "sha256" // sha256 with hex encoding
18
-	SHA384 Algorithm = "sha384" // sha384 with hex encoding
19
-	SHA512 Algorithm = "sha512" // sha512 with hex encoding
20
-
21
-	// Canonical is the primary digest algorithm used with the distribution
22
-	// project. Other digests may be used but this one is the primary storage
23
-	// digest.
24
-	Canonical = SHA256
25
-)
26
-
27
-var (
28
-	// TODO(stevvooe): Follow the pattern of the standard crypto package for
29
-	// registration of digests. Effectively, we are a registerable set and
30
-	// common symbol access.
31
-
32
-	// algorithms maps values to hash.Hash implementations. Other algorithms
33
-	// may be available but they cannot be calculated by the digest package.
34
-	algorithms = map[Algorithm]crypto.Hash{
35
-		SHA256: crypto.SHA256,
36
-		SHA384: crypto.SHA384,
37
-		SHA512: crypto.SHA512,
38
-	}
39
-)
40
-
41
-// Available returns true if the digest type is available for use. If this
42
-// returns false, New and Hash will return nil.
43
-func (a Algorithm) Available() bool {
44
-	h, ok := algorithms[a]
45
-	if !ok {
46
-		return false
47
-	}
48
-
49
-	// check availability of the hash, as well
50
-	return h.Available()
51
-}
52
-
53
-func (a Algorithm) String() string {
54
-	return string(a)
55
-}
56
-
57
-// Size returns number of bytes returned by the hash.
58
-func (a Algorithm) Size() int {
59
-	h, ok := algorithms[a]
60
-	if !ok {
61
-		return 0
62
-	}
63
-	return h.Size()
64
-}
65
-
66
-// Set implemented to allow use of Algorithm as a command line flag.
67
-func (a *Algorithm) Set(value string) error {
68
-	if value == "" {
69
-		*a = Canonical
70
-	} else {
71
-		// just do a type conversion, support is queried with Available.
72
-		*a = Algorithm(value)
73
-	}
74
-
75
-	return nil
76
-}
77
-
78
-// New returns a new digester for the specified algorithm. If the algorithm
79
-// does not have a digester implementation, nil will be returned. This can be
80
-// checked by calling Available before calling New.
81
-func (a Algorithm) New() Digester {
82
-	return &digester{
83
-		alg:  a,
84
-		hash: a.Hash(),
85
-	}
86
-}
87
-
88
-// Hash returns a new hash as used by the algorithm. If not available, the
89
-// method will panic. Check Algorithm.Available() before calling.
90
-func (a Algorithm) Hash() hash.Hash {
91
-	if !a.Available() {
92
-		// NOTE(stevvooe): A missing hash is usually a programming error that
93
-		// must be resolved at compile time. We don't import in the digest
94
-		// package to allow users to choose their hash implementation (such as
95
-		// when using stevvooe/resumable or a hardware accelerated package).
96
-		//
97
-		// Applications that may want to resolve the hash at runtime should
98
-		// call Algorithm.Available before call Algorithm.Hash().
99
-		panic(fmt.Sprintf("%v not available (make sure it is imported)", a))
100
-	}
101
-
102
-	return algorithms[a].New()
103
-}
104
-
105
-// FromReader returns the digest of the reader using the algorithm.
106
-func (a Algorithm) FromReader(rd io.Reader) (Digest, error) {
107
-	digester := a.New()
108
-
109
-	if _, err := io.Copy(digester.Hash(), rd); err != nil {
110
-		return "", err
111
-	}
112
-
113
-	return digester.Digest(), nil
114
-}
115
-
116
-// FromBytes digests the input and returns a Digest.
117
-func (a Algorithm) FromBytes(p []byte) Digest {
118
-	digester := a.New()
119
-
120
-	if _, err := digester.Hash().Write(p); err != nil {
121
-		// Writes to a Hash should never fail. None of the existing
122
-		// hash implementations in the stdlib or hashes vendored
123
-		// here can return errors from Write. Having a panic in this
124
-		// condition instead of having FromBytes return an error value
125
-		// avoids unnecessary error handling paths in all callers.
126
-		panic("write to hash function returned error: " + err.Error())
127
-	}
128
-
129
-	return digester.Digest()
130
-}
131
-
132
-// FromString digests the string input and returns a Digest.
133
-func (a Algorithm) FromString(s string) Digest {
134
-	return a.FromBytes([]byte(s))
135
-}
136
-
137
-// TODO(stevvooe): Allow resolution of verifiers using the digest type and
138
-// this registration system.
139
-
140
-// Digester calculates the digest of written data. Writes should go directly
141
-// to the return value of Hash, while calling Digest will return the current
142
-// value of the digest.
143
-type Digester interface {
144
-	Hash() hash.Hash // provides direct access to underlying hash instance.
145
-	Digest() Digest
146
-}
147
-
148
-// digester provides a simple digester definition that embeds a hasher.
149
-type digester struct {
150
-	alg  Algorithm
151
-	hash hash.Hash
152
-}
153
-
154
-func (d *digester) Hash() hash.Hash {
155
-	return d.hash
156
-}
157
-
158
-func (d *digester) Digest() Digest {
159
-	return NewDigest(d.alg, d.hash)
160
-}
161 1
deleted file mode 100644
... ...
@@ -1,42 +0,0 @@
1
-// Package digest provides a generalized type to opaquely represent message
2
-// digests and their operations within the registry. The Digest type is
3
-// designed to serve as a flexible identifier in a content-addressable system.
4
-// More importantly, it provides tools and wrappers to work with
5
-// hash.Hash-based digests with little effort.
6
-//
7
-// Basics
8
-//
9
-// The format of a digest is simply a string with two parts, dubbed the
10
-// "algorithm" and the "digest", separated by a colon:
11
-//
12
-// 	<algorithm>:<digest>
13
-//
14
-// An example of a sha256 digest representation follows:
15
-//
16
-// 	sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc
17
-//
18
-// In this case, the string "sha256" is the algorithm and the hex bytes are
19
-// the "digest".
20
-//
21
-// Because the Digest type is simply a string, once a valid Digest is
22
-// obtained, comparisons are cheap, quick and simple to express with the
23
-// standard equality operator.
24
-//
25
-// Verification
26
-//
27
-// The main benefit of using the Digest type is simple verification against a
28
-// given digest. The Verifier interface, modeled after the stdlib hash.Hash
29
-// interface, provides a common write sink for digest verification. After
30
-// writing is complete, calling the Verifier.Verified method will indicate
31
-// whether or not the stream of bytes matches the target digest.
32
-//
33
-// Missing Features
34
-//
35
-// In addition to the above, we intend to add the following features to this
36
-// package:
37
-//
38
-// 1. A Digester type that supports write sink digest calculation.
39
-//
40
-// 2. Suspend and resume of ongoing digest calculations to support efficient digest verification in the registry.
41
-//
42
-package digest
43 1
deleted file mode 100644
... ...
@@ -1,245 +0,0 @@
1
-package digest
2
-
3
-import (
4
-	"errors"
5
-	"sort"
6
-	"strings"
7
-	"sync"
8
-)
9
-
10
-var (
11
-	// ErrDigestNotFound is used when a matching digest
12
-	// could not be found in a set.
13
-	ErrDigestNotFound = errors.New("digest not found")
14
-
15
-	// ErrDigestAmbiguous is used when multiple digests
16
-	// are found in a set. None of the matching digests
17
-	// should be considered valid matches.
18
-	ErrDigestAmbiguous = errors.New("ambiguous digest string")
19
-)
20
-
21
-// Set is used to hold a unique set of digests which
22
-// may be easily referenced by easily  referenced by a string
23
-// representation of the digest as well as short representation.
24
-// The uniqueness of the short representation is based on other
25
-// digests in the set. If digests are omitted from this set,
26
-// collisions in a larger set may not be detected, therefore it
27
-// is important to always do short representation lookups on
28
-// the complete set of digests. To mitigate collisions, an
29
-// appropriately long short code should be used.
30
-type Set struct {
31
-	mutex   sync.RWMutex
32
-	entries digestEntries
33
-}
34
-
35
-// NewSet creates an empty set of digests
36
-// which may have digests added.
37
-func NewSet() *Set {
38
-	return &Set{
39
-		entries: digestEntries{},
40
-	}
41
-}
42
-
43
-// checkShortMatch checks whether two digests match as either whole
44
-// values or short values. This function does not test equality,
45
-// rather whether the second value could match against the first
46
-// value.
47
-func checkShortMatch(alg Algorithm, hex, shortAlg, shortHex string) bool {
48
-	if len(hex) == len(shortHex) {
49
-		if hex != shortHex {
50
-			return false
51
-		}
52
-		if len(shortAlg) > 0 && string(alg) != shortAlg {
53
-			return false
54
-		}
55
-	} else if !strings.HasPrefix(hex, shortHex) {
56
-		return false
57
-	} else if len(shortAlg) > 0 && string(alg) != shortAlg {
58
-		return false
59
-	}
60
-	return true
61
-}
62
-
63
-// Lookup looks for a digest matching the given string representation.
64
-// If no digests could be found ErrDigestNotFound will be returned
65
-// with an empty digest value. If multiple matches are found
66
-// ErrDigestAmbiguous will be returned with an empty digest value.
67
-func (dst *Set) Lookup(d string) (Digest, error) {
68
-	dst.mutex.RLock()
69
-	defer dst.mutex.RUnlock()
70
-	if len(dst.entries) == 0 {
71
-		return "", ErrDigestNotFound
72
-	}
73
-	var (
74
-		searchFunc func(int) bool
75
-		alg        Algorithm
76
-		hex        string
77
-	)
78
-	dgst, err := ParseDigest(d)
79
-	if err == ErrDigestInvalidFormat {
80
-		hex = d
81
-		searchFunc = func(i int) bool {
82
-			return dst.entries[i].val >= d
83
-		}
84
-	} else {
85
-		hex = dgst.Hex()
86
-		alg = dgst.Algorithm()
87
-		searchFunc = func(i int) bool {
88
-			if dst.entries[i].val == hex {
89
-				return dst.entries[i].alg >= alg
90
-			}
91
-			return dst.entries[i].val >= hex
92
-		}
93
-	}
94
-	idx := sort.Search(len(dst.entries), searchFunc)
95
-	if idx == len(dst.entries) || !checkShortMatch(dst.entries[idx].alg, dst.entries[idx].val, string(alg), hex) {
96
-		return "", ErrDigestNotFound
97
-	}
98
-	if dst.entries[idx].alg == alg && dst.entries[idx].val == hex {
99
-		return dst.entries[idx].digest, nil
100
-	}
101
-	if idx+1 < len(dst.entries) && checkShortMatch(dst.entries[idx+1].alg, dst.entries[idx+1].val, string(alg), hex) {
102
-		return "", ErrDigestAmbiguous
103
-	}
104
-
105
-	return dst.entries[idx].digest, nil
106
-}
107
-
108
-// Add adds the given digest to the set. An error will be returned
109
-// if the given digest is invalid. If the digest already exists in the
110
-// set, this operation will be a no-op.
111
-func (dst *Set) Add(d Digest) error {
112
-	if err := d.Validate(); err != nil {
113
-		return err
114
-	}
115
-	dst.mutex.Lock()
116
-	defer dst.mutex.Unlock()
117
-	entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d}
118
-	searchFunc := func(i int) bool {
119
-		if dst.entries[i].val == entry.val {
120
-			return dst.entries[i].alg >= entry.alg
121
-		}
122
-		return dst.entries[i].val >= entry.val
123
-	}
124
-	idx := sort.Search(len(dst.entries), searchFunc)
125
-	if idx == len(dst.entries) {
126
-		dst.entries = append(dst.entries, entry)
127
-		return nil
128
-	} else if dst.entries[idx].digest == d {
129
-		return nil
130
-	}
131
-
132
-	entries := append(dst.entries, nil)
133
-	copy(entries[idx+1:], entries[idx:len(entries)-1])
134
-	entries[idx] = entry
135
-	dst.entries = entries
136
-	return nil
137
-}
138
-
139
-// Remove removes the given digest from the set. An err will be
140
-// returned if the given digest is invalid. If the digest does
141
-// not exist in the set, this operation will be a no-op.
142
-func (dst *Set) Remove(d Digest) error {
143
-	if err := d.Validate(); err != nil {
144
-		return err
145
-	}
146
-	dst.mutex.Lock()
147
-	defer dst.mutex.Unlock()
148
-	entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d}
149
-	searchFunc := func(i int) bool {
150
-		if dst.entries[i].val == entry.val {
151
-			return dst.entries[i].alg >= entry.alg
152
-		}
153
-		return dst.entries[i].val >= entry.val
154
-	}
155
-	idx := sort.Search(len(dst.entries), searchFunc)
156
-	// Not found if idx is after or value at idx is not digest
157
-	if idx == len(dst.entries) || dst.entries[idx].digest != d {
158
-		return nil
159
-	}
160
-
161
-	entries := dst.entries
162
-	copy(entries[idx:], entries[idx+1:])
163
-	entries = entries[:len(entries)-1]
164
-	dst.entries = entries
165
-
166
-	return nil
167
-}
168
-
169
-// All returns all the digests in the set
170
-func (dst *Set) All() []Digest {
171
-	dst.mutex.RLock()
172
-	defer dst.mutex.RUnlock()
173
-	retValues := make([]Digest, len(dst.entries))
174
-	for i := range dst.entries {
175
-		retValues[i] = dst.entries[i].digest
176
-	}
177
-
178
-	return retValues
179
-}
180
-
181
-// ShortCodeTable returns a map of Digest to unique short codes. The
182
-// length represents the minimum value, the maximum length may be the
183
-// entire value of digest if uniqueness cannot be achieved without the
184
-// full value. This function will attempt to make short codes as short
185
-// as possible to be unique.
186
-func ShortCodeTable(dst *Set, length int) map[Digest]string {
187
-	dst.mutex.RLock()
188
-	defer dst.mutex.RUnlock()
189
-	m := make(map[Digest]string, len(dst.entries))
190
-	l := length
191
-	resetIdx := 0
192
-	for i := 0; i < len(dst.entries); i++ {
193
-		var short string
194
-		extended := true
195
-		for extended {
196
-			extended = false
197
-			if len(dst.entries[i].val) <= l {
198
-				short = dst.entries[i].digest.String()
199
-			} else {
200
-				short = dst.entries[i].val[:l]
201
-				for j := i + 1; j < len(dst.entries); j++ {
202
-					if checkShortMatch(dst.entries[j].alg, dst.entries[j].val, "", short) {
203
-						if j > resetIdx {
204
-							resetIdx = j
205
-						}
206
-						extended = true
207
-					} else {
208
-						break
209
-					}
210
-				}
211
-				if extended {
212
-					l++
213
-				}
214
-			}
215
-		}
216
-		m[dst.entries[i].digest] = short
217
-		if i >= resetIdx {
218
-			l = length
219
-		}
220
-	}
221
-	return m
222
-}
223
-
224
-type digestEntry struct {
225
-	alg    Algorithm
226
-	val    string
227
-	digest Digest
228
-}
229
-
230
-type digestEntries []*digestEntry
231
-
232
-func (d digestEntries) Len() int {
233
-	return len(d)
234
-}
235
-
236
-func (d digestEntries) Less(i, j int) bool {
237
-	if d[i].val != d[j].val {
238
-		return d[i].val < d[j].val
239
-	}
240
-	return d[i].alg < d[j].alg
241
-}
242
-
243
-func (d digestEntries) Swap(i, j int) {
244
-	d[i], d[j] = d[j], d[i]
245
-}
246 1
deleted file mode 100644
... ...
@@ -1,44 +0,0 @@
1
-package digest
2
-
3
-import (
4
-	"hash"
5
-	"io"
6
-)
7
-
8
-// Verifier presents a general verification interface to be used with message
9
-// digests and other byte stream verifications. Users instantiate a Verifier
10
-// from one of the various methods, write the data under test to it then check
11
-// the result with the Verified method.
12
-type Verifier interface {
13
-	io.Writer
14
-
15
-	// Verified will return true if the content written to Verifier matches
16
-	// the digest.
17
-	Verified() bool
18
-}
19
-
20
-// NewDigestVerifier returns a verifier that compares the written bytes
21
-// against a passed in digest.
22
-func NewDigestVerifier(d Digest) (Verifier, error) {
23
-	if err := d.Validate(); err != nil {
24
-		return nil, err
25
-	}
26
-
27
-	return hashVerifier{
28
-		hash:   d.Algorithm().Hash(),
29
-		digest: d,
30
-	}, nil
31
-}
32
-
33
-type hashVerifier struct {
34
-	digest Digest
35
-	hash   hash.Hash
36
-}
37
-
38
-func (hv hashVerifier) Write(p []byte) (n int, err error) {
39
-	return hv.hash.Write(p)
40
-}
41
-
42
-func (hv hashVerifier) Verified() bool {
43
-	return hv.digest == NewDigest(hv.digest.Algorithm(), hv.hash)
44
-}
45 1
new file mode 100644
... ...
@@ -0,0 +1,247 @@
0
+package digestset
1
+
2
+import (
3
+	"errors"
4
+	"sort"
5
+	"strings"
6
+	"sync"
7
+
8
+	digest "github.com/opencontainers/go-digest"
9
+)
10
+
11
+var (
12
+	// ErrDigestNotFound is used when a matching digest
13
+	// could not be found in a set.
14
+	ErrDigestNotFound = errors.New("digest not found")
15
+
16
+	// ErrDigestAmbiguous is used when multiple digests
17
+	// are found in a set. None of the matching digests
18
+	// should be considered valid matches.
19
+	ErrDigestAmbiguous = errors.New("ambiguous digest string")
20
+)
21
+
22
+// Set is used to hold a unique set of digests which
23
+// may be easily referenced by easily  referenced by a string
24
+// representation of the digest as well as short representation.
25
+// The uniqueness of the short representation is based on other
26
+// digests in the set. If digests are omitted from this set,
27
+// collisions in a larger set may not be detected, therefore it
28
+// is important to always do short representation lookups on
29
+// the complete set of digests. To mitigate collisions, an
30
+// appropriately long short code should be used.
31
+type Set struct {
32
+	mutex   sync.RWMutex
33
+	entries digestEntries
34
+}
35
+
36
+// NewSet creates an empty set of digests
37
+// which may have digests added.
38
+func NewSet() *Set {
39
+	return &Set{
40
+		entries: digestEntries{},
41
+	}
42
+}
43
+
44
+// checkShortMatch checks whether two digests match as either whole
45
+// values or short values. This function does not test equality,
46
+// rather whether the second value could match against the first
47
+// value.
48
+func checkShortMatch(alg digest.Algorithm, hex, shortAlg, shortHex string) bool {
49
+	if len(hex) == len(shortHex) {
50
+		if hex != shortHex {
51
+			return false
52
+		}
53
+		if len(shortAlg) > 0 && string(alg) != shortAlg {
54
+			return false
55
+		}
56
+	} else if !strings.HasPrefix(hex, shortHex) {
57
+		return false
58
+	} else if len(shortAlg) > 0 && string(alg) != shortAlg {
59
+		return false
60
+	}
61
+	return true
62
+}
63
+
64
+// Lookup looks for a digest matching the given string representation.
65
+// If no digests could be found ErrDigestNotFound will be returned
66
+// with an empty digest value. If multiple matches are found
67
+// ErrDigestAmbiguous will be returned with an empty digest value.
68
+func (dst *Set) Lookup(d string) (digest.Digest, error) {
69
+	dst.mutex.RLock()
70
+	defer dst.mutex.RUnlock()
71
+	if len(dst.entries) == 0 {
72
+		return "", ErrDigestNotFound
73
+	}
74
+	var (
75
+		searchFunc func(int) bool
76
+		alg        digest.Algorithm
77
+		hex        string
78
+	)
79
+	dgst, err := digest.Parse(d)
80
+	if err == digest.ErrDigestInvalidFormat {
81
+		hex = d
82
+		searchFunc = func(i int) bool {
83
+			return dst.entries[i].val >= d
84
+		}
85
+	} else {
86
+		hex = dgst.Hex()
87
+		alg = dgst.Algorithm()
88
+		searchFunc = func(i int) bool {
89
+			if dst.entries[i].val == hex {
90
+				return dst.entries[i].alg >= alg
91
+			}
92
+			return dst.entries[i].val >= hex
93
+		}
94
+	}
95
+	idx := sort.Search(len(dst.entries), searchFunc)
96
+	if idx == len(dst.entries) || !checkShortMatch(dst.entries[idx].alg, dst.entries[idx].val, string(alg), hex) {
97
+		return "", ErrDigestNotFound
98
+	}
99
+	if dst.entries[idx].alg == alg && dst.entries[idx].val == hex {
100
+		return dst.entries[idx].digest, nil
101
+	}
102
+	if idx+1 < len(dst.entries) && checkShortMatch(dst.entries[idx+1].alg, dst.entries[idx+1].val, string(alg), hex) {
103
+		return "", ErrDigestAmbiguous
104
+	}
105
+
106
+	return dst.entries[idx].digest, nil
107
+}
108
+
109
+// Add adds the given digest to the set. An error will be returned
110
+// if the given digest is invalid. If the digest already exists in the
111
+// set, this operation will be a no-op.
112
+func (dst *Set) Add(d digest.Digest) error {
113
+	if err := d.Validate(); err != nil {
114
+		return err
115
+	}
116
+	dst.mutex.Lock()
117
+	defer dst.mutex.Unlock()
118
+	entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d}
119
+	searchFunc := func(i int) bool {
120
+		if dst.entries[i].val == entry.val {
121
+			return dst.entries[i].alg >= entry.alg
122
+		}
123
+		return dst.entries[i].val >= entry.val
124
+	}
125
+	idx := sort.Search(len(dst.entries), searchFunc)
126
+	if idx == len(dst.entries) {
127
+		dst.entries = append(dst.entries, entry)
128
+		return nil
129
+	} else if dst.entries[idx].digest == d {
130
+		return nil
131
+	}
132
+
133
+	entries := append(dst.entries, nil)
134
+	copy(entries[idx+1:], entries[idx:len(entries)-1])
135
+	entries[idx] = entry
136
+	dst.entries = entries
137
+	return nil
138
+}
139
+
140
+// Remove removes the given digest from the set. An err will be
141
+// returned if the given digest is invalid. If the digest does
142
+// not exist in the set, this operation will be a no-op.
143
+func (dst *Set) Remove(d digest.Digest) error {
144
+	if err := d.Validate(); err != nil {
145
+		return err
146
+	}
147
+	dst.mutex.Lock()
148
+	defer dst.mutex.Unlock()
149
+	entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d}
150
+	searchFunc := func(i int) bool {
151
+		if dst.entries[i].val == entry.val {
152
+			return dst.entries[i].alg >= entry.alg
153
+		}
154
+		return dst.entries[i].val >= entry.val
155
+	}
156
+	idx := sort.Search(len(dst.entries), searchFunc)
157
+	// Not found if idx is after or value at idx is not digest
158
+	if idx == len(dst.entries) || dst.entries[idx].digest != d {
159
+		return nil
160
+	}
161
+
162
+	entries := dst.entries
163
+	copy(entries[idx:], entries[idx+1:])
164
+	entries = entries[:len(entries)-1]
165
+	dst.entries = entries
166
+
167
+	return nil
168
+}
169
+
170
+// All returns all the digests in the set
171
+func (dst *Set) All() []digest.Digest {
172
+	dst.mutex.RLock()
173
+	defer dst.mutex.RUnlock()
174
+	retValues := make([]digest.Digest, len(dst.entries))
175
+	for i := range dst.entries {
176
+		retValues[i] = dst.entries[i].digest
177
+	}
178
+
179
+	return retValues
180
+}
181
+
182
+// ShortCodeTable returns a map of Digest to unique short codes. The
183
+// length represents the minimum value, the maximum length may be the
184
+// entire value of digest if uniqueness cannot be achieved without the
185
+// full value. This function will attempt to make short codes as short
186
+// as possible to be unique.
187
+func ShortCodeTable(dst *Set, length int) map[digest.Digest]string {
188
+	dst.mutex.RLock()
189
+	defer dst.mutex.RUnlock()
190
+	m := make(map[digest.Digest]string, len(dst.entries))
191
+	l := length
192
+	resetIdx := 0
193
+	for i := 0; i < len(dst.entries); i++ {
194
+		var short string
195
+		extended := true
196
+		for extended {
197
+			extended = false
198
+			if len(dst.entries[i].val) <= l {
199
+				short = dst.entries[i].digest.String()
200
+			} else {
201
+				short = dst.entries[i].val[:l]
202
+				for j := i + 1; j < len(dst.entries); j++ {
203
+					if checkShortMatch(dst.entries[j].alg, dst.entries[j].val, "", short) {
204
+						if j > resetIdx {
205
+							resetIdx = j
206
+						}
207
+						extended = true
208
+					} else {
209
+						break
210
+					}
211
+				}
212
+				if extended {
213
+					l++
214
+				}
215
+			}
216
+		}
217
+		m[dst.entries[i].digest] = short
218
+		if i >= resetIdx {
219
+			l = length
220
+		}
221
+	}
222
+	return m
223
+}
224
+
225
+type digestEntry struct {
226
+	alg    digest.Algorithm
227
+	val    string
228
+	digest digest.Digest
229
+}
230
+
231
+type digestEntries []*digestEntry
232
+
233
+func (d digestEntries) Len() int {
234
+	return len(d)
235
+}
236
+
237
+func (d digestEntries) Less(i, j int) bool {
238
+	if d[i].val != d[j].val {
239
+		return d[i].val < d[j].val
240
+	}
241
+	return d[i].alg < d[j].alg
242
+}
243
+
244
+func (d digestEntries) Swap(i, j int) {
245
+	d[i], d[j] = d[j], d[i]
246
+}
... ...
@@ -5,7 +5,7 @@ import (
5 5
 	"fmt"
6 6
 	"strings"
7 7
 
8
-	"github.com/docker/distribution/digest"
8
+	"github.com/opencontainers/go-digest"
9 9
 )
10 10
 
11 11
 // ErrAccessDenied is returned when an access to a requested resource is
... ...
@@ -6,8 +6,8 @@ import (
6 6
 	"fmt"
7 7
 
8 8
 	"github.com/docker/distribution"
9
-	"github.com/docker/distribution/digest"
10 9
 	"github.com/docker/distribution/manifest"
10
+	"github.com/opencontainers/go-digest"
11 11
 )
12 12
 
13 13
 // MediaTypeManifestList specifies the mediaType for manifest lists.
... ...
@@ -9,10 +9,10 @@ import (
9 9
 
10 10
 	"github.com/docker/distribution"
11 11
 	"github.com/docker/distribution/context"
12
-	"github.com/docker/distribution/digest"
13 12
 	"github.com/docker/distribution/manifest"
14 13
 	"github.com/docker/distribution/reference"
15 14
 	"github.com/docker/libtrust"
15
+	"github.com/opencontainers/go-digest"
16 16
 )
17 17
 
18 18
 type diffID digest.Digest
... ...
@@ -5,9 +5,9 @@ import (
5 5
 	"fmt"
6 6
 
7 7
 	"github.com/docker/distribution"
8
-	"github.com/docker/distribution/digest"
9 8
 	"github.com/docker/distribution/manifest"
10 9
 	"github.com/docker/libtrust"
10
+	"github.com/opencontainers/go-digest"
11 11
 )
12 12
 
13 13
 const (
... ...
@@ -6,10 +6,10 @@ import (
6 6
 	"errors"
7 7
 	"github.com/docker/distribution"
8 8
 	"github.com/docker/distribution/context"
9
-	"github.com/docker/distribution/digest"
10 9
 	"github.com/docker/distribution/manifest"
11 10
 	"github.com/docker/distribution/reference"
12 11
 	"github.com/docker/libtrust"
12
+	"github.com/opencontainers/go-digest"
13 13
 )
14 14
 
15 15
 // referenceManifestBuilder is a type for constructing manifests from schema1
... ...
@@ -3,7 +3,7 @@ package schema2
3 3
 import (
4 4
 	"github.com/docker/distribution"
5 5
 	"github.com/docker/distribution/context"
6
-	"github.com/docker/distribution/digest"
6
+	"github.com/opencontainers/go-digest"
7 7
 )
8 8
 
9 9
 // builder is a type for constructing manifests.
... ...
@@ -6,8 +6,8 @@ import (
6 6
 	"fmt"
7 7
 
8 8
 	"github.com/docker/distribution"
9
-	"github.com/docker/distribution/digest"
10 9
 	"github.com/docker/distribution/manifest"
10
+	"github.com/opencontainers/go-digest"
11 11
 )
12 12
 
13 13
 const (
... ...
@@ -5,7 +5,7 @@ import (
5 5
 	"mime"
6 6
 
7 7
 	"github.com/docker/distribution/context"
8
-	"github.com/docker/distribution/digest"
8
+	"github.com/opencontainers/go-digest"
9 9
 )
10 10
 
11 11
 // Manifest represents a registry object specifying a set of
... ...
@@ -27,7 +27,7 @@ import (
27 27
 	"path"
28 28
 	"strings"
29 29
 
30
-	"github.com/docker/distribution/digest"
30
+	"github.com/opencontainers/go-digest"
31 31
 )
32 32
 
33 33
 const (
... ...
@@ -170,7 +170,7 @@ func Parse(s string) (Reference, error) {
170 170
 	}
171 171
 	if matches[3] != "" {
172 172
 		var err error
173
-		ref.digest, err = digest.ParseDigest(matches[3])
173
+		ref.digest, err = digest.Parse(matches[3])
174 174
 		if err != nil {
175 175
 			return nil, err
176 176
 		}
... ...
@@ -4,9 +4,9 @@ import (
4 4
 	"net/http"
5 5
 	"regexp"
6 6
 
7
-	"github.com/docker/distribution/digest"
8 7
 	"github.com/docker/distribution/reference"
9 8
 	"github.com/docker/distribution/registry/api/errcode"
9
+	"github.com/opencontainers/go-digest"
10 10
 )
11 11
 
12 12
 var (
... ...
@@ -15,12 +15,12 @@ import (
15 15
 
16 16
 	"github.com/docker/distribution"
17 17
 	"github.com/docker/distribution/context"
18
-	"github.com/docker/distribution/digest"
19 18
 	"github.com/docker/distribution/reference"
20 19
 	"github.com/docker/distribution/registry/api/v2"
21 20
 	"github.com/docker/distribution/registry/client/transport"
22 21
 	"github.com/docker/distribution/registry/storage/cache"
23 22
 	"github.com/docker/distribution/registry/storage/cache/memory"
23
+	"github.com/opencontainers/go-digest"
24 24
 )
25 25
 
26 26
 // 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
268 268
 		return desc, nil
269 269
 	}
270 270
 
271
-	dgst, err := digest.ParseDigest(digestHeader)
271
+	dgst, err := digest.Parse(digestHeader)
272 272
 	if err != nil {
273 273
 		return distribution.Descriptor{}, err
274 274
 	}
... ...
@@ -475,7 +475,7 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis
475 475
 		return nil, distribution.ErrManifestNotModified
476 476
 	} else if SuccessStatus(resp.StatusCode) {
477 477
 		if contentDgst != nil {
478
-			dgst, err := digest.ParseDigest(resp.Header.Get("Docker-Content-Digest"))
478
+			dgst, err := digest.Parse(resp.Header.Get("Docker-Content-Digest"))
479 479
 			if err == nil {
480 480
 				*contentDgst = dgst
481 481
 			}
... ...
@@ -553,7 +553,7 @@ func (ms *manifests) Put(ctx context.Context, m distribution.Manifest, options .
553 553
 
554 554
 	if SuccessStatus(resp.StatusCode) {
555 555
 		dgstHeader := resp.Header.Get("Docker-Content-Digest")
556
-		dgst, err := digest.ParseDigest(dgstHeader)
556
+		dgst, err := digest.Parse(dgstHeader)
557 557
 		if err != nil {
558 558
 			return "", err
559 559
 		}
... ...
@@ -661,7 +661,7 @@ func (bs *blobs) Put(ctx context.Context, mediaType string, p []byte) (distribut
661 661
 	if err != nil {
662 662
 		return distribution.Descriptor{}, err
663 663
 	}
664
-	dgstr := digest.Canonical.New()
664
+	dgstr := digest.Canonical.Digester()
665 665
 	n, err := io.Copy(writer, io.TeeReader(bytes.NewReader(p), dgstr.Hash()))
666 666
 	if err != nil {
667 667
 		return distribution.Descriptor{}, err
... ...
@@ -2,7 +2,7 @@ package cache
2 2
 
3 3
 import (
4 4
 	"github.com/docker/distribution/context"
5
-	"github.com/docker/distribution/digest"
5
+	"github.com/opencontainers/go-digest"
6 6
 
7 7
 	"github.com/docker/distribution"
8 8
 )
... ...
@@ -5,9 +5,9 @@ import (
5 5
 
6 6
 	"github.com/docker/distribution"
7 7
 	"github.com/docker/distribution/context"
8
-	"github.com/docker/distribution/digest"
9 8
 	"github.com/docker/distribution/reference"
10 9
 	"github.com/docker/distribution/registry/storage/cache"
10
+	"github.com/opencontainers/go-digest"
11 11
 )
12 12
 
13 13
 type inMemoryBlobDescriptorCacheProvider struct {
... ...
@@ -302,15 +302,6 @@ func reconcileTaskState(ctx context.Context, w *worker, assignments []*api.Assig
302 302
 }
303 303
 
304 304
 func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.AssignmentChange, fullSnapshot bool) error {
305
-	var secrets exec.SecretsManager
306
-	provider, ok := w.executor.(exec.SecretsProvider)
307
-	if !ok {
308
-		log.G(ctx).Warn("secrets update ignored; executor does not support secrets")
309
-		return nil
310
-	}
311
-
312
-	secrets = provider.Secrets()
313
-
314 305
 	var (
315 306
 		updatedSecrets []api.Secret
316 307
 		removedSecrets []string
... ...
@@ -327,6 +318,16 @@ func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.Assignm
327 327
 		}
328 328
 	}
329 329
 
330
+	provider, ok := w.executor.(exec.SecretsProvider)
331
+	if !ok {
332
+		if len(updatedSecrets) != 0 || len(removedSecrets) != 0 {
333
+			log.G(ctx).Warn("secrets update ignored; executor does not support secrets")
334
+		}
335
+		return nil
336
+	}
337
+
338
+	secrets := provider.Secrets()
339
+
330 340
 	log.G(ctx).WithFields(logrus.Fields{
331 341
 		"len(updatedSecrets)": len(updatedSecrets),
332 342
 		"len(removedSecrets)": len(removedSecrets),
... ...
@@ -57,6 +57,16 @@ type Node struct {
57 57
 	Attachment *NetworkAttachment `protobuf:"bytes,7,opt,name=attachment" json:"attachment,omitempty"`
58 58
 	// Certificate is the TLS certificate issued for the node, if any.
59 59
 	Certificate Certificate `protobuf:"bytes,8,opt,name=certificate" json:"certificate"`
60
+	// Role is the *observed* role for this node. It differs from the
61
+	// desired role set in Node.Spec.Role because the role here is only
62
+	// updated after the Raft member list has been reconciled with the
63
+	// desired role from the spec.
64
+	//
65
+	// This field represents the current reconciled state. If an action is
66
+	// to be performed, first verify the role in the cert. This field only
67
+	// shows the privilege level that the CA would currently grant when
68
+	// issuing or renewing the node's certificate.
69
+	Role NodeRole `protobuf:"varint,9,opt,name=role,proto3,enum=docker.swarmkit.v1.NodeRole" json:"role,omitempty"`
60 70
 }
61 71
 
62 72
 func (m *Node) Reset()                    { *m = Node{} }
... ...
@@ -303,6 +313,7 @@ func (m *Node) Copy() *Node {
303 303
 		ManagerStatus: m.ManagerStatus.Copy(),
304 304
 		Attachment:    m.Attachment.Copy(),
305 305
 		Certificate:   *m.Certificate.Copy(),
306
+		Role:          m.Role,
306 307
 	}
307 308
 
308 309
 	return o
... ...
@@ -504,7 +515,7 @@ func (this *Node) GoString() string {
504 504
 	if this == nil {
505 505
 		return "nil"
506 506
 	}
507
-	s := make([]string, 0, 12)
507
+	s := make([]string, 0, 13)
508 508
 	s = append(s, "&api.Node{")
509 509
 	s = append(s, "ID: "+fmt.Sprintf("%#v", this.ID)+",\n")
510 510
 	s = append(s, "Meta: "+strings.Replace(this.Meta.GoString(), `&`, ``, 1)+",\n")
... ...
@@ -520,6 +531,7 @@ func (this *Node) GoString() string {
520 520
 		s = append(s, "Attachment: "+fmt.Sprintf("%#v", this.Attachment)+",\n")
521 521
 	}
522 522
 	s = append(s, "Certificate: "+strings.Replace(this.Certificate.GoString(), `&`, ``, 1)+",\n")
523
+	s = append(s, "Role: "+fmt.Sprintf("%#v", this.Role)+",\n")
523 524
 	s = append(s, "}")
524 525
 	return strings.Join(s, "")
525 526
 }
... ...
@@ -834,6 +846,11 @@ func (m *Node) MarshalTo(data []byte) (int, error) {
834 834
 		return 0, err
835 835
 	}
836 836
 	i += n10
837
+	if m.Role != 0 {
838
+		data[i] = 0x48
839
+		i++
840
+		i = encodeVarintObjects(data, i, uint64(m.Role))
841
+	}
837 842
 	return i, nil
838 843
 }
839 844
 
... ...
@@ -1451,6 +1468,9 @@ func (m *Node) Size() (n int) {
1451 1451
 	}
1452 1452
 	l = m.Certificate.Size()
1453 1453
 	n += 1 + l + sovObjects(uint64(l))
1454
+	if m.Role != 0 {
1455
+		n += 1 + sovObjects(uint64(m.Role))
1456
+	}
1454 1457
 	return n
1455 1458
 }
1456 1459
 
... ...
@@ -1707,6 +1727,7 @@ func (this *Node) String() string {
1707 1707
 		`ManagerStatus:` + strings.Replace(fmt.Sprintf("%v", this.ManagerStatus), "ManagerStatus", "ManagerStatus", 1) + `,`,
1708 1708
 		`Attachment:` + strings.Replace(fmt.Sprintf("%v", this.Attachment), "NetworkAttachment", "NetworkAttachment", 1) + `,`,
1709 1709
 		`Certificate:` + strings.Replace(strings.Replace(this.Certificate.String(), "Certificate", "Certificate", 1), `&`, ``, 1) + `,`,
1710
+		`Role:` + fmt.Sprintf("%v", this.Role) + `,`,
1710 1711
 		`}`,
1711 1712
 	}, "")
1712 1713
 	return s
... ...
@@ -2268,6 +2289,25 @@ func (m *Node) Unmarshal(data []byte) error {
2268 2268
 				return err
2269 2269
 			}
2270 2270
 			iNdEx = postIndex
2271
+		case 9:
2272
+			if wireType != 0 {
2273
+				return fmt.Errorf("proto: wrong wireType = %d for field Role", wireType)
2274
+			}
2275
+			m.Role = 0
2276
+			for shift := uint(0); ; shift += 7 {
2277
+				if shift >= 64 {
2278
+					return ErrIntOverflowObjects
2279
+				}
2280
+				if iNdEx >= l {
2281
+					return io.ErrUnexpectedEOF
2282
+				}
2283
+				b := data[iNdEx]
2284
+				iNdEx++
2285
+				m.Role |= (NodeRole(b) & 0x7F) << shift
2286
+				if b < 0x80 {
2287
+					break
2288
+				}
2289
+			}
2271 2290
 		default:
2272 2291
 			iNdEx = preIndex
2273 2292
 			skippy, err := skipObjects(data[iNdEx:])
... ...
@@ -4186,78 +4226,79 @@ var (
4186 4186
 func init() { proto.RegisterFile("objects.proto", fileDescriptorObjects) }
4187 4187
 
4188 4188
 var fileDescriptorObjects = []byte{
4189
-	// 1161 bytes of a gzipped FileDescriptorProto
4190
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x57, 0x4d, 0x8f, 0x1b, 0x35,
4191
-	0x18, 0xee, 0x24, 0xb3, 0xf9, 0x78, 0xb3, 0x59, 0x81, 0xa9, 0xca, 0x34, 0x2c, 0xc9, 0x92, 0x0a,
4192
-	0x54, 0xa1, 0x2a, 0x15, 0xa5, 0xa0, 0x2d, 0xb4, 0x82, 0x7c, 0x09, 0xa2, 0x52, 0xa8, 0xdc, 0xb2,
4193
-	0x3d, 0x46, 0xde, 0x19, 0x37, 0x0c, 0x99, 0x8c, 0x47, 0xb6, 0x93, 0x2a, 0x37, 0xc4, 0x0f, 0xe0,
4194
-	0x27, 0x20, 0xce, 0xfc, 0x09, 0xae, 0x7b, 0xe0, 0xc0, 0x0d, 0x4e, 0x11, 0x9b, 0x1b, 0x37, 0x7e,
4195
-	0x02, 0xb2, 0xc7, 0x93, 0xcc, 0x2a, 0x93, 0x65, 0x2b, 0x55, 0x7b, 0xb3, 0xe3, 0xe7, 0x79, 0xde,
4196
-	0xd7, 0xaf, 0x1f, 0xbf, 0xe3, 0x40, 0x95, 0x1d, 0x7f, 0x4f, 0x5d, 0x29, 0x5a, 0x11, 0x67, 0x92,
4197
-	0x21, 0xe4, 0x31, 0x77, 0x4c, 0x79, 0x4b, 0xbc, 0x20, 0x7c, 0x32, 0xf6, 0x65, 0x6b, 0xf6, 0x41,
4198
-	0xad, 0x22, 0xe7, 0x11, 0x35, 0x80, 0x5a, 0x45, 0x44, 0xd4, 0x4d, 0x26, 0xd7, 0xa5, 0x3f, 0xa1,
4199
-	0x42, 0x92, 0x49, 0x74, 0x7b, 0x35, 0x32, 0x4b, 0x57, 0x47, 0x6c, 0xc4, 0xf4, 0xf0, 0xb6, 0x1a,
4200
-	0xc5, 0xbf, 0x36, 0x7f, 0xb3, 0xc0, 0x7e, 0x44, 0x25, 0x41, 0x9f, 0x42, 0x71, 0x46, 0xb9, 0xf0,
4201
-	0x59, 0xe8, 0x58, 0x07, 0xd6, 0xcd, 0xca, 0x9d, 0xb7, 0x5a, 0x9b, 0x91, 0x5b, 0x47, 0x31, 0xa4,
4202
-	0x63, 0x9f, 0x2c, 0x1a, 0x57, 0x70, 0xc2, 0x40, 0xf7, 0x01, 0x5c, 0x4e, 0x89, 0xa4, 0xde, 0x90,
4203
-	0x48, 0x27, 0xa7, 0xf9, 0x6f, 0x67, 0xf1, 0x9f, 0x26, 0x49, 0xe1, 0xb2, 0x21, 0xb4, 0xa5, 0x62,
4204
-	0x4f, 0x23, 0x2f, 0x61, 0xe7, 0x2f, 0xc4, 0x36, 0x84, 0xb6, 0x6c, 0xfe, 0x93, 0x07, 0xfb, 0x6b,
4205
-	0xe6, 0x51, 0x74, 0x0d, 0x72, 0xbe, 0xa7, 0x93, 0x2f, 0x77, 0x0a, 0xcb, 0x45, 0x23, 0x37, 0xe8,
4206
-	0xe1, 0x9c, 0xef, 0xa1, 0x3b, 0x60, 0x4f, 0xa8, 0x24, 0x26, 0x2d, 0x27, 0x4b, 0x58, 0x55, 0xc0,
4207
-	0xec, 0x49, 0x63, 0xd1, 0xc7, 0x60, 0xab, 0xb2, 0x9a, 0x64, 0xf6, 0xb3, 0x38, 0x2a, 0xe6, 0x93,
4208
-	0x88, 0xba, 0x09, 0x4f, 0xe1, 0x51, 0x1f, 0x2a, 0x1e, 0x15, 0x2e, 0xf7, 0x23, 0xa9, 0x2a, 0x69,
4209
-	0x6b, 0xfa, 0x8d, 0x6d, 0xf4, 0xde, 0x1a, 0x8a, 0xd3, 0x3c, 0x74, 0x1f, 0x0a, 0x42, 0x12, 0x39,
4210
-	0x15, 0xce, 0x8e, 0x56, 0xa8, 0x6f, 0x4d, 0x40, 0xa3, 0x4c, 0x0a, 0x86, 0x83, 0xbe, 0x84, 0xbd,
4211
-	0x09, 0x09, 0xc9, 0x88, 0xf2, 0xa1, 0x51, 0x29, 0x68, 0x95, 0x77, 0x32, 0xb7, 0x1e, 0x23, 0x63,
4212
-	0x21, 0x5c, 0x9d, 0xa4, 0xa7, 0xa8, 0x0f, 0x40, 0xa4, 0x24, 0xee, 0x77, 0x13, 0x1a, 0x4a, 0xa7,
4213
-	0xa8, 0x55, 0xde, 0xcd, 0xcc, 0x85, 0xca, 0x17, 0x8c, 0x8f, 0xdb, 0x2b, 0x30, 0x4e, 0x11, 0xd1,
4214
-	0x17, 0x50, 0x71, 0x29, 0x97, 0xfe, 0x73, 0xdf, 0x25, 0x92, 0x3a, 0x25, 0xad, 0xd3, 0xc8, 0xd2,
4215
-	0xe9, 0xae, 0x61, 0x66, 0x53, 0x69, 0x66, 0xf3, 0xcf, 0x1c, 0x14, 0x9f, 0x50, 0x3e, 0xf3, 0xdd,
4216
-	0x57, 0x7b, 0xdc, 0xf7, 0xce, 0x1c, 0x77, 0x66, 0x66, 0x26, 0xec, 0xc6, 0x89, 0x1f, 0x42, 0x89,
4217
-	0x86, 0x5e, 0xc4, 0xfc, 0x50, 0x9a, 0xe3, 0xce, 0x74, 0x4b, 0xdf, 0x60, 0xf0, 0x0a, 0x8d, 0xfa,
4218
-	0x50, 0x8d, 0x5d, 0x3c, 0x3c, 0x73, 0xd6, 0x07, 0x59, 0xf4, 0x6f, 0x35, 0xd0, 0x1c, 0xd2, 0xee,
4219
-	0x34, 0x35, 0x43, 0x3d, 0xa8, 0x46, 0x9c, 0xce, 0x7c, 0x36, 0x15, 0x43, 0xbd, 0x89, 0xc2, 0x85,
4220
-	0x36, 0x81, 0x77, 0x13, 0x96, 0x9a, 0x35, 0x7f, 0xce, 0x41, 0x29, 0xc9, 0x11, 0xdd, 0x35, 0xe5,
4221
-	0xb0, 0xb6, 0x27, 0x94, 0x60, 0xb5, 0x54, 0x5c, 0x89, 0xbb, 0xb0, 0x13, 0x31, 0x2e, 0x85, 0x93,
4222
-	0x3b, 0xc8, 0x6f, 0xf3, 0xec, 0x63, 0xc6, 0x65, 0x97, 0x85, 0xcf, 0xfd, 0x11, 0x8e, 0xc1, 0xe8,
4223
-	0x19, 0x54, 0x66, 0x3e, 0x97, 0x53, 0x12, 0x0c, 0xfd, 0x48, 0x38, 0x79, 0xcd, 0x7d, 0xef, 0xbc,
4224
-	0x90, 0xad, 0xa3, 0x18, 0x3f, 0x78, 0xdc, 0xd9, 0x5b, 0x2e, 0x1a, 0xb0, 0x9a, 0x0a, 0x0c, 0x46,
4225
-	0x6a, 0x10, 0x89, 0xda, 0x23, 0x28, 0xaf, 0x56, 0xd0, 0x2d, 0x80, 0x30, 0xb6, 0xe8, 0x70, 0x65,
4226
-	0x9a, 0xea, 0x72, 0xd1, 0x28, 0x1b, 0xe3, 0x0e, 0x7a, 0xb8, 0x6c, 0x00, 0x03, 0x0f, 0x21, 0xb0,
4227
-	0x89, 0xe7, 0x71, 0x6d, 0xa1, 0x32, 0xd6, 0xe3, 0xe6, 0xef, 0x3b, 0x60, 0x3f, 0x25, 0x62, 0x7c,
4228
-	0xd9, 0x6d, 0x46, 0xc5, 0xdc, 0x30, 0xdd, 0x2d, 0x00, 0x11, 0x1f, 0xa5, 0xda, 0x8e, 0xbd, 0xde,
4229
-	0x8e, 0x39, 0x60, 0xb5, 0x1d, 0x03, 0x88, 0xb7, 0x23, 0x02, 0x26, 0xb5, 0xbf, 0x6c, 0xac, 0xc7,
4230
-	0xe8, 0x06, 0x14, 0x43, 0xe6, 0x69, 0x7a, 0x41, 0xd3, 0x61, 0xb9, 0x68, 0x14, 0x54, 0x4b, 0x19,
4231
-	0xf4, 0x70, 0x41, 0x2d, 0x0d, 0x3c, 0x75, 0x6f, 0x49, 0x18, 0x32, 0x49, 0x54, 0x53, 0x12, 0xe6,
4232
-	0xfe, 0x67, 0x1a, 0xab, 0xbd, 0x86, 0x25, 0xf7, 0x36, 0xc5, 0x44, 0x47, 0xf0, 0x46, 0x92, 0x6f,
4233
-	0x5a, 0xb0, 0xf4, 0x32, 0x82, 0xc8, 0x28, 0xa4, 0x56, 0x52, 0x7d, 0xb2, 0xbc, 0xbd, 0x4f, 0xea,
4234
-	0x0a, 0x66, 0xf5, 0xc9, 0x0e, 0x54, 0x3d, 0x2a, 0x7c, 0x4e, 0x3d, 0x7d, 0x03, 0xa9, 0x03, 0x07,
4235
-	0xd6, 0xcd, 0xbd, 0x2d, 0x9f, 0x1e, 0x23, 0x42, 0xf1, 0xae, 0xe1, 0xe8, 0x19, 0x6a, 0x43, 0xc9,
4236
-	0xf8, 0x46, 0x38, 0x15, 0xed, 0xdd, 0x0b, 0xf6, 0xc7, 0x15, 0xed, 0x4c, 0x07, 0xd9, 0x7d, 0xa9,
4237
-	0x0e, 0x72, 0x0f, 0x20, 0x60, 0xa3, 0xa1, 0xc7, 0xfd, 0x19, 0xe5, 0x4e, 0x55, 0x73, 0x6b, 0x59,
4238
-	0xdc, 0x9e, 0x46, 0xe0, 0x72, 0xc0, 0x46, 0xf1, 0xb0, 0xf9, 0xa3, 0x05, 0xaf, 0x6f, 0x24, 0x85,
4239
-	0x3e, 0x82, 0xa2, 0x49, 0xeb, 0xbc, 0x47, 0x80, 0xe1, 0xe1, 0x04, 0x8b, 0xf6, 0xa1, 0xac, 0xee,
4240
-	0x08, 0x15, 0x82, 0xc6, 0xb7, 0xbf, 0x8c, 0xd7, 0x3f, 0x20, 0x07, 0x8a, 0x24, 0xf0, 0x89, 0x5a,
4241
-	0xcb, 0xeb, 0xb5, 0x64, 0xda, 0xfc, 0x29, 0x07, 0x45, 0x23, 0x76, 0xd9, 0xed, 0xdc, 0x84, 0xdd,
4242
-	0xb8, 0x59, 0x0f, 0x60, 0x37, 0x2e, 0xa7, 0xb1, 0x84, 0xfd, 0xbf, 0x45, 0xad, 0xc4, 0xf8, 0xd8,
4243
-	0x0e, 0x0f, 0xc0, 0xf6, 0x23, 0x32, 0x31, 0xad, 0x3c, 0x33, 0xf2, 0xe0, 0x71, 0xfb, 0xd1, 0x37,
4244
-	0x51, 0xec, 0xec, 0xd2, 0x72, 0xd1, 0xb0, 0xd5, 0x0f, 0x58, 0xd3, 0x9a, 0xbf, 0xec, 0x40, 0xb1,
4245
-	0x1b, 0x4c, 0x85, 0xa4, 0xfc, 0xb2, 0x0b, 0x62, 0xc2, 0x6e, 0x14, 0xa4, 0x0b, 0x45, 0xce, 0x98,
4246
-	0x1c, 0xba, 0xe4, 0xbc, 0x5a, 0x60, 0xc6, 0x64, 0xb7, 0xdd, 0xd9, 0x53, 0x44, 0xd5, 0x48, 0xe2,
4247
-	0x39, 0x2e, 0x28, 0x6a, 0x97, 0xa0, 0x67, 0x70, 0x2d, 0x69, 0xbf, 0xc7, 0x8c, 0x49, 0x21, 0x39,
4248
-	0x89, 0x86, 0x63, 0x3a, 0x57, 0xdf, 0xbc, 0xfc, 0xb6, 0x97, 0x49, 0x3f, 0x74, 0xf9, 0x5c, 0x17,
4249
-	0xea, 0x21, 0x9d, 0xe3, 0xab, 0x46, 0xa0, 0x93, 0xf0, 0x1f, 0xd2, 0xb9, 0x40, 0x9f, 0xc1, 0x3e,
4250
-	0x5d, 0xc1, 0x94, 0xe2, 0x30, 0x20, 0x13, 0xf5, 0x61, 0x19, 0xba, 0x01, 0x73, 0xc7, 0xba, 0xb7,
4251
-	0xd9, 0xf8, 0x3a, 0x4d, 0x4b, 0x7d, 0x15, 0x23, 0xba, 0x0a, 0x80, 0x04, 0x38, 0xc7, 0x01, 0x71,
4252
-	0xc7, 0x81, 0x2f, 0xd4, 0xfb, 0x33, 0xf5, 0xd8, 0x50, 0xed, 0x49, 0xe5, 0x76, 0x78, 0x4e, 0xb5,
4253
-	0x5a, 0x9d, 0x35, 0x37, 0xf5, 0x74, 0x11, 0xfd, 0x50, 0xf2, 0x39, 0x7e, 0xf3, 0x38, 0x7b, 0x15,
4254
-	0x75, 0xa0, 0x32, 0x0d, 0x55, 0xf8, 0xb8, 0x06, 0xe5, 0x8b, 0xd6, 0x00, 0x62, 0x96, 0xda, 0x79,
4255
-	0x6d, 0x06, 0xfb, 0xe7, 0x05, 0x47, 0xaf, 0x41, 0x7e, 0x4c, 0xe7, 0xb1, 0x7f, 0xb0, 0x1a, 0xa2,
4256
-	0xcf, 0x61, 0x67, 0x46, 0x82, 0x29, 0x35, 0xce, 0x79, 0x3f, 0x2b, 0x5e, 0xb6, 0x24, 0x8e, 0x89,
4257
-	0x9f, 0xe4, 0x0e, 0xad, 0xe6, 0xaf, 0x16, 0x14, 0x9e, 0x50, 0x97, 0x53, 0xf9, 0x4a, 0x1d, 0x7a,
4258
-	0x78, 0xc6, 0xa1, 0xf5, 0xec, 0xc7, 0x8b, 0x8a, 0xba, 0x61, 0xd0, 0x1a, 0x94, 0xfc, 0x50, 0x52,
4259
-	0x1e, 0x92, 0x40, 0x3b, 0xb4, 0x84, 0x57, 0xf3, 0xce, 0xfe, 0xc9, 0x69, 0xfd, 0xca, 0x5f, 0xa7,
4260
-	0xf5, 0x2b, 0xff, 0x9e, 0xd6, 0xad, 0x1f, 0x96, 0x75, 0xeb, 0x64, 0x59, 0xb7, 0xfe, 0x58, 0xd6,
4261
-	0xad, 0xbf, 0x97, 0x75, 0xeb, 0xb8, 0xa0, 0xff, 0x02, 0x7d, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0xff,
4262
-	0xff, 0x38, 0xf8, 0x23, 0xac, 0x72, 0x0d, 0x00, 0x00,
4189
+	// 1176 bytes of a gzipped FileDescriptorProto
4190
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x57, 0xcf, 0x8e, 0x1b, 0x35,
4191
+	0x1c, 0xee, 0x64, 0x67, 0x93, 0xcc, 0x2f, 0x9b, 0x15, 0x98, 0xaa, 0x4c, 0x97, 0x6d, 0xb2, 0xa4,
4192
+	0x02, 0x55, 0xa8, 0x4a, 0xa1, 0x14, 0xb4, 0x85, 0x56, 0x90, 0x7f, 0x82, 0xa8, 0x14, 0x2a, 0xb7,
4193
+	0xb4, 0xc7, 0xc8, 0x3b, 0xe3, 0x86, 0x21, 0x93, 0xf1, 0xc8, 0x76, 0x52, 0xe5, 0x86, 0x78, 0x00,
4194
+	0x5e, 0x00, 0x09, 0x71, 0xe6, 0x25, 0xb8, 0xf6, 0xc0, 0x81, 0x1b, 0x9c, 0x22, 0x9a, 0x27, 0xe0,
4195
+	0x11, 0x90, 0x3d, 0x9e, 0x64, 0x56, 0x99, 0x84, 0xad, 0x54, 0xed, 0xcd, 0x8e, 0xbf, 0xef, 0xfb,
4196
+	0xfd, 0x99, 0xcf, 0xbf, 0xf5, 0x42, 0x95, 0x9d, 0x7c, 0x4f, 0x3d, 0x29, 0x9a, 0x31, 0x67, 0x92,
4197
+	0x21, 0xe4, 0x33, 0x6f, 0x44, 0x79, 0x53, 0x3c, 0x23, 0x7c, 0x3c, 0x0a, 0x64, 0x73, 0xfa, 0xc1,
4198
+	0x41, 0x45, 0xce, 0x62, 0x6a, 0x00, 0x07, 0x15, 0x11, 0x53, 0x2f, 0xdd, 0x5c, 0x96, 0xc1, 0x98,
4199
+	0x0a, 0x49, 0xc6, 0xf1, 0x8d, 0xe5, 0xca, 0x1c, 0x5d, 0x1c, 0xb2, 0x21, 0xd3, 0xcb, 0x1b, 0x6a,
4200
+	0x95, 0xfc, 0xda, 0xf8, 0xdd, 0x02, 0xfb, 0x3e, 0x95, 0x04, 0x7d, 0x0a, 0xa5, 0x29, 0xe5, 0x22,
4201
+	0x60, 0x91, 0x6b, 0x1d, 0x59, 0xd7, 0x2a, 0x37, 0xdf, 0x6a, 0xae, 0x47, 0x6e, 0x3e, 0x4e, 0x20,
4202
+	0x6d, 0xfb, 0xf9, 0xbc, 0x7e, 0x01, 0xa7, 0x0c, 0x74, 0x07, 0xc0, 0xe3, 0x94, 0x48, 0xea, 0x0f,
4203
+	0x88, 0x74, 0x0b, 0x9a, 0x7f, 0x25, 0x8f, 0xff, 0x28, 0x4d, 0x0a, 0x3b, 0x86, 0xd0, 0x92, 0x8a,
4204
+	0x3d, 0x89, 0xfd, 0x94, 0xbd, 0x73, 0x26, 0xb6, 0x21, 0xb4, 0x64, 0xe3, 0x67, 0x1b, 0xec, 0xaf,
4205
+	0x99, 0x4f, 0xd1, 0x25, 0x28, 0x04, 0xbe, 0x4e, 0xde, 0x69, 0x17, 0x17, 0xf3, 0x7a, 0xa1, 0xdf,
4206
+	0xc5, 0x85, 0xc0, 0x47, 0x37, 0xc1, 0x1e, 0x53, 0x49, 0x4c, 0x5a, 0x6e, 0x9e, 0xb0, 0xea, 0x80,
4207
+	0xa9, 0x49, 0x63, 0xd1, 0xc7, 0x60, 0xab, 0xb6, 0x9a, 0x64, 0x0e, 0xf3, 0x38, 0x2a, 0xe6, 0xc3,
4208
+	0x98, 0x7a, 0x29, 0x4f, 0xe1, 0x51, 0x0f, 0x2a, 0x3e, 0x15, 0x1e, 0x0f, 0x62, 0xa9, 0x3a, 0x69,
4209
+	0x6b, 0xfa, 0xd5, 0x4d, 0xf4, 0xee, 0x0a, 0x8a, 0xb3, 0x3c, 0x74, 0x07, 0x8a, 0x42, 0x12, 0x39,
4210
+	0x11, 0xee, 0xae, 0x56, 0xa8, 0x6d, 0x4c, 0x40, 0xa3, 0x4c, 0x0a, 0x86, 0x83, 0xbe, 0x84, 0xfd,
4211
+	0x31, 0x89, 0xc8, 0x90, 0xf2, 0x81, 0x51, 0x29, 0x6a, 0x95, 0xb7, 0x73, 0x4b, 0x4f, 0x90, 0x89,
4212
+	0x10, 0xae, 0x8e, 0xb3, 0x5b, 0xd4, 0x03, 0x20, 0x52, 0x12, 0xef, 0xbb, 0x31, 0x8d, 0xa4, 0x5b,
4213
+	0xd2, 0x2a, 0xef, 0xe4, 0xe6, 0x42, 0xe5, 0x33, 0xc6, 0x47, 0xad, 0x25, 0x18, 0x67, 0x88, 0xe8,
4214
+	0x0b, 0xa8, 0x78, 0x94, 0xcb, 0xe0, 0x69, 0xe0, 0x11, 0x49, 0xdd, 0xb2, 0xd6, 0xa9, 0xe7, 0xe9,
4215
+	0x74, 0x56, 0x30, 0x53, 0x54, 0x96, 0x89, 0xde, 0x07, 0x9b, 0xb3, 0x90, 0xba, 0xce, 0x91, 0x75,
4216
+	0x6d, 0x7f, 0xf3, 0x67, 0xc1, 0x2c, 0xa4, 0x58, 0x23, 0x1b, 0x7f, 0x15, 0xa0, 0xf4, 0x90, 0xf2,
4217
+	0x69, 0xe0, 0xbd, 0x5a, 0x83, 0xdc, 0x3e, 0x65, 0x90, 0xdc, 0x5a, 0x4c, 0xd8, 0x35, 0x8f, 0x1c,
4218
+	0x43, 0x99, 0x46, 0x7e, 0xcc, 0x82, 0x48, 0x1a, 0x83, 0xe4, 0x16, 0xd2, 0x33, 0x18, 0xbc, 0x44,
4219
+	0xa3, 0x1e, 0x54, 0x13, 0xdf, 0x0f, 0x4e, 0xb9, 0xe3, 0x28, 0x8f, 0xfe, 0xad, 0x06, 0x9a, 0xcf,
4220
+	0xba, 0x37, 0xc9, 0xec, 0x50, 0x17, 0xaa, 0x31, 0xa7, 0xd3, 0x80, 0x4d, 0xc4, 0x40, 0x17, 0x51,
4221
+	0x3c, 0x53, 0x11, 0x78, 0x2f, 0x65, 0xa9, 0x5d, 0xe3, 0x97, 0x02, 0x94, 0xd3, 0x1c, 0xd1, 0x2d,
4222
+	0xd3, 0x0e, 0x6b, 0x73, 0x42, 0x29, 0x56, 0x4b, 0x25, 0x9d, 0xb8, 0x05, 0xbb, 0x31, 0xe3, 0x52,
4223
+	0xb8, 0x85, 0xa3, 0x9d, 0x4d, 0x2e, 0x7f, 0xc0, 0xb8, 0xec, 0xb0, 0xe8, 0x69, 0x30, 0xc4, 0x09,
4224
+	0x18, 0x3d, 0x81, 0xca, 0x34, 0xe0, 0x72, 0x42, 0xc2, 0x41, 0x10, 0x0b, 0x77, 0x47, 0x73, 0xdf,
4225
+	0xdd, 0x16, 0xb2, 0xf9, 0x38, 0xc1, 0xf7, 0x1f, 0xb4, 0xf7, 0x17, 0xf3, 0x3a, 0x2c, 0xb7, 0x02,
4226
+	0x83, 0x91, 0xea, 0xc7, 0xe2, 0xe0, 0x3e, 0x38, 0xcb, 0x13, 0x74, 0x1d, 0x20, 0x4a, 0x4c, 0x3d,
4227
+	0x58, 0x9a, 0xa6, 0xba, 0x98, 0xd7, 0x1d, 0x63, 0xf5, 0x7e, 0x17, 0x3b, 0x06, 0xd0, 0xf7, 0x11,
4228
+	0x02, 0x9b, 0xf8, 0x3e, 0xd7, 0x16, 0x72, 0xb0, 0x5e, 0x37, 0xfe, 0xd8, 0x05, 0xfb, 0x11, 0x11,
4229
+	0xa3, 0xf3, 0x1e, 0x4c, 0x2a, 0xe6, 0x9a, 0xe9, 0xae, 0x03, 0x88, 0xe4, 0x53, 0xaa, 0x72, 0xec,
4230
+	0x55, 0x39, 0xe6, 0x03, 0xab, 0x72, 0x0c, 0x20, 0x29, 0x47, 0x84, 0x4c, 0x6a, 0x7f, 0xd9, 0x58,
4231
+	0xaf, 0xd1, 0x55, 0x28, 0x45, 0xcc, 0xd7, 0xf4, 0xa2, 0xa6, 0xc3, 0x62, 0x5e, 0x2f, 0xaa, 0xeb,
4232
+	0xd6, 0xef, 0xe2, 0xa2, 0x3a, 0xea, 0xfb, 0xea, 0xa6, 0x93, 0x28, 0x62, 0x92, 0xa8, 0x31, 0x26,
4233
+	0xcc, 0xc4, 0xc8, 0x35, 0x56, 0x6b, 0x05, 0x4b, 0x6f, 0x7a, 0x86, 0x89, 0x1e, 0xc3, 0x1b, 0x69,
4234
+	0xbe, 0x59, 0xc1, 0xf2, 0xcb, 0x08, 0x22, 0xa3, 0x90, 0x39, 0xc9, 0x4c, 0x56, 0x67, 0xf3, 0x64,
4235
+	0xd5, 0x1d, 0xcc, 0x9b, 0xac, 0x6d, 0xa8, 0xfa, 0x54, 0x04, 0x9c, 0xfa, 0xfa, 0x06, 0x52, 0x17,
4236
+	0xf4, 0x20, 0xba, 0xb2, 0x4d, 0x84, 0xe2, 0x3d, 0xc3, 0xd1, 0x3b, 0xd4, 0x82, 0xb2, 0xf1, 0x8d,
4237
+	0x70, 0x2b, 0xda, 0xbb, 0x67, 0x9c, 0xa8, 0x4b, 0xda, 0xa9, 0x09, 0xb2, 0xf7, 0x52, 0x13, 0xe4,
4238
+	0x36, 0x40, 0xc8, 0x86, 0x03, 0x9f, 0x07, 0x53, 0xca, 0xdd, 0xaa, 0xe6, 0x1e, 0xe4, 0x71, 0xbb,
4239
+	0x1a, 0x81, 0x9d, 0x90, 0x0d, 0x93, 0x65, 0xe3, 0x47, 0x0b, 0x5e, 0x5f, 0x4b, 0x0a, 0x7d, 0x04,
4240
+	0x25, 0x93, 0xd6, 0xb6, 0x67, 0x83, 0xe1, 0xe1, 0x14, 0x8b, 0x0e, 0xc1, 0x51, 0x77, 0x84, 0x0a,
4241
+	0x41, 0x93, 0xdb, 0xef, 0xe0, 0xd5, 0x0f, 0xc8, 0x85, 0x12, 0x09, 0x03, 0xa2, 0xce, 0x76, 0xf4,
4242
+	0x59, 0xba, 0x6d, 0xfc, 0x54, 0x80, 0x92, 0x11, 0x3b, 0xef, 0x71, 0x6e, 0xc2, 0xae, 0xdd, 0xac,
4243
+	0xbb, 0xb0, 0x97, 0xb4, 0xd3, 0x58, 0xc2, 0xfe, 0xdf, 0xa6, 0x56, 0x12, 0x7c, 0x62, 0x87, 0xbb,
4244
+	0x60, 0x07, 0x31, 0x19, 0x9b, 0x51, 0x9e, 0x1b, 0xb9, 0xff, 0xa0, 0x75, 0xff, 0x9b, 0x38, 0x71,
4245
+	0x76, 0x79, 0x31, 0xaf, 0xdb, 0xea, 0x07, 0xac, 0x69, 0x8d, 0x5f, 0x77, 0xa1, 0xd4, 0x09, 0x27,
4246
+	0x42, 0x52, 0x7e, 0xde, 0x0d, 0x31, 0x61, 0xd7, 0x1a, 0xd2, 0x81, 0x12, 0x67, 0x4c, 0x0e, 0x3c,
4247
+	0xb2, 0xad, 0x17, 0x98, 0x31, 0xd9, 0x69, 0xb5, 0xf7, 0x15, 0x51, 0x0d, 0x92, 0x64, 0x8f, 0x8b,
4248
+	0x8a, 0xda, 0x21, 0xe8, 0x09, 0x5c, 0x4a, 0xc7, 0xef, 0x09, 0x63, 0x52, 0x48, 0x4e, 0xe2, 0xc1,
4249
+	0x88, 0xce, 0xd4, 0xdf, 0xbc, 0x9d, 0x4d, 0x6f, 0x99, 0x5e, 0xe4, 0xf1, 0x99, 0x6e, 0xd4, 0x3d,
4250
+	0x3a, 0xc3, 0x17, 0x8d, 0x40, 0x3b, 0xe5, 0xdf, 0xa3, 0x33, 0x81, 0x3e, 0x83, 0x43, 0xba, 0x84,
4251
+	0x29, 0xc5, 0x41, 0x48, 0xc6, 0xea, 0x0f, 0xcb, 0xc0, 0x0b, 0x99, 0x37, 0xd2, 0xb3, 0xcd, 0xc6,
4252
+	0x97, 0x69, 0x56, 0xea, 0xab, 0x04, 0xd1, 0x51, 0x00, 0x24, 0xc0, 0x3d, 0x09, 0x89, 0x37, 0x0a,
4253
+	0x03, 0xa1, 0x5e, 0xac, 0x99, 0xe7, 0x89, 0x1a, 0x4f, 0x2a, 0xb7, 0xe3, 0x2d, 0xdd, 0x6a, 0xb6,
4254
+	0x57, 0xdc, 0xcc, 0x63, 0x47, 0xf4, 0x22, 0xc9, 0x67, 0xf8, 0xcd, 0x93, 0xfc, 0x53, 0xd4, 0x86,
4255
+	0xca, 0x24, 0x52, 0xe1, 0x93, 0x1e, 0x38, 0x67, 0xed, 0x01, 0x24, 0x2c, 0x55, 0xf9, 0xc1, 0x14,
4256
+	0x0e, 0xb7, 0x05, 0x47, 0xaf, 0xc1, 0xce, 0x88, 0xce, 0x12, 0xff, 0x60, 0xb5, 0x44, 0x9f, 0xc3,
4257
+	0xee, 0x94, 0x84, 0x13, 0x6a, 0x9c, 0xf3, 0x5e, 0x5e, 0xbc, 0x7c, 0x49, 0x9c, 0x10, 0x3f, 0x29,
4258
+	0x1c, 0x5b, 0x8d, 0xdf, 0x2c, 0x28, 0x3e, 0xa4, 0x1e, 0xa7, 0xf2, 0x95, 0x3a, 0xf4, 0xf8, 0x94,
4259
+	0x43, 0x6b, 0xf9, 0x8f, 0x17, 0x15, 0x75, 0xcd, 0xa0, 0x07, 0x50, 0x0e, 0x22, 0x49, 0x79, 0x44,
4260
+	0x42, 0xed, 0xd0, 0x32, 0x5e, 0xee, 0xdb, 0x87, 0xcf, 0x5f, 0xd4, 0x2e, 0xfc, 0xfd, 0xa2, 0x76,
4261
+	0xe1, 0xdf, 0x17, 0x35, 0xeb, 0x87, 0x45, 0xcd, 0x7a, 0xbe, 0xa8, 0x59, 0x7f, 0x2e, 0x6a, 0xd6,
4262
+	0x3f, 0x8b, 0x9a, 0x75, 0x52, 0xd4, 0xff, 0x34, 0x7d, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff,
4263
+	0x9f, 0x52, 0xfb, 0x4a, 0xa4, 0x0d, 0x00, 0x00,
4263 4264
 }
... ...
@@ -48,6 +48,17 @@ message Node {
48 48
 
49 49
 	// Certificate is the TLS certificate issued for the node, if any.
50 50
 	Certificate certificate = 8 [(gogoproto.nullable) = false];
51
+
52
+	// Role is the *observed* role for this node. It differs from the
53
+	// desired role set in Node.Spec.Role because the role here is only
54
+	// updated after the Raft member list has been reconciled with the
55
+	// desired role from the spec.
56
+	//
57
+	// This field represents the current reconciled state. If an action is
58
+	// to be performed, first verify the role in the cert. This field only
59
+	// shows the privilege level that the CA would currently grant when
60
+	// issuing or renewing the node's certificate.
61
+	NodeRole role = 9;
51 62
 }
52 63
 
53 64
 message Service {
... ...
@@ -112,8 +112,8 @@ func (EndpointSpec_ResolutionMode) EnumDescriptor() ([]byte, []int) {
112 112
 
113 113
 type NodeSpec struct {
114 114
 	Annotations Annotations `protobuf:"bytes,1,opt,name=annotations" json:"annotations"`
115
-	// Role defines the role the node should have.
116
-	Role NodeRole `protobuf:"varint,2,opt,name=role,proto3,enum=docker.swarmkit.v1.NodeRole" json:"role,omitempty"`
115
+	// DesiredRole defines the role the node should have.
116
+	DesiredRole NodeRole `protobuf:"varint,2,opt,name=desired_role,json=desiredRole,proto3,enum=docker.swarmkit.v1.NodeRole" json:"desired_role,omitempty"`
117 117
 	// Membership controls the admission of the node into the cluster.
118 118
 	Membership NodeSpec_Membership `protobuf:"varint,3,opt,name=membership,proto3,enum=docker.swarmkit.v1.NodeSpec_Membership" json:"membership,omitempty"`
119 119
 	// Availability allows a user to control the current scheduling status of a
... ...
@@ -645,7 +645,7 @@ func (m *NodeSpec) Copy() *NodeSpec {
645 645
 
646 646
 	o := &NodeSpec{
647 647
 		Annotations:  *m.Annotations.Copy(),
648
-		Role:         m.Role,
648
+		DesiredRole:  m.DesiredRole,
649 649
 		Membership:   m.Membership,
650 650
 		Availability: m.Availability,
651 651
 	}
... ...
@@ -941,7 +941,7 @@ func (this *NodeSpec) GoString() string {
941 941
 	s := make([]string, 0, 8)
942 942
 	s = append(s, "&api.NodeSpec{")
943 943
 	s = append(s, "Annotations: "+strings.Replace(this.Annotations.GoString(), `&`, ``, 1)+",\n")
944
-	s = append(s, "Role: "+fmt.Sprintf("%#v", this.Role)+",\n")
944
+	s = append(s, "DesiredRole: "+fmt.Sprintf("%#v", this.DesiredRole)+",\n")
945 945
 	s = append(s, "Membership: "+fmt.Sprintf("%#v", this.Membership)+",\n")
946 946
 	s = append(s, "Availability: "+fmt.Sprintf("%#v", this.Availability)+",\n")
947 947
 	s = append(s, "}")
... ...
@@ -1241,10 +1241,10 @@ func (m *NodeSpec) MarshalTo(data []byte) (int, error) {
1241 1241
 		return 0, err
1242 1242
 	}
1243 1243
 	i += n1
1244
-	if m.Role != 0 {
1244
+	if m.DesiredRole != 0 {
1245 1245
 		data[i] = 0x10
1246 1246
 		i++
1247
-		i = encodeVarintSpecs(data, i, uint64(m.Role))
1247
+		i = encodeVarintSpecs(data, i, uint64(m.DesiredRole))
1248 1248
 	}
1249 1249
 	if m.Membership != 0 {
1250 1250
 		data[i] = 0x18
... ...
@@ -2106,8 +2106,8 @@ func (m *NodeSpec) Size() (n int) {
2106 2106
 	_ = l
2107 2107
 	l = m.Annotations.Size()
2108 2108
 	n += 1 + l + sovSpecs(uint64(l))
2109
-	if m.Role != 0 {
2110
-		n += 1 + sovSpecs(uint64(m.Role))
2109
+	if m.DesiredRole != 0 {
2110
+		n += 1 + sovSpecs(uint64(m.DesiredRole))
2111 2111
 	}
2112 2112
 	if m.Membership != 0 {
2113 2113
 		n += 1 + sovSpecs(uint64(m.Membership))
... ...
@@ -2461,7 +2461,7 @@ func (this *NodeSpec) String() string {
2461 2461
 	}
2462 2462
 	s := strings.Join([]string{`&NodeSpec{`,
2463 2463
 		`Annotations:` + strings.Replace(strings.Replace(this.Annotations.String(), "Annotations", "Annotations", 1), `&`, ``, 1) + `,`,
2464
-		`Role:` + fmt.Sprintf("%v", this.Role) + `,`,
2464
+		`DesiredRole:` + fmt.Sprintf("%v", this.DesiredRole) + `,`,
2465 2465
 		`Membership:` + fmt.Sprintf("%v", this.Membership) + `,`,
2466 2466
 		`Availability:` + fmt.Sprintf("%v", this.Availability) + `,`,
2467 2467
 		`}`,
... ...
@@ -2750,9 +2750,9 @@ func (m *NodeSpec) Unmarshal(data []byte) error {
2750 2750
 			iNdEx = postIndex
2751 2751
 		case 2:
2752 2752
 			if wireType != 0 {
2753
-				return fmt.Errorf("proto: wrong wireType = %d for field Role", wireType)
2753
+				return fmt.Errorf("proto: wrong wireType = %d for field DesiredRole", wireType)
2754 2754
 			}
2755
-			m.Role = 0
2755
+			m.DesiredRole = 0
2756 2756
 			for shift := uint(0); ; shift += 7 {
2757 2757
 				if shift >= 64 {
2758 2758
 					return ErrIntOverflowSpecs
... ...
@@ -2762,7 +2762,7 @@ func (m *NodeSpec) Unmarshal(data []byte) error {
2762 2762
 				}
2763 2763
 				b := data[iNdEx]
2764 2764
 				iNdEx++
2765
-				m.Role |= (NodeRole(b) & 0x7F) << shift
2765
+				m.DesiredRole |= (NodeRole(b) & 0x7F) << shift
2766 2766
 				if b < 0x80 {
2767 2767
 					break
2768 2768
 				}
... ...
@@ -5283,108 +5283,108 @@ var (
5283 5283
 func init() { proto.RegisterFile("specs.proto", fileDescriptorSpecs) }
5284 5284
 
5285 5285
 var fileDescriptorSpecs = []byte{
5286
-	// 1640 bytes of a gzipped FileDescriptorProto
5287
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x57, 0xdd, 0x72, 0xdb, 0xc6,
5288
-	0x15, 0x26, 0x24, 0x8a, 0x3f, 0x07, 0x94, 0x4d, 0xed, 0xe4, 0x07, 0x66, 0x12, 0x8a, 0x66, 0xdc,
5289
-	0x54, 0x69, 0xa6, 0x72, 0xab, 0x76, 0x52, 0xa7, 0x6e, 0xa6, 0x25, 0x45, 0x56, 0x56, 0x55, 0x29,
5290
-	0x9c, 0x95, 0xe2, 0x8e, 0xaf, 0x38, 0x2b, 0x60, 0x45, 0x62, 0x04, 0x62, 0xd1, 0xdd, 0x05, 0x33,
5291
-	0xbc, 0xeb, 0x65, 0xc6, 0x17, 0x7d, 0x03, 0x5f, 0xf5, 0x19, 0xfa, 0x0e, 0xbe, 0xec, 0x65, 0x7b,
5292
-	0xa3, 0xa9, 0xf9, 0x04, 0x9d, 0xe9, 0x03, 0xb4, 0xb3, 0x8b, 0x05, 0x08, 0x26, 0x50, 0x9c, 0x99,
5293
-	0xf8, 0x6e, 0xf7, 0xe0, 0xfb, 0x0e, 0xce, 0x9e, 0xfd, 0x70, 0xce, 0x01, 0xd8, 0x22, 0xa2, 0xae,
5294
-	0xd8, 0x8f, 0x38, 0x93, 0x0c, 0x21, 0x8f, 0xb9, 0xd7, 0x94, 0xef, 0x8b, 0xaf, 0x08, 0x9f, 0x5d,
5295
-	0xfb, 0x72, 0x7f, 0xfe, 0xf3, 0x96, 0x2d, 0x17, 0x11, 0x35, 0x80, 0xd6, 0x5b, 0x13, 0x36, 0x61,
5296
-	0x7a, 0xf9, 0x50, 0xad, 0x8c, 0xf5, 0x5d, 0x2f, 0xe6, 0x44, 0xfa, 0x2c, 0x7c, 0x98, 0x2e, 0x92,
5297
-	0x07, 0xdd, 0xbf, 0x96, 0xa1, 0x76, 0xc6, 0x3c, 0x7a, 0x1e, 0x51, 0x17, 0x1d, 0x81, 0x4d, 0xc2,
5298
-	0x90, 0x49, 0x0d, 0x10, 0x8e, 0xd5, 0xb1, 0xf6, 0xec, 0x83, 0xdd, 0xfd, 0x6f, 0xbf, 0x72, 0xbf,
5299
-	0xb7, 0x82, 0xf5, 0xcb, 0x2f, 0x6f, 0x76, 0x4b, 0x38, 0xcf, 0x44, 0x3f, 0x83, 0x32, 0x67, 0x01,
5300
-	0x75, 0x36, 0x3a, 0xd6, 0xde, 0x9d, 0x83, 0xf7, 0x8b, 0x3c, 0xa8, 0x97, 0x62, 0x16, 0x50, 0xac,
5301
-	0x91, 0xe8, 0x08, 0x60, 0x46, 0x67, 0x97, 0x94, 0x8b, 0xa9, 0x1f, 0x39, 0x9b, 0x9a, 0xf7, 0xe3,
5302
-	0xdb, 0x78, 0x2a, 0xd8, 0xfd, 0xd3, 0x0c, 0x8e, 0x73, 0x54, 0x74, 0x0a, 0x0d, 0x32, 0x27, 0x7e,
5303
-	0x40, 0x2e, 0xfd, 0xc0, 0x97, 0x0b, 0xa7, 0xac, 0x5d, 0x7d, 0xfc, 0x9d, 0xae, 0x7a, 0x39, 0x02,
5304
-	0x5e, 0xa3, 0x77, 0x3d, 0x80, 0xd5, 0x8b, 0xd0, 0x47, 0x50, 0x1d, 0x0d, 0xcf, 0x06, 0xc7, 0x67,
5305
-	0x47, 0xcd, 0x52, 0xeb, 0xde, 0xf3, 0x17, 0x9d, 0xb7, 0x95, 0x8f, 0x15, 0x60, 0x44, 0x43, 0xcf,
5306
-	0x0f, 0x27, 0x68, 0x0f, 0x6a, 0xbd, 0xc3, 0xc3, 0xe1, 0xe8, 0x62, 0x38, 0x68, 0x5a, 0xad, 0xd6,
5307
-	0xf3, 0x17, 0x9d, 0x77, 0xd6, 0x81, 0x3d, 0xd7, 0xa5, 0x91, 0xa4, 0x5e, 0xab, 0xfc, 0xf5, 0xdf,
5308
-	0xda, 0xa5, 0xee, 0xd7, 0x16, 0x34, 0xf2, 0x41, 0xa0, 0x8f, 0xa0, 0xd2, 0x3b, 0xbc, 0x38, 0x7e,
5309
-	0x3a, 0x6c, 0x96, 0x56, 0xf4, 0x3c, 0xa2, 0xe7, 0x4a, 0x7f, 0x4e, 0xd1, 0x03, 0xd8, 0x1a, 0xf5,
5310
-	0xbe, 0x3c, 0x1f, 0x36, 0xad, 0x55, 0x38, 0x79, 0xd8, 0x88, 0xc4, 0x42, 0xa3, 0x06, 0xb8, 0x77,
5311
-	0x7c, 0xd6, 0xdc, 0x28, 0x46, 0x0d, 0x38, 0xf1, 0x43, 0x13, 0xca, 0xab, 0x4d, 0xb0, 0xcf, 0x29,
5312
-	0x9f, 0xfb, 0xee, 0x1b, 0xd6, 0xc4, 0xa7, 0x50, 0x96, 0x44, 0x5c, 0x6b, 0x4d, 0xd8, 0xc5, 0x9a,
5313
-	0xb8, 0x20, 0xe2, 0x5a, 0xbd, 0xd4, 0xd0, 0x35, 0x5e, 0x29, 0x83, 0xd3, 0x28, 0xf0, 0x5d, 0x22,
5314
-	0xa9, 0xa7, 0x95, 0x61, 0x1f, 0xfc, 0xa8, 0x88, 0x8d, 0x33, 0x94, 0x89, 0xff, 0x49, 0x09, 0xe7,
5315
-	0xa8, 0xe8, 0x31, 0x54, 0x26, 0x01, 0xbb, 0x24, 0x81, 0xd6, 0x84, 0x7d, 0x70, 0xbf, 0xc8, 0xc9,
5316
-	0x91, 0x46, 0xac, 0x1c, 0x18, 0x0a, 0x7a, 0x04, 0x95, 0x38, 0xf2, 0x88, 0xa4, 0x4e, 0x45, 0x93,
5317
-	0x3b, 0x45, 0xe4, 0x2f, 0x35, 0xe2, 0x90, 0x85, 0x57, 0xfe, 0x04, 0x1b, 0x3c, 0x3a, 0x81, 0x5a,
5318
-	0x48, 0xe5, 0x57, 0x8c, 0x5f, 0x0b, 0xa7, 0xda, 0xd9, 0xdc, 0xb3, 0x0f, 0x3e, 0x29, 0x14, 0x63,
5319
-	0x82, 0xe9, 0x49, 0x49, 0xdc, 0xe9, 0x8c, 0x86, 0x32, 0x71, 0xd3, 0xdf, 0x70, 0x2c, 0x9c, 0x39,
5320
-	0x40, 0xbf, 0x81, 0x1a, 0x0d, 0xbd, 0x88, 0xf9, 0xa1, 0x74, 0x6a, 0xb7, 0x07, 0x32, 0x34, 0x18,
5321
-	0x95, 0x4c, 0x9c, 0x31, 0xfa, 0x15, 0x28, 0xcf, 0x98, 0x47, 0xbb, 0x0f, 0x61, 0xe7, 0x5b, 0xc9,
5322
-	0x42, 0x2d, 0xa8, 0x99, 0x64, 0x25, 0xb7, 0x5c, 0xc6, 0xd9, 0xbe, 0x7b, 0x17, 0xb6, 0xd7, 0x12,
5323
-	0xa3, 0xcb, 0x46, 0x7a, 0x5b, 0xa8, 0x07, 0x75, 0x97, 0x85, 0x92, 0xf8, 0x21, 0xe5, 0x46, 0x20,
5324
-	0x85, 0xb9, 0x3d, 0x4c, 0x41, 0x8a, 0xf5, 0xa4, 0x84, 0x57, 0x2c, 0xf4, 0x7b, 0xa8, 0x73, 0x2a,
5325
-	0x58, 0xcc, 0x5d, 0x2a, 0x8c, 0x42, 0xf6, 0x8a, 0xef, 0x38, 0x01, 0x61, 0xfa, 0xe7, 0xd8, 0xe7,
5326
-	0x54, 0xe5, 0x49, 0xe0, 0x15, 0x15, 0x3d, 0x86, 0x2a, 0xa7, 0x42, 0x12, 0x2e, 0xbf, 0xeb, 0x92,
5327
-	0x71, 0x02, 0x19, 0xb1, 0xc0, 0x77, 0x17, 0x38, 0x65, 0xa0, 0xc7, 0x50, 0x8f, 0x02, 0xe2, 0x6a,
5328
-	0xaf, 0xce, 0x96, 0xa6, 0x7f, 0x50, 0x44, 0x1f, 0xa5, 0x20, 0xbc, 0xc2, 0xa3, 0xcf, 0x00, 0x02,
5329
-	0x36, 0x19, 0x7b, 0xdc, 0x9f, 0x53, 0x6e, 0x44, 0xd2, 0x2a, 0x62, 0x0f, 0x34, 0x02, 0xd7, 0x03,
5330
-	0x36, 0x49, 0x96, 0xe8, 0xe8, 0x07, 0x29, 0x24, 0xa7, 0x8e, 0x13, 0x00, 0x92, 0x3d, 0x35, 0xfa,
5331
-	0xf8, 0xf8, 0x7b, 0xb9, 0x32, 0x37, 0x92, 0xa3, 0xa3, 0xfb, 0xd0, 0xb8, 0x62, 0xdc, 0xa5, 0x63,
5332
-	0xa3, 0xfb, 0xba, 0xd6, 0x84, 0xad, 0x6d, 0x89, 0xd0, 0xfb, 0x75, 0xa8, 0xf2, 0x38, 0x94, 0xfe,
5333
-	0x8c, 0x76, 0x4f, 0xe0, 0xed, 0x42, 0xa7, 0xe8, 0x00, 0x1a, 0xd9, 0x35, 0x8f, 0x7d, 0x4f, 0xeb,
5334
-	0xa3, 0xde, 0xbf, 0xbb, 0xbc, 0xd9, 0xb5, 0x33, 0x3d, 0x1c, 0x0f, 0xb0, 0x9d, 0x81, 0x8e, 0xbd,
5335
-	0xee, 0xbf, 0xaa, 0xb0, 0xbd, 0x26, 0x16, 0xf4, 0x16, 0x6c, 0xf9, 0x33, 0x32, 0xa1, 0x09, 0x1d,
5336
-	0x27, 0x1b, 0x34, 0x84, 0x4a, 0x40, 0x2e, 0x69, 0xa0, 0x24, 0xa3, 0xd2, 0xf6, 0xd3, 0xd7, 0xaa,
5337
-	0x6e, 0xff, 0x8f, 0x1a, 0x3f, 0x0c, 0x25, 0x5f, 0x60, 0x43, 0x46, 0x0e, 0x54, 0x5d, 0x36, 0x9b,
5338
-	0x91, 0x50, 0x95, 0x97, 0xcd, 0xbd, 0x3a, 0x4e, 0xb7, 0x08, 0x41, 0x99, 0xf0, 0x89, 0x70, 0xca,
5339
-	0xda, 0xac, 0xd7, 0xa8, 0x09, 0x9b, 0x34, 0x9c, 0x3b, 0x5b, 0xda, 0xa4, 0x96, 0xca, 0xe2, 0xf9,
5340
-	0xc9, 0x9d, 0xd7, 0xb1, 0x5a, 0x2a, 0x5e, 0x2c, 0x28, 0x77, 0xaa, 0xda, 0xa4, 0xd7, 0xe8, 0x57,
5341
-	0x50, 0x99, 0xb1, 0x38, 0x94, 0xc2, 0xa9, 0xe9, 0x60, 0xef, 0x15, 0x05, 0x7b, 0xaa, 0x10, 0xa6,
5342
-	0xfc, 0x19, 0x38, 0x7a, 0x02, 0x3b, 0x42, 0xb2, 0x68, 0x3c, 0xe1, 0xc4, 0xa5, 0xe3, 0x88, 0x72,
5343
-	0x9f, 0x79, 0xfa, 0x36, 0x6e, 0xa9, 0xa2, 0x03, 0xd3, 0xe1, 0xf1, 0x5d, 0x45, 0x3b, 0x52, 0xac,
5344
-	0x91, 0x26, 0xa1, 0x11, 0x34, 0xa2, 0x38, 0x08, 0xc6, 0x2c, 0x4a, 0x8a, 0x39, 0x68, 0x27, 0xdf,
5345
-	0x23, 0x6b, 0xa3, 0x38, 0x08, 0xbe, 0x48, 0x48, 0xd8, 0x8e, 0x56, 0x1b, 0xf4, 0x0e, 0x54, 0x26,
5346
-	0x9c, 0xc5, 0x91, 0x70, 0x6c, 0x9d, 0x0f, 0xb3, 0x43, 0x9f, 0x43, 0x55, 0x50, 0x97, 0x53, 0x29,
5347
-	0x9c, 0x86, 0x3e, 0xed, 0x87, 0x45, 0x2f, 0x39, 0xd7, 0x10, 0x4c, 0xaf, 0x28, 0xa7, 0xa1, 0x4b,
5348
-	0x71, 0xca, 0x41, 0xf7, 0x60, 0x53, 0xca, 0x85, 0xb3, 0xdd, 0xb1, 0xf6, 0x6a, 0xfd, 0xea, 0xf2,
5349
-	0x66, 0x77, 0xf3, 0xe2, 0xe2, 0x19, 0x56, 0x36, 0x55, 0xa6, 0xa6, 0x4c, 0xc8, 0x90, 0xcc, 0xa8,
5350
-	0x73, 0x47, 0xa7, 0x37, 0xdb, 0xa3, 0x67, 0x00, 0x5e, 0x28, 0xc6, 0xae, 0xfe, 0x2e, 0x9c, 0xbb,
5351
-	0xfa, 0x74, 0x9f, 0xbc, 0xfe, 0x74, 0x83, 0xb3, 0x73, 0x53, 0x6c, 0xb7, 0x97, 0x37, 0xbb, 0xf5,
5352
-	0x6c, 0x8b, 0xeb, 0x5e, 0x28, 0x92, 0x25, 0xea, 0x83, 0x3d, 0xa5, 0x24, 0x90, 0x53, 0x77, 0x4a,
5353
-	0xdd, 0x6b, 0xa7, 0x79, 0x7b, 0xed, 0x7d, 0xa2, 0x61, 0xc6, 0x43, 0x9e, 0xa4, 0x44, 0xac, 0x42,
5354
-	0x15, 0xce, 0x8e, 0xce, 0x55, 0xb2, 0x41, 0x1f, 0x00, 0xb0, 0x88, 0x86, 0x63, 0x21, 0x3d, 0x3f,
5355
-	0x74, 0x90, 0x3a, 0x32, 0xae, 0x2b, 0xcb, 0xb9, 0x32, 0xb4, 0x3e, 0x03, 0x3b, 0xa7, 0x59, 0xa5,
5356
-	0xb5, 0x6b, 0xba, 0x30, 0x9f, 0x81, 0x5a, 0x2a, 0xaf, 0x73, 0x12, 0xc4, 0xc9, 0xb0, 0x55, 0xc7,
5357
-	0xc9, 0xe6, 0xd7, 0x1b, 0x8f, 0xac, 0xd6, 0x01, 0xd8, 0xb9, 0x8b, 0x43, 0x1f, 0xc2, 0x36, 0xa7,
5358
-	0x13, 0x5f, 0x48, 0xbe, 0x18, 0x93, 0x58, 0x4e, 0x9d, 0xdf, 0x69, 0x42, 0x23, 0x35, 0xf6, 0x62,
5359
-	0x39, 0x6d, 0x8d, 0x61, 0x75, 0x7e, 0xd4, 0x01, 0x5b, 0xe5, 0x55, 0x50, 0x3e, 0xa7, 0x5c, 0x75,
5360
-	0x05, 0x15, 0x76, 0xde, 0xa4, 0xee, 0x5f, 0x50, 0xc2, 0xdd, 0xa9, 0xfe, 0x02, 0xeb, 0xd8, 0xec,
5361
-	0xd4, 0x27, 0x95, 0x8a, 0xcc, 0x7c, 0x52, 0x66, 0xdb, 0xfd, 0xaf, 0x05, 0x8d, 0x7c, 0x7b, 0x42,
5362
-	0x87, 0x49, 0x53, 0xd2, 0x47, 0xba, 0x73, 0xf0, 0xf0, 0x75, 0xed, 0x4c, 0xb7, 0x80, 0x20, 0x56,
5363
-	0xce, 0x4e, 0xd5, 0x08, 0xa9, 0xc9, 0xe8, 0x97, 0xb0, 0x15, 0x31, 0x2e, 0xd3, 0x42, 0xd0, 0x2e,
5364
-	0x2c, 0xdb, 0x8c, 0xa7, 0x25, 0x33, 0x01, 0x77, 0xa7, 0x70, 0x67, 0xdd, 0x1b, 0x7a, 0x00, 0x9b,
5365
-	0x4f, 0x8f, 0x47, 0xcd, 0x52, 0xeb, 0xbd, 0xe7, 0x2f, 0x3a, 0xef, 0xae, 0x3f, 0x7c, 0xea, 0x73,
5366
-	0x19, 0x93, 0xe0, 0x78, 0x84, 0x7e, 0x02, 0x5b, 0x83, 0xb3, 0x73, 0x8c, 0x9b, 0x56, 0x6b, 0xf7,
5367
-	0xf9, 0x8b, 0xce, 0x7b, 0xeb, 0x38, 0xf5, 0x88, 0xc5, 0xa1, 0x87, 0xd9, 0x65, 0x36, 0x55, 0xfd,
5368
-	0x7d, 0x03, 0x6c, 0x53, 0x1f, 0xdf, 0xec, 0x54, 0xf5, 0x5b, 0xd8, 0x4e, 0x5a, 0x4e, 0xaa, 0xfa,
5369
-	0x8d, 0xd7, 0x76, 0x9e, 0x46, 0x42, 0x30, 0x77, 0x7c, 0x1f, 0x1a, 0x7e, 0x34, 0xff, 0x74, 0x4c,
5370
-	0x43, 0x72, 0x19, 0x98, 0x01, 0xab, 0x86, 0x6d, 0x65, 0x1b, 0x26, 0x26, 0xf5, 0xc9, 0xf9, 0xa1,
5371
-	0xa4, 0x3c, 0x34, 0xa3, 0x53, 0x0d, 0x67, 0x7b, 0xf4, 0x39, 0x94, 0xfd, 0x88, 0xcc, 0x4c, 0xbb,
5372
-	0x2c, 0x3c, 0xc1, 0xf1, 0xa8, 0x77, 0x6a, 0x34, 0xd8, 0xaf, 0x2d, 0x6f, 0x76, 0xcb, 0xca, 0x80,
5373
-	0x35, 0x0d, 0xb5, 0xd3, 0x8e, 0xa5, 0xde, 0xa4, 0x2b, 0x68, 0x0d, 0xe7, 0x2c, 0xdd, 0xff, 0x95,
5374
-	0xc1, 0x3e, 0x0c, 0x62, 0x21, 0x4d, 0x1f, 0x78, 0x63, 0x79, 0x7b, 0x06, 0x3b, 0x44, 0xcf, 0xe0,
5375
-	0x24, 0x54, 0x45, 0x55, 0x4f, 0x02, 0x26, 0x77, 0x0f, 0x0a, 0xdd, 0x65, 0xe0, 0x64, 0x6a, 0xe8,
5376
-	0x57, 0x94, 0x4f, 0xc7, 0xc2, 0x4d, 0xf2, 0x8d, 0x27, 0xe8, 0x1c, 0xb6, 0x19, 0x77, 0xa7, 0x54,
5377
-	0xc8, 0xa4, 0x0e, 0x9b, 0x99, 0xb5, 0xf0, 0x6f, 0xe6, 0x8b, 0x3c, 0xd0, 0x14, 0xa1, 0x24, 0xda,
5378
-	0x75, 0x1f, 0xe8, 0x11, 0x94, 0x39, 0xb9, 0x4a, 0xa7, 0x9a, 0x42, 0x7d, 0x63, 0x72, 0x25, 0xd7,
5379
-	0x5c, 0x68, 0x06, 0xfa, 0x03, 0x80, 0xe7, 0x8b, 0x88, 0x48, 0x77, 0x4a, 0xb9, 0xb9, 0xa7, 0xc2,
5380
-	0x23, 0x0e, 0x32, 0xd4, 0x9a, 0x97, 0x1c, 0x1b, 0x9d, 0x40, 0xdd, 0x25, 0xa9, 0xd2, 0x2a, 0xb7,
5381
-	0xb7, 0xa0, 0xc3, 0x9e, 0x71, 0xd1, 0x54, 0x2e, 0x96, 0x37, 0xbb, 0xb5, 0xd4, 0x82, 0x6b, 0x2e,
5382
-	0x31, 0xca, 0x3b, 0x81, 0x6d, 0x35, 0xe0, 0x8f, 0x3d, 0x7a, 0x45, 0xe2, 0x40, 0x0a, 0xdd, 0x2d,
5383
-	0x6f, 0x29, 0xaa, 0x6a, 0xd6, 0x1c, 0x18, 0x9c, 0x89, 0xab, 0x21, 0x73, 0x36, 0xf4, 0x27, 0xd8,
5384
-	0xa1, 0xa1, 0xcb, 0x17, 0x5a, 0x67, 0x69, 0x84, 0xb5, 0xdb, 0x0f, 0x3b, 0xcc, 0xc0, 0x6b, 0x87,
5385
-	0x6d, 0xd2, 0x6f, 0xd8, 0xbb, 0x3e, 0x40, 0xd2, 0xa6, 0xde, 0xac, 0xfe, 0x10, 0x94, 0x3d, 0x22,
5386
-	0x89, 0x96, 0x5c, 0x03, 0xeb, 0x75, 0xff, 0xfd, 0x97, 0xaf, 0xda, 0xa5, 0x7f, 0xbe, 0x6a, 0x97,
5387
-	0xfe, 0xf3, 0xaa, 0x6d, 0xfd, 0x65, 0xd9, 0xb6, 0x5e, 0x2e, 0xdb, 0xd6, 0x3f, 0x96, 0x6d, 0xeb,
5388
-	0xdf, 0xcb, 0xb6, 0x75, 0x59, 0xd1, 0x3f, 0xec, 0xbf, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff,
5389
-	0xab, 0x02, 0x96, 0x72, 0x0f, 0x10, 0x00, 0x00,
5286
+	// 1647 bytes of a gzipped FileDescriptorProto
5287
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x57, 0xdd, 0x6e, 0xe3, 0xc6,
5288
+	0x15, 0x16, 0x6d, 0x59, 0x3f, 0x87, 0xf2, 0xae, 0x3c, 0xc8, 0x0f, 0x57, 0x49, 0x64, 0xad, 0xb2,
5289
+	0x4d, 0x9d, 0x06, 0xf5, 0xa2, 0x6e, 0x91, 0x6e, 0xba, 0x0d, 0x5a, 0xc9, 0x52, 0xbd, 0xae, 0x6b,
5290
+	0x47, 0x18, 0x3b, 0x5b, 0xec, 0x95, 0x30, 0x26, 0xc7, 0x12, 0x61, 0x8a, 0xc3, 0xce, 0x0c, 0x15,
5291
+	0xf8, 0xae, 0x97, 0xc1, 0x5e, 0xf4, 0x0d, 0x7c, 0xd5, 0x67, 0xe8, 0x3b, 0xec, 0x65, 0x2f, 0xdb,
5292
+	0x1b, 0xa3, 0xab, 0x27, 0x28, 0xd0, 0x07, 0x68, 0x31, 0xc3, 0x21, 0x45, 0x25, 0x74, 0x76, 0x81,
5293
+	0xfa, 0x6e, 0xe6, 0xf0, 0xfb, 0x0e, 0xcf, 0x9c, 0xf9, 0x78, 0xce, 0x21, 0xd8, 0x22, 0xa2, 0xae,
5294
+	0xd8, 0x8d, 0x38, 0x93, 0x0c, 0x21, 0x8f, 0xb9, 0x97, 0x94, 0xef, 0x8a, 0x6f, 0x08, 0x9f, 0x5d,
5295
+	0xfa, 0x72, 0x77, 0xfe, 0xb3, 0x96, 0x2d, 0xaf, 0x22, 0x6a, 0x00, 0xad, 0x77, 0x26, 0x6c, 0xc2,
5296
+	0xf4, 0xf2, 0xb1, 0x5a, 0x19, 0xeb, 0xfb, 0x5e, 0xcc, 0x89, 0xf4, 0x59, 0xf8, 0x38, 0x5d, 0x24,
5297
+	0x0f, 0xba, 0xd7, 0x65, 0xa8, 0x9d, 0x30, 0x8f, 0x9e, 0x46, 0xd4, 0x45, 0x07, 0x60, 0x93, 0x30,
5298
+	0x64, 0x52, 0x03, 0x84, 0x63, 0x75, 0xac, 0x1d, 0x7b, 0x6f, 0x7b, 0xf7, 0xfb, 0xaf, 0xdc, 0xed,
5299
+	0x2d, 0x61, 0xfd, 0xf2, 0xab, 0x9b, 0xed, 0x12, 0xce, 0x33, 0xd1, 0x6f, 0xa0, 0xe1, 0x51, 0xe1,
5300
+	0x73, 0xea, 0x8d, 0x39, 0x0b, 0xa8, 0xb3, 0xd6, 0xb1, 0x76, 0xee, 0xed, 0x7d, 0x58, 0xe4, 0x49,
5301
+	0xbd, 0x1c, 0xb3, 0x80, 0x62, 0xdb, 0x30, 0xd4, 0x06, 0x1d, 0x00, 0xcc, 0xe8, 0xec, 0x9c, 0x72,
5302
+	0x31, 0xf5, 0x23, 0x67, 0x5d, 0xd3, 0x7f, 0x7c, 0x1b, 0x5d, 0xc5, 0xbe, 0x7b, 0x9c, 0xc1, 0x71,
5303
+	0x8e, 0x8a, 0x8e, 0xa1, 0x41, 0xe6, 0xc4, 0x0f, 0xc8, 0xb9, 0x1f, 0xf8, 0xf2, 0xca, 0x29, 0x6b,
5304
+	0x57, 0x9f, 0xfe, 0xa0, 0xab, 0x5e, 0x8e, 0x80, 0x57, 0xe8, 0x5d, 0x0f, 0x60, 0xf9, 0x22, 0xf4,
5305
+	0x09, 0x54, 0x47, 0xc3, 0x93, 0xc1, 0xe1, 0xc9, 0x41, 0xb3, 0xd4, 0x7a, 0xf0, 0xf2, 0xba, 0xf3,
5306
+	0xae, 0xf2, 0xb1, 0x04, 0x8c, 0x68, 0xe8, 0xf9, 0xe1, 0x04, 0xed, 0x40, 0xad, 0xb7, 0xbf, 0x3f,
5307
+	0x1c, 0x9d, 0x0d, 0x07, 0x4d, 0xab, 0xd5, 0x7a, 0x79, 0xdd, 0x79, 0x6f, 0x15, 0xd8, 0x73, 0x5d,
5308
+	0x1a, 0x49, 0xea, 0xb5, 0xca, 0xdf, 0xfe, 0xb5, 0x5d, 0xea, 0x7e, 0x6b, 0x41, 0x23, 0x1f, 0x04,
5309
+	0xfa, 0x04, 0x2a, 0xbd, 0xfd, 0xb3, 0xc3, 0xe7, 0xc3, 0x66, 0x69, 0x49, 0xcf, 0x23, 0x7a, 0xae,
5310
+	0xf4, 0xe7, 0x14, 0x3d, 0x82, 0x8d, 0x51, 0xef, 0xeb, 0xd3, 0x61, 0xd3, 0x5a, 0x86, 0x93, 0x87,
5311
+	0x8d, 0x48, 0x2c, 0x34, 0x6a, 0x80, 0x7b, 0x87, 0x27, 0xcd, 0xb5, 0x62, 0xd4, 0x80, 0x13, 0x3f,
5312
+	0x34, 0xa1, 0xbc, 0x5e, 0x07, 0xfb, 0x94, 0xf2, 0xb9, 0xef, 0xde, 0xb1, 0x44, 0x3e, 0x87, 0xb2,
5313
+	0x24, 0xe2, 0x52, 0x4b, 0xc3, 0x2e, 0x96, 0xc6, 0x19, 0x11, 0x97, 0xea, 0xa5, 0x86, 0xae, 0xf1,
5314
+	0x4a, 0x19, 0x9c, 0x46, 0x81, 0xef, 0x12, 0x49, 0x3d, 0xad, 0x0c, 0x7b, 0xef, 0x47, 0x45, 0x6c,
5315
+	0x9c, 0xa1, 0x4c, 0xfc, 0xcf, 0x4a, 0x38, 0x47, 0x45, 0x4f, 0xa1, 0x32, 0x09, 0xd8, 0x39, 0x09,
5316
+	0xb4, 0x26, 0xec, 0xbd, 0x87, 0x45, 0x4e, 0x0e, 0x34, 0x62, 0xe9, 0xc0, 0x50, 0xd0, 0x13, 0xa8,
5317
+	0xc4, 0x91, 0x47, 0x24, 0x75, 0x2a, 0x9a, 0xdc, 0x29, 0x22, 0x7f, 0xad, 0x11, 0xfb, 0x2c, 0xbc,
5318
+	0xf0, 0x27, 0xd8, 0xe0, 0xd1, 0x11, 0xd4, 0x42, 0x2a, 0xbf, 0x61, 0xfc, 0x52, 0x38, 0xd5, 0xce,
5319
+	0xfa, 0x8e, 0xbd, 0xf7, 0x59, 0xa1, 0x18, 0x13, 0x4c, 0x4f, 0x4a, 0xe2, 0x4e, 0x67, 0x34, 0x94,
5320
+	0x89, 0x9b, 0xfe, 0x9a, 0x63, 0xe1, 0xcc, 0x01, 0xfa, 0x35, 0xd4, 0x68, 0xe8, 0x45, 0xcc, 0x0f,
5321
+	0xa5, 0x53, 0xbb, 0x3d, 0x90, 0xa1, 0xc1, 0xa8, 0x64, 0xe2, 0x8c, 0xd1, 0xaf, 0x40, 0x79, 0xc6,
5322
+	0x3c, 0xda, 0x7d, 0x0c, 0x5b, 0xdf, 0x4b, 0x16, 0x6a, 0x41, 0xcd, 0x24, 0x2b, 0xb9, 0xe5, 0x32,
5323
+	0xce, 0xf6, 0xdd, 0xfb, 0xb0, 0xb9, 0x92, 0x98, 0xee, 0x5f, 0xca, 0x50, 0x4b, 0x6f, 0x0b, 0xf5,
5324
+	0xa0, 0xee, 0xb2, 0x50, 0x12, 0x3f, 0xa4, 0xdc, 0x08, 0xa4, 0x30, 0xb7, 0xfb, 0x29, 0x48, 0xb1,
5325
+	0x9e, 0x95, 0xf0, 0x92, 0x85, 0x7e, 0x07, 0x75, 0x4e, 0x05, 0x8b, 0xb9, 0x4b, 0x85, 0x51, 0xc8,
5326
+	0x4e, 0xf1, 0x1d, 0x27, 0x20, 0x4c, 0xff, 0x14, 0xfb, 0x9c, 0xaa, 0x3c, 0x09, 0xbc, 0xa4, 0xa2,
5327
+	0xa7, 0x50, 0xe5, 0x54, 0x48, 0xc2, 0xe5, 0x0f, 0x5d, 0x32, 0x4e, 0x20, 0x23, 0x16, 0xf8, 0xee,
5328
+	0x15, 0x4e, 0x19, 0xe8, 0x29, 0xd4, 0xa3, 0x80, 0xb8, 0xda, 0xab, 0xb3, 0xa1, 0xe9, 0x1f, 0x15,
5329
+	0xd1, 0x47, 0x29, 0x08, 0x2f, 0xf1, 0xe8, 0x0b, 0x80, 0x80, 0x4d, 0xc6, 0x1e, 0xf7, 0xe7, 0x94,
5330
+	0x1b, 0x91, 0xb4, 0x8a, 0xd8, 0x03, 0x8d, 0xc0, 0xf5, 0x80, 0x4d, 0x92, 0x25, 0x3a, 0xf8, 0xbf,
5331
+	0x14, 0x92, 0x53, 0xc7, 0x11, 0x00, 0xc9, 0x9e, 0x1a, 0x7d, 0x7c, 0xfa, 0x56, 0xae, 0xcc, 0x8d,
5332
+	0xe4, 0xe8, 0xe8, 0x21, 0x34, 0x2e, 0x18, 0x77, 0xe9, 0xd8, 0xe8, 0xbe, 0xae, 0x35, 0x61, 0x6b,
5333
+	0x5b, 0x22, 0xf4, 0x7e, 0x1d, 0xaa, 0x3c, 0x0e, 0xa5, 0x3f, 0xa3, 0xdd, 0x23, 0x78, 0xb7, 0xd0,
5334
+	0x29, 0xda, 0x83, 0x46, 0x76, 0xcd, 0x63, 0xdf, 0xd3, 0xfa, 0xa8, 0xf7, 0xef, 0x2f, 0x6e, 0xb6,
5335
+	0xed, 0x4c, 0x0f, 0x87, 0x03, 0x6c, 0x67, 0xa0, 0x43, 0xaf, 0xfb, 0xcf, 0x2a, 0x6c, 0xae, 0x88,
5336
+	0x05, 0xbd, 0x03, 0x1b, 0xfe, 0x8c, 0x4c, 0x68, 0x42, 0xc7, 0xc9, 0x06, 0x0d, 0xa1, 0x12, 0x90,
5337
+	0x73, 0x1a, 0x28, 0xc9, 0xa8, 0xb4, 0xfd, 0xf4, 0x8d, 0xaa, 0xdb, 0xfd, 0x83, 0xc6, 0x0f, 0x43,
5338
+	0xc9, 0xaf, 0xb0, 0x21, 0x23, 0x07, 0xaa, 0x2e, 0x9b, 0xcd, 0x48, 0xa8, 0xca, 0xcb, 0xfa, 0x4e,
5339
+	0x1d, 0xa7, 0x5b, 0x84, 0xa0, 0x4c, 0xf8, 0x44, 0x38, 0x65, 0x6d, 0xd6, 0x6b, 0xd4, 0x84, 0x75,
5340
+	0x1a, 0xce, 0x9d, 0x0d, 0x6d, 0x52, 0x4b, 0x65, 0xf1, 0xfc, 0xe4, 0xce, 0xeb, 0x58, 0x2d, 0x15,
5341
+	0x2f, 0x16, 0x94, 0x3b, 0x55, 0x6d, 0xd2, 0x6b, 0xf4, 0x4b, 0xa8, 0xcc, 0x58, 0x1c, 0x4a, 0xe1,
5342
+	0xd4, 0x74, 0xb0, 0x0f, 0x8a, 0x82, 0x3d, 0x56, 0x08, 0x53, 0xfe, 0x0c, 0x1c, 0x3d, 0x83, 0x2d,
5343
+	0x21, 0x59, 0x34, 0x9e, 0x70, 0xe2, 0xd2, 0x71, 0x44, 0xb9, 0xcf, 0x3c, 0x7d, 0x1b, 0xb7, 0x54,
5344
+	0xd1, 0x81, 0x69, 0xf8, 0xf8, 0xbe, 0xa2, 0x1d, 0x28, 0xd6, 0x48, 0x93, 0xd0, 0x08, 0x1a, 0x51,
5345
+	0x1c, 0x04, 0x63, 0x16, 0x25, 0xc5, 0x1c, 0xb4, 0x93, 0xb7, 0xc8, 0xda, 0x28, 0x0e, 0x82, 0xaf,
5346
+	0x12, 0x12, 0xb6, 0xa3, 0xe5, 0x06, 0xbd, 0x07, 0x95, 0x09, 0x67, 0x71, 0x24, 0x1c, 0x5b, 0xe7,
5347
+	0xc3, 0xec, 0xd0, 0x97, 0x50, 0x15, 0xd4, 0xe5, 0x54, 0x0a, 0xa7, 0xa1, 0x4f, 0xfb, 0x71, 0xd1,
5348
+	0x4b, 0x4e, 0x35, 0x04, 0xd3, 0x0b, 0xca, 0x69, 0xe8, 0x52, 0x9c, 0x72, 0xd0, 0x03, 0x58, 0x97,
5349
+	0xf2, 0xca, 0xd9, 0xec, 0x58, 0x3b, 0xb5, 0x7e, 0x75, 0x71, 0xb3, 0xbd, 0x7e, 0x76, 0xf6, 0x02,
5350
+	0x2b, 0x9b, 0x2a, 0x53, 0x53, 0x26, 0x64, 0x48, 0x66, 0xd4, 0xb9, 0xa7, 0xd3, 0x9b, 0xed, 0xd1,
5351
+	0x0b, 0x00, 0x2f, 0x14, 0x63, 0x57, 0x7f, 0x17, 0xce, 0x7d, 0x7d, 0xba, 0xcf, 0xde, 0x7c, 0xba,
5352
+	0xc1, 0xc9, 0xa9, 0x29, 0xb6, 0x9b, 0x8b, 0x9b, 0xed, 0x7a, 0xb6, 0xc5, 0x75, 0x2f, 0x14, 0xc9,
5353
+	0x12, 0xf5, 0xc1, 0x9e, 0x52, 0x12, 0xc8, 0xa9, 0x3b, 0xa5, 0xee, 0xa5, 0xd3, 0xbc, 0xbd, 0xf6,
5354
+	0x3e, 0xd3, 0x30, 0xe3, 0x21, 0x4f, 0x52, 0x22, 0x56, 0xa1, 0x0a, 0x67, 0x4b, 0xe7, 0x2a, 0xd9,
5355
+	0xa0, 0x8f, 0x00, 0x58, 0x44, 0xc3, 0xb1, 0x90, 0x9e, 0x1f, 0x3a, 0x48, 0x1d, 0x19, 0xd7, 0x95,
5356
+	0xe5, 0x54, 0x19, 0x5a, 0x5f, 0x80, 0x9d, 0xd3, 0xac, 0xd2, 0xda, 0x25, 0xbd, 0x32, 0x9f, 0x81,
5357
+	0x5a, 0x2a, 0xaf, 0x73, 0x12, 0xc4, 0xc9, 0xcc, 0x55, 0xc7, 0xc9, 0xe6, 0x57, 0x6b, 0x4f, 0xac,
5358
+	0xd6, 0x1e, 0xd8, 0xb9, 0x8b, 0x43, 0x1f, 0xc3, 0x26, 0xa7, 0x13, 0x5f, 0x48, 0x7e, 0x35, 0x26,
5359
+	0xb1, 0x9c, 0x3a, 0xbf, 0xd5, 0x84, 0x46, 0x6a, 0xec, 0xc5, 0x72, 0xda, 0x1a, 0xc3, 0xf2, 0xfc,
5360
+	0xa8, 0x03, 0xb6, 0xca, 0xab, 0xa0, 0x7c, 0x4e, 0xb9, 0xea, 0x0a, 0x2a, 0xec, 0xbc, 0x49, 0xdd,
5361
+	0xbf, 0xa0, 0x84, 0xbb, 0x53, 0xfd, 0x05, 0xd6, 0xb1, 0xd9, 0xa9, 0x4f, 0x2a, 0x15, 0x99, 0xf9,
5362
+	0xa4, 0xcc, 0xb6, 0xfb, 0x1f, 0x0b, 0x1a, 0xf9, 0xf6, 0x84, 0xf6, 0x93, 0xa6, 0xa4, 0x8f, 0x74,
5363
+	0x6f, 0xef, 0xf1, 0x9b, 0xda, 0x99, 0x6e, 0x01, 0x41, 0xac, 0x9c, 0x1d, 0xab, 0x49, 0x52, 0x93,
5364
+	0xd1, 0x2f, 0x60, 0x23, 0x62, 0x5c, 0xa6, 0x85, 0xa0, 0x5d, 0x58, 0xb6, 0x19, 0x4f, 0x4b, 0x66,
5365
+	0x02, 0xee, 0x4e, 0xe1, 0xde, 0xaa, 0x37, 0xf4, 0x08, 0xd6, 0x9f, 0x1f, 0x8e, 0x9a, 0xa5, 0xd6,
5366
+	0x07, 0x2f, 0xaf, 0x3b, 0xef, 0xaf, 0x3e, 0x7c, 0xee, 0x73, 0x19, 0x93, 0xe0, 0x70, 0x84, 0x7e,
5367
+	0x02, 0x1b, 0x83, 0x93, 0x53, 0x8c, 0x9b, 0x56, 0x6b, 0xfb, 0xe5, 0x75, 0xe7, 0x83, 0x55, 0x9c,
5368
+	0x7a, 0xc4, 0xe2, 0xd0, 0xc3, 0xec, 0x3c, 0x9b, 0xaa, 0xfe, 0xb6, 0x06, 0xb6, 0xa9, 0x8f, 0x77,
5369
+	0x3d, 0x78, 0x6f, 0x26, 0x2d, 0x27, 0x55, 0xfd, 0xda, 0x1b, 0x3b, 0x4f, 0x23, 0x21, 0x98, 0x3b,
5370
+	0x7e, 0x08, 0x0d, 0x3f, 0x9a, 0x7f, 0x3e, 0xa6, 0x21, 0x39, 0x0f, 0xcc, 0x80, 0x55, 0xc3, 0xb6,
5371
+	0xb2, 0x0d, 0x13, 0x93, 0xfa, 0xe4, 0xfc, 0x50, 0x52, 0x1e, 0x9a, 0xd1, 0xa9, 0x86, 0xb3, 0x3d,
5372
+	0xfa, 0x12, 0xca, 0x7e, 0x44, 0x66, 0xa6, 0x5d, 0x16, 0x9e, 0xe0, 0x70, 0xd4, 0x3b, 0x36, 0x1a,
5373
+	0xec, 0xd7, 0x16, 0x37, 0xdb, 0x65, 0x65, 0xc0, 0x9a, 0x86, 0xda, 0x69, 0xc7, 0x52, 0x6f, 0xd2,
5374
+	0x15, 0xb4, 0x86, 0x73, 0x96, 0xee, 0x7f, 0xcb, 0x60, 0xef, 0x07, 0xb1, 0x90, 0xa6, 0x0f, 0xdc,
5375
+	0x59, 0xde, 0x5e, 0xc0, 0x16, 0xd1, 0x33, 0x38, 0x09, 0x55, 0x51, 0xd5, 0x93, 0x80, 0xc9, 0xdd,
5376
+	0xa3, 0x42, 0x77, 0x19, 0x38, 0x99, 0x1a, 0xfa, 0x15, 0xe5, 0xd3, 0xb1, 0x70, 0x93, 0x7c, 0xe7,
5377
+	0x09, 0x3a, 0x85, 0x4d, 0xc6, 0xdd, 0x29, 0x15, 0x32, 0xa9, 0xc3, 0x66, 0x66, 0x2d, 0xfc, 0x9b,
5378
+	0xf9, 0x2a, 0x0f, 0x34, 0x45, 0x28, 0x89, 0x76, 0xd5, 0x07, 0x7a, 0x02, 0x65, 0x4e, 0x2e, 0xd2,
5379
+	0xa9, 0xa6, 0x50, 0xdf, 0x98, 0x5c, 0xc8, 0x15, 0x17, 0x9a, 0x81, 0x7e, 0x0f, 0xe0, 0xf9, 0x22,
5380
+	0x22, 0xd2, 0x9d, 0x52, 0x6e, 0xee, 0xa9, 0xf0, 0x88, 0x83, 0x0c, 0xb5, 0xe2, 0x25, 0xc7, 0x46,
5381
+	0x47, 0x50, 0x77, 0x49, 0xaa, 0xb4, 0xca, 0xed, 0x2d, 0x68, 0xbf, 0x67, 0x5c, 0x34, 0x95, 0x8b,
5382
+	0xc5, 0xcd, 0x76, 0x2d, 0xb5, 0xe0, 0x9a, 0x4b, 0x8c, 0xf2, 0x8e, 0x60, 0x53, 0x0d, 0xf8, 0x63,
5383
+	0x8f, 0x5e, 0x90, 0x38, 0x90, 0x42, 0x77, 0xcb, 0x5b, 0x8a, 0xaa, 0x9a, 0x35, 0x07, 0x06, 0x67,
5384
+	0xe2, 0x6a, 0xc8, 0x9c, 0x0d, 0xfd, 0x11, 0xb6, 0x68, 0xe8, 0xf2, 0x2b, 0xad, 0xb3, 0x34, 0xc2,
5385
+	0xda, 0xed, 0x87, 0x1d, 0x66, 0xe0, 0x95, 0xc3, 0x36, 0xe9, 0x77, 0xec, 0x5d, 0x1f, 0x20, 0x69,
5386
+	0x53, 0x77, 0xab, 0x3f, 0x04, 0x65, 0x8f, 0x48, 0xa2, 0x25, 0xd7, 0xc0, 0x7a, 0xdd, 0xff, 0xf0,
5387
+	0xd5, 0xeb, 0x76, 0xe9, 0x1f, 0xaf, 0xdb, 0xa5, 0x7f, 0xbf, 0x6e, 0x5b, 0x7f, 0x5e, 0xb4, 0xad,
5388
+	0x57, 0x8b, 0xb6, 0xf5, 0xf7, 0x45, 0xdb, 0xfa, 0xd7, 0xa2, 0x6d, 0x9d, 0x57, 0xf4, 0xff, 0xfb,
5389
+	0xcf, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0x66, 0xb4, 0xcd, 0xfe, 0x1e, 0x10, 0x00, 0x00,
5390 5390
 }
... ...
@@ -41,8 +41,8 @@ message NodeSpec {
41 41
 		DRAIN = 2 [(gogoproto.enumvalue_customname) = "NodeAvailabilityDrain"];
42 42
 	}
43 43
 
44
-	// Role defines the role the node should have.
45
-	NodeRole role = 2;
44
+	// DesiredRole defines the role the node should have.
45
+	NodeRole desired_role = 2;
46 46
 
47 47
 	// Membership controls the admission of the node into the cluster.
48 48
 	Membership membership = 3;
... ...
@@ -20,11 +20,11 @@ import (
20 20
 	cflog "github.com/cloudflare/cfssl/log"
21 21
 	cfsigner "github.com/cloudflare/cfssl/signer"
22 22
 	"github.com/cloudflare/cfssl/signer/local"
23
-	"github.com/docker/distribution/digest"
24 23
 	"github.com/docker/go-events"
25 24
 	"github.com/docker/swarmkit/api"
26 25
 	"github.com/docker/swarmkit/ioutils"
27 26
 	"github.com/docker/swarmkit/remotes"
27
+	"github.com/opencontainers/go-digest"
28 28
 	"github.com/pkg/errors"
29 29
 	"golang.org/x/net/context"
30 30
 	"google.golang.org/grpc"
... ...
@@ -486,7 +486,7 @@ func GetRemoteCA(ctx context.Context, d digest.Digest, r remotes.Remotes) (RootC
486 486
 	}
487 487
 
488 488
 	if d != "" {
489
-		verifier, err := digest.NewDigestVerifier(d)
489
+		verifier := d.Verifier()
490 490
 		if err != nil {
491 491
 			return RootCA{}, errors.Wrap(err, "unexpected error getting digest verifier")
492 492
 		}
... ...
@@ -15,11 +15,11 @@ import (
15 15
 
16 16
 	"github.com/Sirupsen/logrus"
17 17
 	cfconfig "github.com/cloudflare/cfssl/config"
18
-	"github.com/docker/distribution/digest"
19 18
 	"github.com/docker/swarmkit/api"
20 19
 	"github.com/docker/swarmkit/identity"
21 20
 	"github.com/docker/swarmkit/log"
22 21
 	"github.com/docker/swarmkit/remotes"
22
+	"github.com/opencontainers/go-digest"
23 23
 	"github.com/pkg/errors"
24 24
 	"google.golang.org/grpc/credentials"
25 25
 
... ...
@@ -196,7 +196,7 @@ func getCAHashFromToken(token string) (digest.Digest, error) {
196 196
 	var digestInt big.Int
197 197
 	digestInt.SetString(split[2], joinTokenBase)
198 198
 
199
-	return digest.ParseDigest(fmt.Sprintf("sha256:%0[1]*s", 64, digestInt.Text(16)))
199
+	return digest.Parse(fmt.Sprintf("sha256:%0[1]*s", 64, digestInt.Text(16)))
200 200
 }
201 201
 
202 202
 // DownloadRootCA tries to retrieve a remote root CA and matches the digest against the provided token.
... ...
@@ -250,7 +250,8 @@ func (s *Server) IssueNodeCertificate(ctx context.Context, request *api.IssueNod
250 250
 		// Create a new node
251 251
 		err := s.store.Update(func(tx store.Tx) error {
252 252
 			node := &api.Node{
253
-				ID: nodeID,
253
+				Role: role,
254
+				ID:   nodeID,
254 255
 				Certificate: api.Certificate{
255 256
 					CSR:  request.CSR,
256 257
 					CN:   nodeID,
... ...
@@ -260,7 +261,7 @@ func (s *Server) IssueNodeCertificate(ctx context.Context, request *api.IssueNod
260 260
 					},
261 261
 				},
262 262
 				Spec: api.NodeSpec{
263
-					Role:         role,
263
+					DesiredRole:  role,
264 264
 					Membership:   api.NodeMembershipAccepted,
265 265
 					Availability: request.Availability,
266 266
 				},
... ...
@@ -318,7 +319,7 @@ func (s *Server) issueRenewCertificate(ctx context.Context, nodeID string, csr [
318 318
 		cert = api.Certificate{
319 319
 			CSR:  csr,
320 320
 			CN:   node.ID,
321
-			Role: node.Spec.Role,
321
+			Role: node.Role,
322 322
 			Status: api.IssuanceStatus{
323 323
 				State: api.IssuanceStateRenew,
324 324
 			},
... ...
@@ -122,7 +122,7 @@ func NodeMatches(constraints []Constraint, n *api.Node) bool {
122 122
 				return false
123 123
 			}
124 124
 		case strings.EqualFold(constraint.key, "node.role"):
125
-			if !constraint.Match(n.Spec.Role.String()) {
125
+			if !constraint.Match(n.Role.String()) {
126 126
 				return false
127 127
 			}
128 128
 		case strings.EqualFold(constraint.key, "node.platform.os"):
... ...
@@ -146,7 +146,7 @@ func (s *Server) ListNodes(ctx context.Context, request *api.ListNodesRequest) (
146 146
 					return true
147 147
 				}
148 148
 				for _, c := range request.Filters.Roles {
149
-					if c == e.Spec.Role {
149
+					if c == e.Role {
150 150
 						return true
151 151
 					}
152 152
 				}
... ...
@@ -205,7 +205,6 @@ func (s *Server) UpdateNode(ctx context.Context, request *api.UpdateNodeRequest)
205 205
 	var (
206 206
 		node   *api.Node
207 207
 		member *membership.Member
208
-		demote bool
209 208
 	)
210 209
 
211 210
 	err := s.store.Update(func(tx store.Tx) error {
... ...
@@ -215,9 +214,7 @@ func (s *Server) UpdateNode(ctx context.Context, request *api.UpdateNodeRequest)
215 215
 		}
216 216
 
217 217
 		// Demotion sanity checks.
218
-		if node.Spec.Role == api.NodeRoleManager && request.Spec.Role == api.NodeRoleWorker {
219
-			demote = true
220
-
218
+		if node.Spec.DesiredRole == api.NodeRoleManager && request.Spec.DesiredRole == api.NodeRoleWorker {
221 219
 			// Check for manager entries in Store.
222 220
 			managers, err := store.FindNodes(tx, store.ByRole(api.NodeRoleManager))
223 221
 			if err != nil {
... ...
@@ -246,16 +243,6 @@ func (s *Server) UpdateNode(ctx context.Context, request *api.UpdateNodeRequest)
246 246
 		return nil, err
247 247
 	}
248 248
 
249
-	if demote && s.raft != nil {
250
-		// TODO(abronan): the remove can potentially fail and leave the node with
251
-		// an incorrect role (worker rather than manager), we need to reconcile the
252
-		// memberlist with the desired state rather than attempting to remove the
253
-		// member once.
254
-		if err := s.raft.RemoveMember(ctx, member.RaftID); err != nil {
255
-			return nil, grpc.Errorf(codes.Internal, "cannot demote manager to worker: %v", err)
256
-		}
257
-	}
258
-
259 249
 	return &api.UpdateNodeResponse{
260 250
 		Node: node,
261 251
 	}, nil
... ...
@@ -276,7 +263,7 @@ func (s *Server) RemoveNode(ctx context.Context, request *api.RemoveNodeRequest)
276 276
 		if node == nil {
277 277
 			return grpc.Errorf(codes.NotFound, "node %s not found", request.NodeID)
278 278
 		}
279
-		if node.Spec.Role == api.NodeRoleManager {
279
+		if node.Spec.DesiredRole == api.NodeRoleManager {
280 280
 			if s.raft == nil {
281 281
 				return grpc.Errorf(codes.FailedPrecondition, "node %s is a manager but cannot access node information from the raft memberlist", request.NodeID)
282 282
 			}
... ...
@@ -125,6 +125,7 @@ type Manager struct {
125 125
 	localserver            *grpc.Server
126 126
 	raftNode               *raft.Node
127 127
 	dekRotator             *RaftDEKManager
128
+	roleManager            *roleManager
128 129
 
129 130
 	cancelFunc context.CancelFunc
130 131
 
... ...
@@ -270,6 +271,12 @@ func New(config *Config) (*Manager, error) {
270 270
 	return m, nil
271 271
 }
272 272
 
273
+// RemovedFromRaft returns a channel that's closed if the manager is removed
274
+// from the raft cluster. This should be used to trigger a manager shutdown.
275
+func (m *Manager) RemovedFromRaft() <-chan struct{} {
276
+	return m.raftNode.RemovedFromRaft
277
+}
278
+
273 279
 // Addr returns tcp address on which remote api listens.
274 280
 func (m *Manager) Addr() string {
275 281
 	return m.config.RemoteAPI.ListenAddr
... ...
@@ -388,39 +395,26 @@ func (m *Manager) Run(parent context.Context) error {
388 388
 
389 389
 	close(m.started)
390 390
 
391
-	errCh := make(chan error, 1)
392 391
 	go func() {
393 392
 		err := m.raftNode.Run(ctx)
394 393
 		if err != nil {
395
-			errCh <- err
396 394
 			log.G(ctx).WithError(err).Error("raft node stopped")
397
-			m.Stop(ctx)
395
+			m.Stop(ctx, false)
398 396
 		}
399 397
 	}()
400 398
 
401
-	returnErr := func(err error) error {
402
-		select {
403
-		case runErr := <-errCh:
404
-			if runErr == raft.ErrMemberRemoved {
405
-				return runErr
406
-			}
407
-		default:
408
-		}
409
-		return err
410
-	}
411
-
412 399
 	if err := raft.WaitForLeader(ctx, m.raftNode); err != nil {
413
-		return returnErr(err)
400
+		return err
414 401
 	}
415 402
 
416 403
 	c, err := raft.WaitForCluster(ctx, m.raftNode)
417 404
 	if err != nil {
418
-		return returnErr(err)
405
+		return err
419 406
 	}
420 407
 	raftConfig := c.Spec.Raft
421 408
 
422 409
 	if err := m.watchForKEKChanges(ctx); err != nil {
423
-		return returnErr(err)
410
+		return err
424 411
 	}
425 412
 
426 413
 	if int(raftConfig.ElectionTick) != m.raftNode.Config.ElectionTick {
... ...
@@ -438,16 +432,17 @@ func (m *Manager) Run(parent context.Context) error {
438 438
 		return nil
439 439
 	}
440 440
 	m.mu.Unlock()
441
-	m.Stop(ctx)
441
+	m.Stop(ctx, false)
442 442
 
443
-	return returnErr(err)
443
+	return err
444 444
 }
445 445
 
446 446
 const stopTimeout = 8 * time.Second
447 447
 
448 448
 // Stop stops the manager. It immediately closes all open connections and
449
-// active RPCs as well as stopping the scheduler.
450
-func (m *Manager) Stop(ctx context.Context) {
449
+// active RPCs as well as stopping the scheduler. If clearData is set, the
450
+// raft logs, snapshots, and keys will be erased.
451
+func (m *Manager) Stop(ctx context.Context, clearData bool) {
451 452
 	log.G(ctx).Info("Stopping manager")
452 453
 	// It's not safe to start shutting down while the manager is still
453 454
 	// starting up.
... ...
@@ -472,6 +467,8 @@ func (m *Manager) Stop(ctx context.Context) {
472 472
 		close(localSrvDone)
473 473
 	}()
474 474
 
475
+	m.raftNode.Cancel()
476
+
475 477
 	m.dispatcher.Stop()
476 478
 	m.logbroker.Stop()
477 479
 	m.caserver.Stop()
... ...
@@ -494,10 +491,16 @@ func (m *Manager) Stop(ctx context.Context) {
494 494
 	if m.scheduler != nil {
495 495
 		m.scheduler.Stop()
496 496
 	}
497
+	if m.roleManager != nil {
498
+		m.roleManager.Stop()
499
+	}
497 500
 	if m.keyManager != nil {
498 501
 		m.keyManager.Stop()
499 502
 	}
500 503
 
504
+	if clearData {
505
+		m.raftNode.ClearData()
506
+	}
501 507
 	m.cancelFunc()
502 508
 	<-m.raftNode.Done()
503 509
 
... ...
@@ -778,6 +781,7 @@ func (m *Manager) becomeLeader(ctx context.Context) {
778 778
 	m.taskReaper = taskreaper.New(s)
779 779
 	m.scheduler = scheduler.New(s)
780 780
 	m.keyManager = keymanager.New(s, keymanager.DefaultConfig())
781
+	m.roleManager = newRoleManager(s, m.raftNode)
781 782
 
782 783
 	// TODO(stevvooe): Allocate a context that can be used to
783 784
 	// shutdown underlying manager processes when leadership is
... ...
@@ -853,6 +857,9 @@ func (m *Manager) becomeLeader(ctx context.Context) {
853 853
 		}
854 854
 	}(m.globalOrchestrator)
855 855
 
856
+	go func(roleManager *roleManager) {
857
+		roleManager.Run()
858
+	}(m.roleManager)
856 859
 }
857 860
 
858 861
 // becomeFollower shuts down the subsystems that are only run by the leader.
... ...
@@ -881,6 +888,9 @@ func (m *Manager) becomeFollower() {
881 881
 	m.scheduler.Stop()
882 882
 	m.scheduler = nil
883 883
 
884
+	m.roleManager.Stop()
885
+	m.roleManager = nil
886
+
884 887
 	if m.keyManager != nil {
885 888
 		m.keyManager.Stop()
886 889
 		m.keyManager = nil
... ...
@@ -937,7 +947,7 @@ func managerNode(nodeID string, availability api.NodeSpec_Availability) *api.Nod
937 937
 			},
938 938
 		},
939 939
 		Spec: api.NodeSpec{
940
-			Role:         api.NodeRoleManager,
940
+			DesiredRole:  api.NodeRoleManager,
941 941
 			Membership:   api.NodeMembershipAccepted,
942 942
 			Availability: availability,
943 943
 		},
944 944
new file mode 100644
... ...
@@ -0,0 +1,167 @@
0
+package manager
1
+
2
+import (
3
+	"time"
4
+
5
+	"github.com/docker/swarmkit/api"
6
+	"github.com/docker/swarmkit/log"
7
+	"github.com/docker/swarmkit/manager/state"
8
+	"github.com/docker/swarmkit/manager/state/raft"
9
+	"github.com/docker/swarmkit/manager/state/store"
10
+	"golang.org/x/net/context"
11
+)
12
+
13
+const roleReconcileInterval = 5 * time.Second
14
+
15
+// roleManager reconciles the raft member list with desired role changes.
16
+type roleManager struct {
17
+	ctx    context.Context
18
+	cancel func()
19
+
20
+	store    *store.MemoryStore
21
+	raft     *raft.Node
22
+	doneChan chan struct{}
23
+
24
+	// pending contains changed nodes that have not yet been reconciled in
25
+	// the raft member list.
26
+	pending map[string]*api.Node
27
+}
28
+
29
+// newRoleManager creates a new roleManager.
30
+func newRoleManager(store *store.MemoryStore, raftNode *raft.Node) *roleManager {
31
+	ctx, cancel := context.WithCancel(context.Background())
32
+	return &roleManager{
33
+		ctx:      ctx,
34
+		cancel:   cancel,
35
+		store:    store,
36
+		raft:     raftNode,
37
+		doneChan: make(chan struct{}),
38
+		pending:  make(map[string]*api.Node),
39
+	}
40
+}
41
+
42
+// Run is roleManager's main loop.
43
+func (rm *roleManager) Run() {
44
+	defer close(rm.doneChan)
45
+
46
+	var (
47
+		nodes    []*api.Node
48
+		ticker   *time.Ticker
49
+		tickerCh <-chan time.Time
50
+	)
51
+
52
+	watcher, cancelWatch, err := store.ViewAndWatch(rm.store,
53
+		func(readTx store.ReadTx) error {
54
+			var err error
55
+			nodes, err = store.FindNodes(readTx, store.All)
56
+			return err
57
+		},
58
+		state.EventUpdateNode{})
59
+	defer cancelWatch()
60
+
61
+	if err != nil {
62
+		log.L.WithError(err).Error("failed to check nodes for role changes")
63
+	} else {
64
+		for _, node := range nodes {
65
+			rm.pending[node.ID] = node
66
+			rm.reconcileRole(node)
67
+		}
68
+		if len(rm.pending) != 0 {
69
+			ticker = time.NewTicker(roleReconcileInterval)
70
+			tickerCh = ticker.C
71
+		}
72
+	}
73
+
74
+	for {
75
+		select {
76
+		case event := <-watcher:
77
+			node := event.(state.EventUpdateNode).Node
78
+			rm.pending[node.ID] = node
79
+			rm.reconcileRole(node)
80
+			if len(rm.pending) != 0 && ticker == nil {
81
+				ticker = time.NewTicker(roleReconcileInterval)
82
+				tickerCh = ticker.C
83
+			}
84
+		case <-tickerCh:
85
+			for _, node := range rm.pending {
86
+				rm.reconcileRole(node)
87
+			}
88
+			if len(rm.pending) == 0 {
89
+				ticker.Stop()
90
+				ticker = nil
91
+				tickerCh = nil
92
+			}
93
+		case <-rm.ctx.Done():
94
+			if ticker != nil {
95
+				ticker.Stop()
96
+			}
97
+			return
98
+		}
99
+	}
100
+}
101
+
102
+func (rm *roleManager) reconcileRole(node *api.Node) {
103
+	if node.Role == node.Spec.DesiredRole {
104
+		// Nothing to do.
105
+		delete(rm.pending, node.ID)
106
+		return
107
+	}
108
+
109
+	// Promotion can proceed right away.
110
+	if node.Spec.DesiredRole == api.NodeRoleManager && node.Role == api.NodeRoleWorker {
111
+		err := rm.store.Update(func(tx store.Tx) error {
112
+			updatedNode := store.GetNode(tx, node.ID)
113
+			if updatedNode == nil || updatedNode.Spec.DesiredRole != node.Spec.DesiredRole || updatedNode.Role != node.Role {
114
+				return nil
115
+			}
116
+			updatedNode.Role = api.NodeRoleManager
117
+			return store.UpdateNode(tx, updatedNode)
118
+		})
119
+		if err != nil {
120
+			log.L.WithError(err).Errorf("failed to promote node %s", node.ID)
121
+		} else {
122
+			delete(rm.pending, node.ID)
123
+		}
124
+	} else if node.Spec.DesiredRole == api.NodeRoleWorker && node.Role == api.NodeRoleManager {
125
+		// Check for node in memberlist
126
+		member := rm.raft.GetMemberByNodeID(node.ID)
127
+		if member != nil {
128
+			// Quorum safeguard
129
+			if !rm.raft.CanRemoveMember(member.RaftID) {
130
+				// TODO(aaronl): Retry later
131
+				log.L.Debugf("can't demote node %s at this time: removing member from raft would result in a loss of quorum", node.ID)
132
+				return
133
+			}
134
+
135
+			rmCtx, rmCancel := context.WithTimeout(rm.ctx, 5*time.Second)
136
+			defer rmCancel()
137
+
138
+			if err := rm.raft.RemoveMember(rmCtx, member.RaftID); err != nil {
139
+				// TODO(aaronl): Retry later
140
+				log.L.WithError(err).Debugf("can't demote node %s at this time", node.ID)
141
+				return
142
+			}
143
+		}
144
+
145
+		err := rm.store.Update(func(tx store.Tx) error {
146
+			updatedNode := store.GetNode(tx, node.ID)
147
+			if updatedNode == nil || updatedNode.Spec.DesiredRole != node.Spec.DesiredRole || updatedNode.Role != node.Role {
148
+				return nil
149
+			}
150
+			updatedNode.Role = api.NodeRoleWorker
151
+
152
+			return store.UpdateNode(tx, updatedNode)
153
+		})
154
+		if err != nil {
155
+			log.L.WithError(err).Errorf("failed to demote node %s", node.ID)
156
+		} else {
157
+			delete(rm.pending, node.ID)
158
+		}
159
+	}
160
+}
161
+
162
+// Stop stops the roleManager and waits for the main loop to exit.
163
+func (rm *roleManager) Stop() {
164
+	rm.cancel()
165
+	<-rm.doneChan
166
+}
... ...
@@ -112,9 +112,10 @@ type Node struct {
112 112
 
113 113
 	ticker clock.Ticker
114 114
 	doneCh chan struct{}
115
-	// removeRaftCh notifies about node deletion from raft cluster
116
-	removeRaftCh        chan struct{}
115
+	// RemovedFromRaft notifies about node deletion from raft cluster
116
+	RemovedFromRaft     chan struct{}
117 117
 	removeRaftFunc      func()
118
+	cancelFunc          func()
118 119
 	leadershipBroadcast *watch.Queue
119 120
 
120 121
 	// used to coordinate shutdown
... ...
@@ -134,6 +135,7 @@ type Node struct {
134 134
 	raftLogger          *storage.EncryptedRaftLogger
135 135
 	keyRotator          EncryptionKeyRotator
136 136
 	rotationQueued      bool
137
+	clearData           bool
137 138
 	waitForAppliedIndex uint64
138 139
 }
139 140
 
... ...
@@ -199,7 +201,7 @@ func NewNode(opts NodeOptions) *Node {
199 199
 			Logger:          cfg.Logger,
200 200
 		},
201 201
 		doneCh:              make(chan struct{}),
202
-		removeRaftCh:        make(chan struct{}),
202
+		RemovedFromRaft:     make(chan struct{}),
203 203
 		stopped:             make(chan struct{}),
204 204
 		leadershipBroadcast: watch.NewQueue(),
205 205
 		lastSendToMember:    make(map[uint64]chan struct{}),
... ...
@@ -220,7 +222,17 @@ func NewNode(opts NodeOptions) *Node {
220 220
 		var removeRaftOnce sync.Once
221 221
 		return func() {
222 222
 			removeRaftOnce.Do(func() {
223
-				close(n.removeRaftCh)
223
+				atomic.StoreUint32(&n.isMember, 0)
224
+				close(n.RemovedFromRaft)
225
+			})
226
+		}
227
+	}(n)
228
+
229
+	n.cancelFunc = func(n *Node) func() {
230
+		var cancelOnce sync.Once
231
+		return func() {
232
+			cancelOnce.Do(func() {
233
+				close(n.stopped)
224 234
 			})
225 235
 		}
226 236
 	}(n)
... ...
@@ -364,6 +376,12 @@ func (n *Node) done() {
364 364
 	close(n.doneCh)
365 365
 }
366 366
 
367
+// ClearData tells the raft node to delete its WALs, snapshots, and keys on
368
+// shutdown.
369
+func (n *Node) ClearData() {
370
+	n.clearData = true
371
+}
372
+
367 373
 // Run is the main loop for a Raft node, it goes along the state machine,
368 374
 // acting on the messages received from other Raft nodes in the cluster.
369 375
 //
... ...
@@ -373,13 +391,10 @@ func (n *Node) Run(ctx context.Context) error {
373 373
 	ctx = log.WithLogger(ctx, logrus.WithField("raft_id", fmt.Sprintf("%x", n.Config.ID)))
374 374
 	ctx, cancel := context.WithCancel(ctx)
375 375
 
376
-	// nodeRemoved indicates that node was stopped due its removal.
377
-	nodeRemoved := false
378
-
379 376
 	defer func() {
380 377
 		cancel()
381 378
 		n.stop(ctx)
382
-		if nodeRemoved {
379
+		if n.clearData {
383 380
 			// Delete WAL and snapshots, since they are no longer
384 381
 			// usable.
385 382
 			if err := n.raftLogger.Clear(ctx); err != nil {
... ...
@@ -501,9 +516,7 @@ func (n *Node) Run(ctx context.Context) error {
501 501
 					n.campaignWhenAble = false
502 502
 				}
503 503
 				if len(members) == 1 && members[n.Config.ID] != nil {
504
-					if err := n.raftNode.Campaign(ctx); err != nil {
505
-						panic("raft: cannot campaign to be the leader on node restore")
506
-					}
504
+					n.raftNode.Campaign(ctx)
507 505
 				}
508 506
 			}
509 507
 
... ...
@@ -536,12 +549,6 @@ func (n *Node) Run(ctx context.Context) error {
536 536
 			case n.needsSnapshot(ctx):
537 537
 				n.doSnapshot(ctx, n.getCurrentRaftConfig())
538 538
 			}
539
-		case <-n.removeRaftCh:
540
-			nodeRemoved = true
541
-			// If the node was removed from other members,
542
-			// send back an error to the caller to start
543
-			// the shutdown process.
544
-			return ErrMemberRemoved
545 539
 		case <-ctx.Done():
546 540
 			return nil
547 541
 		}
... ...
@@ -605,6 +612,15 @@ func (n *Node) getCurrentRaftConfig() api.RaftConfig {
605 605
 	return raftConfig
606 606
 }
607 607
 
608
+// Cancel interrupts all ongoing proposals, and prevents new ones from
609
+// starting. This is useful for the shutdown sequence because it allows
610
+// the manager to shut down raft-dependent services that might otherwise
611
+// block on shutdown if quorum isn't met. Then the raft node can be completely
612
+// shut down once no more code is using it.
613
+func (n *Node) Cancel() {
614
+	n.cancelFunc()
615
+}
616
+
608 617
 // Done returns channel which is closed when raft node is fully stopped.
609 618
 func (n *Node) Done() <-chan struct{} {
610 619
 	return n.doneCh
... ...
@@ -614,8 +630,7 @@ func (n *Node) stop(ctx context.Context) {
614 614
 	n.stopMu.Lock()
615 615
 	defer n.stopMu.Unlock()
616 616
 
617
-	close(n.stopped)
618
-
617
+	n.Cancel()
619 618
 	n.waitProp.Wait()
620 619
 	n.asyncTasks.Wait()
621 620
 
... ...
@@ -1240,17 +1255,6 @@ func (n *Node) IsMember() bool {
1240 1240
 	return atomic.LoadUint32(&n.isMember) == 1
1241 1241
 }
1242 1242
 
1243
-// canSubmitProposal defines if any more proposals
1244
-// could be submitted and processed.
1245
-func (n *Node) canSubmitProposal() bool {
1246
-	select {
1247
-	case <-n.stopped:
1248
-		return false
1249
-	default:
1250
-		return true
1251
-	}
1252
-}
1253
-
1254 1243
 // Saves a log entry to our Store
1255 1244
 func (n *Node) saveToStorage(
1256 1245
 	ctx context.Context,
... ...
@@ -1467,11 +1471,6 @@ func (n *Node) handleAddressChange(ctx context.Context, member *membership.Membe
1467 1467
 	return nil
1468 1468
 }
1469 1469
 
1470
-type applyResult struct {
1471
-	resp proto.Message
1472
-	err  error
1473
-}
1474
-
1475 1470
 // processInternalRaftRequest sends a message to nodes participating
1476 1471
 // in the raft to apply a log entry and then waits for it to be applied
1477 1472
 // on the server. It will block until the update is performed, there is
... ...
@@ -1479,7 +1478,7 @@ type applyResult struct {
1479 1479
 // shutdown.
1480 1480
 func (n *Node) processInternalRaftRequest(ctx context.Context, r *api.InternalRaftRequest, cb func()) (proto.Message, error) {
1481 1481
 	n.stopMu.RLock()
1482
-	if !n.canSubmitProposal() {
1482
+	if !n.IsMember() {
1483 1483
 		n.stopMu.RUnlock()
1484 1484
 		return nil, ErrStopped
1485 1485
 	}
... ...
@@ -1519,15 +1518,27 @@ func (n *Node) processInternalRaftRequest(ctx context.Context, r *api.InternalRa
1519 1519
 	}
1520 1520
 
1521 1521
 	select {
1522
-	case x := <-ch:
1523
-		res := x.(*applyResult)
1524
-		return res.resp, res.err
1522
+	case x, ok := <-ch:
1523
+		if !ok {
1524
+			return nil, ErrLostLeadership
1525
+		}
1526
+		return x.(proto.Message), nil
1525 1527
 	case <-waitCtx.Done():
1526 1528
 		n.wait.cancel(r.ID)
1527
-		return nil, ErrLostLeadership
1529
+		// if channel is closed, wait item was canceled, otherwise it was triggered
1530
+		x, ok := <-ch
1531
+		if !ok {
1532
+			return nil, ErrLostLeadership
1533
+		}
1534
+		return x.(proto.Message), nil
1528 1535
 	case <-ctx.Done():
1529 1536
 		n.wait.cancel(r.ID)
1530
-		return nil, ctx.Err()
1537
+		// if channel is closed, wait item was canceled, otherwise it was triggered
1538
+		x, ok := <-ch
1539
+		if !ok {
1540
+			return nil, ctx.Err()
1541
+		}
1542
+		return x.(proto.Message), nil
1531 1543
 	}
1532 1544
 }
1533 1545
 
... ...
@@ -1588,7 +1599,7 @@ func (n *Node) processEntry(ctx context.Context, entry raftpb.Entry) error {
1588 1588
 		return nil
1589 1589
 	}
1590 1590
 
1591
-	if !n.wait.trigger(r.ID, &applyResult{resp: r, err: nil}) {
1591
+	if !n.wait.trigger(r.ID, r) {
1592 1592
 		// There was no wait on this ID, meaning we don't have a
1593 1593
 		// transaction in progress that would be committed to the
1594 1594
 		// 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
1713 1713
 	}
1714 1714
 
1715 1715
 	if cc.NodeID == n.Config.ID {
1716
-		n.removeRaftFunc()
1717
-
1718 1716
 		// wait the commit ack to be sent before closing connection
1719 1717
 		n.asyncTasks.Wait()
1720 1718
 
1719
+		n.removeRaftFunc()
1720
+
1721 1721
 		// if there are only 2 nodes in the cluster, and leader is leaving
1722 1722
 		// before closing the connection, leader has to ensure that follower gets
1723 1723
 		// noticed about this raft conf change commit. Otherwise, follower would
... ...
@@ -55,8 +55,11 @@ func (w *wait) cancel(id uint64) {
55 55
 	waitItem, ok := w.m[id]
56 56
 	delete(w.m, id)
57 57
 	w.l.Unlock()
58
-	if ok && waitItem.cancel != nil {
59
-		waitItem.cancel()
58
+	if ok {
59
+		if waitItem.cancel != nil {
60
+			waitItem.cancel()
61
+		}
62
+		close(waitItem.ch)
60 63
 	}
61 64
 }
62 65
 
... ...
@@ -69,5 +72,6 @@ func (w *wait) cancelAll() {
69 69
 		if waitItem.cancel != nil {
70 70
 			waitItem.cancel()
71 71
 		}
72
+		close(waitItem.ch)
72 73
 	}
73 74
 }
... ...
@@ -238,7 +238,7 @@ func (ni nodeIndexerByRole) FromObject(obj interface{}) (bool, []byte, error) {
238 238
 	}
239 239
 
240 240
 	// Add the null character as a terminator
241
-	return true, []byte(strconv.FormatInt(int64(n.Spec.Role), 10) + "\x00"), nil
241
+	return true, []byte(strconv.FormatInt(int64(n.Role), 10) + "\x00"), nil
242 242
 }
243 243
 
244 244
 type nodeIndexerByMembership struct{}
... ...
@@ -22,7 +22,6 @@ import (
22 22
 	"github.com/docker/swarmkit/log"
23 23
 	"github.com/docker/swarmkit/manager"
24 24
 	"github.com/docker/swarmkit/manager/encryption"
25
-	"github.com/docker/swarmkit/manager/state/raft"
26 25
 	"github.com/docker/swarmkit/remotes"
27 26
 	"github.com/docker/swarmkit/xnet"
28 27
 	"github.com/pkg/errors"
... ...
@@ -249,18 +248,13 @@ func (n *Node) run(ctx context.Context) (err error) {
249 249
 				// If we got a role change, renew
250 250
 				lastRole := n.role
251 251
 				role := ca.WorkerRole
252
-				if node.Spec.Role == api.NodeRoleManager {
252
+				if node.Role == api.NodeRoleManager {
253 253
 					role = ca.ManagerRole
254 254
 				}
255 255
 				if lastRole == role {
256 256
 					n.Unlock()
257 257
 					continue
258 258
 				}
259
-				// switch role to agent immediately to shutdown manager early
260
-				if role == ca.WorkerRole {
261
-					n.role = role
262
-					n.roleCond.Broadcast()
263
-				}
264 259
 				n.Unlock()
265 260
 				renewCert()
266 261
 			}
... ...
@@ -308,7 +302,18 @@ func (n *Node) run(ctx context.Context) (err error) {
308 308
 	go func() {
309 309
 		<-agentReady
310 310
 		if role == ca.ManagerRole {
311
-			<-managerReady
311
+			workerRole := make(chan struct{})
312
+			waitRoleCtx, waitRoleCancel := context.WithCancel(ctx)
313
+			go func() {
314
+				if n.waitRole(waitRoleCtx, ca.WorkerRole) == nil {
315
+					close(workerRole)
316
+				}
317
+			}()
318
+			select {
319
+			case <-managerReady:
320
+			case <-workerRole:
321
+			}
322
+			waitRoleCancel()
312 323
 		}
313 324
 		close(n.ready)
314 325
 	}()
... ...
@@ -632,7 +637,7 @@ func (n *Node) waitRole(ctx context.Context, role string) error {
632 632
 	return nil
633 633
 }
634 634
 
635
-func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig, ready chan struct{}) error {
635
+func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig, ready chan struct{}, workerRole <-chan struct{}) error {
636 636
 	remoteAddr, _ := n.remotes.Select(n.NodeID())
637 637
 	m, err := manager.New(&manager.Config{
638 638
 		ForceNewCluster: n.config.ForceNewCluster,
... ...
@@ -657,25 +662,18 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
657 657
 	done := make(chan struct{})
658 658
 	var runErr error
659 659
 	go func() {
660
-		if err := m.Run(context.Background()); err != nil && err != raft.ErrMemberRemoved {
660
+		if err := m.Run(context.Background()); err != nil {
661 661
 			runErr = err
662 662
 		}
663 663
 		close(done)
664 664
 	}()
665 665
 
666
-	workerRole := make(chan struct{})
667
-	waitRoleCtx, waitRoleCancel := context.WithCancel(ctx)
668
-	defer waitRoleCancel()
669
-	go func() {
670
-		n.waitRole(waitRoleCtx, ca.WorkerRole)
671
-		close(workerRole)
672
-	}()
673
-
666
+	var clearData bool
674 667
 	defer func() {
675 668
 		n.Lock()
676 669
 		n.manager = nil
677 670
 		n.Unlock()
678
-		m.Stop(ctx)
671
+		m.Stop(ctx, clearData)
679 672
 		<-done
680 673
 		n.setControlSocket(nil)
681 674
 	}()
... ...
@@ -706,33 +704,19 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
706 706
 	}
707 707
 
708 708
 	// wait for manager stop or for role change
709
-	// if manager stopped before role change, wait for new role for 16 seconds,
710
-	// then just restart manager, we might just miss that event.
711
-	// we need to wait for role to prevent manager to start again with wrong
712
-	// certificate
713 709
 	select {
714 710
 	case <-done:
715
-		timer := time.NewTimer(16 * time.Second)
716
-		defer timer.Stop()
717
-		select {
718
-		case <-timer.C:
719
-			log.G(ctx).Warn("failed to get worker role after manager stop, restart manager")
720
-		case <-workerRole:
721
-		case <-ctx.Done():
722
-			return ctx.Err()
723
-		}
724 711
 		return runErr
725 712
 	case <-workerRole:
726
-		log.G(ctx).Info("role changed to worker, wait for manager to stop")
727
-		select {
728
-		case <-done:
729
-			return runErr
730
-		case <-ctx.Done():
731
-			return ctx.Err()
732
-		}
713
+		log.G(ctx).Info("role changed to worker, stopping manager")
714
+		clearData = true
715
+	case <-m.RemovedFromRaft():
716
+		log.G(ctx).Info("manager removed from raft cluster, stopping manager")
717
+		clearData = true
733 718
 	case <-ctx.Done():
734 719
 		return ctx.Err()
735 720
 	}
721
+	return nil
736 722
 }
737 723
 
738 724
 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
740 740
 		if err := n.waitRole(ctx, ca.ManagerRole); err != nil {
741 741
 			return err
742 742
 		}
743
-		if err := n.runManager(ctx, securityConfig, ready); err != nil {
743
+
744
+		workerRole := make(chan struct{})
745
+		waitRoleCtx, waitRoleCancel := context.WithCancel(ctx)
746
+		go func() {
747
+			if n.waitRole(waitRoleCtx, ca.WorkerRole) == nil {
748
+				close(workerRole)
749
+			}
750
+		}()
751
+
752
+		if err := n.runManager(ctx, securityConfig, ready, workerRole); err != nil {
753
+			waitRoleCancel()
744 754
 			return errors.Wrap(err, "manager stopped")
745 755
 		}
756
+
757
+		// If the manager stopped running and our role is still
758
+		// "manager", it's possible that the manager was demoted and
759
+		// the agent hasn't realized this yet. We should wait for the
760
+		// role to change instead of restarting the manager immediately.
761
+		timer := time.NewTimer(16 * time.Second)
762
+		select {
763
+		case <-timer.C:
764
+			log.G(ctx).Warn("failed to get worker role after manager stop, restarting manager")
765
+		case <-workerRole:
766
+		case <-ctx.Done():
767
+			timer.Stop()
768
+			waitRoleCancel()
769
+			return ctx.Err()
770
+		}
771
+		timer.Stop()
772
+		waitRoleCancel()
773
+
746 774
 		ready = nil
747 775
 	}
748 776
 }
749 777
new file mode 100644
... ...
@@ -0,0 +1,144 @@
0
+package digest
1
+
2
+import (
3
+	"crypto"
4
+	"fmt"
5
+	"hash"
6
+	"io"
7
+)
8
+
9
+// Algorithm identifies and implementation of a digester by an identifier.
10
+// Note the that this defines both the hash algorithm used and the string
11
+// encoding.
12
+type Algorithm string
13
+
14
+// supported digest types
15
+const (
16
+	SHA256 Algorithm = "sha256" // sha256 with hex encoding
17
+	SHA384 Algorithm = "sha384" // sha384 with hex encoding
18
+	SHA512 Algorithm = "sha512" // sha512 with hex encoding
19
+
20
+	// Canonical is the primary digest algorithm used with the distribution
21
+	// project. Other digests may be used but this one is the primary storage
22
+	// digest.
23
+	Canonical = SHA256
24
+)
25
+
26
+var (
27
+	// TODO(stevvooe): Follow the pattern of the standard crypto package for
28
+	// registration of digests. Effectively, we are a registerable set and
29
+	// common symbol access.
30
+
31
+	// algorithms maps values to hash.Hash implementations. Other algorithms
32
+	// may be available but they cannot be calculated by the digest package.
33
+	algorithms = map[Algorithm]crypto.Hash{
34
+		SHA256: crypto.SHA256,
35
+		SHA384: crypto.SHA384,
36
+		SHA512: crypto.SHA512,
37
+	}
38
+)
39
+
40
+// Available returns true if the digest type is available for use. If this
41
+// returns false, Digester and Hash will return nil.
42
+func (a Algorithm) Available() bool {
43
+	h, ok := algorithms[a]
44
+	if !ok {
45
+		return false
46
+	}
47
+
48
+	// check availability of the hash, as well
49
+	return h.Available()
50
+}
51
+
52
+func (a Algorithm) String() string {
53
+	return string(a)
54
+}
55
+
56
+// Size returns number of bytes returned by the hash.
57
+func (a Algorithm) Size() int {
58
+	h, ok := algorithms[a]
59
+	if !ok {
60
+		return 0
61
+	}
62
+	return h.Size()
63
+}
64
+
65
+// Set implemented to allow use of Algorithm as a command line flag.
66
+func (a *Algorithm) Set(value string) error {
67
+	if value == "" {
68
+		*a = Canonical
69
+	} else {
70
+		// just do a type conversion, support is queried with Available.
71
+		*a = Algorithm(value)
72
+	}
73
+
74
+	if !a.Available() {
75
+		return ErrDigestUnsupported
76
+	}
77
+
78
+	return nil
79
+}
80
+
81
+// Digester returns a new digester for the specified algorithm. If the algorithm
82
+// does not have a digester implementation, nil will be returned. This can be
83
+// checked by calling Available before calling Digester.
84
+func (a Algorithm) Digester() Digester {
85
+	return &digester{
86
+		alg:  a,
87
+		hash: a.Hash(),
88
+	}
89
+}
90
+
91
+// Hash returns a new hash as used by the algorithm. If not available, the
92
+// method will panic. Check Algorithm.Available() before calling.
93
+func (a Algorithm) Hash() hash.Hash {
94
+	if !a.Available() {
95
+		// Empty algorithm string is invalid
96
+		if a == "" {
97
+			panic(fmt.Sprintf("empty digest algorithm, validate before calling Algorithm.Hash()"))
98
+		}
99
+
100
+		// NOTE(stevvooe): A missing hash is usually a programming error that
101
+		// must be resolved at compile time. We don't import in the digest
102
+		// package to allow users to choose their hash implementation (such as
103
+		// when using stevvooe/resumable or a hardware accelerated package).
104
+		//
105
+		// Applications that may want to resolve the hash at runtime should
106
+		// call Algorithm.Available before call Algorithm.Hash().
107
+		panic(fmt.Sprintf("%v not available (make sure it is imported)", a))
108
+	}
109
+
110
+	return algorithms[a].New()
111
+}
112
+
113
+// FromReader returns the digest of the reader using the algorithm.
114
+func (a Algorithm) FromReader(rd io.Reader) (Digest, error) {
115
+	digester := a.Digester()
116
+
117
+	if _, err := io.Copy(digester.Hash(), rd); err != nil {
118
+		return "", err
119
+	}
120
+
121
+	return digester.Digest(), nil
122
+}
123
+
124
+// FromBytes digests the input and returns a Digest.
125
+func (a Algorithm) FromBytes(p []byte) Digest {
126
+	digester := a.Digester()
127
+
128
+	if _, err := digester.Hash().Write(p); err != nil {
129
+		// Writes to a Hash should never fail. None of the existing
130
+		// hash implementations in the stdlib or hashes vendored
131
+		// here can return errors from Write. Having a panic in this
132
+		// condition instead of having FromBytes return an error value
133
+		// avoids unnecessary error handling paths in all callers.
134
+		panic("write to hash function returned error: " + err.Error())
135
+	}
136
+
137
+	return digester.Digest()
138
+}
139
+
140
+// FromString digests the string input and returns a Digest.
141
+func (a Algorithm) FromString(s string) Digest {
142
+	return a.FromBytes([]byte(s))
143
+}
0 144
new file mode 100644
... ...
@@ -0,0 +1,140 @@
0
+package digest
1
+
2
+import (
3
+	"fmt"
4
+	"hash"
5
+	"io"
6
+	"regexp"
7
+	"strings"
8
+)
9
+
10
+// Digest allows simple protection of hex formatted digest strings, prefixed
11
+// by their algorithm. Strings of type Digest have some guarantee of being in
12
+// the correct format and it provides quick access to the components of a
13
+// digest string.
14
+//
15
+// The following is an example of the contents of Digest types:
16
+//
17
+// 	sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc
18
+//
19
+// This allows to abstract the digest behind this type and work only in those
20
+// terms.
21
+type Digest string
22
+
23
+// NewDigest returns a Digest from alg and a hash.Hash object.
24
+func NewDigest(alg Algorithm, h hash.Hash) Digest {
25
+	return NewDigestFromBytes(alg, h.Sum(nil))
26
+}
27
+
28
+// NewDigestFromBytes returns a new digest from the byte contents of p.
29
+// Typically, this can come from hash.Hash.Sum(...) or xxx.SumXXX(...)
30
+// functions. This is also useful for rebuilding digests from binary
31
+// serializations.
32
+func NewDigestFromBytes(alg Algorithm, p []byte) Digest {
33
+	return Digest(fmt.Sprintf("%s:%x", alg, p))
34
+}
35
+
36
+// NewDigestFromHex returns a Digest from alg and a the hex encoded digest.
37
+func NewDigestFromHex(alg, hex string) Digest {
38
+	return Digest(fmt.Sprintf("%s:%s", alg, hex))
39
+}
40
+
41
+// DigestRegexp matches valid digest types.
42
+var DigestRegexp = regexp.MustCompile(`[a-zA-Z0-9-_+.]+:[a-fA-F0-9]+`)
43
+
44
+// DigestRegexpAnchored matches valid digest types, anchored to the start and end of the match.
45
+var DigestRegexpAnchored = regexp.MustCompile(`^` + DigestRegexp.String() + `$`)
46
+
47
+var (
48
+	// ErrDigestInvalidFormat returned when digest format invalid.
49
+	ErrDigestInvalidFormat = fmt.Errorf("invalid checksum digest format")
50
+
51
+	// ErrDigestInvalidLength returned when digest has invalid length.
52
+	ErrDigestInvalidLength = fmt.Errorf("invalid checksum digest length")
53
+
54
+	// ErrDigestUnsupported returned when the digest algorithm is unsupported.
55
+	ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm")
56
+)
57
+
58
+// Parse parses s and returns the validated digest object. An error will
59
+// be returned if the format is invalid.
60
+func Parse(s string) (Digest, error) {
61
+	d := Digest(s)
62
+	return d, d.Validate()
63
+}
64
+
65
+// FromReader consumes the content of rd until io.EOF, returning canonical digest.
66
+func FromReader(rd io.Reader) (Digest, error) {
67
+	return Canonical.FromReader(rd)
68
+}
69
+
70
+// FromBytes digests the input and returns a Digest.
71
+func FromBytes(p []byte) Digest {
72
+	return Canonical.FromBytes(p)
73
+}
74
+
75
+// FromString digests the input and returns a Digest.
76
+func FromString(s string) Digest {
77
+	return Canonical.FromString(s)
78
+}
79
+
80
+// Validate checks that the contents of d is a valid digest, returning an
81
+// error if not.
82
+func (d Digest) Validate() error {
83
+	s := string(d)
84
+
85
+	i := strings.Index(s, ":")
86
+
87
+	// validate i then run through regexp
88
+	if i < 0 || i+1 == len(s) || !DigestRegexpAnchored.MatchString(s) {
89
+		return ErrDigestInvalidFormat
90
+	}
91
+
92
+	algorithm := Algorithm(s[:i])
93
+	if !algorithm.Available() {
94
+		return ErrDigestUnsupported
95
+	}
96
+
97
+	// Digests much always be hex-encoded, ensuring that their hex portion will
98
+	// always be size*2
99
+	if algorithm.Size()*2 != len(s[i+1:]) {
100
+		return ErrDigestInvalidLength
101
+	}
102
+
103
+	return nil
104
+}
105
+
106
+// Algorithm returns the algorithm portion of the digest. This will panic if
107
+// the underlying digest is not in a valid format.
108
+func (d Digest) Algorithm() Algorithm {
109
+	return Algorithm(d[:d.sepIndex()])
110
+}
111
+
112
+// Verifier returns a writer object that can be used to verify a stream of
113
+// content against the digest. If the digest is invalid, the method will panic.
114
+func (d Digest) Verifier() Verifier {
115
+	return hashVerifier{
116
+		hash:   d.Algorithm().Hash(),
117
+		digest: d,
118
+	}
119
+}
120
+
121
+// Hex returns the hex digest portion of the digest. This will panic if the
122
+// underlying digest is not in a valid format.
123
+func (d Digest) Hex() string {
124
+	return string(d[d.sepIndex()+1:])
125
+}
126
+
127
+func (d Digest) String() string {
128
+	return string(d)
129
+}
130
+
131
+func (d Digest) sepIndex() int {
132
+	i := strings.Index(string(d), ":")
133
+
134
+	if i < 0 {
135
+		panic(fmt.Sprintf("no ':' separator in digest %q", d))
136
+	}
137
+
138
+	return i
139
+}
0 140
new file mode 100644
... ...
@@ -0,0 +1,25 @@
0
+package digest
1
+
2
+import "hash"
3
+
4
+// Digester calculates the digest of written data. Writes should go directly
5
+// to the return value of Hash, while calling Digest will return the current
6
+// value of the digest.
7
+type Digester interface {
8
+	Hash() hash.Hash // provides direct access to underlying hash instance.
9
+	Digest() Digest
10
+}
11
+
12
+// digester provides a simple digester definition that embeds a hasher.
13
+type digester struct {
14
+	alg  Algorithm
15
+	hash hash.Hash
16
+}
17
+
18
+func (d *digester) Hash() hash.Hash {
19
+	return d.hash
20
+}
21
+
22
+func (d *digester) Digest() Digest {
23
+	return NewDigest(d.alg, d.hash)
24
+}
0 25
new file mode 100644
... ...
@@ -0,0 +1,42 @@
0
+// Package digest provides a generalized type to opaquely represent message
1
+// digests and their operations within the registry. The Digest type is
2
+// designed to serve as a flexible identifier in a content-addressable system.
3
+// More importantly, it provides tools and wrappers to work with
4
+// hash.Hash-based digests with little effort.
5
+//
6
+// Basics
7
+//
8
+// The format of a digest is simply a string with two parts, dubbed the
9
+// "algorithm" and the "digest", separated by a colon:
10
+//
11
+// 	<algorithm>:<digest>
12
+//
13
+// An example of a sha256 digest representation follows:
14
+//
15
+// 	sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc
16
+//
17
+// In this case, the string "sha256" is the algorithm and the hex bytes are
18
+// the "digest".
19
+//
20
+// Because the Digest type is simply a string, once a valid Digest is
21
+// obtained, comparisons are cheap, quick and simple to express with the
22
+// standard equality operator.
23
+//
24
+// Verification
25
+//
26
+// The main benefit of using the Digest type is simple verification against a
27
+// given digest. The Verifier interface, modeled after the stdlib hash.Hash
28
+// interface, provides a common write sink for digest verification. After
29
+// writing is complete, calling the Verifier.Verified method will indicate
30
+// whether or not the stream of bytes matches the target digest.
31
+//
32
+// Missing Features
33
+//
34
+// In addition to the above, we intend to add the following features to this
35
+// package:
36
+//
37
+// 1. A Digester type that supports write sink digest calculation.
38
+//
39
+// 2. Suspend and resume of ongoing digest calculations to support efficient digest verification in the registry.
40
+//
41
+package digest
0 42
new file mode 100644
... ...
@@ -0,0 +1,31 @@
0
+package digest
1
+
2
+import (
3
+	"hash"
4
+	"io"
5
+)
6
+
7
+// Verifier presents a general verification interface to be used with message
8
+// digests and other byte stream verifications. Users instantiate a Verifier
9
+// from one of the various methods, write the data under test to it then check
10
+// the result with the Verified method.
11
+type Verifier interface {
12
+	io.Writer
13
+
14
+	// Verified will return true if the content written to Verifier matches
15
+	// the digest.
16
+	Verified() bool
17
+}
18
+
19
+type hashVerifier struct {
20
+	digest Digest
21
+	hash   hash.Hash
22
+}
23
+
24
+func (hv hashVerifier) Write(p []byte) (n int, err error) {
25
+	return hv.hash.Write(p)
26
+}
27
+
28
+func (hv hashVerifier) Verified() bool {
29
+	return hv.digest == NewDigest(hv.digest.Algorithm(), hv.hash)
30
+}