Signed-off-by: Stephen J Day <stephen.day@docker.com>
| ... | ... |
@@ -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 |
| 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 |
+} |
| ... | ... |
@@ -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 |
| ... | ... |
@@ -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 |
| ... | ... |
@@ -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 |
} |
| ... | ... |
@@ -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
|
| ... | ... |
@@ -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 |
+} |