Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
| ... | ... |
@@ -60,12 +60,12 @@ clone git golang.org/x/net 2beffdc2e92c8a3027590f898fe88f69af48a3f8 https://gith |
| 60 | 60 |
clone git golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git |
| 61 | 61 |
clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3 |
| 62 | 62 |
clone git github.com/docker/go-connections fa2850ff103453a9ad190da0df0af134f0314b3d |
| 63 |
-clone git github.com/docker/engine-api 19b4fb48a86c3318e610e156ec06b684f79ac31d |
|
| 63 |
+clone git github.com/docker/engine-api 62043eb79d581a32ea849645277023c550732e52 |
|
| 64 | 64 |
clone git github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837 |
| 65 | 65 |
clone git github.com/imdario/mergo 0.2.1 |
| 66 | 66 |
|
| 67 | 67 |
#get libnetwork packages |
| 68 |
-clone git github.com/docker/libnetwork ed311d050fda7821f2e7c53a7e08a0205923aef5 |
|
| 68 |
+clone git github.com/docker/libnetwork 377a7337f2387cce3be1df7a4503446147b68ff1 |
|
| 69 | 69 |
clone git github.com/docker/go-events 39718a26497694185f8fb58a7d6f31947f3dc42d |
| 70 | 70 |
clone git github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 |
| 71 | 71 |
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec |
| ... | ... |
@@ -139,10 +139,10 @@ clone git github.com/docker/docker-credential-helpers v0.3.0 |
| 139 | 139 |
clone git github.com/docker/containerd b93a33be39bc4ef0fb00bfcb79147a28c33d9d43 |
| 140 | 140 |
|
| 141 | 141 |
# cluster |
| 142 |
-clone git github.com/docker/swarmkit 3f135f206179ea157aeef2d1d401eb795f618da8 |
|
| 142 |
+clone git github.com/docker/swarmkit 036a4a1e934bd1bbb35c3ec7f85dea2ba6d4e336 |
|
| 143 | 143 |
clone git github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9 |
| 144 | 144 |
clone git github.com/gogo/protobuf 43a2e0b1c32252bfbbdf81f7faa7a88fb3fa4028 |
| 145 |
-clone git github.com/cloudflare/cfssl 92f037e39eb103fb30f9151be40d9ed267fc4ae2 |
|
| 145 |
+clone git github.com/cloudflare/cfssl b895b0549c0ff676f92cf09ba971ae02bb41367b |
|
| 146 | 146 |
clone git github.com/google/certificate-transparency 025a5cab06f6a819c455d9fdc9e2a1b6d0982284 |
| 147 | 147 |
clone git golang.org/x/crypto 3fbbcd23f1cb824e69491a5930cfeff09b12f4d2 https://github.com/golang/crypto.git |
| 148 | 148 |
clone git github.com/mreiferson/go-httpclient 63fe23f7434723dc904c901043af07931f293c47 |
| 149 | 149 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,231 @@ |
| 0 |
+// Package api implements an HTTP-based API and server for CFSSL. |
|
| 1 |
+package api |
|
| 2 |
+ |
|
| 3 |
+import ( |
|
| 4 |
+ "encoding/json" |
|
| 5 |
+ "io/ioutil" |
|
| 6 |
+ "net/http" |
|
| 7 |
+ |
|
| 8 |
+ "github.com/cloudflare/cfssl/errors" |
|
| 9 |
+ "github.com/cloudflare/cfssl/log" |
|
| 10 |
+) |
|
| 11 |
+ |
|
| 12 |
+// Handler is an interface providing a generic mechanism for handling HTTP requests. |
|
| 13 |
+type Handler interface {
|
|
| 14 |
+ Handle(w http.ResponseWriter, r *http.Request) error |
|
| 15 |
+} |
|
| 16 |
+ |
|
| 17 |
+// HTTPHandler is a wrapper that encapsulates Handler interface as http.Handler. |
|
| 18 |
+// HTTPHandler also enforces that the Handler only responds to requests with registered HTTP methods. |
|
| 19 |
+type HTTPHandler struct {
|
|
| 20 |
+ Handler // CFSSL handler |
|
| 21 |
+ Methods []string // The associated HTTP methods |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+// HandlerFunc is similar to the http.HandlerFunc type; it serves as |
|
| 25 |
+// an adapter allowing the use of ordinary functions as Handlers. If |
|
| 26 |
+// f is a function with the appropriate signature, HandlerFunc(f) is a |
|
| 27 |
+// Handler object that calls f. |
|
| 28 |
+type HandlerFunc func(http.ResponseWriter, *http.Request) error |
|
| 29 |
+ |
|
| 30 |
+// Handle calls f(w, r) |
|
| 31 |
+func (f HandlerFunc) Handle(w http.ResponseWriter, r *http.Request) error {
|
|
| 32 |
+ w.Header().Set("Content-Type", "application/json")
|
|
| 33 |
+ return f(w, r) |
|
| 34 |
+} |
|
| 35 |
+ |
|
| 36 |
+// handleError is the centralised error handling and reporting. |
|
| 37 |
+func handleError(w http.ResponseWriter, err error) (code int) {
|
|
| 38 |
+ if err == nil {
|
|
| 39 |
+ return http.StatusOK |
|
| 40 |
+ } |
|
| 41 |
+ msg := err.Error() |
|
| 42 |
+ httpCode := http.StatusInternalServerError |
|
| 43 |
+ |
|
| 44 |
+ // If it is recognized as HttpError emitted from cfssl, |
|
| 45 |
+ // we rewrite the status code accordingly. If it is a |
|
| 46 |
+ // cfssl error, set the http status to StatusBadRequest |
|
| 47 |
+ switch err := err.(type) {
|
|
| 48 |
+ case *errors.HTTPError: |
|
| 49 |
+ httpCode = err.StatusCode |
|
| 50 |
+ code = err.StatusCode |
|
| 51 |
+ case *errors.Error: |
|
| 52 |
+ httpCode = http.StatusBadRequest |
|
| 53 |
+ code = err.ErrorCode |
|
| 54 |
+ msg = err.Message |
|
| 55 |
+ } |
|
| 56 |
+ |
|
| 57 |
+ response := NewErrorResponse(msg, code) |
|
| 58 |
+ jsonMessage, err := json.Marshal(response) |
|
| 59 |
+ if err != nil {
|
|
| 60 |
+ log.Errorf("Failed to marshal JSON: %v", err)
|
|
| 61 |
+ } else {
|
|
| 62 |
+ msg = string(jsonMessage) |
|
| 63 |
+ } |
|
| 64 |
+ http.Error(w, msg, httpCode) |
|
| 65 |
+ return code |
|
| 66 |
+} |
|
| 67 |
+ |
|
| 68 |
+// ServeHTTP encapsulates the call to underlying Handler to handle the request |
|
| 69 |
+// and return the response with proper HTTP status code |
|
| 70 |
+func (h HTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
| 71 |
+ var err error |
|
| 72 |
+ var match bool |
|
| 73 |
+ // Throw 405 when requested with an unsupported verb. |
|
| 74 |
+ for _, m := range h.Methods {
|
|
| 75 |
+ if m == r.Method {
|
|
| 76 |
+ match = true |
|
| 77 |
+ } |
|
| 78 |
+ } |
|
| 79 |
+ if match {
|
|
| 80 |
+ err = h.Handle(w, r) |
|
| 81 |
+ } else {
|
|
| 82 |
+ err = errors.NewMethodNotAllowed(r.Method) |
|
| 83 |
+ } |
|
| 84 |
+ status := handleError(w, err) |
|
| 85 |
+ log.Infof("%s - \"%s %s\" %d", r.RemoteAddr, r.Method, r.URL, status)
|
|
| 86 |
+} |
|
| 87 |
+ |
|
| 88 |
+// readRequestBlob takes a JSON-blob-encoded response body in the form |
|
| 89 |
+// map[string]string and returns it, the list of keywords presented, |
|
| 90 |
+// and any error that occurred. |
|
| 91 |
+func readRequestBlob(r *http.Request) (map[string]string, error) {
|
|
| 92 |
+ var blob map[string]string |
|
| 93 |
+ |
|
| 94 |
+ body, err := ioutil.ReadAll(r.Body) |
|
| 95 |
+ if err != nil {
|
|
| 96 |
+ return nil, err |
|
| 97 |
+ } |
|
| 98 |
+ r.Body.Close() |
|
| 99 |
+ |
|
| 100 |
+ err = json.Unmarshal(body, &blob) |
|
| 101 |
+ if err != nil {
|
|
| 102 |
+ return nil, err |
|
| 103 |
+ } |
|
| 104 |
+ return blob, nil |
|
| 105 |
+} |
|
| 106 |
+ |
|
| 107 |
+// ProcessRequestOneOf reads a JSON blob for the request and makes |
|
| 108 |
+// sure it contains one of a set of keywords. For example, a request |
|
| 109 |
+// might have the ('foo' && 'bar') keys, OR it might have the 'baz'
|
|
| 110 |
+// key. In either case, we want to accept the request; however, if |
|
| 111 |
+// none of these sets shows up, the request is a bad request, and it |
|
| 112 |
+// should be returned. |
|
| 113 |
+func ProcessRequestOneOf(r *http.Request, keywordSets [][]string) (map[string]string, []string, error) {
|
|
| 114 |
+ blob, err := readRequestBlob(r) |
|
| 115 |
+ if err != nil {
|
|
| 116 |
+ return nil, nil, err |
|
| 117 |
+ } |
|
| 118 |
+ |
|
| 119 |
+ var matched []string |
|
| 120 |
+ for _, set := range keywordSets {
|
|
| 121 |
+ if matchKeywords(blob, set) {
|
|
| 122 |
+ if matched != nil {
|
|
| 123 |
+ return nil, nil, errors.NewBadRequestString("mismatched parameters")
|
|
| 124 |
+ } |
|
| 125 |
+ matched = set |
|
| 126 |
+ } |
|
| 127 |
+ } |
|
| 128 |
+ if matched == nil {
|
|
| 129 |
+ return nil, nil, errors.NewBadRequestString("no valid parameter sets found")
|
|
| 130 |
+ } |
|
| 131 |
+ return blob, matched, nil |
|
| 132 |
+} |
|
| 133 |
+ |
|
| 134 |
+// ProcessRequestFirstMatchOf reads a JSON blob for the request and returns |
|
| 135 |
+// the first match of a set of keywords. For example, a request |
|
| 136 |
+// might have one of the following combinations: (foo=1, bar=2), (foo=1), and (bar=2) |
|
| 137 |
+// By giving a specific ordering of those combinations, we could decide how to accept |
|
| 138 |
+// the request. |
|
| 139 |
+func ProcessRequestFirstMatchOf(r *http.Request, keywordSets [][]string) (map[string]string, []string, error) {
|
|
| 140 |
+ blob, err := readRequestBlob(r) |
|
| 141 |
+ if err != nil {
|
|
| 142 |
+ return nil, nil, err |
|
| 143 |
+ } |
|
| 144 |
+ |
|
| 145 |
+ for _, set := range keywordSets {
|
|
| 146 |
+ if matchKeywords(blob, set) {
|
|
| 147 |
+ return blob, set, nil |
|
| 148 |
+ } |
|
| 149 |
+ } |
|
| 150 |
+ return nil, nil, errors.NewBadRequestString("no valid parameter sets found")
|
|
| 151 |
+} |
|
| 152 |
+ |
|
| 153 |
+func matchKeywords(blob map[string]string, keywords []string) bool {
|
|
| 154 |
+ for _, keyword := range keywords {
|
|
| 155 |
+ if _, ok := blob[keyword]; !ok {
|
|
| 156 |
+ return false |
|
| 157 |
+ } |
|
| 158 |
+ } |
|
| 159 |
+ return true |
|
| 160 |
+} |
|
| 161 |
+ |
|
| 162 |
+// ResponseMessage implements the standard for response errors and |
|
| 163 |
+// messages. A message has a code and a string message. |
|
| 164 |
+type ResponseMessage struct {
|
|
| 165 |
+ Code int `json:"code"` |
|
| 166 |
+ Message string `json:"message"` |
|
| 167 |
+} |
|
| 168 |
+ |
|
| 169 |
+// Response implements the CloudFlare standard for API |
|
| 170 |
+// responses. |
|
| 171 |
+type Response struct {
|
|
| 172 |
+ Success bool `json:"success"` |
|
| 173 |
+ Result interface{} `json:"result"`
|
|
| 174 |
+ Errors []ResponseMessage `json:"errors"` |
|
| 175 |
+ Messages []ResponseMessage `json:"messages"` |
|
| 176 |
+} |
|
| 177 |
+ |
|
| 178 |
+// NewSuccessResponse is a shortcut for creating new successul API |
|
| 179 |
+// responses. |
|
| 180 |
+func NewSuccessResponse(result interface{}) Response {
|
|
| 181 |
+ return Response{
|
|
| 182 |
+ Success: true, |
|
| 183 |
+ Result: result, |
|
| 184 |
+ Errors: []ResponseMessage{},
|
|
| 185 |
+ Messages: []ResponseMessage{},
|
|
| 186 |
+ } |
|
| 187 |
+} |
|
| 188 |
+ |
|
| 189 |
+// NewSuccessResponseWithMessage is a shortcut for creating new successul API |
|
| 190 |
+// responses that includes a message. |
|
| 191 |
+func NewSuccessResponseWithMessage(result interface{}, message string, code int) Response {
|
|
| 192 |
+ return Response{
|
|
| 193 |
+ Success: true, |
|
| 194 |
+ Result: result, |
|
| 195 |
+ Errors: []ResponseMessage{},
|
|
| 196 |
+ Messages: []ResponseMessage{{code, message}},
|
|
| 197 |
+ } |
|
| 198 |
+} |
|
| 199 |
+ |
|
| 200 |
+// NewErrorResponse is a shortcut for creating an error response for a |
|
| 201 |
+// single error. |
|
| 202 |
+func NewErrorResponse(message string, code int) Response {
|
|
| 203 |
+ return Response{
|
|
| 204 |
+ Success: false, |
|
| 205 |
+ Result: nil, |
|
| 206 |
+ Errors: []ResponseMessage{{code, message}},
|
|
| 207 |
+ Messages: []ResponseMessage{},
|
|
| 208 |
+ } |
|
| 209 |
+} |
|
| 210 |
+ |
|
| 211 |
+// SendResponse builds a response from the result, sets the JSON |
|
| 212 |
+// header, and writes to the http.ResponseWriter. |
|
| 213 |
+func SendResponse(w http.ResponseWriter, result interface{}) error {
|
|
| 214 |
+ response := NewSuccessResponse(result) |
|
| 215 |
+ w.Header().Set("Content-Type", "application/json")
|
|
| 216 |
+ enc := json.NewEncoder(w) |
|
| 217 |
+ err := enc.Encode(response) |
|
| 218 |
+ return err |
|
| 219 |
+} |
|
| 220 |
+ |
|
| 221 |
+// SendResponseWithMessage builds a response from the result and the |
|
| 222 |
+// provided message, sets the JSON header, and writes to the |
|
| 223 |
+// http.ResponseWriter. |
|
| 224 |
+func SendResponseWithMessage(w http.ResponseWriter, result interface{}, message string, code int) error {
|
|
| 225 |
+ response := NewSuccessResponseWithMessage(result, message, code) |
|
| 226 |
+ w.Header().Set("Content-Type", "application/json")
|
|
| 227 |
+ enc := json.NewEncoder(w) |
|
| 228 |
+ err := enc.Encode(response) |
|
| 229 |
+ return err |
|
| 230 |
+} |
| ... | ... |
@@ -16,21 +16,26 @@ A database is required for the following: |
| 16 | 16 |
|
| 17 | 17 |
This directory stores [goose](https://bitbucket.org/liamstask/goose/) db migration scripts for various DB backends. |
| 18 | 18 |
Currently supported: |
| 19 |
- - SQLite in sqlite |
|
| 19 |
+ - MySQL in mysql |
|
| 20 | 20 |
- PostgreSQL in pg |
| 21 |
+ - SQLite in sqlite |
|
| 21 | 22 |
|
| 22 | 23 |
### Get goose |
| 23 | 24 |
|
| 24 |
- go get https://bitbucket.org/liamstask/goose/ |
|
| 25 |
+ go get bitbucket.org/liamstask/goose/cmd/goose |
|
| 25 | 26 |
|
| 26 |
-### Use goose to start and terminate a SQLite DB |
|
| 27 |
-To start a SQLite DB using goose: |
|
| 27 |
+### Use goose to start and terminate a MySQL DB |
|
| 28 |
+To start a MySQL using goose: |
|
| 28 | 29 |
|
| 29 |
- goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite up' |
|
| 30 |
+ goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql up |
|
| 30 | 31 |
|
| 31 |
-To tear down a SQLite DB using goose |
|
| 32 |
+To tear down a MySQL DB using goose |
|
| 32 | 33 |
|
| 33 |
- goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite down |
|
| 34 |
+ goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql down |
|
| 35 |
+ |
|
| 36 |
+Note: the administration of MySQL DB is not included. We assume |
|
| 37 |
+the databases being connected to are already created and access control |
|
| 38 |
+is properly handled. |
|
| 34 | 39 |
|
| 35 | 40 |
### Use goose to start and terminate a PostgreSQL DB |
| 36 | 41 |
To start a PostgreSQL using goose: |
| ... | ... |
@@ -43,7 +48,16 @@ To tear down a PostgreSQL DB using goose |
| 43 | 43 |
|
| 44 | 44 |
Note: the administration of PostgreSQL DB is not included. We assume |
| 45 | 45 |
the databases being connected to are already created and access control |
| 46 |
-are properly handled. |
|
| 46 |
+is properly handled. |
|
| 47 |
+ |
|
| 48 |
+### Use goose to start and terminate a SQLite DB |
|
| 49 |
+To start a SQLite DB using goose: |
|
| 50 |
+ |
|
| 51 |
+ goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite up |
|
| 52 |
+ |
|
| 53 |
+To tear down a SQLite DB using goose |
|
| 54 |
+ |
|
| 55 |
+ goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite down |
|
| 47 | 56 |
|
| 48 | 57 |
## CFSSL Configuration |
| 49 | 58 |
|
| ... | ... |
@@ -55,4 +69,3 @@ JSON dictionary: |
| 55 | 55 |
or |
| 56 | 56 |
|
| 57 | 57 |
{"driver":"postgres","data_source":"postgres://user:password@host/db"}
|
| 58 |
- |
| ... | ... |
@@ -9,6 +9,7 @@ import ( |
| 9 | 9 |
"crypto/rsa" |
| 10 | 10 |
"crypto/x509" |
| 11 | 11 |
"crypto/x509/pkix" |
| 12 |
+ "encoding/asn1" |
|
| 12 | 13 |
"encoding/pem" |
| 13 | 14 |
"errors" |
| 14 | 15 |
"net" |
| ... | ... |
@@ -129,8 +130,9 @@ func (kr *BasicKeyRequest) SigAlgo() x509.SignatureAlgorithm {
|
| 129 | 129 |
|
| 130 | 130 |
// CAConfig is a section used in the requests initialising a new CA. |
| 131 | 131 |
type CAConfig struct {
|
| 132 |
- PathLength int `json:"pathlen"` |
|
| 133 |
- Expiry string `json:"expiry"` |
|
| 132 |
+ PathLength int `json:"pathlen"` |
|
| 133 |
+ PathLenZero bool `json:"pathlenzero"` |
|
| 134 |
+ Expiry string `json:"expiry"` |
|
| 134 | 135 |
} |
| 135 | 136 |
|
| 136 | 137 |
// A CertificateRequest encapsulates the API interface to the |
| ... | ... |
@@ -175,6 +177,12 @@ func (cr *CertificateRequest) Name() pkix.Name {
|
| 175 | 175 |
return name |
| 176 | 176 |
} |
| 177 | 177 |
|
| 178 |
+// BasicConstraints CSR information RFC 5280, 4.2.1.9 |
|
| 179 |
+type BasicConstraints struct {
|
|
| 180 |
+ IsCA bool `asn1:"optional"` |
|
| 181 |
+ MaxPathLen int `asn1:"optional,default:-1"` |
|
| 182 |
+} |
|
| 183 |
+ |
|
| 178 | 184 |
// ParseRequest takes a certificate request and generates a key and |
| 179 | 185 |
// CSR from it. It does no validation -- caveat emptor. It will, |
| 180 | 186 |
// however, fail if the key request is not valid (i.e., an unsupported |
| ... | ... |
@@ -217,34 +225,11 @@ func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) {
|
| 217 | 217 |
panic("Generate should have failed to produce a valid key.")
|
| 218 | 218 |
} |
| 219 | 219 |
|
| 220 |
- var tpl = x509.CertificateRequest{
|
|
| 221 |
- Subject: req.Name(), |
|
| 222 |
- SignatureAlgorithm: req.KeyRequest.SigAlgo(), |
|
| 223 |
- } |
|
| 224 |
- |
|
| 225 |
- for i := range req.Hosts {
|
|
| 226 |
- if ip := net.ParseIP(req.Hosts[i]); ip != nil {
|
|
| 227 |
- tpl.IPAddresses = append(tpl.IPAddresses, ip) |
|
| 228 |
- } else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil {
|
|
| 229 |
- tpl.EmailAddresses = append(tpl.EmailAddresses, req.Hosts[i]) |
|
| 230 |
- } else {
|
|
| 231 |
- tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i]) |
|
| 232 |
- } |
|
| 233 |
- } |
|
| 234 |
- |
|
| 235 |
- csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv) |
|
| 220 |
+ csr, err = Generate(priv.(crypto.Signer), req) |
|
| 236 | 221 |
if err != nil {
|
| 237 | 222 |
log.Errorf("failed to generate a CSR: %v", err)
|
| 238 | 223 |
err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err) |
| 239 |
- return |
|
| 240 |
- } |
|
| 241 |
- block := pem.Block{
|
|
| 242 |
- Type: "CERTIFICATE REQUEST", |
|
| 243 |
- Bytes: csr, |
|
| 244 | 224 |
} |
| 245 |
- |
|
| 246 |
- log.Info("encoded CSR")
|
|
| 247 |
- csr = pem.EncodeToMemory(&block) |
|
| 248 | 225 |
return |
| 249 | 226 |
} |
| 250 | 227 |
|
| ... | ... |
@@ -265,6 +250,7 @@ func ExtractCertificateRequest(cert *x509.Certificate) *CertificateRequest {
|
| 265 | 265 |
// issue date and expiry date. |
| 266 | 266 |
req.CA.Expiry = cert.NotAfter.Sub(cert.NotBefore).String() |
| 267 | 267 |
req.CA.PathLength = cert.MaxPathLen |
| 268 |
+ req.CA.PathLenZero = cert.MaxPathLenZero |
|
| 268 | 269 |
} |
| 269 | 270 |
|
| 270 | 271 |
return req |
| ... | ... |
@@ -377,7 +363,7 @@ func Regenerate(priv crypto.Signer, csr []byte) ([]byte, error) {
|
| 377 | 377 |
// Generate creates a new CSR from a CertificateRequest structure and |
| 378 | 378 |
// an existing key. The KeyRequest field is ignored. |
| 379 | 379 |
func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) {
|
| 380 |
- sigAlgo := helpers.SignerAlgo(priv, crypto.SHA256) |
|
| 380 |
+ sigAlgo := helpers.SignerAlgo(priv) |
|
| 381 | 381 |
if sigAlgo == x509.UnknownSignatureAlgorithm {
|
| 382 | 382 |
return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable) |
| 383 | 383 |
} |
| ... | ... |
@@ -397,6 +383,14 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro |
| 397 | 397 |
} |
| 398 | 398 |
} |
| 399 | 399 |
|
| 400 |
+ if req.CA != nil {
|
|
| 401 |
+ err = appendCAInfoToCSR(req.CA, &tpl) |
|
| 402 |
+ if err != nil {
|
|
| 403 |
+ err = cferr.Wrap(cferr.CSRError, cferr.GenerationFailed, err) |
|
| 404 |
+ return |
|
| 405 |
+ } |
|
| 406 |
+ } |
|
| 407 |
+ |
|
| 400 | 408 |
csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv) |
| 401 | 409 |
if err != nil {
|
| 402 | 410 |
log.Errorf("failed to generate a CSR: %v", err)
|
| ... | ... |
@@ -412,3 +406,26 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro |
| 412 | 412 |
csr = pem.EncodeToMemory(&block) |
| 413 | 413 |
return |
| 414 | 414 |
} |
| 415 |
+ |
|
| 416 |
+// appendCAInfoToCSR appends CAConfig BasicConstraint extension to a CSR |
|
| 417 |
+func appendCAInfoToCSR(reqConf *CAConfig, csr *x509.CertificateRequest) error {
|
|
| 418 |
+ pathlen := reqConf.PathLength |
|
| 419 |
+ if pathlen == 0 && !reqConf.PathLenZero {
|
|
| 420 |
+ pathlen = -1 |
|
| 421 |
+ } |
|
| 422 |
+ val, err := asn1.Marshal(BasicConstraints{true, pathlen})
|
|
| 423 |
+ |
|
| 424 |
+ if err != nil {
|
|
| 425 |
+ return err |
|
| 426 |
+ } |
|
| 427 |
+ |
|
| 428 |
+ csr.ExtraExtensions = []pkix.Extension{
|
|
| 429 |
+ {
|
|
| 430 |
+ Id: asn1.ObjectIdentifier{2, 5, 29, 19},
|
|
| 431 |
+ Value: val, |
|
| 432 |
+ Critical: true, |
|
| 433 |
+ }, |
|
| 434 |
+ } |
|
| 435 |
+ |
|
| 436 |
+ return nil |
|
| 437 |
+} |
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"bytes" |
| 7 | 7 |
"crypto" |
| 8 | 8 |
"crypto/ecdsa" |
| 9 |
+ "crypto/elliptic" |
|
| 9 | 10 |
"crypto/rsa" |
| 10 | 11 |
"crypto/x509" |
| 11 | 12 |
"encoding/asn1" |
| ... | ... |
@@ -410,7 +411,7 @@ func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error) |
| 410 | 410 |
in = bytes.TrimSpace(in) |
| 411 | 411 |
p, rest := pem.Decode(in) |
| 412 | 412 |
if p != nil {
|
| 413 |
- if p.Type != "CERTIFICATE REQUEST" {
|
|
| 413 |
+ if p.Type != "NEW CERTIFICATE REQUEST" && p.Type != "CERTIFICATE REQUEST" {
|
|
| 414 | 414 |
return nil, rest, cferr.New(cferr.CSRError, cferr.BadRequest) |
| 415 | 415 |
} |
| 416 | 416 |
|
| ... | ... |
@@ -446,28 +447,28 @@ func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) {
|
| 446 | 446 |
return csrObject, nil |
| 447 | 447 |
} |
| 448 | 448 |
|
| 449 |
-// SignerAlgo returns an X.509 signature algorithm corresponding to |
|
| 450 |
-// the crypto.Hash provided from a crypto.Signer. |
|
| 451 |
-func SignerAlgo(priv crypto.Signer, h crypto.Hash) x509.SignatureAlgorithm {
|
|
| 452 |
- switch priv.Public().(type) {
|
|
| 449 |
+// SignerAlgo returns an X.509 signature algorithm from a crypto.Signer. |
|
| 450 |
+func SignerAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
|
|
| 451 |
+ switch pub := priv.Public().(type) {
|
|
| 453 | 452 |
case *rsa.PublicKey: |
| 454 |
- switch h {
|
|
| 455 |
- case crypto.SHA512: |
|
| 453 |
+ bitLength := pub.N.BitLen() |
|
| 454 |
+ switch {
|
|
| 455 |
+ case bitLength >= 4096: |
|
| 456 | 456 |
return x509.SHA512WithRSA |
| 457 |
- case crypto.SHA384: |
|
| 457 |
+ case bitLength >= 3072: |
|
| 458 | 458 |
return x509.SHA384WithRSA |
| 459 |
- case crypto.SHA256: |
|
| 459 |
+ case bitLength >= 2048: |
|
| 460 | 460 |
return x509.SHA256WithRSA |
| 461 | 461 |
default: |
| 462 | 462 |
return x509.SHA1WithRSA |
| 463 | 463 |
} |
| 464 | 464 |
case *ecdsa.PublicKey: |
| 465 |
- switch h {
|
|
| 466 |
- case crypto.SHA512: |
|
| 465 |
+ switch pub.Curve {
|
|
| 466 |
+ case elliptic.P521(): |
|
| 467 | 467 |
return x509.ECDSAWithSHA512 |
| 468 |
- case crypto.SHA384: |
|
| 468 |
+ case elliptic.P384(): |
|
| 469 | 469 |
return x509.ECDSAWithSHA384 |
| 470 |
- case crypto.SHA256: |
|
| 470 |
+ case elliptic.P256(): |
|
| 471 | 471 |
return x509.ECDSAWithSHA256 |
| 472 | 472 |
default: |
| 473 | 473 |
return x509.ECDSAWithSHA1 |
| ... | ... |
@@ -5,14 +5,10 @@ package initca |
| 5 | 5 |
import ( |
| 6 | 6 |
"crypto" |
| 7 | 7 |
"crypto/ecdsa" |
| 8 |
- "crypto/elliptic" |
|
| 9 |
- "crypto/rand" |
|
| 10 | 8 |
"crypto/rsa" |
| 11 | 9 |
"crypto/x509" |
| 12 |
- "encoding/pem" |
|
| 13 | 10 |
"errors" |
| 14 | 11 |
"io/ioutil" |
| 15 |
- "net" |
|
| 16 | 12 |
"time" |
| 17 | 13 |
|
| 18 | 14 |
"github.com/cloudflare/cfssl/config" |
| ... | ... |
@@ -47,14 +43,18 @@ func validator(req *csr.CertificateRequest) error {
|
| 47 | 47 |
|
| 48 | 48 |
// New creates a new root certificate from the certificate request. |
| 49 | 49 |
func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
|
| 50 |
+ policy := CAPolicy() |
|
| 50 | 51 |
if req.CA != nil {
|
| 51 | 52 |
if req.CA.Expiry != "" {
|
| 52 |
- CAPolicy.Default.ExpiryString = req.CA.Expiry |
|
| 53 |
- CAPolicy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry) |
|
| 53 |
+ policy.Default.ExpiryString = req.CA.Expiry |
|
| 54 |
+ policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry) |
|
| 54 | 55 |
} |
| 55 | 56 |
|
| 56 |
- if req.CA.PathLength != 0 {
|
|
| 57 |
- signer.MaxPathLen = req.CA.PathLength |
|
| 57 |
+ signer.MaxPathLen = req.CA.PathLength |
|
| 58 |
+ if req.CA.PathLength != 0 && req.CA.PathLenZero == true {
|
|
| 59 |
+ log.Infof("ignore invalid 'pathlenzero' value")
|
|
| 60 |
+ } else {
|
|
| 61 |
+ signer.MaxPathLenZero = req.CA.PathLenZero |
|
| 58 | 62 |
} |
| 59 | 63 |
} |
| 60 | 64 |
|
| ... | ... |
@@ -77,7 +77,7 @@ func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
|
| 77 | 77 |
log.Errorf("failed to create signer: %v", err)
|
| 78 | 78 |
return |
| 79 | 79 |
} |
| 80 |
- s.SetPolicy(CAPolicy) |
|
| 80 |
+ s.SetPolicy(policy) |
|
| 81 | 81 |
|
| 82 | 82 |
signReq := signer.SignRequest{Hosts: req.Hosts, Request: string(csrPEM)}
|
| 83 | 83 |
cert, err = s.Sign(signReq) |
| ... | ... |
@@ -133,92 +133,35 @@ func RenewFromPEM(caFile, keyFile string) ([]byte, error) {
|
| 133 | 133 |
|
| 134 | 134 |
// NewFromSigner creates a new root certificate from a crypto.Signer. |
| 135 | 135 |
func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) {
|
| 136 |
+ policy := CAPolicy() |
|
| 136 | 137 |
if req.CA != nil {
|
| 137 | 138 |
if req.CA.Expiry != "" {
|
| 138 |
- CAPolicy.Default.ExpiryString = req.CA.Expiry |
|
| 139 |
- CAPolicy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry) |
|
| 139 |
+ policy.Default.ExpiryString = req.CA.Expiry |
|
| 140 |
+ policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry) |
|
| 140 | 141 |
if err != nil {
|
| 141 | 142 |
return nil, nil, err |
| 142 | 143 |
} |
| 143 | 144 |
} |
| 144 | 145 |
|
| 145 |
- if req.CA.PathLength != 0 {
|
|
| 146 |
- signer.MaxPathLen = req.CA.PathLength |
|
| 147 |
- } |
|
| 148 |
- } |
|
| 149 |
- |
|
| 150 |
- var sigAlgo x509.SignatureAlgorithm |
|
| 151 |
- switch pub := priv.Public().(type) {
|
|
| 152 |
- case *rsa.PublicKey: |
|
| 153 |
- bitLength := pub.N.BitLen() |
|
| 154 |
- switch {
|
|
| 155 |
- case bitLength >= 4096: |
|
| 156 |
- sigAlgo = x509.SHA512WithRSA |
|
| 157 |
- case bitLength >= 3072: |
|
| 158 |
- sigAlgo = x509.SHA384WithRSA |
|
| 159 |
- case bitLength >= 2048: |
|
| 160 |
- sigAlgo = x509.SHA256WithRSA |
|
| 161 |
- default: |
|
| 162 |
- sigAlgo = x509.SHA1WithRSA |
|
| 163 |
- } |
|
| 164 |
- case *ecdsa.PublicKey: |
|
| 165 |
- switch pub.Curve {
|
|
| 166 |
- case elliptic.P521(): |
|
| 167 |
- sigAlgo = x509.ECDSAWithSHA512 |
|
| 168 |
- case elliptic.P384(): |
|
| 169 |
- sigAlgo = x509.ECDSAWithSHA384 |
|
| 170 |
- case elliptic.P256(): |
|
| 171 |
- sigAlgo = x509.ECDSAWithSHA256 |
|
| 172 |
- default: |
|
| 173 |
- sigAlgo = x509.ECDSAWithSHA1 |
|
| 174 |
- } |
|
| 175 |
- default: |
|
| 176 |
- sigAlgo = x509.UnknownSignatureAlgorithm |
|
| 177 |
- } |
|
| 178 |
- |
|
| 179 |
- var tpl = x509.CertificateRequest{
|
|
| 180 |
- Subject: req.Name(), |
|
| 181 |
- SignatureAlgorithm: sigAlgo, |
|
| 182 |
- } |
|
| 183 |
- |
|
| 184 |
- for i := range req.Hosts {
|
|
| 185 |
- if ip := net.ParseIP(req.Hosts[i]); ip != nil {
|
|
| 186 |
- tpl.IPAddresses = append(tpl.IPAddresses, ip) |
|
| 146 |
+ signer.MaxPathLen = req.CA.PathLength |
|
| 147 |
+ if req.CA.PathLength != 0 && req.CA.PathLenZero == true {
|
|
| 148 |
+ log.Infof("ignore invalid 'pathlenzero' value")
|
|
| 187 | 149 |
} else {
|
| 188 |
- tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i]) |
|
| 150 |
+ signer.MaxPathLenZero = req.CA.PathLenZero |
|
| 189 | 151 |
} |
| 190 | 152 |
} |
| 191 | 153 |
|
| 192 |
- return signWithCSR(&tpl, priv) |
|
| 193 |
-} |
|
| 194 |
- |
|
| 195 |
-// signWithCSR creates a new root certificate from signing a X509.CertificateRequest |
|
| 196 |
-// by a crypto.Signer. |
|
| 197 |
-func signWithCSR(tpl *x509.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) {
|
|
| 198 |
- csrPEM, err = x509.CreateCertificateRequest(rand.Reader, tpl, priv) |
|
| 154 |
+ csrPEM, err = csr.Generate(priv, req) |
|
| 199 | 155 |
if err != nil {
|
| 200 |
- log.Errorf("failed to generate a CSR: %v", err)
|
|
| 201 |
- // The use of CertificateError was a matter of some |
|
| 202 |
- // debate; it is the one edge case in which a new |
|
| 203 |
- // error category specifically for CSRs might be |
|
| 204 |
- // useful, but it was deemed that one edge case did |
|
| 205 |
- // not a new category justify. |
|
| 206 |
- err = cferr.Wrap(cferr.CertificateError, cferr.BadRequest, err) |
|
| 207 |
- return |
|
| 208 |
- } |
|
| 209 |
- |
|
| 210 |
- p := &pem.Block{
|
|
| 211 |
- Type: "CERTIFICATE REQUEST", |
|
| 212 |
- Bytes: csrPEM, |
|
| 156 |
+ return nil, nil, err |
|
| 213 | 157 |
} |
| 214 |
- csrPEM = pem.EncodeToMemory(p) |
|
| 215 | 158 |
|
| 216 | 159 |
s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), nil) |
| 217 | 160 |
if err != nil {
|
| 218 | 161 |
log.Errorf("failed to create signer: %v", err)
|
| 219 | 162 |
return |
| 220 | 163 |
} |
| 221 |
- s.SetPolicy(CAPolicy) |
|
| 164 |
+ s.SetPolicy(policy) |
|
| 222 | 165 |
|
| 223 | 166 |
signReq := signer.SignRequest{Request: string(csrPEM)}
|
| 224 | 167 |
cert, err = s.Sign(signReq) |
| ... | ... |
@@ -268,11 +211,13 @@ func RenewFromSigner(ca *x509.Certificate, priv crypto.Signer) ([]byte, error) {
|
| 268 | 268 |
} |
| 269 | 269 |
|
| 270 | 270 |
// CAPolicy contains the CA issuing policy as default policy. |
| 271 |
-var CAPolicy = &config.Signing{
|
|
| 272 |
- Default: &config.SigningProfile{
|
|
| 273 |
- Usage: []string{"cert sign", "crl sign"},
|
|
| 274 |
- ExpiryString: "43800h", |
|
| 275 |
- Expiry: 5 * helpers.OneYear, |
|
| 276 |
- CA: true, |
|
| 277 |
- }, |
|
| 271 |
+var CAPolicy = func() *config.Signing {
|
|
| 272 |
+ return &config.Signing{
|
|
| 273 |
+ Default: &config.SigningProfile{
|
|
| 274 |
+ Usage: []string{"cert sign", "crl sign"},
|
|
| 275 |
+ ExpiryString: "43800h", |
|
| 276 |
+ Expiry: 5 * helpers.OneYear, |
|
| 277 |
+ CA: true, |
|
| 278 |
+ }, |
|
| 279 |
+ } |
|
| 278 | 280 |
} |
| ... | ... |
@@ -45,12 +45,12 @@ var Level = LevelInfo |
| 45 | 45 |
// |
| 46 | 46 |
// SyslogWriter is satisfied by *syslog.Writer. |
| 47 | 47 |
type SyslogWriter interface {
|
| 48 |
- Debug(string) error |
|
| 49 |
- Info(string) error |
|
| 50 |
- Warning(string) error |
|
| 51 |
- Err(string) error |
|
| 52 |
- Crit(string) error |
|
| 53 |
- Emerg(string) error |
|
| 48 |
+ Debug(string) |
|
| 49 |
+ Info(string) |
|
| 50 |
+ Warning(string) |
|
| 51 |
+ Err(string) |
|
| 52 |
+ Crit(string) |
|
| 53 |
+ Emerg(string) |
|
| 54 | 54 |
} |
| 55 | 55 |
|
| 56 | 56 |
// syslogWriter stores the SetLogger() parameter. |
| ... | ... |
@@ -73,23 +73,19 @@ func init() {
|
| 73 | 73 |
func print(l int, msg string) {
|
| 74 | 74 |
if l >= Level {
|
| 75 | 75 |
if syslogWriter != nil {
|
| 76 |
- var err error |
|
| 77 | 76 |
switch l {
|
| 78 | 77 |
case LevelDebug: |
| 79 |
- err = syslogWriter.Debug(msg) |
|
| 78 |
+ syslogWriter.Debug(msg) |
|
| 80 | 79 |
case LevelInfo: |
| 81 |
- err = syslogWriter.Info(msg) |
|
| 80 |
+ syslogWriter.Info(msg) |
|
| 82 | 81 |
case LevelWarning: |
| 83 |
- err = syslogWriter.Warning(msg) |
|
| 82 |
+ syslogWriter.Warning(msg) |
|
| 84 | 83 |
case LevelError: |
| 85 |
- err = syslogWriter.Err(msg) |
|
| 84 |
+ syslogWriter.Err(msg) |
|
| 86 | 85 |
case LevelCritical: |
| 87 |
- err = syslogWriter.Crit(msg) |
|
| 86 |
+ syslogWriter.Crit(msg) |
|
| 88 | 87 |
case LevelFatal: |
| 89 |
- err = syslogWriter.Emerg(msg) |
|
| 90 |
- } |
|
| 91 |
- if err != nil {
|
|
| 92 |
- log.Printf("Unable to write syslog: %v for msg: %s\n", err, msg)
|
|
| 88 |
+ syslogWriter.Emerg(msg) |
|
| 93 | 89 |
} |
| 94 | 90 |
} else {
|
| 95 | 91 |
log.Printf("[%s] %s", levelPrefix[l], msg)
|
| ... | ... |
@@ -96,7 +96,11 @@ func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signe |
| 96 | 96 |
} |
| 97 | 97 |
|
| 98 | 98 |
func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile) (cert []byte, err error) {
|
| 99 |
+ var distPoints = template.CRLDistributionPoints |
|
| 99 | 100 |
err = signer.FillTemplate(template, s.policy.Default, profile) |
| 101 |
+ if distPoints != nil && len(distPoints) > 0 {
|
|
| 102 |
+ template.CRLDistributionPoints = distPoints |
|
| 103 |
+ } |
|
| 100 | 104 |
if err != nil {
|
| 101 | 105 |
return |
| 102 | 106 |
} |
| ... | ... |
@@ -111,9 +115,7 @@ func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile |
| 111 | 111 |
template.EmailAddresses = nil |
| 112 | 112 |
s.ca = template |
| 113 | 113 |
initRoot = true |
| 114 |
- template.MaxPathLen = signer.MaxPathLen |
|
| 115 | 114 |
} else if template.IsCA {
|
| 116 |
- template.MaxPathLen = 1 |
|
| 117 | 115 |
template.DNSNames = nil |
| 118 | 116 |
template.EmailAddresses = nil |
| 119 | 117 |
} |
| ... | ... |
@@ -203,7 +205,7 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
|
| 203 | 203 |
return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed) |
| 204 | 204 |
} |
| 205 | 205 |
|
| 206 |
- if block.Type != "CERTIFICATE REQUEST" {
|
|
| 206 |
+ if block.Type != "NEW CERTIFICATE REQUEST" && block.Type != "CERTIFICATE REQUEST" {
|
|
| 207 | 207 |
return nil, cferr.Wrap(cferr.CSRError, |
| 208 | 208 |
cferr.BadRequest, errors.New("not a certificate or csr"))
|
| 209 | 209 |
} |
| ... | ... |
@@ -243,6 +245,26 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
|
| 243 | 243 |
} |
| 244 | 244 |
} |
| 245 | 245 |
|
| 246 |
+ if req.CRLOverride != "" {
|
|
| 247 |
+ safeTemplate.CRLDistributionPoints = []string{req.CRLOverride}
|
|
| 248 |
+ } |
|
| 249 |
+ |
|
| 250 |
+ if safeTemplate.IsCA {
|
|
| 251 |
+ if !profile.CA {
|
|
| 252 |
+ return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest) |
|
| 253 |
+ } |
|
| 254 |
+ |
|
| 255 |
+ if s.ca != nil && s.ca.MaxPathLen > 0 {
|
|
| 256 |
+ if safeTemplate.MaxPathLen >= s.ca.MaxPathLen {
|
|
| 257 |
+ // do not sign a cert with pathlen > current |
|
| 258 |
+ return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest) |
|
| 259 |
+ } |
|
| 260 |
+ } else if s.ca != nil && s.ca.MaxPathLen == 0 && s.ca.MaxPathLenZero {
|
|
| 261 |
+ // signer has pathlen of 0, do not sign more intermediate CAs |
|
| 262 |
+ return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest) |
|
| 263 |
+ } |
|
| 264 |
+ } |
|
| 265 |
+ |
|
| 246 | 266 |
OverrideHosts(&safeTemplate, req.Hosts) |
| 247 | 267 |
safeTemplate.Subject = PopulateSubjectFromCSR(req.Subject, safeTemplate.Subject) |
| 248 | 268 |
|
| ... | ... |
@@ -26,6 +26,9 @@ import ( |
| 26 | 26 |
// MaxPathLen is the default path length for a new CA certificate. |
| 27 | 27 |
var MaxPathLen = 2 |
| 28 | 28 |
|
| 29 |
+// MaxPathLenZero indicates whether a new CA certificate has pathlen=0 |
|
| 30 |
+var MaxPathLenZero = false |
|
| 31 |
+ |
|
| 29 | 32 |
// Subject contains the information that should be used to override the |
| 30 | 33 |
// subject information when signing a certificate. |
| 31 | 34 |
type Subject struct {
|
| ... | ... |
@@ -50,13 +53,14 @@ type Extension struct {
|
| 50 | 50 |
// Extensions requested in the CSR are ignored, except for those processed by |
| 51 | 51 |
// ParseCertificateRequest (mainly subjectAltName). |
| 52 | 52 |
type SignRequest struct {
|
| 53 |
- Hosts []string `json:"hosts"` |
|
| 54 |
- Request string `json:"certificate_request"` |
|
| 55 |
- Subject *Subject `json:"subject,omitempty"` |
|
| 56 |
- Profile string `json:"profile"` |
|
| 57 |
- Label string `json:"label"` |
|
| 58 |
- Serial *big.Int `json:"serial,omitempty"` |
|
| 59 |
- Extensions []Extension `json:"extensions,omitempty"` |
|
| 53 |
+ Hosts []string `json:"hosts"` |
|
| 54 |
+ Request string `json:"certificate_request"` |
|
| 55 |
+ Subject *Subject `json:"subject,omitempty"` |
|
| 56 |
+ Profile string `json:"profile"` |
|
| 57 |
+ CRLOverride string `json:"crl_override"` |
|
| 58 |
+ Label string `json:"label"` |
|
| 59 |
+ Serial *big.Int `json:"serial,omitempty"` |
|
| 60 |
+ Extensions []Extension `json:"extensions,omitempty"` |
|
| 60 | 61 |
} |
| 61 | 62 |
|
| 62 | 63 |
// appendIf appends to a if s is not an empty string. |
| ... | ... |
@@ -157,26 +161,46 @@ func DefaultSigAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
|
| 157 | 157 |
// ParseCertificateRequest takes an incoming certificate request and |
| 158 | 158 |
// builds a certificate template from it. |
| 159 | 159 |
func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certificate, err error) {
|
| 160 |
- csr, err := x509.ParseCertificateRequest(csrBytes) |
|
| 160 |
+ csrv, err := x509.ParseCertificateRequest(csrBytes) |
|
| 161 | 161 |
if err != nil {
|
| 162 | 162 |
err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err) |
| 163 | 163 |
return |
| 164 | 164 |
} |
| 165 | 165 |
|
| 166 |
- err = helpers.CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature) |
|
| 166 |
+ err = helpers.CheckSignature(csrv, csrv.SignatureAlgorithm, csrv.RawTBSCertificateRequest, csrv.Signature) |
|
| 167 | 167 |
if err != nil {
|
| 168 | 168 |
err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err) |
| 169 | 169 |
return |
| 170 | 170 |
} |
| 171 | 171 |
|
| 172 | 172 |
template = &x509.Certificate{
|
| 173 |
- Subject: csr.Subject, |
|
| 174 |
- PublicKeyAlgorithm: csr.PublicKeyAlgorithm, |
|
| 175 |
- PublicKey: csr.PublicKey, |
|
| 173 |
+ Subject: csrv.Subject, |
|
| 174 |
+ PublicKeyAlgorithm: csrv.PublicKeyAlgorithm, |
|
| 175 |
+ PublicKey: csrv.PublicKey, |
|
| 176 | 176 |
SignatureAlgorithm: s.SigAlgo(), |
| 177 |
- DNSNames: csr.DNSNames, |
|
| 178 |
- IPAddresses: csr.IPAddresses, |
|
| 179 |
- EmailAddresses: csr.EmailAddresses, |
|
| 177 |
+ DNSNames: csrv.DNSNames, |
|
| 178 |
+ IPAddresses: csrv.IPAddresses, |
|
| 179 |
+ EmailAddresses: csrv.EmailAddresses, |
|
| 180 |
+ } |
|
| 181 |
+ |
|
| 182 |
+ for _, val := range csrv.Extensions {
|
|
| 183 |
+ // Check the CSR for the X.509 BasicConstraints (RFC 5280, 4.2.1.9) |
|
| 184 |
+ // extension and append to template if necessary |
|
| 185 |
+ if val.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) {
|
|
| 186 |
+ var constraints csr.BasicConstraints |
|
| 187 |
+ var rest []byte |
|
| 188 |
+ |
|
| 189 |
+ if rest, err = asn1.Unmarshal(val.Value, &constraints); err != nil {
|
|
| 190 |
+ return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err) |
|
| 191 |
+ } else if len(rest) != 0 {
|
|
| 192 |
+ return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, errors.New("x509: trailing data after X.509 BasicConstraints"))
|
|
| 193 |
+ } |
|
| 194 |
+ |
|
| 195 |
+ template.BasicConstraintsValid = true |
|
| 196 |
+ template.IsCA = constraints.IsCA |
|
| 197 |
+ template.MaxPathLen = constraints.MaxPathLen |
|
| 198 |
+ template.MaxPathLenZero = template.MaxPathLen == 0 |
|
| 199 |
+ } |
|
| 180 | 200 |
} |
| 181 | 201 |
|
| 182 | 202 |
return |
| ... | ... |
@@ -222,6 +246,7 @@ func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.Si |
| 222 | 222 |
notBefore time.Time |
| 223 | 223 |
notAfter time.Time |
| 224 | 224 |
crlURL, ocspURL string |
| 225 |
+ issuerURL = profile.IssuerURL |
|
| 225 | 226 |
) |
| 226 | 227 |
|
| 227 | 228 |
// The third value returned from Usages is a list of unknown key usages. |
| ... | ... |
@@ -229,7 +254,7 @@ func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.Si |
| 229 | 229 |
// here. |
| 230 | 230 |
ku, eku, _ = profile.Usages() |
| 231 | 231 |
if profile.IssuerURL == nil {
|
| 232 |
- profile.IssuerURL = defaultProfile.IssuerURL |
|
| 232 |
+ issuerURL = defaultProfile.IssuerURL |
|
| 233 | 233 |
} |
| 234 | 234 |
|
| 235 | 235 |
if ku == 0 && len(eku) == 0 {
|
| ... | ... |
@@ -279,8 +304,8 @@ func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.Si |
| 279 | 279 |
template.CRLDistributionPoints = []string{crlURL}
|
| 280 | 280 |
} |
| 281 | 281 |
|
| 282 |
- if len(profile.IssuerURL) != 0 {
|
|
| 283 |
- template.IssuingCertificateURL = profile.IssuerURL |
|
| 282 |
+ if len(issuerURL) != 0 {
|
|
| 283 |
+ template.IssuingCertificateURL = issuerURL |
|
| 284 | 284 |
} |
| 285 | 285 |
if len(profile.Policies) != 0 {
|
| 286 | 286 |
err = addPolicies(template, profile.Policies) |
| ... | ... |
@@ -27,7 +27,7 @@ func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (ty |
| 27 | 27 |
return response, err |
| 28 | 28 |
} |
| 29 | 29 |
|
| 30 |
-// ContainerInspectWithRaw returns the container information and it's raw representation. |
|
| 30 |
+// ContainerInspectWithRaw returns the container information and its raw representation. |
|
| 31 | 31 |
func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID string, getSize bool) (types.ContainerJSON, []byte, error) {
|
| 32 | 32 |
query := url.Values{}
|
| 33 | 33 |
if getSize {
|
| ... | ... |
@@ -131,6 +131,11 @@ func (e nodeNotFoundError) Error() string {
|
| 131 | 131 |
return fmt.Sprintf("Error: No such node: %s", e.nodeID)
|
| 132 | 132 |
} |
| 133 | 133 |
|
| 134 |
+// NoFound indicates that this error type is of NotFound |
|
| 135 |
+func (e nodeNotFoundError) NotFound() bool {
|
|
| 136 |
+ return true |
|
| 137 |
+} |
|
| 138 |
+ |
|
| 134 | 139 |
// IsErrNodeNotFound returns true if the error is caused |
| 135 | 140 |
// when a node is not found. |
| 136 | 141 |
func IsErrNodeNotFound(err error) bool {
|
| ... | ... |
@@ -148,6 +153,11 @@ func (e serviceNotFoundError) Error() string {
|
| 148 | 148 |
return fmt.Sprintf("Error: No such service: %s", e.serviceID)
|
| 149 | 149 |
} |
| 150 | 150 |
|
| 151 |
+// NoFound indicates that this error type is of NotFound |
|
| 152 |
+func (e serviceNotFoundError) NotFound() bool {
|
|
| 153 |
+ return true |
|
| 154 |
+} |
|
| 155 |
+ |
|
| 151 | 156 |
// IsErrServiceNotFound returns true if the error is caused |
| 152 | 157 |
// when a service is not found. |
| 153 | 158 |
func IsErrServiceNotFound(err error) bool {
|
| ... | ... |
@@ -165,6 +175,11 @@ func (e taskNotFoundError) Error() string {
|
| 165 | 165 |
return fmt.Sprintf("Error: No such task: %s", e.taskID)
|
| 166 | 166 |
} |
| 167 | 167 |
|
| 168 |
+// NoFound indicates that this error type is of NotFound |
|
| 169 |
+func (e taskNotFoundError) NotFound() bool {
|
|
| 170 |
+ return true |
|
| 171 |
+} |
|
| 172 |
+ |
|
| 168 | 173 |
// IsErrTaskNotFound returns true if the error is caused |
| 169 | 174 |
// when a task is not found. |
| 170 | 175 |
func IsErrTaskNotFound(err error) bool {
|
| ... | ... |
@@ -92,7 +92,7 @@ type NetworkAPIClient interface {
|
| 92 | 92 |
|
| 93 | 93 |
// NodeAPIClient defines API client methods for the nodes |
| 94 | 94 |
type NodeAPIClient interface {
|
| 95 |
- NodeInspect(ctx context.Context, nodeID string) (swarm.Node, error) |
|
| 95 |
+ NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error) |
|
| 96 | 96 |
NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) |
| 97 | 97 |
NodeRemove(ctx context.Context, nodeID string) error |
| 98 | 98 |
NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error |
| ... | ... |
@@ -16,7 +16,7 @@ func (cli *Client) NetworkInspect(ctx context.Context, networkID string) (types. |
| 16 | 16 |
return networkResource, err |
| 17 | 17 |
} |
| 18 | 18 |
|
| 19 |
-// NetworkInspectWithRaw returns the information for a specific network configured in the docker host and it's raw representation. |
|
| 19 |
+// NetworkInspectWithRaw returns the information for a specific network configured in the docker host and its raw representation. |
|
| 20 | 20 |
func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string) (types.NetworkResource, []byte, error) {
|
| 21 | 21 |
var networkResource types.NetworkResource |
| 22 | 22 |
resp, err := cli.get(ctx, "/networks/"+networkID, nil, nil) |
| ... | ... |
@@ -1,25 +1,33 @@ |
| 1 | 1 |
package client |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "bytes" |
|
| 4 | 5 |
"encoding/json" |
| 6 |
+ "io/ioutil" |
|
| 5 | 7 |
"net/http" |
| 6 | 8 |
|
| 7 | 9 |
"github.com/docker/engine-api/types/swarm" |
| 8 | 10 |
"golang.org/x/net/context" |
| 9 | 11 |
) |
| 10 | 12 |
|
| 11 |
-// NodeInspect returns the node information. |
|
| 12 |
-func (cli *Client) NodeInspect(ctx context.Context, nodeID string) (swarm.Node, error) {
|
|
| 13 |
+// NodeInspectWithRaw returns the node information. |
|
| 14 |
+func (cli *Client) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error) {
|
|
| 13 | 15 |
serverResp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil) |
| 14 | 16 |
if err != nil {
|
| 15 | 17 |
if serverResp.statusCode == http.StatusNotFound {
|
| 16 |
- return swarm.Node{}, nodeNotFoundError{nodeID}
|
|
| 18 |
+ return swarm.Node{}, nil, nodeNotFoundError{nodeID}
|
|
| 17 | 19 |
} |
| 18 |
- return swarm.Node{}, err
|
|
| 20 |
+ return swarm.Node{}, nil, err
|
|
| 21 |
+ } |
|
| 22 |
+ defer ensureReaderClosed(serverResp) |
|
| 23 |
+ |
|
| 24 |
+ body, err := ioutil.ReadAll(serverResp.body) |
|
| 25 |
+ if err != nil {
|
|
| 26 |
+ return swarm.Node{}, nil, err
|
|
| 19 | 27 |
} |
| 20 | 28 |
|
| 21 | 29 |
var response swarm.Node |
| 22 |
- err = json.NewDecoder(serverResp.body).Decode(&response) |
|
| 23 |
- ensureReaderClosed(serverResp) |
|
| 24 |
- return response, err |
|
| 30 |
+ rdr := bytes.NewReader(body) |
|
| 31 |
+ err = json.NewDecoder(rdr).Decode(&response) |
|
| 32 |
+ return response, body, err |
|
| 25 | 33 |
} |
| ... | ... |
@@ -31,6 +31,7 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types |
| 31 | 31 |
} |
| 32 | 32 |
var privileges types.PluginPrivileges |
| 33 | 33 |
if err := json.NewDecoder(resp.body).Decode(&privileges); err != nil {
|
| 34 |
+ ensureReaderClosed(resp) |
|
| 34 | 35 |
return err |
| 35 | 36 |
} |
| 36 | 37 |
ensureReaderClosed(resp) |
| ... | ... |
@@ -16,7 +16,7 @@ func (cli *Client) VolumeInspect(ctx context.Context, volumeID string) (types.Vo |
| 16 | 16 |
return volume, err |
| 17 | 17 |
} |
| 18 | 18 |
|
| 19 |
-// VolumeInspectWithRaw returns the information about a specific volume in the docker host and it's raw representation |
|
| 19 |
+// VolumeInspectWithRaw returns the information about a specific volume in the docker host and its raw representation |
|
| 20 | 20 |
func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (types.Volume, []byte, error) {
|
| 21 | 21 |
var volume types.Volume |
| 22 | 22 |
resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil) |
| ... | ... |
@@ -54,7 +54,7 @@ const ( |
| 54 | 54 |
MountPropagationSlave MountPropagation = "slave" |
| 55 | 55 |
) |
| 56 | 56 |
|
| 57 |
-// BindOptions define options specific to mounts of type "bind". |
|
| 57 |
+// BindOptions defines options specific to mounts of type "bind". |
|
| 58 | 58 |
type BindOptions struct {
|
| 59 | 59 |
Propagation MountPropagation `json:",omitempty"` |
| 60 | 60 |
} |
| ... | ... |
@@ -15,7 +15,7 @@ type ServiceSpec struct {
|
| 15 | 15 |
Annotations |
| 16 | 16 |
|
| 17 | 17 |
// TaskTemplate defines how the service should construct new tasks when |
| 18 |
- // ochestrating this service. |
|
| 18 |
+ // orchestrating this service. |
|
| 19 | 19 |
TaskTemplate TaskSpec `json:",omitempty"` |
| 20 | 20 |
Mode ServiceMode `json:",omitempty"` |
| 21 | 21 |
UpdateConfig *UpdateConfig `json:",omitempty"` |
| ... | ... |
@@ -32,7 +32,7 @@ type Policy struct {
|
| 32 | 32 |
Secret *string `json:",omitempty"` |
| 33 | 33 |
} |
| 34 | 34 |
|
| 35 |
-// OrchestrationConfig represents ochestration configuration. |
|
| 35 |
+// OrchestrationConfig represents orchestration configuration. |
|
| 36 | 36 |
type OrchestrationConfig struct {
|
| 37 | 37 |
TaskHistoryRetentionLimit int64 `json:",omitempty"` |
| 38 | 38 |
} |
| ... | ... |
@@ -54,6 +54,20 @@ type DispatcherConfig struct {
|
| 54 | 54 |
// CAConfig represents CA configuration. |
| 55 | 55 |
type CAConfig struct {
|
| 56 | 56 |
NodeCertExpiry time.Duration `json:",omitempty"` |
| 57 |
+ ExternalCAs []*ExternalCA `json:",omitempty"` |
|
| 58 |
+} |
|
| 59 |
+ |
|
| 60 |
+// ExternalCAProtocol represents type of external CA. |
|
| 61 |
+type ExternalCAProtocol string |
|
| 62 |
+ |
|
| 63 |
+// ExternalCAProtocolCFSSL CFSSL |
|
| 64 |
+const ExternalCAProtocolCFSSL ExternalCAProtocol = "cfssl" |
|
| 65 |
+ |
|
| 66 |
+// ExternalCA defines external CA to be used by the cluster. |
|
| 67 |
+type ExternalCA struct {
|
|
| 68 |
+ Protocol ExternalCAProtocol |
|
| 69 |
+ URL string |
|
| 70 |
+ Options map[string]string `json:",omitempty"` |
|
| 57 | 71 |
} |
| 58 | 72 |
|
| 59 | 73 |
// InitRequest is the request used to init a swarm. |
| ... | ... |
@@ -504,10 +504,6 @@ type Checkpoint struct {
|
| 504 | 504 |
Name string // Name is the name of the checkpoint |
| 505 | 505 |
} |
| 506 | 506 |
|
| 507 |
-// DefaultRuntimeName is the reserved name/alias used to represent the |
|
| 508 |
-// OCI runtime being shipped with the docker daemon package. |
|
| 509 |
-var DefaultRuntimeName = "default" |
|
| 510 |
- |
|
| 511 | 507 |
// Runtime describes an OCI runtime |
| 512 | 508 |
type Runtime struct {
|
| 513 | 509 |
Path string `json:"path"` |
| ... | ... |
@@ -102,7 +102,7 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error {
|
| 102 | 102 |
deleted = cKey.Key |
| 103 | 103 |
} |
| 104 | 104 |
|
| 105 |
- if cKey.Subsystem == subsysGossip /* subsysIPSec */ {
|
|
| 105 |
+ if cKey.Subsystem == subsysIPSec {
|
|
| 106 | 106 |
drvEnc.Prune = cKey.Key |
| 107 | 107 |
drvEnc.PruneTag = cKey.LamportTime |
| 108 | 108 |
} |
| ... | ... |
@@ -128,7 +128,7 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error {
|
| 128 | 128 |
a.networkDB.SetKey(key.Key) |
| 129 | 129 |
} |
| 130 | 130 |
|
| 131 |
- if key.Subsystem == subsysGossip /*subsysIPSec*/ {
|
|
| 131 |
+ if key.Subsystem == subsysIPSec {
|
|
| 132 | 132 |
drvEnc.Key = key.Key |
| 133 | 133 |
drvEnc.Tag = key.LamportTime |
| 134 | 134 |
} |
| ... | ... |
@@ -138,7 +138,7 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error {
|
| 138 | 138 |
key, tag := c.getPrimaryKeyTag(subsysGossip) |
| 139 | 139 |
a.networkDB.SetPrimaryKey(key) |
| 140 | 140 |
|
| 141 |
- //key, tag = c.getPrimaryKeyTag(subsysIPSec) |
|
| 141 |
+ key, tag = c.getPrimaryKeyTag(subsysIPSec) |
|
| 142 | 142 |
drvEnc.Primary = key |
| 143 | 143 |
drvEnc.PrimaryTag = tag |
| 144 | 144 |
|
| ... | ... |
@@ -317,17 +317,12 @@ func (c *controller) agentInit(bindAddrOrInterface string) error {
|
| 317 | 317 |
return nil |
| 318 | 318 |
} |
| 319 | 319 |
|
| 320 |
- drvEnc := discoverapi.DriverEncryptionConfig{}
|
|
| 321 |
- |
|
| 322 |
- keys, tags := c.getKeys(subsysGossip) // getKeys(subsysIPSec) |
|
| 323 |
- drvEnc.Keys = keys |
|
| 324 |
- drvEnc.Tags = tags |
|
| 325 |
- |
|
| 326 | 320 |
bindAddr, err := resolveAddr(bindAddrOrInterface) |
| 327 | 321 |
if err != nil {
|
| 328 | 322 |
return err |
| 329 | 323 |
} |
| 330 | 324 |
|
| 325 |
+ keys, tags := c.getKeys(subsysGossip) |
|
| 331 | 326 |
hostname, _ := os.Hostname() |
| 332 | 327 |
nDB, err := networkdb.New(&networkdb.Config{
|
| 333 | 328 |
BindAddr: bindAddr, |
| ... | ... |
@@ -350,6 +345,11 @@ func (c *controller) agentInit(bindAddrOrInterface string) error {
|
| 350 | 350 |
|
| 351 | 351 |
go c.handleTableEvents(ch, c.handleEpTableEvent) |
| 352 | 352 |
|
| 353 |
+ drvEnc := discoverapi.DriverEncryptionConfig{}
|
|
| 354 |
+ keys, tags = c.getKeys(subsysIPSec) |
|
| 355 |
+ drvEnc.Keys = keys |
|
| 356 |
+ drvEnc.Tags = tags |
|
| 357 |
+ |
|
| 353 | 358 |
c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool {
|
| 354 | 359 |
err := driver.DiscoverNew(discoverapi.EncryptionKeysConfig, drvEnc) |
| 355 | 360 |
if err != nil {
|
| ... | ... |
@@ -380,7 +380,7 @@ func (c *controller) agentDriverNotify(d driverapi.Driver) {
|
| 380 | 380 |
}) |
| 381 | 381 |
|
| 382 | 382 |
drvEnc := discoverapi.DriverEncryptionConfig{}
|
| 383 |
- keys, tags := c.getKeys(subsysGossip) // getKeys(subsysIPSec) |
|
| 383 |
+ keys, tags := c.getKeys(subsysIPSec) |
|
| 384 | 384 |
drvEnc.Keys = keys |
| 385 | 385 |
drvEnc.Tags = tags |
| 386 | 386 |
|
| ... | ... |
@@ -144,7 +144,7 @@ type controller struct {
|
| 144 | 144 |
unWatchCh chan *endpoint |
| 145 | 145 |
svcRecords map[string]svcInfo |
| 146 | 146 |
nmap map[string]*netWatch |
| 147 |
- serviceBindings map[string]*service |
|
| 147 |
+ serviceBindings map[serviceKey]*service |
|
| 148 | 148 |
defOsSbox osl.Sandbox |
| 149 | 149 |
ingressSandbox *sandbox |
| 150 | 150 |
sboxOnce sync.Once |
| ... | ... |
@@ -167,7 +167,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
|
| 167 | 167 |
cfg: config.ParseConfigOptions(cfgOptions...), |
| 168 | 168 |
sandboxes: sandboxTable{},
|
| 169 | 169 |
svcRecords: make(map[string]svcInfo), |
| 170 |
- serviceBindings: make(map[string]*service), |
|
| 170 |
+ serviceBindings: make(map[serviceKey]*service), |
|
| 171 | 171 |
agentInitDone: make(chan struct{}),
|
| 172 | 172 |
} |
| 173 | 173 |
|
| ... | ... |
@@ -54,11 +54,12 @@ var ( |
| 54 | 54 |
) |
| 55 | 55 |
|
| 56 | 56 |
type datastore struct {
|
| 57 |
- scope string |
|
| 58 |
- store store.Store |
|
| 59 |
- cache *cache |
|
| 60 |
- watchCh chan struct{}
|
|
| 61 |
- active bool |
|
| 57 |
+ scope string |
|
| 58 |
+ store store.Store |
|
| 59 |
+ cache *cache |
|
| 60 |
+ watchCh chan struct{}
|
|
| 61 |
+ active bool |
|
| 62 |
+ sequential bool |
|
| 62 | 63 |
sync.Mutex |
| 63 | 64 |
} |
| 64 | 65 |
|
| ... | ... |
@@ -190,6 +191,10 @@ func newClient(scope string, kv string, addr string, config *store.Config, cache |
| 190 | 190 |
if cached && scope != LocalScope {
|
| 191 | 191 |
return nil, fmt.Errorf("caching supported only for scope %s", LocalScope)
|
| 192 | 192 |
} |
| 193 |
+ sequential := false |
|
| 194 |
+ if scope == LocalScope {
|
|
| 195 |
+ sequential = true |
|
| 196 |
+ } |
|
| 193 | 197 |
|
| 194 | 198 |
if config == nil {
|
| 195 | 199 |
config = &store.Config{}
|
| ... | ... |
@@ -216,7 +221,7 @@ func newClient(scope string, kv string, addr string, config *store.Config, cache |
| 216 | 216 |
return nil, err |
| 217 | 217 |
} |
| 218 | 218 |
|
| 219 |
- ds := &datastore{scope: scope, store: store, active: true, watchCh: make(chan struct{})}
|
|
| 219 |
+ ds := &datastore{scope: scope, store: store, active: true, watchCh: make(chan struct{}), sequential: sequential}
|
|
| 220 | 220 |
if cached {
|
| 221 | 221 |
ds.cache = newCache(ds) |
| 222 | 222 |
} |
| ... | ... |
@@ -375,8 +380,10 @@ func (ds *datastore) PutObjectAtomic(kvObject KVObject) error {
|
| 375 | 375 |
pair *store.KVPair |
| 376 | 376 |
err error |
| 377 | 377 |
) |
| 378 |
- ds.Lock() |
|
| 379 |
- defer ds.Unlock() |
|
| 378 |
+ if ds.sequential {
|
|
| 379 |
+ ds.Lock() |
|
| 380 |
+ defer ds.Unlock() |
|
| 381 |
+ } |
|
| 380 | 382 |
|
| 381 | 383 |
if kvObject == nil {
|
| 382 | 384 |
return types.BadRequestErrorf("invalid KV Object : nil")
|
| ... | ... |
@@ -420,8 +427,10 @@ add_cache: |
| 420 | 420 |
|
| 421 | 421 |
// PutObject adds a new Record based on an object into the datastore |
| 422 | 422 |
func (ds *datastore) PutObject(kvObject KVObject) error {
|
| 423 |
- ds.Lock() |
|
| 424 |
- defer ds.Unlock() |
|
| 423 |
+ if ds.sequential {
|
|
| 424 |
+ ds.Lock() |
|
| 425 |
+ defer ds.Unlock() |
|
| 426 |
+ } |
|
| 425 | 427 |
|
| 426 | 428 |
if kvObject == nil {
|
| 427 | 429 |
return types.BadRequestErrorf("invalid KV Object : nil")
|
| ... | ... |
@@ -456,8 +465,10 @@ func (ds *datastore) putObjectWithKey(kvObject KVObject, key ...string) error {
|
| 456 | 456 |
|
| 457 | 457 |
// GetObject returns a record matching the key |
| 458 | 458 |
func (ds *datastore) GetObject(key string, o KVObject) error {
|
| 459 |
- ds.Lock() |
|
| 460 |
- defer ds.Unlock() |
|
| 459 |
+ if ds.sequential {
|
|
| 460 |
+ ds.Lock() |
|
| 461 |
+ defer ds.Unlock() |
|
| 462 |
+ } |
|
| 461 | 463 |
|
| 462 | 464 |
if ds.cache != nil {
|
| 463 | 465 |
return ds.cache.get(key, o) |
| ... | ... |
@@ -490,8 +501,10 @@ func (ds *datastore) ensureParent(parent string) error {
|
| 490 | 490 |
} |
| 491 | 491 |
|
| 492 | 492 |
func (ds *datastore) List(key string, kvObject KVObject) ([]KVObject, error) {
|
| 493 |
- ds.Lock() |
|
| 494 |
- defer ds.Unlock() |
|
| 493 |
+ if ds.sequential {
|
|
| 494 |
+ ds.Lock() |
|
| 495 |
+ defer ds.Unlock() |
|
| 496 |
+ } |
|
| 495 | 497 |
|
| 496 | 498 |
if ds.cache != nil {
|
| 497 | 499 |
return ds.cache.list(kvObject) |
| ... | ... |
@@ -536,8 +549,10 @@ func (ds *datastore) List(key string, kvObject KVObject) ([]KVObject, error) {
|
| 536 | 536 |
|
| 537 | 537 |
// DeleteObject unconditionally deletes a record from the store |
| 538 | 538 |
func (ds *datastore) DeleteObject(kvObject KVObject) error {
|
| 539 |
- ds.Lock() |
|
| 540 |
- defer ds.Unlock() |
|
| 539 |
+ if ds.sequential {
|
|
| 540 |
+ ds.Lock() |
|
| 541 |
+ defer ds.Unlock() |
|
| 542 |
+ } |
|
| 541 | 543 |
|
| 542 | 544 |
// cleaup the cache first |
| 543 | 545 |
if ds.cache != nil {
|
| ... | ... |
@@ -555,8 +570,10 @@ func (ds *datastore) DeleteObject(kvObject KVObject) error {
|
| 555 | 555 |
|
| 556 | 556 |
// DeleteObjectAtomic performs atomic delete on a record |
| 557 | 557 |
func (ds *datastore) DeleteObjectAtomic(kvObject KVObject) error {
|
| 558 |
- ds.Lock() |
|
| 559 |
- defer ds.Unlock() |
|
| 558 |
+ if ds.sequential {
|
|
| 559 |
+ ds.Lock() |
|
| 560 |
+ defer ds.Unlock() |
|
| 561 |
+ } |
|
| 560 | 562 |
|
| 561 | 563 |
if kvObject == nil {
|
| 562 | 564 |
return types.BadRequestErrorf("invalid KV Object : nil")
|
| ... | ... |
@@ -588,8 +605,10 @@ del_cache: |
| 588 | 588 |
|
| 589 | 589 |
// DeleteTree unconditionally deletes a record from the store |
| 590 | 590 |
func (ds *datastore) DeleteTree(kvObject KVObject) error {
|
| 591 |
- ds.Lock() |
|
| 592 |
- defer ds.Unlock() |
|
| 591 |
+ if ds.sequential {
|
|
| 592 |
+ ds.Lock() |
|
| 593 |
+ defer ds.Unlock() |
|
| 594 |
+ } |
|
| 593 | 595 |
|
| 594 | 596 |
// cleaup the cache first |
| 595 | 597 |
if ds.cache != nil {
|
| ... | ... |
@@ -1020,7 +1020,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, |
| 1020 | 1020 |
} |
| 1021 | 1021 |
|
| 1022 | 1022 |
if err = d.storeUpdate(endpoint); err != nil {
|
| 1023 |
- return fmt.Errorf("failed to save bridge endpoint %s to store: %v", ep.id[0:7], err)
|
|
| 1023 |
+ return fmt.Errorf("failed to save bridge endpoint %s to store: %v", endpoint.id[0:7], err)
|
|
| 1024 | 1024 |
} |
| 1025 | 1025 |
|
| 1026 | 1026 |
return nil |
| ... | ... |
@@ -183,7 +183,7 @@ func (ieie InvalidEndpointIDError) BadRequest() {}
|
| 183 | 183 |
type InvalidSandboxIDError string |
| 184 | 184 |
|
| 185 | 185 |
func (isie InvalidSandboxIDError) Error() string {
|
| 186 |
- return fmt.Sprintf("invalid sanbox id: %s", string(isie))
|
|
| 186 |
+ return fmt.Sprintf("invalid sandbox id: %s", string(isie))
|
|
| 187 | 187 |
} |
| 188 | 188 |
|
| 189 | 189 |
// BadRequest denotes the type of this error |
| ... | ... |
@@ -2,7 +2,6 @@ package ovmanager |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 |
- "log" |
|
| 6 | 5 |
"net" |
| 7 | 6 |
"strconv" |
| 8 | 7 |
"strings" |
| ... | ... |
@@ -20,7 +19,7 @@ import ( |
| 20 | 20 |
const ( |
| 21 | 21 |
networkType = "overlay" |
| 22 | 22 |
vxlanIDStart = 256 |
| 23 |
- vxlanIDEnd = 1000 |
|
| 23 |
+ vxlanIDEnd = (1 << 24) - 1 |
|
| 24 | 24 |
) |
| 25 | 25 |
|
| 26 | 26 |
type networkTable map[string]*network |
| ... | ... |
@@ -111,7 +110,8 @@ func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, |
| 111 | 111 |
} |
| 112 | 112 |
|
| 113 | 113 |
if err := n.obtainVxlanID(s); err != nil {
|
| 114 |
- log.Printf("Could not obtain vxlan id for pool %s: %v", s.subnetIP, err)
|
|
| 114 |
+ n.releaseVxlanID() |
|
| 115 |
+ return nil, fmt.Errorf("could not obtain vxlan id for pool %s: %v", s.subnetIP, err)
|
|
| 115 | 116 |
} |
| 116 | 117 |
|
| 117 | 118 |
n.subnets = append(n.subnets, s) |
| ... | ... |
@@ -294,7 +294,7 @@ func (d *driver) Type() string {
|
| 294 | 294 |
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster |
| 295 | 295 |
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
|
| 296 | 296 |
if dType != discoverapi.NodeDiscovery {
|
| 297 |
- return fmt.Errorf("Unknown discovery type : %v", dType)
|
|
| 297 |
+ return nil |
|
| 298 | 298 |
} |
| 299 | 299 |
notif := &api.DiscoveryNotification{
|
| 300 | 300 |
DiscoveryType: dType, |
| ... | ... |
@@ -306,7 +306,7 @@ func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{})
|
| 306 | 306 |
// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster |
| 307 | 307 |
func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
|
| 308 | 308 |
if dType != discoverapi.NodeDiscovery {
|
| 309 |
- return fmt.Errorf("Unknown discovery type : %v", dType)
|
|
| 309 |
+ return nil |
|
| 310 | 310 |
} |
| 311 | 311 |
notif := &api.DiscoveryNotification{
|
| 312 | 312 |
DiscoveryType: dType, |
| ... | ... |
@@ -722,18 +722,6 @@ func (ep *endpoint) sbLeave(sb *sandbox, force bool, options ...EndpointOption) |
| 722 | 722 |
return nil |
| 723 | 723 |
} |
| 724 | 724 |
|
| 725 |
-func (n *network) validateForceDelete(locator string) error {
|
|
| 726 |
- if n.Scope() == datastore.LocalScope {
|
|
| 727 |
- return nil |
|
| 728 |
- } |
|
| 729 |
- |
|
| 730 |
- if locator == "" {
|
|
| 731 |
- return fmt.Errorf("invalid endpoint locator identifier")
|
|
| 732 |
- } |
|
| 733 |
- |
|
| 734 |
- return nil |
|
| 735 |
-} |
|
| 736 |
- |
|
| 737 | 725 |
func (ep *endpoint) Delete(force bool) error {
|
| 738 | 726 |
var err error |
| 739 | 727 |
n, err := ep.getNetworkFromStore() |
| ... | ... |
@@ -750,15 +738,8 @@ func (ep *endpoint) Delete(force bool) error {
|
| 750 | 750 |
epid := ep.id |
| 751 | 751 |
name := ep.name |
| 752 | 752 |
sbid := ep.sandboxID |
| 753 |
- locator := ep.locator |
|
| 754 | 753 |
ep.Unlock() |
| 755 | 754 |
|
| 756 |
- if force {
|
|
| 757 |
- if err = n.validateForceDelete(locator); err != nil {
|
|
| 758 |
- return fmt.Errorf("unable to force delete endpoint %s: %v", name, err)
|
|
| 759 |
- } |
|
| 760 |
- } |
|
| 761 |
- |
|
| 762 | 755 |
sb, _ := n.getController().SandboxByID(sbid) |
| 763 | 756 |
if sb != nil && !force {
|
| 764 | 757 |
return &ActiveContainerError{name: name, id: epid}
|
| ... | ... |
@@ -83,17 +83,29 @@ func (n *networkNamespace) programGateway(gw net.IP, isAdd bool) error {
|
| 83 | 83 |
return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err)
|
| 84 | 84 |
} |
| 85 | 85 |
|
| 86 |
+ var linkIndex int |
|
| 87 |
+ for _, gwRoute := range gwRoutes {
|
|
| 88 |
+ if gwRoute.Gw == nil {
|
|
| 89 |
+ linkIndex = gwRoute.LinkIndex |
|
| 90 |
+ break |
|
| 91 |
+ } |
|
| 92 |
+ } |
|
| 93 |
+ |
|
| 94 |
+ if linkIndex == 0 {
|
|
| 95 |
+ return fmt.Errorf("Direct route for the gateway %s could not be found", gw)
|
|
| 96 |
+ } |
|
| 97 |
+ |
|
| 86 | 98 |
if isAdd {
|
| 87 | 99 |
return n.nlHandle.RouteAdd(&netlink.Route{
|
| 88 | 100 |
Scope: netlink.SCOPE_UNIVERSE, |
| 89 |
- LinkIndex: gwRoutes[0].LinkIndex, |
|
| 101 |
+ LinkIndex: linkIndex, |
|
| 90 | 102 |
Gw: gw, |
| 91 | 103 |
}) |
| 92 | 104 |
} |
| 93 | 105 |
|
| 94 | 106 |
return n.nlHandle.RouteDel(&netlink.Route{
|
| 95 | 107 |
Scope: netlink.SCOPE_UNIVERSE, |
| 96 |
- LinkIndex: gwRoutes[0].LinkIndex, |
|
| 108 |
+ LinkIndex: linkIndex, |
|
| 97 | 109 |
Gw: gw, |
| 98 | 110 |
}) |
| 99 | 111 |
} |
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package libnetwork |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "fmt" |
|
| 4 | 5 |
"net" |
| 5 | 6 |
"sync" |
| 6 | 7 |
) |
| ... | ... |
@@ -12,6 +13,27 @@ var ( |
| 12 | 12 |
fwMarkCtrMu sync.Mutex |
| 13 | 13 |
) |
| 14 | 14 |
|
| 15 |
+type portConfigs []*PortConfig |
|
| 16 |
+ |
|
| 17 |
+func (p portConfigs) String() string {
|
|
| 18 |
+ if len(p) == 0 {
|
|
| 19 |
+ return "" |
|
| 20 |
+ } |
|
| 21 |
+ |
|
| 22 |
+ pc := p[0] |
|
| 23 |
+ str := fmt.Sprintf("%d:%d/%s", pc.PublishedPort, pc.TargetPort, PortConfig_Protocol_name[int32(pc.Protocol)])
|
|
| 24 |
+ for _, pc := range p[1:] {
|
|
| 25 |
+ str = str + fmt.Sprintf(",%d:%d/%s", pc.PublishedPort, pc.TargetPort, PortConfig_Protocol_name[int32(pc.Protocol)])
|
|
| 26 |
+ } |
|
| 27 |
+ |
|
| 28 |
+ return str |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+type serviceKey struct {
|
|
| 32 |
+ id string |
|
| 33 |
+ ports string |
|
| 34 |
+} |
|
| 35 |
+ |
|
| 15 | 36 |
type service struct {
|
| 16 | 37 |
name string // Service Name |
| 17 | 38 |
id string // Service ID |
| ... | ... |
@@ -21,7 +43,7 @@ type service struct {
|
| 21 | 21 |
loadBalancers map[string]*loadBalancer |
| 22 | 22 |
|
| 23 | 23 |
// List of ingress ports exposed by the service |
| 24 |
- ingressPorts []*PortConfig |
|
| 24 |
+ ingressPorts portConfigs |
|
| 25 | 25 |
|
| 26 | 26 |
sync.Mutex |
| 27 | 27 |
} |
| ... | ... |
@@ -48,13 +48,18 @@ func (c *controller) addServiceBinding(name, sid, nid, eid string, vip net.IP, i |
| 48 | 48 |
return err |
| 49 | 49 |
} |
| 50 | 50 |
|
| 51 |
+ skey := serviceKey{
|
|
| 52 |
+ id: sid, |
|
| 53 |
+ ports: portConfigs(ingressPorts).String(), |
|
| 54 |
+ } |
|
| 55 |
+ |
|
| 51 | 56 |
c.Lock() |
| 52 |
- s, ok := c.serviceBindings[sid] |
|
| 57 |
+ s, ok := c.serviceBindings[skey] |
|
| 53 | 58 |
if !ok {
|
| 54 | 59 |
// Create a new service if we are seeing this service |
| 55 | 60 |
// for the first time. |
| 56 | 61 |
s = newService(name, sid, ingressPorts) |
| 57 |
- c.serviceBindings[sid] = s |
|
| 62 |
+ c.serviceBindings[skey] = s |
|
| 58 | 63 |
} |
| 59 | 64 |
c.Unlock() |
| 60 | 65 |
|
| ... | ... |
@@ -121,8 +126,13 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in |
| 121 | 121 |
return err |
| 122 | 122 |
} |
| 123 | 123 |
|
| 124 |
+ skey := serviceKey{
|
|
| 125 |
+ id: sid, |
|
| 126 |
+ ports: portConfigs(ingressPorts).String(), |
|
| 127 |
+ } |
|
| 128 |
+ |
|
| 124 | 129 |
c.Lock() |
| 125 |
- s, ok := c.serviceBindings[sid] |
|
| 130 |
+ s, ok := c.serviceBindings[skey] |
|
| 126 | 131 |
if !ok {
|
| 127 | 132 |
c.Unlock() |
| 128 | 133 |
return nil |
| ... | ... |
@@ -135,22 +145,19 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in |
| 135 | 135 |
n.(*network).deleteSvcRecords("tasks."+alias, ip, nil, false)
|
| 136 | 136 |
} |
| 137 | 137 |
|
| 138 |
- // Make sure to remove the right IP since if vip is |
|
| 139 |
- // not valid we would have added a DNS RR record. |
|
| 140 |
- svcIP := vip |
|
| 141 |
- if len(svcIP) == 0 {
|
|
| 142 |
- svcIP = ip |
|
| 143 |
- } |
|
| 144 |
- n.(*network).deleteSvcRecords(name, svcIP, nil, false) |
|
| 145 |
- for _, alias := range aliases {
|
|
| 146 |
- n.(*network).deleteSvcRecords(alias, svcIP, nil, false) |
|
| 138 |
+ // If we are doing DNS RR add the endpoint IP to DNS record |
|
| 139 |
+ // right away. |
|
| 140 |
+ if len(vip) == 0 {
|
|
| 141 |
+ n.(*network).deleteSvcRecords(name, ip, nil, false) |
|
| 142 |
+ for _, alias := range aliases {
|
|
| 143 |
+ n.(*network).deleteSvcRecords(alias, ip, nil, false) |
|
| 144 |
+ } |
|
| 147 | 145 |
} |
| 148 | 146 |
|
| 149 | 147 |
s.Lock() |
| 150 |
- defer s.Unlock() |
|
| 151 |
- |
|
| 152 | 148 |
lb, ok := s.loadBalancers[nid] |
| 153 | 149 |
if !ok {
|
| 150 |
+ s.Unlock() |
|
| 154 | 151 |
return nil |
| 155 | 152 |
} |
| 156 | 153 |
|
| ... | ... |
@@ -167,7 +174,7 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in |
| 167 | 167 |
if len(s.loadBalancers) == 0 {
|
| 168 | 168 |
// All loadbalancers for the service removed. Time to |
| 169 | 169 |
// remove the service itself. |
| 170 |
- delete(c.serviceBindings, sid) |
|
| 170 |
+ delete(c.serviceBindings, skey) |
|
| 171 | 171 |
} |
| 172 | 172 |
|
| 173 | 173 |
// Remove loadbalancer service(if needed) and backend in all |
| ... | ... |
@@ -175,6 +182,15 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in |
| 175 | 175 |
if len(vip) != 0 {
|
| 176 | 176 |
n.(*network).rmLBBackend(ip, vip, lb.fwMark, ingressPorts, rmService) |
| 177 | 177 |
} |
| 178 |
+ s.Unlock() |
|
| 179 |
+ |
|
| 180 |
+ // Remove the DNS record for VIP only if we are removing the service |
|
| 181 |
+ if rmService && len(vip) != 0 {
|
|
| 182 |
+ n.(*network).deleteSvcRecords(name, vip, nil, false) |
|
| 183 |
+ for _, alias := range aliases {
|
|
| 184 |
+ n.(*network).deleteSvcRecords(alias, vip, nil, false) |
|
| 185 |
+ } |
|
| 186 |
+ } |
|
| 178 | 187 |
|
| 179 | 188 |
return nil |
| 180 | 189 |
} |
| ... | ... |
@@ -314,7 +330,7 @@ func (sb *sandbox) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*P |
| 314 | 314 |
if addService {
|
| 315 | 315 |
var iPorts []*PortConfig |
| 316 | 316 |
if sb.ingress {
|
| 317 |
- iPorts = ingressPorts |
|
| 317 |
+ iPorts = filterPortConfigs(ingressPorts, false) |
|
| 318 | 318 |
if err := programIngress(gwIP, iPorts, false); err != nil {
|
| 319 | 319 |
logrus.Errorf("Failed to add ingress: %v", err)
|
| 320 | 320 |
return |
| ... | ... |
@@ -383,7 +399,7 @@ func (sb *sandbox) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po |
| 383 | 383 |
|
| 384 | 384 |
var iPorts []*PortConfig |
| 385 | 385 |
if sb.ingress {
|
| 386 |
- iPorts = ingressPorts |
|
| 386 |
+ iPorts = filterPortConfigs(ingressPorts, true) |
|
| 387 | 387 |
if err := programIngress(gwIP, iPorts, true); err != nil {
|
| 388 | 388 |
logrus.Errorf("Failed to delete ingress: %v", err)
|
| 389 | 389 |
} |
| ... | ... |
@@ -401,8 +417,47 @@ var ( |
| 401 | 401 |
ingressOnce sync.Once |
| 402 | 402 |
ingressProxyMu sync.Mutex |
| 403 | 403 |
ingressProxyTbl = make(map[string]io.Closer) |
| 404 |
+ portConfigMu sync.Mutex |
|
| 405 |
+ portConfigTbl = make(map[PortConfig]int) |
|
| 404 | 406 |
) |
| 405 | 407 |
|
| 408 |
+func filterPortConfigs(ingressPorts []*PortConfig, isDelete bool) []*PortConfig {
|
|
| 409 |
+ portConfigMu.Lock() |
|
| 410 |
+ iPorts := make([]*PortConfig, 0, len(ingressPorts)) |
|
| 411 |
+ for _, pc := range ingressPorts {
|
|
| 412 |
+ if isDelete {
|
|
| 413 |
+ if cnt, ok := portConfigTbl[*pc]; ok {
|
|
| 414 |
+ // This is the last reference to this |
|
| 415 |
+ // port config. Delete the port config |
|
| 416 |
+ // and add it to filtered list to be |
|
| 417 |
+ // plumbed. |
|
| 418 |
+ if cnt == 1 {
|
|
| 419 |
+ delete(portConfigTbl, *pc) |
|
| 420 |
+ iPorts = append(iPorts, pc) |
|
| 421 |
+ continue |
|
| 422 |
+ } |
|
| 423 |
+ |
|
| 424 |
+ portConfigTbl[*pc] = cnt - 1 |
|
| 425 |
+ } |
|
| 426 |
+ |
|
| 427 |
+ continue |
|
| 428 |
+ } |
|
| 429 |
+ |
|
| 430 |
+ if cnt, ok := portConfigTbl[*pc]; ok {
|
|
| 431 |
+ portConfigTbl[*pc] = cnt + 1 |
|
| 432 |
+ continue |
|
| 433 |
+ } |
|
| 434 |
+ |
|
| 435 |
+ // We are adding it for the first time. Add it to the |
|
| 436 |
+ // filter list to be plumbed. |
|
| 437 |
+ portConfigTbl[*pc] = 1 |
|
| 438 |
+ iPorts = append(iPorts, pc) |
|
| 439 |
+ } |
|
| 440 |
+ portConfigMu.Unlock() |
|
| 441 |
+ |
|
| 442 |
+ return iPorts |
|
| 443 |
+} |
|
| 444 |
+ |
|
| 406 | 445 |
func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) error {
|
| 407 | 446 |
addDelOpt := "-I" |
| 408 | 447 |
if isDelete {
|
| ... | ... |
@@ -4,7 +4,6 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"math/rand" |
| 6 | 6 |
"reflect" |
| 7 |
- "sync" |
|
| 8 | 7 |
"time" |
| 9 | 8 |
|
| 10 | 9 |
"github.com/docker/swarmkit/api" |
| ... | ... |
@@ -37,7 +36,6 @@ type Agent struct {
|
| 37 | 37 |
stopped chan struct{} // requests shutdown
|
| 38 | 38 |
closed chan struct{} // only closed in run
|
| 39 | 39 |
err error // read only after closed is closed |
| 40 |
- mu sync.Mutex |
|
| 41 | 40 |
} |
| 42 | 41 |
|
| 43 | 42 |
// New returns a new agent, ready for task dispatch. |
| ... | ... |
@@ -55,7 +55,7 @@ type ContainerStatuser interface {
|
| 55 | 55 |
// correct status depending on the tasks current state according to the result. |
| 56 | 56 |
// |
| 57 | 57 |
// Unlike Do, if an error is returned, the status should still be reported. The |
| 58 |
-// error merely reports the |
|
| 58 |
+// error merely reports the failure at getting the controller. |
|
| 59 | 59 |
func Resolve(ctx context.Context, task *api.Task, executor Executor) (Controller, *api.TaskStatus, error) {
|
| 60 | 60 |
status := task.Status.Copy() |
| 61 | 61 |
|
| ... | ... |
@@ -10,7 +10,7 @@ type Executor interface {
|
| 10 | 10 |
// Describe returns the underlying node description. |
| 11 | 11 |
Describe(ctx context.Context) (*api.NodeDescription, error) |
| 12 | 12 |
|
| 13 |
- // Configure uses the node object state to propogate node |
|
| 13 |
+ // Configure uses the node object state to propagate node |
|
| 14 | 14 |
// state to the underlying executor. |
| 15 | 15 |
Configure(ctx context.Context, node *api.Node) error |
| 16 | 16 |
|
| ... | ... |
@@ -49,6 +49,10 @@ type NodeConfig struct {
|
| 49 | 49 |
// Secret to be used on the first certificate request. |
| 50 | 50 |
Secret string |
| 51 | 51 |
|
| 52 |
+ // ExternalCAs is a list of CAs to which a manager node |
|
| 53 |
+ // will make certificate signing requests for node certificates. |
|
| 54 |
+ ExternalCAs []*api.ExternalCA |
|
| 55 |
+ |
|
| 52 | 56 |
// ForceNewCluster creates a new cluster from current raft state. |
| 53 | 57 |
ForceNewCluster bool |
| 54 | 58 |
|
| ... | ... |
@@ -81,7 +85,6 @@ type Node struct {
|
| 81 | 81 |
config *NodeConfig |
| 82 | 82 |
remotes *persistentRemotes |
| 83 | 83 |
role string |
| 84 |
- roleCond *sync.Cond |
|
| 85 | 84 |
conn *grpc.ClientConn |
| 86 | 85 |
connCond *sync.Cond |
| 87 | 86 |
nodeID string |
| ... | ... |
@@ -95,6 +98,7 @@ type Node struct {
|
| 95 | 95 |
agent *Agent |
| 96 | 96 |
manager *manager.Manager |
| 97 | 97 |
roleChangeReq chan api.NodeRole // used to send role updates from the dispatcher api on promotion/demotion |
| 98 |
+ managerRoleCh chan struct{}
|
|
| 98 | 99 |
} |
| 99 | 100 |
|
| 100 | 101 |
// NewNode returns new Node instance. |
| ... | ... |
@@ -124,8 +128,8 @@ func NewNode(c *NodeConfig) (*Node, error) {
|
| 124 | 124 |
ready: make(chan struct{}),
|
| 125 | 125 |
certificateRequested: make(chan struct{}),
|
| 126 | 126 |
roleChangeReq: make(chan api.NodeRole, 1), |
| 127 |
+ managerRoleCh: make(chan struct{}, 32), // 32 just for the case
|
|
| 127 | 128 |
} |
| 128 |
- n.roleCond = sync.NewCond(n.RLocker()) |
|
| 129 | 129 |
n.connCond = sync.NewCond(n.RLocker()) |
| 130 | 130 |
if err := n.loadCertificates(); err != nil {
|
| 131 | 131 |
return nil, err |
| ... | ... |
@@ -174,6 +178,8 @@ func (n *Node) run(ctx context.Context) (err error) {
|
| 174 | 174 |
} |
| 175 | 175 |
}() |
| 176 | 176 |
|
| 177 |
+ // NOTE: When this node is created by NewNode(), our nodeID is set if |
|
| 178 |
+ // n.loadCertificates() succeeded in loading TLS credentials. |
|
| 177 | 179 |
if n.config.JoinAddr == "" && n.nodeID == "" {
|
| 178 | 180 |
if err := n.bootstrapCA(); err != nil {
|
| 179 | 181 |
return err |
| ... | ... |
@@ -234,6 +240,10 @@ func (n *Node) run(ctx context.Context) (err error) {
|
| 234 | 234 |
return err |
| 235 | 235 |
} |
| 236 | 236 |
|
| 237 |
+ if n.role == ca.ManagerRole {
|
|
| 238 |
+ n.managerRoleCh <- struct{}{}
|
|
| 239 |
+ } |
|
| 240 |
+ |
|
| 237 | 241 |
forceCertRenewal := make(chan struct{})
|
| 238 | 242 |
go func() {
|
| 239 | 243 |
n.RLock() |
| ... | ... |
@@ -270,7 +280,9 @@ func (n *Node) run(ctx context.Context) (err error) {
|
| 270 | 270 |
} |
| 271 | 271 |
n.Lock() |
| 272 | 272 |
n.role = certUpdate.Role |
| 273 |
- n.roleCond.Broadcast() |
|
| 273 |
+ if n.role == ca.ManagerRole {
|
|
| 274 |
+ n.managerRoleCh <- struct{}{}
|
|
| 275 |
+ } |
|
| 274 | 276 |
n.Unlock() |
| 275 | 277 |
case <-ctx.Done(): |
| 276 | 278 |
return |
| ... | ... |
@@ -419,34 +431,6 @@ func (n *Node) CertificateRequested() <-chan struct{} {
|
| 419 | 419 |
return n.certificateRequested |
| 420 | 420 |
} |
| 421 | 421 |
|
| 422 |
-func (n *Node) waitRole(ctx context.Context, role string) <-chan struct{} {
|
|
| 423 |
- c := make(chan struct{})
|
|
| 424 |
- n.roleCond.L.Lock() |
|
| 425 |
- if role == n.role {
|
|
| 426 |
- close(c) |
|
| 427 |
- n.roleCond.L.Unlock() |
|
| 428 |
- return c |
|
| 429 |
- } |
|
| 430 |
- go func() {
|
|
| 431 |
- select {
|
|
| 432 |
- case <-ctx.Done(): |
|
| 433 |
- n.roleCond.Broadcast() |
|
| 434 |
- case <-c: |
|
| 435 |
- } |
|
| 436 |
- }() |
|
| 437 |
- go func() {
|
|
| 438 |
- defer n.roleCond.L.Unlock() |
|
| 439 |
- defer close(c) |
|
| 440 |
- for role != n.role {
|
|
| 441 |
- n.roleCond.Wait() |
|
| 442 |
- if ctx.Err() != nil {
|
|
| 443 |
- return |
|
| 444 |
- } |
|
| 445 |
- } |
|
| 446 |
- }() |
|
| 447 |
- return c |
|
| 448 |
-} |
|
| 449 |
- |
|
| 450 | 422 |
func (n *Node) setControlSocket(conn *grpc.ClientConn) {
|
| 451 | 423 |
n.Lock() |
| 452 | 424 |
n.conn = conn |
| ... | ... |
@@ -549,7 +533,6 @@ func (n *Node) loadCertificates() error {
|
| 549 | 549 |
n.role = clientTLSCreds.Role() |
| 550 | 550 |
n.nodeID = clientTLSCreds.NodeID() |
| 551 | 551 |
n.nodeMembership = api.NodeMembershipAccepted |
| 552 |
- n.roleCond.Broadcast() |
|
| 553 | 552 |
n.Unlock() |
| 554 | 553 |
|
| 555 | 554 |
return nil |
| ... | ... |
@@ -599,10 +582,17 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig |
| 599 | 599 |
select {
|
| 600 | 600 |
case <-ctx.Done(): |
| 601 | 601 |
return ctx.Err() |
| 602 |
- case <-n.waitRole(ctx, ca.ManagerRole): |
|
| 602 |
+ case <-n.managerRoleCh: |
|
| 603 | 603 |
if ctx.Err() != nil {
|
| 604 | 604 |
return ctx.Err() |
| 605 | 605 |
} |
| 606 |
+ n.Lock() |
|
| 607 |
+ // in case if we missed some notifications |
|
| 608 |
+ if n.role != ca.ManagerRole {
|
|
| 609 |
+ n.Unlock() |
|
| 610 |
+ continue |
|
| 611 |
+ } |
|
| 612 |
+ n.Unlock() |
|
| 606 | 613 |
remoteAddr, _ := n.remotes.Select(n.nodeID) |
| 607 | 614 |
m, err := manager.New(&manager.Config{
|
| 608 | 615 |
ForceNewCluster: n.config.ForceNewCluster, |
| ... | ... |
@@ -611,6 +601,7 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig |
| 611 | 611 |
"unix": n.config.ListenControlAPI, |
| 612 | 612 |
}, |
| 613 | 613 |
SecurityConfig: securityConfig, |
| 614 |
+ ExternalCAs: n.config.ExternalCAs, |
|
| 614 | 615 |
JoinRaft: remoteAddr.Addr, |
| 615 | 616 |
StateDir: n.config.StateDir, |
| 616 | 617 |
HeartbeatTick: n.config.HeartbeatTick, |
| ... | ... |
@@ -629,17 +620,21 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig |
| 629 | 629 |
n.manager = m |
| 630 | 630 |
n.Unlock() |
| 631 | 631 |
|
| 632 |
- go n.initManagerConnection(ctx, ready) |
|
| 632 |
+ connCtx, connCancel := context.WithCancel(ctx) |
|
| 633 |
+ go n.initManagerConnection(connCtx, ready) |
|
| 633 | 634 |
|
| 634 |
- go func() {
|
|
| 635 |
- select {
|
|
| 636 |
- case <-ready: |
|
| 637 |
- case <-ctx.Done(): |
|
| 638 |
- } |
|
| 639 |
- if ctx.Err() == nil {
|
|
| 640 |
- n.remotes.Observe(api.Peer{NodeID: n.nodeID, Addr: n.config.ListenRemoteAPI}, 5)
|
|
| 641 |
- } |
|
| 642 |
- }() |
|
| 635 |
+ // this happens only on initial start |
|
| 636 |
+ if ready != nil {
|
|
| 637 |
+ go func(ready chan struct{}) {
|
|
| 638 |
+ select {
|
|
| 639 |
+ case <-ready: |
|
| 640 |
+ n.remotes.Observe(api.Peer{NodeID: n.nodeID, Addr: n.config.ListenRemoteAPI}, 5)
|
|
| 641 |
+ case <-connCtx.Done(): |
|
| 642 |
+ } |
|
| 643 |
+ }(ready) |
|
| 644 |
+ } |
|
| 645 |
+ |
|
| 646 |
+ ready = nil |
|
| 643 | 647 |
|
| 644 | 648 |
select {
|
| 645 | 649 |
case <-ctx.Done(): |
| ... | ... |
@@ -648,8 +643,8 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig |
| 648 | 648 |
// in case of demotion manager will stop itself |
| 649 | 649 |
case <-done: |
| 650 | 650 |
} |
| 651 |
+ connCancel() |
|
| 651 | 652 |
|
| 652 |
- ready = nil // ready event happens once, even on multiple starts |
|
| 653 | 653 |
n.Lock() |
| 654 | 654 |
n.manager = nil |
| 655 | 655 |
if n.conn != nil {
|
| ... | ... |
@@ -669,7 +664,6 @@ type persistentRemotes struct {
|
| 669 | 669 |
c *sync.Cond |
| 670 | 670 |
picker.Remotes |
| 671 | 671 |
storePath string |
| 672 |
- ch []chan api.Peer |
|
| 673 | 672 |
lastSavedState []api.Peer |
| 674 | 673 |
} |
| 675 | 674 |
|
| ... | ... |
@@ -1,8 +1,6 @@ |
| 1 | 1 |
package agent |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "bytes" |
|
| 5 |
- |
|
| 6 | 4 |
"github.com/boltdb/bolt" |
| 7 | 5 |
"github.com/docker/swarmkit/api" |
| 8 | 6 |
"github.com/gogo/protobuf/proto" |
| ... | ... |
@@ -22,12 +20,6 @@ var ( |
| 22 | 22 |
bucketKeyStatus = []byte("status")
|
| 23 | 23 |
) |
| 24 | 24 |
|
| 25 |
-type bucketKeyPath [][]byte |
|
| 26 |
- |
|
| 27 |
-func (bk bucketKeyPath) String() string {
|
|
| 28 |
- return string(bytes.Join([][]byte(bk), []byte("/")))
|
|
| 29 |
-} |
|
| 30 |
- |
|
| 31 | 25 |
// InitDB prepares a database for writing task data. |
| 32 | 26 |
// |
| 33 | 27 |
// Proper buckets will be created if they don't already exist. |
| 34 | 28 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,8 @@ |
| 0 |
+### Notice |
|
| 1 |
+ |
|
| 2 |
+Do not change .pb.go files directly. You need to change the corresponding .proto files and run the following command to regenerate the .pb.go files. |
|
| 3 |
+``` |
|
| 4 |
+$ make generate |
|
| 5 |
+``` |
|
| 6 |
+ |
|
| 7 |
+Click [here](https://github.com/google/protobuf) for more information about protobuf. |
| ... | ... |
@@ -1,3 +1,3 @@ |
| 1 | 1 |
package api |
| 2 | 2 |
|
| 3 |
-//go:generate protoc -I.:../protobuf:../vendor:../vendor/github.com/gogo/protobuf --gogoswarm_out=plugins=grpc+deepcopy+raftproxy+authenticatedwrapper,import_path=github.com/docker/swarmkit/api,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto,Mtimestamp/timestamp.proto=github.com/docker/swarmkit/api/timestamp,Mduration/duration.proto=github.com/docker/swarmkit/api/duration,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor,Mplugin/plugin.proto=github.com/docker/swarmkit/protobuf/plugin:. types.proto specs.proto objects.proto control.proto dispatcher.proto ca.proto snapshot.proto raft.proto |
|
| 3 |
+//go:generate protoc -I.:../protobuf:../vendor:../vendor/github.com/gogo/protobuf --gogoswarm_out=plugins=grpc+deepcopy+raftproxy+authenticatedwrapper,import_path=github.com/docker/swarmkit/api,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto,Mtimestamp/timestamp.proto=github.com/docker/swarmkit/api/timestamp,Mduration/duration.proto=github.com/docker/swarmkit/api/duration,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor,Mplugin/plugin.proto=github.com/docker/swarmkit/protobuf/plugin:. types.proto specs.proto objects.proto control.proto dispatcher.proto ca.proto snapshot.proto raft.proto health.proto |
| 4 | 4 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,714 @@ |
| 0 |
+// Code generated by protoc-gen-gogo. |
|
| 1 |
+// source: health.proto |
|
| 2 |
+// DO NOT EDIT! |
|
| 3 |
+ |
|
| 4 |
+package api |
|
| 5 |
+ |
|
| 6 |
+import proto "github.com/gogo/protobuf/proto" |
|
| 7 |
+import fmt "fmt" |
|
| 8 |
+import math "math" |
|
| 9 |
+import _ "github.com/gogo/protobuf/gogoproto" |
|
| 10 |
+import _ "github.com/docker/swarmkit/protobuf/plugin" |
|
| 11 |
+ |
|
| 12 |
+import strings "strings" |
|
| 13 |
+import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto" |
|
| 14 |
+import sort "sort" |
|
| 15 |
+import strconv "strconv" |
|
| 16 |
+import reflect "reflect" |
|
| 17 |
+ |
|
| 18 |
+import ( |
|
| 19 |
+ context "golang.org/x/net/context" |
|
| 20 |
+ grpc "google.golang.org/grpc" |
|
| 21 |
+) |
|
| 22 |
+ |
|
| 23 |
+import raftpicker "github.com/docker/swarmkit/manager/raftpicker" |
|
| 24 |
+import codes "google.golang.org/grpc/codes" |
|
| 25 |
+import metadata "google.golang.org/grpc/metadata" |
|
| 26 |
+import transport "google.golang.org/grpc/transport" |
|
| 27 |
+ |
|
| 28 |
+import io "io" |
|
| 29 |
+ |
|
| 30 |
+// Reference imports to suppress errors if they are not otherwise used. |
|
| 31 |
+var _ = proto.Marshal |
|
| 32 |
+var _ = fmt.Errorf |
|
| 33 |
+var _ = math.Inf |
|
| 34 |
+ |
|
| 35 |
+type HealthCheckResponse_ServingStatus int32 |
|
| 36 |
+ |
|
| 37 |
+const ( |
|
| 38 |
+ HealthCheckResponse_UNKNOWN HealthCheckResponse_ServingStatus = 0 |
|
| 39 |
+ HealthCheckResponse_SERVING HealthCheckResponse_ServingStatus = 1 |
|
| 40 |
+ HealthCheckResponse_NOT_SERVING HealthCheckResponse_ServingStatus = 2 |
|
| 41 |
+) |
|
| 42 |
+ |
|
| 43 |
+var HealthCheckResponse_ServingStatus_name = map[int32]string{
|
|
| 44 |
+ 0: "UNKNOWN", |
|
| 45 |
+ 1: "SERVING", |
|
| 46 |
+ 2: "NOT_SERVING", |
|
| 47 |
+} |
|
| 48 |
+var HealthCheckResponse_ServingStatus_value = map[string]int32{
|
|
| 49 |
+ "UNKNOWN": 0, |
|
| 50 |
+ "SERVING": 1, |
|
| 51 |
+ "NOT_SERVING": 2, |
|
| 52 |
+} |
|
| 53 |
+ |
|
| 54 |
+func (x HealthCheckResponse_ServingStatus) String() string {
|
|
| 55 |
+ return proto.EnumName(HealthCheckResponse_ServingStatus_name, int32(x)) |
|
| 56 |
+} |
|
| 57 |
+func (HealthCheckResponse_ServingStatus) EnumDescriptor() ([]byte, []int) {
|
|
| 58 |
+ return fileDescriptorHealth, []int{1, 0}
|
|
| 59 |
+} |
|
| 60 |
+ |
|
| 61 |
+type HealthCheckRequest struct {
|
|
| 62 |
+ Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` |
|
| 63 |
+} |
|
| 64 |
+ |
|
| 65 |
+func (m *HealthCheckRequest) Reset() { *m = HealthCheckRequest{} }
|
|
| 66 |
+func (*HealthCheckRequest) ProtoMessage() {}
|
|
| 67 |
+func (*HealthCheckRequest) Descriptor() ([]byte, []int) { return fileDescriptorHealth, []int{0} }
|
|
| 68 |
+ |
|
| 69 |
+type HealthCheckResponse struct {
|
|
| 70 |
+ Status HealthCheckResponse_ServingStatus `protobuf:"varint,1,opt,name=status,proto3,enum=docker.swarmkit.v1.HealthCheckResponse_ServingStatus" json:"status,omitempty"` |
|
| 71 |
+} |
|
| 72 |
+ |
|
| 73 |
+func (m *HealthCheckResponse) Reset() { *m = HealthCheckResponse{} }
|
|
| 74 |
+func (*HealthCheckResponse) ProtoMessage() {}
|
|
| 75 |
+func (*HealthCheckResponse) Descriptor() ([]byte, []int) { return fileDescriptorHealth, []int{1} }
|
|
| 76 |
+ |
|
| 77 |
+func init() {
|
|
| 78 |
+ proto.RegisterType((*HealthCheckRequest)(nil), "docker.swarmkit.v1.HealthCheckRequest") |
|
| 79 |
+ proto.RegisterType((*HealthCheckResponse)(nil), "docker.swarmkit.v1.HealthCheckResponse") |
|
| 80 |
+ proto.RegisterEnum("docker.swarmkit.v1.HealthCheckResponse_ServingStatus", HealthCheckResponse_ServingStatus_name, HealthCheckResponse_ServingStatus_value)
|
|
| 81 |
+} |
|
| 82 |
+ |
|
| 83 |
+type authenticatedWrapperHealthServer struct {
|
|
| 84 |
+ local HealthServer |
|
| 85 |
+ authorize func(context.Context, []string) error |
|
| 86 |
+} |
|
| 87 |
+ |
|
| 88 |
+func NewAuthenticatedWrapperHealthServer(local HealthServer, authorize func(context.Context, []string) error) HealthServer {
|
|
| 89 |
+ return &authenticatedWrapperHealthServer{
|
|
| 90 |
+ local: local, |
|
| 91 |
+ authorize: authorize, |
|
| 92 |
+ } |
|
| 93 |
+} |
|
| 94 |
+ |
|
| 95 |
+func (p *authenticatedWrapperHealthServer) Check(ctx context.Context, r *HealthCheckRequest) (*HealthCheckResponse, error) {
|
|
| 96 |
+ |
|
| 97 |
+ if err := p.authorize(ctx, []string{"swarm-manager"}); err != nil {
|
|
| 98 |
+ return nil, err |
|
| 99 |
+ } |
|
| 100 |
+ return p.local.Check(ctx, r) |
|
| 101 |
+} |
|
| 102 |
+ |
|
| 103 |
+func (m *HealthCheckRequest) Copy() *HealthCheckRequest {
|
|
| 104 |
+ if m == nil {
|
|
| 105 |
+ return nil |
|
| 106 |
+ } |
|
| 107 |
+ |
|
| 108 |
+ o := &HealthCheckRequest{
|
|
| 109 |
+ Service: m.Service, |
|
| 110 |
+ } |
|
| 111 |
+ |
|
| 112 |
+ return o |
|
| 113 |
+} |
|
| 114 |
+ |
|
| 115 |
+func (m *HealthCheckResponse) Copy() *HealthCheckResponse {
|
|
| 116 |
+ if m == nil {
|
|
| 117 |
+ return nil |
|
| 118 |
+ } |
|
| 119 |
+ |
|
| 120 |
+ o := &HealthCheckResponse{
|
|
| 121 |
+ Status: m.Status, |
|
| 122 |
+ } |
|
| 123 |
+ |
|
| 124 |
+ return o |
|
| 125 |
+} |
|
| 126 |
+ |
|
| 127 |
+func (this *HealthCheckRequest) GoString() string {
|
|
| 128 |
+ if this == nil {
|
|
| 129 |
+ return "nil" |
|
| 130 |
+ } |
|
| 131 |
+ s := make([]string, 0, 5) |
|
| 132 |
+ s = append(s, "&api.HealthCheckRequest{")
|
|
| 133 |
+ s = append(s, "Service: "+fmt.Sprintf("%#v", this.Service)+",\n")
|
|
| 134 |
+ s = append(s, "}") |
|
| 135 |
+ return strings.Join(s, "") |
|
| 136 |
+} |
|
| 137 |
+func (this *HealthCheckResponse) GoString() string {
|
|
| 138 |
+ if this == nil {
|
|
| 139 |
+ return "nil" |
|
| 140 |
+ } |
|
| 141 |
+ s := make([]string, 0, 5) |
|
| 142 |
+ s = append(s, "&api.HealthCheckResponse{")
|
|
| 143 |
+ s = append(s, "Status: "+fmt.Sprintf("%#v", this.Status)+",\n")
|
|
| 144 |
+ s = append(s, "}") |
|
| 145 |
+ return strings.Join(s, "") |
|
| 146 |
+} |
|
| 147 |
+func valueToGoStringHealth(v interface{}, typ string) string {
|
|
| 148 |
+ rv := reflect.ValueOf(v) |
|
| 149 |
+ if rv.IsNil() {
|
|
| 150 |
+ return "nil" |
|
| 151 |
+ } |
|
| 152 |
+ pv := reflect.Indirect(rv).Interface() |
|
| 153 |
+ return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv)
|
|
| 154 |
+} |
|
| 155 |
+func extensionToGoStringHealth(e map[int32]github_com_gogo_protobuf_proto.Extension) string {
|
|
| 156 |
+ if e == nil {
|
|
| 157 |
+ return "nil" |
|
| 158 |
+ } |
|
| 159 |
+ s := "map[int32]proto.Extension{"
|
|
| 160 |
+ keys := make([]int, 0, len(e)) |
|
| 161 |
+ for k := range e {
|
|
| 162 |
+ keys = append(keys, int(k)) |
|
| 163 |
+ } |
|
| 164 |
+ sort.Ints(keys) |
|
| 165 |
+ ss := []string{}
|
|
| 166 |
+ for _, k := range keys {
|
|
| 167 |
+ ss = append(ss, strconv.Itoa(k)+": "+e[int32(k)].GoString()) |
|
| 168 |
+ } |
|
| 169 |
+ s += strings.Join(ss, ",") + "}" |
|
| 170 |
+ return s |
|
| 171 |
+} |
|
| 172 |
+ |
|
| 173 |
+// Reference imports to suppress errors if they are not otherwise used. |
|
| 174 |
+var _ context.Context |
|
| 175 |
+var _ grpc.ClientConn |
|
| 176 |
+ |
|
| 177 |
+// This is a compile-time assertion to ensure that this generated file |
|
| 178 |
+// is compatible with the grpc package it is being compiled against. |
|
| 179 |
+const _ = grpc.SupportPackageIsVersion2 |
|
| 180 |
+ |
|
| 181 |
+// Client API for Health service |
|
| 182 |
+ |
|
| 183 |
+type HealthClient interface {
|
|
| 184 |
+ Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) |
|
| 185 |
+} |
|
| 186 |
+ |
|
| 187 |
+type healthClient struct {
|
|
| 188 |
+ cc *grpc.ClientConn |
|
| 189 |
+} |
|
| 190 |
+ |
|
| 191 |
+func NewHealthClient(cc *grpc.ClientConn) HealthClient {
|
|
| 192 |
+ return &healthClient{cc}
|
|
| 193 |
+} |
|
| 194 |
+ |
|
| 195 |
+func (c *healthClient) Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) {
|
|
| 196 |
+ out := new(HealthCheckResponse) |
|
| 197 |
+ err := grpc.Invoke(ctx, "/docker.swarmkit.v1.Health/Check", in, out, c.cc, opts...) |
|
| 198 |
+ if err != nil {
|
|
| 199 |
+ return nil, err |
|
| 200 |
+ } |
|
| 201 |
+ return out, nil |
|
| 202 |
+} |
|
| 203 |
+ |
|
| 204 |
+// Server API for Health service |
|
| 205 |
+ |
|
| 206 |
+type HealthServer interface {
|
|
| 207 |
+ Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) |
|
| 208 |
+} |
|
| 209 |
+ |
|
| 210 |
+func RegisterHealthServer(s *grpc.Server, srv HealthServer) {
|
|
| 211 |
+ s.RegisterService(&_Health_serviceDesc, srv) |
|
| 212 |
+} |
|
| 213 |
+ |
|
| 214 |
+func _Health_Check_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
| 215 |
+ in := new(HealthCheckRequest) |
|
| 216 |
+ if err := dec(in); err != nil {
|
|
| 217 |
+ return nil, err |
|
| 218 |
+ } |
|
| 219 |
+ if interceptor == nil {
|
|
| 220 |
+ return srv.(HealthServer).Check(ctx, in) |
|
| 221 |
+ } |
|
| 222 |
+ info := &grpc.UnaryServerInfo{
|
|
| 223 |
+ Server: srv, |
|
| 224 |
+ FullMethod: "/docker.swarmkit.v1.Health/Check", |
|
| 225 |
+ } |
|
| 226 |
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
| 227 |
+ return srv.(HealthServer).Check(ctx, req.(*HealthCheckRequest)) |
|
| 228 |
+ } |
|
| 229 |
+ return interceptor(ctx, in, info, handler) |
|
| 230 |
+} |
|
| 231 |
+ |
|
| 232 |
+var _Health_serviceDesc = grpc.ServiceDesc{
|
|
| 233 |
+ ServiceName: "docker.swarmkit.v1.Health", |
|
| 234 |
+ HandlerType: (*HealthServer)(nil), |
|
| 235 |
+ Methods: []grpc.MethodDesc{
|
|
| 236 |
+ {
|
|
| 237 |
+ MethodName: "Check", |
|
| 238 |
+ Handler: _Health_Check_Handler, |
|
| 239 |
+ }, |
|
| 240 |
+ }, |
|
| 241 |
+ Streams: []grpc.StreamDesc{},
|
|
| 242 |
+} |
|
| 243 |
+ |
|
| 244 |
+func (m *HealthCheckRequest) Marshal() (data []byte, err error) {
|
|
| 245 |
+ size := m.Size() |
|
| 246 |
+ data = make([]byte, size) |
|
| 247 |
+ n, err := m.MarshalTo(data) |
|
| 248 |
+ if err != nil {
|
|
| 249 |
+ return nil, err |
|
| 250 |
+ } |
|
| 251 |
+ return data[:n], nil |
|
| 252 |
+} |
|
| 253 |
+ |
|
| 254 |
+func (m *HealthCheckRequest) MarshalTo(data []byte) (int, error) {
|
|
| 255 |
+ var i int |
|
| 256 |
+ _ = i |
|
| 257 |
+ var l int |
|
| 258 |
+ _ = l |
|
| 259 |
+ if len(m.Service) > 0 {
|
|
| 260 |
+ data[i] = 0xa |
|
| 261 |
+ i++ |
|
| 262 |
+ i = encodeVarintHealth(data, i, uint64(len(m.Service))) |
|
| 263 |
+ i += copy(data[i:], m.Service) |
|
| 264 |
+ } |
|
| 265 |
+ return i, nil |
|
| 266 |
+} |
|
| 267 |
+ |
|
| 268 |
+func (m *HealthCheckResponse) Marshal() (data []byte, err error) {
|
|
| 269 |
+ size := m.Size() |
|
| 270 |
+ data = make([]byte, size) |
|
| 271 |
+ n, err := m.MarshalTo(data) |
|
| 272 |
+ if err != nil {
|
|
| 273 |
+ return nil, err |
|
| 274 |
+ } |
|
| 275 |
+ return data[:n], nil |
|
| 276 |
+} |
|
| 277 |
+ |
|
| 278 |
+func (m *HealthCheckResponse) MarshalTo(data []byte) (int, error) {
|
|
| 279 |
+ var i int |
|
| 280 |
+ _ = i |
|
| 281 |
+ var l int |
|
| 282 |
+ _ = l |
|
| 283 |
+ if m.Status != 0 {
|
|
| 284 |
+ data[i] = 0x8 |
|
| 285 |
+ i++ |
|
| 286 |
+ i = encodeVarintHealth(data, i, uint64(m.Status)) |
|
| 287 |
+ } |
|
| 288 |
+ return i, nil |
|
| 289 |
+} |
|
| 290 |
+ |
|
| 291 |
+func encodeFixed64Health(data []byte, offset int, v uint64) int {
|
|
| 292 |
+ data[offset] = uint8(v) |
|
| 293 |
+ data[offset+1] = uint8(v >> 8) |
|
| 294 |
+ data[offset+2] = uint8(v >> 16) |
|
| 295 |
+ data[offset+3] = uint8(v >> 24) |
|
| 296 |
+ data[offset+4] = uint8(v >> 32) |
|
| 297 |
+ data[offset+5] = uint8(v >> 40) |
|
| 298 |
+ data[offset+6] = uint8(v >> 48) |
|
| 299 |
+ data[offset+7] = uint8(v >> 56) |
|
| 300 |
+ return offset + 8 |
|
| 301 |
+} |
|
| 302 |
+func encodeFixed32Health(data []byte, offset int, v uint32) int {
|
|
| 303 |
+ data[offset] = uint8(v) |
|
| 304 |
+ data[offset+1] = uint8(v >> 8) |
|
| 305 |
+ data[offset+2] = uint8(v >> 16) |
|
| 306 |
+ data[offset+3] = uint8(v >> 24) |
|
| 307 |
+ return offset + 4 |
|
| 308 |
+} |
|
| 309 |
+func encodeVarintHealth(data []byte, offset int, v uint64) int {
|
|
| 310 |
+ for v >= 1<<7 {
|
|
| 311 |
+ data[offset] = uint8(v&0x7f | 0x80) |
|
| 312 |
+ v >>= 7 |
|
| 313 |
+ offset++ |
|
| 314 |
+ } |
|
| 315 |
+ data[offset] = uint8(v) |
|
| 316 |
+ return offset + 1 |
|
| 317 |
+} |
|
| 318 |
+ |
|
| 319 |
+type raftProxyHealthServer struct {
|
|
| 320 |
+ local HealthServer |
|
| 321 |
+ connSelector *raftpicker.ConnSelector |
|
| 322 |
+ cluster raftpicker.RaftCluster |
|
| 323 |
+ ctxMods []func(context.Context) (context.Context, error) |
|
| 324 |
+} |
|
| 325 |
+ |
|
| 326 |
+func NewRaftProxyHealthServer(local HealthServer, connSelector *raftpicker.ConnSelector, cluster raftpicker.RaftCluster, ctxMod func(context.Context) (context.Context, error)) HealthServer {
|
|
| 327 |
+ redirectChecker := func(ctx context.Context) (context.Context, error) {
|
|
| 328 |
+ s, ok := transport.StreamFromContext(ctx) |
|
| 329 |
+ if !ok {
|
|
| 330 |
+ return ctx, grpc.Errorf(codes.InvalidArgument, "remote addr is not found in context") |
|
| 331 |
+ } |
|
| 332 |
+ addr := s.ServerTransport().RemoteAddr().String() |
|
| 333 |
+ md, ok := metadata.FromContext(ctx) |
|
| 334 |
+ if ok && len(md["redirect"]) != 0 {
|
|
| 335 |
+ return ctx, grpc.Errorf(codes.ResourceExhausted, "more than one redirect to leader from: %s", md["redirect"]) |
|
| 336 |
+ } |
|
| 337 |
+ if !ok {
|
|
| 338 |
+ md = metadata.New(map[string]string{})
|
|
| 339 |
+ } |
|
| 340 |
+ md["redirect"] = append(md["redirect"], addr) |
|
| 341 |
+ return metadata.NewContext(ctx, md), nil |
|
| 342 |
+ } |
|
| 343 |
+ mods := []func(context.Context) (context.Context, error){redirectChecker}
|
|
| 344 |
+ mods = append(mods, ctxMod) |
|
| 345 |
+ |
|
| 346 |
+ return &raftProxyHealthServer{
|
|
| 347 |
+ local: local, |
|
| 348 |
+ cluster: cluster, |
|
| 349 |
+ connSelector: connSelector, |
|
| 350 |
+ ctxMods: mods, |
|
| 351 |
+ } |
|
| 352 |
+} |
|
| 353 |
+func (p *raftProxyHealthServer) runCtxMods(ctx context.Context) (context.Context, error) {
|
|
| 354 |
+ var err error |
|
| 355 |
+ for _, mod := range p.ctxMods {
|
|
| 356 |
+ ctx, err = mod(ctx) |
|
| 357 |
+ if err != nil {
|
|
| 358 |
+ return ctx, err |
|
| 359 |
+ } |
|
| 360 |
+ } |
|
| 361 |
+ return ctx, nil |
|
| 362 |
+} |
|
| 363 |
+ |
|
| 364 |
+func (p *raftProxyHealthServer) Check(ctx context.Context, r *HealthCheckRequest) (*HealthCheckResponse, error) {
|
|
| 365 |
+ |
|
| 366 |
+ if p.cluster.IsLeader() {
|
|
| 367 |
+ return p.local.Check(ctx, r) |
|
| 368 |
+ } |
|
| 369 |
+ ctx, err := p.runCtxMods(ctx) |
|
| 370 |
+ if err != nil {
|
|
| 371 |
+ return nil, err |
|
| 372 |
+ } |
|
| 373 |
+ conn, err := p.connSelector.Conn() |
|
| 374 |
+ if err != nil {
|
|
| 375 |
+ return nil, err |
|
| 376 |
+ } |
|
| 377 |
+ return NewHealthClient(conn).Check(ctx, r) |
|
| 378 |
+} |
|
| 379 |
+ |
|
| 380 |
+func (m *HealthCheckRequest) Size() (n int) {
|
|
| 381 |
+ var l int |
|
| 382 |
+ _ = l |
|
| 383 |
+ l = len(m.Service) |
|
| 384 |
+ if l > 0 {
|
|
| 385 |
+ n += 1 + l + sovHealth(uint64(l)) |
|
| 386 |
+ } |
|
| 387 |
+ return n |
|
| 388 |
+} |
|
| 389 |
+ |
|
| 390 |
+func (m *HealthCheckResponse) Size() (n int) {
|
|
| 391 |
+ var l int |
|
| 392 |
+ _ = l |
|
| 393 |
+ if m.Status != 0 {
|
|
| 394 |
+ n += 1 + sovHealth(uint64(m.Status)) |
|
| 395 |
+ } |
|
| 396 |
+ return n |
|
| 397 |
+} |
|
| 398 |
+ |
|
| 399 |
+func sovHealth(x uint64) (n int) {
|
|
| 400 |
+ for {
|
|
| 401 |
+ n++ |
|
| 402 |
+ x >>= 7 |
|
| 403 |
+ if x == 0 {
|
|
| 404 |
+ break |
|
| 405 |
+ } |
|
| 406 |
+ } |
|
| 407 |
+ return n |
|
| 408 |
+} |
|
| 409 |
+func sozHealth(x uint64) (n int) {
|
|
| 410 |
+ return sovHealth(uint64((x << 1) ^ uint64((int64(x) >> 63)))) |
|
| 411 |
+} |
|
| 412 |
+func (this *HealthCheckRequest) String() string {
|
|
| 413 |
+ if this == nil {
|
|
| 414 |
+ return "nil" |
|
| 415 |
+ } |
|
| 416 |
+ s := strings.Join([]string{`&HealthCheckRequest{`,
|
|
| 417 |
+ `Service:` + fmt.Sprintf("%v", this.Service) + `,`,
|
|
| 418 |
+ `}`, |
|
| 419 |
+ }, "") |
|
| 420 |
+ return s |
|
| 421 |
+} |
|
| 422 |
+func (this *HealthCheckResponse) String() string {
|
|
| 423 |
+ if this == nil {
|
|
| 424 |
+ return "nil" |
|
| 425 |
+ } |
|
| 426 |
+ s := strings.Join([]string{`&HealthCheckResponse{`,
|
|
| 427 |
+ `Status:` + fmt.Sprintf("%v", this.Status) + `,`,
|
|
| 428 |
+ `}`, |
|
| 429 |
+ }, "") |
|
| 430 |
+ return s |
|
| 431 |
+} |
|
| 432 |
+func valueToStringHealth(v interface{}) string {
|
|
| 433 |
+ rv := reflect.ValueOf(v) |
|
| 434 |
+ if rv.IsNil() {
|
|
| 435 |
+ return "nil" |
|
| 436 |
+ } |
|
| 437 |
+ pv := reflect.Indirect(rv).Interface() |
|
| 438 |
+ return fmt.Sprintf("*%v", pv)
|
|
| 439 |
+} |
|
| 440 |
+func (m *HealthCheckRequest) Unmarshal(data []byte) error {
|
|
| 441 |
+ l := len(data) |
|
| 442 |
+ iNdEx := 0 |
|
| 443 |
+ for iNdEx < l {
|
|
| 444 |
+ preIndex := iNdEx |
|
| 445 |
+ var wire uint64 |
|
| 446 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 447 |
+ if shift >= 64 {
|
|
| 448 |
+ return ErrIntOverflowHealth |
|
| 449 |
+ } |
|
| 450 |
+ if iNdEx >= l {
|
|
| 451 |
+ return io.ErrUnexpectedEOF |
|
| 452 |
+ } |
|
| 453 |
+ b := data[iNdEx] |
|
| 454 |
+ iNdEx++ |
|
| 455 |
+ wire |= (uint64(b) & 0x7F) << shift |
|
| 456 |
+ if b < 0x80 {
|
|
| 457 |
+ break |
|
| 458 |
+ } |
|
| 459 |
+ } |
|
| 460 |
+ fieldNum := int32(wire >> 3) |
|
| 461 |
+ wireType := int(wire & 0x7) |
|
| 462 |
+ if wireType == 4 {
|
|
| 463 |
+ return fmt.Errorf("proto: HealthCheckRequest: wiretype end group for non-group")
|
|
| 464 |
+ } |
|
| 465 |
+ if fieldNum <= 0 {
|
|
| 466 |
+ return fmt.Errorf("proto: HealthCheckRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
|
| 467 |
+ } |
|
| 468 |
+ switch fieldNum {
|
|
| 469 |
+ case 1: |
|
| 470 |
+ if wireType != 2 {
|
|
| 471 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Service", wireType)
|
|
| 472 |
+ } |
|
| 473 |
+ var stringLen uint64 |
|
| 474 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 475 |
+ if shift >= 64 {
|
|
| 476 |
+ return ErrIntOverflowHealth |
|
| 477 |
+ } |
|
| 478 |
+ if iNdEx >= l {
|
|
| 479 |
+ return io.ErrUnexpectedEOF |
|
| 480 |
+ } |
|
| 481 |
+ b := data[iNdEx] |
|
| 482 |
+ iNdEx++ |
|
| 483 |
+ stringLen |= (uint64(b) & 0x7F) << shift |
|
| 484 |
+ if b < 0x80 {
|
|
| 485 |
+ break |
|
| 486 |
+ } |
|
| 487 |
+ } |
|
| 488 |
+ intStringLen := int(stringLen) |
|
| 489 |
+ if intStringLen < 0 {
|
|
| 490 |
+ return ErrInvalidLengthHealth |
|
| 491 |
+ } |
|
| 492 |
+ postIndex := iNdEx + intStringLen |
|
| 493 |
+ if postIndex > l {
|
|
| 494 |
+ return io.ErrUnexpectedEOF |
|
| 495 |
+ } |
|
| 496 |
+ m.Service = string(data[iNdEx:postIndex]) |
|
| 497 |
+ iNdEx = postIndex |
|
| 498 |
+ default: |
|
| 499 |
+ iNdEx = preIndex |
|
| 500 |
+ skippy, err := skipHealth(data[iNdEx:]) |
|
| 501 |
+ if err != nil {
|
|
| 502 |
+ return err |
|
| 503 |
+ } |
|
| 504 |
+ if skippy < 0 {
|
|
| 505 |
+ return ErrInvalidLengthHealth |
|
| 506 |
+ } |
|
| 507 |
+ if (iNdEx + skippy) > l {
|
|
| 508 |
+ return io.ErrUnexpectedEOF |
|
| 509 |
+ } |
|
| 510 |
+ iNdEx += skippy |
|
| 511 |
+ } |
|
| 512 |
+ } |
|
| 513 |
+ |
|
| 514 |
+ if iNdEx > l {
|
|
| 515 |
+ return io.ErrUnexpectedEOF |
|
| 516 |
+ } |
|
| 517 |
+ return nil |
|
| 518 |
+} |
|
| 519 |
+func (m *HealthCheckResponse) Unmarshal(data []byte) error {
|
|
| 520 |
+ l := len(data) |
|
| 521 |
+ iNdEx := 0 |
|
| 522 |
+ for iNdEx < l {
|
|
| 523 |
+ preIndex := iNdEx |
|
| 524 |
+ var wire uint64 |
|
| 525 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 526 |
+ if shift >= 64 {
|
|
| 527 |
+ return ErrIntOverflowHealth |
|
| 528 |
+ } |
|
| 529 |
+ if iNdEx >= l {
|
|
| 530 |
+ return io.ErrUnexpectedEOF |
|
| 531 |
+ } |
|
| 532 |
+ b := data[iNdEx] |
|
| 533 |
+ iNdEx++ |
|
| 534 |
+ wire |= (uint64(b) & 0x7F) << shift |
|
| 535 |
+ if b < 0x80 {
|
|
| 536 |
+ break |
|
| 537 |
+ } |
|
| 538 |
+ } |
|
| 539 |
+ fieldNum := int32(wire >> 3) |
|
| 540 |
+ wireType := int(wire & 0x7) |
|
| 541 |
+ if wireType == 4 {
|
|
| 542 |
+ return fmt.Errorf("proto: HealthCheckResponse: wiretype end group for non-group")
|
|
| 543 |
+ } |
|
| 544 |
+ if fieldNum <= 0 {
|
|
| 545 |
+ return fmt.Errorf("proto: HealthCheckResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
|
| 546 |
+ } |
|
| 547 |
+ switch fieldNum {
|
|
| 548 |
+ case 1: |
|
| 549 |
+ if wireType != 0 {
|
|
| 550 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType)
|
|
| 551 |
+ } |
|
| 552 |
+ m.Status = 0 |
|
| 553 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 554 |
+ if shift >= 64 {
|
|
| 555 |
+ return ErrIntOverflowHealth |
|
| 556 |
+ } |
|
| 557 |
+ if iNdEx >= l {
|
|
| 558 |
+ return io.ErrUnexpectedEOF |
|
| 559 |
+ } |
|
| 560 |
+ b := data[iNdEx] |
|
| 561 |
+ iNdEx++ |
|
| 562 |
+ m.Status |= (HealthCheckResponse_ServingStatus(b) & 0x7F) << shift |
|
| 563 |
+ if b < 0x80 {
|
|
| 564 |
+ break |
|
| 565 |
+ } |
|
| 566 |
+ } |
|
| 567 |
+ default: |
|
| 568 |
+ iNdEx = preIndex |
|
| 569 |
+ skippy, err := skipHealth(data[iNdEx:]) |
|
| 570 |
+ if err != nil {
|
|
| 571 |
+ return err |
|
| 572 |
+ } |
|
| 573 |
+ if skippy < 0 {
|
|
| 574 |
+ return ErrInvalidLengthHealth |
|
| 575 |
+ } |
|
| 576 |
+ if (iNdEx + skippy) > l {
|
|
| 577 |
+ return io.ErrUnexpectedEOF |
|
| 578 |
+ } |
|
| 579 |
+ iNdEx += skippy |
|
| 580 |
+ } |
|
| 581 |
+ } |
|
| 582 |
+ |
|
| 583 |
+ if iNdEx > l {
|
|
| 584 |
+ return io.ErrUnexpectedEOF |
|
| 585 |
+ } |
|
| 586 |
+ return nil |
|
| 587 |
+} |
|
| 588 |
+func skipHealth(data []byte) (n int, err error) {
|
|
| 589 |
+ l := len(data) |
|
| 590 |
+ iNdEx := 0 |
|
| 591 |
+ for iNdEx < l {
|
|
| 592 |
+ var wire uint64 |
|
| 593 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 594 |
+ if shift >= 64 {
|
|
| 595 |
+ return 0, ErrIntOverflowHealth |
|
| 596 |
+ } |
|
| 597 |
+ if iNdEx >= l {
|
|
| 598 |
+ return 0, io.ErrUnexpectedEOF |
|
| 599 |
+ } |
|
| 600 |
+ b := data[iNdEx] |
|
| 601 |
+ iNdEx++ |
|
| 602 |
+ wire |= (uint64(b) & 0x7F) << shift |
|
| 603 |
+ if b < 0x80 {
|
|
| 604 |
+ break |
|
| 605 |
+ } |
|
| 606 |
+ } |
|
| 607 |
+ wireType := int(wire & 0x7) |
|
| 608 |
+ switch wireType {
|
|
| 609 |
+ case 0: |
|
| 610 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 611 |
+ if shift >= 64 {
|
|
| 612 |
+ return 0, ErrIntOverflowHealth |
|
| 613 |
+ } |
|
| 614 |
+ if iNdEx >= l {
|
|
| 615 |
+ return 0, io.ErrUnexpectedEOF |
|
| 616 |
+ } |
|
| 617 |
+ iNdEx++ |
|
| 618 |
+ if data[iNdEx-1] < 0x80 {
|
|
| 619 |
+ break |
|
| 620 |
+ } |
|
| 621 |
+ } |
|
| 622 |
+ return iNdEx, nil |
|
| 623 |
+ case 1: |
|
| 624 |
+ iNdEx += 8 |
|
| 625 |
+ return iNdEx, nil |
|
| 626 |
+ case 2: |
|
| 627 |
+ var length int |
|
| 628 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 629 |
+ if shift >= 64 {
|
|
| 630 |
+ return 0, ErrIntOverflowHealth |
|
| 631 |
+ } |
|
| 632 |
+ if iNdEx >= l {
|
|
| 633 |
+ return 0, io.ErrUnexpectedEOF |
|
| 634 |
+ } |
|
| 635 |
+ b := data[iNdEx] |
|
| 636 |
+ iNdEx++ |
|
| 637 |
+ length |= (int(b) & 0x7F) << shift |
|
| 638 |
+ if b < 0x80 {
|
|
| 639 |
+ break |
|
| 640 |
+ } |
|
| 641 |
+ } |
|
| 642 |
+ iNdEx += length |
|
| 643 |
+ if length < 0 {
|
|
| 644 |
+ return 0, ErrInvalidLengthHealth |
|
| 645 |
+ } |
|
| 646 |
+ return iNdEx, nil |
|
| 647 |
+ case 3: |
|
| 648 |
+ for {
|
|
| 649 |
+ var innerWire uint64 |
|
| 650 |
+ var start int = iNdEx |
|
| 651 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 652 |
+ if shift >= 64 {
|
|
| 653 |
+ return 0, ErrIntOverflowHealth |
|
| 654 |
+ } |
|
| 655 |
+ if iNdEx >= l {
|
|
| 656 |
+ return 0, io.ErrUnexpectedEOF |
|
| 657 |
+ } |
|
| 658 |
+ b := data[iNdEx] |
|
| 659 |
+ iNdEx++ |
|
| 660 |
+ innerWire |= (uint64(b) & 0x7F) << shift |
|
| 661 |
+ if b < 0x80 {
|
|
| 662 |
+ break |
|
| 663 |
+ } |
|
| 664 |
+ } |
|
| 665 |
+ innerWireType := int(innerWire & 0x7) |
|
| 666 |
+ if innerWireType == 4 {
|
|
| 667 |
+ break |
|
| 668 |
+ } |
|
| 669 |
+ next, err := skipHealth(data[start:]) |
|
| 670 |
+ if err != nil {
|
|
| 671 |
+ return 0, err |
|
| 672 |
+ } |
|
| 673 |
+ iNdEx = start + next |
|
| 674 |
+ } |
|
| 675 |
+ return iNdEx, nil |
|
| 676 |
+ case 4: |
|
| 677 |
+ return iNdEx, nil |
|
| 678 |
+ case 5: |
|
| 679 |
+ iNdEx += 4 |
|
| 680 |
+ return iNdEx, nil |
|
| 681 |
+ default: |
|
| 682 |
+ return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
|
| 683 |
+ } |
|
| 684 |
+ } |
|
| 685 |
+ panic("unreachable")
|
|
| 686 |
+} |
|
| 687 |
+ |
|
| 688 |
+var ( |
|
| 689 |
+ ErrInvalidLengthHealth = fmt.Errorf("proto: negative length found during unmarshaling")
|
|
| 690 |
+ ErrIntOverflowHealth = fmt.Errorf("proto: integer overflow")
|
|
| 691 |
+) |
|
| 692 |
+ |
|
| 693 |
+var fileDescriptorHealth = []byte{
|
|
| 694 |
+ // 284 bytes of a gzipped FileDescriptorProto |
|
| 695 |
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0xc9, 0x48, 0x4d, 0xcc, |
|
| 696 |
+ 0x29, 0xc9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x4a, 0xc9, 0x4f, 0xce, 0x4e, 0x2d, |
|
| 697 |
+ 0xd2, 0x2b, 0x2e, 0x4f, 0x2c, 0xca, 0xcd, 0xce, 0x2c, 0xd1, 0x2b, 0x33, 0x94, 0x12, 0x49, 0xcf, |
|
| 698 |
+ 0x4f, 0xcf, 0x07, 0x4b, 0xeb, 0x83, 0x58, 0x10, 0x95, 0x52, 0xc2, 0x05, 0x39, 0xa5, 0xe9, 0x99, |
|
| 699 |
+ 0x79, 0xfa, 0x10, 0x0a, 0x22, 0xa8, 0xa4, 0xc7, 0x25, 0xe4, 0x01, 0x36, 0xce, 0x39, 0x23, 0x35, |
|
| 700 |
+ 0x39, 0x3b, 0x28, 0xb5, 0xb0, 0x34, 0xb5, 0xb8, 0x44, 0x48, 0x82, 0x8b, 0xbd, 0x38, 0xb5, 0xa8, |
|
| 701 |
+ 0x2c, 0x33, 0x39, 0x55, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x08, 0xc6, 0x55, 0x5a, 0xc0, 0xc8, |
|
| 702 |
+ 0x25, 0x8c, 0xa2, 0xa1, 0xb8, 0x20, 0x3f, 0xaf, 0x38, 0x55, 0xc8, 0x97, 0x8b, 0xad, 0xb8, 0x24, |
|
| 703 |
+ 0xb1, 0xa4, 0xb4, 0x18, 0xac, 0x81, 0xcf, 0xc8, 0x54, 0x0f, 0xd3, 0x5d, 0x7a, 0x58, 0x34, 0xea, |
|
| 704 |
+ 0x05, 0x83, 0x0c, 0xce, 0x4b, 0x0f, 0x06, 0x6b, 0x0e, 0x82, 0x1a, 0xa2, 0x64, 0xc5, 0xc5, 0x8b, |
|
| 705 |
+ 0x22, 0x21, 0xc4, 0xcd, 0xc5, 0x1e, 0xea, 0xe7, 0xed, 0xe7, 0x1f, 0xee, 0x27, 0xc0, 0x00, 0xe2, |
|
| 706 |
+ 0x04, 0xbb, 0x06, 0x85, 0x79, 0xfa, 0xb9, 0x0b, 0x30, 0x0a, 0xf1, 0x73, 0x71, 0xfb, 0xf9, 0x87, |
|
| 707 |
+ 0xc4, 0xc3, 0x04, 0x98, 0x8c, 0x2a, 0xb9, 0xd8, 0x20, 0x16, 0x09, 0xe5, 0x73, 0xb1, 0x82, 0x2d, |
|
| 708 |
+ 0x13, 0x52, 0x23, 0xe8, 0x1a, 0xb0, 0xbf, 0xa5, 0xd4, 0x89, 0x74, 0xb5, 0x92, 0xe8, 0xa9, 0x75, |
|
| 709 |
+ 0xef, 0x66, 0x30, 0xf1, 0x73, 0xf1, 0x82, 0x15, 0xea, 0xe6, 0x26, 0xe6, 0x25, 0xa6, 0xa7, 0x16, |
|
| 710 |
+ 0x39, 0xc9, 0x9c, 0x78, 0x28, 0xc7, 0x70, 0x03, 0x88, 0x3f, 0x3c, 0x94, 0x63, 0x6c, 0x78, 0x24, |
|
| 711 |
+ 0xc7, 0x78, 0x02, 0x88, 0x2f, 0x00, 0xf1, 0x03, 0x20, 0x4e, 0x62, 0x03, 0x07, 0xb9, 0x31, 0x20, |
|
| 712 |
+ 0x00, 0x00, 0xff, 0xff, 0xf7, 0x14, 0x7c, 0x23, 0xc1, 0x01, 0x00, 0x00, |
|
| 713 |
+} |
| 0 | 714 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,34 @@ |
| 0 |
+syntax = "proto3"; |
|
| 1 |
+ |
|
| 2 |
+// See: https://github.com/grpc/grpc-go/blob/master/health/grpc_health_v1/health.proto |
|
| 3 |
+// |
|
| 4 |
+// We use the same health check service proto description defined in the gRPC documentation, |
|
| 5 |
+// including the authorization check. This requires our own implementation of the health |
|
| 6 |
+// package located in `manager/health`. |
|
| 7 |
+// |
|
| 8 |
+// For more infos, refer to: |
|
| 9 |
+// https://github.com/grpc/grpc/blob/master/doc/health-checking.md |
|
| 10 |
+ |
|
| 11 |
+package docker.swarmkit.v1; |
|
| 12 |
+ |
|
| 13 |
+import "gogoproto/gogo.proto"; |
|
| 14 |
+import "plugin/plugin.proto"; |
|
| 15 |
+ |
|
| 16 |
+service Health {
|
|
| 17 |
+ rpc Check(HealthCheckRequest) returns (HealthCheckResponse) {
|
|
| 18 |
+ option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-manager" };
|
|
| 19 |
+ }; |
|
| 20 |
+} |
|
| 21 |
+ |
|
| 22 |
+message HealthCheckRequest {
|
|
| 23 |
+ string service = 1; |
|
| 24 |
+} |
|
| 25 |
+ |
|
| 26 |
+message HealthCheckResponse {
|
|
| 27 |
+ enum ServingStatus {
|
|
| 28 |
+ UNKNOWN = 0; |
|
| 29 |
+ SERVING = 1; |
|
| 30 |
+ NOT_SERVING = 2; |
|
| 31 |
+ } |
|
| 32 |
+ ServingStatus status = 1; |
|
| 33 |
+} |
| ... | ... |
@@ -90,8 +90,13 @@ func (*JoinRequest) ProtoMessage() {}
|
| 90 | 90 |
func (*JoinRequest) Descriptor() ([]byte, []int) { return fileDescriptorRaft, []int{1} }
|
| 91 | 91 |
|
| 92 | 92 |
type JoinResponse struct {
|
| 93 |
- RaftID uint64 `protobuf:"varint,1,opt,name=raft_id,json=raftId,proto3" json:"raft_id,omitempty"` |
|
| 93 |
+ // RaftID is the ID assigned to the new member. |
|
| 94 |
+ RaftID uint64 `protobuf:"varint,1,opt,name=raft_id,json=raftId,proto3" json:"raft_id,omitempty"` |
|
| 95 |
+ // Members is the membership set of the cluster. |
|
| 94 | 96 |
Members []*RaftMember `protobuf:"bytes,2,rep,name=members" json:"members,omitempty"` |
| 97 |
+ // RemovedMembers is a list of members that have been removed from |
|
| 98 |
+ // the cluster, so the new node can avoid communicating with them. |
|
| 99 |
+ RemovedMembers []uint64 `protobuf:"varint,3,rep,name=removed_members,json=removedMembers" json:"removed_members,omitempty"` |
|
| 95 | 100 |
} |
| 96 | 101 |
|
| 97 | 102 |
func (m *JoinResponse) Reset() { *m = JoinResponse{} }
|
| ... | ... |
@@ -489,6 +494,13 @@ func (m *JoinResponse) Copy() *JoinResponse {
|
| 489 | 489 |
} |
| 490 | 490 |
} |
| 491 | 491 |
|
| 492 |
+ if m.RemovedMembers != nil {
|
|
| 493 |
+ o.RemovedMembers = make([]uint64, 0, len(m.RemovedMembers)) |
|
| 494 |
+ for _, v := range m.RemovedMembers {
|
|
| 495 |
+ o.RemovedMembers = append(o.RemovedMembers, v) |
|
| 496 |
+ } |
|
| 497 |
+ } |
|
| 498 |
+ |
|
| 492 | 499 |
return o |
| 493 | 500 |
} |
| 494 | 501 |
|
| ... | ... |
@@ -639,12 +651,13 @@ func (this *JoinResponse) GoString() string {
|
| 639 | 639 |
if this == nil {
|
| 640 | 640 |
return "nil" |
| 641 | 641 |
} |
| 642 |
- s := make([]string, 0, 6) |
|
| 642 |
+ s := make([]string, 0, 7) |
|
| 643 | 643 |
s = append(s, "&api.JoinResponse{")
|
| 644 | 644 |
s = append(s, "RaftID: "+fmt.Sprintf("%#v", this.RaftID)+",\n")
|
| 645 | 645 |
if this.Members != nil {
|
| 646 | 646 |
s = append(s, "Members: "+fmt.Sprintf("%#v", this.Members)+",\n")
|
| 647 | 647 |
} |
| 648 |
+ s = append(s, "RemovedMembers: "+fmt.Sprintf("%#v", this.RemovedMembers)+",\n")
|
|
| 648 | 649 |
s = append(s, "}") |
| 649 | 650 |
return strings.Join(s, "") |
| 650 | 651 |
} |
| ... | ... |
@@ -1111,6 +1124,13 @@ func (m *JoinResponse) MarshalTo(data []byte) (int, error) {
|
| 1111 | 1111 |
i += n |
| 1112 | 1112 |
} |
| 1113 | 1113 |
} |
| 1114 |
+ if len(m.RemovedMembers) > 0 {
|
|
| 1115 |
+ for _, num := range m.RemovedMembers {
|
|
| 1116 |
+ data[i] = 0x18 |
|
| 1117 |
+ i++ |
|
| 1118 |
+ i = encodeVarintRaft(data, i, uint64(num)) |
|
| 1119 |
+ } |
|
| 1120 |
+ } |
|
| 1114 | 1121 |
return i, nil |
| 1115 | 1122 |
} |
| 1116 | 1123 |
|
| ... | ... |
@@ -1611,6 +1631,11 @@ func (m *JoinResponse) Size() (n int) {
|
| 1611 | 1611 |
n += 1 + l + sovRaft(uint64(l)) |
| 1612 | 1612 |
} |
| 1613 | 1613 |
} |
| 1614 |
+ if len(m.RemovedMembers) > 0 {
|
|
| 1615 |
+ for _, e := range m.RemovedMembers {
|
|
| 1616 |
+ n += 1 + sovRaft(uint64(e)) |
|
| 1617 |
+ } |
|
| 1618 |
+ } |
|
| 1614 | 1619 |
return n |
| 1615 | 1620 |
} |
| 1616 | 1621 |
|
| ... | ... |
@@ -1781,6 +1806,7 @@ func (this *JoinResponse) String() string {
|
| 1781 | 1781 |
s := strings.Join([]string{`&JoinResponse{`,
|
| 1782 | 1782 |
`RaftID:` + fmt.Sprintf("%v", this.RaftID) + `,`,
|
| 1783 | 1783 |
`Members:` + strings.Replace(fmt.Sprintf("%v", this.Members), "RaftMember", "RaftMember", 1) + `,`,
|
| 1784 |
+ `RemovedMembers:` + fmt.Sprintf("%v", this.RemovedMembers) + `,`,
|
|
| 1784 | 1785 |
`}`, |
| 1785 | 1786 |
}, "") |
| 1786 | 1787 |
return s |
| ... | ... |
@@ -2238,6 +2264,26 @@ func (m *JoinResponse) Unmarshal(data []byte) error {
|
| 2238 | 2238 |
return err |
| 2239 | 2239 |
} |
| 2240 | 2240 |
iNdEx = postIndex |
| 2241 |
+ case 3: |
|
| 2242 |
+ if wireType != 0 {
|
|
| 2243 |
+ return fmt.Errorf("proto: wrong wireType = %d for field RemovedMembers", wireType)
|
|
| 2244 |
+ } |
|
| 2245 |
+ var v uint64 |
|
| 2246 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 2247 |
+ if shift >= 64 {
|
|
| 2248 |
+ return ErrIntOverflowRaft |
|
| 2249 |
+ } |
|
| 2250 |
+ if iNdEx >= l {
|
|
| 2251 |
+ return io.ErrUnexpectedEOF |
|
| 2252 |
+ } |
|
| 2253 |
+ b := data[iNdEx] |
|
| 2254 |
+ iNdEx++ |
|
| 2255 |
+ v |= (uint64(b) & 0x7F) << shift |
|
| 2256 |
+ if b < 0x80 {
|
|
| 2257 |
+ break |
|
| 2258 |
+ } |
|
| 2259 |
+ } |
|
| 2260 |
+ m.RemovedMembers = append(m.RemovedMembers, v) |
|
| 2241 | 2261 |
default: |
| 2242 | 2262 |
iNdEx = preIndex |
| 2243 | 2263 |
skippy, err := skipRaft(data[iNdEx:]) |
| ... | ... |
@@ -3108,58 +3154,59 @@ var ( |
| 3108 | 3108 |
) |
| 3109 | 3109 |
|
| 3110 | 3110 |
var fileDescriptorRaft = []byte{
|
| 3111 |
- // 833 bytes of a gzipped FileDescriptorProto |
|
| 3112 |
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x95, 0x4d, 0x53, 0xdb, 0x46, |
|
| 3113 |
- 0x18, 0xc7, 0x2d, 0x59, 0xc8, 0xed, 0x9a, 0xb7, 0x59, 0x0a, 0x35, 0x2a, 0x63, 0x40, 0x74, 0xa6, |
|
| 3114 |
- 0x85, 0x29, 0xf2, 0xd4, 0x3d, 0xb4, 0xd3, 0xf6, 0x62, 0x1b, 0xcf, 0xd4, 0x05, 0x6c, 0x46, 0xd8, |
|
| 3115 |
- 0x2d, 0x37, 0x2a, 0x4b, 0x8b, 0x51, 0x6d, 0x6b, 0x5d, 0xed, 0xda, 0x4c, 0x2f, 0x19, 0x8e, 0x19, |
|
| 3116 |
- 0xae, 0x39, 0x24, 0x97, 0x9c, 0x92, 0x33, 0x1f, 0x20, 0x9f, 0x80, 0xc9, 0x29, 0xb7, 0xe4, 0x44, |
|
| 3117 |
- 0x02, 0x1f, 0x20, 0xc9, 0x47, 0xc8, 0xae, 0x5e, 0x0c, 0x31, 0xb2, 0xf1, 0x41, 0xb0, 0xec, 0xfe, |
|
| 3118 |
- 0xfe, 0xcf, 0xff, 0xd9, 0x67, 0xf7, 0x59, 0x00, 0x70, 0x8d, 0x23, 0xaa, 0x75, 0x5c, 0x4c, 0x31, |
|
| 3119 |
- 0x84, 0x16, 0x36, 0x9b, 0xc8, 0xd5, 0xc8, 0x89, 0xe1, 0xb6, 0x9b, 0x36, 0xd5, 0x7a, 0x3f, 0x2a, |
|
| 3120 |
- 0x53, 0xb8, 0xfe, 0x2f, 0x32, 0x29, 0xf1, 0x11, 0x25, 0x49, 0xff, 0xef, 0xa0, 0xf0, 0x8f, 0xcd, |
|
| 3121 |
- 0x86, 0x4d, 0x8f, 0xbb, 0x75, 0xcd, 0xc4, 0xed, 0x8c, 0x89, 0x5d, 0x84, 0x49, 0x06, 0x51, 0xd3, |
|
| 3122 |
- 0xca, 0xf0, 0x90, 0xde, 0x8f, 0x4e, 0x3d, 0x73, 0x13, 0x5e, 0xf9, 0xaa, 0x81, 0x1b, 0xd8, 0x1b, |
|
| 3123 |
- 0x66, 0xf8, 0x28, 0x98, 0x9d, 0xeb, 0xb4, 0xba, 0x0d, 0xdb, 0xc9, 0xf8, 0xbf, 0xfc, 0x49, 0xf5, |
|
| 3124 |
- 0x5c, 0x00, 0x40, 0x67, 0xca, 0x5d, 0xd4, 0xae, 0x23, 0x17, 0xae, 0x81, 0x04, 0x8f, 0x73, 0x68, |
|
| 3125 |
- 0x5b, 0x29, 0x61, 0x45, 0xf8, 0x5e, 0xca, 0x83, 0xeb, 0xcb, 0x65, 0x99, 0x03, 0xa5, 0x2d, 0x5d, |
|
| 3126 |
- 0xe6, 0x4b, 0x25, 0x8b, 0x43, 0x0e, 0xb6, 0x10, 0x87, 0x44, 0x06, 0x7d, 0xe9, 0x43, 0x65, 0x36, |
|
| 3127 |
- 0xc5, 0x21, 0xbe, 0xc4, 0x20, 0x08, 0x24, 0xc3, 0xb2, 0xdc, 0x54, 0x9c, 0x13, 0xba, 0x37, 0x86, |
|
| 3128 |
- 0x79, 0x20, 0x13, 0x6a, 0xd0, 0x2e, 0x49, 0x49, 0x6c, 0x36, 0x99, 0xfd, 0x56, 0xbb, 0x5b, 0x07, |
|
| 3129 |
- 0xed, 0x26, 0x9b, 0x7d, 0x8f, 0xcd, 0x4b, 0x17, 0x97, 0xcb, 0x31, 0x3d, 0x50, 0xaa, 0xab, 0x20, |
|
| 3130 |
- 0xf9, 0x27, 0xb6, 0x1d, 0x1d, 0xfd, 0xd7, 0x45, 0x84, 0xf6, 0x6d, 0x84, 0x1b, 0x1b, 0xb5, 0x0d, |
|
| 3131 |
- 0x26, 0x7d, 0x84, 0x74, 0xb0, 0x43, 0xd0, 0x78, 0x9b, 0xfa, 0x05, 0x24, 0xda, 0x9e, 0x2b, 0x61, |
|
| 3132 |
- 0x9b, 0x8a, 0xb3, 0xe4, 0xd2, 0xa3, 0x93, 0xd3, 0x43, 0x5c, 0xcd, 0x83, 0xc9, 0x1d, 0x64, 0xf4, |
|
| 3133 |
- 0x50, 0x98, 0x52, 0x16, 0x48, 0xbc, 0x06, 0x9e, 0xd7, 0xfd, 0x61, 0x3c, 0x56, 0x9d, 0x01, 0x53, |
|
| 3134 |
- 0x41, 0x0c, 0x3f, 0x67, 0x75, 0x07, 0x2c, 0xee, 0xb9, 0xd8, 0x44, 0x84, 0xf8, 0x2c, 0x21, 0x46, |
|
| 3135 |
- 0xa3, 0xef, 0xb0, 0xce, 0x73, 0xf5, 0x66, 0x02, 0x93, 0x19, 0xcd, 0xbf, 0x04, 0x5a, 0x08, 0x86, |
|
| 3136 |
- 0xeb, 0xbf, 0x4a, 0xa7, 0x8f, 0xd5, 0x98, 0xba, 0x04, 0x94, 0xa8, 0x68, 0x81, 0xd7, 0xef, 0x60, |
|
| 3137 |
- 0x9e, 0x8d, 0x71, 0xab, 0x87, 0x72, 0xac, 0x7c, 0x1c, 0x0a, 0x7c, 0xc6, 0x29, 0x9c, 0xfa, 0x03, |
|
| 3138 |
- 0x58, 0x18, 0x54, 0x07, 0x75, 0x8f, 0x3a, 0x9b, 0x23, 0x30, 0x57, 0x72, 0x28, 0x72, 0x1d, 0xa3, |
|
| 3139 |
- 0xc5, 0xe3, 0x84, 0x4e, 0x0b, 0x40, 0xec, 0x9b, 0xc8, 0xcc, 0x44, 0x64, 0x06, 0x6c, 0x06, 0xfe, |
|
| 3140 |
- 0x0c, 0x64, 0xc3, 0xa4, 0x36, 0x76, 0x82, 0x43, 0x59, 0x8e, 0xaa, 0xe6, 0x3e, 0x65, 0x2d, 0x91, |
|
| 3141 |
- 0xf3, 0x30, 0x3d, 0xc0, 0xd5, 0xb7, 0x22, 0x48, 0xde, 0x9a, 0x87, 0xbf, 0xf5, 0x03, 0x71, 0x93, |
|
| 3142 |
- 0xe9, 0xec, 0xda, 0x3d, 0x81, 0xb6, 0x6d, 0xc7, 0x0a, 0x83, 0x41, 0x2d, 0x38, 0x51, 0xd1, 0x2b, |
|
| 3143 |
- 0x76, 0x2a, 0x4a, 0xca, 0x6f, 0xff, 0x1f, 0x31, 0xff, 0x34, 0x59, 0xd6, 0x09, 0x82, 0xdc, 0x9e, |
|
| 3144 |
- 0x6d, 0x22, 0xef, 0xfa, 0x27, 0xb3, 0xdf, 0x44, 0xba, 0xf9, 0x08, 0x53, 0x85, 0x34, 0x37, 0xa2, |
|
| 3145 |
- 0x06, 0x69, 0x06, 0xed, 0x11, 0x69, 0x54, 0x65, 0xeb, 0xdc, 0x88, 0x73, 0xdc, 0xc8, 0x41, 0xf4, |
|
| 3146 |
- 0x04, 0xbb, 0xcd, 0xd4, 0xc4, 0x70, 0xa3, 0xb2, 0x8f, 0x70, 0xa3, 0x80, 0xe6, 0x42, 0xb3, 0xd5, |
|
| 3147 |
- 0x25, 0xec, 0x20, 0x52, 0xf2, 0x70, 0x61, 0xc1, 0x47, 0xb8, 0x30, 0xa0, 0xf3, 0x5f, 0x00, 0x99, |
|
| 3148 |
- 0x1a, 0x6e, 0x03, 0xd1, 0x8d, 0x0f, 0x02, 0x98, 0x19, 0x28, 0x18, 0xfc, 0x0e, 0x24, 0x6a, 0xe5, |
|
| 3149 |
- 0xed, 0x72, 0xe5, 0xef, 0xf2, 0x6c, 0x4c, 0x51, 0xce, 0x9e, 0xae, 0x2c, 0x0c, 0x10, 0x35, 0xa7, |
|
| 3150 |
- 0xe9, 0xe0, 0x13, 0x87, 0xf5, 0xc8, 0xdc, 0x7e, 0xb5, 0xa2, 0x17, 0x0f, 0x73, 0x85, 0x6a, 0xa9, |
|
| 3151 |
- 0x52, 0x3e, 0x2c, 0xe8, 0xc5, 0x5c, 0xb5, 0x38, 0x2b, 0x28, 0x8b, 0x4c, 0x34, 0x3f, 0x20, 0x2a, |
|
| 3152 |
- 0xb8, 0xc8, 0xa0, 0xe8, 0x8e, 0xa6, 0xb6, 0xb7, 0xc5, 0x35, 0x62, 0xa4, 0xa6, 0xd6, 0xb1, 0xa2, |
|
| 3153 |
- 0x34, 0x7a, 0x71, 0xb7, 0xf2, 0x57, 0x71, 0x36, 0x1e, 0xa9, 0xd1, 0x51, 0x1b, 0xf7, 0x90, 0xf2, |
|
| 3154 |
- 0xf5, 0xc3, 0x67, 0xe9, 0xd8, 0x8b, 0xe7, 0xe9, 0xc1, 0xdd, 0x65, 0x1f, 0x89, 0x40, 0xe2, 0x97, |
|
| 3155 |
- 0x16, 0x9e, 0x09, 0x00, 0xde, 0xed, 0x27, 0xb8, 0x19, 0x55, 0xc3, 0xa1, 0x5d, 0xac, 0x68, 0xe3, |
|
| 3156 |
- 0xe2, 0x41, 0x9b, 0xce, 0xbf, 0x3c, 0x7f, 0xff, 0x44, 0x64, 0x2f, 0x85, 0xc7, 0x6f, 0xb6, 0x0d, |
|
| 3157 |
- 0x87, 0xad, 0xba, 0xf0, 0x01, 0x98, 0xfe, 0xbc, 0xff, 0xe0, 0x7a, 0xe4, 0x93, 0x13, 0xd5, 0xe1, |
|
| 3158 |
- 0xca, 0xc6, 0x38, 0xe8, 0x48, 0xff, 0xec, 0x6b, 0x81, 0x25, 0xd0, 0x7f, 0xcf, 0xc8, 0xb1, 0xdd, |
|
| 3159 |
- 0x81, 0xff, 0x00, 0x89, 0x3f, 0xc0, 0x30, 0xb2, 0x5b, 0x6f, 0xbd, 0xde, 0xca, 0xca, 0x70, 0x60, |
|
| 3160 |
- 0xf4, 0xa6, 0x4d, 0x30, 0xe1, 0xbd, 0x97, 0x30, 0x32, 0xc2, 0xed, 0xe7, 0x58, 0x59, 0x1d, 0x41, |
|
| 3161 |
- 0x8c, 0x34, 0xc9, 0x2f, 0x5d, 0x5c, 0xa5, 0x63, 0x6f, 0xd8, 0xf7, 0xf1, 0x2a, 0x2d, 0x9c, 0x5e, |
|
| 3162 |
- 0xa7, 0x85, 0x0b, 0xf6, 0xbd, 0x62, 0xdf, 0x3b, 0xf6, 0x1d, 0xc4, 0x0f, 0xa4, 0xba, 0xec, 0xfd, |
|
| 3163 |
- 0x13, 0xfd, 0xe9, 0x53, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa4, 0xfb, 0x14, 0x74, 0xdc, 0x07, 0x00, |
|
| 3164 |
- 0x00, |
|
| 3111 |
+ // 852 bytes of a gzipped FileDescriptorProto |
|
| 3112 |
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x95, 0x4f, 0x53, 0x23, 0x45, |
|
| 3113 |
+ 0x18, 0xc6, 0x33, 0x93, 0x61, 0xa2, 0x1d, 0x20, 0x54, 0x23, 0x18, 0x46, 0x2a, 0xc0, 0x60, 0x95, |
|
| 3114 |
+ 0x42, 0xc9, 0xa4, 0x8c, 0x07, 0x2d, 0xf5, 0x92, 0x84, 0x54, 0x19, 0x81, 0x84, 0x1a, 0x12, 0xe5, |
|
| 3115 |
+ 0x16, 0x27, 0x33, 0x4d, 0x18, 0x93, 0x4c, 0xc7, 0xe9, 0x4e, 0x28, 0x2f, 0x16, 0x47, 0x8b, 0xab, |
|
| 3116 |
+ 0x55, 0xea, 0xc5, 0x93, 0x9e, 0xf9, 0x00, 0x7e, 0x02, 0x6a, 0x4f, 0x7b, 0xdb, 0x3d, 0xb1, 0x0b, |
|
| 3117 |
+ 0x1f, 0x60, 0x77, 0x3f, 0xc2, 0x76, 0xcf, 0x9f, 0xc0, 0x86, 0x49, 0xc8, 0xa1, 0xa1, 0x79, 0xfb, |
|
| 3118 |
+ 0xf7, 0xbc, 0x4f, 0xf7, 0xdb, 0xf3, 0x36, 0x00, 0xb8, 0xc6, 0x09, 0xd5, 0x7a, 0x2e, 0xa6, 0x18, |
|
| 3119 |
+ 0x42, 0x0b, 0x9b, 0x6d, 0xe4, 0x6a, 0xe4, 0xcc, 0x70, 0xbb, 0x6d, 0x9b, 0x6a, 0x83, 0xcf, 0x95, |
|
| 3120 |
+ 0x39, 0xdc, 0xfc, 0x19, 0x99, 0x94, 0xf8, 0x88, 0x92, 0xa4, 0xbf, 0xf6, 0x50, 0xf8, 0xc7, 0x4e, |
|
| 3121 |
+ 0xcb, 0xa6, 0xa7, 0xfd, 0xa6, 0x66, 0xe2, 0x6e, 0xd6, 0xc4, 0x2e, 0xc2, 0x24, 0x8b, 0xa8, 0x69, |
|
| 3122 |
+ 0x65, 0x79, 0x4a, 0xef, 0x47, 0xaf, 0x99, 0xbd, 0x4b, 0xaf, 0x7c, 0xd0, 0xc2, 0x2d, 0xec, 0x4d, |
|
| 3123 |
+ 0xb3, 0x7c, 0x16, 0x44, 0x17, 0x7b, 0x9d, 0x7e, 0xcb, 0x76, 0xb2, 0xfe, 0x2f, 0x3f, 0xa8, 0x5e, |
|
| 3124 |
+ 0x0a, 0x00, 0xe8, 0x4c, 0x79, 0x80, 0xba, 0x4d, 0xe4, 0xc2, 0x4d, 0x90, 0xe0, 0x79, 0x1a, 0xb6, |
|
| 3125 |
+ 0x95, 0x16, 0xd6, 0x85, 0x4f, 0xa5, 0x02, 0xb8, 0xbd, 0x5e, 0x93, 0x39, 0x50, 0xde, 0xd5, 0x65, |
|
| 3126 |
+ 0xbe, 0x54, 0xb6, 0x38, 0xe4, 0x60, 0x0b, 0x71, 0x48, 0x64, 0xd0, 0xfb, 0x3e, 0x54, 0x61, 0x21, |
|
| 3127 |
+ 0x0e, 0xf1, 0x25, 0x06, 0x41, 0x20, 0x19, 0x96, 0xe5, 0xa6, 0xe3, 0x9c, 0xd0, 0xbd, 0x39, 0x2c, |
|
| 3128 |
+ 0x00, 0x99, 0x50, 0x83, 0xf6, 0x49, 0x5a, 0x62, 0xd1, 0x64, 0xee, 0x63, 0xed, 0x61, 0x1d, 0xb4, |
|
| 3129 |
+ 0xbb, 0xdd, 0x1c, 0x79, 0x6c, 0x41, 0xba, 0xba, 0x5e, 0x8b, 0xe9, 0x81, 0x52, 0xdd, 0x00, 0xc9, |
|
| 3130 |
+ 0xef, 0xb1, 0xed, 0xe8, 0xe8, 0x97, 0x3e, 0x22, 0x74, 0x68, 0x23, 0xdc, 0xd9, 0xa8, 0x7f, 0x0a, |
|
| 3131 |
+ 0x60, 0xd6, 0x67, 0x48, 0x0f, 0x3b, 0x04, 0x4d, 0x77, 0xaa, 0xaf, 0x40, 0xa2, 0xeb, 0xd9, 0x12, |
|
| 3132 |
+ 0x76, 0xaa, 0x38, 0xdb, 0x5d, 0x66, 0xf2, 0xee, 0xf4, 0x10, 0x87, 0x9f, 0x80, 0x94, 0x8b, 0xba, |
|
| 3133 |
+ 0x78, 0x80, 0xac, 0x46, 0x98, 0x21, 0xce, 0x32, 0x48, 0xfa, 0x7c, 0x10, 0xf6, 0x05, 0x44, 0x2d, |
|
| 3134 |
+ 0x80, 0xd9, 0x7d, 0x64, 0x0c, 0x50, 0xb8, 0xf9, 0x1c, 0x90, 0x78, 0xb5, 0xbc, 0x4d, 0x3d, 0xee, |
|
| 3135 |
+ 0xe7, 0xb1, 0x6a, 0x0a, 0xcc, 0x05, 0x39, 0xfc, 0xc3, 0xa9, 0xfb, 0x60, 0xe5, 0xd0, 0xc5, 0x26, |
|
| 3136 |
+ 0x22, 0xc4, 0x67, 0x09, 0x31, 0x5a, 0x43, 0x87, 0x2d, 0x7e, 0x28, 0x2f, 0x12, 0x98, 0xa4, 0x34, |
|
| 3137 |
+ 0xff, 0x73, 0xd1, 0x42, 0x30, 0x5c, 0xff, 0x5a, 0x3a, 0xff, 0x4b, 0x8d, 0xa9, 0xab, 0x40, 0x89, |
|
| 3138 |
+ 0xca, 0x16, 0x78, 0x7d, 0x0b, 0x96, 0xd8, 0x1c, 0x77, 0x06, 0x28, 0xcf, 0x0a, 0xcd, 0xa1, 0xc0, |
|
| 3139 |
+ 0x67, 0x9a, 0x0a, 0xab, 0x9f, 0x81, 0xe5, 0x51, 0x75, 0x70, 0x41, 0x51, 0xb7, 0x78, 0x02, 0x16, |
|
| 3140 |
+ 0xcb, 0x0e, 0x45, 0xae, 0x63, 0x74, 0x78, 0x9e, 0xd0, 0x69, 0x19, 0x88, 0x43, 0x13, 0x99, 0x99, |
|
| 3141 |
+ 0x88, 0xcc, 0x80, 0x45, 0xe0, 0x97, 0x40, 0x36, 0x4c, 0x6a, 0x63, 0x27, 0xb8, 0xbd, 0xb5, 0xa8, |
|
| 3142 |
+ 0x6a, 0x1e, 0x51, 0xd6, 0x3c, 0x79, 0x0f, 0xd3, 0x03, 0x5c, 0x7d, 0x21, 0x82, 0xe4, 0xbd, 0x38, |
|
| 3143 |
+ 0xfc, 0x66, 0x98, 0x88, 0x9b, 0xcc, 0xe7, 0x36, 0x1f, 0x49, 0xb4, 0x67, 0x3b, 0x56, 0x98, 0x0c, |
|
| 3144 |
+ 0x6a, 0xc1, 0x8d, 0x8a, 0x5e, 0xb1, 0xd3, 0x51, 0x52, 0xde, 0x27, 0xdf, 0xc5, 0xfc, 0xdb, 0x64, |
|
| 3145 |
+ 0xbb, 0x4e, 0x10, 0xe4, 0x0e, 0x6c, 0x13, 0x79, 0x8d, 0x92, 0xcc, 0x7d, 0x14, 0xe9, 0xe6, 0x23, |
|
| 3146 |
+ 0x4c, 0x15, 0xd2, 0xdc, 0x88, 0x1a, 0xa4, 0x1d, 0x34, 0x52, 0xa4, 0x51, 0x8d, 0xad, 0x73, 0x23, |
|
| 3147 |
+ 0xce, 0x71, 0x23, 0x07, 0xd1, 0x33, 0xec, 0xb6, 0xd3, 0x33, 0xe3, 0x8d, 0x2a, 0x3e, 0xc2, 0x8d, |
|
| 3148 |
+ 0x02, 0x9a, 0x0b, 0xcd, 0x4e, 0x9f, 0xb0, 0x8b, 0x48, 0xcb, 0xe3, 0x85, 0x45, 0x1f, 0xe1, 0xc2, |
|
| 3149 |
+ 0x80, 0x2e, 0xbc, 0x07, 0x64, 0x6a, 0xb8, 0x2d, 0x44, 0xb7, 0x5f, 0x0b, 0x20, 0x35, 0x52, 0x30, |
|
| 3150 |
+ 0xd6, 0x33, 0x89, 0x7a, 0x65, 0xaf, 0x52, 0xfd, 0xb1, 0xb2, 0x10, 0x53, 0x94, 0x8b, 0x7f, 0xd6, |
|
| 3151 |
+ 0x97, 0x47, 0x88, 0xba, 0xd3, 0x76, 0xf0, 0x99, 0xc3, 0x7a, 0x64, 0xf1, 0xa8, 0x56, 0xd5, 0x4b, |
|
| 3152 |
+ 0x8d, 0x7c, 0xb1, 0x56, 0xae, 0x56, 0x1a, 0x45, 0xbd, 0x94, 0xaf, 0x95, 0x16, 0x04, 0x65, 0x85, |
|
| 3153 |
+ 0x89, 0x96, 0x46, 0x44, 0x45, 0x17, 0x19, 0x14, 0x3d, 0xd0, 0xd4, 0x0f, 0x77, 0xb9, 0x46, 0x8c, |
|
| 3154 |
+ 0xd4, 0xd4, 0x7b, 0x56, 0x94, 0x46, 0x2f, 0x1d, 0x54, 0x7f, 0x28, 0x2d, 0xc4, 0x23, 0x35, 0xba, |
|
| 3155 |
+ 0xd7, 0xd7, 0xca, 0x87, 0xbf, 0xff, 0x9b, 0x89, 0xfd, 0xff, 0x5f, 0x66, 0xf4, 0x74, 0xb9, 0x3f, |
|
| 3156 |
+ 0x44, 0x20, 0xf1, 0x8f, 0x16, 0x5e, 0x08, 0x00, 0x3e, 0xec, 0x27, 0xb8, 0x13, 0x55, 0xc3, 0xb1, |
|
| 3157 |
+ 0x5d, 0xac, 0x68, 0xd3, 0xe2, 0x41, 0x9b, 0x2e, 0x3d, 0xb9, 0x7c, 0xf5, 0xb7, 0xc8, 0x5e, 0x0a, |
|
| 3158 |
+ 0x8f, 0xdf, 0xe9, 0x1a, 0x0e, 0x5b, 0x75, 0xe1, 0x6f, 0x60, 0xfe, 0xdd, 0xfe, 0x83, 0x5b, 0x91, |
|
| 3159 |
+ 0x4f, 0x4e, 0x54, 0x87, 0x2b, 0xdb, 0xd3, 0xa0, 0x13, 0xfd, 0x73, 0xcf, 0x04, 0xb6, 0x81, 0xe1, |
|
| 3160 |
+ 0x7b, 0x46, 0x4e, 0xed, 0x1e, 0xfc, 0x09, 0x48, 0xfc, 0xa5, 0x86, 0x91, 0xdd, 0x7a, 0xef, 0x9d, |
|
| 3161 |
+ 0x57, 0xd6, 0xc7, 0x03, 0x93, 0x0f, 0x6d, 0x82, 0x19, 0xef, 0xbd, 0x84, 0x91, 0x19, 0xee, 0x3f, |
|
| 3162 |
+ 0xc7, 0xca, 0xc6, 0x04, 0x62, 0xa2, 0x49, 0x61, 0xf5, 0xea, 0x26, 0x13, 0x7b, 0xce, 0xc6, 0x9b, |
|
| 3163 |
+ 0x9b, 0x8c, 0x70, 0x7e, 0x9b, 0x11, 0xae, 0xd8, 0x78, 0xca, 0xc6, 0x4b, 0x36, 0x8e, 0xe3, 0xc7, |
|
| 3164 |
+ 0x52, 0x53, 0xf6, 0xfe, 0xdd, 0x7e, 0xf1, 0x36, 0x00, 0x00, 0xff, 0xff, 0xd7, 0x61, 0x3c, 0x43, |
|
| 3165 |
+ 0x06, 0x08, 0x00, 0x00, |
|
| 3165 | 3166 |
} |
| ... | ... |
@@ -58,8 +58,15 @@ message JoinRequest {
|
| 58 | 58 |
} |
| 59 | 59 |
|
| 60 | 60 |
message JoinResponse {
|
| 61 |
+ // RaftID is the ID assigned to the new member. |
|
| 61 | 62 |
uint64 raft_id = 1 [(gogoproto.customname) = "RaftID"]; |
| 63 |
+ |
|
| 64 |
+ // Members is the membership set of the cluster. |
|
| 62 | 65 |
repeated RaftMember members = 2; |
| 66 |
+ |
|
| 67 |
+ // RemovedMembers is a list of members that have been removed from |
|
| 68 |
+ // the cluster, so the new node can avoid communicating with them. |
|
| 69 |
+ repeated uint64 removed_members = 3; |
|
| 63 | 70 |
} |
| 64 | 71 |
|
| 65 | 72 |
message LeaveRequest {
|
| ... | ... |
@@ -268,7 +268,7 @@ func _ServiceSpec_OneofSizer(msg proto.Message) (n int) {
|
| 268 | 268 |
// instructing Swarm on how this service should work on the particular |
| 269 | 269 |
// network. |
| 270 | 270 |
type ServiceSpec_NetworkAttachmentConfig struct {
|
| 271 |
- // Target specifies the target network for attachement. This value may be a |
|
| 271 |
+ // Target specifies the target network for attachment. This value may be a |
|
| 272 | 272 |
// network name or identifier. Only identifiers are supported at this time. |
| 273 | 273 |
Target string `protobuf:"bytes,1,opt,name=target,proto3" json:"target,omitempty"` |
| 274 | 274 |
// Aliases specifies a list of discoverable alternate names for the service on this Target. |
| ... | ... |
@@ -281,7 +281,7 @@ func (*ServiceSpec_NetworkAttachmentConfig) Descriptor() ([]byte, []int) {
|
| 281 | 281 |
return fileDescriptorSpecs, []int{1, 0}
|
| 282 | 282 |
} |
| 283 | 283 |
|
| 284 |
-// ReplicatedService set the reconcilation target to certain number of replicas. |
|
| 284 |
+// ReplicatedService sets the reconciliation target to certain number of replicas. |
|
| 285 | 285 |
type ReplicatedService struct {
|
| 286 | 286 |
Replicas uint64 `protobuf:"varint,1,opt,name=replicas,proto3" json:"replicas,omitempty"` |
| 287 | 287 |
} |
| ... | ... |
@@ -290,7 +290,7 @@ func (m *ReplicatedService) Reset() { *m = ReplicatedService{
|
| 290 | 290 |
func (*ReplicatedService) ProtoMessage() {}
|
| 291 | 291 |
func (*ReplicatedService) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{2} }
|
| 292 | 292 |
|
| 293 |
-// GlobalService represent global service. |
|
| 293 |
+// GlobalService represents global service. |
|
| 294 | 294 |
type GlobalService struct {
|
| 295 | 295 |
} |
| 296 | 296 |
|
| ... | ... |
@@ -415,9 +415,12 @@ type ContainerSpec struct {
|
| 415 | 415 |
// executable and the following elements are treated as arguments. |
| 416 | 416 |
// |
| 417 | 417 |
// If command is empty, execution will fall back to the image's entrypoint. |
| 418 |
+ // |
|
| 419 |
+ // Command should only be used when overriding entrypoint. |
|
| 418 | 420 |
Command []string `protobuf:"bytes,3,rep,name=command" json:"command,omitempty"` |
| 419 | 421 |
// Args specifies arguments provided to the image's entrypoint. |
| 420 |
- // Ignored if command is specified. |
|
| 422 |
+ // |
|
| 423 |
+ // If Command and Args are provided, Args will be appended to Command. |
|
| 421 | 424 |
Args []string `protobuf:"bytes,4,rep,name=args" json:"args,omitempty"` |
| 422 | 425 |
// Env specifies the environment variables for the container in NAME=VALUE |
| 423 | 426 |
// format. These must be compliant with [IEEE Std |
| ... | ... |
@@ -78,7 +78,7 @@ message ServiceSpec {
|
| 78 | 78 |
// instructing Swarm on how this service should work on the particular |
| 79 | 79 |
// network. |
| 80 | 80 |
message NetworkAttachmentConfig {
|
| 81 |
- // Target specifies the target network for attachement. This value may be a |
|
| 81 |
+ // Target specifies the target network for attachment. This value may be a |
|
| 82 | 82 |
// network name or identifier. Only identifiers are supported at this time. |
| 83 | 83 |
string target = 1; |
| 84 | 84 |
// Aliases specifies a list of discoverable alternate names for the service on this Target. |
| ... | ... |
@@ -91,12 +91,12 @@ message ServiceSpec {
|
| 91 | 91 |
EndpointSpec endpoint = 8; |
| 92 | 92 |
} |
| 93 | 93 |
|
| 94 |
-// ReplicatedService set the reconcilation target to certain number of replicas. |
|
| 94 |
+// ReplicatedService sets the reconciliation target to certain number of replicas. |
|
| 95 | 95 |
message ReplicatedService {
|
| 96 | 96 |
uint64 replicas = 1; |
| 97 | 97 |
} |
| 98 | 98 |
|
| 99 |
-// GlobalService represent global service. |
|
| 99 |
+// GlobalService represents global service. |
|
| 100 | 100 |
message GlobalService {
|
| 101 | 101 |
// Empty message for now. |
| 102 | 102 |
} |
| ... | ... |
@@ -138,10 +138,13 @@ message ContainerSpec {
|
| 138 | 138 |
// executable and the following elements are treated as arguments. |
| 139 | 139 |
// |
| 140 | 140 |
// If command is empty, execution will fall back to the image's entrypoint. |
| 141 |
+ // |
|
| 142 |
+ // Command should only be used when overriding entrypoint. |
|
| 141 | 143 |
repeated string command = 3; |
| 142 | 144 |
|
| 143 | 145 |
// Args specifies arguments provided to the image's entrypoint. |
| 144 |
- // Ignored if command is specified. |
|
| 146 |
+ // |
|
| 147 |
+ // If Command and Args are provided, Args will be appended to Command. |
|
| 145 | 148 |
repeated string args = 4; |
| 146 | 149 |
|
| 147 | 150 |
// Env specifies the environment variables for the container in NAME=VALUE |
| ... | ... |
@@ -14,6 +14,7 @@ |
| 14 | 14 |
ca.proto |
| 15 | 15 |
snapshot.proto |
| 16 | 16 |
raft.proto |
| 17 |
+ health.proto |
|
| 17 | 18 |
|
| 18 | 19 |
It has these top-level messages: |
| 19 | 20 |
Version |
| ... | ... |
@@ -40,6 +41,7 @@ |
| 40 | 40 |
WeightedPeer |
| 41 | 41 |
IssuanceStatus |
| 42 | 42 |
AcceptancePolicy |
| 43 |
+ ExternalCA |
|
| 43 | 44 |
CAConfig |
| 44 | 45 |
OrchestrationConfig |
| 45 | 46 |
DispatcherConfig |
| ... | ... |
@@ -132,6 +134,8 @@ |
| 132 | 132 |
ResolveAddressResponse |
| 133 | 133 |
InternalRaftRequest |
| 134 | 134 |
StoreAction |
| 135 |
+ HealthCheckRequest |
|
| 136 |
+ HealthCheckResponse |
|
| 135 | 137 |
*/ |
| 136 | 138 |
package api |
| 137 | 139 |
|
| ... | ... |
@@ -462,6 +466,26 @@ func (x IssuanceStatus_State) String() string {
|
| 462 | 462 |
} |
| 463 | 463 |
func (IssuanceStatus_State) EnumDescriptor() ([]byte, []int) { return fileDescriptorTypes, []int{22, 0} }
|
| 464 | 464 |
|
| 465 |
+type ExternalCA_CAProtocol int32 |
|
| 466 |
+ |
|
| 467 |
+const ( |
|
| 468 |
+ ExternalCA_CAProtocolCFSSL ExternalCA_CAProtocol = 0 |
|
| 469 |
+) |
|
| 470 |
+ |
|
| 471 |
+var ExternalCA_CAProtocol_name = map[int32]string{
|
|
| 472 |
+ 0: "CFSSL", |
|
| 473 |
+} |
|
| 474 |
+var ExternalCA_CAProtocol_value = map[string]int32{
|
|
| 475 |
+ "CFSSL": 0, |
|
| 476 |
+} |
|
| 477 |
+ |
|
| 478 |
+func (x ExternalCA_CAProtocol) String() string {
|
|
| 479 |
+ return proto.EnumName(ExternalCA_CAProtocol_name, int32(x)) |
|
| 480 |
+} |
|
| 481 |
+func (ExternalCA_CAProtocol) EnumDescriptor() ([]byte, []int) {
|
|
| 482 |
+ return fileDescriptorTypes, []int{24, 0}
|
|
| 483 |
+} |
|
| 484 |
+ |
|
| 465 | 485 |
// Encryption algorithm that can implemented using this key |
| 466 | 486 |
type EncryptionKey_Algorithm int32 |
| 467 | 487 |
|
| ... | ... |
@@ -480,7 +504,7 @@ func (x EncryptionKey_Algorithm) String() string {
|
| 480 | 480 |
return proto.EnumName(EncryptionKey_Algorithm_name, int32(x)) |
| 481 | 481 |
} |
| 482 | 482 |
func (EncryptionKey_Algorithm) EnumDescriptor() ([]byte, []int) {
|
| 483 |
- return fileDescriptorTypes, []int{31, 0}
|
|
| 483 |
+ return fileDescriptorTypes, []int{32, 0}
|
|
| 484 | 484 |
} |
| 485 | 485 |
|
| 486 | 486 |
// Version tracks the last time an object in the store was updated. |
| ... | ... |
@@ -955,14 +979,31 @@ func (*AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) Descriptor() ([]byte, |
| 955 | 955 |
return fileDescriptorTypes, []int{23, 0, 0}
|
| 956 | 956 |
} |
| 957 | 957 |
|
| 958 |
+type ExternalCA struct {
|
|
| 959 |
+ // Protocol is the protocol used by this external CA. |
|
| 960 |
+ Protocol ExternalCA_CAProtocol `protobuf:"varint,1,opt,name=protocol,proto3,enum=docker.swarmkit.v1.ExternalCA_CAProtocol" json:"protocol,omitempty"` |
|
| 961 |
+ // URL is the URL where the external CA can be reached. |
|
| 962 |
+ URL string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` |
|
| 963 |
+ // Options is a set of additional key/value pairs whose interpretation |
|
| 964 |
+ // depends on the specified CA type. |
|
| 965 |
+ Options map[string]string `protobuf:"bytes,3,rep,name=options" json:"options,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` |
|
| 966 |
+} |
|
| 967 |
+ |
|
| 968 |
+func (m *ExternalCA) Reset() { *m = ExternalCA{} }
|
|
| 969 |
+func (*ExternalCA) ProtoMessage() {}
|
|
| 970 |
+func (*ExternalCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{24} }
|
|
| 971 |
+ |
|
| 958 | 972 |
type CAConfig struct {
|
| 959 | 973 |
// NodeCertExpiry is the duration certificates should be issued for |
| 960 | 974 |
NodeCertExpiry *docker_swarmkit_v11.Duration `protobuf:"bytes,1,opt,name=node_cert_expiry,json=nodeCertExpiry" json:"node_cert_expiry,omitempty"` |
| 975 |
+ // ExternalCAs is a list of CAs to which a manager node will make |
|
| 976 |
+ // certificate signing requests for node certificates. |
|
| 977 |
+ ExternalCAs []*ExternalCA `protobuf:"bytes,2,rep,name=external_cas,json=externalCas" json:"external_cas,omitempty"` |
|
| 961 | 978 |
} |
| 962 | 979 |
|
| 963 | 980 |
func (m *CAConfig) Reset() { *m = CAConfig{} }
|
| 964 | 981 |
func (*CAConfig) ProtoMessage() {}
|
| 965 |
-func (*CAConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{24} }
|
|
| 982 |
+func (*CAConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{25} }
|
|
| 966 | 983 |
|
| 967 | 984 |
// OrchestrationConfig defines cluster-level orchestration settings. |
| 968 | 985 |
type OrchestrationConfig struct {
|
| ... | ... |
@@ -973,7 +1014,7 @@ type OrchestrationConfig struct {
|
| 973 | 973 |
|
| 974 | 974 |
func (m *OrchestrationConfig) Reset() { *m = OrchestrationConfig{} }
|
| 975 | 975 |
func (*OrchestrationConfig) ProtoMessage() {}
|
| 976 |
-func (*OrchestrationConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{25} }
|
|
| 976 |
+func (*OrchestrationConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{26} }
|
|
| 977 | 977 |
|
| 978 | 978 |
// DispatcherConfig defines cluster-level dispatcher settings. |
| 979 | 979 |
type DispatcherConfig struct {
|
| ... | ... |
@@ -984,7 +1025,7 @@ type DispatcherConfig struct {
|
| 984 | 984 |
|
| 985 | 985 |
func (m *DispatcherConfig) Reset() { *m = DispatcherConfig{} }
|
| 986 | 986 |
func (*DispatcherConfig) ProtoMessage() {}
|
| 987 |
-func (*DispatcherConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{26} }
|
|
| 987 |
+func (*DispatcherConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{27} }
|
|
| 988 | 988 |
|
| 989 | 989 |
// RaftConfig defines raft settings for the cluster. |
| 990 | 990 |
type RaftConfig struct {
|
| ... | ... |
@@ -1006,7 +1047,7 @@ type RaftConfig struct {
|
| 1006 | 1006 |
|
| 1007 | 1007 |
func (m *RaftConfig) Reset() { *m = RaftConfig{} }
|
| 1008 | 1008 |
func (*RaftConfig) ProtoMessage() {}
|
| 1009 |
-func (*RaftConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{27} }
|
|
| 1009 |
+func (*RaftConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{28} }
|
|
| 1010 | 1010 |
|
| 1011 | 1011 |
// Placement specifies task distribution constraints. |
| 1012 | 1012 |
type Placement struct {
|
| ... | ... |
@@ -1016,7 +1057,7 @@ type Placement struct {
|
| 1016 | 1016 |
|
| 1017 | 1017 |
func (m *Placement) Reset() { *m = Placement{} }
|
| 1018 | 1018 |
func (*Placement) ProtoMessage() {}
|
| 1019 |
-func (*Placement) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{28} }
|
|
| 1019 |
+func (*Placement) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{29} }
|
|
| 1020 | 1020 |
|
| 1021 | 1021 |
type RootCA struct {
|
| 1022 | 1022 |
// CAKey is the root CA private key. |
| ... | ... |
@@ -1029,7 +1070,7 @@ type RootCA struct {
|
| 1029 | 1029 |
|
| 1030 | 1030 |
func (m *RootCA) Reset() { *m = RootCA{} }
|
| 1031 | 1031 |
func (*RootCA) ProtoMessage() {}
|
| 1032 |
-func (*RootCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{29} }
|
|
| 1032 |
+func (*RootCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{30} }
|
|
| 1033 | 1033 |
|
| 1034 | 1034 |
type Certificate struct {
|
| 1035 | 1035 |
Role NodeRole `protobuf:"varint,1,opt,name=role,proto3,enum=docker.swarmkit.v1.NodeRole" json:"role,omitempty"` |
| ... | ... |
@@ -1042,7 +1083,7 @@ type Certificate struct {
|
| 1042 | 1042 |
|
| 1043 | 1043 |
func (m *Certificate) Reset() { *m = Certificate{} }
|
| 1044 | 1044 |
func (*Certificate) ProtoMessage() {}
|
| 1045 |
-func (*Certificate) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{30} }
|
|
| 1045 |
+func (*Certificate) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{31} }
|
|
| 1046 | 1046 |
|
| 1047 | 1047 |
// Symmetric keys to encrypt inter-agent communication. |
| 1048 | 1048 |
type EncryptionKey struct {
|
| ... | ... |
@@ -1058,7 +1099,7 @@ type EncryptionKey struct {
|
| 1058 | 1058 |
|
| 1059 | 1059 |
func (m *EncryptionKey) Reset() { *m = EncryptionKey{} }
|
| 1060 | 1060 |
func (*EncryptionKey) ProtoMessage() {}
|
| 1061 |
-func (*EncryptionKey) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{31} }
|
|
| 1061 |
+func (*EncryptionKey) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{32} }
|
|
| 1062 | 1062 |
|
| 1063 | 1063 |
// ManagerStatus provides informations about the state of a manager in the cluster. |
| 1064 | 1064 |
type ManagerStatus struct {
|
| ... | ... |
@@ -1075,7 +1116,7 @@ type ManagerStatus struct {
|
| 1075 | 1075 |
|
| 1076 | 1076 |
func (m *ManagerStatus) Reset() { *m = ManagerStatus{} }
|
| 1077 | 1077 |
func (*ManagerStatus) ProtoMessage() {}
|
| 1078 |
-func (*ManagerStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{32} }
|
|
| 1078 |
+func (*ManagerStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{33} }
|
|
| 1079 | 1079 |
|
| 1080 | 1080 |
func init() {
|
| 1081 | 1081 |
proto.RegisterType((*Version)(nil), "docker.swarmkit.v1.Version") |
| ... | ... |
@@ -1106,6 +1147,7 @@ func init() {
|
| 1106 | 1106 |
proto.RegisterType((*AcceptancePolicy)(nil), "docker.swarmkit.v1.AcceptancePolicy") |
| 1107 | 1107 |
proto.RegisterType((*AcceptancePolicy_RoleAdmissionPolicy)(nil), "docker.swarmkit.v1.AcceptancePolicy.RoleAdmissionPolicy") |
| 1108 | 1108 |
proto.RegisterType((*AcceptancePolicy_RoleAdmissionPolicy_HashedSecret)(nil), "docker.swarmkit.v1.AcceptancePolicy.RoleAdmissionPolicy.HashedSecret") |
| 1109 |
+ proto.RegisterType((*ExternalCA)(nil), "docker.swarmkit.v1.ExternalCA") |
|
| 1109 | 1110 |
proto.RegisterType((*CAConfig)(nil), "docker.swarmkit.v1.CAConfig") |
| 1110 | 1111 |
proto.RegisterType((*OrchestrationConfig)(nil), "docker.swarmkit.v1.OrchestrationConfig") |
| 1111 | 1112 |
proto.RegisterType((*DispatcherConfig)(nil), "docker.swarmkit.v1.DispatcherConfig") |
| ... | ... |
@@ -1125,6 +1167,7 @@ func init() {
|
| 1125 | 1125 |
proto.RegisterEnum("docker.swarmkit.v1.IPAMConfig_AddressFamily", IPAMConfig_AddressFamily_name, IPAMConfig_AddressFamily_value)
|
| 1126 | 1126 |
proto.RegisterEnum("docker.swarmkit.v1.PortConfig_Protocol", PortConfig_Protocol_name, PortConfig_Protocol_value)
|
| 1127 | 1127 |
proto.RegisterEnum("docker.swarmkit.v1.IssuanceStatus_State", IssuanceStatus_State_name, IssuanceStatus_State_value)
|
| 1128 |
+ proto.RegisterEnum("docker.swarmkit.v1.ExternalCA_CAProtocol", ExternalCA_CAProtocol_name, ExternalCA_CAProtocol_value)
|
|
| 1128 | 1129 |
proto.RegisterEnum("docker.swarmkit.v1.EncryptionKey_Algorithm", EncryptionKey_Algorithm_name, EncryptionKey_Algorithm_value)
|
| 1129 | 1130 |
} |
| 1130 | 1131 |
|
| ... | ... |
@@ -1564,6 +1607,26 @@ func (m *AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) Copy() *AcceptancePo |
| 1564 | 1564 |
return o |
| 1565 | 1565 |
} |
| 1566 | 1566 |
|
| 1567 |
+func (m *ExternalCA) Copy() *ExternalCA {
|
|
| 1568 |
+ if m == nil {
|
|
| 1569 |
+ return nil |
|
| 1570 |
+ } |
|
| 1571 |
+ |
|
| 1572 |
+ o := &ExternalCA{
|
|
| 1573 |
+ Protocol: m.Protocol, |
|
| 1574 |
+ URL: m.URL, |
|
| 1575 |
+ } |
|
| 1576 |
+ |
|
| 1577 |
+ if m.Options != nil {
|
|
| 1578 |
+ o.Options = make(map[string]string) |
|
| 1579 |
+ for k, v := range m.Options {
|
|
| 1580 |
+ o.Options[k] = v |
|
| 1581 |
+ } |
|
| 1582 |
+ } |
|
| 1583 |
+ |
|
| 1584 |
+ return o |
|
| 1585 |
+} |
|
| 1586 |
+ |
|
| 1567 | 1587 |
func (m *CAConfig) Copy() *CAConfig {
|
| 1568 | 1588 |
if m == nil {
|
| 1569 | 1589 |
return nil |
| ... | ... |
@@ -1573,6 +1636,13 @@ func (m *CAConfig) Copy() *CAConfig {
|
| 1573 | 1573 |
NodeCertExpiry: m.NodeCertExpiry.Copy(), |
| 1574 | 1574 |
} |
| 1575 | 1575 |
|
| 1576 |
+ if m.ExternalCAs != nil {
|
|
| 1577 |
+ o.ExternalCAs = make([]*ExternalCA, 0, len(m.ExternalCAs)) |
|
| 1578 |
+ for _, v := range m.ExternalCAs {
|
|
| 1579 |
+ o.ExternalCAs = append(o.ExternalCAs, v.Copy()) |
|
| 1580 |
+ } |
|
| 1581 |
+ } |
|
| 1582 |
+ |
|
| 1576 | 1583 |
return o |
| 1577 | 1584 |
} |
| 1578 | 1585 |
|
| ... | ... |
@@ -2122,15 +2192,42 @@ func (this *AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) GoString() string |
| 2122 | 2122 |
s = append(s, "}") |
| 2123 | 2123 |
return strings.Join(s, "") |
| 2124 | 2124 |
} |
| 2125 |
+func (this *ExternalCA) GoString() string {
|
|
| 2126 |
+ if this == nil {
|
|
| 2127 |
+ return "nil" |
|
| 2128 |
+ } |
|
| 2129 |
+ s := make([]string, 0, 7) |
|
| 2130 |
+ s = append(s, "&api.ExternalCA{")
|
|
| 2131 |
+ s = append(s, "Protocol: "+fmt.Sprintf("%#v", this.Protocol)+",\n")
|
|
| 2132 |
+ s = append(s, "URL: "+fmt.Sprintf("%#v", this.URL)+",\n")
|
|
| 2133 |
+ keysForOptions := make([]string, 0, len(this.Options)) |
|
| 2134 |
+ for k, _ := range this.Options {
|
|
| 2135 |
+ keysForOptions = append(keysForOptions, k) |
|
| 2136 |
+ } |
|
| 2137 |
+ github_com_gogo_protobuf_sortkeys.Strings(keysForOptions) |
|
| 2138 |
+ mapStringForOptions := "map[string]string{"
|
|
| 2139 |
+ for _, k := range keysForOptions {
|
|
| 2140 |
+ mapStringForOptions += fmt.Sprintf("%#v: %#v,", k, this.Options[k])
|
|
| 2141 |
+ } |
|
| 2142 |
+ mapStringForOptions += "}" |
|
| 2143 |
+ if this.Options != nil {
|
|
| 2144 |
+ s = append(s, "Options: "+mapStringForOptions+",\n") |
|
| 2145 |
+ } |
|
| 2146 |
+ s = append(s, "}") |
|
| 2147 |
+ return strings.Join(s, "") |
|
| 2148 |
+} |
|
| 2125 | 2149 |
func (this *CAConfig) GoString() string {
|
| 2126 | 2150 |
if this == nil {
|
| 2127 | 2151 |
return "nil" |
| 2128 | 2152 |
} |
| 2129 |
- s := make([]string, 0, 5) |
|
| 2153 |
+ s := make([]string, 0, 6) |
|
| 2130 | 2154 |
s = append(s, "&api.CAConfig{")
|
| 2131 | 2155 |
if this.NodeCertExpiry != nil {
|
| 2132 | 2156 |
s = append(s, "NodeCertExpiry: "+fmt.Sprintf("%#v", this.NodeCertExpiry)+",\n")
|
| 2133 | 2157 |
} |
| 2158 |
+ if this.ExternalCAs != nil {
|
|
| 2159 |
+ s = append(s, "ExternalCAs: "+fmt.Sprintf("%#v", this.ExternalCAs)+",\n")
|
|
| 2160 |
+ } |
|
| 2134 | 2161 |
s = append(s, "}") |
| 2135 | 2162 |
return strings.Join(s, "") |
| 2136 | 2163 |
} |
| ... | ... |
@@ -3341,6 +3438,52 @@ func (m *AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) MarshalTo(data []byt |
| 3341 | 3341 |
return i, nil |
| 3342 | 3342 |
} |
| 3343 | 3343 |
|
| 3344 |
+func (m *ExternalCA) Marshal() (data []byte, err error) {
|
|
| 3345 |
+ size := m.Size() |
|
| 3346 |
+ data = make([]byte, size) |
|
| 3347 |
+ n, err := m.MarshalTo(data) |
|
| 3348 |
+ if err != nil {
|
|
| 3349 |
+ return nil, err |
|
| 3350 |
+ } |
|
| 3351 |
+ return data[:n], nil |
|
| 3352 |
+} |
|
| 3353 |
+ |
|
| 3354 |
+func (m *ExternalCA) MarshalTo(data []byte) (int, error) {
|
|
| 3355 |
+ var i int |
|
| 3356 |
+ _ = i |
|
| 3357 |
+ var l int |
|
| 3358 |
+ _ = l |
|
| 3359 |
+ if m.Protocol != 0 {
|
|
| 3360 |
+ data[i] = 0x8 |
|
| 3361 |
+ i++ |
|
| 3362 |
+ i = encodeVarintTypes(data, i, uint64(m.Protocol)) |
|
| 3363 |
+ } |
|
| 3364 |
+ if len(m.URL) > 0 {
|
|
| 3365 |
+ data[i] = 0x12 |
|
| 3366 |
+ i++ |
|
| 3367 |
+ i = encodeVarintTypes(data, i, uint64(len(m.URL))) |
|
| 3368 |
+ i += copy(data[i:], m.URL) |
|
| 3369 |
+ } |
|
| 3370 |
+ if len(m.Options) > 0 {
|
|
| 3371 |
+ for k, _ := range m.Options {
|
|
| 3372 |
+ data[i] = 0x1a |
|
| 3373 |
+ i++ |
|
| 3374 |
+ v := m.Options[k] |
|
| 3375 |
+ mapSize := 1 + len(k) + sovTypes(uint64(len(k))) + 1 + len(v) + sovTypes(uint64(len(v))) |
|
| 3376 |
+ i = encodeVarintTypes(data, i, uint64(mapSize)) |
|
| 3377 |
+ data[i] = 0xa |
|
| 3378 |
+ i++ |
|
| 3379 |
+ i = encodeVarintTypes(data, i, uint64(len(k))) |
|
| 3380 |
+ i += copy(data[i:], k) |
|
| 3381 |
+ data[i] = 0x12 |
|
| 3382 |
+ i++ |
|
| 3383 |
+ i = encodeVarintTypes(data, i, uint64(len(v))) |
|
| 3384 |
+ i += copy(data[i:], v) |
|
| 3385 |
+ } |
|
| 3386 |
+ } |
|
| 3387 |
+ return i, nil |
|
| 3388 |
+} |
|
| 3389 |
+ |
|
| 3344 | 3390 |
func (m *CAConfig) Marshal() (data []byte, err error) {
|
| 3345 | 3391 |
size := m.Size() |
| 3346 | 3392 |
data = make([]byte, size) |
| ... | ... |
@@ -3366,6 +3509,18 @@ func (m *CAConfig) MarshalTo(data []byte) (int, error) {
|
| 3366 | 3366 |
} |
| 3367 | 3367 |
i += n18 |
| 3368 | 3368 |
} |
| 3369 |
+ if len(m.ExternalCAs) > 0 {
|
|
| 3370 |
+ for _, msg := range m.ExternalCAs {
|
|
| 3371 |
+ data[i] = 0x12 |
|
| 3372 |
+ i++ |
|
| 3373 |
+ i = encodeVarintTypes(data, i, uint64(msg.Size())) |
|
| 3374 |
+ n, err := msg.MarshalTo(data[i:]) |
|
| 3375 |
+ if err != nil {
|
|
| 3376 |
+ return 0, err |
|
| 3377 |
+ } |
|
| 3378 |
+ i += n |
|
| 3379 |
+ } |
|
| 3380 |
+ } |
|
| 3369 | 3381 |
return i, nil |
| 3370 | 3382 |
} |
| 3371 | 3383 |
|
| ... | ... |
@@ -4161,6 +4316,27 @@ func (m *AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) Size() (n int) {
|
| 4161 | 4161 |
return n |
| 4162 | 4162 |
} |
| 4163 | 4163 |
|
| 4164 |
+func (m *ExternalCA) Size() (n int) {
|
|
| 4165 |
+ var l int |
|
| 4166 |
+ _ = l |
|
| 4167 |
+ if m.Protocol != 0 {
|
|
| 4168 |
+ n += 1 + sovTypes(uint64(m.Protocol)) |
|
| 4169 |
+ } |
|
| 4170 |
+ l = len(m.URL) |
|
| 4171 |
+ if l > 0 {
|
|
| 4172 |
+ n += 1 + l + sovTypes(uint64(l)) |
|
| 4173 |
+ } |
|
| 4174 |
+ if len(m.Options) > 0 {
|
|
| 4175 |
+ for k, v := range m.Options {
|
|
| 4176 |
+ _ = k |
|
| 4177 |
+ _ = v |
|
| 4178 |
+ mapEntrySize := 1 + len(k) + sovTypes(uint64(len(k))) + 1 + len(v) + sovTypes(uint64(len(v))) |
|
| 4179 |
+ n += mapEntrySize + 1 + sovTypes(uint64(mapEntrySize)) |
|
| 4180 |
+ } |
|
| 4181 |
+ } |
|
| 4182 |
+ return n |
|
| 4183 |
+} |
|
| 4184 |
+ |
|
| 4164 | 4185 |
func (m *CAConfig) Size() (n int) {
|
| 4165 | 4186 |
var l int |
| 4166 | 4187 |
_ = l |
| ... | ... |
@@ -4168,6 +4344,12 @@ func (m *CAConfig) Size() (n int) {
|
| 4168 | 4168 |
l = m.NodeCertExpiry.Size() |
| 4169 | 4169 |
n += 1 + l + sovTypes(uint64(l)) |
| 4170 | 4170 |
} |
| 4171 |
+ if len(m.ExternalCAs) > 0 {
|
|
| 4172 |
+ for _, e := range m.ExternalCAs {
|
|
| 4173 |
+ l = e.Size() |
|
| 4174 |
+ n += 1 + l + sovTypes(uint64(l)) |
|
| 4175 |
+ } |
|
| 4176 |
+ } |
|
| 4171 | 4177 |
return n |
| 4172 | 4178 |
} |
| 4173 | 4179 |
|
| ... | ... |
@@ -4701,12 +4883,35 @@ func (this *AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) String() string {
|
| 4701 | 4701 |
}, "") |
| 4702 | 4702 |
return s |
| 4703 | 4703 |
} |
| 4704 |
+func (this *ExternalCA) String() string {
|
|
| 4705 |
+ if this == nil {
|
|
| 4706 |
+ return "nil" |
|
| 4707 |
+ } |
|
| 4708 |
+ keysForOptions := make([]string, 0, len(this.Options)) |
|
| 4709 |
+ for k, _ := range this.Options {
|
|
| 4710 |
+ keysForOptions = append(keysForOptions, k) |
|
| 4711 |
+ } |
|
| 4712 |
+ github_com_gogo_protobuf_sortkeys.Strings(keysForOptions) |
|
| 4713 |
+ mapStringForOptions := "map[string]string{"
|
|
| 4714 |
+ for _, k := range keysForOptions {
|
|
| 4715 |
+ mapStringForOptions += fmt.Sprintf("%v: %v,", k, this.Options[k])
|
|
| 4716 |
+ } |
|
| 4717 |
+ mapStringForOptions += "}" |
|
| 4718 |
+ s := strings.Join([]string{`&ExternalCA{`,
|
|
| 4719 |
+ `Protocol:` + fmt.Sprintf("%v", this.Protocol) + `,`,
|
|
| 4720 |
+ `URL:` + fmt.Sprintf("%v", this.URL) + `,`,
|
|
| 4721 |
+ `Options:` + mapStringForOptions + `,`, |
|
| 4722 |
+ `}`, |
|
| 4723 |
+ }, "") |
|
| 4724 |
+ return s |
|
| 4725 |
+} |
|
| 4704 | 4726 |
func (this *CAConfig) String() string {
|
| 4705 | 4727 |
if this == nil {
|
| 4706 | 4728 |
return "nil" |
| 4707 | 4729 |
} |
| 4708 | 4730 |
s := strings.Join([]string{`&CAConfig{`,
|
| 4709 | 4731 |
`NodeCertExpiry:` + strings.Replace(fmt.Sprintf("%v", this.NodeCertExpiry), "Duration", "docker_swarmkit_v11.Duration", 1) + `,`,
|
| 4732 |
+ `ExternalCAs:` + strings.Replace(fmt.Sprintf("%v", this.ExternalCAs), "ExternalCA", "ExternalCA", 1) + `,`,
|
|
| 4710 | 4733 |
`}`, |
| 4711 | 4734 |
}, "") |
| 4712 | 4735 |
return s |
| ... | ... |
@@ -8574,6 +8779,215 @@ func (m *AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) Unmarshal(data []byt |
| 8574 | 8574 |
} |
| 8575 | 8575 |
return nil |
| 8576 | 8576 |
} |
| 8577 |
+func (m *ExternalCA) Unmarshal(data []byte) error {
|
|
| 8578 |
+ l := len(data) |
|
| 8579 |
+ iNdEx := 0 |
|
| 8580 |
+ for iNdEx < l {
|
|
| 8581 |
+ preIndex := iNdEx |
|
| 8582 |
+ var wire uint64 |
|
| 8583 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 8584 |
+ if shift >= 64 {
|
|
| 8585 |
+ return ErrIntOverflowTypes |
|
| 8586 |
+ } |
|
| 8587 |
+ if iNdEx >= l {
|
|
| 8588 |
+ return io.ErrUnexpectedEOF |
|
| 8589 |
+ } |
|
| 8590 |
+ b := data[iNdEx] |
|
| 8591 |
+ iNdEx++ |
|
| 8592 |
+ wire |= (uint64(b) & 0x7F) << shift |
|
| 8593 |
+ if b < 0x80 {
|
|
| 8594 |
+ break |
|
| 8595 |
+ } |
|
| 8596 |
+ } |
|
| 8597 |
+ fieldNum := int32(wire >> 3) |
|
| 8598 |
+ wireType := int(wire & 0x7) |
|
| 8599 |
+ if wireType == 4 {
|
|
| 8600 |
+ return fmt.Errorf("proto: ExternalCA: wiretype end group for non-group")
|
|
| 8601 |
+ } |
|
| 8602 |
+ if fieldNum <= 0 {
|
|
| 8603 |
+ return fmt.Errorf("proto: ExternalCA: illegal tag %d (wire type %d)", fieldNum, wire)
|
|
| 8604 |
+ } |
|
| 8605 |
+ switch fieldNum {
|
|
| 8606 |
+ case 1: |
|
| 8607 |
+ if wireType != 0 {
|
|
| 8608 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Protocol", wireType)
|
|
| 8609 |
+ } |
|
| 8610 |
+ m.Protocol = 0 |
|
| 8611 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 8612 |
+ if shift >= 64 {
|
|
| 8613 |
+ return ErrIntOverflowTypes |
|
| 8614 |
+ } |
|
| 8615 |
+ if iNdEx >= l {
|
|
| 8616 |
+ return io.ErrUnexpectedEOF |
|
| 8617 |
+ } |
|
| 8618 |
+ b := data[iNdEx] |
|
| 8619 |
+ iNdEx++ |
|
| 8620 |
+ m.Protocol |= (ExternalCA_CAProtocol(b) & 0x7F) << shift |
|
| 8621 |
+ if b < 0x80 {
|
|
| 8622 |
+ break |
|
| 8623 |
+ } |
|
| 8624 |
+ } |
|
| 8625 |
+ case 2: |
|
| 8626 |
+ if wireType != 2 {
|
|
| 8627 |
+ return fmt.Errorf("proto: wrong wireType = %d for field URL", wireType)
|
|
| 8628 |
+ } |
|
| 8629 |
+ var stringLen uint64 |
|
| 8630 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 8631 |
+ if shift >= 64 {
|
|
| 8632 |
+ return ErrIntOverflowTypes |
|
| 8633 |
+ } |
|
| 8634 |
+ if iNdEx >= l {
|
|
| 8635 |
+ return io.ErrUnexpectedEOF |
|
| 8636 |
+ } |
|
| 8637 |
+ b := data[iNdEx] |
|
| 8638 |
+ iNdEx++ |
|
| 8639 |
+ stringLen |= (uint64(b) & 0x7F) << shift |
|
| 8640 |
+ if b < 0x80 {
|
|
| 8641 |
+ break |
|
| 8642 |
+ } |
|
| 8643 |
+ } |
|
| 8644 |
+ intStringLen := int(stringLen) |
|
| 8645 |
+ if intStringLen < 0 {
|
|
| 8646 |
+ return ErrInvalidLengthTypes |
|
| 8647 |
+ } |
|
| 8648 |
+ postIndex := iNdEx + intStringLen |
|
| 8649 |
+ if postIndex > l {
|
|
| 8650 |
+ return io.ErrUnexpectedEOF |
|
| 8651 |
+ } |
|
| 8652 |
+ m.URL = string(data[iNdEx:postIndex]) |
|
| 8653 |
+ iNdEx = postIndex |
|
| 8654 |
+ case 3: |
|
| 8655 |
+ if wireType != 2 {
|
|
| 8656 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Options", wireType)
|
|
| 8657 |
+ } |
|
| 8658 |
+ var msglen int |
|
| 8659 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 8660 |
+ if shift >= 64 {
|
|
| 8661 |
+ return ErrIntOverflowTypes |
|
| 8662 |
+ } |
|
| 8663 |
+ if iNdEx >= l {
|
|
| 8664 |
+ return io.ErrUnexpectedEOF |
|
| 8665 |
+ } |
|
| 8666 |
+ b := data[iNdEx] |
|
| 8667 |
+ iNdEx++ |
|
| 8668 |
+ msglen |= (int(b) & 0x7F) << shift |
|
| 8669 |
+ if b < 0x80 {
|
|
| 8670 |
+ break |
|
| 8671 |
+ } |
|
| 8672 |
+ } |
|
| 8673 |
+ if msglen < 0 {
|
|
| 8674 |
+ return ErrInvalidLengthTypes |
|
| 8675 |
+ } |
|
| 8676 |
+ postIndex := iNdEx + msglen |
|
| 8677 |
+ if postIndex > l {
|
|
| 8678 |
+ return io.ErrUnexpectedEOF |
|
| 8679 |
+ } |
|
| 8680 |
+ var keykey uint64 |
|
| 8681 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 8682 |
+ if shift >= 64 {
|
|
| 8683 |
+ return ErrIntOverflowTypes |
|
| 8684 |
+ } |
|
| 8685 |
+ if iNdEx >= l {
|
|
| 8686 |
+ return io.ErrUnexpectedEOF |
|
| 8687 |
+ } |
|
| 8688 |
+ b := data[iNdEx] |
|
| 8689 |
+ iNdEx++ |
|
| 8690 |
+ keykey |= (uint64(b) & 0x7F) << shift |
|
| 8691 |
+ if b < 0x80 {
|
|
| 8692 |
+ break |
|
| 8693 |
+ } |
|
| 8694 |
+ } |
|
| 8695 |
+ var stringLenmapkey uint64 |
|
| 8696 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 8697 |
+ if shift >= 64 {
|
|
| 8698 |
+ return ErrIntOverflowTypes |
|
| 8699 |
+ } |
|
| 8700 |
+ if iNdEx >= l {
|
|
| 8701 |
+ return io.ErrUnexpectedEOF |
|
| 8702 |
+ } |
|
| 8703 |
+ b := data[iNdEx] |
|
| 8704 |
+ iNdEx++ |
|
| 8705 |
+ stringLenmapkey |= (uint64(b) & 0x7F) << shift |
|
| 8706 |
+ if b < 0x80 {
|
|
| 8707 |
+ break |
|
| 8708 |
+ } |
|
| 8709 |
+ } |
|
| 8710 |
+ intStringLenmapkey := int(stringLenmapkey) |
|
| 8711 |
+ if intStringLenmapkey < 0 {
|
|
| 8712 |
+ return ErrInvalidLengthTypes |
|
| 8713 |
+ } |
|
| 8714 |
+ postStringIndexmapkey := iNdEx + intStringLenmapkey |
|
| 8715 |
+ if postStringIndexmapkey > l {
|
|
| 8716 |
+ return io.ErrUnexpectedEOF |
|
| 8717 |
+ } |
|
| 8718 |
+ mapkey := string(data[iNdEx:postStringIndexmapkey]) |
|
| 8719 |
+ iNdEx = postStringIndexmapkey |
|
| 8720 |
+ var valuekey uint64 |
|
| 8721 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 8722 |
+ if shift >= 64 {
|
|
| 8723 |
+ return ErrIntOverflowTypes |
|
| 8724 |
+ } |
|
| 8725 |
+ if iNdEx >= l {
|
|
| 8726 |
+ return io.ErrUnexpectedEOF |
|
| 8727 |
+ } |
|
| 8728 |
+ b := data[iNdEx] |
|
| 8729 |
+ iNdEx++ |
|
| 8730 |
+ valuekey |= (uint64(b) & 0x7F) << shift |
|
| 8731 |
+ if b < 0x80 {
|
|
| 8732 |
+ break |
|
| 8733 |
+ } |
|
| 8734 |
+ } |
|
| 8735 |
+ var stringLenmapvalue uint64 |
|
| 8736 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 8737 |
+ if shift >= 64 {
|
|
| 8738 |
+ return ErrIntOverflowTypes |
|
| 8739 |
+ } |
|
| 8740 |
+ if iNdEx >= l {
|
|
| 8741 |
+ return io.ErrUnexpectedEOF |
|
| 8742 |
+ } |
|
| 8743 |
+ b := data[iNdEx] |
|
| 8744 |
+ iNdEx++ |
|
| 8745 |
+ stringLenmapvalue |= (uint64(b) & 0x7F) << shift |
|
| 8746 |
+ if b < 0x80 {
|
|
| 8747 |
+ break |
|
| 8748 |
+ } |
|
| 8749 |
+ } |
|
| 8750 |
+ intStringLenmapvalue := int(stringLenmapvalue) |
|
| 8751 |
+ if intStringLenmapvalue < 0 {
|
|
| 8752 |
+ return ErrInvalidLengthTypes |
|
| 8753 |
+ } |
|
| 8754 |
+ postStringIndexmapvalue := iNdEx + intStringLenmapvalue |
|
| 8755 |
+ if postStringIndexmapvalue > l {
|
|
| 8756 |
+ return io.ErrUnexpectedEOF |
|
| 8757 |
+ } |
|
| 8758 |
+ mapvalue := string(data[iNdEx:postStringIndexmapvalue]) |
|
| 8759 |
+ iNdEx = postStringIndexmapvalue |
|
| 8760 |
+ if m.Options == nil {
|
|
| 8761 |
+ m.Options = make(map[string]string) |
|
| 8762 |
+ } |
|
| 8763 |
+ m.Options[mapkey] = mapvalue |
|
| 8764 |
+ iNdEx = postIndex |
|
| 8765 |
+ default: |
|
| 8766 |
+ iNdEx = preIndex |
|
| 8767 |
+ skippy, err := skipTypes(data[iNdEx:]) |
|
| 8768 |
+ if err != nil {
|
|
| 8769 |
+ return err |
|
| 8770 |
+ } |
|
| 8771 |
+ if skippy < 0 {
|
|
| 8772 |
+ return ErrInvalidLengthTypes |
|
| 8773 |
+ } |
|
| 8774 |
+ if (iNdEx + skippy) > l {
|
|
| 8775 |
+ return io.ErrUnexpectedEOF |
|
| 8776 |
+ } |
|
| 8777 |
+ iNdEx += skippy |
|
| 8778 |
+ } |
|
| 8779 |
+ } |
|
| 8780 |
+ |
|
| 8781 |
+ if iNdEx > l {
|
|
| 8782 |
+ return io.ErrUnexpectedEOF |
|
| 8783 |
+ } |
|
| 8784 |
+ return nil |
|
| 8785 |
+} |
|
| 8577 | 8786 |
func (m *CAConfig) Unmarshal(data []byte) error {
|
| 8578 | 8787 |
l := len(data) |
| 8579 | 8788 |
iNdEx := 0 |
| ... | ... |
@@ -8636,6 +9050,37 @@ func (m *CAConfig) Unmarshal(data []byte) error {
|
| 8636 | 8636 |
return err |
| 8637 | 8637 |
} |
| 8638 | 8638 |
iNdEx = postIndex |
| 8639 |
+ case 2: |
|
| 8640 |
+ if wireType != 2 {
|
|
| 8641 |
+ return fmt.Errorf("proto: wrong wireType = %d for field ExternalCAs", wireType)
|
|
| 8642 |
+ } |
|
| 8643 |
+ var msglen int |
|
| 8644 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 8645 |
+ if shift >= 64 {
|
|
| 8646 |
+ return ErrIntOverflowTypes |
|
| 8647 |
+ } |
|
| 8648 |
+ if iNdEx >= l {
|
|
| 8649 |
+ return io.ErrUnexpectedEOF |
|
| 8650 |
+ } |
|
| 8651 |
+ b := data[iNdEx] |
|
| 8652 |
+ iNdEx++ |
|
| 8653 |
+ msglen |= (int(b) & 0x7F) << shift |
|
| 8654 |
+ if b < 0x80 {
|
|
| 8655 |
+ break |
|
| 8656 |
+ } |
|
| 8657 |
+ } |
|
| 8658 |
+ if msglen < 0 {
|
|
| 8659 |
+ return ErrInvalidLengthTypes |
|
| 8660 |
+ } |
|
| 8661 |
+ postIndex := iNdEx + msglen |
|
| 8662 |
+ if postIndex > l {
|
|
| 8663 |
+ return io.ErrUnexpectedEOF |
|
| 8664 |
+ } |
|
| 8665 |
+ m.ExternalCAs = append(m.ExternalCAs, &ExternalCA{})
|
|
| 8666 |
+ if err := m.ExternalCAs[len(m.ExternalCAs)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
|
|
| 8667 |
+ return err |
|
| 8668 |
+ } |
|
| 8669 |
+ iNdEx = postIndex |
|
| 8639 | 8670 |
default: |
| 8640 | 8671 |
iNdEx = preIndex |
| 8641 | 8672 |
skippy, err := skipTypes(data[iNdEx:]) |
| ... | ... |
@@ -9755,188 +10200,195 @@ var ( |
| 9755 | 9755 |
) |
| 9756 | 9756 |
|
| 9757 | 9757 |
var fileDescriptorTypes = []byte{
|
| 9758 |
- // 2925 bytes of a gzipped FileDescriptorProto |
|
| 9758 |
+ // 3030 bytes of a gzipped FileDescriptorProto |
|
| 9759 | 9759 |
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x58, 0x4d, 0x6c, 0x1b, 0xc7, |
| 9760 |
- 0xf5, 0x37, 0x3f, 0x45, 0x0e, 0x29, 0x89, 0x5e, 0x3b, 0x8e, 0xcc, 0xe8, 0x2f, 0xfb, 0xbf, 0x89, |
|
| 9761 |
- 0x1b, 0x37, 0x49, 0x99, 0x58, 0x49, 0x0b, 0x37, 0x41, 0x9b, 0x2c, 0x3f, 0x64, 0xb1, 0x96, 0x28, |
|
| 9762 |
- 0x62, 0x48, 0xc9, 0x08, 0x8a, 0x96, 0x58, 0x2d, 0x47, 0xe2, 0x46, 0xcb, 0x5d, 0x76, 0x77, 0x29, |
|
| 9763 |
- 0x99, 0x28, 0x0a, 0x38, 0xbd, 0xb4, 0xc8, 0xa9, 0xf7, 0x22, 0x28, 0x8a, 0xf6, 0xda, 0x73, 0x81, |
|
| 9764 |
- 0x9e, 0x7c, 0xf4, 0xb1, 0x45, 0x81, 0x22, 0xa7, 0xa0, 0x49, 0x0f, 0xbd, 0x16, 0x68, 0xd1, 0x1c, |
|
| 9765 |
- 0xda, 0x43, 0xdf, 0x9b, 0x8f, 0xe5, 0x87, 0xd7, 0x8a, 0xd3, 0xf4, 0x40, 0x70, 0xe7, 0xcd, 0xef, |
|
| 9766 |
- 0xbd, 0x99, 0x37, 0xf3, 0xe6, 0xfd, 0xde, 0x0c, 0x29, 0x84, 0x93, 0x11, 0x0b, 0x2a, 0x23, 0xdf, |
|
| 9767 |
- 0x0b, 0x3d, 0x4d, 0xeb, 0x7b, 0xd6, 0x09, 0xf3, 0x2b, 0xc1, 0x99, 0xe9, 0x0f, 0x4f, 0xec, 0xb0, |
|
| 9768 |
- 0x72, 0x7a, 0xab, 0x7c, 0x35, 0xb4, 0x87, 0x2c, 0x08, 0xcd, 0xe1, 0xe8, 0xd5, 0xe8, 0x4b, 0xc0, |
|
| 9769 |
- 0xcb, 0xcf, 0xf6, 0xc7, 0xbe, 0x19, 0xda, 0x9e, 0xfb, 0xaa, 0xfa, 0x90, 0x1d, 0x97, 0x8f, 0xbd, |
|
| 9770 |
- 0x63, 0x8f, 0x7f, 0xbe, 0x8a, 0x5f, 0x42, 0xaa, 0x5f, 0x23, 0x4b, 0x07, 0xcc, 0x0f, 0x00, 0xa6, |
|
| 9771 |
- 0x5d, 0x26, 0x19, 0xdb, 0xed, 0xb3, 0xfb, 0x6b, 0x89, 0xeb, 0x89, 0x9b, 0x69, 0x2a, 0x1a, 0xfa, |
|
| 9772 |
- 0x2f, 0x13, 0xa4, 0x60, 0xb8, 0xae, 0x17, 0x72, 0x5b, 0x81, 0xa6, 0x91, 0xb4, 0x6b, 0x0e, 0x19, |
|
| 9773 |
- 0x07, 0xe5, 0x29, 0xff, 0xd6, 0x6a, 0x24, 0xeb, 0x98, 0x87, 0xcc, 0x09, 0xd6, 0x92, 0xd7, 0x53, |
|
| 9774 |
- 0x37, 0x0b, 0x9b, 0x2f, 0x57, 0x1e, 0x9f, 0x73, 0x65, 0xc6, 0x48, 0x65, 0x87, 0xa3, 0x1b, 0x6e, |
|
| 9775 |
- 0xe8, 0x4f, 0xa8, 0x54, 0x2d, 0x7f, 0x93, 0x14, 0x66, 0xc4, 0x5a, 0x89, 0xa4, 0x4e, 0xd8, 0x44, |
|
| 9776 |
- 0x0e, 0x83, 0x9f, 0x38, 0xbf, 0x53, 0xd3, 0x19, 0x33, 0x18, 0x04, 0x65, 0xa2, 0xf1, 0x66, 0xf2, |
|
| 9777 |
- 0x76, 0x42, 0x7f, 0x97, 0xe4, 0x29, 0x0b, 0xbc, 0xb1, 0x6f, 0xb1, 0x40, 0xfb, 0x2a, 0xc9, 0xbb, |
|
| 9778 |
- 0xa6, 0xeb, 0xf5, 0xac, 0xd1, 0x38, 0xe0, 0xea, 0xa9, 0x6a, 0xf1, 0xd3, 0x8f, 0xaf, 0xe5, 0x5a, |
|
| 9779 |
- 0x20, 0xac, 0xb5, 0xf7, 0x03, 0x9a, 0xc3, 0xee, 0x1a, 0xf4, 0x6a, 0xff, 0x4f, 0x8a, 0x43, 0x36, |
|
| 9780 |
- 0xf4, 0xfc, 0x49, 0xef, 0x70, 0x12, 0xb2, 0x80, 0x1b, 0x4e, 0xd1, 0x82, 0x90, 0x55, 0x51, 0xa4, |
|
| 9781 |
- 0xff, 0x2c, 0x41, 0x2e, 0x2b, 0xdb, 0x94, 0xfd, 0x60, 0x6c, 0xfb, 0x6c, 0xc8, 0xdc, 0x30, 0xd0, |
|
| 9782 |
- 0xbe, 0x0e, 0x3e, 0xdb, 0x43, 0x3b, 0x14, 0x63, 0x14, 0x36, 0xff, 0x2f, 0xce, 0xe7, 0x68, 0x56, |
|
| 9783 |
- 0x54, 0x82, 0x35, 0x83, 0x14, 0x7d, 0x16, 0x30, 0xff, 0x54, 0xac, 0x04, 0x1f, 0xf2, 0x73, 0x95, |
|
| 9784 |
- 0xe7, 0x54, 0xf4, 0x2d, 0x92, 0x6b, 0x3b, 0x66, 0x78, 0xe4, 0xf9, 0x43, 0x4d, 0x27, 0x45, 0xd3, |
|
| 9785 |
- 0xb7, 0x06, 0x76, 0xc8, 0xac, 0x70, 0xec, 0xab, 0x5d, 0x99, 0x93, 0x69, 0x57, 0x48, 0xd2, 0x13, |
|
| 9786 |
- 0x03, 0xe5, 0xab, 0x59, 0x58, 0x89, 0xe4, 0x5e, 0x87, 0x82, 0x44, 0x7f, 0x8b, 0x5c, 0x6c, 0x3b, |
|
| 9787 |
- 0xe3, 0x63, 0xdb, 0xad, 0xb3, 0xc0, 0xf2, 0xed, 0x11, 0x5a, 0xc7, 0xed, 0xc5, 0xe0, 0x53, 0xdb, |
|
| 9788 |
- 0x8b, 0xdf, 0xd1, 0x96, 0x27, 0xa7, 0x5b, 0xae, 0xff, 0x24, 0x49, 0x2e, 0x36, 0x5c, 0x50, 0x66, |
|
| 9789 |
- 0xb3, 0xda, 0x37, 0xc8, 0x0a, 0xe3, 0xc2, 0xde, 0xa9, 0x08, 0x2a, 0x69, 0x67, 0x59, 0x48, 0x55, |
|
| 9790 |
- 0xa4, 0x35, 0x17, 0xe2, 0xe5, 0x56, 0x9c, 0xfb, 0x8f, 0x59, 0x8f, 0x8b, 0x1a, 0xad, 0x41, 0x96, |
|
| 9791 |
- 0x46, 0xdc, 0x89, 0x60, 0x2d, 0xc5, 0x6d, 0xdd, 0x88, 0xb3, 0xf5, 0x98, 0x9f, 0xd5, 0xf4, 0xa3, |
|
| 9792 |
- 0x8f, 0xaf, 0x5d, 0xa0, 0x4a, 0xf7, 0xcb, 0x04, 0xdf, 0x5f, 0x12, 0x64, 0xb5, 0xe5, 0xf5, 0xe7, |
|
| 9793 |
- 0xd6, 0xa1, 0x4c, 0x72, 0x03, 0x2f, 0x08, 0x67, 0x0e, 0x4a, 0xd4, 0xd6, 0x6e, 0x93, 0xdc, 0x48, |
|
| 9794 |
- 0x6e, 0x9f, 0xdc, 0xfd, 0xf5, 0xf8, 0x29, 0x0b, 0x0c, 0x8d, 0xd0, 0xda, 0x5b, 0x24, 0xef, 0xab, |
|
| 9795 |
- 0x98, 0x00, 0x6f, 0x9f, 0x22, 0x70, 0xa6, 0x78, 0xed, 0x5b, 0x24, 0x2b, 0x36, 0x61, 0x2d, 0xcd, |
|
| 9796 |
- 0x35, 0x6f, 0x3c, 0xd5, 0x9a, 0x53, 0xa9, 0xa4, 0x7f, 0x94, 0x20, 0x25, 0x6a, 0x1e, 0x85, 0xbb, |
|
| 9797 |
- 0x6c, 0x78, 0xc8, 0xfc, 0x0e, 0x1c, 0x64, 0x38, 0x3f, 0x57, 0x60, 0x1f, 0x99, 0xd9, 0x67, 0x3e, |
|
| 9798 |
- 0x77, 0x32, 0x47, 0x65, 0x4b, 0xdb, 0xc7, 0x20, 0x37, 0xad, 0x81, 0x79, 0x68, 0x3b, 0x76, 0x38, |
|
| 9799 |
- 0xe1, 0x6e, 0xae, 0xc4, 0xef, 0xf2, 0xa2, 0x4d, 0x98, 0xfc, 0x54, 0x91, 0xce, 0x99, 0xd1, 0xd6, |
|
| 9800 |
- 0xc8, 0x12, 0xe4, 0xba, 0xc0, 0x3c, 0x66, 0xdc, 0xfb, 0x3c, 0x55, 0x4d, 0x08, 0xe5, 0xe2, 0xac, |
|
| 9801 |
- 0x9e, 0x56, 0x20, 0x4b, 0xfb, 0xad, 0xbb, 0xad, 0xbd, 0x7b, 0xad, 0xd2, 0x05, 0x6d, 0x95, 0x14, |
|
| 9802 |
- 0xf6, 0x5b, 0xb4, 0x61, 0xd4, 0xb6, 0x8d, 0xea, 0x4e, 0xa3, 0x94, 0xd0, 0x96, 0x21, 0x5d, 0x44, |
|
| 9803 |
- 0xcd, 0xa4, 0xfe, 0x8b, 0x04, 0x21, 0xb8, 0x81, 0xd2, 0xa9, 0x37, 0x49, 0x06, 0xf2, 0x69, 0x28, |
|
| 9804 |
- 0x36, 0x6e, 0x65, 0xf3, 0x85, 0xb8, 0x59, 0x4f, 0xe1, 0x15, 0xfc, 0x63, 0x54, 0xa8, 0xcc, 0xce, |
|
| 9805 |
- 0x30, 0xb9, 0x38, 0xc3, 0x0c, 0x47, 0xce, 0x4f, 0x2d, 0x47, 0xd2, 0x75, 0xfc, 0x4a, 0x68, 0x79, |
|
| 9806 |
- 0x92, 0x81, 0x39, 0xd5, 0xdf, 0x2d, 0x25, 0x21, 0xf8, 0x8a, 0xf5, 0x66, 0xa7, 0xb6, 0xd7, 0x6a, |
|
| 9807 |
- 0x35, 0x6a, 0xdd, 0x46, 0xbd, 0x94, 0xd2, 0x6f, 0x90, 0x4c, 0x73, 0x08, 0x56, 0xb4, 0x75, 0x8c, |
|
| 9808 |
- 0x80, 0x23, 0xe6, 0x33, 0xd7, 0x52, 0x81, 0x35, 0x15, 0xe8, 0xff, 0x5c, 0x22, 0x99, 0x5d, 0x6f, |
|
| 9809 |
- 0xec, 0x86, 0xda, 0xe6, 0xcc, 0x29, 0x5e, 0xd9, 0xdc, 0x88, 0x73, 0x81, 0x03, 0x2b, 0x5d, 0x40, |
|
| 9810 |
- 0xc9, 0x53, 0x0e, 0x9b, 0x29, 0x62, 0x45, 0x4e, 0x5d, 0xb6, 0x50, 0x1e, 0x9a, 0xfe, 0x31, 0x0b, |
|
| 9811 |
- 0xe5, 0xa2, 0xcb, 0x16, 0xc6, 0xf8, 0x99, 0x6f, 0x87, 0xe6, 0xa1, 0x23, 0x42, 0x2a, 0x47, 0xa3, |
|
| 9812 |
- 0xb6, 0xb6, 0x4d, 0x8a, 0x87, 0x40, 0x1f, 0x3d, 0x6f, 0x24, 0xb2, 0x5c, 0xe6, 0xc9, 0x21, 0x27, |
|
| 9813 |
- 0xe6, 0x51, 0x05, 0xf4, 0x9e, 0x00, 0xd3, 0xc2, 0xe1, 0xb4, 0xa1, 0xb5, 0xc8, 0xca, 0xa9, 0xe7, |
|
| 9814 |
- 0x8c, 0x87, 0x2c, 0xb2, 0x95, 0xe5, 0xb6, 0x5e, 0x7c, 0xb2, 0xad, 0x03, 0x8e, 0x57, 0xd6, 0x96, |
|
| 9815 |
- 0x4f, 0x67, 0x9b, 0xe5, 0x1f, 0xa7, 0x48, 0x61, 0x66, 0x30, 0xad, 0x43, 0x0a, 0x40, 0x84, 0x23, |
|
| 9816 |
- 0xf3, 0x98, 0x27, 0x57, 0xb9, 0x60, 0xb7, 0x9e, 0x6a, 0xa2, 0x95, 0xf6, 0x54, 0x91, 0xce, 0x5a, |
|
| 9817 |
- 0xd1, 0x3f, 0x4c, 0x92, 0xc2, 0x4c, 0xa7, 0xf6, 0x12, 0xc9, 0xd1, 0x36, 0x6d, 0x1e, 0x18, 0xdd, |
|
| 9818 |
- 0x46, 0xe9, 0x42, 0x79, 0xfd, 0x83, 0x0f, 0xaf, 0xaf, 0x71, 0x6b, 0xb3, 0x06, 0xda, 0xbe, 0x7d, |
|
| 9819 |
- 0x8a, 0xf1, 0x71, 0x93, 0x2c, 0x29, 0x68, 0xa2, 0xfc, 0x1c, 0x40, 0x9f, 0x5d, 0x84, 0xce, 0x20, |
|
| 9820 |
- 0x69, 0x67, 0xdb, 0xa0, 0x10, 0x22, 0xc9, 0x78, 0x24, 0xed, 0x0c, 0x4c, 0x9f, 0xf5, 0xb5, 0xaf, |
|
| 9821 |
- 0x90, 0xac, 0x04, 0xa6, 0xca, 0x65, 0x00, 0x5e, 0x59, 0x04, 0x4e, 0x71, 0xb4, 0xb3, 0x63, 0x1c, |
|
| 9822 |
- 0x34, 0x4a, 0xe9, 0x78, 0x1c, 0xed, 0x38, 0xe6, 0x29, 0xd3, 0x5e, 0x80, 0x60, 0xe6, 0xb0, 0x4c, |
|
| 9823 |
- 0xf9, 0x2a, 0xc0, 0x9e, 0x79, 0xcc, 0x1c, 0xa2, 0xca, 0x6b, 0x3f, 0xfd, 0xd5, 0xc6, 0x85, 0xdf, |
|
| 9824 |
- 0xfd, 0x7a, 0xa3, 0xb4, 0xd8, 0x5d, 0xfe, 0x47, 0x82, 0x2c, 0xcf, 0xed, 0x12, 0x06, 0xd3, 0xc8, |
|
| 9825 |
- 0x1b, 0x8d, 0x1d, 0x75, 0xee, 0x20, 0x98, 0x54, 0x5b, 0xbb, 0xbb, 0xc0, 0x16, 0xaf, 0x3f, 0xe5, |
|
| 9826 |
- 0xd6, 0xc7, 0xf2, 0xc5, 0xdb, 0x64, 0xb9, 0x0f, 0xeb, 0xc7, 0xfc, 0x9e, 0xe5, 0xb9, 0x47, 0xf6, |
|
| 9827 |
- 0xb1, 0xcc, 0xa3, 0xe5, 0x38, 0x9b, 0x75, 0x0e, 0xa4, 0x45, 0xa1, 0x50, 0xe3, 0xf8, 0x2f, 0xc3, |
|
| 9828 |
- 0x14, 0xf7, 0x48, 0x1a, 0xcf, 0x9b, 0xf6, 0x1c, 0x49, 0x57, 0x9b, 0xad, 0x3a, 0x84, 0xc2, 0x45, |
|
| 9829 |
- 0x58, 0xbd, 0x65, 0x3e, 0x75, 0xec, 0xc0, 0xd8, 0xd2, 0xae, 0x91, 0xec, 0xc1, 0xde, 0xce, 0xfe, |
|
| 9830 |
- 0x2e, 0x6e, 0xff, 0x25, 0xe8, 0x5e, 0x8d, 0xba, 0x85, 0x73, 0xe5, 0x8b, 0x72, 0x59, 0xf3, 0x51, |
|
| 9831 |
- 0x87, 0xfe, 0xaf, 0x24, 0x59, 0xa6, 0x58, 0x05, 0xfa, 0x61, 0xdb, 0x73, 0x6c, 0x6b, 0xa2, 0xb5, |
|
| 9832 |
- 0x49, 0x1e, 0xfc, 0xeb, 0xdb, 0x33, 0x41, 0xbd, 0xf9, 0x04, 0xaa, 0x98, 0x6a, 0xa9, 0x56, 0x4d, |
|
| 9833 |
- 0x69, 0xd2, 0xa9, 0x11, 0x48, 0x29, 0x99, 0x3e, 0x73, 0xcc, 0xc9, 0x79, 0x9c, 0x55, 0x97, 0x15, |
|
| 9834 |
- 0x27, 0x15, 0x50, 0x5e, 0x5f, 0x99, 0xf7, 0x7b, 0x66, 0x18, 0xb2, 0xe1, 0x28, 0x14, 0x9c, 0x95, |
|
| 9835 |
- 0x86, 0xfa, 0xca, 0xbc, 0x6f, 0x48, 0x91, 0xf6, 0x06, 0xc9, 0x9e, 0x81, 0xdb, 0xde, 0x99, 0xa4, |
|
| 9836 |
- 0xa5, 0xf3, 0xed, 0x4a, 0xac, 0xfe, 0x01, 0xb2, 0xd1, 0xc2, 0x64, 0x71, 0x59, 0x5b, 0x7b, 0xad, |
|
| 9837 |
- 0x86, 0x5a, 0x56, 0xd9, 0xbf, 0xe7, 0xb6, 0x3c, 0x17, 0x43, 0x96, 0xec, 0xb5, 0x7a, 0x5b, 0x46, |
|
| 9838 |
- 0x73, 0x67, 0x9f, 0xe2, 0xd2, 0x5e, 0x06, 0x48, 0x29, 0x82, 0x6c, 0x99, 0xb6, 0x83, 0xa5, 0xd2, |
|
| 9839 |
- 0x55, 0x92, 0x32, 0x5a, 0x90, 0x83, 0xcb, 0x25, 0xe8, 0x2e, 0x46, 0xdd, 0x86, 0x3b, 0x99, 0x46, |
|
| 9840 |
- 0xf3, 0xe2, 0xb8, 0xfa, 0x7b, 0xa4, 0xb8, 0x3f, 0xea, 0x43, 0xa4, 0x8a, 0x08, 0xd1, 0xae, 0x43, |
|
| 9841 |
- 0x4a, 0x31, 0x7d, 0xd3, 0x71, 0x98, 0x63, 0x07, 0x43, 0x59, 0x4d, 0xcf, 0x8a, 0xa0, 0x04, 0x78, |
|
| 9842 |
- 0xfa, 0xb5, 0x94, 0x95, 0x8a, 0x50, 0xd0, 0x7f, 0x44, 0x56, 0x61, 0x94, 0xd0, 0x04, 0x4a, 0x56, |
|
| 9843 |
- 0x24, 0xbc, 0x49, 0x8a, 0x96, 0x12, 0xf5, 0xec, 0xbe, 0x08, 0xc5, 0xea, 0x2a, 0x14, 0x7a, 0x85, |
|
| 9844 |
- 0x08, 0xda, 0xac, 0xd3, 0x42, 0x04, 0x6a, 0xf6, 0xd1, 0xcf, 0x11, 0x40, 0x71, 0xf8, 0x4c, 0x75, |
|
| 9845 |
- 0x09, 0xa0, 0xa9, 0x36, 0x40, 0x50, 0x06, 0xab, 0x98, 0x67, 0xf7, 0xed, 0x10, 0x8e, 0x47, 0x5f, |
|
| 9846 |
- 0xd0, 0x6c, 0x86, 0xe6, 0x50, 0x50, 0x83, 0xb6, 0xfe, 0x7e, 0x92, 0x90, 0xae, 0x19, 0x9c, 0xc8, |
|
| 9847 |
- 0xa1, 0xa1, 0x20, 0x89, 0xae, 0x1f, 0xe7, 0x95, 0xc1, 0x5d, 0x05, 0xa2, 0x53, 0xbc, 0xf6, 0xba, |
|
| 9848 |
- 0xe2, 0x59, 0x51, 0x1d, 0xc4, 0x2b, 0xca, 0xb1, 0xe2, 0x08, 0x76, 0xbe, 0x04, 0xc0, 0x83, 0xc8, |
|
| 9849 |
- 0x7c, 0x9f, 0x47, 0x11, 0x1c, 0x44, 0xf8, 0x84, 0x5b, 0x49, 0x3e, 0xf2, 0x59, 0x32, 0xd0, 0xf3, |
|
| 9850 |
- 0x71, 0x83, 0x2c, 0x2c, 0xe8, 0xf6, 0x05, 0x3a, 0xd5, 0xab, 0x96, 0xc8, 0x8a, 0x0f, 0xc7, 0x0c, |
|
| 9851 |
- 0x66, 0xdd, 0x0b, 0x78, 0xb7, 0xfe, 0x47, 0x58, 0x83, 0x66, 0xdb, 0xd8, 0x95, 0xbb, 0x5d, 0x27, |
|
| 9852 |
- 0xd9, 0x23, 0x73, 0x68, 0x3b, 0x13, 0x79, 0xcc, 0x5e, 0x89, 0x1b, 0x62, 0x8a, 0xaf, 0x18, 0xfd, |
|
| 9853 |
- 0x3e, 0x14, 0x65, 0xc1, 0x16, 0xd7, 0xa1, 0x52, 0x97, 0x93, 0xef, 0xf8, 0xd0, 0x05, 0x92, 0x55, |
|
| 9854 |
- 0xe4, 0xcb, 0x5b, 0x98, 0x4c, 0x7c, 0xd3, 0x8d, 0xbc, 0x15, 0x0d, 0x5c, 0x05, 0xc8, 0xa4, 0xec, |
|
| 9855 |
- 0x0c, 0x22, 0x48, 0xf8, 0xab, 0x9a, 0x40, 0xbc, 0x39, 0x71, 0x57, 0x60, 0x7d, 0x70, 0x19, 0xb3, |
|
| 9856 |
- 0xe5, 0xe7, 0xcd, 0x87, 0x4a, 0xb8, 0x48, 0x93, 0x91, 0x76, 0xf9, 0x2d, 0x9e, 0x52, 0xa6, 0x5d, |
|
| 9857 |
- 0x5f, 0x28, 0xd3, 0xbd, 0x46, 0x96, 0xe7, 0xfc, 0x7c, 0xac, 0xea, 0x69, 0xb6, 0x0f, 0xde, 0x28, |
|
| 9858 |
- 0xa5, 0xe5, 0xd7, 0x37, 0x4a, 0x59, 0xfd, 0xef, 0x50, 0x84, 0xb5, 0x3d, 0x7e, 0xac, 0x70, 0x55, |
|
| 9859 |
- 0xe3, 0x6f, 0x99, 0x39, 0x7e, 0x67, 0xb5, 0x3c, 0x47, 0xc6, 0x4c, 0x6c, 0x11, 0x30, 0xb5, 0x82, |
|
| 9860 |
- 0x04, 0xcd, 0xe1, 0x34, 0x52, 0x84, 0xf4, 0x5a, 0x10, 0xf5, 0x4b, 0x6f, 0x04, 0x38, 0xbe, 0xac, |
|
| 9861 |
- 0xcb, 0x94, 0x08, 0x11, 0x6a, 0xe2, 0x15, 0x66, 0x34, 0x3e, 0x84, 0x63, 0x3a, 0x60, 0x7d, 0x81, |
|
| 9862 |
- 0x49, 0x73, 0xcc, 0x72, 0x24, 0x45, 0x98, 0x5e, 0x87, 0x4b, 0x98, 0xb2, 0xb9, 0x46, 0x52, 0xdd, |
|
| 9863 |
- 0x5a, 0x1b, 0xf2, 0xce, 0x2a, 0x64, 0x8d, 0x82, 0x12, 0x83, 0x08, 0x7b, 0xf6, 0xeb, 0x6d, 0x48, |
|
| 9864 |
- 0x37, 0x73, 0x3d, 0x20, 0x2a, 0xa7, 0x31, 0x9d, 0xe8, 0x3f, 0x4f, 0x90, 0xac, 0x60, 0x99, 0x58, |
|
| 9865 |
- 0x8f, 0x0d, 0xb2, 0xa4, 0xaa, 0x1e, 0x41, 0x7d, 0x2f, 0x3e, 0x99, 0xa6, 0x2a, 0x92, 0xf5, 0xc4, |
|
| 9866 |
- 0x3e, 0x2a, 0xbd, 0xf2, 0x9b, 0xa4, 0x38, 0xdb, 0xf1, 0x85, 0x76, 0xf1, 0x87, 0xa4, 0x80, 0x81, |
|
| 9867 |
- 0xa2, 0x38, 0x7a, 0x93, 0x64, 0x05, 0x13, 0xca, 0xa3, 0x7e, 0x1e, 0x67, 0x4a, 0x24, 0x64, 0xba, |
|
| 9868 |
- 0x25, 0xc1, 0xb3, 0xea, 0x7a, 0xb6, 0x71, 0x7e, 0x38, 0x52, 0x05, 0xd7, 0xdf, 0x26, 0xe9, 0x36, |
|
| 9869 |
- 0x03, 0x0b, 0xcf, 0x93, 0x25, 0x17, 0x52, 0xcf, 0x34, 0xb3, 0x11, 0x48, 0x57, 0x59, 0x2c, 0xc0, |
|
| 9870 |
- 0x21, 0x63, 0x65, 0xb1, 0x0b, 0xf2, 0x19, 0x2c, 0x9e, 0x09, 0xf1, 0xa6, 0x6e, 0xa8, 0xf8, 0xad, |
|
| 9871 |
- 0x77, 0x49, 0xf1, 0x1e, 0xb3, 0x8f, 0x07, 0x21, 0xec, 0x18, 0x1a, 0x7a, 0x85, 0xa4, 0x47, 0x2c, |
|
| 9872 |
- 0x9a, 0xfc, 0x5a, 0x6c, 0xe8, 0x40, 0x3f, 0xe5, 0x28, 0x3c, 0x90, 0x67, 0x5c, 0x5b, 0x3e, 0x0a, |
|
| 9873 |
- 0xc8, 0x96, 0xfe, 0x9b, 0x24, 0x59, 0x69, 0x06, 0xc1, 0xd8, 0x84, 0x82, 0x5b, 0x66, 0xc1, 0x6f, |
|
| 9874 |
- 0xcf, 0x5f, 0x18, 0x6e, 0xc6, 0x7a, 0x38, 0xa7, 0x32, 0x7f, 0x69, 0x90, 0x99, 0x2b, 0x19, 0x65, |
|
| 9875 |
- 0x2e, 0xfd, 0x51, 0x42, 0xdd, 0x16, 0x6e, 0xcc, 0x9c, 0x9b, 0xf2, 0x1a, 0x04, 0xd1, 0xe5, 0x59, |
|
| 9876 |
- 0x4b, 0x6c, 0xdf, 0x3d, 0x71, 0xbd, 0x33, 0x17, 0x88, 0x16, 0x6e, 0x0f, 0xad, 0xc6, 0x3d, 0x88, |
|
| 9877 |
- 0xb4, 0x2b, 0x00, 0xd2, 0xe6, 0x40, 0x94, 0xb9, 0xec, 0x0c, 0x2d, 0xb5, 0x1b, 0xad, 0x7a, 0xb3, |
|
| 9878 |
- 0x75, 0x07, 0xe8, 0xed, 0x71, 0x4b, 0x6d, 0x06, 0x74, 0xe6, 0x1e, 0xc3, 0x72, 0x67, 0x9b, 0x9d, |
|
| 9879 |
- 0xce, 0x3e, 0x2f, 0x15, 0x9f, 0x05, 0xd4, 0xa5, 0x39, 0x14, 0x36, 0xa0, 0x4e, 0x04, 0x10, 0x32, |
|
| 9880 |
- 0x29, 0x80, 0xd2, 0x31, 0x20, 0x24, 0x53, 0x48, 0x20, 0x22, 0xc2, 0xff, 0x9a, 0x24, 0x25, 0xc3, |
|
| 9881 |
- 0xb2, 0xd8, 0x28, 0xc4, 0x7e, 0x59, 0x9d, 0x74, 0xb1, 0xda, 0x83, 0x2f, 0x9b, 0xe1, 0xeb, 0x09, |
|
| 9882 |
- 0x86, 0xc5, 0xed, 0xd8, 0x17, 0xa3, 0x05, 0xbd, 0x0a, 0xf5, 0x1c, 0x66, 0xf4, 0x87, 0x76, 0x80, |
|
| 9883 |
- 0xaf, 0x08, 0x42, 0x46, 0x23, 0x4b, 0xe5, 0x7f, 0x27, 0xc8, 0xa5, 0x18, 0x84, 0xf6, 0x1a, 0x49, |
|
| 9884 |
- 0xfb, 0x20, 0x96, 0xdb, 0xb3, 0xfe, 0xa4, 0xfb, 0x1c, 0xaa, 0x52, 0x8e, 0xd4, 0x36, 0x08, 0x31, |
|
| 9885 |
- 0xc7, 0xa1, 0x67, 0xf2, 0xf1, 0xf9, 0xc6, 0xe4, 0xe8, 0x8c, 0x44, 0xfb, 0x1e, 0x64, 0x6b, 0x66, |
|
| 9886 |
- 0xf9, 0xf2, 0x4a, 0x54, 0xd8, 0x6c, 0xfc, 0xb7, 0xb3, 0xaf, 0x6c, 0x9b, 0x98, 0x51, 0x3a, 0xdc, |
|
| 9887 |
- 0x18, 0x95, 0x46, 0xcb, 0x6f, 0x90, 0xe2, 0xac, 0x1c, 0xa3, 0x1b, 0xca, 0x0b, 0x93, 0x3b, 0x50, |
|
| 9888 |
- 0xa4, 0xfc, 0x1b, 0x83, 0xc6, 0x74, 0x8e, 0x55, 0xd0, 0xc0, 0xa7, 0x4e, 0x49, 0xae, 0x66, 0xc8, |
|
| 9889 |
- 0xf4, 0xb9, 0x45, 0x4a, 0xfc, 0xd0, 0x58, 0xcc, 0x0f, 0x7b, 0xec, 0xfe, 0xc8, 0xf6, 0x27, 0x32, |
|
| 9890 |
- 0xee, 0xcf, 0xaf, 0xaf, 0x56, 0x50, 0xab, 0x06, 0x4a, 0x0d, 0xae, 0xa3, 0x1f, 0x90, 0x4b, 0x7b, |
|
| 9891 |
- 0xbe, 0x35, 0x00, 0xc6, 0x16, 0x00, 0x69, 0xfe, 0x6d, 0xb2, 0x1e, 0x02, 0x33, 0xf7, 0x06, 0x76, |
|
| 9892 |
- 0x10, 0xe2, 0xeb, 0x19, 0x4c, 0x92, 0xb9, 0xd8, 0xdf, 0xe3, 0xaf, 0x5c, 0xe2, 0xd5, 0x8d, 0x5e, |
|
| 9893 |
- 0x45, 0xcc, 0xb6, 0x80, 0x50, 0x85, 0xd8, 0x41, 0x80, 0xfe, 0x5d, 0x52, 0xaa, 0xdb, 0xc1, 0xc8, |
|
| 9894 |
- 0x0c, 0xc1, 0xb6, 0x2c, 0xac, 0xb5, 0x3b, 0xa4, 0x34, 0x60, 0x50, 0x58, 0x1d, 0x32, 0x13, 0x92, |
|
| 9895 |
- 0x33, 0xf3, 0x6d, 0xaf, 0xff, 0x54, 0x73, 0x5e, 0x8d, 0xb4, 0xda, 0x5c, 0x49, 0xff, 0x0c, 0xa8, |
|
| 9896 |
- 0x04, 0x9f, 0x15, 0xa4, 0xdd, 0x97, 0xc9, 0xc5, 0xc0, 0x35, 0x47, 0xc1, 0xc0, 0x0b, 0x7b, 0xb6, |
|
| 9897 |
- 0x1b, 0xe2, 0x3b, 0x9a, 0x23, 0x8b, 0xb2, 0x92, 0xea, 0x68, 0x4a, 0x39, 0x24, 0x09, 0xed, 0x84, |
|
| 9898 |
- 0xb1, 0x51, 0xcf, 0x73, 0xfa, 0x3d, 0xd5, 0x29, 0xde, 0xce, 0x00, 0x8d, 0x3d, 0x7b, 0x4e, 0xbf, |
|
| 9899 |
- 0xa3, 0xe4, 0x5a, 0x95, 0x6c, 0x38, 0xde, 0x71, 0x0f, 0x3c, 0xf3, 0x21, 0x00, 0x7b, 0x47, 0x9e, |
|
| 9900 |
- 0xdf, 0x0b, 0x1c, 0xef, 0x0c, 0x3e, 0x1c, 0xf8, 0x63, 0xbe, 0xaa, 0x78, 0xcb, 0x80, 0x6a, 0x08, |
|
| 9901 |
- 0xd0, 0x96, 0xe7, 0x77, 0xa0, 0x6f, 0x4b, 0x21, 0x90, 0x6f, 0xa6, 0x6e, 0x87, 0xb6, 0x75, 0xa2, |
|
| 9902 |
- 0xf8, 0x26, 0x92, 0x76, 0x41, 0x08, 0x47, 0x6e, 0x99, 0x39, 0xcc, 0xe2, 0x8b, 0xcc, 0x51, 0x19, |
|
| 9903 |
- 0x8e, 0x2a, 0x2a, 0x21, 0x82, 0xf4, 0xaf, 0x91, 0x7c, 0xdb, 0x31, 0x2d, 0xfe, 0x42, 0x89, 0x65, |
|
| 9904 |
- 0x28, 0xe4, 0x52, 0xdc, 0x39, 0xf0, 0x5a, 0x9c, 0xb3, 0x3c, 0x9d, 0x15, 0xe9, 0xef, 0x03, 0xfb, |
|
| 9905 |
- 0x50, 0xcf, 0x0b, 0x6b, 0x06, 0x80, 0xb3, 0x96, 0xd9, 0x53, 0xcc, 0x50, 0xac, 0xe6, 0x21, 0xc9, |
|
| 9906 |
- 0x66, 0x6a, 0xc6, 0x5d, 0x36, 0xa1, 0x19, 0xcb, 0x84, 0x3f, 0xcc, 0xc3, 0x80, 0xc0, 0x80, 0xe2, |
|
| 9907 |
- 0xcb, 0x51, 0x14, 0x79, 0x18, 0x22, 0x0e, 0x24, 0x14, 0x94, 0xf1, 0x1f, 0x8e, 0x5a, 0x51, 0x82, |
|
| 9908 |
- 0x7a, 0x03, 0x88, 0x60, 0x51, 0xb5, 0x54, 0x57, 0x00, 0x49, 0x04, 0x12, 0xe3, 0x9a, 0x12, 0x81, |
|
| 9909 |
- 0xc6, 0x6f, 0xfd, 0x4f, 0x09, 0x52, 0xc0, 0x86, 0x7d, 0x64, 0x5b, 0x98, 0xf0, 0xbe, 0xf8, 0x61, |
|
| 9910 |
- 0x85, 0x5a, 0xd6, 0x0a, 0x7c, 0x39, 0x29, 0x5e, 0xcb, 0xd6, 0x3a, 0x94, 0xa2, 0x4c, 0x7b, 0x07, |
|
| 9911 |
- 0xce, 0x29, 0x4f, 0xb8, 0xf2, 0x9c, 0xea, 0x9f, 0x9f, 0x9a, 0x65, 0xb9, 0x2d, 0xf5, 0xf8, 0x22, |
|
| 9912 |
- 0x4e, 0x67, 0xc7, 0xb7, 0xa6, 0x48, 0x67, 0x45, 0xf8, 0xba, 0x6a, 0xb9, 0x7c, 0x37, 0xe4, 0xeb, |
|
| 9913 |
- 0x6a, 0xad, 0x45, 0x41, 0xa2, 0xff, 0x01, 0xee, 0xb8, 0x0d, 0xd7, 0xf2, 0x27, 0x9c, 0x3d, 0x71, |
|
| 9914 |
- 0x05, 0xd7, 0x49, 0x1e, 0xaa, 0xba, 0x60, 0x12, 0xc0, 0xd5, 0x47, 0x3d, 0xde, 0x44, 0x02, 0xad, |
|
| 9915 |
- 0x49, 0xf2, 0x70, 0x8a, 0x3d, 0xdf, 0x0e, 0x07, 0x43, 0x59, 0xde, 0xbc, 0x1c, 0xff, 0x44, 0x37, |
|
| 9916 |
- 0x63, 0xb3, 0x62, 0x28, 0x15, 0x3a, 0xd5, 0x56, 0x1c, 0x9f, 0xe2, 0x93, 0xe5, 0x1c, 0x0f, 0x17, |
|
| 9917 |
- 0x31, 0x07, 0x6a, 0x6e, 0x28, 0x5c, 0x7a, 0x58, 0xca, 0x72, 0x3f, 0xe0, 0x4e, 0x22, 0x65, 0x58, |
|
| 9918 |
- 0x9e, 0xeb, 0x3a, 0xc9, 0x47, 0xc6, 0xf0, 0xc9, 0xcc, 0x68, 0x74, 0x7a, 0xb7, 0x36, 0x6f, 0xf7, |
|
| 9919 |
- 0xee, 0xd4, 0x76, 0x81, 0x7a, 0x44, 0x32, 0xff, 0x2d, 0xf8, 0xb4, 0x6b, 0xba, 0x50, 0x6e, 0xab, |
|
| 9920 |
- 0xcb, 0x07, 0x44, 0x85, 0x0f, 0x47, 0x4d, 0xb1, 0x73, 0x5a, 0x44, 0x05, 0x9e, 0x3e, 0x64, 0x67, |
|
| 9921 |
- 0xec, 0x8a, 0x67, 0xe7, 0x99, 0xa7, 0xc3, 0xd4, 0xb9, 0x4f, 0x87, 0xe9, 0xff, 0xc9, 0xd3, 0xe1, |
|
| 9922 |
- 0x4b, 0x9f, 0xa5, 0x48, 0x3e, 0xba, 0x4c, 0x60, 0xc8, 0x20, 0x59, 0x5e, 0x10, 0xd7, 0xbc, 0x48, |
|
| 9923 |
- 0xde, 0xe2, 0x34, 0x99, 0x37, 0x76, 0x76, 0xf6, 0x6a, 0x06, 0xbe, 0xbc, 0xbd, 0x23, 0xd8, 0x34, |
|
| 9924 |
- 0x02, 0x18, 0x70, 0x68, 0x71, 0xd3, 0xfb, 0x9a, 0x3e, 0x65, 0xd3, 0x07, 0xf2, 0x32, 0x19, 0xa1, |
|
| 9925 |
- 0x14, 0x95, 0xbe, 0x40, 0x72, 0x46, 0xa7, 0xd3, 0xbc, 0xd3, 0x02, 0x4b, 0x0f, 0x13, 0xe5, 0x67, |
|
| 9926 |
- 0x00, 0x74, 0x71, 0x6a, 0x0a, 0x58, 0xe0, 0xd8, 0x05, 0x4b, 0x88, 0xaa, 0xd5, 0x1a, 0x6d, 0x1c, |
|
| 9927 |
- 0xef, 0x41, 0x72, 0x11, 0xc5, 0x39, 0x84, 0xbf, 0xcc, 0xe4, 0xdb, 0xb4, 0xd1, 0x36, 0x28, 0x8e, |
|
| 9928 |
- 0xf8, 0x30, 0xb9, 0x30, 0xaf, 0xb6, 0xcf, 0xe0, 0x7a, 0x89, 0x63, 0x6e, 0xa8, 0x67, 0xc4, 0x07, |
|
| 9929 |
- 0xa9, 0xb2, 0x06, 0x98, 0x95, 0xe9, 0x0d, 0x0a, 0xd6, 0x77, 0x82, 0xa3, 0x75, 0xba, 0x06, 0xed, |
|
| 9930 |
- 0x72, 0x33, 0xa9, 0x85, 0xd1, 0x3a, 0x78, 0xaf, 0x45, 0x2b, 0xe0, 0x1d, 0xdd, 0x6f, 0xb5, 0xb8, |
|
| 9931 |
- 0x77, 0xe9, 0x05, 0xef, 0xe8, 0xd8, 0x75, 0x11, 0x73, 0x03, 0xe8, 0x66, 0x6f, 0xb7, 0xbd, 0xd3, |
|
| 9932 |
- 0xe8, 0x36, 0x4a, 0x0f, 0xd3, 0x0b, 0x13, 0xaa, 0x79, 0xc3, 0x91, 0xc3, 0x42, 0xe1, 0x5e, 0x67, |
|
| 9933 |
- 0x7b, 0xbf, 0xcb, 0x5f, 0x39, 0x1f, 0x64, 0x16, 0x07, 0x1c, 0x8c, 0xc3, 0x3e, 0xd6, 0x2f, 0xd7, |
|
| 9934 |
- 0xa3, 0x82, 0xe2, 0x61, 0x46, 0xbc, 0x7a, 0x44, 0x18, 0x51, 0x4d, 0xa0, 0x1d, 0xda, 0xf8, 0x8e, |
|
| 9935 |
- 0x78, 0x10, 0x7d, 0x90, 0x5d, 0xb0, 0x43, 0xd9, 0x7b, 0x90, 0x05, 0xa1, 0xe6, 0x88, 0xde, 0x46, |
|
| 9936 |
- 0xa2, 0xae, 0x97, 0xbe, 0x4f, 0x72, 0x2a, 0x61, 0xc0, 0xea, 0x64, 0xef, 0xed, 0xd1, 0xbb, 0x0d, |
|
| 9937 |
- 0x0a, 0x5b, 0xcf, 0x57, 0x47, 0xf5, 0xdc, 0xf3, 0x7c, 0x88, 0x2e, 0x98, 0xc6, 0xd2, 0xae, 0xd1, |
|
| 9938 |
- 0x32, 0xee, 0x00, 0x40, 0x3e, 0xbe, 0x28, 0x80, 0x8c, 0xfa, 0x72, 0x49, 0x0e, 0x10, 0xd9, 0xac, |
|
| 9939 |
- 0xae, 0x3f, 0xfa, 0x64, 0xe3, 0xc2, 0x47, 0xf0, 0xfb, 0xdb, 0x27, 0x1b, 0x89, 0x07, 0x9f, 0x6e, |
|
| 9940 |
- 0x24, 0x1e, 0xc1, 0xef, 0xf7, 0xf0, 0xfb, 0x33, 0xfc, 0x0e, 0xb3, 0xfc, 0xe2, 0xf1, 0xfa, 0x7f, |
|
| 9941 |
- 0x02, 0x00, 0x00, 0xff, 0xff, 0x35, 0xa0, 0x81, 0xdd, 0xd2, 0x1b, 0x00, 0x00, |
|
| 9760 |
+ 0xf5, 0x17, 0x3f, 0x45, 0x0e, 0x29, 0x89, 0x5e, 0x3b, 0x8e, 0xcc, 0xe8, 0x2f, 0xfb, 0xbf, 0x89, |
|
| 9761 |
+ 0x1b, 0xe7, 0xa3, 0x4c, 0xac, 0xa4, 0x85, 0x9b, 0xa0, 0x4d, 0x96, 0x1f, 0xb2, 0x58, 0x4b, 0x14, |
|
| 9762 |
+ 0x31, 0x94, 0x64, 0x04, 0x45, 0x4b, 0xac, 0x96, 0x23, 0x71, 0xa3, 0xe5, 0x2e, 0xbb, 0xbb, 0x94, |
|
| 9763 |
+ 0x4c, 0x14, 0x05, 0x9c, 0x5e, 0x5a, 0xe4, 0xd4, 0x7b, 0x11, 0x04, 0x45, 0x8b, 0xde, 0x7a, 0x2e, |
|
| 9764 |
+ 0xd0, 0x93, 0x8f, 0x3e, 0xb6, 0x28, 0x50, 0xe4, 0x14, 0x34, 0xe9, 0xa1, 0xd7, 0x02, 0x2d, 0x9a, |
|
| 9765 |
+ 0x43, 0x7b, 0xe8, 0x7b, 0xf3, 0xb1, 0xfc, 0xf0, 0x5a, 0x71, 0x9a, 0x1c, 0x08, 0xee, 0xbc, 0xf9, |
|
| 9766 |
+ 0xbd, 0x37, 0xf3, 0xde, 0xbc, 0x79, 0x1f, 0x43, 0x0a, 0xe1, 0x78, 0xc8, 0x82, 0xca, 0xd0, 0xf7, |
|
| 9767 |
+ 0x42, 0x4f, 0xd3, 0x7a, 0x9e, 0x75, 0xc2, 0xfc, 0x4a, 0x70, 0x66, 0xfa, 0x83, 0x13, 0x3b, 0xac, |
|
| 9768 |
+ 0x9c, 0xde, 0x2c, 0x5f, 0x09, 0xed, 0x01, 0x0b, 0x42, 0x73, 0x30, 0x7c, 0x25, 0xfa, 0x12, 0xf0, |
|
| 9769 |
+ 0xf2, 0xd3, 0xbd, 0x91, 0x6f, 0x86, 0xb6, 0xe7, 0xbe, 0xa2, 0x3e, 0xe4, 0xc4, 0xa5, 0x63, 0xef, |
|
| 9770 |
+ 0xd8, 0xe3, 0x9f, 0xaf, 0xe0, 0x97, 0xa0, 0xea, 0x57, 0xc9, 0xe2, 0x01, 0xf3, 0x03, 0x80, 0x69, |
|
| 9771 |
+ 0x97, 0x48, 0xc6, 0x76, 0x7b, 0xec, 0xde, 0x6a, 0xe2, 0x5a, 0xe2, 0x46, 0x9a, 0x8a, 0x81, 0xfe, |
|
| 9772 |
+ 0xcb, 0x04, 0x29, 0x18, 0xae, 0xeb, 0x85, 0x5c, 0x56, 0xa0, 0x69, 0x24, 0xed, 0x9a, 0x03, 0xc6, |
|
| 9773 |
+ 0x41, 0x79, 0xca, 0xbf, 0xb5, 0x1a, 0xc9, 0x3a, 0xe6, 0x21, 0x73, 0x82, 0xd5, 0xe4, 0xb5, 0xd4, |
|
| 9774 |
+ 0x8d, 0xc2, 0xc6, 0x4b, 0x95, 0x47, 0xf7, 0x5c, 0x99, 0x12, 0x52, 0xd9, 0xe6, 0xe8, 0x86, 0x1b, |
|
| 9775 |
+ 0xfa, 0x63, 0x2a, 0x59, 0xcb, 0xdf, 0x22, 0x85, 0x29, 0xb2, 0x56, 0x22, 0xa9, 0x13, 0x36, 0x96, |
|
| 9776 |
+ 0xcb, 0xe0, 0x27, 0xee, 0xef, 0xd4, 0x74, 0x46, 0x0c, 0x16, 0x41, 0x9a, 0x18, 0xbc, 0x91, 0xbc, |
|
| 9777 |
+ 0x95, 0xd0, 0xdf, 0x21, 0x79, 0xca, 0x02, 0x6f, 0xe4, 0x5b, 0x2c, 0xd0, 0x5e, 0x20, 0x79, 0xd7, |
|
| 9778 |
+ 0x74, 0xbd, 0xae, 0x35, 0x1c, 0x05, 0x9c, 0x3d, 0x55, 0x2d, 0x7e, 0xfa, 0xf1, 0xd5, 0x5c, 0x0b, |
|
| 9779 |
+ 0x88, 0xb5, 0xf6, 0x7e, 0x40, 0x73, 0x38, 0x5d, 0x83, 0x59, 0xed, 0xff, 0x49, 0x71, 0xc0, 0x06, |
|
| 9780 |
+ 0x9e, 0x3f, 0xee, 0x1e, 0x8e, 0x43, 0x16, 0x70, 0xc1, 0x29, 0x5a, 0x10, 0xb4, 0x2a, 0x92, 0xf4, |
|
| 9781 |
+ 0x9f, 0x27, 0xc8, 0x25, 0x25, 0x9b, 0xb2, 0x1f, 0x8e, 0x6c, 0x9f, 0x0d, 0x98, 0x1b, 0x06, 0xda, |
|
| 9782 |
+ 0x37, 0x40, 0x67, 0x7b, 0x60, 0x87, 0x62, 0x8d, 0xc2, 0xc6, 0xff, 0xc5, 0xe9, 0x1c, 0xed, 0x8a, |
|
| 9783 |
+ 0x4a, 0xb0, 0x66, 0x90, 0xa2, 0xcf, 0x02, 0xe6, 0x9f, 0x0a, 0x4b, 0xf0, 0x25, 0x3f, 0x97, 0x79, |
|
| 9784 |
+ 0x86, 0x45, 0xdf, 0x24, 0xb9, 0xb6, 0x63, 0x86, 0x47, 0x9e, 0x3f, 0xd0, 0x74, 0x52, 0x34, 0x7d, |
|
| 9785 |
+ 0xab, 0x6f, 0x87, 0xcc, 0x0a, 0x47, 0xbe, 0x3a, 0x95, 0x19, 0x9a, 0x76, 0x99, 0x24, 0x3d, 0xb1, |
|
| 9786 |
+ 0x50, 0xbe, 0x9a, 0x05, 0x4b, 0x24, 0x77, 0x3b, 0x14, 0x28, 0xfa, 0x9b, 0xe4, 0x42, 0xdb, 0x19, |
|
| 9787 |
+ 0x1d, 0xdb, 0x6e, 0x9d, 0x05, 0x96, 0x6f, 0x0f, 0x51, 0x3a, 0x1e, 0x2f, 0x3a, 0x9f, 0x3a, 0x5e, |
|
| 9788 |
+ 0xfc, 0x8e, 0x8e, 0x3c, 0x39, 0x39, 0x72, 0xfd, 0xa7, 0x49, 0x72, 0xa1, 0xe1, 0x02, 0x33, 0x9b, |
|
| 9789 |
+ 0xe6, 0xbe, 0x4e, 0x96, 0x19, 0x27, 0x76, 0x4f, 0x85, 0x53, 0x49, 0x39, 0x4b, 0x82, 0xaa, 0x3c, |
|
| 9790 |
+ 0xad, 0x39, 0xe7, 0x2f, 0x37, 0xe3, 0xd4, 0x7f, 0x44, 0x7a, 0x9c, 0xd7, 0x68, 0x0d, 0xb2, 0x38, |
|
| 9791 |
+ 0xe4, 0x4a, 0x04, 0xab, 0x29, 0x2e, 0xeb, 0x7a, 0x9c, 0xac, 0x47, 0xf4, 0xac, 0xa6, 0x1f, 0x7e, |
|
| 9792 |
+ 0x7c, 0x75, 0x81, 0x2a, 0xde, 0x2f, 0xe3, 0x7c, 0x7f, 0x4d, 0x90, 0x95, 0x96, 0xd7, 0x9b, 0xb1, |
|
| 9793 |
+ 0x43, 0x99, 0xe4, 0xfa, 0x5e, 0x10, 0x4e, 0x5d, 0x94, 0x68, 0xac, 0xdd, 0x22, 0xb9, 0xa1, 0x3c, |
|
| 9794 |
+ 0x3e, 0x79, 0xfa, 0x6b, 0xf1, 0x5b, 0x16, 0x18, 0x1a, 0xa1, 0xb5, 0x37, 0x49, 0xde, 0x57, 0x3e, |
|
| 9795 |
+ 0x01, 0xda, 0x3e, 0x81, 0xe3, 0x4c, 0xf0, 0xda, 0xb7, 0x49, 0x56, 0x1c, 0xc2, 0x6a, 0x9a, 0x73, |
|
| 9796 |
+ 0x5e, 0x7f, 0x22, 0x9b, 0x53, 0xc9, 0xa4, 0x7f, 0x94, 0x20, 0x25, 0x6a, 0x1e, 0x85, 0x3b, 0x6c, |
|
| 9797 |
+ 0x70, 0xc8, 0xfc, 0x0e, 0x5c, 0x64, 0xb8, 0x3f, 0x97, 0xe1, 0x1c, 0x99, 0xd9, 0x63, 0x3e, 0x57, |
|
| 9798 |
+ 0x32, 0x47, 0xe5, 0x48, 0xdb, 0x47, 0x27, 0x37, 0xad, 0xbe, 0x79, 0x68, 0x3b, 0x76, 0x38, 0xe6, |
|
| 9799 |
+ 0x6a, 0x2e, 0xc7, 0x9f, 0xf2, 0xbc, 0x4c, 0xd8, 0xfc, 0x84, 0x91, 0xce, 0x88, 0xd1, 0x56, 0xc9, |
|
| 9800 |
+ 0x22, 0xc4, 0xba, 0xc0, 0x3c, 0x66, 0x5c, 0xfb, 0x3c, 0x55, 0x43, 0x70, 0xe5, 0xe2, 0x34, 0x9f, |
|
| 9801 |
+ 0x56, 0x20, 0x8b, 0xfb, 0xad, 0x3b, 0xad, 0xdd, 0xbb, 0xad, 0xd2, 0x82, 0xb6, 0x42, 0x0a, 0xfb, |
|
| 9802 |
+ 0x2d, 0xda, 0x30, 0x6a, 0x5b, 0x46, 0x75, 0xbb, 0x51, 0x4a, 0x68, 0x4b, 0x10, 0x2e, 0xa2, 0x61, |
|
| 9803 |
+ 0x52, 0xff, 0x30, 0x41, 0x08, 0x1e, 0xa0, 0x54, 0xea, 0x0d, 0x92, 0x81, 0x78, 0x1a, 0x8a, 0x83, |
|
| 9804 |
+ 0x5b, 0xde, 0x78, 0x2e, 0x6e, 0xd7, 0x13, 0x78, 0x05, 0xff, 0x18, 0x15, 0x2c, 0xd3, 0x3b, 0x4c, |
|
| 9805 |
+ 0xce, 0xef, 0x30, 0xc3, 0x91, 0xb3, 0x5b, 0xcb, 0x91, 0x74, 0x1d, 0xbf, 0x12, 0x5a, 0x9e, 0x64, |
|
| 9806 |
+ 0x60, 0x4f, 0xf5, 0x77, 0x4a, 0x49, 0x70, 0xbe, 0x62, 0xbd, 0xd9, 0xa9, 0xed, 0xb6, 0x5a, 0x8d, |
|
| 9807 |
+ 0xda, 0x5e, 0xa3, 0x5e, 0x4a, 0xe9, 0xd7, 0x49, 0xa6, 0x39, 0x00, 0x29, 0xda, 0x1a, 0x7a, 0xc0, |
|
| 9808 |
+ 0x11, 0xf3, 0x99, 0x6b, 0x29, 0xc7, 0x9a, 0x10, 0xf4, 0x7f, 0x2d, 0x92, 0xcc, 0x8e, 0x37, 0x72, |
|
| 9809 |
+ 0x43, 0x6d, 0x63, 0xea, 0x16, 0x2f, 0x6f, 0xac, 0xc7, 0xa9, 0xc0, 0x81, 0x95, 0x3d, 0x40, 0xc9, |
|
| 9810 |
+ 0x5b, 0x0e, 0x87, 0x29, 0x7c, 0x45, 0x6e, 0x5d, 0x8e, 0x90, 0x1e, 0x9a, 0xfe, 0x31, 0x0b, 0xa5, |
|
| 9811 |
+ 0xd1, 0xe5, 0x08, 0x7d, 0xfc, 0xcc, 0xb7, 0x43, 0xf3, 0xd0, 0x11, 0x2e, 0x95, 0xa3, 0xd1, 0x58, |
|
| 9812 |
+ 0xdb, 0x22, 0xc5, 0x43, 0x48, 0x1f, 0x5d, 0x6f, 0x28, 0xa2, 0x5c, 0xe6, 0xf1, 0x2e, 0x27, 0xf6, |
|
| 9813 |
+ 0x51, 0x05, 0xf4, 0xae, 0x00, 0xd3, 0xc2, 0xe1, 0x64, 0xa0, 0xb5, 0xc8, 0xf2, 0xa9, 0xe7, 0x8c, |
|
| 9814 |
+ 0x06, 0x2c, 0x92, 0x95, 0xe5, 0xb2, 0x9e, 0x7f, 0xbc, 0xac, 0x03, 0x8e, 0x57, 0xd2, 0x96, 0x4e, |
|
| 9815 |
+ 0xa7, 0x87, 0xe5, 0x9f, 0xa4, 0x48, 0x61, 0x6a, 0x31, 0xad, 0x43, 0x0a, 0x90, 0x08, 0x87, 0xe6, |
|
| 9816 |
+ 0x31, 0x0f, 0xae, 0xd2, 0x60, 0x37, 0x9f, 0x68, 0xa3, 0x95, 0xf6, 0x84, 0x91, 0x4e, 0x4b, 0xd1, |
|
| 9817 |
+ 0x3f, 0x48, 0x92, 0xc2, 0xd4, 0xa4, 0xf6, 0x22, 0xc9, 0xd1, 0x36, 0x6d, 0x1e, 0x18, 0x7b, 0x8d, |
|
| 9818 |
+ 0xd2, 0x42, 0x79, 0xed, 0xfd, 0x0f, 0xae, 0xad, 0x72, 0x69, 0xd3, 0x02, 0xda, 0xbe, 0x7d, 0x8a, |
|
| 9819 |
+ 0xfe, 0x71, 0x83, 0x2c, 0x2a, 0x68, 0xa2, 0xfc, 0x0c, 0x40, 0x9f, 0x9e, 0x87, 0x4e, 0x21, 0x69, |
|
| 9820 |
+ 0x67, 0xcb, 0xa0, 0xe0, 0x22, 0xc9, 0x78, 0x24, 0xed, 0xf4, 0x4d, 0x9f, 0xf5, 0xb4, 0xaf, 0x91, |
|
| 9821 |
+ 0xac, 0x04, 0xa6, 0xca, 0x65, 0x00, 0x5e, 0x9e, 0x07, 0x4e, 0x70, 0xb4, 0xb3, 0x6d, 0x1c, 0x34, |
|
| 9822 |
+ 0x4a, 0xe9, 0x78, 0x1c, 0xed, 0x38, 0xe6, 0x29, 0xd3, 0x9e, 0x03, 0x67, 0xe6, 0xb0, 0x4c, 0xf9, |
|
| 9823 |
+ 0x0a, 0xc0, 0x9e, 0x7a, 0x44, 0x1c, 0xa2, 0xca, 0xab, 0x3f, 0xfb, 0xd5, 0xfa, 0xc2, 0xef, 0x7f, |
|
| 9824 |
+ 0xbd, 0x5e, 0x9a, 0x9f, 0x2e, 0xff, 0x33, 0x41, 0x96, 0x66, 0x4e, 0x09, 0x9d, 0x69, 0xe8, 0x0d, |
|
| 9825 |
+ 0x47, 0x8e, 0xba, 0x77, 0xe0, 0x4c, 0x6a, 0xac, 0xdd, 0x99, 0xcb, 0x16, 0xaf, 0x3d, 0xe1, 0xd1, |
|
| 9826 |
+ 0xc7, 0xe6, 0x8b, 0xb7, 0xc8, 0x52, 0x0f, 0xec, 0xc7, 0xfc, 0xae, 0xe5, 0xb9, 0x47, 0xf6, 0xb1, |
|
| 9827 |
+ 0x8c, 0xa3, 0xe5, 0x38, 0x99, 0x75, 0x0e, 0xa4, 0x45, 0xc1, 0x50, 0xe3, 0xf8, 0x2f, 0x93, 0x29, |
|
| 9828 |
+ 0xee, 0x92, 0x34, 0xde, 0x37, 0xed, 0x19, 0x92, 0xae, 0x36, 0x5b, 0x75, 0x70, 0x85, 0x0b, 0x60, |
|
| 9829 |
+ 0xbd, 0x25, 0xbe, 0x75, 0x9c, 0x40, 0xdf, 0xd2, 0xae, 0x92, 0xec, 0xc1, 0xee, 0xf6, 0xfe, 0x0e, |
|
| 9830 |
+ 0x1e, 0xff, 0x45, 0x98, 0x5e, 0x89, 0xa6, 0x85, 0x72, 0xe5, 0x0b, 0xd2, 0xac, 0xf9, 0x68, 0x42, |
|
| 9831 |
+ 0xff, 0x77, 0x92, 0x2c, 0x51, 0xac, 0x02, 0xfd, 0xb0, 0xed, 0x39, 0xb6, 0x35, 0xd6, 0xda, 0x24, |
|
| 9832 |
+ 0x0f, 0xfa, 0xf5, 0xec, 0x29, 0xa7, 0xde, 0x78, 0x4c, 0xaa, 0x98, 0x70, 0xa9, 0x51, 0x4d, 0x71, |
|
| 9833 |
+ 0xd2, 0x89, 0x10, 0x08, 0x29, 0x99, 0x1e, 0x73, 0xcc, 0xf1, 0x79, 0x39, 0xab, 0x2e, 0x2b, 0x4e, |
|
| 9834 |
+ 0x2a, 0xa0, 0xbc, 0xbe, 0x32, 0xef, 0x75, 0xcd, 0x30, 0x64, 0x83, 0x61, 0x28, 0x72, 0x56, 0x1a, |
|
| 9835 |
+ 0xea, 0x2b, 0xf3, 0x9e, 0x21, 0x49, 0xda, 0xeb, 0x24, 0x7b, 0x06, 0x6a, 0x7b, 0x67, 0x32, 0x2d, |
|
| 9836 |
+ 0x9d, 0x2f, 0x57, 0x62, 0xf5, 0xf7, 0x31, 0x1b, 0xcd, 0x6d, 0x16, 0xcd, 0xda, 0xda, 0x6d, 0x35, |
|
| 9837 |
+ 0x94, 0x59, 0xe5, 0xfc, 0xae, 0xdb, 0xf2, 0x5c, 0x74, 0x59, 0xb2, 0xdb, 0xea, 0x6e, 0x1a, 0xcd, |
|
| 9838 |
+ 0xed, 0x7d, 0x8a, 0xa6, 0xbd, 0x04, 0x90, 0x52, 0x04, 0xd9, 0x34, 0x6d, 0x07, 0x4b, 0xa5, 0x2b, |
|
| 9839 |
+ 0x24, 0x65, 0xb4, 0x20, 0x06, 0x97, 0x4b, 0x30, 0x5d, 0x8c, 0xa6, 0x0d, 0x77, 0x3c, 0xf1, 0xe6, |
|
| 9840 |
+ 0xf9, 0x75, 0xf5, 0x77, 0x49, 0x71, 0x7f, 0xd8, 0x03, 0x4f, 0x15, 0x1e, 0xa2, 0x5d, 0x83, 0x90, |
|
| 9841 |
+ 0x62, 0xfa, 0xa6, 0xe3, 0x30, 0xc7, 0x0e, 0x06, 0xb2, 0x9a, 0x9e, 0x26, 0x41, 0x09, 0xf0, 0xe4, |
|
| 9842 |
+ 0xb6, 0x94, 0x95, 0x8a, 0x60, 0xd0, 0x7f, 0x4c, 0x56, 0x60, 0x95, 0xd0, 0x84, 0x94, 0xac, 0x92, |
|
| 9843 |
+ 0xf0, 0x06, 0x29, 0x5a, 0x8a, 0xd4, 0xb5, 0x7b, 0xc2, 0x15, 0xab, 0x2b, 0x50, 0xe8, 0x15, 0x22, |
|
| 9844 |
+ 0x68, 0xb3, 0x4e, 0x0b, 0x11, 0xa8, 0xd9, 0x43, 0x3d, 0x87, 0x00, 0xc5, 0xe5, 0x33, 0xd5, 0x45, |
|
| 9845 |
+ 0x80, 0xa6, 0xda, 0x00, 0x41, 0x1a, 0x58, 0x31, 0xcf, 0xee, 0xd9, 0x21, 0x5c, 0x8f, 0x9e, 0x48, |
|
| 9846 |
+ 0xb3, 0x19, 0x9a, 0x43, 0x42, 0x0d, 0xc6, 0xfa, 0x7b, 0x49, 0x42, 0xf6, 0xcc, 0xe0, 0x44, 0x2e, |
|
| 9847 |
+ 0x0d, 0x05, 0x49, 0xd4, 0x7e, 0x9c, 0x57, 0x06, 0xef, 0x29, 0x10, 0x9d, 0xe0, 0xb5, 0xd7, 0x54, |
|
| 9848 |
+ 0x9e, 0x15, 0xd5, 0x41, 0x3c, 0xa3, 0x5c, 0x2b, 0x2e, 0xc1, 0xce, 0x96, 0x00, 0x78, 0x11, 0x99, |
|
| 9849 |
+ 0xef, 0x73, 0x2f, 0x82, 0x8b, 0x08, 0x9f, 0xd0, 0x95, 0xe4, 0x23, 0x9d, 0x65, 0x06, 0x7a, 0x36, |
|
| 9850 |
+ 0x6e, 0x91, 0x39, 0x83, 0x6e, 0x2d, 0xd0, 0x09, 0x5f, 0xb5, 0x44, 0x96, 0x7d, 0xb8, 0x66, 0xb0, |
|
| 9851 |
+ 0xeb, 0x6e, 0xc0, 0xa7, 0xf5, 0x3f, 0x81, 0x0d, 0x9a, 0x6d, 0x63, 0x47, 0x9e, 0x76, 0x9d, 0x64, |
|
| 9852 |
+ 0x8f, 0xcc, 0x81, 0xed, 0x8c, 0xe5, 0x35, 0x7b, 0x39, 0x6e, 0x89, 0x09, 0xbe, 0x62, 0xf4, 0x7a, |
|
| 9853 |
+ 0x50, 0x94, 0x05, 0x9b, 0x9c, 0x87, 0x4a, 0x5e, 0x9e, 0x7c, 0x47, 0x87, 0x2e, 0x24, 0x59, 0x95, |
|
| 9854 |
+ 0x7c, 0xf9, 0x08, 0x83, 0x89, 0x6f, 0xba, 0x91, 0xb6, 0x62, 0x80, 0x56, 0x80, 0x48, 0xca, 0xce, |
|
| 9855 |
+ 0xc0, 0x83, 0x84, 0xbe, 0x6a, 0x08, 0x89, 0x37, 0x27, 0x7a, 0x05, 0xd6, 0x03, 0x95, 0x31, 0x5a, |
|
| 9856 |
+ 0x7e, 0xde, 0x7e, 0xa8, 0x84, 0x8b, 0x30, 0x19, 0x71, 0x97, 0xdf, 0xe4, 0x21, 0x65, 0x32, 0xf5, |
|
| 9857 |
+ 0x85, 0x22, 0xdd, 0xab, 0x64, 0x69, 0x46, 0xcf, 0x47, 0xaa, 0x9e, 0x66, 0xfb, 0xe0, 0xf5, 0x52, |
|
| 9858 |
+ 0x5a, 0x7e, 0x7d, 0xb3, 0x94, 0xd5, 0xff, 0x01, 0x45, 0x58, 0xdb, 0xe3, 0xd7, 0x0a, 0xad, 0x1a, |
|
| 9859 |
+ 0xdf, 0x65, 0xe6, 0x78, 0xcf, 0x6a, 0x79, 0x8e, 0xf4, 0x99, 0xd8, 0x22, 0x60, 0x22, 0x05, 0x13, |
|
| 9860 |
+ 0x34, 0x87, 0xd3, 0x88, 0x11, 0xc2, 0x6b, 0x41, 0xd4, 0x2f, 0xdd, 0x21, 0xe0, 0xb8, 0x59, 0x97, |
|
| 9861 |
+ 0x28, 0x11, 0x24, 0xe4, 0xc4, 0x16, 0x66, 0x38, 0x3a, 0x84, 0x6b, 0xda, 0x67, 0x3d, 0x81, 0x49, |
|
| 9862 |
+ 0x73, 0xcc, 0x52, 0x44, 0x45, 0x98, 0x5e, 0x87, 0x26, 0x4c, 0xc9, 0x5c, 0x25, 0xa9, 0xbd, 0x5a, |
|
| 9863 |
+ 0x1b, 0xe2, 0xce, 0x0a, 0x44, 0x8d, 0x82, 0x22, 0x03, 0x09, 0x67, 0xf6, 0xeb, 0x6d, 0x08, 0x37, |
|
| 9864 |
+ 0x33, 0x33, 0x40, 0x2a, 0xa7, 0x31, 0x9c, 0xe8, 0xbf, 0x48, 0x90, 0xac, 0xc8, 0x32, 0xb1, 0x1a, |
|
| 9865 |
+ 0x1b, 0x64, 0x51, 0x55, 0x3d, 0x22, 0xf5, 0x3d, 0xff, 0xf8, 0x34, 0x55, 0x91, 0x59, 0x4f, 0x9c, |
|
| 9866 |
+ 0xa3, 0xe2, 0x2b, 0xbf, 0x41, 0x8a, 0xd3, 0x13, 0x5f, 0xe8, 0x14, 0x7f, 0x44, 0x0a, 0xe8, 0x28, |
|
| 9867 |
+ 0x2a, 0x47, 0x6f, 0x90, 0xac, 0xc8, 0x84, 0xf2, 0xaa, 0x9f, 0x97, 0x33, 0x25, 0x12, 0x22, 0xdd, |
|
| 9868 |
+ 0xa2, 0xc8, 0xb3, 0xaa, 0x3d, 0x5b, 0x3f, 0xdf, 0x1d, 0xa9, 0x82, 0xeb, 0x6f, 0x91, 0x74, 0x9b, |
|
| 9869 |
+ 0x81, 0x84, 0x67, 0xc9, 0xa2, 0x0b, 0xa1, 0x67, 0x12, 0xd9, 0x08, 0x84, 0xab, 0x2c, 0x16, 0xe0, |
|
| 9870 |
+ 0x10, 0xb1, 0xb2, 0x38, 0x05, 0xf1, 0x0c, 0x8c, 0x67, 0x82, 0xbf, 0xa9, 0x0e, 0x15, 0xbf, 0xf5, |
|
| 9871 |
+ 0x3d, 0x52, 0xbc, 0xcb, 0xec, 0xe3, 0x7e, 0x08, 0x27, 0x86, 0x82, 0x5e, 0x26, 0xe9, 0x21, 0x8b, |
|
| 9872 |
+ 0x36, 0xbf, 0x1a, 0xeb, 0x3a, 0x30, 0x4f, 0x39, 0x0a, 0x2f, 0xe4, 0x19, 0xe7, 0x96, 0x8f, 0x02, |
|
| 9873 |
+ 0x72, 0xa4, 0xff, 0x36, 0x49, 0x96, 0x9b, 0x41, 0x30, 0x32, 0xa1, 0xe0, 0x96, 0x51, 0xf0, 0x3b, |
|
| 9874 |
+ 0xb3, 0x0d, 0xc3, 0x8d, 0x58, 0x0d, 0x67, 0x58, 0x66, 0x9b, 0x06, 0x19, 0xb9, 0x92, 0x51, 0xe4, |
|
| 9875 |
+ 0xd2, 0x1f, 0x26, 0x54, 0xb7, 0x70, 0x7d, 0xea, 0xde, 0x94, 0x57, 0xc1, 0x89, 0x2e, 0x4d, 0x4b, |
|
| 9876 |
+ 0x62, 0xfb, 0xee, 0x89, 0xeb, 0x9d, 0xb9, 0x90, 0x68, 0xa1, 0x7b, 0x68, 0x35, 0xee, 0x82, 0xa7, |
|
| 9877 |
+ 0x5d, 0x06, 0x90, 0x36, 0x03, 0xa2, 0xcc, 0x65, 0x67, 0x28, 0xa9, 0xdd, 0x68, 0xd5, 0x9b, 0xad, |
|
| 9878 |
+ 0xdb, 0x90, 0xde, 0x1e, 0x95, 0xd4, 0x66, 0x90, 0xce, 0xdc, 0x63, 0x30, 0x77, 0xb6, 0xd9, 0xe9, |
|
| 9879 |
+ 0xec, 0xf3, 0x52, 0xf1, 0x69, 0x40, 0x5d, 0x9c, 0x41, 0xe1, 0x00, 0xea, 0x44, 0x00, 0x61, 0x26, |
|
| 9880 |
+ 0x05, 0x50, 0x3a, 0x06, 0x84, 0xc9, 0x14, 0x02, 0x88, 0xf0, 0xf0, 0xbf, 0x25, 0x49, 0xc9, 0xb0, |
|
| 9881 |
+ 0x2c, 0x36, 0x0c, 0x71, 0x5e, 0x56, 0x27, 0x7b, 0x58, 0xed, 0xc1, 0x97, 0xcd, 0xf0, 0xf5, 0x04, |
|
| 9882 |
+ 0xdd, 0xe2, 0x56, 0xec, 0x8b, 0xd1, 0x1c, 0x5f, 0x85, 0x7a, 0x0e, 0x33, 0x7a, 0x03, 0x3b, 0xc0, |
|
| 9883 |
+ 0x57, 0x04, 0x41, 0xa3, 0x91, 0xa4, 0xf2, 0x7f, 0x12, 0xe4, 0x62, 0x0c, 0x42, 0x7b, 0x95, 0xa4, |
|
| 9884 |
+ 0x7d, 0x20, 0xcb, 0xe3, 0x59, 0x7b, 0x5c, 0x3f, 0x87, 0xac, 0x94, 0x23, 0xb5, 0x75, 0x42, 0xcc, |
|
| 9885 |
+ 0x51, 0xe8, 0x99, 0x7c, 0x7d, 0x7e, 0x30, 0x39, 0x3a, 0x45, 0xd1, 0xbe, 0x0f, 0xd1, 0x9a, 0x59, |
|
| 9886 |
+ 0xbe, 0x6c, 0x89, 0x0a, 0x1b, 0x8d, 0xff, 0x75, 0xf7, 0x95, 0x2d, 0x13, 0x23, 0x4a, 0x87, 0x0b, |
|
| 9887 |
+ 0xa3, 0x52, 0x68, 0xf9, 0x75, 0x52, 0x9c, 0xa6, 0xa3, 0x77, 0x43, 0x79, 0x61, 0x72, 0x05, 0x8a, |
|
| 9888 |
+ 0x94, 0x7f, 0xa3, 0xd3, 0x98, 0xce, 0xb1, 0x72, 0x1a, 0xf8, 0xd4, 0x3f, 0x84, 0xbc, 0xd4, 0xb8, |
|
| 9889 |
+ 0x17, 0x32, 0xdf, 0x35, 0x9d, 0x9a, 0xa1, 0x35, 0xa6, 0xa2, 0xa5, 0xd0, 0xfc, 0x85, 0xd8, 0x8e, |
|
| 9890 |
+ 0x3f, 0xe2, 0xa8, 0xd4, 0x8c, 0x98, 0x78, 0x09, 0x95, 0xc2, 0xc8, 0x77, 0xe4, 0xeb, 0x11, 0xaf, |
|
| 9891 |
+ 0x14, 0xf6, 0xe9, 0x36, 0x45, 0x1a, 0x3e, 0xbd, 0xa8, 0xe8, 0x94, 0x7a, 0xfc, 0xb3, 0xdf, 0xd4, |
|
| 9892 |
+ 0x02, 0x5f, 0x7d, 0x84, 0x7a, 0x99, 0x90, 0xc9, 0xae, 0xe1, 0xd8, 0x32, 0xb5, 0xcd, 0x4e, 0x67, |
|
| 9893 |
+ 0x1b, 0xae, 0x0a, 0xaf, 0x9c, 0x27, 0x53, 0x9c, 0xac, 0xff, 0x26, 0x41, 0x72, 0x35, 0x43, 0x66, |
|
| 9894 |
+ 0x98, 0x4d, 0x52, 0xe2, 0x71, 0xc5, 0x62, 0x7e, 0xd8, 0x65, 0xf7, 0x86, 0xb6, 0x3f, 0x96, 0xa1, |
|
| 9895 |
+ 0xe1, 0xfc, 0x12, 0x74, 0x19, 0xb9, 0x6a, 0xc0, 0xd4, 0xe0, 0x3c, 0x1a, 0x25, 0x45, 0x26, 0x55, |
|
| 9896 |
+ 0xec, 0x5a, 0xa6, 0x0a, 0xd4, 0xeb, 0xe7, 0x9b, 0x42, 0x94, 0x67, 0x93, 0x31, 0x34, 0xbd, 0x4a, |
|
| 9897 |
+ 0x48, 0xcd, 0x0c, 0xf4, 0x03, 0x72, 0x71, 0xd7, 0xb7, 0xfa, 0x50, 0x28, 0x89, 0x45, 0xe5, 0x96, |
|
| 9898 |
+ 0xdf, 0x22, 0x6b, 0x21, 0x14, 0x44, 0xdd, 0xbe, 0x1d, 0x84, 0xf8, 0x68, 0x09, 0xbe, 0xc1, 0x5c, |
|
| 9899 |
+ 0x9c, 0xef, 0xf2, 0xc7, 0x45, 0xf1, 0xd8, 0x49, 0xaf, 0x20, 0x66, 0x4b, 0x40, 0xa8, 0x42, 0x6c, |
|
| 9900 |
+ 0x23, 0x40, 0xff, 0x1e, 0x29, 0xd5, 0xed, 0x60, 0x68, 0x86, 0x20, 0x5b, 0xf6, 0x33, 0xda, 0x6d, |
|
| 9901 |
+ 0x52, 0xea, 0x33, 0xa8, 0x67, 0x0f, 0x99, 0x09, 0x39, 0x91, 0xf9, 0xb6, 0xd7, 0x7b, 0x22, 0x3b, |
|
| 9902 |
+ 0xac, 0x44, 0x5c, 0x6d, 0xce, 0xa4, 0x7f, 0x06, 0x19, 0x1c, 0x5f, 0x73, 0xa4, 0xdc, 0x97, 0xc8, |
|
| 9903 |
+ 0x85, 0xc0, 0x35, 0x87, 0x41, 0xdf, 0x0b, 0xbb, 0xb6, 0x1b, 0xe2, 0xf3, 0xa5, 0x23, 0x6b, 0xe1, |
|
| 9904 |
+ 0x92, 0x9a, 0x68, 0x4a, 0x3a, 0xc4, 0x66, 0xed, 0x84, 0xb1, 0x61, 0xd7, 0x73, 0x7a, 0x5d, 0x35, |
|
| 9905 |
+ 0x29, 0x9e, 0x2c, 0x01, 0x8d, 0x33, 0xbb, 0x4e, 0xaf, 0xa3, 0xe8, 0x5a, 0x95, 0xac, 0x3b, 0xde, |
|
| 9906 |
+ 0x71, 0x17, 0x34, 0xf3, 0xe1, 0xde, 0x77, 0x8f, 0x3c, 0xbf, 0x1b, 0x38, 0xde, 0x19, 0x7c, 0x38, |
|
| 9907 |
+ 0xf0, 0xc7, 0x7c, 0xd5, 0x68, 0x94, 0x01, 0xd5, 0x10, 0xa0, 0x4d, 0xcf, 0xef, 0xc0, 0xdc, 0xa6, |
|
| 9908 |
+ 0x42, 0x60, 0x9a, 0x9f, 0xa8, 0x1d, 0xda, 0xd6, 0x89, 0x4a, 0xf3, 0x11, 0x75, 0x0f, 0x88, 0x10, |
|
| 9909 |
+ 0xe9, 0x96, 0x98, 0xc3, 0x2c, 0x6e, 0x64, 0x8e, 0xca, 0x70, 0x54, 0x51, 0x11, 0x11, 0xa4, 0x7f, |
|
| 9910 |
+ 0x9d, 0xe4, 0xdb, 0x8e, 0x69, 0xf1, 0x87, 0x61, 0xac, 0xfe, 0x21, 0x85, 0xe1, 0xc9, 0x81, 0xd6, |
|
| 9911 |
+ 0x22, 0xbc, 0xe5, 0xe9, 0x34, 0x49, 0x7f, 0x0f, 0x92, 0x3e, 0xf5, 0xbc, 0x10, 0x2e, 0xe9, 0x35, |
|
| 9912 |
+ 0x92, 0xb5, 0xcc, 0xae, 0x72, 0xf7, 0x62, 0x35, 0x0f, 0x6e, 0x91, 0xa9, 0x19, 0x77, 0xd8, 0x98, |
|
| 9913 |
+ 0x66, 0x2c, 0x13, 0xfe, 0x30, 0xfd, 0x01, 0x02, 0x9d, 0x94, 0x9b, 0xa3, 0x28, 0xd2, 0x1f, 0x78, |
|
| 9914 |
+ 0x31, 0x50, 0x28, 0x30, 0xe3, 0x3f, 0x44, 0xb8, 0xa2, 0x04, 0x75, 0xfb, 0x10, 0x38, 0x44, 0xb1, |
|
| 9915 |
+ 0x58, 0x5d, 0x06, 0x24, 0x11, 0x48, 0x0c, 0x27, 0x94, 0x08, 0x34, 0x7e, 0xeb, 0x7f, 0x4e, 0x90, |
|
| 9916 |
+ 0x02, 0x0e, 0xec, 0x23, 0xdb, 0xc2, 0x3c, 0xf3, 0xc5, 0x63, 0x24, 0x04, 0x06, 0x2b, 0xf0, 0xe5, |
|
| 9917 |
+ 0xa6, 0x78, 0x60, 0xa8, 0x75, 0x28, 0x45, 0x9a, 0xf6, 0x36, 0x84, 0x47, 0x9e, 0xe7, 0x64, 0x78, |
|
| 9918 |
+ 0xd4, 0x3f, 0x3f, 0x23, 0xca, 0x2e, 0x47, 0xf2, 0x71, 0x23, 0x4e, 0x76, 0xc7, 0x8f, 0xa6, 0x48, |
|
| 9919 |
+ 0xa7, 0x49, 0xf8, 0xa8, 0x6d, 0xb9, 0xfc, 0x34, 0xe4, 0xa3, 0x76, 0xad, 0x45, 0x81, 0xa2, 0xff, |
|
| 9920 |
+ 0x31, 0x41, 0x96, 0x1a, 0xae, 0xe5, 0x8f, 0x79, 0x48, 0x41, 0x0b, 0xae, 0x91, 0x3c, 0x14, 0xd3, |
|
| 9921 |
+ 0xc1, 0x38, 0x80, 0x8e, 0x53, 0xbd, 0x99, 0x45, 0x04, 0xad, 0x49, 0xf2, 0x10, 0x3c, 0x3d, 0xdf, |
|
| 9922 |
+ 0x0e, 0xfb, 0x03, 0x59, 0x55, 0xc6, 0x87, 0xb1, 0x69, 0x99, 0x15, 0x43, 0xb1, 0xd0, 0x09, 0xb7, |
|
| 9923 |
+ 0x0a, 0x5c, 0x29, 0xbe, 0x59, 0x1e, 0xb8, 0xa0, 0xff, 0x75, 0xa0, 0xd5, 0x81, 0x7a, 0xb1, 0x8b, |
|
| 9924 |
+ 0x1d, 0x04, 0xd7, 0x03, 0x5a, 0x41, 0x49, 0xc3, 0xae, 0x48, 0xd7, 0x49, 0x3e, 0x12, 0x86, 0x2f, |
|
| 9925 |
+ 0x95, 0x46, 0xa3, 0xd3, 0xbd, 0xb9, 0x71, 0xab, 0x7b, 0xbb, 0xb6, 0x03, 0x61, 0x4c, 0xe4, 0xd0, |
|
| 9926 |
+ 0xdf, 0x81, 0x4e, 0x3b, 0xa6, 0x0b, 0x5d, 0x8e, 0xea, 0xf9, 0xc0, 0x2b, 0x7c, 0xb8, 0x6a, 0xaa, |
|
| 9927 |
+ 0x28, 0x4a, 0x0b, 0xaf, 0xc0, 0xdb, 0x87, 0x45, 0x11, 0x4e, 0xc5, 0x17, 0x45, 0x53, 0x2f, 0xb6, |
|
| 9928 |
+ 0xa9, 0x73, 0x5f, 0x6c, 0xd3, 0x5f, 0xc9, 0x8b, 0xed, 0x8b, 0x9f, 0xa5, 0x48, 0x3e, 0xea, 0xe1, |
|
| 9929 |
+ 0xd0, 0x65, 0xb0, 0x46, 0x59, 0x10, 0xdd, 0x75, 0x44, 0x6f, 0xf1, 0xea, 0x24, 0x6f, 0x6c, 0x6f, |
|
| 9930 |
+ 0xef, 0xd6, 0x0c, 0x7c, 0xf0, 0x7c, 0x5b, 0x14, 0x31, 0x11, 0xc0, 0x80, 0x4b, 0x8b, 0x87, 0xde, |
|
| 9931 |
+ 0xd3, 0xf4, 0x49, 0x11, 0x73, 0x5f, 0xf6, 0xf0, 0x11, 0x4a, 0x55, 0x30, 0xcf, 0x91, 0x9c, 0xd1, |
|
| 9932 |
+ 0xe9, 0x34, 0x6f, 0xb7, 0x40, 0xd2, 0x83, 0x44, 0xf9, 0x29, 0x00, 0x5d, 0x98, 0x88, 0x82, 0xe4, |
|
| 9933 |
+ 0x7b, 0xec, 0x82, 0x24, 0x44, 0xd5, 0x6a, 0x8d, 0x36, 0xae, 0x77, 0x3f, 0x39, 0x8f, 0xe2, 0xa9, |
|
| 9934 |
+ 0x9b, 0x3f, 0x88, 0xe5, 0xdb, 0xb4, 0xd1, 0x36, 0x28, 0xae, 0xf8, 0x20, 0x39, 0xb7, 0xaf, 0xb6, |
|
| 9935 |
+ 0xcf, 0xa0, 0xab, 0xc7, 0x35, 0xd7, 0xd5, 0xeb, 0xed, 0xfd, 0x54, 0x59, 0x03, 0xcc, 0xf2, 0xa4, |
|
| 9936 |
+ 0x71, 0x05, 0xfb, 0x8e, 0x71, 0xb5, 0xce, 0x9e, 0x41, 0xf7, 0xb8, 0x98, 0xd4, 0xdc, 0x6a, 0x1d, |
|
| 9937 |
+ 0x7c, 0x4e, 0x40, 0x29, 0xa0, 0x1d, 0xdd, 0x6f, 0xb5, 0xb8, 0x76, 0xe9, 0x39, 0xed, 0xe8, 0xc8, |
|
| 9938 |
+ 0x75, 0x11, 0x73, 0x1d, 0x52, 0xd8, 0xee, 0x4e, 0x7b, 0xbb, 0xb1, 0xd7, 0x28, 0x3d, 0x48, 0xcf, |
|
| 9939 |
+ 0x6d, 0xa8, 0xe6, 0x0d, 0x86, 0x0e, 0x0b, 0x85, 0x7a, 0x9d, 0xad, 0xfd, 0x3d, 0xfe, 0xb8, 0x7c, |
|
| 9940 |
+ 0x3f, 0x33, 0xbf, 0x60, 0x7f, 0x14, 0xf6, 0xb0, 0x6c, 0xbc, 0x16, 0xd5, 0x71, 0x0f, 0x32, 0x22, |
|
| 9941 |
+ 0x65, 0x46, 0x18, 0x51, 0xc4, 0xa1, 0x1c, 0xda, 0xf8, 0xae, 0x78, 0x87, 0xbe, 0x9f, 0x9d, 0x93, |
|
| 9942 |
+ 0x43, 0xd9, 0xbb, 0x10, 0x05, 0xa1, 0xd4, 0x8b, 0x9e, 0xa4, 0xa2, 0xa9, 0x17, 0x7f, 0x40, 0x72, |
|
| 9943 |
+ 0x2a, 0x60, 0x80, 0x75, 0xb2, 0x77, 0x77, 0xe9, 0x9d, 0x06, 0x85, 0xa3, 0xe7, 0xd6, 0x51, 0x33, |
|
| 9944 |
+ 0x77, 0x3d, 0x1f, 0xbc, 0x0b, 0xb6, 0xb1, 0xb8, 0x63, 0xb4, 0x8c, 0xdb, 0x00, 0x90, 0x6f, 0x5e, |
|
| 9945 |
+ 0x0a, 0x20, 0xbd, 0xbe, 0x5c, 0x92, 0x0b, 0x44, 0x32, 0xab, 0x6b, 0x0f, 0x3f, 0x59, 0x5f, 0xf8, |
|
| 9946 |
+ 0x08, 0x7e, 0x7f, 0xff, 0x64, 0x3d, 0x71, 0xff, 0xd3, 0xf5, 0xc4, 0x43, 0xf8, 0xfd, 0x01, 0x7e, |
|
| 9947 |
+ 0x7f, 0x81, 0xdf, 0x61, 0x96, 0xd7, 0x2f, 0xaf, 0xfd, 0x37, 0x00, 0x00, 0xff, 0xff, 0x2c, 0xf4, |
|
| 9948 |
+ 0xf4, 0x16, 0x49, 0x1d, 0x00, 0x00, |
|
| 9942 | 9949 |
} |
| ... | ... |
@@ -447,9 +447,29 @@ message AcceptancePolicy {
|
| 447 | 447 |
} |
| 448 | 448 |
|
| 449 | 449 |
|
| 450 |
+message ExternalCA {
|
|
| 451 |
+ enum CAProtocol {
|
|
| 452 |
+ CFSSL = 0 [(gogoproto.enumvalue_customname) = "CAProtocolCFSSL"]; |
|
| 453 |
+ } |
|
| 454 |
+ |
|
| 455 |
+ // Protocol is the protocol used by this external CA. |
|
| 456 |
+ CAProtocol protocol = 1; |
|
| 457 |
+ |
|
| 458 |
+ // URL is the URL where the external CA can be reached. |
|
| 459 |
+ string url = 2 [(gogoproto.customname) = "URL"]; |
|
| 460 |
+ |
|
| 461 |
+ // Options is a set of additional key/value pairs whose interpretation |
|
| 462 |
+ // depends on the specified CA type. |
|
| 463 |
+ map<string, string> options = 3; |
|
| 464 |
+} |
|
| 465 |
+ |
|
| 450 | 466 |
message CAConfig {
|
| 451 | 467 |
// NodeCertExpiry is the duration certificates should be issued for |
| 452 | 468 |
Duration node_cert_expiry = 1; |
| 469 |
+ |
|
| 470 |
+ // ExternalCAs is a list of CAs to which a manager node will make |
|
| 471 |
+ // certificate signing requests for node certificates. |
|
| 472 |
+ repeated ExternalCA external_cas = 2 [(gogoproto.customname) = "ExternalCAs"]; |
|
| 453 | 473 |
} |
| 454 | 474 |
|
| 455 | 475 |
// OrchestrationConfig defines cluster-level orchestration settings. |
| ... | ... |
@@ -167,7 +167,16 @@ func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, paths Cert |
| 167 | 167 |
} |
| 168 | 168 |
|
| 169 | 169 |
// Get the remote manager to issue a CA signed certificate for this node |
| 170 |
- signedCert, err := GetRemoteSignedCertificate(ctx, csr, role, secret, rca.Pool, picker, transport, nodeInfo) |
|
| 170 |
+ // Retry up to 5 times in case the manager we first try to contact isn't |
|
| 171 |
+ // responding properly (for example, it may have just been demoted). |
|
| 172 |
+ var signedCert []byte |
|
| 173 |
+ for i := 0; i != 5; i++ {
|
|
| 174 |
+ signedCert, err = GetRemoteSignedCertificate(ctx, csr, role, secret, rca.Pool, picker, transport, nodeInfo) |
|
| 175 |
+ if err == nil {
|
|
| 176 |
+ break |
|
| 177 |
+ } |
|
| 178 |
+ log.Warningf("error fetching signed node certificate: %v", err)
|
|
| 179 |
+ } |
|
| 171 | 180 |
if err != nil {
|
| 172 | 181 |
return nil, err |
| 173 | 182 |
} |
| ... | ... |
@@ -192,6 +201,12 @@ func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, paths Cert |
| 192 | 192 |
return nil, err |
| 193 | 193 |
} |
| 194 | 194 |
|
| 195 |
+ // Create a valid TLSKeyPair out of the PEM encoded private key and certificate |
|
| 196 |
+ tlsKeyPair, err := tls.X509KeyPair(signedCert, key) |
|
| 197 |
+ if err != nil {
|
|
| 198 |
+ return nil, err |
|
| 199 |
+ } |
|
| 200 |
+ |
|
| 195 | 201 |
log.Infof("Downloaded new TLS credentials with role: %s.", role)
|
| 196 | 202 |
|
| 197 | 203 |
// Ensure directory exists |
| ... | ... |
@@ -210,40 +225,50 @@ func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, paths Cert |
| 210 | 210 |
return nil, err |
| 211 | 211 |
} |
| 212 | 212 |
|
| 213 |
- // Create a valid TLSKeyPair out of the PEM encoded private key and certificate |
|
| 214 |
- tlsKeyPair, err := tls.X509KeyPair(signedCert, key) |
|
| 215 |
- if err != nil {
|
|
| 216 |
- return nil, err |
|
| 217 |
- } |
|
| 218 |
- |
|
| 219 | 213 |
return &tlsKeyPair, nil |
| 220 | 214 |
} |
| 221 | 215 |
|
| 222 |
-// ParseValidateAndSignCSR returns a signed certificate from a particular rootCA and a CSR. |
|
| 223 |
-func (rca *RootCA) ParseValidateAndSignCSR(csrBytes []byte, cn, ou, org string) ([]byte, error) {
|
|
| 224 |
- if !rca.CanSign() {
|
|
| 225 |
- return nil, ErrNoValidSigner |
|
| 226 |
- } |
|
| 227 |
- |
|
| 228 |
- // All managers get added the subject-alt-name of CA, so they can be used for cert issuance |
|
| 216 |
+// PrepareCSR creates a CFSSL Sign Request based on the given raw CSR and |
|
| 217 |
+// overrides the Subject and Hosts with the given extra args. |
|
| 218 |
+func PrepareCSR(csrBytes []byte, cn, ou, org string) cfsigner.SignRequest {
|
|
| 219 |
+ // All managers get added the subject-alt-name of CA, so they can be |
|
| 220 |
+ // used for cert issuance. |
|
| 229 | 221 |
hosts := []string{ou}
|
| 230 | 222 |
if ou == ManagerRole {
|
| 231 | 223 |
hosts = append(hosts, CARole) |
| 232 | 224 |
} |
| 233 | 225 |
|
| 234 |
- cert, err := rca.Signer.Sign(cfsigner.SignRequest{
|
|
| 226 |
+ return cfsigner.SignRequest{
|
|
| 235 | 227 |
Request: string(csrBytes), |
| 236 | 228 |
// OU is used for Authentication of the node type. The CN has the random |
| 237 | 229 |
// node ID. |
| 238 | 230 |
Subject: &cfsigner.Subject{CN: cn, Names: []cfcsr.Name{{OU: ou, O: org}}},
|
| 239 | 231 |
// Adding ou as DNS alt name, so clients can connect to ManagerRole and CARole |
| 240 | 232 |
Hosts: hosts, |
| 241 |
- }) |
|
| 233 |
+ } |
|
| 234 |
+} |
|
| 235 |
+ |
|
| 236 |
+// ParseValidateAndSignCSR returns a signed certificate from a particular rootCA and a CSR. |
|
| 237 |
+func (rca *RootCA) ParseValidateAndSignCSR(csrBytes []byte, cn, ou, org string) ([]byte, error) {
|
|
| 238 |
+ if !rca.CanSign() {
|
|
| 239 |
+ return nil, ErrNoValidSigner |
|
| 240 |
+ } |
|
| 241 |
+ |
|
| 242 |
+ signRequest := PrepareCSR(csrBytes, cn, ou, org) |
|
| 243 |
+ |
|
| 244 |
+ cert, err := rca.Signer.Sign(signRequest) |
|
| 242 | 245 |
if err != nil {
|
| 243 | 246 |
log.Debugf("failed to sign node certificate: %v", err)
|
| 244 | 247 |
return nil, err |
| 245 | 248 |
} |
| 246 | 249 |
|
| 250 |
+ return rca.AppendFirstRootPEM(cert) |
|
| 251 |
+} |
|
| 252 |
+ |
|
| 253 |
+// AppendFirstRootPEM appends the first certificate from this RootCA's cert |
|
| 254 |
+// bundle to the given cert bundle (which should already be encoded as a series |
|
| 255 |
+// of PEM-encoded certificate blocks). |
|
| 256 |
+func (rca *RootCA) AppendFirstRootPEM(cert []byte) ([]byte, error) {
|
|
| 247 | 257 |
// Append the first root CA Cert to the certificate, to create a valid chain |
| 248 | 258 |
// Get the first Root CA Cert on the bundle |
| 249 | 259 |
firstRootCA, _, err := helpers.ParseOneCertificateFromPEM(rca.Cert) |
| ... | ... |
@@ -390,7 +415,7 @@ func GetLocalRootCA(baseDir string) (RootCA, error) {
|
| 390 | 390 |
|
| 391 | 391 |
rootCA, err := NewRootCA(cert, key, DefaultNodeCertExpiration) |
| 392 | 392 |
if err == nil {
|
| 393 |
- log.Debugf("successfully loaded the signer for the Root CA: %s", paths.RootCA.Cert)
|
|
| 393 |
+ log.Debugf("successfully loaded the Root CA: %s", paths.RootCA.Cert)
|
|
| 394 | 394 |
} |
| 395 | 395 |
|
| 396 | 396 |
return rootCA, err |
| ... | ... |
@@ -602,7 +627,7 @@ func GetRemoteSignedCertificate(ctx context.Context, csr []byte, role, secret st |
| 602 | 602 |
} |
| 603 | 603 |
defer conn.Close() |
| 604 | 604 |
|
| 605 |
- // Create a CAClient to retreive a new Certificate |
|
| 605 |
+ // Create a CAClient to retrieve a new Certificate |
|
| 606 | 606 |
caClient := api.NewNodeCAClient(conn) |
| 607 | 607 |
|
| 608 | 608 |
// Convert our internal string roles into an API role |
| ... | ... |
@@ -644,7 +669,15 @@ func GetRemoteSignedCertificate(ctx context.Context, csr []byte, role, secret st |
| 644 | 644 |
if statusResponse.Certificate == nil {
|
| 645 | 645 |
return nil, fmt.Errorf("no certificate in CertificateStatus response")
|
| 646 | 646 |
} |
| 647 |
- return statusResponse.Certificate.Certificate, nil |
|
| 647 |
+ |
|
| 648 |
+ // The certificate in the response must match the CSR |
|
| 649 |
+ // we submitted. If we are getting a response for a |
|
| 650 |
+ // certificate that was previously issued, we need to |
|
| 651 |
+ // retry until the certificate gets updated per our |
|
| 652 |
+ // current request. |
|
| 653 |
+ if bytes.Equal(statusResponse.Certificate.CSR, csr) {
|
|
| 654 |
+ return statusResponse.Certificate.Certificate, nil |
|
| 655 |
+ } |
|
| 648 | 656 |
} |
| 649 | 657 |
|
| 650 | 658 |
// If we're still pending, the issuance failed, or the state is unknown |
| ... | ... |
@@ -45,7 +45,8 @@ const ( |
| 45 | 45 |
type SecurityConfig struct {
|
| 46 | 46 |
mu sync.Mutex |
| 47 | 47 |
|
| 48 |
- rootCA *RootCA |
|
| 48 |
+ rootCA *RootCA |
|
| 49 |
+ externalCA *ExternalCA |
|
| 49 | 50 |
|
| 50 | 51 |
ServerTLSCreds *MutableTLSCreds |
| 51 | 52 |
ClientTLSCreds *MutableTLSCreds |
| ... | ... |
@@ -60,8 +61,19 @@ type CertificateUpdate struct {
|
| 60 | 60 |
|
| 61 | 61 |
// NewSecurityConfig initializes and returns a new SecurityConfig. |
| 62 | 62 |
func NewSecurityConfig(rootCA *RootCA, clientTLSCreds, serverTLSCreds *MutableTLSCreds) *SecurityConfig {
|
| 63 |
+ // Make a new TLS config for the external CA client without a |
|
| 64 |
+ // ServerName value set. |
|
| 65 |
+ clientTLSConfig := clientTLSCreds.Config() |
|
| 66 |
+ |
|
| 67 |
+ externalCATLSConfig := &tls.Config{
|
|
| 68 |
+ Certificates: clientTLSConfig.Certificates, |
|
| 69 |
+ RootCAs: clientTLSConfig.RootCAs, |
|
| 70 |
+ MinVersion: tls.VersionTLS12, |
|
| 71 |
+ } |
|
| 72 |
+ |
|
| 63 | 73 |
return &SecurityConfig{
|
| 64 | 74 |
rootCA: rootCA, |
| 75 |
+ externalCA: NewExternalCA(rootCA, externalCATLSConfig), |
|
| 65 | 76 |
ClientTLSCreds: clientTLSCreds, |
| 66 | 77 |
ServerTLSCreds: serverTLSCreds, |
| 67 | 78 |
} |
| ... | ... |
@@ -164,8 +176,18 @@ func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, caHash, secret |
| 164 | 164 |
return nil, err |
| 165 | 165 |
} |
| 166 | 166 |
|
| 167 |
- // Get the remote CA certificate, verify integrity with the hash provided |
|
| 168 |
- rootCA, err = GetRemoteCA(ctx, d, picker) |
|
| 167 |
+ // Get the remote CA certificate, verify integrity with the |
|
| 168 |
+ // hash provided. Retry up to 5 times, in case the manager we |
|
| 169 |
+ // first try to contact is not responding properly (it may have |
|
| 170 |
+ // just been demoted, for example). |
|
| 171 |
+ |
|
| 172 |
+ for i := 0; i != 5; i++ {
|
|
| 173 |
+ rootCA, err = GetRemoteCA(ctx, d, picker) |
|
| 174 |
+ if err == nil {
|
|
| 175 |
+ break |
|
| 176 |
+ } |
|
| 177 |
+ log.Warningf("failed to retrieve remote root CA certificate: %v", err)
|
|
| 178 |
+ } |
|
| 169 | 179 |
if err != nil {
|
| 170 | 180 |
return nil, err |
| 171 | 181 |
} |
| ... | ... |
@@ -180,9 +202,9 @@ func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, caHash, secret |
| 180 | 180 |
return nil, err |
| 181 | 181 |
} |
| 182 | 182 |
|
| 183 |
- // At this point we've successfully loaded the CA details from disk, or successfully |
|
| 184 |
- // downloaded them remotely. |
|
| 185 |
- // The next step is to try to load our certificates. |
|
| 183 |
+ // At this point we've successfully loaded the CA details from disk, or |
|
| 184 |
+ // successfully downloaded them remotely. The next step is to try to |
|
| 185 |
+ // load our certificates. |
|
| 186 | 186 |
clientTLSCreds, serverTLSCreds, err = LoadTLSCreds(rootCA, paths.Node) |
| 187 | 187 |
if err != nil {
|
| 188 | 188 |
log.Debugf("no valid local TLS credentials found: %v", err)
|
| ... | ... |
@@ -204,6 +226,9 @@ func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, caHash, secret |
| 204 | 204 |
} |
| 205 | 205 |
} |
| 206 | 206 |
tlsKeyPair, err = rootCA.IssueAndSaveNewCertificates(paths.Node, cn, proposedRole, org) |
| 207 |
+ if err != nil {
|
|
| 208 |
+ return nil, err |
|
| 209 |
+ } |
|
| 207 | 210 |
} else {
|
| 208 | 211 |
// There was an error loading our Credentials, let's get a new certificate issued |
| 209 | 212 |
// Last argument is nil because at this point we don't have any valid TLS creds |
| ... | ... |
@@ -211,7 +236,6 @@ func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, caHash, secret |
| 211 | 211 |
if err != nil {
|
| 212 | 212 |
return nil, err |
| 213 | 213 |
} |
| 214 |
- |
|
| 215 | 214 |
} |
| 216 | 215 |
// Create the Server TLS Credentials for this node. These will not be used by agents. |
| 217 | 216 |
serverTLSCreds, err = rootCA.NewServerTLSCredentials(tlsKeyPair) |
| ... | ... |
@@ -236,12 +260,7 @@ func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, caHash, secret |
| 236 | 236 |
log.Debugf("loaded local TLS credentials: %s.", paths.Node.Cert)
|
| 237 | 237 |
} |
| 238 | 238 |
|
| 239 |
- return &SecurityConfig{
|
|
| 240 |
- rootCA: &rootCA, |
|
| 241 |
- |
|
| 242 |
- ServerTLSCreds: serverTLSCreds, |
|
| 243 |
- ClientTLSCreds: clientTLSCreds, |
|
| 244 |
- }, nil |
|
| 239 |
+ return NewSecurityConfig(&rootCA, clientTLSCreds, serverTLSCreds), nil |
|
| 245 | 240 |
} |
| 246 | 241 |
|
| 247 | 242 |
// RenewTLSConfig will continuously monitor for the necessity of renewing the local certificates, either by |
| ... | ... |
@@ -317,6 +336,14 @@ func RenewTLSConfig(ctx context.Context, s *SecurityConfig, baseCertDir string, |
| 317 | 317 |
updates <- CertificateUpdate{Err: err}
|
| 318 | 318 |
} |
| 319 | 319 |
|
| 320 |
+ // Update the external CA to use the new client TLS |
|
| 321 |
+ // config using a copy without a serverName specified. |
|
| 322 |
+ s.externalCA.UpdateTLSConfig(&tls.Config{
|
|
| 323 |
+ Certificates: clientTLSConfig.Certificates, |
|
| 324 |
+ RootCAs: clientTLSConfig.RootCAs, |
|
| 325 |
+ MinVersion: tls.VersionTLS12, |
|
| 326 |
+ }) |
|
| 327 |
+ |
|
| 320 | 328 |
err = s.ServerTLSCreds.LoadNewTLSConfig(serverTLSConfig) |
| 321 | 329 |
if err != nil {
|
| 322 | 330 |
log.Debugf("failed to update the server TLS credentials: %v", err)
|
| ... | ... |
@@ -405,7 +432,7 @@ func LoadTLSCreds(rootCA RootCA, paths CertPaths) (*MutableTLSCreds, *MutableTLS |
| 405 | 405 |
} |
| 406 | 406 |
|
| 407 | 407 |
keyPair, newErr = tls.X509KeyPair(cert, key) |
| 408 |
- if err != nil {
|
|
| 408 |
+ if newErr != nil {
|
|
| 409 | 409 |
return nil, nil, err |
| 410 | 410 |
} |
| 411 | 411 |
} |
| 412 | 412 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,141 @@ |
| 0 |
+package ca |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "bytes" |
|
| 4 |
+ "crypto/tls" |
|
| 5 |
+ "encoding/json" |
|
| 6 |
+ "errors" |
|
| 7 |
+ "fmt" |
|
| 8 |
+ "io/ioutil" |
|
| 9 |
+ "net/http" |
|
| 10 |
+ "sync" |
|
| 11 |
+ |
|
| 12 |
+ log "github.com/Sirupsen/logrus" |
|
| 13 |
+ "github.com/cloudflare/cfssl/api" |
|
| 14 |
+ "github.com/cloudflare/cfssl/signer" |
|
| 15 |
+) |
|
| 16 |
+ |
|
| 17 |
+// ErrNoExternalCAURLs is an error used it indicate that an ExternalCA is |
|
| 18 |
+// configured with no URLs to which it can proxy certificate signing requests. |
|
| 19 |
+var ErrNoExternalCAURLs = errors.New("no external CA URLs")
|
|
| 20 |
+ |
|
| 21 |
+// ExternalCA is able to make certificate signing requests to one of a list |
|
| 22 |
+// remote CFSSL API endpoints. |
|
| 23 |
+type ExternalCA struct {
|
|
| 24 |
+ mu sync.Mutex |
|
| 25 |
+ rootCA *RootCA |
|
| 26 |
+ urls []string |
|
| 27 |
+ client *http.Client |
|
| 28 |
+} |
|
| 29 |
+ |
|
| 30 |
+// NewExternalCA creates a new ExternalCA which uses the given tlsConfig to |
|
| 31 |
+// authenticate to any of the given URLS of CFSSL API endpoints. |
|
| 32 |
+func NewExternalCA(rootCA *RootCA, tlsConfig *tls.Config, urls ...string) *ExternalCA {
|
|
| 33 |
+ return &ExternalCA{
|
|
| 34 |
+ rootCA: rootCA, |
|
| 35 |
+ urls: urls, |
|
| 36 |
+ client: &http.Client{
|
|
| 37 |
+ Transport: &http.Transport{
|
|
| 38 |
+ TLSClientConfig: tlsConfig, |
|
| 39 |
+ }, |
|
| 40 |
+ }, |
|
| 41 |
+ } |
|
| 42 |
+} |
|
| 43 |
+ |
|
| 44 |
+// UpdateTLSConfig updates the HTTP Client for this ExternalCA by creating |
|
| 45 |
+// a new client which uses the given tlsConfig. |
|
| 46 |
+func (eca *ExternalCA) UpdateTLSConfig(tlsConfig *tls.Config) {
|
|
| 47 |
+ eca.mu.Lock() |
|
| 48 |
+ defer eca.mu.Unlock() |
|
| 49 |
+ |
|
| 50 |
+ eca.client = &http.Client{
|
|
| 51 |
+ Transport: &http.Transport{
|
|
| 52 |
+ TLSClientConfig: tlsConfig, |
|
| 53 |
+ }, |
|
| 54 |
+ } |
|
| 55 |
+} |
|
| 56 |
+ |
|
| 57 |
+// UpdateURLs updates the list of CSR API endpoints by setting it to the given |
|
| 58 |
+// urls. |
|
| 59 |
+func (eca *ExternalCA) UpdateURLs(urls ...string) {
|
|
| 60 |
+ eca.mu.Lock() |
|
| 61 |
+ defer eca.mu.Unlock() |
|
| 62 |
+ |
|
| 63 |
+ eca.urls = urls |
|
| 64 |
+} |
|
| 65 |
+ |
|
| 66 |
+// Sign signs a new certificate by proxying the given certificate signing |
|
| 67 |
+// request to an external CFSSL API server. |
|
| 68 |
+func (eca *ExternalCA) Sign(req signer.SignRequest) (cert []byte, err error) {
|
|
| 69 |
+ // Get the current HTTP client and list of URLs in a small critical |
|
| 70 |
+ // section. We will use these to make certificate signing requests. |
|
| 71 |
+ eca.mu.Lock() |
|
| 72 |
+ urls := eca.urls |
|
| 73 |
+ client := eca.client |
|
| 74 |
+ eca.mu.Unlock() |
|
| 75 |
+ |
|
| 76 |
+ if len(urls) == 0 {
|
|
| 77 |
+ return nil, ErrNoExternalCAURLs |
|
| 78 |
+ } |
|
| 79 |
+ |
|
| 80 |
+ csrJSON, err := json.Marshal(req) |
|
| 81 |
+ if err != nil {
|
|
| 82 |
+ return nil, fmt.Errorf("unable to JSON-encode CFSSL signing request: %s", err)
|
|
| 83 |
+ } |
|
| 84 |
+ |
|
| 85 |
+ // Try each configured proxy URL. Return after the first success. If |
|
| 86 |
+ // all fail then the last error will be returned. |
|
| 87 |
+ for _, url := range urls {
|
|
| 88 |
+ cert, err = makeExternalSignRequest(client, url, csrJSON) |
|
| 89 |
+ if err == nil {
|
|
| 90 |
+ return eca.rootCA.AppendFirstRootPEM(cert) |
|
| 91 |
+ } |
|
| 92 |
+ |
|
| 93 |
+ log.Debugf("unable to proxy certificate signing request to %s: %s", url, err)
|
|
| 94 |
+ } |
|
| 95 |
+ |
|
| 96 |
+ return nil, err |
|
| 97 |
+} |
|
| 98 |
+ |
|
| 99 |
+func makeExternalSignRequest(client *http.Client, url string, csrJSON []byte) (cert []byte, err error) {
|
|
| 100 |
+ resp, err := client.Post(url, "application/json", bytes.NewReader(csrJSON)) |
|
| 101 |
+ if err != nil {
|
|
| 102 |
+ return nil, fmt.Errorf("unable to perform certificate signing request: %s", err)
|
|
| 103 |
+ } |
|
| 104 |
+ defer resp.Body.Close() |
|
| 105 |
+ |
|
| 106 |
+ body, err := ioutil.ReadAll(resp.Body) |
|
| 107 |
+ if err != nil {
|
|
| 108 |
+ return nil, fmt.Errorf("unable to read CSR response body: %s", err)
|
|
| 109 |
+ } |
|
| 110 |
+ |
|
| 111 |
+ if resp.StatusCode != http.StatusOK {
|
|
| 112 |
+ return nil, fmt.Errorf("unexpected status code in CSR response: %d - %s", resp.StatusCode, string(body))
|
|
| 113 |
+ } |
|
| 114 |
+ |
|
| 115 |
+ var apiResponse api.Response |
|
| 116 |
+ if err := json.Unmarshal(body, &apiResponse); err != nil {
|
|
| 117 |
+ log.Debugf("unable to JSON-parse CFSSL API response body: %s", string(body))
|
|
| 118 |
+ return nil, fmt.Errorf("unable to parse JSON response: %s", err)
|
|
| 119 |
+ } |
|
| 120 |
+ |
|
| 121 |
+ if !apiResponse.Success || apiResponse.Result == nil {
|
|
| 122 |
+ if len(apiResponse.Errors) > 0 {
|
|
| 123 |
+ return nil, fmt.Errorf("response errors: %v", apiResponse.Errors)
|
|
| 124 |
+ } |
|
| 125 |
+ |
|
| 126 |
+ return nil, fmt.Errorf("certificate signing request failed")
|
|
| 127 |
+ } |
|
| 128 |
+ |
|
| 129 |
+ result, ok := apiResponse.Result.(map[string]interface{})
|
|
| 130 |
+ if !ok {
|
|
| 131 |
+ return nil, fmt.Errorf("invalid result type: %T", apiResponse.Result)
|
|
| 132 |
+ } |
|
| 133 |
+ |
|
| 134 |
+ certPEM, ok := result["certificate"].(string) |
|
| 135 |
+ if !ok {
|
|
| 136 |
+ return nil, fmt.Errorf("invalid result certificate field type: %T", result["certificate"])
|
|
| 137 |
+ } |
|
| 138 |
+ |
|
| 139 |
+ return []byte(certPEM), nil |
|
| 140 |
+} |
| ... | ... |
@@ -355,7 +355,7 @@ func (s *Server) Run(ctx context.Context) error {
|
| 355 | 355 |
s.mu.Lock() |
| 356 | 356 |
if s.isRunning() {
|
| 357 | 357 |
s.mu.Unlock() |
| 358 |
- return fmt.Errorf("CA signer is stopped")
|
|
| 358 |
+ return fmt.Errorf("CA signer is already running")
|
|
| 359 | 359 |
} |
| 360 | 360 |
s.wg.Add(1) |
| 361 | 361 |
defer s.wg.Done() |
| ... | ... |
@@ -443,12 +443,14 @@ func (s *Server) Run(ctx context.Context) error {
|
| 443 | 443 |
func (s *Server) Stop() error {
|
| 444 | 444 |
s.mu.Lock() |
| 445 | 445 |
if !s.isRunning() {
|
| 446 |
+ s.mu.Unlock() |
|
| 446 | 447 |
return fmt.Errorf("CA signer is already stopped")
|
| 447 | 448 |
} |
| 448 | 449 |
s.cancel() |
| 449 | 450 |
s.mu.Unlock() |
| 450 | 451 |
// wait for all handlers to finish their CA deals, |
| 451 | 452 |
s.wg.Wait() |
| 453 |
+ s.started = make(chan struct{})
|
|
| 452 | 454 |
return nil |
| 453 | 455 |
} |
| 454 | 456 |
|
| ... | ... |
@@ -530,6 +532,21 @@ func (s *Server) updateCluster(ctx context.Context, cluster *api.Cluster) {
|
| 530 | 530 |
}).Debugf("Root CA updated successfully")
|
| 531 | 531 |
} |
| 532 | 532 |
} |
| 533 |
+ |
|
| 534 |
+ // Update our security config with the list of External CA URLs |
|
| 535 |
+ // from the new cluster state. |
|
| 536 |
+ |
|
| 537 |
+ // TODO(aaronl): In the future, this will be abstracted with an |
|
| 538 |
+ // ExternalCA interface that has different implementations for |
|
| 539 |
+ // different CA types. At the moment, only CFSSL is supported. |
|
| 540 |
+ var cfsslURLs []string |
|
| 541 |
+ for _, ca := range cluster.Spec.CAConfig.ExternalCAs {
|
|
| 542 |
+ if ca.Protocol == api.ExternalCA_CAProtocolCFSSL {
|
|
| 543 |
+ cfsslURLs = append(cfsslURLs, ca.URL) |
|
| 544 |
+ } |
|
| 545 |
+ } |
|
| 546 |
+ |
|
| 547 |
+ s.securityConfig.externalCA.UpdateURLs(cfsslURLs...) |
|
| 533 | 548 |
} |
| 534 | 549 |
|
| 535 | 550 |
// evaluateAndSignNodeCert implements the logic of which certificates to sign |
| ... | ... |
@@ -555,13 +572,8 @@ func (s *Server) evaluateAndSignNodeCert(ctx context.Context, node *api.Node) {
|
| 555 | 555 |
|
| 556 | 556 |
// signNodeCert does the bulk of the work for signing a certificate |
| 557 | 557 |
func (s *Server) signNodeCert(ctx context.Context, node *api.Node) {
|
| 558 |
- if !s.securityConfig.RootCA().CanSign() {
|
|
| 559 |
- log.G(ctx).WithFields(logrus.Fields{
|
|
| 560 |
- "node.id": node.ID, |
|
| 561 |
- "method": "(*Server).signNodeCert", |
|
| 562 |
- }).Errorf("no valid signer found")
|
|
| 563 |
- return |
|
| 564 |
- } |
|
| 558 |
+ rootCA := s.securityConfig.RootCA() |
|
| 559 |
+ externalCA := s.securityConfig.externalCA |
|
| 565 | 560 |
|
| 566 | 561 |
node = node.Copy() |
| 567 | 562 |
nodeID := node.ID |
| ... | ... |
@@ -576,7 +588,20 @@ func (s *Server) signNodeCert(ctx context.Context, node *api.Node) {
|
| 576 | 576 |
} |
| 577 | 577 |
|
| 578 | 578 |
// Attempt to sign the CSR |
| 579 |
- cert, err := s.securityConfig.RootCA().ParseValidateAndSignCSR(node.Certificate.CSR, node.Certificate.CN, role, s.securityConfig.ClientTLSCreds.Organization()) |
|
| 579 |
+ var ( |
|
| 580 |
+ rawCSR = node.Certificate.CSR |
|
| 581 |
+ cn = node.Certificate.CN |
|
| 582 |
+ ou = role |
|
| 583 |
+ org = s.securityConfig.ClientTLSCreds.Organization() |
|
| 584 |
+ ) |
|
| 585 |
+ |
|
| 586 |
+ // Try using the external CA first. |
|
| 587 |
+ cert, err := externalCA.Sign(PrepareCSR(rawCSR, cn, ou, org)) |
|
| 588 |
+ if err == ErrNoExternalCAURLs {
|
|
| 589 |
+ // No external CA servers configured. Try using the local CA. |
|
| 590 |
+ cert, err = rootCA.ParseValidateAndSignCSR(rawCSR, cn, ou, org) |
|
| 591 |
+ } |
|
| 592 |
+ |
|
| 580 | 593 |
if err != nil {
|
| 581 | 594 |
log.G(ctx).WithFields(logrus.Fields{
|
| 582 | 595 |
"node.id": node.ID, |
| ... | ... |
@@ -124,6 +124,14 @@ func (c *MutableTLSCreds) LoadNewTLSConfig(newConfig *tls.Config) error {
|
| 124 | 124 |
return nil |
| 125 | 125 |
} |
| 126 | 126 |
|
| 127 |
+// Config returns the current underlying TLS config. |
|
| 128 |
+func (c *MutableTLSCreds) Config() *tls.Config {
|
|
| 129 |
+ c.Lock() |
|
| 130 |
+ defer c.Unlock() |
|
| 131 |
+ |
|
| 132 |
+ return c.config |
|
| 133 |
+} |
|
| 134 |
+ |
|
| 127 | 135 |
// Role returns the OU for the certificate encapsulated in this TransportAuthenticator |
| 128 | 136 |
func (c *MutableTLSCreds) Role() string {
|
| 129 | 137 |
c.Lock() |
| ... | ... |
@@ -52,6 +52,16 @@ type networkContext struct {
|
| 52 | 52 |
// A table of unallocated tasks which will be revisited if any thing |
| 53 | 53 |
// changes in system state that might help task allocation. |
| 54 | 54 |
unallocatedTasks map[string]*api.Task |
| 55 |
+ |
|
| 56 |
+ // A table of unallocated services which will be revisited if |
|
| 57 |
+ // any thing changes in system state that might help service |
|
| 58 |
+ // allocation. |
|
| 59 |
+ unallocatedServices map[string]*api.Service |
|
| 60 |
+ |
|
| 61 |
+ // A table of unallocated networks which will be revisited if |
|
| 62 |
+ // any thing changes in system state that might help network |
|
| 63 |
+ // allocation. |
|
| 64 |
+ unallocatedNetworks map[string]*api.Network |
|
| 55 | 65 |
} |
| 56 | 66 |
|
| 57 | 67 |
func (a *Allocator) doNetworkInit(ctx context.Context) error {
|
| ... | ... |
@@ -61,8 +71,10 @@ func (a *Allocator) doNetworkInit(ctx context.Context) error {
|
| 61 | 61 |
} |
| 62 | 62 |
|
| 63 | 63 |
nc := &networkContext{
|
| 64 |
- nwkAllocator: na, |
|
| 65 |
- unallocatedTasks: make(map[string]*api.Task), |
|
| 64 |
+ nwkAllocator: na, |
|
| 65 |
+ unallocatedTasks: make(map[string]*api.Task), |
|
| 66 |
+ unallocatedServices: make(map[string]*api.Service), |
|
| 67 |
+ unallocatedNetworks: make(map[string]*api.Network), |
|
| 66 | 68 |
} |
| 67 | 69 |
|
| 68 | 70 |
// Check if we have the ingress network. If not found create |
| ... | ... |
@@ -326,6 +338,8 @@ func (a *Allocator) doNetworkAlloc(ctx context.Context, ev events.Event) {
|
| 326 | 326 |
case state.EventCreateTask, state.EventUpdateTask, state.EventDeleteTask: |
| 327 | 327 |
a.doTaskAlloc(ctx, nc, ev) |
| 328 | 328 |
case state.EventCommit: |
| 329 |
+ a.procUnallocatedNetworks(ctx, nc) |
|
| 330 |
+ a.procUnallocatedServices(ctx, nc) |
|
| 329 | 331 |
a.procUnallocatedTasksNetwork(ctx, nc) |
| 330 | 332 |
return |
| 331 | 333 |
} |
| ... | ... |
@@ -554,29 +568,34 @@ func (a *Allocator) allocateNode(ctx context.Context, nc *networkContext, node * |
| 554 | 554 |
} |
| 555 | 555 |
|
| 556 | 556 |
func (a *Allocator) allocateService(ctx context.Context, nc *networkContext, s *api.Service) error {
|
| 557 |
- // The service is trying to expose ports to the external |
|
| 558 |
- // world. Automatically attach the service to the ingress |
|
| 559 |
- // network only if it is not already done. |
|
| 560 |
- if s.Spec.Endpoint != nil && len(s.Spec.Endpoint.Ports) != 0 {
|
|
| 557 |
+ if s.Spec.Endpoint != nil {
|
|
| 561 | 558 |
if s.Endpoint == nil {
|
| 562 |
- s.Endpoint = &api.Endpoint{}
|
|
| 559 |
+ s.Endpoint = &api.Endpoint{
|
|
| 560 |
+ Spec: s.Spec.Endpoint.Copy(), |
|
| 561 |
+ } |
|
| 563 | 562 |
} |
| 564 | 563 |
|
| 565 |
- var found bool |
|
| 566 |
- for _, vip := range s.Endpoint.VirtualIPs {
|
|
| 567 |
- if vip.NetworkID == ingressNetwork.ID {
|
|
| 568 |
- found = true |
|
| 569 |
- break |
|
| 564 |
+ // The service is trying to expose ports to the external |
|
| 565 |
+ // world. Automatically attach the service to the ingress |
|
| 566 |
+ // network only if it is not already done. |
|
| 567 |
+ if len(s.Spec.Endpoint.Ports) != 0 {
|
|
| 568 |
+ var found bool |
|
| 569 |
+ for _, vip := range s.Endpoint.VirtualIPs {
|
|
| 570 |
+ if vip.NetworkID == ingressNetwork.ID {
|
|
| 571 |
+ found = true |
|
| 572 |
+ break |
|
| 573 |
+ } |
|
| 570 | 574 |
} |
| 571 |
- } |
|
| 572 | 575 |
|
| 573 |
- if !found {
|
|
| 574 |
- s.Endpoint.VirtualIPs = append(s.Endpoint.VirtualIPs, |
|
| 575 |
- &api.Endpoint_VirtualIP{NetworkID: ingressNetwork.ID})
|
|
| 576 |
+ if !found {
|
|
| 577 |
+ s.Endpoint.VirtualIPs = append(s.Endpoint.VirtualIPs, |
|
| 578 |
+ &api.Endpoint_VirtualIP{NetworkID: ingressNetwork.ID})
|
|
| 579 |
+ } |
|
| 576 | 580 |
} |
| 577 | 581 |
} |
| 578 | 582 |
|
| 579 | 583 |
if err := nc.nwkAllocator.ServiceAllocate(s); err != nil {
|
| 584 |
+ nc.unallocatedServices[s.ID] = s |
|
| 580 | 585 |
return err |
| 581 | 586 |
} |
| 582 | 587 |
|
| ... | ... |
@@ -611,6 +630,7 @@ func (a *Allocator) allocateService(ctx context.Context, nc *networkContext, s * |
| 611 | 611 |
|
| 612 | 612 |
func (a *Allocator) allocateNetwork(ctx context.Context, nc *networkContext, n *api.Network) error {
|
| 613 | 613 |
if err := nc.nwkAllocator.Allocate(n); err != nil {
|
| 614 |
+ nc.unallocatedNetworks[n.ID] = n |
|
| 614 | 615 |
return fmt.Errorf("failed during network allocation for network %s: %v", n.ID, err)
|
| 615 | 616 |
} |
| 616 | 617 |
|
| ... | ... |
@@ -666,6 +686,8 @@ func (a *Allocator) allocateTask(ctx context.Context, nc *networkContext, tx sto |
| 666 | 666 |
if !nc.nwkAllocator.IsAllocated(n) {
|
| 667 | 667 |
return nil, fmt.Errorf("network %s attached to task %s not allocated yet", n.ID, t.ID)
|
| 668 | 668 |
} |
| 669 |
+ |
|
| 670 |
+ na.Network = n |
|
| 669 | 671 |
} |
| 670 | 672 |
|
| 671 | 673 |
if err := nc.nwkAllocator.AllocateTask(t); err != nil {
|
| ... | ... |
@@ -696,6 +718,32 @@ func (a *Allocator) allocateTask(ctx context.Context, nc *networkContext, tx sto |
| 696 | 696 |
return storeT, nil |
| 697 | 697 |
} |
| 698 | 698 |
|
| 699 |
+func (a *Allocator) procUnallocatedNetworks(ctx context.Context, nc *networkContext) {
|
|
| 700 |
+ for _, n := range nc.unallocatedNetworks {
|
|
| 701 |
+ if !nc.nwkAllocator.IsAllocated(n) {
|
|
| 702 |
+ if err := a.allocateNetwork(ctx, nc, n); err != nil {
|
|
| 703 |
+ log.G(ctx).Debugf("Failed allocation of unallocated network %s: %v", n.ID, err)
|
|
| 704 |
+ continue |
|
| 705 |
+ } |
|
| 706 |
+ } |
|
| 707 |
+ |
|
| 708 |
+ delete(nc.unallocatedNetworks, n.ID) |
|
| 709 |
+ } |
|
| 710 |
+} |
|
| 711 |
+ |
|
| 712 |
+func (a *Allocator) procUnallocatedServices(ctx context.Context, nc *networkContext) {
|
|
| 713 |
+ for _, s := range nc.unallocatedServices {
|
|
| 714 |
+ if serviceAllocationNeeded(s, nc) {
|
|
| 715 |
+ if err := a.allocateService(ctx, nc, s); err != nil {
|
|
| 716 |
+ log.G(ctx).Debugf("Failed allocation of unallocated service %s: %v", s.ID, err)
|
|
| 717 |
+ continue |
|
| 718 |
+ } |
|
| 719 |
+ } |
|
| 720 |
+ |
|
| 721 |
+ delete(nc.unallocatedServices, s.ID) |
|
| 722 |
+ } |
|
| 723 |
+} |
|
| 724 |
+ |
|
| 699 | 725 |
func (a *Allocator) procUnallocatedTasksNetwork(ctx context.Context, nc *networkContext) {
|
| 700 | 726 |
tasks := make([]*api.Task, 0, len(nc.unallocatedTasks)) |
| 701 | 727 |
|
| ... | ... |
@@ -14,7 +14,10 @@ import ( |
| 14 | 14 |
) |
| 15 | 15 |
|
| 16 | 16 |
const ( |
| 17 |
- defaultDriver = "overlay" |
|
| 17 |
+ // DefaultDriver defines the name of the driver to be used by |
|
| 18 |
+ // default if a network without any driver name specified is |
|
| 19 |
+ // created. |
|
| 20 |
+ DefaultDriver = "overlay" |
|
| 18 | 21 |
) |
| 19 | 22 |
|
| 20 | 23 |
var ( |
| ... | ... |
@@ -69,7 +72,7 @@ func New() (*NetworkAllocator, error) {
|
| 69 | 69 |
} |
| 70 | 70 |
|
| 71 | 71 |
// Add the manager component of overlay driver to the registry. |
| 72 |
- if err := reg.AddDriver(defaultDriver, defaultDriverInitFunc, nil); err != nil {
|
|
| 72 |
+ if err := reg.AddDriver(DefaultDriver, defaultDriverInitFunc, nil); err != nil {
|
|
| 73 | 73 |
return nil, err |
| 74 | 74 |
} |
| 75 | 75 |
|
| ... | ... |
@@ -96,6 +99,7 @@ func (na *NetworkAllocator) Allocate(n *api.Network) error {
|
| 96 | 96 |
} |
| 97 | 97 |
|
| 98 | 98 |
if err := na.allocateDriverState(n); err != nil {
|
| 99 |
+ na.freePools(n, pools) |
|
| 99 | 100 |
return fmt.Errorf("failed while allocating driver state for network %s: %v", n.ID, err)
|
| 100 | 101 |
} |
| 101 | 102 |
|
| ... | ... |
@@ -146,7 +150,9 @@ func (na *NetworkAllocator) ServiceAllocate(s *api.Service) (err error) {
|
| 146 | 146 |
} |
| 147 | 147 |
|
| 148 | 148 |
if s.Endpoint == nil {
|
| 149 |
- s.Endpoint = &api.Endpoint{}
|
|
| 149 |
+ s.Endpoint = &api.Endpoint{
|
|
| 150 |
+ Spec: s.Spec.Endpoint.Copy(), |
|
| 151 |
+ } |
|
| 150 | 152 |
} |
| 151 | 153 |
|
| 152 | 154 |
// First allocate VIPs for all the pre-populated endpoint attachments |
| ... | ... |
@@ -520,7 +526,7 @@ func (na *NetworkAllocator) allocateDriverState(n *api.Network) error {
|
| 520 | 520 |
|
| 521 | 521 |
// Resolve network driver |
| 522 | 522 |
func (na *NetworkAllocator) resolveDriver(n *api.Network) (driverapi.Driver, string, error) {
|
| 523 |
- dName := defaultDriver |
|
| 523 |
+ dName := DefaultDriver |
|
| 524 | 524 |
if n.Spec.DriverConfig != nil && n.Spec.DriverConfig.Name != "" {
|
| 525 | 525 |
dName = n.Spec.DriverConfig.Name |
| 526 | 526 |
} |
| ... | ... |
@@ -3,8 +3,10 @@ package controlapi |
| 3 | 3 |
import ( |
| 4 | 4 |
"net" |
| 5 | 5 |
|
| 6 |
+ "github.com/docker/libnetwork/ipamapi" |
|
| 6 | 7 |
"github.com/docker/swarmkit/api" |
| 7 | 8 |
"github.com/docker/swarmkit/identity" |
| 9 |
+ "github.com/docker/swarmkit/manager/allocator/networkallocator" |
|
| 8 | 10 |
"github.com/docker/swarmkit/manager/state/store" |
| 9 | 11 |
"golang.org/x/net/context" |
| 10 | 12 |
"google.golang.org/grpc" |
| ... | ... |
@@ -57,6 +59,10 @@ func validateIPAM(ipam *api.IPAMOptions) error {
|
| 57 | 57 |
return err |
| 58 | 58 |
} |
| 59 | 59 |
|
| 60 |
+ if ipam.Driver != nil && ipam.Driver.Name != ipamapi.DefaultIPAM {
|
|
| 61 |
+ return grpc.Errorf(codes.InvalidArgument, "invalid IPAM specified") |
|
| 62 |
+ } |
|
| 63 |
+ |
|
| 60 | 64 |
for _, ipamConf := range ipam.Configs {
|
| 61 | 65 |
if err := validateIPAMConfiguration(ipamConf); err != nil {
|
| 62 | 66 |
return err |
| ... | ... |
@@ -79,6 +85,10 @@ func validateNetworkSpec(spec *api.NetworkSpec) error {
|
| 79 | 79 |
return err |
| 80 | 80 |
} |
| 81 | 81 |
|
| 82 |
+ if spec.DriverConfig != nil && spec.DriverConfig.Name != networkallocator.DefaultDriver {
|
|
| 83 |
+ return grpc.Errorf(codes.InvalidArgument, "invalid driver specified") |
|
| 84 |
+ } |
|
| 85 |
+ |
|
| 82 | 86 |
if err := validateIPAM(spec.IPAM); err != nil {
|
| 83 | 87 |
return err |
| 84 | 88 |
} |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"github.com/docker/swarmkit/api" |
| 9 | 9 |
"github.com/docker/swarmkit/identity" |
| 10 | 10 |
"github.com/docker/swarmkit/manager/state/store" |
| 11 |
+ "github.com/docker/swarmkit/protobuf/ptypes" |
|
| 11 | 12 |
"golang.org/x/net/context" |
| 12 | 13 |
"google.golang.org/grpc" |
| 13 | 14 |
"google.golang.org/grpc/codes" |
| ... | ... |
@@ -15,6 +16,7 @@ import ( |
| 15 | 15 |
|
| 16 | 16 |
var ( |
| 17 | 17 |
errNetworkUpdateNotSupported = errors.New("changing network in service is not supported")
|
| 18 |
+ errModeChangeNotAllowed = errors.New("service mode change is not allowed")
|
|
| 18 | 19 |
) |
| 19 | 20 |
|
| 20 | 21 |
func validateResources(r *api.Resources) error {
|
| ... | ... |
@@ -45,21 +47,70 @@ func validateResourceRequirements(r *api.ResourceRequirements) error {
|
| 45 | 45 |
return nil |
| 46 | 46 |
} |
| 47 | 47 |
|
| 48 |
-func validateServiceSpecTemplate(spec *api.ServiceSpec) error {
|
|
| 49 |
- if err := validateResourceRequirements(spec.Task.Resources); err != nil {
|
|
| 48 |
+func validateRestartPolicy(rp *api.RestartPolicy) error {
|
|
| 49 |
+ if rp == nil {
|
|
| 50 |
+ return nil |
|
| 51 |
+ } |
|
| 52 |
+ |
|
| 53 |
+ if rp.Delay != nil {
|
|
| 54 |
+ delay, err := ptypes.Duration(rp.Delay) |
|
| 55 |
+ if err != nil {
|
|
| 56 |
+ return err |
|
| 57 |
+ } |
|
| 58 |
+ if delay < 0 {
|
|
| 59 |
+ return grpc.Errorf(codes.InvalidArgument, "TaskSpec: restart-delay cannot be negative") |
|
| 60 |
+ } |
|
| 61 |
+ } |
|
| 62 |
+ |
|
| 63 |
+ if rp.Window != nil {
|
|
| 64 |
+ win, err := ptypes.Duration(rp.Window) |
|
| 65 |
+ if err != nil {
|
|
| 66 |
+ return err |
|
| 67 |
+ } |
|
| 68 |
+ if win < 0 {
|
|
| 69 |
+ return grpc.Errorf(codes.InvalidArgument, "TaskSpec: restart-window cannot be negative") |
|
| 70 |
+ } |
|
| 71 |
+ } |
|
| 72 |
+ |
|
| 73 |
+ return nil |
|
| 74 |
+} |
|
| 75 |
+ |
|
| 76 |
+func validateUpdate(uc *api.UpdateConfig) error {
|
|
| 77 |
+ if uc == nil {
|
|
| 78 |
+ return nil |
|
| 79 |
+ } |
|
| 80 |
+ |
|
| 81 |
+ delay, err := ptypes.Duration(&uc.Delay) |
|
| 82 |
+ if err != nil {
|
|
| 83 |
+ return err |
|
| 84 |
+ } |
|
| 85 |
+ |
|
| 86 |
+ if delay < 0 {
|
|
| 87 |
+ return grpc.Errorf(codes.InvalidArgument, "TaskSpec: update-delay cannot be negative") |
|
| 88 |
+ } |
|
| 89 |
+ |
|
| 90 |
+ return nil |
|
| 91 |
+} |
|
| 92 |
+ |
|
| 93 |
+func validateTask(taskSpec api.TaskSpec) error {
|
|
| 94 |
+ if err := validateResourceRequirements(taskSpec.Resources); err != nil {
|
|
| 50 | 95 |
return err |
| 51 | 96 |
} |
| 52 | 97 |
|
| 53 |
- if spec.Task.GetRuntime() == nil {
|
|
| 98 |
+ if err := validateRestartPolicy(taskSpec.Restart); err != nil {
|
|
| 99 |
+ return err |
|
| 100 |
+ } |
|
| 101 |
+ |
|
| 102 |
+ if taskSpec.GetRuntime() == nil {
|
|
| 54 | 103 |
return grpc.Errorf(codes.InvalidArgument, "TaskSpec: missing runtime") |
| 55 | 104 |
} |
| 56 | 105 |
|
| 57 |
- _, ok := spec.Task.GetRuntime().(*api.TaskSpec_Container) |
|
| 106 |
+ _, ok := taskSpec.GetRuntime().(*api.TaskSpec_Container) |
|
| 58 | 107 |
if !ok {
|
| 59 | 108 |
return grpc.Errorf(codes.Unimplemented, "RuntimeSpec: unimplemented runtime in service spec") |
| 60 | 109 |
} |
| 61 | 110 |
|
| 62 |
- container := spec.Task.GetContainer() |
|
| 111 |
+ container := taskSpec.GetContainer() |
|
| 63 | 112 |
if container == nil {
|
| 64 | 113 |
return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: missing in service spec") |
| 65 | 114 |
} |
| ... | ... |
@@ -99,7 +150,13 @@ func validateServiceSpec(spec *api.ServiceSpec) error {
|
| 99 | 99 |
if err := validateAnnotations(spec.Annotations); err != nil {
|
| 100 | 100 |
return err |
| 101 | 101 |
} |
| 102 |
- if err := validateServiceSpecTemplate(spec); err != nil {
|
|
| 102 |
+ if err := validateTask(spec.Task); err != nil {
|
|
| 103 |
+ return err |
|
| 104 |
+ } |
|
| 105 |
+ if err := validateUpdate(spec.Update); err != nil {
|
|
| 106 |
+ return err |
|
| 107 |
+ } |
|
| 108 |
+ if err := validateEndpointSpec(spec.Endpoint); err != nil {
|
|
| 103 | 109 |
return err |
| 104 | 110 |
} |
| 105 | 111 |
return nil |
| ... | ... |
@@ -179,6 +236,12 @@ func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRe |
| 179 | 179 |
return errNetworkUpdateNotSupported |
| 180 | 180 |
} |
| 181 | 181 |
|
| 182 |
+ // orchestrator is designed to be stateless, so it should not deal |
|
| 183 |
+ // with service mode change (comparing current config with previous config). |
|
| 184 |
+ // proper way to change service mode is to delete and re-add. |
|
| 185 |
+ if request.Spec != nil && reflect.TypeOf(service.Spec.Mode) != reflect.TypeOf(request.Spec.Mode) {
|
|
| 186 |
+ return errModeChangeNotAllowed |
|
| 187 |
+ } |
|
| 182 | 188 |
service.Meta.Version = *request.ServiceVersion |
| 183 | 189 |
service.Spec = *request.Spec.Copy() |
| 184 | 190 |
return store.UpdateService(tx, service) |
| ... | ... |
@@ -29,6 +29,7 @@ const ( |
| 29 | 29 |
DefaultHeartBeatPeriod = 5 * time.Second |
| 30 | 30 |
defaultHeartBeatEpsilon = 500 * time.Millisecond |
| 31 | 31 |
defaultGracePeriodMultiplier = 3 |
| 32 |
+ defaultRateLimitPeriod = 16 * time.Second |
|
| 32 | 33 |
|
| 33 | 34 |
// maxBatchItems is the threshold of queued writes that should |
| 34 | 35 |
// trigger an actual transaction to commit them to the shared store. |
| ... | ... |
@@ -59,9 +60,12 @@ var ( |
| 59 | 59 |
// DefautConfig. |
| 60 | 60 |
type Config struct {
|
| 61 | 61 |
// Addr configures the address the dispatcher reports to agents. |
| 62 |
- Addr string |
|
| 63 |
- HeartbeatPeriod time.Duration |
|
| 64 |
- HeartbeatEpsilon time.Duration |
|
| 62 |
+ Addr string |
|
| 63 |
+ HeartbeatPeriod time.Duration |
|
| 64 |
+ HeartbeatEpsilon time.Duration |
|
| 65 |
+ // RateLimitPeriod specifies how often node with same ID can try to register |
|
| 66 |
+ // new session. |
|
| 67 |
+ RateLimitPeriod time.Duration |
|
| 65 | 68 |
GracePeriodMultiplier int |
| 66 | 69 |
} |
| 67 | 70 |
|
| ... | ... |
@@ -70,6 +74,7 @@ func DefaultConfig() *Config {
|
| 70 | 70 |
return &Config{
|
| 71 | 71 |
HeartbeatPeriod: DefaultHeartBeatPeriod, |
| 72 | 72 |
HeartbeatEpsilon: defaultHeartBeatEpsilon, |
| 73 |
+ RateLimitPeriod: defaultRateLimitPeriod, |
|
| 73 | 74 |
GracePeriodMultiplier: defaultGracePeriodMultiplier, |
| 74 | 75 |
} |
| 75 | 76 |
} |
| ... | ... |
@@ -116,12 +121,11 @@ func (b weightedPeerByNodeID) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
| 116 | 116 |
func New(cluster Cluster, c *Config) *Dispatcher {
|
| 117 | 117 |
return &Dispatcher{
|
| 118 | 118 |
addr: c.Addr, |
| 119 |
- nodes: newNodeStore(c.HeartbeatPeriod, c.HeartbeatEpsilon, c.GracePeriodMultiplier), |
|
| 119 |
+ nodes: newNodeStore(c.HeartbeatPeriod, c.HeartbeatEpsilon, c.GracePeriodMultiplier, c.RateLimitPeriod), |
|
| 120 | 120 |
store: cluster.MemoryStore(), |
| 121 | 121 |
cluster: cluster, |
| 122 | 122 |
mgrQueue: watch.NewQueue(16), |
| 123 | 123 |
keyMgrQueue: watch.NewQueue(16), |
| 124 |
- lastSeenManagers: getWeightedPeers(cluster), |
|
| 125 | 124 |
taskUpdates: make(map[string]*api.TaskStatus), |
| 126 | 125 |
processTaskUpdatesTrigger: make(chan struct{}, 1),
|
| 127 | 126 |
config: c, |
| ... | ... |
@@ -149,12 +153,12 @@ func (d *Dispatcher) Run(ctx context.Context) error {
|
| 149 | 149 |
d.mu.Lock() |
| 150 | 150 |
if d.isRunning() {
|
| 151 | 151 |
d.mu.Unlock() |
| 152 |
- return fmt.Errorf("dispatcher is stopped")
|
|
| 152 |
+ return fmt.Errorf("dispatcher is already running")
|
|
| 153 | 153 |
} |
| 154 | 154 |
logger := log.G(ctx).WithField("module", "dispatcher")
|
| 155 | 155 |
ctx = log.WithLogger(ctx, logger) |
| 156 | 156 |
if err := d.markNodesUnknown(ctx); err != nil {
|
| 157 |
- logger.Errorf("failed to mark all nodes unknown: %v", err)
|
|
| 157 |
+ logger.Errorf(`failed to move all nodes to "unknown" state: %v`, err) |
|
| 158 | 158 |
} |
| 159 | 159 |
configWatcher, cancel, err := store.ViewAndWatch( |
| 160 | 160 |
d.store, |
| ... | ... |
@@ -177,6 +181,7 @@ func (d *Dispatcher) Run(ctx context.Context) error {
|
| 177 | 177 |
state.EventUpdateCluster{},
|
| 178 | 178 |
) |
| 179 | 179 |
if err != nil {
|
| 180 |
+ d.mu.Unlock() |
|
| 180 | 181 |
return err |
| 181 | 182 |
} |
| 182 | 183 |
defer cancel() |
| ... | ... |
@@ -238,6 +243,7 @@ func (d *Dispatcher) Run(ctx context.Context) error {
|
| 238 | 238 |
func (d *Dispatcher) Stop() error {
|
| 239 | 239 |
d.mu.Lock() |
| 240 | 240 |
if !d.isRunning() {
|
| 241 |
+ d.mu.Unlock() |
|
| 241 | 242 |
return fmt.Errorf("dispatcher is already stopped")
|
| 242 | 243 |
} |
| 243 | 244 |
d.cancel() |
| ... | ... |
@@ -280,20 +286,20 @@ func (d *Dispatcher) markNodesUnknown(ctx context.Context) error {
|
| 280 | 280 |
} |
| 281 | 281 |
node.Status = api.NodeStatus{
|
| 282 | 282 |
State: api.NodeStatus_UNKNOWN, |
| 283 |
- Message: "Node marked as unknown due to leadership change in cluster", |
|
| 283 |
+ Message: `Node moved to "unknown" state due to leadership change in cluster`, |
|
| 284 | 284 |
} |
| 285 | 285 |
nodeID := node.ID |
| 286 | 286 |
|
| 287 | 287 |
expireFunc := func() {
|
| 288 | 288 |
log := log.WithField("node", nodeID)
|
| 289 |
- nodeStatus := api.NodeStatus{State: api.NodeStatus_DOWN, Message: "heartbeat failure for unknown node"}
|
|
| 289 |
+ nodeStatus := api.NodeStatus{State: api.NodeStatus_DOWN, Message: `heartbeat failure for node in "unknown" state`}
|
|
| 290 | 290 |
log.Debugf("heartbeat expiration for unknown node")
|
| 291 | 291 |
if err := d.nodeRemove(nodeID, nodeStatus); err != nil {
|
| 292 |
- log.WithError(err).Errorf("failed deregistering node after heartbeat expiration for unknown node")
|
|
| 292 |
+ log.WithError(err).Errorf(`failed deregistering node after heartbeat expiration for node in "unknown" state`) |
|
| 293 | 293 |
} |
| 294 | 294 |
} |
| 295 | 295 |
if err := d.nodes.AddUnknown(node, expireFunc); err != nil {
|
| 296 |
- return fmt.Errorf("add unknown node failed: %v", err)
|
|
| 296 |
+ return fmt.Errorf(`adding node in "unknown" state to node store failed: %v`, err) |
|
| 297 | 297 |
} |
| 298 | 298 |
if err := store.UpdateNode(tx, node); err != nil {
|
| 299 | 299 |
return fmt.Errorf("update failed %v", err)
|
| ... | ... |
@@ -301,7 +307,7 @@ func (d *Dispatcher) markNodesUnknown(ctx context.Context) error {
|
| 301 | 301 |
return nil |
| 302 | 302 |
}) |
| 303 | 303 |
if err != nil {
|
| 304 |
- log.WithField("node", n.ID).WithError(err).Errorf("failed to mark node as unknown")
|
|
| 304 |
+ log.WithField("node", n.ID).WithError(err).Errorf(`failed to move node to "unknown" state`)
|
|
| 305 | 305 |
} |
| 306 | 306 |
} |
| 307 | 307 |
return nil |
| ... | ... |
@@ -328,6 +334,10 @@ func (d *Dispatcher) register(ctx context.Context, nodeID string, description *a |
| 328 | 328 |
return "", "", err |
| 329 | 329 |
} |
| 330 | 330 |
|
| 331 |
+ if err := d.nodes.CheckRateLimit(nodeID); err != nil {
|
|
| 332 |
+ return "", "", err |
|
| 333 |
+ } |
|
| 334 |
+ |
|
| 331 | 335 |
// create or update node in store |
| 332 | 336 |
// TODO(stevvooe): Validate node specification. |
| 333 | 337 |
var node *api.Node |
| ... | ... |
@@ -15,6 +15,7 @@ import ( |
| 15 | 15 |
type registeredNode struct {
|
| 16 | 16 |
SessionID string |
| 17 | 17 |
Heartbeat *heartbeat.Heartbeat |
| 18 |
+ Registered time.Time |
|
| 18 | 19 |
Node *api.Node |
| 19 | 20 |
Disconnect chan struct{} // signal to disconnect
|
| 20 | 21 |
mu sync.Mutex |
| ... | ... |
@@ -41,15 +42,17 @@ func (rn *registeredNode) checkSessionID(sessionID string) error {
|
| 41 | 41 |
type nodeStore struct {
|
| 42 | 42 |
periodChooser *periodChooser |
| 43 | 43 |
gracePeriodMultiplier time.Duration |
| 44 |
+ rateLimitPeriod time.Duration |
|
| 44 | 45 |
nodes map[string]*registeredNode |
| 45 | 46 |
mu sync.RWMutex |
| 46 | 47 |
} |
| 47 | 48 |
|
| 48 |
-func newNodeStore(hbPeriod, hbEpsilon time.Duration, graceMultiplier int) *nodeStore {
|
|
| 49 |
+func newNodeStore(hbPeriod, hbEpsilon time.Duration, graceMultiplier int, rateLimitPeriod time.Duration) *nodeStore {
|
|
| 49 | 50 |
return &nodeStore{
|
| 50 | 51 |
nodes: make(map[string]*registeredNode), |
| 51 | 52 |
periodChooser: newPeriodChooser(hbPeriod, hbEpsilon), |
| 52 | 53 |
gracePeriodMultiplier: time.Duration(graceMultiplier), |
| 54 |
+ rateLimitPeriod: rateLimitPeriod, |
|
| 53 | 55 |
} |
| 54 | 56 |
} |
| 55 | 57 |
|
| ... | ... |
@@ -77,6 +80,19 @@ func (s *nodeStore) AddUnknown(n *api.Node, expireFunc func()) error {
|
| 77 | 77 |
return nil |
| 78 | 78 |
} |
| 79 | 79 |
|
| 80 |
+// CheckRateLimit returs error if node with specified id is allowed to re-register |
|
| 81 |
+// again. |
|
| 82 |
+func (s *nodeStore) CheckRateLimit(id string) error {
|
|
| 83 |
+ s.mu.Lock() |
|
| 84 |
+ defer s.mu.Unlock() |
|
| 85 |
+ if existRn, ok := s.nodes[id]; ok {
|
|
| 86 |
+ if time.Since(existRn.Registered) < s.rateLimitPeriod {
|
|
| 87 |
+ return grpc.Errorf(codes.Unavailable, "node %s attempted registration too recently", id) |
|
| 88 |
+ } |
|
| 89 |
+ } |
|
| 90 |
+ return nil |
|
| 91 |
+} |
|
| 92 |
+ |
|
| 80 | 93 |
// Add adds new node and returns it, it replaces existing without notification. |
| 81 | 94 |
func (s *nodeStore) Add(n *api.Node, expireFunc func()) *registeredNode {
|
| 82 | 95 |
s.mu.Lock() |
| ... | ... |
@@ -88,6 +104,7 @@ func (s *nodeStore) Add(n *api.Node, expireFunc func()) *registeredNode {
|
| 88 | 88 |
rn := ®isteredNode{
|
| 89 | 89 |
SessionID: identity.NewID(), // session ID is local to the dispatcher. |
| 90 | 90 |
Node: n, |
| 91 |
+ Registered: time.Now(), |
|
| 91 | 92 |
Disconnect: make(chan struct{}),
|
| 92 | 93 |
} |
| 93 | 94 |
s.nodes[n.ID] = rn |
| 94 | 95 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,58 @@ |
| 0 |
+// Package health provides some utility functions to health-check a server. The implementation |
|
| 1 |
+// is based on protobuf. Users need to write their own implementations if other IDLs are used. |
|
| 2 |
+// |
|
| 3 |
+// See original source: https://github.com/grpc/grpc-go/blob/master/health/health.go |
|
| 4 |
+// |
|
| 5 |
+// We use our own implementation of grpc server health check to include the authorization |
|
| 6 |
+// wrapper necessary for the Managers. |
|
| 7 |
+package health |
|
| 8 |
+ |
|
| 9 |
+import ( |
|
| 10 |
+ "sync" |
|
| 11 |
+ |
|
| 12 |
+ "github.com/docker/swarmkit/api" |
|
| 13 |
+ "golang.org/x/net/context" |
|
| 14 |
+ "google.golang.org/grpc" |
|
| 15 |
+ "google.golang.org/grpc/codes" |
|
| 16 |
+) |
|
| 17 |
+ |
|
| 18 |
+// Server represents a Health Check server to check |
|
| 19 |
+// if a service is running or not on some host. |
|
| 20 |
+type Server struct {
|
|
| 21 |
+ mu sync.Mutex |
|
| 22 |
+ // statusMap stores the serving status of the services this HealthServer monitors. |
|
| 23 |
+ statusMap map[string]api.HealthCheckResponse_ServingStatus |
|
| 24 |
+} |
|
| 25 |
+ |
|
| 26 |
+// NewHealthServer creates a new health check server for grpc services. |
|
| 27 |
+func NewHealthServer() *Server {
|
|
| 28 |
+ return &Server{
|
|
| 29 |
+ statusMap: make(map[string]api.HealthCheckResponse_ServingStatus), |
|
| 30 |
+ } |
|
| 31 |
+} |
|
| 32 |
+ |
|
| 33 |
+// Check checks if the grpc server is healthy and running. |
|
| 34 |
+func (s *Server) Check(ctx context.Context, in *api.HealthCheckRequest) (*api.HealthCheckResponse, error) {
|
|
| 35 |
+ s.mu.Lock() |
|
| 36 |
+ defer s.mu.Unlock() |
|
| 37 |
+ if in.Service == "" {
|
|
| 38 |
+ // check the server overall health status. |
|
| 39 |
+ return &api.HealthCheckResponse{
|
|
| 40 |
+ Status: api.HealthCheckResponse_SERVING, |
|
| 41 |
+ }, nil |
|
| 42 |
+ } |
|
| 43 |
+ if status, ok := s.statusMap[in.Service]; ok {
|
|
| 44 |
+ return &api.HealthCheckResponse{
|
|
| 45 |
+ Status: status, |
|
| 46 |
+ }, nil |
|
| 47 |
+ } |
|
| 48 |
+ return nil, grpc.Errorf(codes.NotFound, "unknown service") |
|
| 49 |
+} |
|
| 50 |
+ |
|
| 51 |
+// SetServingStatus is called when need to reset the serving status of a service |
|
| 52 |
+// or insert a new service entry into the statusMap. |
|
| 53 |
+func (s *Server) SetServingStatus(service string, status api.HealthCheckResponse_ServingStatus) {
|
|
| 54 |
+ s.mu.Lock() |
|
| 55 |
+ s.statusMap[service] = status |
|
| 56 |
+ s.mu.Unlock() |
|
| 57 |
+} |
| ... | ... |
@@ -32,6 +32,8 @@ const ( |
| 32 | 32 |
|
| 33 | 33 |
// DefaultSubsystem is gossip |
| 34 | 34 |
DefaultSubsystem = SubsystemGossip |
| 35 |
+ // number of keys to mainrain in the key ring. |
|
| 36 |
+ keyringSize = 3 |
|
| 35 | 37 |
) |
| 36 | 38 |
|
| 37 | 39 |
// map of subsystems and corresponding encryption algorithm. Initially only |
| ... | ... |
@@ -59,7 +61,6 @@ type KeyManager struct {
|
| 59 | 59 |
config *Config |
| 60 | 60 |
store *store.MemoryStore |
| 61 | 61 |
keyRing *keyRing |
| 62 |
- ticker *time.Ticker |
|
| 63 | 62 |
ctx context.Context |
| 64 | 63 |
cancel context.CancelFunc |
| 65 | 64 |
|
| ... | ... |
@@ -72,7 +73,7 @@ func DefaultConfig() *Config {
|
| 72 | 72 |
ClusterName: store.DefaultClusterName, |
| 73 | 73 |
Keylen: DefaultKeyLen, |
| 74 | 74 |
RotationInterval: DefaultKeyRotationInterval, |
| 75 |
- Subsystems: []string{DefaultSubsystem},
|
|
| 75 |
+ Subsystems: []string{SubsystemGossip, SubsystemIPSec},
|
|
| 76 | 76 |
} |
| 77 | 77 |
} |
| 78 | 78 |
|
| ... | ... |
@@ -148,7 +149,7 @@ func (k *KeyManager) rotateKey(ctx context.Context) error {
|
| 148 | 148 |
// We maintain the latest key and the one before in the key ring to allow |
| 149 | 149 |
// agents to communicate without disruption on key change. |
| 150 | 150 |
for subsys, keys := range subsysKeys {
|
| 151 |
- if len(keys) > 1 {
|
|
| 151 |
+ if len(keys) == keyringSize {
|
|
| 152 | 152 |
min := 0 |
| 153 | 153 |
for i, key := range keys[1:] {
|
| 154 | 154 |
if key.LamportTime < keys[min].LamportTime {
|
| ... | ... |
@@ -189,7 +190,9 @@ func (k *KeyManager) Run(ctx context.Context) error {
|
| 189 | 189 |
cluster := clusters[0] |
| 190 | 190 |
if len(cluster.NetworkBootstrapKeys) == 0 {
|
| 191 | 191 |
for _, subsys := range k.config.Subsystems {
|
| 192 |
- k.keyRing.keys = append(k.keyRing.keys, k.allocateKey(ctx, subsys)) |
|
| 192 |
+ for i := 0; i < keyringSize; i++ {
|
|
| 193 |
+ k.keyRing.keys = append(k.keyRing.keys, k.allocateKey(ctx, subsys)) |
|
| 194 |
+ } |
|
| 193 | 195 |
} |
| 194 | 196 |
if err := k.updateKey(cluster); err != nil {
|
| 195 | 197 |
log.Errorf("store update failed %v", err)
|
| ... | ... |
@@ -19,6 +19,7 @@ import ( |
| 19 | 19 |
"github.com/docker/swarmkit/manager/allocator" |
| 20 | 20 |
"github.com/docker/swarmkit/manager/controlapi" |
| 21 | 21 |
"github.com/docker/swarmkit/manager/dispatcher" |
| 22 |
+ "github.com/docker/swarmkit/manager/health" |
|
| 22 | 23 |
"github.com/docker/swarmkit/manager/keymanager" |
| 23 | 24 |
"github.com/docker/swarmkit/manager/orchestrator" |
| 24 | 25 |
"github.com/docker/swarmkit/manager/raftpicker" |
| ... | ... |
@@ -39,6 +40,10 @@ const ( |
| 39 | 39 |
type Config struct {
|
| 40 | 40 |
SecurityConfig *ca.SecurityConfig |
| 41 | 41 |
|
| 42 |
+ // ExternalCAs is a list of initial CAs to which a manager node |
|
| 43 |
+ // will make certificate signing requests for node certificates. |
|
| 44 |
+ ExternalCAs []*api.ExternalCA |
|
| 45 |
+ |
|
| 42 | 46 |
ProtoAddr map[string]string |
| 43 | 47 |
// ProtoListener will be used for grpc serving if it's not nil, |
| 44 | 48 |
// ProtoAddr fields will be used to create listeners otherwise. |
| ... | ... |
@@ -83,8 +88,7 @@ type Manager struct {
|
| 83 | 83 |
localserver *grpc.Server |
| 84 | 84 |
RaftNode *raft.Node |
| 85 | 85 |
|
| 86 |
- mu sync.Mutex |
|
| 87 |
- once sync.Once |
|
| 86 |
+ mu sync.Mutex |
|
| 88 | 87 |
|
| 89 | 88 |
stopped chan struct{}
|
| 90 | 89 |
} |
| ... | ... |
@@ -202,13 +206,7 @@ func New(config *Config) (*Manager, error) {
|
| 202 | 202 |
ForceNewCluster: config.ForceNewCluster, |
| 203 | 203 |
TLSCredentials: config.SecurityConfig.ClientTLSCreds, |
| 204 | 204 |
} |
| 205 |
- RaftNode, err := raft.NewNode(context.TODO(), newNodeOpts) |
|
| 206 |
- if err != nil {
|
|
| 207 |
- for _, lis := range listeners {
|
|
| 208 |
- lis.Close() |
|
| 209 |
- } |
|
| 210 |
- return nil, fmt.Errorf("can't create raft node: %v", err)
|
|
| 211 |
- } |
|
| 205 |
+ RaftNode := raft.NewNode(context.TODO(), newNodeOpts) |
|
| 212 | 206 |
|
| 213 | 207 |
opts := []grpc.ServerOption{
|
| 214 | 208 |
grpc.Creds(config.SecurityConfig.ServerTLSCreds)} |
| ... | ... |
@@ -275,6 +273,10 @@ func (m *Manager) Run(parent context.Context) error {
|
| 275 | 275 |
raftCfg.HeartbeatTick = uint32(m.RaftNode.Config.HeartbeatTick) |
| 276 | 276 |
|
| 277 | 277 |
clusterID := m.config.SecurityConfig.ClientTLSCreds.Organization() |
| 278 |
+ |
|
| 279 |
+ initialCAConfig := ca.DefaultCAConfig() |
|
| 280 |
+ initialCAConfig.ExternalCAs = m.config.ExternalCAs |
|
| 281 |
+ |
|
| 278 | 282 |
s.Update(func(tx store.Tx) error {
|
| 279 | 283 |
// Add a default cluster object to the |
| 280 | 284 |
// store. Don't check the error because |
| ... | ... |
@@ -294,7 +296,7 @@ func (m *Manager) Run(parent context.Context) error {
|
| 294 | 294 |
HeartbeatPeriod: ptypes.DurationProto(dispatcher.DefaultHeartBeatPeriod), |
| 295 | 295 |
}, |
| 296 | 296 |
Raft: raftCfg, |
| 297 |
- CAConfig: ca.DefaultCAConfig(), |
|
| 297 |
+ CAConfig: initialCAConfig, |
|
| 298 | 298 |
}, |
| 299 | 299 |
RootCA: api.RootCA{
|
| 300 | 300 |
CAKey: rootCA.Key, |
| ... | ... |
@@ -327,7 +329,7 @@ func (m *Manager) Run(parent context.Context) error {
|
| 327 | 327 |
log.G(ctx).WithError(err).Error("root key-encrypting-key rotation failed")
|
| 328 | 328 |
} |
| 329 | 329 |
|
| 330 |
- m.replicatedOrchestrator = orchestrator.New(s) |
|
| 330 |
+ m.replicatedOrchestrator = orchestrator.NewReplicatedOrchestrator(s) |
|
| 331 | 331 |
m.globalOrchestrator = orchestrator.NewGlobalOrchestrator(s) |
| 332 | 332 |
m.taskReaper = orchestrator.NewTaskReaper(s) |
| 333 | 333 |
m.scheduler = scheduler.New(s) |
| ... | ... |
@@ -421,14 +423,6 @@ func (m *Manager) Run(parent context.Context) error {
|
| 421 | 421 |
} |
| 422 | 422 |
}() |
| 423 | 423 |
|
| 424 |
- go func() {
|
|
| 425 |
- err := m.RaftNode.Run(ctx) |
|
| 426 |
- if err != nil {
|
|
| 427 |
- log.G(ctx).Error(err) |
|
| 428 |
- m.Stop(ctx) |
|
| 429 |
- } |
|
| 430 |
- }() |
|
| 431 |
- |
|
| 432 | 424 |
proxyOpts := []grpc.DialOption{
|
| 433 | 425 |
grpc.WithBackoffMaxDelay(2 * time.Second), |
| 434 | 426 |
grpc.WithTransportCredentials(m.config.SecurityConfig.ClientTLSCreds), |
| ... | ... |
@@ -443,12 +437,14 @@ func (m *Manager) Run(parent context.Context) error {
|
| 443 | 443 |
} |
| 444 | 444 |
|
| 445 | 445 |
baseControlAPI := controlapi.NewServer(m.RaftNode.MemoryStore(), m.RaftNode) |
| 446 |
+ healthServer := health.NewHealthServer() |
|
| 446 | 447 |
|
| 447 | 448 |
authenticatedControlAPI := api.NewAuthenticatedWrapperControlServer(baseControlAPI, authorize) |
| 448 | 449 |
authenticatedDispatcherAPI := api.NewAuthenticatedWrapperDispatcherServer(m.Dispatcher, authorize) |
| 449 | 450 |
authenticatedCAAPI := api.NewAuthenticatedWrapperCAServer(m.caserver, authorize) |
| 450 | 451 |
authenticatedNodeCAAPI := api.NewAuthenticatedWrapperNodeCAServer(m.caserver, authorize) |
| 451 | 452 |
authenticatedRaftAPI := api.NewAuthenticatedWrapperRaftServer(m.RaftNode, authorize) |
| 453 |
+ authenticatedHealthAPI := api.NewAuthenticatedWrapperHealthServer(healthServer, authorize) |
|
| 452 | 454 |
authenticatedRaftMembershipAPI := api.NewAuthenticatedWrapperRaftMembershipServer(m.RaftNode, authorize) |
| 453 | 455 |
|
| 454 | 456 |
proxyDispatcherAPI := api.NewRaftProxyDispatcherServer(authenticatedDispatcherAPI, cs, m.RaftNode, ca.WithMetadataForwardTLSInfo) |
| ... | ... |
@@ -470,6 +466,7 @@ func (m *Manager) Run(parent context.Context) error {
|
| 470 | 470 |
api.RegisterCAServer(m.server, proxyCAAPI) |
| 471 | 471 |
api.RegisterNodeCAServer(m.server, proxyNodeCAAPI) |
| 472 | 472 |
api.RegisterRaftServer(m.server, authenticatedRaftAPI) |
| 473 |
+ api.RegisterHealthServer(m.server, authenticatedHealthAPI) |
|
| 473 | 474 |
api.RegisterRaftMembershipServer(m.server, proxyRaftMembershipAPI) |
| 474 | 475 |
api.RegisterControlServer(m.localserver, localProxyControlAPI) |
| 475 | 476 |
api.RegisterControlServer(m.server, authenticatedControlAPI) |
| ... | ... |
@@ -492,6 +489,24 @@ func (m *Manager) Run(parent context.Context) error {
|
| 492 | 492 |
}(proto, l) |
| 493 | 493 |
} |
| 494 | 494 |
|
| 495 |
+ // Set the raft server as serving for the health server |
|
| 496 |
+ healthServer.SetServingStatus("Raft", api.HealthCheckResponse_SERVING)
|
|
| 497 |
+ |
|
| 498 |
+ if err := m.RaftNode.JoinAndStart(); err != nil {
|
|
| 499 |
+ for _, lis := range m.listeners {
|
|
| 500 |
+ lis.Close() |
|
| 501 |
+ } |
|
| 502 |
+ return fmt.Errorf("can't initialize raft node: %v", err)
|
|
| 503 |
+ } |
|
| 504 |
+ |
|
| 505 |
+ go func() {
|
|
| 506 |
+ err := m.RaftNode.Run(ctx) |
|
| 507 |
+ if err != nil {
|
|
| 508 |
+ log.G(ctx).Error(err) |
|
| 509 |
+ m.Stop(ctx) |
|
| 510 |
+ } |
|
| 511 |
+ }() |
|
| 512 |
+ |
|
| 495 | 513 |
if err := raft.WaitForLeader(ctx, m.RaftNode); err != nil {
|
| 496 | 514 |
m.server.Stop() |
| 497 | 515 |
return err |
| ... | ... |
@@ -255,7 +255,7 @@ func (g *GlobalOrchestrator) reconcileOneNode(ctx context.Context, node *api.Nod |
| 255 | 255 |
return |
| 256 | 256 |
} |
| 257 | 257 |
// typically there are only a few global services on a node |
| 258 |
- // iterate thru all of them one by one. If raft store visits become a concern, |
|
| 258 |
+ // iterate through all of them one by one. If raft store visits become a concern, |
|
| 259 | 259 |
// it can be optimized. |
| 260 | 260 |
for _, service := range g.globalServices {
|
| 261 | 261 |
g.reconcileServiceOneNode(ctx, service.ID, node.ID) |
| ... | ... |
@@ -29,8 +29,8 @@ type ReplicatedOrchestrator struct {
|
| 29 | 29 |
restarts *RestartSupervisor |
| 30 | 30 |
} |
| 31 | 31 |
|
| 32 |
-// New creates a new ReplicatedOrchestrator. |
|
| 33 |
-func New(store *store.MemoryStore) *ReplicatedOrchestrator {
|
|
| 32 |
+// NewReplicatedOrchestrator creates a new ReplicatedOrchestrator. |
|
| 33 |
+func NewReplicatedOrchestrator(store *store.MemoryStore) *ReplicatedOrchestrator {
|
|
| 34 | 34 |
restartSupervisor := NewRestartSupervisor(store) |
| 35 | 35 |
updater := NewUpdateSupervisor(store, restartSupervisor) |
| 36 | 36 |
return &ReplicatedOrchestrator{
|
| ... | ... |
@@ -114,6 +114,9 @@ func newTask(service *api.Service, instance uint64) *api.Task {
|
| 114 | 114 |
Timestamp: ptypes.MustTimestampProto(time.Now()), |
| 115 | 115 |
Message: "created", |
| 116 | 116 |
}, |
| 117 |
+ Endpoint: &api.Endpoint{
|
|
| 118 |
+ Spec: service.Spec.Endpoint.Copy(), |
|
| 119 |
+ }, |
|
| 117 | 120 |
DesiredState: api.TaskStateRunning, |
| 118 | 121 |
} |
| 119 | 122 |
} |
| ... | ... |
@@ -1,6 +1,8 @@ |
| 1 | 1 |
package orchestrator |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "sort" |
|
| 5 |
+ |
|
| 4 | 6 |
"github.com/docker/go-events" |
| 5 | 7 |
"github.com/docker/swarmkit/api" |
| 6 | 8 |
"github.com/docker/swarmkit/log" |
| ... | ... |
@@ -68,6 +70,27 @@ func (r *ReplicatedOrchestrator) resolveService(ctx context.Context, task *api.T |
| 68 | 68 |
return service |
| 69 | 69 |
} |
| 70 | 70 |
|
| 71 |
+type taskWithIndex struct {
|
|
| 72 |
+ task *api.Task |
|
| 73 |
+ |
|
| 74 |
+ // index is a counter that counts this task as the nth instance of |
|
| 75 |
+ // the service on its node. This is used for sorting the tasks so that |
|
| 76 |
+ // when scaling down we leave tasks more evenly balanced. |
|
| 77 |
+ index int |
|
| 78 |
+} |
|
| 79 |
+ |
|
| 80 |
+type tasksByIndex []taskWithIndex |
|
| 81 |
+ |
|
| 82 |
+func (ts tasksByIndex) Len() int { return len(ts) }
|
|
| 83 |
+func (ts tasksByIndex) Swap(i, j int) { ts[i], ts[j] = ts[j], ts[i] }
|
|
| 84 |
+ |
|
| 85 |
+func (ts tasksByIndex) Less(i, j int) bool {
|
|
| 86 |
+ if ts[i].index < 0 {
|
|
| 87 |
+ return false |
|
| 88 |
+ } |
|
| 89 |
+ return ts[i].index < ts[j].index |
|
| 90 |
+} |
|
| 91 |
+ |
|
| 71 | 92 |
func (r *ReplicatedOrchestrator) reconcile(ctx context.Context, service *api.Service) {
|
| 72 | 93 |
var ( |
| 73 | 94 |
tasks []*api.Task |
| ... | ... |
@@ -97,8 +120,6 @@ func (r *ReplicatedOrchestrator) reconcile(ctx context.Context, service *api.Ser |
| 97 | 97 |
deploy := service.Spec.GetMode().(*api.ServiceSpec_Replicated) |
| 98 | 98 |
specifiedInstances := int(deploy.Replicated.Replicas) |
| 99 | 99 |
|
| 100 |
- // TODO(aaronl): Add support for restart delays. |
|
| 101 |
- |
|
| 102 | 100 |
switch {
|
| 103 | 101 |
case specifiedInstances > numTasks: |
| 104 | 102 |
log.G(ctx).Debugf("Service %s was scaled up from %d to %d instances", service.ID, numTasks, specifiedInstances)
|
| ... | ... |
@@ -115,9 +136,35 @@ func (r *ReplicatedOrchestrator) reconcile(ctx context.Context, service *api.Ser |
| 115 | 115 |
case specifiedInstances < numTasks: |
| 116 | 116 |
// Update up to N tasks then remove the extra |
| 117 | 117 |
log.G(ctx).Debugf("Service %s was scaled down from %d to %d instances", service.ID, numTasks, specifiedInstances)
|
| 118 |
- r.updater.Update(ctx, service, runningTasks[:specifiedInstances]) |
|
| 118 |
+ |
|
| 119 |
+ // Preferentially remove tasks on the nodes that have the most |
|
| 120 |
+ // copies of this service, to leave a more balanced result. |
|
| 121 |
+ // Assign each task an index that counts it as the nth copy of |
|
| 122 |
+ // of the service on its node (1, 2, 3, ...), and sort the |
|
| 123 |
+ // tasks by this counter value. |
|
| 124 |
+ |
|
| 125 |
+ instancesByNode := make(map[string]int) |
|
| 126 |
+ tasksWithIndices := make(tasksByIndex, 0, numTasks) |
|
| 127 |
+ |
|
| 128 |
+ for _, t := range runningTasks {
|
|
| 129 |
+ if t.NodeID != "" {
|
|
| 130 |
+ instancesByNode[t.NodeID]++ |
|
| 131 |
+ tasksWithIndices = append(tasksWithIndices, taskWithIndex{task: t, index: instancesByNode[t.NodeID]})
|
|
| 132 |
+ } else {
|
|
| 133 |
+ tasksWithIndices = append(tasksWithIndices, taskWithIndex{task: t, index: -1})
|
|
| 134 |
+ } |
|
| 135 |
+ } |
|
| 136 |
+ |
|
| 137 |
+ sort.Sort(tasksWithIndices) |
|
| 138 |
+ |
|
| 139 |
+ sortedTasks := make([]*api.Task, 0, numTasks) |
|
| 140 |
+ for _, t := range tasksWithIndices {
|
|
| 141 |
+ sortedTasks = append(sortedTasks, t.task) |
|
| 142 |
+ } |
|
| 143 |
+ |
|
| 144 |
+ r.updater.Update(ctx, service, sortedTasks[:specifiedInstances]) |
|
| 119 | 145 |
_, err = r.store.Batch(func(batch *store.Batch) error {
|
| 120 |
- r.removeTasks(ctx, batch, service, runningTasks[specifiedInstances:]) |
|
| 146 |
+ r.removeTasks(ctx, batch, service, sortedTasks[specifiedInstances:]) |
|
| 121 | 147 |
return nil |
| 122 | 148 |
}) |
| 123 | 149 |
if err != nil {
|
| ... | ... |
@@ -104,7 +104,8 @@ func (u *Updater) Run(ctx context.Context, service *api.Service, tasks []*api.Ta |
| 104 | 104 |
dirtyTasks := []*api.Task{}
|
| 105 | 105 |
for _, t := range tasks {
|
| 106 | 106 |
if !reflect.DeepEqual(service.Spec.Task, t.Spec) || |
| 107 |
- !reflect.DeepEqual(service.Endpoint, t.Endpoint) {
|
|
| 107 |
+ (t.Endpoint != nil && |
|
| 108 |
+ !reflect.DeepEqual(service.Spec.Endpoint, t.Endpoint.Spec)) {
|
|
| 108 | 109 |
dirtyTasks = append(dirtyTasks, t) |
| 109 | 110 |
} |
| 110 | 111 |
} |
| ... | ... |
@@ -191,6 +192,9 @@ func (u *Updater) updateTask(ctx context.Context, service *api.Service, original |
| 191 | 191 |
if t == nil {
|
| 192 | 192 |
return fmt.Errorf("task %s not found while trying to update it", original.ID)
|
| 193 | 193 |
} |
| 194 |
+ if t.DesiredState > api.TaskStateRunning {
|
|
| 195 |
+ return fmt.Errorf("task %s was already shut down when reached by updater", original.ID)
|
|
| 196 |
+ } |
|
| 194 | 197 |
t.DesiredState = api.TaskStateShutdown |
| 195 | 198 |
if err := store.UpdateTask(tx, t); err != nil {
|
| 196 | 199 |
return err |
| ... | ... |
@@ -48,13 +48,6 @@ func (nh *nodeHeap) alloc(n int) {
|
| 48 | 48 |
nh.index = make(map[string]int, n) |
| 49 | 49 |
} |
| 50 | 50 |
|
| 51 |
-func (nh *nodeHeap) peek() *NodeInfo {
|
|
| 52 |
- if len(nh.heap) == 0 {
|
|
| 53 |
- return nil |
|
| 54 |
- } |
|
| 55 |
- return &nh.heap[0] |
|
| 56 |
-} |
|
| 57 |
- |
|
| 58 | 51 |
// nodeInfo returns the NodeInfo struct for a given node identified by its ID. |
| 59 | 52 |
func (nh *nodeHeap) nodeInfo(nodeID string) NodeInfo {
|
| 60 | 53 |
index, ok := nh.index[nodeID] |
| ... | ... |
@@ -95,9 +88,7 @@ func (nh *nodeHeap) updateNode(n NodeInfo) {
|
| 95 | 95 |
func (nh *nodeHeap) remove(nodeID string) {
|
| 96 | 96 |
index, ok := nh.index[nodeID] |
| 97 | 97 |
if ok {
|
| 98 |
- nh.heap[index].Tasks = nil |
|
| 99 |
- heap.Fix(nh, index) |
|
| 100 |
- heap.Pop(nh) |
|
| 98 |
+ heap.Remove(nh, index) |
|
| 101 | 99 |
} |
| 102 | 100 |
} |
| 103 | 101 |
|
| ... | ... |
@@ -27,8 +27,6 @@ var ( |
| 27 | 27 |
// Cluster represents a set of active |
| 28 | 28 |
// raft Members |
| 29 | 29 |
type Cluster struct {
|
| 30 |
- id uint64 |
|
| 31 |
- |
|
| 32 | 30 |
mu sync.RWMutex |
| 33 | 31 |
members map[uint64]*Member |
| 34 | 32 |
|
| ... | ... |
@@ -103,17 +101,15 @@ func (c *Cluster) RemoveMember(id uint64) error {
|
| 103 | 103 |
c.mu.Lock() |
| 104 | 104 |
defer c.mu.Unlock() |
| 105 | 105 |
|
| 106 |
- if c.members[id] == nil {
|
|
| 107 |
- return ErrIDNotFound |
|
| 108 |
- } |
|
| 109 |
- |
|
| 110 |
- conn := c.members[id].Conn |
|
| 111 |
- if conn != nil {
|
|
| 112 |
- _ = conn.Close() |
|
| 106 |
+ if c.members[id] != nil {
|
|
| 107 |
+ conn := c.members[id].Conn |
|
| 108 |
+ if conn != nil {
|
|
| 109 |
+ _ = conn.Close() |
|
| 110 |
+ } |
|
| 111 |
+ delete(c.members, id) |
|
| 113 | 112 |
} |
| 114 | 113 |
|
| 115 | 114 |
c.removed[id] = true |
| 116 |
- delete(c.members, id) |
|
| 117 | 115 |
return nil |
| 118 | 116 |
} |
| 119 | 117 |
|
| ... | ... |
@@ -31,6 +31,11 @@ import ( |
| 31 | 31 |
) |
| 32 | 32 |
|
| 33 | 33 |
var ( |
| 34 |
+ // ErrHealthCheckFailure is returned when there is an issue with the initial handshake which means |
|
| 35 |
+ // that the address provided must be invalid or there is ongoing connectivity issues at join time. |
|
| 36 |
+ ErrHealthCheckFailure = errors.New("raft: could not connect to prospective new cluster member using its advertised address")
|
|
| 37 |
+ // ErrNoRaftMember is thrown when the node is not yet part of a raft cluster |
|
| 38 |
+ ErrNoRaftMember = errors.New("raft: node is not yet part of a raft cluster")
|
|
| 34 | 39 |
// ErrConfChangeRefused is returned when there is an issue with the configuration change |
| 35 | 40 |
ErrConfChangeRefused = errors.New("raft: propose configuration change refused")
|
| 36 | 41 |
// ErrApplyNotSpecified is returned during the creation of a raft node when no apply method was provided |
| ... | ... |
@@ -83,12 +88,13 @@ type Node struct {
|
| 83 | 83 |
raftStore *raft.MemoryStorage |
| 84 | 84 |
memoryStore *store.MemoryStore |
| 85 | 85 |
Config *raft.Config |
| 86 |
+ opts NewNodeOptions |
|
| 86 | 87 |
reqIDGen *idutil.Generator |
| 87 | 88 |
wait *wait |
| 88 | 89 |
wal *wal.WAL |
| 89 | 90 |
snapshotter *snap.Snapshotter |
| 90 | 91 |
wasLeader bool |
| 91 |
- removed uint32 |
|
| 92 |
+ isMember uint32 |
|
| 92 | 93 |
joinAddr string |
| 93 | 94 |
|
| 94 | 95 |
// waitProp waits for all the proposals to be terminated before |
| ... | ... |
@@ -103,14 +109,15 @@ type Node struct {
|
| 103 | 103 |
appliedIndex uint64 |
| 104 | 104 |
snapshotIndex uint64 |
| 105 | 105 |
|
| 106 |
- ticker clock.Ticker |
|
| 107 |
- sendTimeout time.Duration |
|
| 108 |
- stopCh chan struct{}
|
|
| 109 |
- doneCh chan struct{}
|
|
| 106 |
+ ticker clock.Ticker |
|
| 107 |
+ sendTimeout time.Duration |
|
| 108 |
+ stopCh chan struct{}
|
|
| 109 |
+ doneCh chan struct{}
|
|
| 110 |
+ // removeRaftCh notifies about node deletion from raft cluster |
|
| 111 |
+ removeRaftCh chan struct{}
|
|
| 112 |
+ removeRaftOnce sync.Once |
|
| 110 | 113 |
leadershipBroadcast *events.Broadcaster |
| 111 | 114 |
|
| 112 |
- startNodePeers []raft.Peer |
|
| 113 |
- |
|
| 114 | 115 |
// used to coordinate shutdown |
| 115 | 116 |
stopMu sync.RWMutex |
| 116 | 117 |
// used for membership management checks |
| ... | ... |
@@ -153,7 +160,7 @@ func init() {
|
| 153 | 153 |
} |
| 154 | 154 |
|
| 155 | 155 |
// NewNode generates a new Raft node |
| 156 |
-func NewNode(ctx context.Context, opts NewNodeOptions) (*Node, error) {
|
|
| 156 |
+func NewNode(ctx context.Context, opts NewNodeOptions) *Node {
|
|
| 157 | 157 |
cfg := opts.Config |
| 158 | 158 |
if cfg == nil {
|
| 159 | 159 |
cfg = DefaultNodeConfig() |
| ... | ... |
@@ -173,6 +180,7 @@ func NewNode(ctx context.Context, opts NewNodeOptions) (*Node, error) {
|
| 173 | 173 |
tlsCredentials: opts.TLSCredentials, |
| 174 | 174 |
raftStore: raftStore, |
| 175 | 175 |
Address: opts.Addr, |
| 176 |
+ opts: opts, |
|
| 176 | 177 |
Config: &raft.Config{
|
| 177 | 178 |
ElectionTick: cfg.ElectionTick, |
| 178 | 179 |
HeartbeatTick: cfg.HeartbeatTick, |
| ... | ... |
@@ -184,6 +192,7 @@ func NewNode(ctx context.Context, opts NewNodeOptions) (*Node, error) {
|
| 184 | 184 |
forceNewCluster: opts.ForceNewCluster, |
| 185 | 185 |
stopCh: make(chan struct{}),
|
| 186 | 186 |
doneCh: make(chan struct{}),
|
| 187 |
+ removeRaftCh: make(chan struct{}),
|
|
| 187 | 188 |
StateDir: opts.StateDir, |
| 188 | 189 |
joinAddr: opts.JoinAddr, |
| 189 | 190 |
sendTimeout: 2 * time.Second, |
| ... | ... |
@@ -200,13 +209,21 @@ func NewNode(ctx context.Context, opts NewNodeOptions) (*Node, error) {
|
| 200 | 200 |
n.sendTimeout = opts.SendTimeout |
| 201 | 201 |
} |
| 202 | 202 |
|
| 203 |
- loadAndStartErr := n.loadAndStart(ctx, opts.ForceNewCluster) |
|
| 203 |
+ n.reqIDGen = idutil.NewGenerator(uint16(n.Config.ID), time.Now()) |
|
| 204 |
+ n.wait = newWait() |
|
| 205 |
+ |
|
| 206 |
+ return n |
|
| 207 |
+} |
|
| 208 |
+ |
|
| 209 |
+// JoinAndStart joins and starts the raft server |
|
| 210 |
+func (n *Node) JoinAndStart() error {
|
|
| 211 |
+ loadAndStartErr := n.loadAndStart(n.Ctx, n.opts.ForceNewCluster) |
|
| 204 | 212 |
if loadAndStartErr != nil && loadAndStartErr != errNoWAL {
|
| 205 | 213 |
n.ticker.Stop() |
| 206 |
- return nil, loadAndStartErr |
|
| 214 |
+ return loadAndStartErr |
|
| 207 | 215 |
} |
| 208 | 216 |
|
| 209 |
- snapshot, err := raftStore.Snapshot() |
|
| 217 |
+ snapshot, err := n.raftStore.Snapshot() |
|
| 210 | 218 |
// Snapshot never returns an error |
| 211 | 219 |
if err != nil {
|
| 212 | 220 |
panic("could not get snapshot of raft store")
|
| ... | ... |
@@ -215,14 +232,12 @@ func NewNode(ctx context.Context, opts NewNodeOptions) (*Node, error) {
|
| 215 | 215 |
n.confState = snapshot.Metadata.ConfState |
| 216 | 216 |
n.appliedIndex = snapshot.Metadata.Index |
| 217 | 217 |
n.snapshotIndex = snapshot.Metadata.Index |
| 218 |
- n.reqIDGen = idutil.NewGenerator(uint16(n.Config.ID), time.Now()) |
|
| 219 |
- n.wait = newWait() |
|
| 220 | 218 |
|
| 221 | 219 |
if loadAndStartErr == errNoWAL {
|
| 222 | 220 |
if n.joinAddr != "" {
|
| 223 | 221 |
c, err := n.ConnectToMember(n.joinAddr, 10*time.Second) |
| 224 | 222 |
if err != nil {
|
| 225 |
- return nil, err |
|
| 223 |
+ return err |
|
| 226 | 224 |
} |
| 227 | 225 |
client := api.NewRaftMembershipClient(c.Conn) |
| 228 | 226 |
defer func() {
|
| ... | ... |
@@ -235,40 +250,42 @@ func NewNode(ctx context.Context, opts NewNodeOptions) (*Node, error) {
|
| 235 | 235 |
Addr: n.Address, |
| 236 | 236 |
}) |
| 237 | 237 |
if err != nil {
|
| 238 |
- return nil, err |
|
| 238 |
+ return err |
|
| 239 | 239 |
} |
| 240 | 240 |
|
| 241 | 241 |
n.Config.ID = resp.RaftID |
| 242 | 242 |
|
| 243 |
- if _, err := n.createWAL(opts.ID); err != nil {
|
|
| 244 |
- return nil, err |
|
| 243 |
+ if _, err := n.createWAL(n.opts.ID); err != nil {
|
|
| 244 |
+ return err |
|
| 245 | 245 |
} |
| 246 | 246 |
|
| 247 | 247 |
n.Node = raft.StartNode(n.Config, []raft.Peer{})
|
| 248 | 248 |
|
| 249 | 249 |
if err := n.registerNodes(resp.Members); err != nil {
|
| 250 |
- return nil, err |
|
| 250 |
+ return err |
|
| 251 | 251 |
} |
| 252 | 252 |
} else {
|
| 253 | 253 |
// First member in the cluster, self-assign ID |
| 254 | 254 |
n.Config.ID = uint64(rand.Int63()) + 1 |
| 255 |
- peer, err := n.createWAL(opts.ID) |
|
| 255 |
+ peer, err := n.createWAL(n.opts.ID) |
|
| 256 | 256 |
if err != nil {
|
| 257 |
- return nil, err |
|
| 257 |
+ return err |
|
| 258 | 258 |
} |
| 259 | 259 |
n.Node = raft.StartNode(n.Config, []raft.Peer{peer})
|
| 260 | 260 |
if err := n.Campaign(n.Ctx); err != nil {
|
| 261 |
- return nil, err |
|
| 261 |
+ return err |
|
| 262 | 262 |
} |
| 263 | 263 |
} |
| 264 |
- return n, nil |
|
| 264 |
+ atomic.StoreUint32(&n.isMember, 1) |
|
| 265 |
+ return nil |
|
| 265 | 266 |
} |
| 266 | 267 |
|
| 267 | 268 |
if n.joinAddr != "" {
|
| 268 | 269 |
n.Config.Logger.Warning("ignoring request to join cluster, because raft state already exists")
|
| 269 | 270 |
} |
| 270 | 271 |
n.Node = raft.RestartNode(n.Config) |
| 271 |
- return n, nil |
|
| 272 |
+ atomic.StoreUint32(&n.isMember, 1) |
|
| 273 |
+ return nil |
|
| 272 | 274 |
} |
| 273 | 275 |
|
| 274 | 276 |
// DefaultNodeConfig returns the default config for a |
| ... | ... |
@@ -377,21 +394,6 @@ func (n *Node) Run(ctx context.Context) error {
|
| 377 | 377 |
} |
| 378 | 378 |
} |
| 379 | 379 |
|
| 380 |
- // If the node was removed from other members, |
|
| 381 |
- // send back an error to the caller to start |
|
| 382 |
- // the shutdown process. |
|
| 383 |
- if n.mustStop() {
|
|
| 384 |
- n.stop() |
|
| 385 |
- |
|
| 386 |
- // Move WAL and snapshot out of the way, since |
|
| 387 |
- // they are no longer usable. |
|
| 388 |
- if err := n.moveWALAndSnap(); err != nil {
|
|
| 389 |
- n.Config.Logger.Error(err) |
|
| 390 |
- } |
|
| 391 |
- |
|
| 392 |
- return ErrMemberRemoved |
|
| 393 |
- } |
|
| 394 |
- |
|
| 395 | 380 |
// Advance the state machine |
| 396 | 381 |
n.Advance() |
| 397 | 382 |
|
| ... | ... |
@@ -400,6 +402,19 @@ func (n *Node) Run(ctx context.Context) error {
|
| 400 | 400 |
n.snapshotIndex = snapshotIndex |
| 401 | 401 |
} |
| 402 | 402 |
n.snapshotInProgress = nil |
| 403 |
+ case <-n.removeRaftCh: |
|
| 404 |
+ // If the node was removed from other members, |
|
| 405 |
+ // send back an error to the caller to start |
|
| 406 |
+ // the shutdown process. |
|
| 407 |
+ n.stop() |
|
| 408 |
+ |
|
| 409 |
+ // Move WAL and snapshot out of the way, since |
|
| 410 |
+ // they are no longer usable. |
|
| 411 |
+ if err := n.moveWALAndSnap(); err != nil {
|
|
| 412 |
+ n.Config.Logger.Error(err) |
|
| 413 |
+ } |
|
| 414 |
+ |
|
| 415 |
+ return ErrMemberRemoved |
|
| 403 | 416 |
case <-n.stopCh: |
| 404 | 417 |
n.stop() |
| 405 | 418 |
return nil |
| ... | ... |
@@ -434,6 +449,7 @@ func (n *Node) stop() {
|
| 434 | 434 |
} |
| 435 | 435 |
} |
| 436 | 436 |
n.Stop() |
| 437 |
+ n.ticker.Stop() |
|
| 437 | 438 |
if err := n.wal.Close(); err != nil {
|
| 438 | 439 |
n.Config.Logger.Errorf("raft: error closing WAL: %v", err)
|
| 439 | 440 |
} |
| ... | ... |
@@ -442,6 +458,10 @@ func (n *Node) stop() {
|
| 442 | 442 |
|
| 443 | 443 |
// IsLeader checks if we are the leader or not |
| 444 | 444 |
func (n *Node) IsLeader() bool {
|
| 445 |
+ if !n.IsMember() {
|
|
| 446 |
+ return false |
|
| 447 |
+ } |
|
| 448 |
+ |
|
| 445 | 449 |
if n.Node.Status().Lead == n.Config.ID {
|
| 446 | 450 |
return true |
| 447 | 451 |
} |
| ... | ... |
@@ -450,6 +470,9 @@ func (n *Node) IsLeader() bool {
|
| 450 | 450 |
|
| 451 | 451 |
// Leader returns the id of the leader |
| 452 | 452 |
func (n *Node) Leader() uint64 {
|
| 453 |
+ if !n.IsMember() {
|
|
| 454 |
+ return 0 |
|
| 455 |
+ } |
|
| 453 | 456 |
return n.Node.Status().Lead |
| 454 | 457 |
} |
| 455 | 458 |
|
| ... | ... |
@@ -479,7 +502,11 @@ func (n *Node) Join(ctx context.Context, req *api.JoinRequest) (*api.JoinRespons |
| 479 | 479 |
n.membershipLock.Lock() |
| 480 | 480 |
defer n.membershipLock.Unlock() |
| 481 | 481 |
|
| 482 |
- if n.Node == nil {
|
|
| 482 |
+ if !n.IsMember() {
|
|
| 483 |
+ return nil, ErrNoRaftMember |
|
| 484 |
+ } |
|
| 485 |
+ |
|
| 486 |
+ if n.IsStopped() {
|
|
| 483 | 487 |
log.WithError(ErrStopped).Errorf(ErrStopped.Error()) |
| 484 | 488 |
return nil, ErrStopped |
| 485 | 489 |
} |
| ... | ... |
@@ -497,6 +524,12 @@ func (n *Node) Join(ctx context.Context, req *api.JoinRequest) (*api.JoinRespons |
| 497 | 497 |
} |
| 498 | 498 |
} |
| 499 | 499 |
|
| 500 |
+ // We do not bother submitting a configuration change for the |
|
| 501 |
+ // new member if we can't contact it back using its address |
|
| 502 |
+ if err := n.checkHealth(ctx, req.Addr, 5*time.Second); err != nil {
|
|
| 503 |
+ return nil, err |
|
| 504 |
+ } |
|
| 505 |
+ |
|
| 500 | 506 |
err = n.addMember(ctx, req.Addr, raftID, nodeInfo.NodeID) |
| 501 | 507 |
if err != nil {
|
| 502 | 508 |
log.WithError(err).Errorf("failed to add member")
|
| ... | ... |
@@ -516,6 +549,28 @@ func (n *Node) Join(ctx context.Context, req *api.JoinRequest) (*api.JoinRespons |
| 516 | 516 |
return &api.JoinResponse{Members: nodes, RaftID: raftID}, nil
|
| 517 | 517 |
} |
| 518 | 518 |
|
| 519 |
+// checkHealth tries to contact an aspiring member through its advertised address |
|
| 520 |
+// and checks if its raft server is running. |
|
| 521 |
+func (n *Node) checkHealth(ctx context.Context, addr string, timeout time.Duration) error {
|
|
| 522 |
+ conn, err := dial(addr, "tcp", n.tlsCredentials, timeout) |
|
| 523 |
+ if err != nil {
|
|
| 524 |
+ return err |
|
| 525 |
+ } |
|
| 526 |
+ |
|
| 527 |
+ client := api.NewHealthClient(conn) |
|
| 528 |
+ defer conn.Close() |
|
| 529 |
+ |
|
| 530 |
+ resp, err := client.Check(ctx, &api.HealthCheckRequest{Service: "Raft"})
|
|
| 531 |
+ if err != nil {
|
|
| 532 |
+ return ErrHealthCheckFailure |
|
| 533 |
+ } |
|
| 534 |
+ if resp != nil && resp.Status != api.HealthCheckResponse_SERVING {
|
|
| 535 |
+ return ErrHealthCheckFailure |
|
| 536 |
+ } |
|
| 537 |
+ |
|
| 538 |
+ return nil |
|
| 539 |
+} |
|
| 540 |
+ |
|
| 519 | 541 |
// addMember submits a configuration change to add a new member on the raft cluster. |
| 520 | 542 |
func (n *Node) addMember(ctx context.Context, addr string, raftID uint64, nodeID string) error {
|
| 521 | 543 |
node := api.RaftMember{
|
| ... | ... |
@@ -563,7 +618,11 @@ func (n *Node) Leave(ctx context.Context, req *api.LeaveRequest) (*api.LeaveResp |
| 563 | 563 |
n.stopMu.RLock() |
| 564 | 564 |
defer n.stopMu.RUnlock() |
| 565 | 565 |
|
| 566 |
- if n.Node == nil {
|
|
| 566 |
+ if !n.IsMember() {
|
|
| 567 |
+ return nil, ErrNoRaftMember |
|
| 568 |
+ } |
|
| 569 |
+ |
|
| 570 |
+ if n.IsStopped() {
|
|
| 567 | 571 |
return nil, ErrStopped |
| 568 | 572 |
} |
| 569 | 573 |
|
| ... | ... |
@@ -612,7 +671,12 @@ func (n *Node) ProcessRaftMessage(ctx context.Context, msg *api.ProcessRaftMessa |
| 612 | 612 |
// can't stop the raft node while an async RPC is in progress |
| 613 | 613 |
n.stopMu.RLock() |
| 614 | 614 |
defer n.stopMu.RUnlock() |
| 615 |
- if n.Node == nil {
|
|
| 615 |
+ |
|
| 616 |
+ if !n.IsMember() {
|
|
| 617 |
+ return nil, ErrNoRaftMember |
|
| 618 |
+ } |
|
| 619 |
+ |
|
| 620 |
+ if n.IsStopped() {
|
|
| 616 | 621 |
return nil, ErrStopped |
| 617 | 622 |
} |
| 618 | 623 |
|
| ... | ... |
@@ -625,6 +689,10 @@ func (n *Node) ProcessRaftMessage(ctx context.Context, msg *api.ProcessRaftMessa |
| 625 | 625 |
|
| 626 | 626 |
// ResolveAddress returns the address reaching for a given node ID. |
| 627 | 627 |
func (n *Node) ResolveAddress(ctx context.Context, msg *api.ResolveAddressRequest) (*api.ResolveAddressResponse, error) {
|
| 628 |
+ if !n.IsMember() {
|
|
| 629 |
+ return nil, ErrNoRaftMember |
|
| 630 |
+ } |
|
| 631 |
+ |
|
| 628 | 632 |
nodeInfo, err := ca.RemoteNode(ctx) |
| 629 | 633 |
if err != nil {
|
| 630 | 634 |
return nil, err |
| ... | ... |
@@ -656,7 +724,7 @@ func (n *Node) LeaderAddr() (string, error) {
|
| 656 | 656 |
if err := WaitForLeader(ctx, n); err != nil {
|
| 657 | 657 |
return "", ErrNoClusterLeader |
| 658 | 658 |
} |
| 659 |
- if n.Node == nil {
|
|
| 659 |
+ if n.IsStopped() {
|
|
| 660 | 660 |
return "", ErrStopped |
| 661 | 661 |
} |
| 662 | 662 |
ms := n.cluster.Members() |
| ... | ... |
@@ -671,7 +739,7 @@ func (n *Node) LeaderAddr() (string, error) {
|
| 671 | 671 |
func (n *Node) registerNode(node *api.RaftMember) error {
|
| 672 | 672 |
member := &membership.Member{}
|
| 673 | 673 |
|
| 674 |
- if n.cluster.GetMember(node.RaftID) != nil {
|
|
| 674 |
+ if n.cluster.GetMember(node.RaftID) != nil || n.cluster.IsIDRemoved(node.RaftID) {
|
|
| 675 | 675 |
// member already exists |
| 676 | 676 |
return nil |
| 677 | 677 |
} |
| ... | ... |
@@ -760,11 +828,18 @@ func (n *Node) GetMemberlist() map[uint64]*api.RaftMember {
|
| 760 | 760 |
return memberlist |
| 761 | 761 |
} |
| 762 | 762 |
|
| 763 |
-// mustStop checks if the raft node must be stopped |
|
| 764 |
-// because it was removed from the cluster from |
|
| 765 |
-// other members |
|
| 766 |
-func (n *Node) mustStop() bool {
|
|
| 767 |
- return atomic.LoadUint32(&n.removed) == 1 |
|
| 763 |
+// IsMember checks if the raft node has effectively joined |
|
| 764 |
+// a cluster of existing members. |
|
| 765 |
+func (n *Node) IsMember() bool {
|
|
| 766 |
+ return atomic.LoadUint32(&n.isMember) == 1 |
|
| 767 |
+} |
|
| 768 |
+ |
|
| 769 |
+// IsStopped checks if the raft node is stopped or not |
|
| 770 |
+func (n *Node) IsStopped() bool {
|
|
| 771 |
+ if n.Node == nil {
|
|
| 772 |
+ return true |
|
| 773 |
+ } |
|
| 774 |
+ return false |
|
| 768 | 775 |
} |
| 769 | 776 |
|
| 770 | 777 |
// canSubmitProposal defines if any more proposals |
| ... | ... |
@@ -882,12 +957,14 @@ func (n *Node) sendToMember(members map[uint64]*membership.Member, m raftpb.Mess |
| 882 | 882 |
_, err := conn.ProcessRaftMessage(ctx, &api.ProcessRaftMessageRequest{Message: &m})
|
| 883 | 883 |
if err != nil {
|
| 884 | 884 |
if grpc.ErrorDesc(err) == ErrMemberRemoved.Error() {
|
| 885 |
- atomic.StoreUint32(&n.removed, 1) |
|
| 885 |
+ n.removeRaftOnce.Do(func() {
|
|
| 886 |
+ close(n.removeRaftCh) |
|
| 887 |
+ }) |
|
| 886 | 888 |
} |
| 887 | 889 |
if m.Type == raftpb.MsgSnap {
|
| 888 | 890 |
n.ReportSnapshot(m.To, raft.SnapshotFailure) |
| 889 | 891 |
} |
| 890 |
- if n.Node == nil {
|
|
| 892 |
+ if n.IsStopped() {
|
|
| 891 | 893 |
panic("node is nil")
|
| 892 | 894 |
} |
| 893 | 895 |
n.ReportUnreachable(m.To) |
| ... | ... |
@@ -162,6 +162,22 @@ func (n *Node) readWAL(ctx context.Context, snapshot *raftpb.Snapshot, forceNewC |
| 162 | 162 |
} |
| 163 | 163 |
n.Config.ID = raftNode.RaftID |
| 164 | 164 |
|
| 165 |
+ // All members that are no longer part of the cluster must be added to |
|
| 166 |
+ // the removed list right away, so that we don't try to connect to them |
|
| 167 |
+ // before processing the configuration change entries, which could make |
|
| 168 |
+ // us get stuck. |
|
| 169 |
+ for _, ent := range ents {
|
|
| 170 |
+ if ent.Index <= st.Commit && ent.Type == raftpb.EntryConfChange {
|
|
| 171 |
+ var cc raftpb.ConfChange |
|
| 172 |
+ if err := cc.Unmarshal(ent.Data); err != nil {
|
|
| 173 |
+ return fmt.Errorf("error unmarshalling config change: %v", err)
|
|
| 174 |
+ } |
|
| 175 |
+ if cc.Type == raftpb.ConfChangeRemoveNode {
|
|
| 176 |
+ n.cluster.RemoveMember(cc.NodeID) |
|
| 177 |
+ } |
|
| 178 |
+ } |
|
| 179 |
+ } |
|
| 180 |
+ |
|
| 165 | 181 |
if forceNewCluster {
|
| 166 | 182 |
// discard the previously uncommitted entries |
| 167 | 183 |
for i, ent := range ents {
|
| ... | ... |
@@ -174,6 +190,23 @@ func (n *Node) readWAL(ctx context.Context, snapshot *raftpb.Snapshot, forceNewC |
| 174 | 174 |
|
| 175 | 175 |
// force append the configuration change entries |
| 176 | 176 |
toAppEnts := createConfigChangeEnts(getIDs(snapshot, ents), uint64(n.Config.ID), st.Term, st.Commit) |
| 177 |
+ |
|
| 178 |
+ // All members that are being removed as part of the |
|
| 179 |
+ // force-new-cluster process must be added to the |
|
| 180 |
+ // removed list right away, so that we don't try to |
|
| 181 |
+ // connect to them before processing the configuration |
|
| 182 |
+ // change entries, which could make us get stuck. |
|
| 183 |
+ for _, ccEnt := range toAppEnts {
|
|
| 184 |
+ if ccEnt.Type == raftpb.EntryConfChange {
|
|
| 185 |
+ var cc raftpb.ConfChange |
|
| 186 |
+ if err := cc.Unmarshal(ccEnt.Data); err != nil {
|
|
| 187 |
+ return fmt.Errorf("error unmarshalling force-new-cluster config change: %v", err)
|
|
| 188 |
+ } |
|
| 189 |
+ if cc.Type == raftpb.ConfChangeRemoveNode {
|
|
| 190 |
+ n.cluster.RemoveMember(cc.NodeID) |
|
| 191 |
+ } |
|
| 192 |
+ } |
|
| 193 |
+ } |
|
| 177 | 194 |
ents = append(ents, toAppEnts...) |
| 178 | 195 |
|
| 179 | 196 |
// force commit newly appended entries |
| ... | ... |
@@ -347,9 +380,10 @@ func (n *Node) restoreFromSnapshot(data []byte, forceNewCluster bool) error {
|
| 347 | 347 |
return err |
| 348 | 348 |
} |
| 349 | 349 |
} |
| 350 |
- for _, removedMember := range snapshot.Membership.Removed {
|
|
| 351 |
- n.cluster.RemoveMember(removedMember) |
|
| 352 |
- } |
|
| 350 |
+ } |
|
| 351 |
+ |
|
| 352 |
+ for _, removedMember := range snapshot.Membership.Removed {
|
|
| 353 |
+ n.cluster.RemoveMember(removedMember) |
|
| 353 | 354 |
} |
| 354 | 355 |
|
| 355 | 356 |
return nil |