浏览代码

Vendor updated swarmkit, libnetwork, engine-api

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Tonis Tiigi 9 年之前
父节点
当前提交
54255f53d8
共有 71 个文件被更改,包括 3032 次插入773 次删除
  1. 4 4
      hack/vendor.sh
  2. 231 0
      vendor/src/github.com/cloudflare/cfssl/api/api.go
  3. 22 9
      vendor/src/github.com/cloudflare/cfssl/certdb/README.md
  4. 44 27
      vendor/src/github.com/cloudflare/cfssl/csr/csr.go
  5. 14 13
      vendor/src/github.com/cloudflare/cfssl/helpers/helpers.go
  6. 28 83
      vendor/src/github.com/cloudflare/cfssl/initca/initca.go
  7. 12 16
      vendor/src/github.com/cloudflare/cfssl/log/log.go
  8. 25 3
      vendor/src/github.com/cloudflare/cfssl/signer/local/local.go
  9. 43 18
      vendor/src/github.com/cloudflare/cfssl/signer/signer.go
  10. 1 1
      vendor/src/github.com/docker/engine-api/client/container_inspect.go
  11. 15 0
      vendor/src/github.com/docker/engine-api/client/errors.go
  12. 1 1
      vendor/src/github.com/docker/engine-api/client/interface.go
  13. 1 1
      vendor/src/github.com/docker/engine-api/client/network_inspect.go
  14. 15 7
      vendor/src/github.com/docker/engine-api/client/node_inspect.go
  15. 1 0
      vendor/src/github.com/docker/engine-api/client/plugin_install.go
  16. 1 1
      vendor/src/github.com/docker/engine-api/client/volume_inspect.go
  17. 1 1
      vendor/src/github.com/docker/engine-api/types/swarm/container.go
  18. 1 1
      vendor/src/github.com/docker/engine-api/types/swarm/service.go
  19. 15 1
      vendor/src/github.com/docker/engine-api/types/swarm/swarm.go
  20. 0 4
      vendor/src/github.com/docker/engine-api/types/types.go
  21. 10 10
      vendor/src/github.com/docker/libnetwork/agent.go
  22. 2 2
      vendor/src/github.com/docker/libnetwork/controller.go
  23. 39 20
      vendor/src/github.com/docker/libnetwork/datastore/datastore.go
  24. 1 1
      vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go
  25. 1 1
      vendor/src/github.com/docker/libnetwork/drivers/bridge/errors.go
  26. 3 3
      vendor/src/github.com/docker/libnetwork/drivers/overlay/ovmanager/ovmanager.go
  27. 2 2
      vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go
  28. 0 19
      vendor/src/github.com/docker/libnetwork/endpoint.go
  29. 14 2
      vendor/src/github.com/docker/libnetwork/osl/route_linux.go
  30. 23 1
      vendor/src/github.com/docker/libnetwork/service.go
  31. 72 17
      vendor/src/github.com/docker/libnetwork/service_linux.go
  32. 0 2
      vendor/src/github.com/docker/swarmkit/agent/agent.go
  33. 1 1
      vendor/src/github.com/docker/swarmkit/agent/exec/controller.go
  34. 1 1
      vendor/src/github.com/docker/swarmkit/agent/exec/executor.go
  35. 39 45
      vendor/src/github.com/docker/swarmkit/agent/node.go
  36. 0 1
      vendor/src/github.com/docker/swarmkit/agent/session.go
  37. 0 8
      vendor/src/github.com/docker/swarmkit/agent/storage.go
  38. 8 0
      vendor/src/github.com/docker/swarmkit/api/README.md
  39. 1 1
      vendor/src/github.com/docker/swarmkit/api/gen.go
  40. 714 0
      vendor/src/github.com/docker/swarmkit/api/health.pb.go
  41. 34 0
      vendor/src/github.com/docker/swarmkit/api/health.proto
  42. 103 56
      vendor/src/github.com/docker/swarmkit/api/raft.pb.go
  43. 7 0
      vendor/src/github.com/docker/swarmkit/api/raft.proto
  44. 7 4
      vendor/src/github.com/docker/swarmkit/api/specs.pb.go
  45. 7 4
      vendor/src/github.com/docker/swarmkit/api/specs.proto
  46. 646 194
      vendor/src/github.com/docker/swarmkit/api/types.pb.go
  47. 20 0
      vendor/src/github.com/docker/swarmkit/api/types.proto
  48. 52 19
      vendor/src/github.com/docker/swarmkit/ca/certificates.go
  49. 41 14
      vendor/src/github.com/docker/swarmkit/ca/config.go
  50. 141 0
      vendor/src/github.com/docker/swarmkit/ca/external.go
  51. 34 9
      vendor/src/github.com/docker/swarmkit/ca/server.go
  52. 8 0
      vendor/src/github.com/docker/swarmkit/ca/transport.go
  53. 64 16
      vendor/src/github.com/docker/swarmkit/manager/allocator/network.go
  54. 10 4
      vendor/src/github.com/docker/swarmkit/manager/allocator/networkallocator/networkallocator.go
  55. 10 0
      vendor/src/github.com/docker/swarmkit/manager/controlapi/network.go
  56. 69 6
      vendor/src/github.com/docker/swarmkit/manager/controlapi/service.go
  57. 22 12
      vendor/src/github.com/docker/swarmkit/manager/dispatcher/dispatcher.go
  58. 18 1
      vendor/src/github.com/docker/swarmkit/manager/dispatcher/nodes.go
  59. 58 0
      vendor/src/github.com/docker/swarmkit/manager/health/health.go
  60. 7 4
      vendor/src/github.com/docker/swarmkit/manager/keymanager/keymanager.go
  61. 34 19
      vendor/src/github.com/docker/swarmkit/manager/manager.go
  62. 1 1
      vendor/src/github.com/docker/swarmkit/manager/orchestrator/global.go
  63. 5 2
      vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated.go
  64. 51 4
      vendor/src/github.com/docker/swarmkit/manager/orchestrator/services.go
  65. 5 1
      vendor/src/github.com/docker/swarmkit/manager/orchestrator/updater.go
  66. 1 10
      vendor/src/github.com/docker/swarmkit/manager/scheduler/indexed_node_heap.go
  67. 6 10
      vendor/src/github.com/docker/swarmkit/manager/state/raft/membership/cluster.go
  68. 127 50
      vendor/src/github.com/docker/swarmkit/manager/state/raft/raft.go
  69. 37 3
      vendor/src/github.com/docker/swarmkit/manager/state/raft/storage.go
  70. 0 1
      vendor/src/github.com/docker/swarmkit/manager/state/store/memory.go
  71. 1 1
      vendor/src/github.com/docker/swarmkit/picker/picker.go

+ 4 - 4
hack/vendor.sh

@@ -60,12 +60,12 @@ clone git golang.org/x/net 2beffdc2e92c8a3027590f898fe88f69af48a3f8 https://gith
 clone git golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git
 clone git golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git
 clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3
 clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3
 clone git github.com/docker/go-connections fa2850ff103453a9ad190da0df0af134f0314b3d
 clone git github.com/docker/go-connections fa2850ff103453a9ad190da0df0af134f0314b3d
-clone git github.com/docker/engine-api 19b4fb48a86c3318e610e156ec06b684f79ac31d
+clone git github.com/docker/engine-api 62043eb79d581a32ea849645277023c550732e52
 clone git github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837
 clone git github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837
 clone git github.com/imdario/mergo 0.2.1
 clone git github.com/imdario/mergo 0.2.1
 
 
 #get libnetwork packages
 #get libnetwork packages
-clone git github.com/docker/libnetwork  ed311d050fda7821f2e7c53a7e08a0205923aef5
+clone git github.com/docker/libnetwork 377a7337f2387cce3be1df7a4503446147b68ff1
 clone git github.com/docker/go-events 39718a26497694185f8fb58a7d6f31947f3dc42d
 clone git github.com/docker/go-events 39718a26497694185f8fb58a7d6f31947f3dc42d
 clone git github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 clone git github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
@@ -139,10 +139,10 @@ clone git github.com/docker/docker-credential-helpers v0.3.0
 clone git github.com/docker/containerd b93a33be39bc4ef0fb00bfcb79147a28c33d9d43
 clone git github.com/docker/containerd b93a33be39bc4ef0fb00bfcb79147a28c33d9d43
 
 
 # cluster
 # cluster
-clone git github.com/docker/swarmkit 3f135f206179ea157aeef2d1d401eb795f618da8
+clone git github.com/docker/swarmkit 036a4a1e934bd1bbb35c3ec7f85dea2ba6d4e336
 clone git github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9
 clone git github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9
 clone git github.com/gogo/protobuf 43a2e0b1c32252bfbbdf81f7faa7a88fb3fa4028
 clone git github.com/gogo/protobuf 43a2e0b1c32252bfbbdf81f7faa7a88fb3fa4028
-clone git github.com/cloudflare/cfssl 92f037e39eb103fb30f9151be40d9ed267fc4ae2
+clone git github.com/cloudflare/cfssl b895b0549c0ff676f92cf09ba971ae02bb41367b
 clone git github.com/google/certificate-transparency 025a5cab06f6a819c455d9fdc9e2a1b6d0982284
 clone git github.com/google/certificate-transparency 025a5cab06f6a819c455d9fdc9e2a1b6d0982284
 clone git golang.org/x/crypto 3fbbcd23f1cb824e69491a5930cfeff09b12f4d2 https://github.com/golang/crypto.git
 clone git golang.org/x/crypto 3fbbcd23f1cb824e69491a5930cfeff09b12f4d2 https://github.com/golang/crypto.git
 clone git github.com/mreiferson/go-httpclient 63fe23f7434723dc904c901043af07931f293c47
 clone git github.com/mreiferson/go-httpclient 63fe23f7434723dc904c901043af07931f293c47

+ 231 - 0
vendor/src/github.com/cloudflare/cfssl/api/api.go

@@ -0,0 +1,231 @@
+// Package api implements an HTTP-based API and server for CFSSL.
+package api
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"net/http"
+
+	"github.com/cloudflare/cfssl/errors"
+	"github.com/cloudflare/cfssl/log"
+)
+
+// Handler is an interface providing a generic mechanism for handling HTTP requests.
+type Handler interface {
+	Handle(w http.ResponseWriter, r *http.Request) error
+}
+
+// HTTPHandler is a wrapper that encapsulates Handler interface as http.Handler.
+// HTTPHandler also enforces that the Handler only responds to requests with registered HTTP methods.
+type HTTPHandler struct {
+	Handler          // CFSSL handler
+	Methods []string // The associated HTTP methods
+}
+
+// HandlerFunc is similar to the http.HandlerFunc type; it serves as
+// an adapter allowing the use of ordinary functions as Handlers. If
+// f is a function with the appropriate signature, HandlerFunc(f) is a
+// Handler object that calls f.
+type HandlerFunc func(http.ResponseWriter, *http.Request) error
+
+// Handle calls f(w, r)
+func (f HandlerFunc) Handle(w http.ResponseWriter, r *http.Request) error {
+	w.Header().Set("Content-Type", "application/json")
+	return f(w, r)
+}
+
+// handleError is the centralised error handling and reporting.
+func handleError(w http.ResponseWriter, err error) (code int) {
+	if err == nil {
+		return http.StatusOK
+	}
+	msg := err.Error()
+	httpCode := http.StatusInternalServerError
+
+	// If it is recognized as HttpError emitted from cfssl,
+	// we rewrite the status code accordingly. If it is a
+	// cfssl error, set the http status to StatusBadRequest
+	switch err := err.(type) {
+	case *errors.HTTPError:
+		httpCode = err.StatusCode
+		code = err.StatusCode
+	case *errors.Error:
+		httpCode = http.StatusBadRequest
+		code = err.ErrorCode
+		msg = err.Message
+	}
+
+	response := NewErrorResponse(msg, code)
+	jsonMessage, err := json.Marshal(response)
+	if err != nil {
+		log.Errorf("Failed to marshal JSON: %v", err)
+	} else {
+		msg = string(jsonMessage)
+	}
+	http.Error(w, msg, httpCode)
+	return code
+}
+
+// ServeHTTP encapsulates the call to underlying Handler to handle the request
+// and return the response with proper HTTP status code
+func (h HTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	var err error
+	var match bool
+	// Throw 405 when requested with an unsupported verb.
+	for _, m := range h.Methods {
+		if m == r.Method {
+			match = true
+		}
+	}
+	if match {
+		err = h.Handle(w, r)
+	} else {
+		err = errors.NewMethodNotAllowed(r.Method)
+	}
+	status := handleError(w, err)
+	log.Infof("%s - \"%s %s\" %d", r.RemoteAddr, r.Method, r.URL, status)
+}
+
+// readRequestBlob takes a JSON-blob-encoded response body in the form
+// map[string]string and returns it, the list of keywords presented,
+// and any error that occurred.
+func readRequestBlob(r *http.Request) (map[string]string, error) {
+	var blob map[string]string
+
+	body, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return nil, err
+	}
+	r.Body.Close()
+
+	err = json.Unmarshal(body, &blob)
+	if err != nil {
+		return nil, err
+	}
+	return blob, nil
+}
+
+// ProcessRequestOneOf reads a JSON blob for the request and makes
+// sure it contains one of a set of keywords. For example, a request
+// might have the ('foo' && 'bar') keys, OR it might have the 'baz'
+// key.  In either case, we want to accept the request; however, if
+// none of these sets shows up, the request is a bad request, and it
+// should be returned.
+func ProcessRequestOneOf(r *http.Request, keywordSets [][]string) (map[string]string, []string, error) {
+	blob, err := readRequestBlob(r)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var matched []string
+	for _, set := range keywordSets {
+		if matchKeywords(blob, set) {
+			if matched != nil {
+				return nil, nil, errors.NewBadRequestString("mismatched parameters")
+			}
+			matched = set
+		}
+	}
+	if matched == nil {
+		return nil, nil, errors.NewBadRequestString("no valid parameter sets found")
+	}
+	return blob, matched, nil
+}
+
+// ProcessRequestFirstMatchOf reads a JSON blob for the request and returns
+// the first match of a set of keywords. For example, a request
+// might have one of the following combinations: (foo=1, bar=2), (foo=1), and (bar=2)
+// By giving a specific ordering of those combinations, we could decide how to accept
+// the request.
+func ProcessRequestFirstMatchOf(r *http.Request, keywordSets [][]string) (map[string]string, []string, error) {
+	blob, err := readRequestBlob(r)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	for _, set := range keywordSets {
+		if matchKeywords(blob, set) {
+			return blob, set, nil
+		}
+	}
+	return nil, nil, errors.NewBadRequestString("no valid parameter sets found")
+}
+
+func matchKeywords(blob map[string]string, keywords []string) bool {
+	for _, keyword := range keywords {
+		if _, ok := blob[keyword]; !ok {
+			return false
+		}
+	}
+	return true
+}
+
+// ResponseMessage implements the standard for response errors and
+// messages. A message has a code and a string message.
+type ResponseMessage struct {
+	Code    int    `json:"code"`
+	Message string `json:"message"`
+}
+
+// Response implements the CloudFlare standard for API
+// responses.
+type Response struct {
+	Success  bool              `json:"success"`
+	Result   interface{}       `json:"result"`
+	Errors   []ResponseMessage `json:"errors"`
+	Messages []ResponseMessage `json:"messages"`
+}
+
+// NewSuccessResponse is a shortcut for creating new successul API
+// responses.
+func NewSuccessResponse(result interface{}) Response {
+	return Response{
+		Success:  true,
+		Result:   result,
+		Errors:   []ResponseMessage{},
+		Messages: []ResponseMessage{},
+	}
+}
+
+// NewSuccessResponseWithMessage is a shortcut for creating new successul API
+// responses that includes a message.
+func NewSuccessResponseWithMessage(result interface{}, message string, code int) Response {
+	return Response{
+		Success:  true,
+		Result:   result,
+		Errors:   []ResponseMessage{},
+		Messages: []ResponseMessage{{code, message}},
+	}
+}
+
+// NewErrorResponse is a shortcut for creating an error response for a
+// single error.
+func NewErrorResponse(message string, code int) Response {
+	return Response{
+		Success:  false,
+		Result:   nil,
+		Errors:   []ResponseMessage{{code, message}},
+		Messages: []ResponseMessage{},
+	}
+}
+
+// SendResponse builds a response from the result, sets the JSON
+// header, and writes to the http.ResponseWriter.
+func SendResponse(w http.ResponseWriter, result interface{}) error {
+	response := NewSuccessResponse(result)
+	w.Header().Set("Content-Type", "application/json")
+	enc := json.NewEncoder(w)
+	err := enc.Encode(response)
+	return err
+}
+
+// SendResponseWithMessage builds a response from the result and the
+// provided message, sets the JSON header, and writes to the
+// http.ResponseWriter.
+func SendResponseWithMessage(w http.ResponseWriter, result interface{}, message string, code int) error {
+	response := NewSuccessResponseWithMessage(result, message, code)
+	w.Header().Set("Content-Type", "application/json")
+	enc := json.NewEncoder(w)
+	err := enc.Encode(response)
+	return err
+}

+ 22 - 9
vendor/src/github.com/cloudflare/cfssl/certdb/README.md

@@ -16,21 +16,26 @@ A database is required for the following:
 
 
 This directory stores [goose](https://bitbucket.org/liamstask/goose/) db migration scripts for various DB backends.
 This directory stores [goose](https://bitbucket.org/liamstask/goose/) db migration scripts for various DB backends.
 Currently supported:
 Currently supported:
- - SQLite in sqlite
+ - MySQL in mysql
  - PostgreSQL in pg
  - PostgreSQL in pg
+ - SQLite in sqlite
 
 
 ### Get goose
 ### Get goose
 
 
-    go get https://bitbucket.org/liamstask/goose/
+    go get bitbucket.org/liamstask/goose/cmd/goose
 
 
-### Use goose to start and terminate a SQLite DB
-To start a SQLite DB using goose:
+### Use goose to start and terminate a MySQL DB
+To start a MySQL using goose:
 
 
-    goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite up'
+    goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql up
 
 
-To tear down a SQLite DB using goose
+To tear down a MySQL DB using goose
 
 
-    goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite down
+    goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql down
+
+Note: the administration of MySQL DB is not included. We assume
+the databases being connected to are already created and access control
+is properly handled.
 
 
 ### Use goose to start and terminate a PostgreSQL DB
 ### Use goose to start and terminate a PostgreSQL DB
 To start a PostgreSQL using goose:
 To start a PostgreSQL using goose:
@@ -43,7 +48,16 @@ To tear down a PostgreSQL DB using goose
 
 
 Note: the administration of PostgreSQL DB is not included. We assume
 Note: the administration of PostgreSQL DB is not included. We assume
 the databases being connected to are already created and access control
 the databases being connected to are already created and access control
-are properly handled.
+is properly handled.
+
+### Use goose to start and terminate a SQLite DB
+To start a SQLite DB using goose:
+
+    goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite up
+
+To tear down a SQLite DB using goose
+
+    goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite down
 
 
 ## CFSSL Configuration
 ## CFSSL Configuration
 
 
@@ -55,4 +69,3 @@ JSON dictionary:
 or
 or
 
 
     {"driver":"postgres","data_source":"postgres://user:password@host/db"}
     {"driver":"postgres","data_source":"postgres://user:password@host/db"}
-

+ 44 - 27
vendor/src/github.com/cloudflare/cfssl/csr/csr.go

@@ -9,6 +9,7 @@ import (
 	"crypto/rsa"
 	"crypto/rsa"
 	"crypto/x509"
 	"crypto/x509"
 	"crypto/x509/pkix"
 	"crypto/x509/pkix"
+	"encoding/asn1"
 	"encoding/pem"
 	"encoding/pem"
 	"errors"
 	"errors"
 	"net"
 	"net"
@@ -129,8 +130,9 @@ func (kr *BasicKeyRequest) SigAlgo() x509.SignatureAlgorithm {
 
 
 // CAConfig is a section used in the requests initialising a new CA.
 // CAConfig is a section used in the requests initialising a new CA.
 type CAConfig struct {
 type CAConfig struct {
-	PathLength int    `json:"pathlen"`
-	Expiry     string `json:"expiry"`
+	PathLength  int    `json:"pathlen"`
+	PathLenZero bool   `json:"pathlenzero"`
+	Expiry      string `json:"expiry"`
 }
 }
 
 
 // A CertificateRequest encapsulates the API interface to the
 // A CertificateRequest encapsulates the API interface to the
@@ -175,6 +177,12 @@ func (cr *CertificateRequest) Name() pkix.Name {
 	return name
 	return name
 }
 }
 
 
+// BasicConstraints CSR information RFC 5280, 4.2.1.9
+type BasicConstraints struct {
+	IsCA       bool `asn1:"optional"`
+	MaxPathLen int  `asn1:"optional,default:-1"`
+}
+
 // ParseRequest takes a certificate request and generates a key and
 // ParseRequest takes a certificate request and generates a key and
 // CSR from it. It does no validation -- caveat emptor. It will,
 // CSR from it. It does no validation -- caveat emptor. It will,
 // however, fail if the key request is not valid (i.e., an unsupported
 // 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) {
 		panic("Generate should have failed to produce a valid key.")
 		panic("Generate should have failed to produce a valid key.")
 	}
 	}
 
 
-	var tpl = x509.CertificateRequest{
-		Subject:            req.Name(),
-		SignatureAlgorithm: req.KeyRequest.SigAlgo(),
-	}
-
-	for i := range req.Hosts {
-		if ip := net.ParseIP(req.Hosts[i]); ip != nil {
-			tpl.IPAddresses = append(tpl.IPAddresses, ip)
-		} else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil {
-			tpl.EmailAddresses = append(tpl.EmailAddresses, req.Hosts[i])
-		} else {
-			tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
-		}
-	}
-
-	csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
+	csr, err = Generate(priv.(crypto.Signer), req)
 	if err != nil {
 	if err != nil {
 		log.Errorf("failed to generate a CSR: %v", err)
 		log.Errorf("failed to generate a CSR: %v", err)
 		err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
 		err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
-		return
-	}
-	block := pem.Block{
-		Type:  "CERTIFICATE REQUEST",
-		Bytes: csr,
 	}
 	}
-
-	log.Info("encoded CSR")
-	csr = pem.EncodeToMemory(&block)
 	return
 	return
 }
 }
 
 
@@ -265,6 +250,7 @@ func ExtractCertificateRequest(cert *x509.Certificate) *CertificateRequest {
 		// issue date and expiry date.
 		// issue date and expiry date.
 		req.CA.Expiry = cert.NotAfter.Sub(cert.NotBefore).String()
 		req.CA.Expiry = cert.NotAfter.Sub(cert.NotBefore).String()
 		req.CA.PathLength = cert.MaxPathLen
 		req.CA.PathLength = cert.MaxPathLen
+		req.CA.PathLenZero = cert.MaxPathLenZero
 	}
 	}
 
 
 	return req
 	return req
@@ -377,7 +363,7 @@ func Regenerate(priv crypto.Signer, csr []byte) ([]byte, error) {
 // Generate creates a new CSR from a CertificateRequest structure and
 // Generate creates a new CSR from a CertificateRequest structure and
 // an existing key. The KeyRequest field is ignored.
 // an existing key. The KeyRequest field is ignored.
 func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) {
 func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) {
-	sigAlgo := helpers.SignerAlgo(priv, crypto.SHA256)
+	sigAlgo := helpers.SignerAlgo(priv)
 	if sigAlgo == x509.UnknownSignatureAlgorithm {
 	if sigAlgo == x509.UnknownSignatureAlgorithm {
 		return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
 		return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
 	}
 	}
@@ -397,6 +383,14 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro
 		}
 		}
 	}
 	}
 
 
+	if req.CA != nil {
+		err = appendCAInfoToCSR(req.CA, &tpl)
+		if err != nil {
+			err = cferr.Wrap(cferr.CSRError, cferr.GenerationFailed, err)
+			return
+		}
+	}
+
 	csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
 	csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
 	if err != nil {
 	if err != nil {
 		log.Errorf("failed to generate a CSR: %v", err)
 		log.Errorf("failed to generate a CSR: %v", err)
@@ -412,3 +406,26 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro
 	csr = pem.EncodeToMemory(&block)
 	csr = pem.EncodeToMemory(&block)
 	return
 	return
 }
 }
+
+// appendCAInfoToCSR appends CAConfig BasicConstraint extension to a CSR
+func appendCAInfoToCSR(reqConf *CAConfig, csr *x509.CertificateRequest) error {
+	pathlen := reqConf.PathLength
+	if pathlen == 0 && !reqConf.PathLenZero {
+		pathlen = -1
+	}
+	val, err := asn1.Marshal(BasicConstraints{true, pathlen})
+
+	if err != nil {
+		return err
+	}
+
+	csr.ExtraExtensions = []pkix.Extension{
+		{
+			Id:       asn1.ObjectIdentifier{2, 5, 29, 19},
+			Value:    val,
+			Critical: true,
+		},
+	}
+
+	return nil
+}

+ 14 - 13
vendor/src/github.com/cloudflare/cfssl/helpers/helpers.go

@@ -6,6 +6,7 @@ import (
 	"bytes"
 	"bytes"
 	"crypto"
 	"crypto"
 	"crypto/ecdsa"
 	"crypto/ecdsa"
+	"crypto/elliptic"
 	"crypto/rsa"
 	"crypto/rsa"
 	"crypto/x509"
 	"crypto/x509"
 	"encoding/asn1"
 	"encoding/asn1"
@@ -410,7 +411,7 @@ func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error)
 	in = bytes.TrimSpace(in)
 	in = bytes.TrimSpace(in)
 	p, rest := pem.Decode(in)
 	p, rest := pem.Decode(in)
 	if p != nil {
 	if p != nil {
-		if p.Type != "CERTIFICATE REQUEST" {
+		if p.Type != "NEW CERTIFICATE REQUEST" && p.Type != "CERTIFICATE REQUEST" {
 			return nil, rest, cferr.New(cferr.CSRError, cferr.BadRequest)
 			return nil, rest, cferr.New(cferr.CSRError, cferr.BadRequest)
 		}
 		}
 
 
@@ -446,28 +447,28 @@ func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) {
 	return csrObject, nil
 	return csrObject, nil
 }
 }
 
 
-// SignerAlgo returns an X.509 signature algorithm corresponding to
-// the crypto.Hash provided from a crypto.Signer.
-func SignerAlgo(priv crypto.Signer, h crypto.Hash) x509.SignatureAlgorithm {
-	switch priv.Public().(type) {
+// SignerAlgo returns an X.509 signature algorithm from a crypto.Signer.
+func SignerAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
+	switch pub := priv.Public().(type) {
 	case *rsa.PublicKey:
 	case *rsa.PublicKey:
-		switch h {
-		case crypto.SHA512:
+		bitLength := pub.N.BitLen()
+		switch {
+		case bitLength >= 4096:
 			return x509.SHA512WithRSA
 			return x509.SHA512WithRSA
-		case crypto.SHA384:
+		case bitLength >= 3072:
 			return x509.SHA384WithRSA
 			return x509.SHA384WithRSA
-		case crypto.SHA256:
+		case bitLength >= 2048:
 			return x509.SHA256WithRSA
 			return x509.SHA256WithRSA
 		default:
 		default:
 			return x509.SHA1WithRSA
 			return x509.SHA1WithRSA
 		}
 		}
 	case *ecdsa.PublicKey:
 	case *ecdsa.PublicKey:
-		switch h {
-		case crypto.SHA512:
+		switch pub.Curve {
+		case elliptic.P521():
 			return x509.ECDSAWithSHA512
 			return x509.ECDSAWithSHA512
-		case crypto.SHA384:
+		case elliptic.P384():
 			return x509.ECDSAWithSHA384
 			return x509.ECDSAWithSHA384
-		case crypto.SHA256:
+		case elliptic.P256():
 			return x509.ECDSAWithSHA256
 			return x509.ECDSAWithSHA256
 		default:
 		default:
 			return x509.ECDSAWithSHA1
 			return x509.ECDSAWithSHA1

+ 28 - 83
vendor/src/github.com/cloudflare/cfssl/initca/initca.go

@@ -5,14 +5,10 @@ package initca
 import (
 import (
 	"crypto"
 	"crypto"
 	"crypto/ecdsa"
 	"crypto/ecdsa"
-	"crypto/elliptic"
-	"crypto/rand"
 	"crypto/rsa"
 	"crypto/rsa"
 	"crypto/x509"
 	"crypto/x509"
-	"encoding/pem"
 	"errors"
 	"errors"
 	"io/ioutil"
 	"io/ioutil"
-	"net"
 	"time"
 	"time"
 
 
 	"github.com/cloudflare/cfssl/config"
 	"github.com/cloudflare/cfssl/config"
@@ -47,14 +43,18 @@ func validator(req *csr.CertificateRequest) error {
 
 
 // New creates a new root certificate from the certificate request.
 // New creates a new root certificate from the certificate request.
 func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
 func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
+	policy := CAPolicy()
 	if req.CA != nil {
 	if req.CA != nil {
 		if req.CA.Expiry != "" {
 		if req.CA.Expiry != "" {
-			CAPolicy.Default.ExpiryString = req.CA.Expiry
-			CAPolicy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
+			policy.Default.ExpiryString = req.CA.Expiry
+			policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
 		}
 		}
 
 
-		if req.CA.PathLength != 0 {
-			signer.MaxPathLen = req.CA.PathLength
+		signer.MaxPathLen = req.CA.PathLength
+		if req.CA.PathLength != 0 && req.CA.PathLenZero == true {
+			log.Infof("ignore invalid 'pathlenzero' value")
+		} else {
+			signer.MaxPathLenZero = req.CA.PathLenZero
 		}
 		}
 	}
 	}
 
 
@@ -77,7 +77,7 @@ func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
 		log.Errorf("failed to create signer: %v", err)
 		log.Errorf("failed to create signer: %v", err)
 		return
 		return
 	}
 	}
-	s.SetPolicy(CAPolicy)
+	s.SetPolicy(policy)
 
 
 	signReq := signer.SignRequest{Hosts: req.Hosts, Request: string(csrPEM)}
 	signReq := signer.SignRequest{Hosts: req.Hosts, Request: string(csrPEM)}
 	cert, err = s.Sign(signReq)
 	cert, err = s.Sign(signReq)
@@ -133,92 +133,35 @@ func RenewFromPEM(caFile, keyFile string) ([]byte, error) {
 
 
 // NewFromSigner creates a new root certificate from a crypto.Signer.
 // NewFromSigner creates a new root certificate from a crypto.Signer.
 func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) {
 func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) {
+	policy := CAPolicy()
 	if req.CA != nil {
 	if req.CA != nil {
 		if req.CA.Expiry != "" {
 		if req.CA.Expiry != "" {
-			CAPolicy.Default.ExpiryString = req.CA.Expiry
-			CAPolicy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
+			policy.Default.ExpiryString = req.CA.Expiry
+			policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
 			if err != nil {
 			if err != nil {
 				return nil, nil, err
 				return nil, nil, err
 			}
 			}
 		}
 		}
 
 
-		if req.CA.PathLength != 0 {
-			signer.MaxPathLen = req.CA.PathLength
-		}
-	}
-
-	var sigAlgo x509.SignatureAlgorithm
-	switch pub := priv.Public().(type) {
-	case *rsa.PublicKey:
-		bitLength := pub.N.BitLen()
-		switch {
-		case bitLength >= 4096:
-			sigAlgo = x509.SHA512WithRSA
-		case bitLength >= 3072:
-			sigAlgo = x509.SHA384WithRSA
-		case bitLength >= 2048:
-			sigAlgo = x509.SHA256WithRSA
-		default:
-			sigAlgo = x509.SHA1WithRSA
-		}
-	case *ecdsa.PublicKey:
-		switch pub.Curve {
-		case elliptic.P521():
-			sigAlgo = x509.ECDSAWithSHA512
-		case elliptic.P384():
-			sigAlgo = x509.ECDSAWithSHA384
-		case elliptic.P256():
-			sigAlgo = x509.ECDSAWithSHA256
-		default:
-			sigAlgo = x509.ECDSAWithSHA1
-		}
-	default:
-		sigAlgo = x509.UnknownSignatureAlgorithm
-	}
-
-	var tpl = x509.CertificateRequest{
-		Subject:            req.Name(),
-		SignatureAlgorithm: sigAlgo,
-	}
-
-	for i := range req.Hosts {
-		if ip := net.ParseIP(req.Hosts[i]); ip != nil {
-			tpl.IPAddresses = append(tpl.IPAddresses, ip)
+		signer.MaxPathLen = req.CA.PathLength
+		if req.CA.PathLength != 0 && req.CA.PathLenZero == true {
+			log.Infof("ignore invalid 'pathlenzero' value")
 		} else {
 		} else {
-			tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
+			signer.MaxPathLenZero = req.CA.PathLenZero
 		}
 		}
 	}
 	}
 
 
-	return signWithCSR(&tpl, priv)
-}
-
-// signWithCSR creates a new root certificate from signing a X509.CertificateRequest
-// by a crypto.Signer.
-func signWithCSR(tpl *x509.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) {
-	csrPEM, err = x509.CreateCertificateRequest(rand.Reader, tpl, priv)
+	csrPEM, err = csr.Generate(priv, req)
 	if err != nil {
 	if err != nil {
-		log.Errorf("failed to generate a CSR: %v", err)
-		// The use of CertificateError was a matter of some
-		// debate; it is the one edge case in which a new
-		// error category specifically for CSRs might be
-		// useful, but it was deemed that one edge case did
-		// not a new category justify.
-		err = cferr.Wrap(cferr.CertificateError, cferr.BadRequest, err)
-		return
-	}
-
-	p := &pem.Block{
-		Type:  "CERTIFICATE REQUEST",
-		Bytes: csrPEM,
+		return nil, nil, err
 	}
 	}
-	csrPEM = pem.EncodeToMemory(p)
 
 
 	s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), nil)
 	s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), nil)
 	if err != nil {
 	if err != nil {
 		log.Errorf("failed to create signer: %v", err)
 		log.Errorf("failed to create signer: %v", err)
 		return
 		return
 	}
 	}
-	s.SetPolicy(CAPolicy)
+	s.SetPolicy(policy)
 
 
 	signReq := signer.SignRequest{Request: string(csrPEM)}
 	signReq := signer.SignRequest{Request: string(csrPEM)}
 	cert, err = s.Sign(signReq)
 	cert, err = s.Sign(signReq)
@@ -268,11 +211,13 @@ func RenewFromSigner(ca *x509.Certificate, priv crypto.Signer) ([]byte, error) {
 }
 }
 
 
 // CAPolicy contains the CA issuing policy as default policy.
 // CAPolicy contains the CA issuing policy as default policy.
-var CAPolicy = &config.Signing{
-	Default: &config.SigningProfile{
-		Usage:        []string{"cert sign", "crl sign"},
-		ExpiryString: "43800h",
-		Expiry:       5 * helpers.OneYear,
-		CA:           true,
-	},
+var CAPolicy = func() *config.Signing {
+	return &config.Signing{
+		Default: &config.SigningProfile{
+			Usage:        []string{"cert sign", "crl sign"},
+			ExpiryString: "43800h",
+			Expiry:       5 * helpers.OneYear,
+			CA:           true,
+		},
+	}
 }
 }

+ 12 - 16
vendor/src/github.com/cloudflare/cfssl/log/log.go

@@ -45,12 +45,12 @@ var Level = LevelInfo
 //
 //
 // SyslogWriter is satisfied by *syslog.Writer.
 // SyslogWriter is satisfied by *syslog.Writer.
 type SyslogWriter interface {
 type SyslogWriter interface {
-	Debug(string) error
-	Info(string) error
-	Warning(string) error
-	Err(string) error
-	Crit(string) error
-	Emerg(string) error
+	Debug(string)
+	Info(string)
+	Warning(string)
+	Err(string)
+	Crit(string)
+	Emerg(string)
 }
 }
 
 
 // syslogWriter stores the SetLogger() parameter.
 // syslogWriter stores the SetLogger() parameter.
@@ -73,23 +73,19 @@ func init() {
 func print(l int, msg string) {
 func print(l int, msg string) {
 	if l >= Level {
 	if l >= Level {
 		if syslogWriter != nil {
 		if syslogWriter != nil {
-			var err error
 			switch l {
 			switch l {
 			case LevelDebug:
 			case LevelDebug:
-				err = syslogWriter.Debug(msg)
+				syslogWriter.Debug(msg)
 			case LevelInfo:
 			case LevelInfo:
-				err = syslogWriter.Info(msg)
+				syslogWriter.Info(msg)
 			case LevelWarning:
 			case LevelWarning:
-				err = syslogWriter.Warning(msg)
+				syslogWriter.Warning(msg)
 			case LevelError:
 			case LevelError:
-				err = syslogWriter.Err(msg)
+				syslogWriter.Err(msg)
 			case LevelCritical:
 			case LevelCritical:
-				err = syslogWriter.Crit(msg)
+				syslogWriter.Crit(msg)
 			case LevelFatal:
 			case LevelFatal:
-				err = syslogWriter.Emerg(msg)
-			}
-			if err != nil {
-				log.Printf("Unable to write syslog: %v for msg: %s\n", err, msg)
+				syslogWriter.Emerg(msg)
 			}
 			}
 		} else {
 		} else {
 			log.Printf("[%s] %s", levelPrefix[l], msg)
 			log.Printf("[%s] %s", levelPrefix[l], msg)

+ 25 - 3
vendor/src/github.com/cloudflare/cfssl/signer/local/local.go

@@ -96,7 +96,11 @@ func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signe
 }
 }
 
 
 func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile) (cert []byte, err error) {
 func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile) (cert []byte, err error) {
+	var distPoints = template.CRLDistributionPoints
 	err = signer.FillTemplate(template, s.policy.Default, profile)
 	err = signer.FillTemplate(template, s.policy.Default, profile)
+	if distPoints != nil && len(distPoints) > 0 {
+		template.CRLDistributionPoints = distPoints
+	}
 	if err != nil {
 	if err != nil {
 		return
 		return
 	}
 	}
@@ -111,9 +115,7 @@ func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile
 		template.EmailAddresses = nil
 		template.EmailAddresses = nil
 		s.ca = template
 		s.ca = template
 		initRoot = true
 		initRoot = true
-		template.MaxPathLen = signer.MaxPathLen
 	} else if template.IsCA {
 	} else if template.IsCA {
-		template.MaxPathLen = 1
 		template.DNSNames = nil
 		template.DNSNames = nil
 		template.EmailAddresses = nil
 		template.EmailAddresses = nil
 	}
 	}
@@ -203,7 +205,7 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
 		return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed)
 		return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed)
 	}
 	}
 
 
-	if block.Type != "CERTIFICATE REQUEST" {
+	if block.Type != "NEW CERTIFICATE REQUEST" && block.Type != "CERTIFICATE REQUEST" {
 		return nil, cferr.Wrap(cferr.CSRError,
 		return nil, cferr.Wrap(cferr.CSRError,
 			cferr.BadRequest, errors.New("not a certificate or csr"))
 			cferr.BadRequest, errors.New("not a certificate or csr"))
 	}
 	}
@@ -243,6 +245,26 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
 		}
 		}
 	}
 	}
 
 
+	if req.CRLOverride != "" {
+		safeTemplate.CRLDistributionPoints = []string{req.CRLOverride}
+	}
+
+	if safeTemplate.IsCA {
+		if !profile.CA {
+			return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest)
+		}
+
+		if s.ca != nil && s.ca.MaxPathLen > 0 {
+			if safeTemplate.MaxPathLen >= s.ca.MaxPathLen {
+				// do not sign a cert with pathlen > current
+				return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest)
+			}
+		} else if s.ca != nil && s.ca.MaxPathLen == 0 && s.ca.MaxPathLenZero {
+			// signer has pathlen of 0, do not sign more intermediate CAs
+			return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest)
+		}
+	}
+
 	OverrideHosts(&safeTemplate, req.Hosts)
 	OverrideHosts(&safeTemplate, req.Hosts)
 	safeTemplate.Subject = PopulateSubjectFromCSR(req.Subject, safeTemplate.Subject)
 	safeTemplate.Subject = PopulateSubjectFromCSR(req.Subject, safeTemplate.Subject)
 
 

+ 43 - 18
vendor/src/github.com/cloudflare/cfssl/signer/signer.go

@@ -26,6 +26,9 @@ import (
 // MaxPathLen is the default path length for a new CA certificate.
 // MaxPathLen is the default path length for a new CA certificate.
 var MaxPathLen = 2
 var MaxPathLen = 2
 
 
+// MaxPathLenZero indicates whether a new CA certificate has pathlen=0
+var MaxPathLenZero = false
+
 // Subject contains the information that should be used to override the
 // Subject contains the information that should be used to override the
 // subject information when signing a certificate.
 // subject information when signing a certificate.
 type Subject struct {
 type Subject struct {
@@ -50,13 +53,14 @@ type Extension struct {
 // Extensions requested in the CSR are ignored, except for those processed by
 // Extensions requested in the CSR are ignored, except for those processed by
 // ParseCertificateRequest (mainly subjectAltName).
 // ParseCertificateRequest (mainly subjectAltName).
 type SignRequest struct {
 type SignRequest struct {
-	Hosts      []string    `json:"hosts"`
-	Request    string      `json:"certificate_request"`
-	Subject    *Subject    `json:"subject,omitempty"`
-	Profile    string      `json:"profile"`
-	Label      string      `json:"label"`
-	Serial     *big.Int    `json:"serial,omitempty"`
-	Extensions []Extension `json:"extensions,omitempty"`
+	Hosts       []string    `json:"hosts"`
+	Request     string      `json:"certificate_request"`
+	Subject     *Subject    `json:"subject,omitempty"`
+	Profile     string      `json:"profile"`
+	CRLOverride string      `json:"crl_override"`
+	Label       string      `json:"label"`
+	Serial      *big.Int    `json:"serial,omitempty"`
+	Extensions  []Extension `json:"extensions,omitempty"`
 }
 }
 
 
 // appendIf appends to a if s is not an empty string.
 // appendIf appends to a if s is not an empty string.
@@ -157,26 +161,46 @@ func DefaultSigAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
 // ParseCertificateRequest takes an incoming certificate request and
 // ParseCertificateRequest takes an incoming certificate request and
 // builds a certificate template from it.
 // builds a certificate template from it.
 func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certificate, err error) {
 func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certificate, err error) {
-	csr, err := x509.ParseCertificateRequest(csrBytes)
+	csrv, err := x509.ParseCertificateRequest(csrBytes)
 	if err != nil {
 	if err != nil {
 		err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
 		err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
 		return
 		return
 	}
 	}
 
 
-	err = helpers.CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature)
+	err = helpers.CheckSignature(csrv, csrv.SignatureAlgorithm, csrv.RawTBSCertificateRequest, csrv.Signature)
 	if err != nil {
 	if err != nil {
 		err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
 		err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
 		return
 		return
 	}
 	}
 
 
 	template = &x509.Certificate{
 	template = &x509.Certificate{
-		Subject:            csr.Subject,
-		PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
-		PublicKey:          csr.PublicKey,
+		Subject:            csrv.Subject,
+		PublicKeyAlgorithm: csrv.PublicKeyAlgorithm,
+		PublicKey:          csrv.PublicKey,
 		SignatureAlgorithm: s.SigAlgo(),
 		SignatureAlgorithm: s.SigAlgo(),
-		DNSNames:           csr.DNSNames,
-		IPAddresses:        csr.IPAddresses,
-		EmailAddresses:     csr.EmailAddresses,
+		DNSNames:           csrv.DNSNames,
+		IPAddresses:        csrv.IPAddresses,
+		EmailAddresses:     csrv.EmailAddresses,
+	}
+
+	for _, val := range csrv.Extensions {
+		// Check the CSR for the X.509 BasicConstraints (RFC 5280, 4.2.1.9)
+		// extension and append to template if necessary
+		if val.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) {
+			var constraints csr.BasicConstraints
+			var rest []byte
+
+			if rest, err = asn1.Unmarshal(val.Value, &constraints); err != nil {
+				return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
+			} else if len(rest) != 0 {
+				return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, errors.New("x509: trailing data after X.509 BasicConstraints"))
+			}
+
+			template.BasicConstraintsValid = true
+			template.IsCA = constraints.IsCA
+			template.MaxPathLen = constraints.MaxPathLen
+			template.MaxPathLenZero = template.MaxPathLen == 0
+		}
 	}
 	}
 
 
 	return
 	return
@@ -222,6 +246,7 @@ func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.Si
 		notBefore       time.Time
 		notBefore       time.Time
 		notAfter        time.Time
 		notAfter        time.Time
 		crlURL, ocspURL string
 		crlURL, ocspURL string
+		issuerURL       = profile.IssuerURL
 	)
 	)
 
 
 	// The third value returned from Usages is a list of unknown key usages.
 	// 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
 	// here.
 	// here.
 	ku, eku, _ = profile.Usages()
 	ku, eku, _ = profile.Usages()
 	if profile.IssuerURL == nil {
 	if profile.IssuerURL == nil {
-		profile.IssuerURL = defaultProfile.IssuerURL
+		issuerURL = defaultProfile.IssuerURL
 	}
 	}
 
 
 	if ku == 0 && len(eku) == 0 {
 	if ku == 0 && len(eku) == 0 {
@@ -279,8 +304,8 @@ func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.Si
 		template.CRLDistributionPoints = []string{crlURL}
 		template.CRLDistributionPoints = []string{crlURL}
 	}
 	}
 
 
-	if len(profile.IssuerURL) != 0 {
-		template.IssuingCertificateURL = profile.IssuerURL
+	if len(issuerURL) != 0 {
+		template.IssuingCertificateURL = issuerURL
 	}
 	}
 	if len(profile.Policies) != 0 {
 	if len(profile.Policies) != 0 {
 		err = addPolicies(template, profile.Policies)
 		err = addPolicies(template, profile.Policies)

+ 1 - 1
vendor/src/github.com/docker/engine-api/client/container_inspect.go

@@ -27,7 +27,7 @@ func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (ty
 	return response, err
 	return response, err
 }
 }
 
 
-// ContainerInspectWithRaw returns the container information and it's raw representation.
+// ContainerInspectWithRaw returns the container information and its raw representation.
 func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID string, getSize bool) (types.ContainerJSON, []byte, error) {
 func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID string, getSize bool) (types.ContainerJSON, []byte, error) {
 	query := url.Values{}
 	query := url.Values{}
 	if getSize {
 	if getSize {

+ 15 - 0
vendor/src/github.com/docker/engine-api/client/errors.go

@@ -131,6 +131,11 @@ func (e nodeNotFoundError) Error() string {
 	return fmt.Sprintf("Error: No such node: %s", e.nodeID)
 	return fmt.Sprintf("Error: No such node: %s", e.nodeID)
 }
 }
 
 
+// NoFound indicates that this error type is of NotFound
+func (e nodeNotFoundError) NotFound() bool {
+	return true
+}
+
 // IsErrNodeNotFound returns true if the error is caused
 // IsErrNodeNotFound returns true if the error is caused
 // when a node is not found.
 // when a node is not found.
 func IsErrNodeNotFound(err error) bool {
 func IsErrNodeNotFound(err error) bool {
@@ -148,6 +153,11 @@ func (e serviceNotFoundError) Error() string {
 	return fmt.Sprintf("Error: No such service: %s", e.serviceID)
 	return fmt.Sprintf("Error: No such service: %s", e.serviceID)
 }
 }
 
 
+// NoFound indicates that this error type is of NotFound
+func (e serviceNotFoundError) NotFound() bool {
+	return true
+}
+
 // IsErrServiceNotFound returns true if the error is caused
 // IsErrServiceNotFound returns true if the error is caused
 // when a service is not found.
 // when a service is not found.
 func IsErrServiceNotFound(err error) bool {
 func IsErrServiceNotFound(err error) bool {
@@ -165,6 +175,11 @@ func (e taskNotFoundError) Error() string {
 	return fmt.Sprintf("Error: No such task: %s", e.taskID)
 	return fmt.Sprintf("Error: No such task: %s", e.taskID)
 }
 }
 
 
+// NoFound indicates that this error type is of NotFound
+func (e taskNotFoundError) NotFound() bool {
+	return true
+}
+
 // IsErrTaskNotFound returns true if the error is caused
 // IsErrTaskNotFound returns true if the error is caused
 // when a task is not found.
 // when a task is not found.
 func IsErrTaskNotFound(err error) bool {
 func IsErrTaskNotFound(err error) bool {

+ 1 - 1
vendor/src/github.com/docker/engine-api/client/interface.go

@@ -92,7 +92,7 @@ type NetworkAPIClient interface {
 
 
 // NodeAPIClient defines API client methods for the nodes
 // NodeAPIClient defines API client methods for the nodes
 type NodeAPIClient interface {
 type NodeAPIClient interface {
-	NodeInspect(ctx context.Context, nodeID string) (swarm.Node, error)
+	NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error)
 	NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error)
 	NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error)
 	NodeRemove(ctx context.Context, nodeID string) error
 	NodeRemove(ctx context.Context, nodeID string) error
 	NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error
 	NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error

+ 1 - 1
vendor/src/github.com/docker/engine-api/client/network_inspect.go

@@ -16,7 +16,7 @@ func (cli *Client) NetworkInspect(ctx context.Context, networkID string) (types.
 	return networkResource, err
 	return networkResource, err
 }
 }
 
 
-// NetworkInspectWithRaw returns the information for a specific network configured in the docker host and it's raw representation.
+// NetworkInspectWithRaw returns the information for a specific network configured in the docker host and its raw representation.
 func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string) (types.NetworkResource, []byte, error) {
 func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string) (types.NetworkResource, []byte, error) {
 	var networkResource types.NetworkResource
 	var networkResource types.NetworkResource
 	resp, err := cli.get(ctx, "/networks/"+networkID, nil, nil)
 	resp, err := cli.get(ctx, "/networks/"+networkID, nil, nil)

+ 15 - 7
vendor/src/github.com/docker/engine-api/client/node_inspect.go

@@ -1,25 +1,33 @@
 package client
 package client
 
 
 import (
 import (
+	"bytes"
 	"encoding/json"
 	"encoding/json"
+	"io/ioutil"
 	"net/http"
 	"net/http"
 
 
 	"github.com/docker/engine-api/types/swarm"
 	"github.com/docker/engine-api/types/swarm"
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 )
 )
 
 
-// NodeInspect returns the node information.
-func (cli *Client) NodeInspect(ctx context.Context, nodeID string) (swarm.Node, error) {
+// NodeInspectWithRaw returns the node information.
+func (cli *Client) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error) {
 	serverResp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil)
 	serverResp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil)
 	if err != nil {
 	if err != nil {
 		if serverResp.statusCode == http.StatusNotFound {
 		if serverResp.statusCode == http.StatusNotFound {
-			return swarm.Node{}, nodeNotFoundError{nodeID}
+			return swarm.Node{}, nil, nodeNotFoundError{nodeID}
 		}
 		}
-		return swarm.Node{}, err
+		return swarm.Node{}, nil, err
+	}
+	defer ensureReaderClosed(serverResp)
+
+	body, err := ioutil.ReadAll(serverResp.body)
+	if err != nil {
+		return swarm.Node{}, nil, err
 	}
 	}
 
 
 	var response swarm.Node
 	var response swarm.Node
-	err = json.NewDecoder(serverResp.body).Decode(&response)
-	ensureReaderClosed(serverResp)
-	return response, err
+	rdr := bytes.NewReader(body)
+	err = json.NewDecoder(rdr).Decode(&response)
+	return response, body, err
 }
 }

+ 1 - 0
vendor/src/github.com/docker/engine-api/client/plugin_install.go

@@ -31,6 +31,7 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
 	}
 	}
 	var privileges types.PluginPrivileges
 	var privileges types.PluginPrivileges
 	if err := json.NewDecoder(resp.body).Decode(&privileges); err != nil {
 	if err := json.NewDecoder(resp.body).Decode(&privileges); err != nil {
+		ensureReaderClosed(resp)
 		return err
 		return err
 	}
 	}
 	ensureReaderClosed(resp)
 	ensureReaderClosed(resp)

+ 1 - 1
vendor/src/github.com/docker/engine-api/client/volume_inspect.go

@@ -16,7 +16,7 @@ func (cli *Client) VolumeInspect(ctx context.Context, volumeID string) (types.Vo
 	return volume, err
 	return volume, err
 }
 }
 
 
-// VolumeInspectWithRaw returns the information about a specific volume in the docker host and it's raw representation
+// VolumeInspectWithRaw returns the information about a specific volume in the docker host and its raw representation
 func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (types.Volume, []byte, error) {
 func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (types.Volume, []byte, error) {
 	var volume types.Volume
 	var volume types.Volume
 	resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil)
 	resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil)

+ 1 - 1
vendor/src/github.com/docker/engine-api/types/swarm/container.go

@@ -54,7 +54,7 @@ const (
 	MountPropagationSlave MountPropagation = "slave"
 	MountPropagationSlave MountPropagation = "slave"
 )
 )
 
 
-// BindOptions define options specific to mounts of type "bind".
+// BindOptions defines options specific to mounts of type "bind".
 type BindOptions struct {
 type BindOptions struct {
 	Propagation MountPropagation `json:",omitempty"`
 	Propagation MountPropagation `json:",omitempty"`
 }
 }

+ 1 - 1
vendor/src/github.com/docker/engine-api/types/swarm/service.go

@@ -15,7 +15,7 @@ type ServiceSpec struct {
 	Annotations
 	Annotations
 
 
 	// TaskTemplate defines how the service should construct new tasks when
 	// TaskTemplate defines how the service should construct new tasks when
-	// ochestrating this service.
+	// orchestrating this service.
 	TaskTemplate TaskSpec                  `json:",omitempty"`
 	TaskTemplate TaskSpec                  `json:",omitempty"`
 	Mode         ServiceMode               `json:",omitempty"`
 	Mode         ServiceMode               `json:",omitempty"`
 	UpdateConfig *UpdateConfig             `json:",omitempty"`
 	UpdateConfig *UpdateConfig             `json:",omitempty"`

+ 15 - 1
vendor/src/github.com/docker/engine-api/types/swarm/swarm.go

@@ -32,7 +32,7 @@ type Policy struct {
 	Secret     *string `json:",omitempty"`
 	Secret     *string `json:",omitempty"`
 }
 }
 
 
-// OrchestrationConfig represents ochestration configuration.
+// OrchestrationConfig represents orchestration configuration.
 type OrchestrationConfig struct {
 type OrchestrationConfig struct {
 	TaskHistoryRetentionLimit int64 `json:",omitempty"`
 	TaskHistoryRetentionLimit int64 `json:",omitempty"`
 }
 }
@@ -54,6 +54,20 @@ type DispatcherConfig struct {
 // CAConfig represents CA configuration.
 // CAConfig represents CA configuration.
 type CAConfig struct {
 type CAConfig struct {
 	NodeCertExpiry time.Duration `json:",omitempty"`
 	NodeCertExpiry time.Duration `json:",omitempty"`
+	ExternalCAs    []*ExternalCA `json:",omitempty"`
+}
+
+// ExternalCAProtocol represents type of external CA.
+type ExternalCAProtocol string
+
+// ExternalCAProtocolCFSSL CFSSL
+const ExternalCAProtocolCFSSL ExternalCAProtocol = "cfssl"
+
+// ExternalCA defines external CA to be used by the cluster.
+type ExternalCA struct {
+	Protocol ExternalCAProtocol
+	URL      string
+	Options  map[string]string `json:",omitempty"`
 }
 }
 
 
 // InitRequest is the request used to init a swarm.
 // InitRequest is the request used to init a swarm.

+ 0 - 4
vendor/src/github.com/docker/engine-api/types/types.go

@@ -504,10 +504,6 @@ type Checkpoint struct {
 	Name string // Name is the name of the checkpoint
 	Name string // Name is the name of the checkpoint
 }
 }
 
 
-// DefaultRuntimeName is the reserved name/alias used to represent the
-// OCI runtime being shipped with the docker daemon package.
-var DefaultRuntimeName = "default"
-
 // Runtime describes an OCI runtime
 // Runtime describes an OCI runtime
 type Runtime struct {
 type Runtime struct {
 	Path string   `json:"path"`
 	Path string   `json:"path"`

+ 10 - 10
vendor/src/github.com/docker/libnetwork/agent.go

@@ -102,7 +102,7 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error {
 				deleted = cKey.Key
 				deleted = cKey.Key
 			}
 			}
 
 
-			if cKey.Subsystem == subsysGossip /* subsysIPSec */ {
+			if cKey.Subsystem == subsysIPSec {
 				drvEnc.Prune = cKey.Key
 				drvEnc.Prune = cKey.Key
 				drvEnc.PruneTag = cKey.LamportTime
 				drvEnc.PruneTag = cKey.LamportTime
 			}
 			}
@@ -128,7 +128,7 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error {
 				a.networkDB.SetKey(key.Key)
 				a.networkDB.SetKey(key.Key)
 			}
 			}
 
 
-			if key.Subsystem == subsysGossip /*subsysIPSec*/ {
+			if key.Subsystem == subsysIPSec {
 				drvEnc.Key = key.Key
 				drvEnc.Key = key.Key
 				drvEnc.Tag = key.LamportTime
 				drvEnc.Tag = key.LamportTime
 			}
 			}
@@ -138,7 +138,7 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error {
 	key, tag := c.getPrimaryKeyTag(subsysGossip)
 	key, tag := c.getPrimaryKeyTag(subsysGossip)
 	a.networkDB.SetPrimaryKey(key)
 	a.networkDB.SetPrimaryKey(key)
 
 
-	//key, tag = c.getPrimaryKeyTag(subsysIPSec)
+	key, tag = c.getPrimaryKeyTag(subsysIPSec)
 	drvEnc.Primary = key
 	drvEnc.Primary = key
 	drvEnc.PrimaryTag = tag
 	drvEnc.PrimaryTag = tag
 
 
@@ -317,17 +317,12 @@ func (c *controller) agentInit(bindAddrOrInterface string) error {
 		return nil
 		return nil
 	}
 	}
 
 
-	drvEnc := discoverapi.DriverEncryptionConfig{}
-
-	keys, tags := c.getKeys(subsysGossip) // getKeys(subsysIPSec)
-	drvEnc.Keys = keys
-	drvEnc.Tags = tags
-
 	bindAddr, err := resolveAddr(bindAddrOrInterface)
 	bindAddr, err := resolveAddr(bindAddrOrInterface)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	keys, tags := c.getKeys(subsysGossip)
 	hostname, _ := os.Hostname()
 	hostname, _ := os.Hostname()
 	nDB, err := networkdb.New(&networkdb.Config{
 	nDB, err := networkdb.New(&networkdb.Config{
 		BindAddr: bindAddr,
 		BindAddr: bindAddr,
@@ -350,6 +345,11 @@ func (c *controller) agentInit(bindAddrOrInterface string) error {
 
 
 	go c.handleTableEvents(ch, c.handleEpTableEvent)
 	go c.handleTableEvents(ch, c.handleEpTableEvent)
 
 
+	drvEnc := discoverapi.DriverEncryptionConfig{}
+	keys, tags = c.getKeys(subsysIPSec)
+	drvEnc.Keys = keys
+	drvEnc.Tags = tags
+
 	c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool {
 	c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool {
 		err := driver.DiscoverNew(discoverapi.EncryptionKeysConfig, drvEnc)
 		err := driver.DiscoverNew(discoverapi.EncryptionKeysConfig, drvEnc)
 		if err != nil {
 		if err != nil {
@@ -380,7 +380,7 @@ func (c *controller) agentDriverNotify(d driverapi.Driver) {
 	})
 	})
 
 
 	drvEnc := discoverapi.DriverEncryptionConfig{}
 	drvEnc := discoverapi.DriverEncryptionConfig{}
-	keys, tags := c.getKeys(subsysGossip) // getKeys(subsysIPSec)
+	keys, tags := c.getKeys(subsysIPSec)
 	drvEnc.Keys = keys
 	drvEnc.Keys = keys
 	drvEnc.Tags = tags
 	drvEnc.Tags = tags
 
 

+ 2 - 2
vendor/src/github.com/docker/libnetwork/controller.go

@@ -144,7 +144,7 @@ type controller struct {
 	unWatchCh              chan *endpoint
 	unWatchCh              chan *endpoint
 	svcRecords             map[string]svcInfo
 	svcRecords             map[string]svcInfo
 	nmap                   map[string]*netWatch
 	nmap                   map[string]*netWatch
-	serviceBindings        map[string]*service
+	serviceBindings        map[serviceKey]*service
 	defOsSbox              osl.Sandbox
 	defOsSbox              osl.Sandbox
 	ingressSandbox         *sandbox
 	ingressSandbox         *sandbox
 	sboxOnce               sync.Once
 	sboxOnce               sync.Once
@@ -167,7 +167,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
 		cfg:             config.ParseConfigOptions(cfgOptions...),
 		cfg:             config.ParseConfigOptions(cfgOptions...),
 		sandboxes:       sandboxTable{},
 		sandboxes:       sandboxTable{},
 		svcRecords:      make(map[string]svcInfo),
 		svcRecords:      make(map[string]svcInfo),
-		serviceBindings: make(map[string]*service),
+		serviceBindings: make(map[serviceKey]*service),
 		agentInitDone:   make(chan struct{}),
 		agentInitDone:   make(chan struct{}),
 	}
 	}
 
 

+ 39 - 20
vendor/src/github.com/docker/libnetwork/datastore/datastore.go

@@ -54,11 +54,12 @@ var (
 )
 )
 
 
 type datastore struct {
 type datastore struct {
-	scope   string
-	store   store.Store
-	cache   *cache
-	watchCh chan struct{}
-	active  bool
+	scope      string
+	store      store.Store
+	cache      *cache
+	watchCh    chan struct{}
+	active     bool
+	sequential bool
 	sync.Mutex
 	sync.Mutex
 }
 }
 
 
@@ -190,6 +191,10 @@ func newClient(scope string, kv string, addr string, config *store.Config, cache
 	if cached && scope != LocalScope {
 	if cached && scope != LocalScope {
 		return nil, fmt.Errorf("caching supported only for scope %s", LocalScope)
 		return nil, fmt.Errorf("caching supported only for scope %s", LocalScope)
 	}
 	}
+	sequential := false
+	if scope == LocalScope {
+		sequential = true
+	}
 
 
 	if config == nil {
 	if config == nil {
 		config = &store.Config{}
 		config = &store.Config{}
@@ -216,7 +221,7 @@ func newClient(scope string, kv string, addr string, config *store.Config, cache
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	ds := &datastore{scope: scope, store: store, active: true, watchCh: make(chan struct{})}
+	ds := &datastore{scope: scope, store: store, active: true, watchCh: make(chan struct{}), sequential: sequential}
 	if cached {
 	if cached {
 		ds.cache = newCache(ds)
 		ds.cache = newCache(ds)
 	}
 	}
@@ -375,8 +380,10 @@ func (ds *datastore) PutObjectAtomic(kvObject KVObject) error {
 		pair     *store.KVPair
 		pair     *store.KVPair
 		err      error
 		err      error
 	)
 	)
-	ds.Lock()
-	defer ds.Unlock()
+	if ds.sequential {
+		ds.Lock()
+		defer ds.Unlock()
+	}
 
 
 	if kvObject == nil {
 	if kvObject == nil {
 		return types.BadRequestErrorf("invalid KV Object : nil")
 		return types.BadRequestErrorf("invalid KV Object : nil")
@@ -420,8 +427,10 @@ add_cache:
 
 
 // PutObject adds a new Record based on an object into the datastore
 // PutObject adds a new Record based on an object into the datastore
 func (ds *datastore) PutObject(kvObject KVObject) error {
 func (ds *datastore) PutObject(kvObject KVObject) error {
-	ds.Lock()
-	defer ds.Unlock()
+	if ds.sequential {
+		ds.Lock()
+		defer ds.Unlock()
+	}
 
 
 	if kvObject == nil {
 	if kvObject == nil {
 		return types.BadRequestErrorf("invalid KV Object : nil")
 		return types.BadRequestErrorf("invalid KV Object : nil")
@@ -456,8 +465,10 @@ func (ds *datastore) putObjectWithKey(kvObject KVObject, key ...string) error {
 
 
 // GetObject returns a record matching the key
 // GetObject returns a record matching the key
 func (ds *datastore) GetObject(key string, o KVObject) error {
 func (ds *datastore) GetObject(key string, o KVObject) error {
-	ds.Lock()
-	defer ds.Unlock()
+	if ds.sequential {
+		ds.Lock()
+		defer ds.Unlock()
+	}
 
 
 	if ds.cache != nil {
 	if ds.cache != nil {
 		return ds.cache.get(key, o)
 		return ds.cache.get(key, o)
@@ -490,8 +501,10 @@ func (ds *datastore) ensureParent(parent string) error {
 }
 }
 
 
 func (ds *datastore) List(key string, kvObject KVObject) ([]KVObject, error) {
 func (ds *datastore) List(key string, kvObject KVObject) ([]KVObject, error) {
-	ds.Lock()
-	defer ds.Unlock()
+	if ds.sequential {
+		ds.Lock()
+		defer ds.Unlock()
+	}
 
 
 	if ds.cache != nil {
 	if ds.cache != nil {
 		return ds.cache.list(kvObject)
 		return ds.cache.list(kvObject)
@@ -536,8 +549,10 @@ func (ds *datastore) List(key string, kvObject KVObject) ([]KVObject, error) {
 
 
 // DeleteObject unconditionally deletes a record from the store
 // DeleteObject unconditionally deletes a record from the store
 func (ds *datastore) DeleteObject(kvObject KVObject) error {
 func (ds *datastore) DeleteObject(kvObject KVObject) error {
-	ds.Lock()
-	defer ds.Unlock()
+	if ds.sequential {
+		ds.Lock()
+		defer ds.Unlock()
+	}
 
 
 	// cleaup the cache first
 	// cleaup the cache first
 	if ds.cache != nil {
 	if ds.cache != nil {
@@ -555,8 +570,10 @@ func (ds *datastore) DeleteObject(kvObject KVObject) error {
 
 
 // DeleteObjectAtomic performs atomic delete on a record
 // DeleteObjectAtomic performs atomic delete on a record
 func (ds *datastore) DeleteObjectAtomic(kvObject KVObject) error {
 func (ds *datastore) DeleteObjectAtomic(kvObject KVObject) error {
-	ds.Lock()
-	defer ds.Unlock()
+	if ds.sequential {
+		ds.Lock()
+		defer ds.Unlock()
+	}
 
 
 	if kvObject == nil {
 	if kvObject == nil {
 		return types.BadRequestErrorf("invalid KV Object : nil")
 		return types.BadRequestErrorf("invalid KV Object : nil")
@@ -588,8 +605,10 @@ del_cache:
 
 
 // DeleteTree unconditionally deletes a record from the store
 // DeleteTree unconditionally deletes a record from the store
 func (ds *datastore) DeleteTree(kvObject KVObject) error {
 func (ds *datastore) DeleteTree(kvObject KVObject) error {
-	ds.Lock()
-	defer ds.Unlock()
+	if ds.sequential {
+		ds.Lock()
+		defer ds.Unlock()
+	}
 
 
 	// cleaup the cache first
 	// cleaup the cache first
 	if ds.cache != nil {
 	if ds.cache != nil {

+ 1 - 1
vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go

@@ -1020,7 +1020,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 	}
 	}
 
 
 	if err = d.storeUpdate(endpoint); err != nil {
 	if err = d.storeUpdate(endpoint); err != nil {
-		return fmt.Errorf("failed to save bridge endpoint %s to store: %v", ep.id[0:7], err)
+		return fmt.Errorf("failed to save bridge endpoint %s to store: %v", endpoint.id[0:7], err)
 	}
 	}
 
 
 	return nil
 	return nil

+ 1 - 1
vendor/src/github.com/docker/libnetwork/drivers/bridge/errors.go

@@ -183,7 +183,7 @@ func (ieie InvalidEndpointIDError) BadRequest() {}
 type InvalidSandboxIDError string
 type InvalidSandboxIDError string
 
 
 func (isie InvalidSandboxIDError) Error() string {
 func (isie InvalidSandboxIDError) Error() string {
-	return fmt.Sprintf("invalid sanbox id: %s", string(isie))
+	return fmt.Sprintf("invalid sandbox id: %s", string(isie))
 }
 }
 
 
 // BadRequest denotes the type of this error
 // BadRequest denotes the type of this error

+ 3 - 3
vendor/src/github.com/docker/libnetwork/drivers/overlay/ovmanager/ovmanager.go

@@ -2,7 +2,6 @@ package ovmanager
 
 
 import (
 import (
 	"fmt"
 	"fmt"
-	"log"
 	"net"
 	"net"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
@@ -20,7 +19,7 @@ import (
 const (
 const (
 	networkType  = "overlay"
 	networkType  = "overlay"
 	vxlanIDStart = 256
 	vxlanIDStart = 256
-	vxlanIDEnd   = 1000
+	vxlanIDEnd   = (1 << 24) - 1
 )
 )
 
 
 type networkTable map[string]*network
 type networkTable map[string]*network
@@ -111,7 +110,8 @@ func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data,
 		}
 		}
 
 
 		if err := n.obtainVxlanID(s); err != nil {
 		if err := n.obtainVxlanID(s); err != nil {
-			log.Printf("Could not obtain vxlan id for pool %s: %v", s.subnetIP, err)
+			n.releaseVxlanID()
+			return nil, fmt.Errorf("could not obtain vxlan id for pool %s: %v", s.subnetIP, err)
 		}
 		}
 
 
 		n.subnets = append(n.subnets, s)
 		n.subnets = append(n.subnets, s)

+ 2 - 2
vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go

@@ -294,7 +294,7 @@ func (d *driver) Type() string {
 // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
 // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
 func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
 func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
 	if dType != discoverapi.NodeDiscovery {
 	if dType != discoverapi.NodeDiscovery {
-		return fmt.Errorf("Unknown discovery type : %v", dType)
+		return nil
 	}
 	}
 	notif := &api.DiscoveryNotification{
 	notif := &api.DiscoveryNotification{
 		DiscoveryType: dType,
 		DiscoveryType: dType,
@@ -306,7 +306,7 @@ func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{})
 // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
 // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
 func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
 func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
 	if dType != discoverapi.NodeDiscovery {
 	if dType != discoverapi.NodeDiscovery {
-		return fmt.Errorf("Unknown discovery type : %v", dType)
+		return nil
 	}
 	}
 	notif := &api.DiscoveryNotification{
 	notif := &api.DiscoveryNotification{
 		DiscoveryType: dType,
 		DiscoveryType: dType,

+ 0 - 19
vendor/src/github.com/docker/libnetwork/endpoint.go

@@ -722,18 +722,6 @@ func (ep *endpoint) sbLeave(sb *sandbox, force bool, options ...EndpointOption)
 	return nil
 	return nil
 }
 }
 
 
-func (n *network) validateForceDelete(locator string) error {
-	if n.Scope() == datastore.LocalScope {
-		return nil
-	}
-
-	if locator == "" {
-		return fmt.Errorf("invalid endpoint locator identifier")
-	}
-
-	return nil
-}
-
 func (ep *endpoint) Delete(force bool) error {
 func (ep *endpoint) Delete(force bool) error {
 	var err error
 	var err error
 	n, err := ep.getNetworkFromStore()
 	n, err := ep.getNetworkFromStore()
@@ -750,15 +738,8 @@ func (ep *endpoint) Delete(force bool) error {
 	epid := ep.id
 	epid := ep.id
 	name := ep.name
 	name := ep.name
 	sbid := ep.sandboxID
 	sbid := ep.sandboxID
-	locator := ep.locator
 	ep.Unlock()
 	ep.Unlock()
 
 
-	if force {
-		if err = n.validateForceDelete(locator); err != nil {
-			return fmt.Errorf("unable to force delete endpoint %s: %v", name, err)
-		}
-	}
-
 	sb, _ := n.getController().SandboxByID(sbid)
 	sb, _ := n.getController().SandboxByID(sbid)
 	if sb != nil && !force {
 	if sb != nil && !force {
 		return &ActiveContainerError{name: name, id: epid}
 		return &ActiveContainerError{name: name, id: epid}

+ 14 - 2
vendor/src/github.com/docker/libnetwork/osl/route_linux.go

@@ -83,17 +83,29 @@ func (n *networkNamespace) programGateway(gw net.IP, isAdd bool) error {
 		return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err)
 		return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err)
 	}
 	}
 
 
+	var linkIndex int
+	for _, gwRoute := range gwRoutes {
+		if gwRoute.Gw == nil {
+			linkIndex = gwRoute.LinkIndex
+			break
+		}
+	}
+
+	if linkIndex == 0 {
+		return fmt.Errorf("Direct route for the gateway %s could not be found", gw)
+	}
+
 	if isAdd {
 	if isAdd {
 		return n.nlHandle.RouteAdd(&netlink.Route{
 		return n.nlHandle.RouteAdd(&netlink.Route{
 			Scope:     netlink.SCOPE_UNIVERSE,
 			Scope:     netlink.SCOPE_UNIVERSE,
-			LinkIndex: gwRoutes[0].LinkIndex,
+			LinkIndex: linkIndex,
 			Gw:        gw,
 			Gw:        gw,
 		})
 		})
 	}
 	}
 
 
 	return n.nlHandle.RouteDel(&netlink.Route{
 	return n.nlHandle.RouteDel(&netlink.Route{
 		Scope:     netlink.SCOPE_UNIVERSE,
 		Scope:     netlink.SCOPE_UNIVERSE,
-		LinkIndex: gwRoutes[0].LinkIndex,
+		LinkIndex: linkIndex,
 		Gw:        gw,
 		Gw:        gw,
 	})
 	})
 }
 }

+ 23 - 1
vendor/src/github.com/docker/libnetwork/service.go

@@ -1,6 +1,7 @@
 package libnetwork
 package libnetwork
 
 
 import (
 import (
+	"fmt"
 	"net"
 	"net"
 	"sync"
 	"sync"
 )
 )
@@ -12,6 +13,27 @@ var (
 	fwMarkCtrMu sync.Mutex
 	fwMarkCtrMu sync.Mutex
 )
 )
 
 
+type portConfigs []*PortConfig
+
+func (p portConfigs) String() string {
+	if len(p) == 0 {
+		return ""
+	}
+
+	pc := p[0]
+	str := fmt.Sprintf("%d:%d/%s", pc.PublishedPort, pc.TargetPort, PortConfig_Protocol_name[int32(pc.Protocol)])
+	for _, pc := range p[1:] {
+		str = str + fmt.Sprintf(",%d:%d/%s", pc.PublishedPort, pc.TargetPort, PortConfig_Protocol_name[int32(pc.Protocol)])
+	}
+
+	return str
+}
+
+type serviceKey struct {
+	id    string
+	ports string
+}
+
 type service struct {
 type service struct {
 	name string // Service Name
 	name string // Service Name
 	id   string // Service ID
 	id   string // Service ID
@@ -21,7 +43,7 @@ type service struct {
 	loadBalancers map[string]*loadBalancer
 	loadBalancers map[string]*loadBalancer
 
 
 	// List of ingress ports exposed by the service
 	// List of ingress ports exposed by the service
-	ingressPorts []*PortConfig
+	ingressPorts portConfigs
 
 
 	sync.Mutex
 	sync.Mutex
 }
 }

+ 72 - 17
vendor/src/github.com/docker/libnetwork/service_linux.go

@@ -48,13 +48,18 @@ func (c *controller) addServiceBinding(name, sid, nid, eid string, vip net.IP, i
 		return err
 		return err
 	}
 	}
 
 
+	skey := serviceKey{
+		id:    sid,
+		ports: portConfigs(ingressPorts).String(),
+	}
+
 	c.Lock()
 	c.Lock()
-	s, ok := c.serviceBindings[sid]
+	s, ok := c.serviceBindings[skey]
 	if !ok {
 	if !ok {
 		// Create a new service if we are seeing this service
 		// Create a new service if we are seeing this service
 		// for the first time.
 		// for the first time.
 		s = newService(name, sid, ingressPorts)
 		s = newService(name, sid, ingressPorts)
-		c.serviceBindings[sid] = s
+		c.serviceBindings[skey] = s
 	}
 	}
 	c.Unlock()
 	c.Unlock()
 
 
@@ -121,8 +126,13 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in
 		return err
 		return err
 	}
 	}
 
 
+	skey := serviceKey{
+		id:    sid,
+		ports: portConfigs(ingressPorts).String(),
+	}
+
 	c.Lock()
 	c.Lock()
-	s, ok := c.serviceBindings[sid]
+	s, ok := c.serviceBindings[skey]
 	if !ok {
 	if !ok {
 		c.Unlock()
 		c.Unlock()
 		return nil
 		return nil
@@ -135,22 +145,19 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in
 		n.(*network).deleteSvcRecords("tasks."+alias, ip, nil, false)
 		n.(*network).deleteSvcRecords("tasks."+alias, ip, nil, false)
 	}
 	}
 
 
-	// Make sure to remove the right IP since if vip is
-	// not valid we would have added a DNS RR record.
-	svcIP := vip
-	if len(svcIP) == 0 {
-		svcIP = ip
-	}
-	n.(*network).deleteSvcRecords(name, svcIP, nil, false)
-	for _, alias := range aliases {
-		n.(*network).deleteSvcRecords(alias, svcIP, nil, false)
+	// If we are doing DNS RR add the endpoint IP to DNS record
+	// right away.
+	if len(vip) == 0 {
+		n.(*network).deleteSvcRecords(name, ip, nil, false)
+		for _, alias := range aliases {
+			n.(*network).deleteSvcRecords(alias, ip, nil, false)
+		}
 	}
 	}
 
 
 	s.Lock()
 	s.Lock()
-	defer s.Unlock()
-
 	lb, ok := s.loadBalancers[nid]
 	lb, ok := s.loadBalancers[nid]
 	if !ok {
 	if !ok {
+		s.Unlock()
 		return nil
 		return nil
 	}
 	}
 
 
@@ -167,7 +174,7 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in
 	if len(s.loadBalancers) == 0 {
 	if len(s.loadBalancers) == 0 {
 		// All loadbalancers for the service removed. Time to
 		// All loadbalancers for the service removed. Time to
 		// remove the service itself.
 		// remove the service itself.
-		delete(c.serviceBindings, sid)
+		delete(c.serviceBindings, skey)
 	}
 	}
 
 
 	// Remove loadbalancer service(if needed) and backend in all
 	// 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
 	if len(vip) != 0 {
 	if len(vip) != 0 {
 		n.(*network).rmLBBackend(ip, vip, lb.fwMark, ingressPorts, rmService)
 		n.(*network).rmLBBackend(ip, vip, lb.fwMark, ingressPorts, rmService)
 	}
 	}
+	s.Unlock()
+
+	// Remove the DNS record for VIP only if we are removing the service
+	if rmService && len(vip) != 0 {
+		n.(*network).deleteSvcRecords(name, vip, nil, false)
+		for _, alias := range aliases {
+			n.(*network).deleteSvcRecords(alias, vip, nil, false)
+		}
+	}
 
 
 	return nil
 	return nil
 }
 }
@@ -314,7 +330,7 @@ func (sb *sandbox) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*P
 	if addService {
 	if addService {
 		var iPorts []*PortConfig
 		var iPorts []*PortConfig
 		if sb.ingress {
 		if sb.ingress {
-			iPorts = ingressPorts
+			iPorts = filterPortConfigs(ingressPorts, false)
 			if err := programIngress(gwIP, iPorts, false); err != nil {
 			if err := programIngress(gwIP, iPorts, false); err != nil {
 				logrus.Errorf("Failed to add ingress: %v", err)
 				logrus.Errorf("Failed to add ingress: %v", err)
 				return
 				return
@@ -383,7 +399,7 @@ func (sb *sandbox) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po
 
 
 		var iPorts []*PortConfig
 		var iPorts []*PortConfig
 		if sb.ingress {
 		if sb.ingress {
-			iPorts = ingressPorts
+			iPorts = filterPortConfigs(ingressPorts, true)
 			if err := programIngress(gwIP, iPorts, true); err != nil {
 			if err := programIngress(gwIP, iPorts, true); err != nil {
 				logrus.Errorf("Failed to delete ingress: %v", err)
 				logrus.Errorf("Failed to delete ingress: %v", err)
 			}
 			}
@@ -401,8 +417,47 @@ var (
 	ingressOnce     sync.Once
 	ingressOnce     sync.Once
 	ingressProxyMu  sync.Mutex
 	ingressProxyMu  sync.Mutex
 	ingressProxyTbl = make(map[string]io.Closer)
 	ingressProxyTbl = make(map[string]io.Closer)
+	portConfigMu    sync.Mutex
+	portConfigTbl   = make(map[PortConfig]int)
 )
 )
 
 
+func filterPortConfigs(ingressPorts []*PortConfig, isDelete bool) []*PortConfig {
+	portConfigMu.Lock()
+	iPorts := make([]*PortConfig, 0, len(ingressPorts))
+	for _, pc := range ingressPorts {
+		if isDelete {
+			if cnt, ok := portConfigTbl[*pc]; ok {
+				// This is the last reference to this
+				// port config. Delete the port config
+				// and add it to filtered list to be
+				// plumbed.
+				if cnt == 1 {
+					delete(portConfigTbl, *pc)
+					iPorts = append(iPorts, pc)
+					continue
+				}
+
+				portConfigTbl[*pc] = cnt - 1
+			}
+
+			continue
+		}
+
+		if cnt, ok := portConfigTbl[*pc]; ok {
+			portConfigTbl[*pc] = cnt + 1
+			continue
+		}
+
+		// We are adding it for the first time. Add it to the
+		// filter list to be plumbed.
+		portConfigTbl[*pc] = 1
+		iPorts = append(iPorts, pc)
+	}
+	portConfigMu.Unlock()
+
+	return iPorts
+}
+
 func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) error {
 func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) error {
 	addDelOpt := "-I"
 	addDelOpt := "-I"
 	if isDelete {
 	if isDelete {

+ 0 - 2
vendor/src/github.com/docker/swarmkit/agent/agent.go

@@ -4,7 +4,6 @@ import (
 	"fmt"
 	"fmt"
 	"math/rand"
 	"math/rand"
 	"reflect"
 	"reflect"
-	"sync"
 	"time"
 	"time"
 
 
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/api"
@@ -37,7 +36,6 @@ type Agent struct {
 	stopped chan struct{} // requests shutdown
 	stopped chan struct{} // requests shutdown
 	closed  chan struct{} // only closed in run
 	closed  chan struct{} // only closed in run
 	err     error         // read only after closed is closed
 	err     error         // read only after closed is closed
-	mu      sync.Mutex
 }
 }
 
 
 // New returns a new agent, ready for task dispatch.
 // New returns a new agent, ready for task dispatch.

+ 1 - 1
vendor/src/github.com/docker/swarmkit/agent/exec/controller.go

@@ -55,7 +55,7 @@ type ContainerStatuser interface {
 // correct status depending on the tasks current state according to the result.
 // correct status depending on the tasks current state according to the result.
 //
 //
 // Unlike Do, if an error is returned, the status should still be reported. The
 // Unlike Do, if an error is returned, the status should still be reported. The
-// error merely reports the
+// error merely reports the failure at getting the controller.
 func Resolve(ctx context.Context, task *api.Task, executor Executor) (Controller, *api.TaskStatus, error) {
 func Resolve(ctx context.Context, task *api.Task, executor Executor) (Controller, *api.TaskStatus, error) {
 	status := task.Status.Copy()
 	status := task.Status.Copy()
 
 

+ 1 - 1
vendor/src/github.com/docker/swarmkit/agent/exec/executor.go

@@ -10,7 +10,7 @@ type Executor interface {
 	// Describe returns the underlying node description.
 	// Describe returns the underlying node description.
 	Describe(ctx context.Context) (*api.NodeDescription, error)
 	Describe(ctx context.Context) (*api.NodeDescription, error)
 
 
-	// Configure uses the node object state to propogate node
+	// Configure uses the node object state to propagate node
 	// state to the underlying executor.
 	// state to the underlying executor.
 	Configure(ctx context.Context, node *api.Node) error
 	Configure(ctx context.Context, node *api.Node) error
 
 

+ 39 - 45
vendor/src/github.com/docker/swarmkit/agent/node.go

@@ -49,6 +49,10 @@ type NodeConfig struct {
 	// Secret to be used on the first certificate request.
 	// Secret to be used on the first certificate request.
 	Secret string
 	Secret string
 
 
+	// ExternalCAs is a list of CAs to which a manager node
+	// will make certificate signing requests for node certificates.
+	ExternalCAs []*api.ExternalCA
+
 	// ForceNewCluster creates a new cluster from current raft state.
 	// ForceNewCluster creates a new cluster from current raft state.
 	ForceNewCluster bool
 	ForceNewCluster bool
 
 
@@ -81,7 +85,6 @@ type Node struct {
 	config               *NodeConfig
 	config               *NodeConfig
 	remotes              *persistentRemotes
 	remotes              *persistentRemotes
 	role                 string
 	role                 string
-	roleCond             *sync.Cond
 	conn                 *grpc.ClientConn
 	conn                 *grpc.ClientConn
 	connCond             *sync.Cond
 	connCond             *sync.Cond
 	nodeID               string
 	nodeID               string
@@ -95,6 +98,7 @@ type Node struct {
 	agent                *Agent
 	agent                *Agent
 	manager              *manager.Manager
 	manager              *manager.Manager
 	roleChangeReq        chan api.NodeRole // used to send role updates from the dispatcher api on promotion/demotion
 	roleChangeReq        chan api.NodeRole // used to send role updates from the dispatcher api on promotion/demotion
+	managerRoleCh        chan struct{}
 }
 }
 
 
 // NewNode returns new Node instance.
 // NewNode returns new Node instance.
@@ -124,8 +128,8 @@ func NewNode(c *NodeConfig) (*Node, error) {
 		ready:                make(chan struct{}),
 		ready:                make(chan struct{}),
 		certificateRequested: make(chan struct{}),
 		certificateRequested: make(chan struct{}),
 		roleChangeReq:        make(chan api.NodeRole, 1),
 		roleChangeReq:        make(chan api.NodeRole, 1),
+		managerRoleCh:        make(chan struct{}, 32), // 32 just for the case
 	}
 	}
-	n.roleCond = sync.NewCond(n.RLocker())
 	n.connCond = sync.NewCond(n.RLocker())
 	n.connCond = sync.NewCond(n.RLocker())
 	if err := n.loadCertificates(); err != nil {
 	if err := n.loadCertificates(); err != nil {
 		return nil, err
 		return nil, err
@@ -174,6 +178,8 @@ func (n *Node) run(ctx context.Context) (err error) {
 		}
 		}
 	}()
 	}()
 
 
+	// NOTE: When this node is created by NewNode(), our nodeID is set if
+	// n.loadCertificates() succeeded in loading TLS credentials.
 	if n.config.JoinAddr == "" && n.nodeID == "" {
 	if n.config.JoinAddr == "" && n.nodeID == "" {
 		if err := n.bootstrapCA(); err != nil {
 		if err := n.bootstrapCA(); err != nil {
 			return err
 			return err
@@ -234,6 +240,10 @@ func (n *Node) run(ctx context.Context) (err error) {
 		return err
 		return err
 	}
 	}
 
 
+	if n.role == ca.ManagerRole {
+		n.managerRoleCh <- struct{}{}
+	}
+
 	forceCertRenewal := make(chan struct{})
 	forceCertRenewal := make(chan struct{})
 	go func() {
 	go func() {
 		n.RLock()
 		n.RLock()
@@ -270,7 +280,9 @@ func (n *Node) run(ctx context.Context) (err error) {
 				}
 				}
 				n.Lock()
 				n.Lock()
 				n.role = certUpdate.Role
 				n.role = certUpdate.Role
-				n.roleCond.Broadcast()
+				if n.role == ca.ManagerRole {
+					n.managerRoleCh <- struct{}{}
+				}
 				n.Unlock()
 				n.Unlock()
 			case <-ctx.Done():
 			case <-ctx.Done():
 				return
 				return
@@ -419,34 +431,6 @@ func (n *Node) CertificateRequested() <-chan struct{} {
 	return n.certificateRequested
 	return n.certificateRequested
 }
 }
 
 
-func (n *Node) waitRole(ctx context.Context, role string) <-chan struct{} {
-	c := make(chan struct{})
-	n.roleCond.L.Lock()
-	if role == n.role {
-		close(c)
-		n.roleCond.L.Unlock()
-		return c
-	}
-	go func() {
-		select {
-		case <-ctx.Done():
-			n.roleCond.Broadcast()
-		case <-c:
-		}
-	}()
-	go func() {
-		defer n.roleCond.L.Unlock()
-		defer close(c)
-		for role != n.role {
-			n.roleCond.Wait()
-			if ctx.Err() != nil {
-				return
-			}
-		}
-	}()
-	return c
-}
-
 func (n *Node) setControlSocket(conn *grpc.ClientConn) {
 func (n *Node) setControlSocket(conn *grpc.ClientConn) {
 	n.Lock()
 	n.Lock()
 	n.conn = conn
 	n.conn = conn
@@ -549,7 +533,6 @@ func (n *Node) loadCertificates() error {
 	n.role = clientTLSCreds.Role()
 	n.role = clientTLSCreds.Role()
 	n.nodeID = clientTLSCreds.NodeID()
 	n.nodeID = clientTLSCreds.NodeID()
 	n.nodeMembership = api.NodeMembershipAccepted
 	n.nodeMembership = api.NodeMembershipAccepted
-	n.roleCond.Broadcast()
 	n.Unlock()
 	n.Unlock()
 
 
 	return nil
 	return nil
@@ -599,10 +582,17 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
 		select {
 		select {
 		case <-ctx.Done():
 		case <-ctx.Done():
 			return ctx.Err()
 			return ctx.Err()
-		case <-n.waitRole(ctx, ca.ManagerRole):
+		case <-n.managerRoleCh:
 			if ctx.Err() != nil {
 			if ctx.Err() != nil {
 				return ctx.Err()
 				return ctx.Err()
 			}
 			}
+			n.Lock()
+			// in case if we missed some notifications
+			if n.role != ca.ManagerRole {
+				n.Unlock()
+				continue
+			}
+			n.Unlock()
 			remoteAddr, _ := n.remotes.Select(n.nodeID)
 			remoteAddr, _ := n.remotes.Select(n.nodeID)
 			m, err := manager.New(&manager.Config{
 			m, err := manager.New(&manager.Config{
 				ForceNewCluster: n.config.ForceNewCluster,
 				ForceNewCluster: n.config.ForceNewCluster,
@@ -611,6 +601,7 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
 					"unix": n.config.ListenControlAPI,
 					"unix": n.config.ListenControlAPI,
 				},
 				},
 				SecurityConfig: securityConfig,
 				SecurityConfig: securityConfig,
+				ExternalCAs:    n.config.ExternalCAs,
 				JoinRaft:       remoteAddr.Addr,
 				JoinRaft:       remoteAddr.Addr,
 				StateDir:       n.config.StateDir,
 				StateDir:       n.config.StateDir,
 				HeartbeatTick:  n.config.HeartbeatTick,
 				HeartbeatTick:  n.config.HeartbeatTick,
@@ -629,17 +620,21 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
 			n.manager = m
 			n.manager = m
 			n.Unlock()
 			n.Unlock()
 
 
-			go n.initManagerConnection(ctx, ready)
+			connCtx, connCancel := context.WithCancel(ctx)
+			go n.initManagerConnection(connCtx, ready)
 
 
-			go func() {
-				select {
-				case <-ready:
-				case <-ctx.Done():
-				}
-				if ctx.Err() == nil {
-					n.remotes.Observe(api.Peer{NodeID: n.nodeID, Addr: n.config.ListenRemoteAPI}, 5)
-				}
-			}()
+			// this happens only on initial start
+			if ready != nil {
+				go func(ready chan struct{}) {
+					select {
+					case <-ready:
+						n.remotes.Observe(api.Peer{NodeID: n.nodeID, Addr: n.config.ListenRemoteAPI}, 5)
+					case <-connCtx.Done():
+					}
+				}(ready)
+			}
+
+			ready = nil
 
 
 			select {
 			select {
 			case <-ctx.Done():
 			case <-ctx.Done():
@@ -648,8 +643,8 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
 			// in case of demotion manager will stop itself
 			// in case of demotion manager will stop itself
 			case <-done:
 			case <-done:
 			}
 			}
+			connCancel()
 
 
-			ready = nil // ready event happens once, even on multiple starts
 			n.Lock()
 			n.Lock()
 			n.manager = nil
 			n.manager = nil
 			if n.conn != nil {
 			if n.conn != nil {
@@ -669,7 +664,6 @@ type persistentRemotes struct {
 	c *sync.Cond
 	c *sync.Cond
 	picker.Remotes
 	picker.Remotes
 	storePath      string
 	storePath      string
-	ch             []chan api.Peer
 	lastSavedState []api.Peer
 	lastSavedState []api.Peer
 }
 }
 
 

+ 0 - 1
vendor/src/github.com/docker/swarmkit/agent/session.go

@@ -26,7 +26,6 @@ var (
 // agent through errs, messages and tasks.
 // agent through errs, messages and tasks.
 type session struct {
 type session struct {
 	agent     *Agent
 	agent     *Agent
-	nodeID    string
 	sessionID string
 	sessionID string
 	session   api.Dispatcher_SessionClient
 	session   api.Dispatcher_SessionClient
 	errs      chan error
 	errs      chan error

+ 0 - 8
vendor/src/github.com/docker/swarmkit/agent/storage.go

@@ -1,8 +1,6 @@
 package agent
 package agent
 
 
 import (
 import (
-	"bytes"
-
 	"github.com/boltdb/bolt"
 	"github.com/boltdb/bolt"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/api"
 	"github.com/gogo/protobuf/proto"
 	"github.com/gogo/protobuf/proto"
@@ -22,12 +20,6 @@ var (
 	bucketKeyStatus         = []byte("status")
 	bucketKeyStatus         = []byte("status")
 )
 )
 
 
-type bucketKeyPath [][]byte
-
-func (bk bucketKeyPath) String() string {
-	return string(bytes.Join([][]byte(bk), []byte("/")))
-}
-
 // InitDB prepares a database for writing task data.
 // InitDB prepares a database for writing task data.
 //
 //
 // Proper buckets will be created if they don't already exist.
 // Proper buckets will be created if they don't already exist.

+ 8 - 0
vendor/src/github.com/docker/swarmkit/api/README.md

@@ -0,0 +1,8 @@
+### Notice
+
+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.
+```
+$ make generate
+```
+
+Click [here](https://github.com/google/protobuf) for more information about protobuf.

+ 1 - 1
vendor/src/github.com/docker/swarmkit/api/gen.go

@@ -1,3 +1,3 @@
 package api
 package api
 
 
-//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
+//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

+ 714 - 0
vendor/src/github.com/docker/swarmkit/api/health.pb.go

@@ -0,0 +1,714 @@
+// Code generated by protoc-gen-gogo.
+// source: health.proto
+// DO NOT EDIT!
+
+package api
+
+import proto "github.com/gogo/protobuf/proto"
+import fmt "fmt"
+import math "math"
+import _ "github.com/gogo/protobuf/gogoproto"
+import _ "github.com/docker/swarmkit/protobuf/plugin"
+
+import strings "strings"
+import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto"
+import sort "sort"
+import strconv "strconv"
+import reflect "reflect"
+
+import (
+	context "golang.org/x/net/context"
+	grpc "google.golang.org/grpc"
+)
+
+import raftpicker "github.com/docker/swarmkit/manager/raftpicker"
+import codes "google.golang.org/grpc/codes"
+import metadata "google.golang.org/grpc/metadata"
+import transport "google.golang.org/grpc/transport"
+
+import io "io"
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+type HealthCheckResponse_ServingStatus int32
+
+const (
+	HealthCheckResponse_UNKNOWN     HealthCheckResponse_ServingStatus = 0
+	HealthCheckResponse_SERVING     HealthCheckResponse_ServingStatus = 1
+	HealthCheckResponse_NOT_SERVING HealthCheckResponse_ServingStatus = 2
+)
+
+var HealthCheckResponse_ServingStatus_name = map[int32]string{
+	0: "UNKNOWN",
+	1: "SERVING",
+	2: "NOT_SERVING",
+}
+var HealthCheckResponse_ServingStatus_value = map[string]int32{
+	"UNKNOWN":     0,
+	"SERVING":     1,
+	"NOT_SERVING": 2,
+}
+
+func (x HealthCheckResponse_ServingStatus) String() string {
+	return proto.EnumName(HealthCheckResponse_ServingStatus_name, int32(x))
+}
+func (HealthCheckResponse_ServingStatus) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptorHealth, []int{1, 0}
+}
+
+type HealthCheckRequest struct {
+	Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
+}
+
+func (m *HealthCheckRequest) Reset()                    { *m = HealthCheckRequest{} }
+func (*HealthCheckRequest) ProtoMessage()               {}
+func (*HealthCheckRequest) Descriptor() ([]byte, []int) { return fileDescriptorHealth, []int{0} }
+
+type HealthCheckResponse struct {
+	Status HealthCheckResponse_ServingStatus `protobuf:"varint,1,opt,name=status,proto3,enum=docker.swarmkit.v1.HealthCheckResponse_ServingStatus" json:"status,omitempty"`
+}
+
+func (m *HealthCheckResponse) Reset()                    { *m = HealthCheckResponse{} }
+func (*HealthCheckResponse) ProtoMessage()               {}
+func (*HealthCheckResponse) Descriptor() ([]byte, []int) { return fileDescriptorHealth, []int{1} }
+
+func init() {
+	proto.RegisterType((*HealthCheckRequest)(nil), "docker.swarmkit.v1.HealthCheckRequest")
+	proto.RegisterType((*HealthCheckResponse)(nil), "docker.swarmkit.v1.HealthCheckResponse")
+	proto.RegisterEnum("docker.swarmkit.v1.HealthCheckResponse_ServingStatus", HealthCheckResponse_ServingStatus_name, HealthCheckResponse_ServingStatus_value)
+}
+
+type authenticatedWrapperHealthServer struct {
+	local     HealthServer
+	authorize func(context.Context, []string) error
+}
+
+func NewAuthenticatedWrapperHealthServer(local HealthServer, authorize func(context.Context, []string) error) HealthServer {
+	return &authenticatedWrapperHealthServer{
+		local:     local,
+		authorize: authorize,
+	}
+}
+
+func (p *authenticatedWrapperHealthServer) Check(ctx context.Context, r *HealthCheckRequest) (*HealthCheckResponse, error) {
+
+	if err := p.authorize(ctx, []string{"swarm-manager"}); err != nil {
+		return nil, err
+	}
+	return p.local.Check(ctx, r)
+}
+
+func (m *HealthCheckRequest) Copy() *HealthCheckRequest {
+	if m == nil {
+		return nil
+	}
+
+	o := &HealthCheckRequest{
+		Service: m.Service,
+	}
+
+	return o
+}
+
+func (m *HealthCheckResponse) Copy() *HealthCheckResponse {
+	if m == nil {
+		return nil
+	}
+
+	o := &HealthCheckResponse{
+		Status: m.Status,
+	}
+
+	return o
+}
+
+func (this *HealthCheckRequest) GoString() string {
+	if this == nil {
+		return "nil"
+	}
+	s := make([]string, 0, 5)
+	s = append(s, "&api.HealthCheckRequest{")
+	s = append(s, "Service: "+fmt.Sprintf("%#v", this.Service)+",\n")
+	s = append(s, "}")
+	return strings.Join(s, "")
+}
+func (this *HealthCheckResponse) GoString() string {
+	if this == nil {
+		return "nil"
+	}
+	s := make([]string, 0, 5)
+	s = append(s, "&api.HealthCheckResponse{")
+	s = append(s, "Status: "+fmt.Sprintf("%#v", this.Status)+",\n")
+	s = append(s, "}")
+	return strings.Join(s, "")
+}
+func valueToGoStringHealth(v interface{}, typ string) string {
+	rv := reflect.ValueOf(v)
+	if rv.IsNil() {
+		return "nil"
+	}
+	pv := reflect.Indirect(rv).Interface()
+	return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv)
+}
+func extensionToGoStringHealth(e map[int32]github_com_gogo_protobuf_proto.Extension) string {
+	if e == nil {
+		return "nil"
+	}
+	s := "map[int32]proto.Extension{"
+	keys := make([]int, 0, len(e))
+	for k := range e {
+		keys = append(keys, int(k))
+	}
+	sort.Ints(keys)
+	ss := []string{}
+	for _, k := range keys {
+		ss = append(ss, strconv.Itoa(k)+": "+e[int32(k)].GoString())
+	}
+	s += strings.Join(ss, ",") + "}"
+	return s
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion2
+
+// Client API for Health service
+
+type HealthClient interface {
+	Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error)
+}
+
+type healthClient struct {
+	cc *grpc.ClientConn
+}
+
+func NewHealthClient(cc *grpc.ClientConn) HealthClient {
+	return &healthClient{cc}
+}
+
+func (c *healthClient) Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) {
+	out := new(HealthCheckResponse)
+	err := grpc.Invoke(ctx, "/docker.swarmkit.v1.Health/Check", in, out, c.cc, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// Server API for Health service
+
+type HealthServer interface {
+	Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error)
+}
+
+func RegisterHealthServer(s *grpc.Server, srv HealthServer) {
+	s.RegisterService(&_Health_serviceDesc, srv)
+}
+
+func _Health_Check_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(HealthCheckRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(HealthServer).Check(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/docker.swarmkit.v1.Health/Check",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(HealthServer).Check(ctx, req.(*HealthCheckRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+var _Health_serviceDesc = grpc.ServiceDesc{
+	ServiceName: "docker.swarmkit.v1.Health",
+	HandlerType: (*HealthServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "Check",
+			Handler:    _Health_Check_Handler,
+		},
+	},
+	Streams: []grpc.StreamDesc{},
+}
+
+func (m *HealthCheckRequest) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+func (m *HealthCheckRequest) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if len(m.Service) > 0 {
+		data[i] = 0xa
+		i++
+		i = encodeVarintHealth(data, i, uint64(len(m.Service)))
+		i += copy(data[i:], m.Service)
+	}
+	return i, nil
+}
+
+func (m *HealthCheckResponse) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+func (m *HealthCheckResponse) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if m.Status != 0 {
+		data[i] = 0x8
+		i++
+		i = encodeVarintHealth(data, i, uint64(m.Status))
+	}
+	return i, nil
+}
+
+func encodeFixed64Health(data []byte, offset int, v uint64) int {
+	data[offset] = uint8(v)
+	data[offset+1] = uint8(v >> 8)
+	data[offset+2] = uint8(v >> 16)
+	data[offset+3] = uint8(v >> 24)
+	data[offset+4] = uint8(v >> 32)
+	data[offset+5] = uint8(v >> 40)
+	data[offset+6] = uint8(v >> 48)
+	data[offset+7] = uint8(v >> 56)
+	return offset + 8
+}
+func encodeFixed32Health(data []byte, offset int, v uint32) int {
+	data[offset] = uint8(v)
+	data[offset+1] = uint8(v >> 8)
+	data[offset+2] = uint8(v >> 16)
+	data[offset+3] = uint8(v >> 24)
+	return offset + 4
+}
+func encodeVarintHealth(data []byte, offset int, v uint64) int {
+	for v >= 1<<7 {
+		data[offset] = uint8(v&0x7f | 0x80)
+		v >>= 7
+		offset++
+	}
+	data[offset] = uint8(v)
+	return offset + 1
+}
+
+type raftProxyHealthServer struct {
+	local        HealthServer
+	connSelector *raftpicker.ConnSelector
+	cluster      raftpicker.RaftCluster
+	ctxMods      []func(context.Context) (context.Context, error)
+}
+
+func NewRaftProxyHealthServer(local HealthServer, connSelector *raftpicker.ConnSelector, cluster raftpicker.RaftCluster, ctxMod func(context.Context) (context.Context, error)) HealthServer {
+	redirectChecker := func(ctx context.Context) (context.Context, error) {
+		s, ok := transport.StreamFromContext(ctx)
+		if !ok {
+			return ctx, grpc.Errorf(codes.InvalidArgument, "remote addr is not found in context")
+		}
+		addr := s.ServerTransport().RemoteAddr().String()
+		md, ok := metadata.FromContext(ctx)
+		if ok && len(md["redirect"]) != 0 {
+			return ctx, grpc.Errorf(codes.ResourceExhausted, "more than one redirect to leader from: %s", md["redirect"])
+		}
+		if !ok {
+			md = metadata.New(map[string]string{})
+		}
+		md["redirect"] = append(md["redirect"], addr)
+		return metadata.NewContext(ctx, md), nil
+	}
+	mods := []func(context.Context) (context.Context, error){redirectChecker}
+	mods = append(mods, ctxMod)
+
+	return &raftProxyHealthServer{
+		local:        local,
+		cluster:      cluster,
+		connSelector: connSelector,
+		ctxMods:      mods,
+	}
+}
+func (p *raftProxyHealthServer) runCtxMods(ctx context.Context) (context.Context, error) {
+	var err error
+	for _, mod := range p.ctxMods {
+		ctx, err = mod(ctx)
+		if err != nil {
+			return ctx, err
+		}
+	}
+	return ctx, nil
+}
+
+func (p *raftProxyHealthServer) Check(ctx context.Context, r *HealthCheckRequest) (*HealthCheckResponse, error) {
+
+	if p.cluster.IsLeader() {
+		return p.local.Check(ctx, r)
+	}
+	ctx, err := p.runCtxMods(ctx)
+	if err != nil {
+		return nil, err
+	}
+	conn, err := p.connSelector.Conn()
+	if err != nil {
+		return nil, err
+	}
+	return NewHealthClient(conn).Check(ctx, r)
+}
+
+func (m *HealthCheckRequest) Size() (n int) {
+	var l int
+	_ = l
+	l = len(m.Service)
+	if l > 0 {
+		n += 1 + l + sovHealth(uint64(l))
+	}
+	return n
+}
+
+func (m *HealthCheckResponse) Size() (n int) {
+	var l int
+	_ = l
+	if m.Status != 0 {
+		n += 1 + sovHealth(uint64(m.Status))
+	}
+	return n
+}
+
+func sovHealth(x uint64) (n int) {
+	for {
+		n++
+		x >>= 7
+		if x == 0 {
+			break
+		}
+	}
+	return n
+}
+func sozHealth(x uint64) (n int) {
+	return sovHealth(uint64((x << 1) ^ uint64((int64(x) >> 63))))
+}
+func (this *HealthCheckRequest) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&HealthCheckRequest{`,
+		`Service:` + fmt.Sprintf("%v", this.Service) + `,`,
+		`}`,
+	}, "")
+	return s
+}
+func (this *HealthCheckResponse) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&HealthCheckResponse{`,
+		`Status:` + fmt.Sprintf("%v", this.Status) + `,`,
+		`}`,
+	}, "")
+	return s
+}
+func valueToStringHealth(v interface{}) string {
+	rv := reflect.ValueOf(v)
+	if rv.IsNil() {
+		return "nil"
+	}
+	pv := reflect.Indirect(rv).Interface()
+	return fmt.Sprintf("*%v", pv)
+}
+func (m *HealthCheckRequest) Unmarshal(data []byte) error {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowHealth
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: HealthCheckRequest: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: HealthCheckRequest: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Service", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowHealth
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthHealth
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Service = string(data[iNdEx:postIndex])
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipHealth(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthHealth
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *HealthCheckResponse) Unmarshal(data []byte) error {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowHealth
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: HealthCheckResponse: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: HealthCheckResponse: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType)
+			}
+			m.Status = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowHealth
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				m.Status |= (HealthCheckResponse_ServingStatus(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		default:
+			iNdEx = preIndex
+			skippy, err := skipHealth(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthHealth
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func skipHealth(data []byte) (n int, err error) {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return 0, ErrIntOverflowHealth
+			}
+			if iNdEx >= l {
+				return 0, io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		wireType := int(wire & 0x7)
+		switch wireType {
+		case 0:
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return 0, ErrIntOverflowHealth
+				}
+				if iNdEx >= l {
+					return 0, io.ErrUnexpectedEOF
+				}
+				iNdEx++
+				if data[iNdEx-1] < 0x80 {
+					break
+				}
+			}
+			return iNdEx, nil
+		case 1:
+			iNdEx += 8
+			return iNdEx, nil
+		case 2:
+			var length int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return 0, ErrIntOverflowHealth
+				}
+				if iNdEx >= l {
+					return 0, io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				length |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			iNdEx += length
+			if length < 0 {
+				return 0, ErrInvalidLengthHealth
+			}
+			return iNdEx, nil
+		case 3:
+			for {
+				var innerWire uint64
+				var start int = iNdEx
+				for shift := uint(0); ; shift += 7 {
+					if shift >= 64 {
+						return 0, ErrIntOverflowHealth
+					}
+					if iNdEx >= l {
+						return 0, io.ErrUnexpectedEOF
+					}
+					b := data[iNdEx]
+					iNdEx++
+					innerWire |= (uint64(b) & 0x7F) << shift
+					if b < 0x80 {
+						break
+					}
+				}
+				innerWireType := int(innerWire & 0x7)
+				if innerWireType == 4 {
+					break
+				}
+				next, err := skipHealth(data[start:])
+				if err != nil {
+					return 0, err
+				}
+				iNdEx = start + next
+			}
+			return iNdEx, nil
+		case 4:
+			return iNdEx, nil
+		case 5:
+			iNdEx += 4
+			return iNdEx, nil
+		default:
+			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
+		}
+	}
+	panic("unreachable")
+}
+
+var (
+	ErrInvalidLengthHealth = fmt.Errorf("proto: negative length found during unmarshaling")
+	ErrIntOverflowHealth   = fmt.Errorf("proto: integer overflow")
+)
+
+var fileDescriptorHealth = []byte{
+	// 284 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0xc9, 0x48, 0x4d, 0xcc,
+	0x29, 0xc9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x4a, 0xc9, 0x4f, 0xce, 0x4e, 0x2d,
+	0xd2, 0x2b, 0x2e, 0x4f, 0x2c, 0xca, 0xcd, 0xce, 0x2c, 0xd1, 0x2b, 0x33, 0x94, 0x12, 0x49, 0xcf,
+	0x4f, 0xcf, 0x07, 0x4b, 0xeb, 0x83, 0x58, 0x10, 0x95, 0x52, 0xc2, 0x05, 0x39, 0xa5, 0xe9, 0x99,
+	0x79, 0xfa, 0x10, 0x0a, 0x22, 0xa8, 0xa4, 0xc7, 0x25, 0xe4, 0x01, 0x36, 0xce, 0x39, 0x23, 0x35,
+	0x39, 0x3b, 0x28, 0xb5, 0xb0, 0x34, 0xb5, 0xb8, 0x44, 0x48, 0x82, 0x8b, 0xbd, 0x38, 0xb5, 0xa8,
+	0x2c, 0x33, 0x39, 0x55, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x08, 0xc6, 0x55, 0x5a, 0xc0, 0xc8,
+	0x25, 0x8c, 0xa2, 0xa1, 0xb8, 0x20, 0x3f, 0xaf, 0x38, 0x55, 0xc8, 0x97, 0x8b, 0xad, 0xb8, 0x24,
+	0xb1, 0xa4, 0xb4, 0x18, 0xac, 0x81, 0xcf, 0xc8, 0x54, 0x0f, 0xd3, 0x5d, 0x7a, 0x58, 0x34, 0xea,
+	0x05, 0x83, 0x0c, 0xce, 0x4b, 0x0f, 0x06, 0x6b, 0x0e, 0x82, 0x1a, 0xa2, 0x64, 0xc5, 0xc5, 0x8b,
+	0x22, 0x21, 0xc4, 0xcd, 0xc5, 0x1e, 0xea, 0xe7, 0xed, 0xe7, 0x1f, 0xee, 0x27, 0xc0, 0x00, 0xe2,
+	0x04, 0xbb, 0x06, 0x85, 0x79, 0xfa, 0xb9, 0x0b, 0x30, 0x0a, 0xf1, 0x73, 0x71, 0xfb, 0xf9, 0x87,
+	0xc4, 0xc3, 0x04, 0x98, 0x8c, 0x2a, 0xb9, 0xd8, 0x20, 0x16, 0x09, 0xe5, 0x73, 0xb1, 0x82, 0x2d,
+	0x13, 0x52, 0x23, 0xe8, 0x1a, 0xb0, 0xbf, 0xa5, 0xd4, 0x89, 0x74, 0xb5, 0x92, 0xe8, 0xa9, 0x75,
+	0xef, 0x66, 0x30, 0xf1, 0x73, 0xf1, 0x82, 0x15, 0xea, 0xe6, 0x26, 0xe6, 0x25, 0xa6, 0xa7, 0x16,
+	0x39, 0xc9, 0x9c, 0x78, 0x28, 0xc7, 0x70, 0x03, 0x88, 0x3f, 0x3c, 0x94, 0x63, 0x6c, 0x78, 0x24,
+	0xc7, 0x78, 0x02, 0x88, 0x2f, 0x00, 0xf1, 0x03, 0x20, 0x4e, 0x62, 0x03, 0x07, 0xb9, 0x31, 0x20,
+	0x00, 0x00, 0xff, 0xff, 0xf7, 0x14, 0x7c, 0x23, 0xc1, 0x01, 0x00, 0x00,
+}

+ 34 - 0
vendor/src/github.com/docker/swarmkit/api/health.proto

@@ -0,0 +1,34 @@
+syntax = "proto3";
+
+// See: https://github.com/grpc/grpc-go/blob/master/health/grpc_health_v1/health.proto
+//
+// We use the same health check service proto description defined in the gRPC documentation,
+// including the authorization check. This requires our own implementation of the health
+// package located in `manager/health`.
+//
+// For more infos, refer to:
+// https://github.com/grpc/grpc/blob/master/doc/health-checking.md
+
+package docker.swarmkit.v1;
+
+import "gogoproto/gogo.proto";
+import "plugin/plugin.proto";
+
+service Health {
+	rpc Check(HealthCheckRequest) returns (HealthCheckResponse) {
+		option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-manager" };
+	};
+}
+
+message HealthCheckRequest {
+	string service = 1;
+}
+
+message HealthCheckResponse {
+	enum ServingStatus {
+		UNKNOWN = 0;
+		SERVING = 1;
+		NOT_SERVING = 2;
+	}
+	ServingStatus status = 1;
+}

+ 103 - 56
vendor/src/github.com/docker/swarmkit/api/raft.pb.go

@@ -90,8 +90,13 @@ func (*JoinRequest) ProtoMessage()               {}
 func (*JoinRequest) Descriptor() ([]byte, []int) { return fileDescriptorRaft, []int{1} }
 func (*JoinRequest) Descriptor() ([]byte, []int) { return fileDescriptorRaft, []int{1} }
 
 
 type JoinResponse struct {
 type JoinResponse struct {
-	RaftID  uint64        `protobuf:"varint,1,opt,name=raft_id,json=raftId,proto3" json:"raft_id,omitempty"`
+	// RaftID is the ID assigned to the new member.
+	RaftID uint64 `protobuf:"varint,1,opt,name=raft_id,json=raftId,proto3" json:"raft_id,omitempty"`
+	// Members is the membership set of the cluster.
 	Members []*RaftMember `protobuf:"bytes,2,rep,name=members" json:"members,omitempty"`
 	Members []*RaftMember `protobuf:"bytes,2,rep,name=members" json:"members,omitempty"`
+	// RemovedMembers is a list of members that have been removed from
+	// the cluster, so the new node can avoid communicating with them.
+	RemovedMembers []uint64 `protobuf:"varint,3,rep,name=removed_members,json=removedMembers" json:"removed_members,omitempty"`
 }
 }
 
 
 func (m *JoinResponse) Reset()                    { *m = JoinResponse{} }
 func (m *JoinResponse) Reset()                    { *m = JoinResponse{} }
@@ -489,6 +494,13 @@ func (m *JoinResponse) Copy() *JoinResponse {
 		}
 		}
 	}
 	}
 
 
+	if m.RemovedMembers != nil {
+		o.RemovedMembers = make([]uint64, 0, len(m.RemovedMembers))
+		for _, v := range m.RemovedMembers {
+			o.RemovedMembers = append(o.RemovedMembers, v)
+		}
+	}
+
 	return o
 	return o
 }
 }
 
 
@@ -639,12 +651,13 @@ func (this *JoinResponse) GoString() string {
 	if this == nil {
 	if this == nil {
 		return "nil"
 		return "nil"
 	}
 	}
-	s := make([]string, 0, 6)
+	s := make([]string, 0, 7)
 	s = append(s, "&api.JoinResponse{")
 	s = append(s, "&api.JoinResponse{")
 	s = append(s, "RaftID: "+fmt.Sprintf("%#v", this.RaftID)+",\n")
 	s = append(s, "RaftID: "+fmt.Sprintf("%#v", this.RaftID)+",\n")
 	if this.Members != nil {
 	if this.Members != nil {
 		s = append(s, "Members: "+fmt.Sprintf("%#v", this.Members)+",\n")
 		s = append(s, "Members: "+fmt.Sprintf("%#v", this.Members)+",\n")
 	}
 	}
+	s = append(s, "RemovedMembers: "+fmt.Sprintf("%#v", this.RemovedMembers)+",\n")
 	s = append(s, "}")
 	s = append(s, "}")
 	return strings.Join(s, "")
 	return strings.Join(s, "")
 }
 }
@@ -1111,6 +1124,13 @@ func (m *JoinResponse) MarshalTo(data []byte) (int, error) {
 			i += n
 			i += n
 		}
 		}
 	}
 	}
+	if len(m.RemovedMembers) > 0 {
+		for _, num := range m.RemovedMembers {
+			data[i] = 0x18
+			i++
+			i = encodeVarintRaft(data, i, uint64(num))
+		}
+	}
 	return i, nil
 	return i, nil
 }
 }
 
 
@@ -1611,6 +1631,11 @@ func (m *JoinResponse) Size() (n int) {
 			n += 1 + l + sovRaft(uint64(l))
 			n += 1 + l + sovRaft(uint64(l))
 		}
 		}
 	}
 	}
+	if len(m.RemovedMembers) > 0 {
+		for _, e := range m.RemovedMembers {
+			n += 1 + sovRaft(uint64(e))
+		}
+	}
 	return n
 	return n
 }
 }
 
 
@@ -1781,6 +1806,7 @@ func (this *JoinResponse) String() string {
 	s := strings.Join([]string{`&JoinResponse{`,
 	s := strings.Join([]string{`&JoinResponse{`,
 		`RaftID:` + fmt.Sprintf("%v", this.RaftID) + `,`,
 		`RaftID:` + fmt.Sprintf("%v", this.RaftID) + `,`,
 		`Members:` + strings.Replace(fmt.Sprintf("%v", this.Members), "RaftMember", "RaftMember", 1) + `,`,
 		`Members:` + strings.Replace(fmt.Sprintf("%v", this.Members), "RaftMember", "RaftMember", 1) + `,`,
+		`RemovedMembers:` + fmt.Sprintf("%v", this.RemovedMembers) + `,`,
 		`}`,
 		`}`,
 	}, "")
 	}, "")
 	return s
 	return s
@@ -2238,6 +2264,26 @@ func (m *JoinResponse) Unmarshal(data []byte) error {
 				return err
 				return err
 			}
 			}
 			iNdEx = postIndex
 			iNdEx = postIndex
+		case 3:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field RemovedMembers", wireType)
+			}
+			var v uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRaft
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				v |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			m.RemovedMembers = append(m.RemovedMembers, v)
 		default:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
 			skippy, err := skipRaft(data[iNdEx:])
 			skippy, err := skipRaft(data[iNdEx:])
@@ -3108,58 +3154,59 @@ var (
 )
 )
 
 
 var fileDescriptorRaft = []byte{
 var fileDescriptorRaft = []byte{
-	// 833 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x95, 0x4d, 0x53, 0xdb, 0x46,
-	0x18, 0xc7, 0x2d, 0x59, 0xc8, 0xed, 0x9a, 0xb7, 0x59, 0x0a, 0x35, 0x2a, 0x63, 0x40, 0x74, 0xa6,
-	0x85, 0x29, 0xf2, 0xd4, 0x3d, 0xb4, 0xd3, 0xf6, 0x62, 0x1b, 0xcf, 0xd4, 0x05, 0x6c, 0x46, 0xd8,
-	0x2d, 0x37, 0x2a, 0x4b, 0x8b, 0x51, 0x6d, 0x6b, 0x5d, 0xed, 0xda, 0x4c, 0x2f, 0x19, 0x8e, 0x19,
-	0xae, 0x39, 0x24, 0x97, 0x9c, 0x92, 0x33, 0x1f, 0x20, 0x9f, 0x80, 0xc9, 0x29, 0xb7, 0xe4, 0x44,
-	0x02, 0x1f, 0x20, 0xc9, 0x47, 0xc8, 0xae, 0x5e, 0x0c, 0x31, 0xb2, 0xf1, 0x41, 0xb0, 0xec, 0xfe,
-	0xfe, 0xcf, 0xff, 0xd9, 0x67, 0xf7, 0x59, 0x00, 0x70, 0x8d, 0x23, 0xaa, 0x75, 0x5c, 0x4c, 0x31,
-	0x84, 0x16, 0x36, 0x9b, 0xc8, 0xd5, 0xc8, 0x89, 0xe1, 0xb6, 0x9b, 0x36, 0xd5, 0x7a, 0x3f, 0x2a,
-	0x53, 0xb8, 0xfe, 0x2f, 0x32, 0x29, 0xf1, 0x11, 0x25, 0x49, 0xff, 0xef, 0xa0, 0xf0, 0x8f, 0xcd,
-	0x86, 0x4d, 0x8f, 0xbb, 0x75, 0xcd, 0xc4, 0xed, 0x8c, 0x89, 0x5d, 0x84, 0x49, 0x06, 0x51, 0xd3,
-	0xca, 0xf0, 0x90, 0xde, 0x8f, 0x4e, 0x3d, 0x73, 0x13, 0x5e, 0xf9, 0xaa, 0x81, 0x1b, 0xd8, 0x1b,
-	0x66, 0xf8, 0x28, 0x98, 0x9d, 0xeb, 0xb4, 0xba, 0x0d, 0xdb, 0xc9, 0xf8, 0xbf, 0xfc, 0x49, 0xf5,
-	0x5c, 0x00, 0x40, 0x67, 0xca, 0x5d, 0xd4, 0xae, 0x23, 0x17, 0xae, 0x81, 0x04, 0x8f, 0x73, 0x68,
-	0x5b, 0x29, 0x61, 0x45, 0xf8, 0x5e, 0xca, 0x83, 0xeb, 0xcb, 0x65, 0x99, 0x03, 0xa5, 0x2d, 0x5d,
-	0xe6, 0x4b, 0x25, 0x8b, 0x43, 0x0e, 0xb6, 0x10, 0x87, 0x44, 0x06, 0x7d, 0xe9, 0x43, 0x65, 0x36,
-	0xc5, 0x21, 0xbe, 0xc4, 0x20, 0x08, 0x24, 0xc3, 0xb2, 0xdc, 0x54, 0x9c, 0x13, 0xba, 0x37, 0x86,
-	0x79, 0x20, 0x13, 0x6a, 0xd0, 0x2e, 0x49, 0x49, 0x6c, 0x36, 0x99, 0xfd, 0x56, 0xbb, 0x5b, 0x07,
-	0xed, 0x26, 0x9b, 0x7d, 0x8f, 0xcd, 0x4b, 0x17, 0x97, 0xcb, 0x31, 0x3d, 0x50, 0xaa, 0xab, 0x20,
-	0xf9, 0x27, 0xb6, 0x1d, 0x1d, 0xfd, 0xd7, 0x45, 0x84, 0xf6, 0x6d, 0x84, 0x1b, 0x1b, 0xb5, 0x0d,
-	0x26, 0x7d, 0x84, 0x74, 0xb0, 0x43, 0xd0, 0x78, 0x9b, 0xfa, 0x05, 0x24, 0xda, 0x9e, 0x2b, 0x61,
-	0x9b, 0x8a, 0xb3, 0xe4, 0xd2, 0xa3, 0x93, 0xd3, 0x43, 0x5c, 0xcd, 0x83, 0xc9, 0x1d, 0x64, 0xf4,
-	0x50, 0x98, 0x52, 0x16, 0x48, 0xbc, 0x06, 0x9e, 0xd7, 0xfd, 0x61, 0x3c, 0x56, 0x9d, 0x01, 0x53,
-	0x41, 0x0c, 0x3f, 0x67, 0x75, 0x07, 0x2c, 0xee, 0xb9, 0xd8, 0x44, 0x84, 0xf8, 0x2c, 0x21, 0x46,
-	0xa3, 0xef, 0xb0, 0xce, 0x73, 0xf5, 0x66, 0x02, 0x93, 0x19, 0xcd, 0xbf, 0x04, 0x5a, 0x08, 0x86,
-	0xeb, 0xbf, 0x4a, 0xa7, 0x8f, 0xd5, 0x98, 0xba, 0x04, 0x94, 0xa8, 0x68, 0x81, 0xd7, 0xef, 0x60,
-	0x9e, 0x8d, 0x71, 0xab, 0x87, 0x72, 0xac, 0x7c, 0x1c, 0x0a, 0x7c, 0xc6, 0x29, 0x9c, 0xfa, 0x03,
-	0x58, 0x18, 0x54, 0x07, 0x75, 0x8f, 0x3a, 0x9b, 0x23, 0x30, 0x57, 0x72, 0x28, 0x72, 0x1d, 0xa3,
-	0xc5, 0xe3, 0x84, 0x4e, 0x0b, 0x40, 0xec, 0x9b, 0xc8, 0xcc, 0x44, 0x64, 0x06, 0x6c, 0x06, 0xfe,
-	0x0c, 0x64, 0xc3, 0xa4, 0x36, 0x76, 0x82, 0x43, 0x59, 0x8e, 0xaa, 0xe6, 0x3e, 0x65, 0x2d, 0x91,
-	0xf3, 0x30, 0x3d, 0xc0, 0xd5, 0xb7, 0x22, 0x48, 0xde, 0x9a, 0x87, 0xbf, 0xf5, 0x03, 0x71, 0x93,
-	0xe9, 0xec, 0xda, 0x3d, 0x81, 0xb6, 0x6d, 0xc7, 0x0a, 0x83, 0x41, 0x2d, 0x38, 0x51, 0xd1, 0x2b,
-	0x76, 0x2a, 0x4a, 0xca, 0x6f, 0xff, 0x1f, 0x31, 0xff, 0x34, 0x59, 0xd6, 0x09, 0x82, 0xdc, 0x9e,
-	0x6d, 0x22, 0xef, 0xfa, 0x27, 0xb3, 0xdf, 0x44, 0xba, 0xf9, 0x08, 0x53, 0x85, 0x34, 0x37, 0xa2,
-	0x06, 0x69, 0x06, 0xed, 0x11, 0x69, 0x54, 0x65, 0xeb, 0xdc, 0x88, 0x73, 0xdc, 0xc8, 0x41, 0xf4,
-	0x04, 0xbb, 0xcd, 0xd4, 0xc4, 0x70, 0xa3, 0xb2, 0x8f, 0x70, 0xa3, 0x80, 0xe6, 0x42, 0xb3, 0xd5,
-	0x25, 0xec, 0x20, 0x52, 0xf2, 0x70, 0x61, 0xc1, 0x47, 0xb8, 0x30, 0xa0, 0xf3, 0x5f, 0x00, 0x99,
-	0x1a, 0x6e, 0x03, 0xd1, 0x8d, 0x0f, 0x02, 0x98, 0x19, 0x28, 0x18, 0xfc, 0x0e, 0x24, 0x6a, 0xe5,
-	0xed, 0x72, 0xe5, 0xef, 0xf2, 0x6c, 0x4c, 0x51, 0xce, 0x9e, 0xae, 0x2c, 0x0c, 0x10, 0x35, 0xa7,
-	0xe9, 0xe0, 0x13, 0x87, 0xf5, 0xc8, 0xdc, 0x7e, 0xb5, 0xa2, 0x17, 0x0f, 0x73, 0x85, 0x6a, 0xa9,
-	0x52, 0x3e, 0x2c, 0xe8, 0xc5, 0x5c, 0xb5, 0x38, 0x2b, 0x28, 0x8b, 0x4c, 0x34, 0x3f, 0x20, 0x2a,
-	0xb8, 0xc8, 0xa0, 0xe8, 0x8e, 0xa6, 0xb6, 0xb7, 0xc5, 0x35, 0x62, 0xa4, 0xa6, 0xd6, 0xb1, 0xa2,
-	0x34, 0x7a, 0x71, 0xb7, 0xf2, 0x57, 0x71, 0x36, 0x1e, 0xa9, 0xd1, 0x51, 0x1b, 0xf7, 0x90, 0xf2,
-	0xf5, 0xc3, 0x67, 0xe9, 0xd8, 0x8b, 0xe7, 0xe9, 0xc1, 0xdd, 0x65, 0x1f, 0x89, 0x40, 0xe2, 0x97,
-	0x16, 0x9e, 0x09, 0x00, 0xde, 0xed, 0x27, 0xb8, 0x19, 0x55, 0xc3, 0xa1, 0x5d, 0xac, 0x68, 0xe3,
-	0xe2, 0x41, 0x9b, 0xce, 0xbf, 0x3c, 0x7f, 0xff, 0x44, 0x64, 0x2f, 0x85, 0xc7, 0x6f, 0xb6, 0x0d,
-	0x87, 0xad, 0xba, 0xf0, 0x01, 0x98, 0xfe, 0xbc, 0xff, 0xe0, 0x7a, 0xe4, 0x93, 0x13, 0xd5, 0xe1,
-	0xca, 0xc6, 0x38, 0xe8, 0x48, 0xff, 0xec, 0x6b, 0x81, 0x25, 0xd0, 0x7f, 0xcf, 0xc8, 0xb1, 0xdd,
-	0x81, 0xff, 0x00, 0x89, 0x3f, 0xc0, 0x30, 0xb2, 0x5b, 0x6f, 0xbd, 0xde, 0xca, 0xca, 0x70, 0x60,
-	0xf4, 0xa6, 0x4d, 0x30, 0xe1, 0xbd, 0x97, 0x30, 0x32, 0xc2, 0xed, 0xe7, 0x58, 0x59, 0x1d, 0x41,
-	0x8c, 0x34, 0xc9, 0x2f, 0x5d, 0x5c, 0xa5, 0x63, 0x6f, 0xd8, 0xf7, 0xf1, 0x2a, 0x2d, 0x9c, 0x5e,
-	0xa7, 0x85, 0x0b, 0xf6, 0xbd, 0x62, 0xdf, 0x3b, 0xf6, 0x1d, 0xc4, 0x0f, 0xa4, 0xba, 0xec, 0xfd,
-	0x13, 0xfd, 0xe9, 0x53, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa4, 0xfb, 0x14, 0x74, 0xdc, 0x07, 0x00,
-	0x00,
+	// 852 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x95, 0x4f, 0x53, 0x23, 0x45,
+	0x18, 0xc6, 0x33, 0x93, 0x61, 0xa2, 0x1d, 0x20, 0x54, 0x23, 0x18, 0x46, 0x2a, 0xc0, 0x60, 0x95,
+	0x42, 0xc9, 0xa4, 0x8c, 0x07, 0x2d, 0xf5, 0x92, 0x84, 0x54, 0x19, 0x81, 0x84, 0x1a, 0x12, 0xe5,
+	0x16, 0x27, 0x33, 0x4d, 0x18, 0x93, 0x4c, 0xc7, 0xe9, 0x4e, 0x28, 0x2f, 0x16, 0x47, 0x8b, 0xab,
+	0x55, 0xea, 0xc5, 0x93, 0x9e, 0xf9, 0x00, 0x7e, 0x02, 0x6a, 0x4f, 0x7b, 0xdb, 0x3d, 0xb1, 0x0b,
+	0x1f, 0x60, 0x77, 0x3f, 0xc2, 0x76, 0xcf, 0x9f, 0xc0, 0x86, 0x49, 0xc8, 0xa1, 0xa1, 0x79, 0xfb,
+	0xf7, 0xbc, 0x4f, 0xf7, 0xdb, 0xf3, 0x36, 0x00, 0xb8, 0xc6, 0x09, 0xd5, 0x7a, 0x2e, 0xa6, 0x18,
+	0x42, 0x0b, 0x9b, 0x6d, 0xe4, 0x6a, 0xe4, 0xcc, 0x70, 0xbb, 0x6d, 0x9b, 0x6a, 0x83, 0xcf, 0x95,
+	0x39, 0xdc, 0xfc, 0x19, 0x99, 0x94, 0xf8, 0x88, 0x92, 0xa4, 0xbf, 0xf6, 0x50, 0xf8, 0xc7, 0x4e,
+	0xcb, 0xa6, 0xa7, 0xfd, 0xa6, 0x66, 0xe2, 0x6e, 0xd6, 0xc4, 0x2e, 0xc2, 0x24, 0x8b, 0xa8, 0x69,
+	0x65, 0x79, 0x4a, 0xef, 0x47, 0xaf, 0x99, 0xbd, 0x4b, 0xaf, 0x7c, 0xd0, 0xc2, 0x2d, 0xec, 0x4d,
+	0xb3, 0x7c, 0x16, 0x44, 0x17, 0x7b, 0x9d, 0x7e, 0xcb, 0x76, 0xb2, 0xfe, 0x2f, 0x3f, 0xa8, 0x5e,
+	0x0a, 0x00, 0xe8, 0x4c, 0x79, 0x80, 0xba, 0x4d, 0xe4, 0xc2, 0x4d, 0x90, 0xe0, 0x79, 0x1a, 0xb6,
+	0x95, 0x16, 0xd6, 0x85, 0x4f, 0xa5, 0x02, 0xb8, 0xbd, 0x5e, 0x93, 0x39, 0x50, 0xde, 0xd5, 0x65,
+	0xbe, 0x54, 0xb6, 0x38, 0xe4, 0x60, 0x0b, 0x71, 0x48, 0x64, 0xd0, 0xfb, 0x3e, 0x54, 0x61, 0x21,
+	0x0e, 0xf1, 0x25, 0x06, 0x41, 0x20, 0x19, 0x96, 0xe5, 0xa6, 0xe3, 0x9c, 0xd0, 0xbd, 0x39, 0x2c,
+	0x00, 0x99, 0x50, 0x83, 0xf6, 0x49, 0x5a, 0x62, 0xd1, 0x64, 0xee, 0x63, 0xed, 0x61, 0x1d, 0xb4,
+	0xbb, 0xdd, 0x1c, 0x79, 0x6c, 0x41, 0xba, 0xba, 0x5e, 0x8b, 0xe9, 0x81, 0x52, 0xdd, 0x00, 0xc9,
+	0xef, 0xb1, 0xed, 0xe8, 0xe8, 0x97, 0x3e, 0x22, 0x74, 0x68, 0x23, 0xdc, 0xd9, 0xa8, 0x7f, 0x0a,
+	0x60, 0xd6, 0x67, 0x48, 0x0f, 0x3b, 0x04, 0x4d, 0x77, 0xaa, 0xaf, 0x40, 0xa2, 0xeb, 0xd9, 0x12,
+	0x76, 0xaa, 0x38, 0xdb, 0x5d, 0x66, 0xf2, 0xee, 0xf4, 0x10, 0x87, 0x9f, 0x80, 0x94, 0x8b, 0xba,
+	0x78, 0x80, 0xac, 0x46, 0x98, 0x21, 0xce, 0x32, 0x48, 0xfa, 0x7c, 0x10, 0xf6, 0x05, 0x44, 0x2d,
+	0x80, 0xd9, 0x7d, 0x64, 0x0c, 0x50, 0xb8, 0xf9, 0x1c, 0x90, 0x78, 0xb5, 0xbc, 0x4d, 0x3d, 0xee,
+	0xe7, 0xb1, 0x6a, 0x0a, 0xcc, 0x05, 0x39, 0xfc, 0xc3, 0xa9, 0xfb, 0x60, 0xe5, 0xd0, 0xc5, 0x26,
+	0x22, 0xc4, 0x67, 0x09, 0x31, 0x5a, 0x43, 0x87, 0x2d, 0x7e, 0x28, 0x2f, 0x12, 0x98, 0xa4, 0x34,
+	0xff, 0x73, 0xd1, 0x42, 0x30, 0x5c, 0xff, 0x5a, 0x3a, 0xff, 0x4b, 0x8d, 0xa9, 0xab, 0x40, 0x89,
+	0xca, 0x16, 0x78, 0x7d, 0x0b, 0x96, 0xd8, 0x1c, 0x77, 0x06, 0x28, 0xcf, 0x0a, 0xcd, 0xa1, 0xc0,
+	0x67, 0x9a, 0x0a, 0xab, 0x9f, 0x81, 0xe5, 0x51, 0x75, 0x70, 0x41, 0x51, 0xb7, 0x78, 0x02, 0x16,
+	0xcb, 0x0e, 0x45, 0xae, 0x63, 0x74, 0x78, 0x9e, 0xd0, 0x69, 0x19, 0x88, 0x43, 0x13, 0x99, 0x99,
+	0x88, 0xcc, 0x80, 0x45, 0xe0, 0x97, 0x40, 0x36, 0x4c, 0x6a, 0x63, 0x27, 0xb8, 0xbd, 0xb5, 0xa8,
+	0x6a, 0x1e, 0x51, 0xd6, 0x3c, 0x79, 0x0f, 0xd3, 0x03, 0x5c, 0x7d, 0x21, 0x82, 0xe4, 0xbd, 0x38,
+	0xfc, 0x66, 0x98, 0x88, 0x9b, 0xcc, 0xe7, 0x36, 0x1f, 0x49, 0xb4, 0x67, 0x3b, 0x56, 0x98, 0x0c,
+	0x6a, 0xc1, 0x8d, 0x8a, 0x5e, 0xb1, 0xd3, 0x51, 0x52, 0xde, 0x27, 0xdf, 0xc5, 0xfc, 0xdb, 0x64,
+	0xbb, 0x4e, 0x10, 0xe4, 0x0e, 0x6c, 0x13, 0x79, 0x8d, 0x92, 0xcc, 0x7d, 0x14, 0xe9, 0xe6, 0x23,
+	0x4c, 0x15, 0xd2, 0xdc, 0x88, 0x1a, 0xa4, 0x1d, 0x34, 0x52, 0xa4, 0x51, 0x8d, 0xad, 0x73, 0x23,
+	0xce, 0x71, 0x23, 0x07, 0xd1, 0x33, 0xec, 0xb6, 0xd3, 0x33, 0xe3, 0x8d, 0x2a, 0x3e, 0xc2, 0x8d,
+	0x02, 0x9a, 0x0b, 0xcd, 0x4e, 0x9f, 0xb0, 0x8b, 0x48, 0xcb, 0xe3, 0x85, 0x45, 0x1f, 0xe1, 0xc2,
+	0x80, 0x2e, 0xbc, 0x07, 0x64, 0x6a, 0xb8, 0x2d, 0x44, 0xb7, 0x5f, 0x0b, 0x20, 0x35, 0x52, 0x30,
+	0xd6, 0x33, 0x89, 0x7a, 0x65, 0xaf, 0x52, 0xfd, 0xb1, 0xb2, 0x10, 0x53, 0x94, 0x8b, 0x7f, 0xd6,
+	0x97, 0x47, 0x88, 0xba, 0xd3, 0x76, 0xf0, 0x99, 0xc3, 0x7a, 0x64, 0xf1, 0xa8, 0x56, 0xd5, 0x4b,
+	0x8d, 0x7c, 0xb1, 0x56, 0xae, 0x56, 0x1a, 0x45, 0xbd, 0x94, 0xaf, 0x95, 0x16, 0x04, 0x65, 0x85,
+	0x89, 0x96, 0x46, 0x44, 0x45, 0x17, 0x19, 0x14, 0x3d, 0xd0, 0xd4, 0x0f, 0x77, 0xb9, 0x46, 0x8c,
+	0xd4, 0xd4, 0x7b, 0x56, 0x94, 0x46, 0x2f, 0x1d, 0x54, 0x7f, 0x28, 0x2d, 0xc4, 0x23, 0x35, 0xba,
+	0xd7, 0xd7, 0xca, 0x87, 0xbf, 0xff, 0x9b, 0x89, 0xfd, 0xff, 0x5f, 0x66, 0xf4, 0x74, 0xb9, 0x3f,
+	0x44, 0x20, 0xf1, 0x8f, 0x16, 0x5e, 0x08, 0x00, 0x3e, 0xec, 0x27, 0xb8, 0x13, 0x55, 0xc3, 0xb1,
+	0x5d, 0xac, 0x68, 0xd3, 0xe2, 0x41, 0x9b, 0x2e, 0x3d, 0xb9, 0x7c, 0xf5, 0xb7, 0xc8, 0x5e, 0x0a,
+	0x8f, 0xdf, 0xe9, 0x1a, 0x0e, 0x5b, 0x75, 0xe1, 0x6f, 0x60, 0xfe, 0xdd, 0xfe, 0x83, 0x5b, 0x91,
+	0x4f, 0x4e, 0x54, 0x87, 0x2b, 0xdb, 0xd3, 0xa0, 0x13, 0xfd, 0x73, 0xcf, 0x04, 0xb6, 0x81, 0xe1,
+	0x7b, 0x46, 0x4e, 0xed, 0x1e, 0xfc, 0x09, 0x48, 0xfc, 0xa5, 0x86, 0x91, 0xdd, 0x7a, 0xef, 0x9d,
+	0x57, 0xd6, 0xc7, 0x03, 0x93, 0x0f, 0x6d, 0x82, 0x19, 0xef, 0xbd, 0x84, 0x91, 0x19, 0xee, 0x3f,
+	0xc7, 0xca, 0xc6, 0x04, 0x62, 0xa2, 0x49, 0x61, 0xf5, 0xea, 0x26, 0x13, 0x7b, 0xce, 0xc6, 0x9b,
+	0x9b, 0x8c, 0x70, 0x7e, 0x9b, 0x11, 0xae, 0xd8, 0x78, 0xca, 0xc6, 0x4b, 0x36, 0x8e, 0xe3, 0xc7,
+	0x52, 0x53, 0xf6, 0xfe, 0xdd, 0x7e, 0xf1, 0x36, 0x00, 0x00, 0xff, 0xff, 0xd7, 0x61, 0x3c, 0x43,
+	0x06, 0x08, 0x00, 0x00,
 }
 }

+ 7 - 0
vendor/src/github.com/docker/swarmkit/api/raft.proto

@@ -58,8 +58,15 @@ message JoinRequest {
 }
 }
 
 
 message JoinResponse {
 message JoinResponse {
+	// RaftID is the ID assigned to the new member.
 	uint64 raft_id = 1 [(gogoproto.customname) = "RaftID"];
 	uint64 raft_id = 1 [(gogoproto.customname) = "RaftID"];
+
+	// Members is the membership set of the cluster.
 	repeated RaftMember members = 2;
 	repeated RaftMember members = 2;
+
+	// RemovedMembers is a list of members that have been removed from
+	// the cluster, so the new node can avoid communicating with them.
+	repeated uint64 removed_members = 3;
 }
 }
 
 
 message LeaveRequest {
 message LeaveRequest {

+ 7 - 4
vendor/src/github.com/docker/swarmkit/api/specs.pb.go

@@ -268,7 +268,7 @@ func _ServiceSpec_OneofSizer(msg proto.Message) (n int) {
 // instructing Swarm on how this service should work on the particular
 // instructing Swarm on how this service should work on the particular
 // network.
 // network.
 type ServiceSpec_NetworkAttachmentConfig struct {
 type ServiceSpec_NetworkAttachmentConfig struct {
-	// Target specifies the target network for attachement. This value may be a
+	// Target specifies the target network for attachment. This value may be a
 	// network name or identifier. Only identifiers are supported at this time.
 	// network name or identifier. Only identifiers are supported at this time.
 	Target string `protobuf:"bytes,1,opt,name=target,proto3" json:"target,omitempty"`
 	Target string `protobuf:"bytes,1,opt,name=target,proto3" json:"target,omitempty"`
 	// Aliases specifies a list of discoverable alternate names for the service on this Target.
 	// Aliases specifies a list of discoverable alternate names for the service on this Target.
@@ -281,7 +281,7 @@ func (*ServiceSpec_NetworkAttachmentConfig) Descriptor() ([]byte, []int) {
 	return fileDescriptorSpecs, []int{1, 0}
 	return fileDescriptorSpecs, []int{1, 0}
 }
 }
 
 
-// ReplicatedService set the reconcilation target to certain number of replicas.
+// ReplicatedService sets the reconciliation target to certain number of replicas.
 type ReplicatedService struct {
 type ReplicatedService struct {
 	Replicas uint64 `protobuf:"varint,1,opt,name=replicas,proto3" json:"replicas,omitempty"`
 	Replicas uint64 `protobuf:"varint,1,opt,name=replicas,proto3" json:"replicas,omitempty"`
 }
 }
@@ -290,7 +290,7 @@ func (m *ReplicatedService) Reset()                    { *m = ReplicatedService{
 func (*ReplicatedService) ProtoMessage()               {}
 func (*ReplicatedService) ProtoMessage()               {}
 func (*ReplicatedService) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{2} }
 func (*ReplicatedService) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{2} }
 
 
-// GlobalService represent global service.
+// GlobalService represents global service.
 type GlobalService struct {
 type GlobalService struct {
 }
 }
 
 
@@ -415,9 +415,12 @@ type ContainerSpec struct {
 	// executable and the following elements are treated as arguments.
 	// executable and the following elements are treated as arguments.
 	//
 	//
 	// If command is empty, execution will fall back to the image's entrypoint.
 	// If command is empty, execution will fall back to the image's entrypoint.
+	//
+	// Command should only be used when overriding entrypoint.
 	Command []string `protobuf:"bytes,3,rep,name=command" json:"command,omitempty"`
 	Command []string `protobuf:"bytes,3,rep,name=command" json:"command,omitempty"`
 	// Args specifies arguments provided to the image's entrypoint.
 	// Args specifies arguments provided to the image's entrypoint.
-	// Ignored if command is specified.
+	//
+	// If Command and Args are provided, Args will be appended to Command.
 	Args []string `protobuf:"bytes,4,rep,name=args" json:"args,omitempty"`
 	Args []string `protobuf:"bytes,4,rep,name=args" json:"args,omitempty"`
 	// Env specifies the environment variables for the container in NAME=VALUE
 	// Env specifies the environment variables for the container in NAME=VALUE
 	// format. These must be compliant with  [IEEE Std
 	// format. These must be compliant with  [IEEE Std

+ 7 - 4
vendor/src/github.com/docker/swarmkit/api/specs.proto

@@ -78,7 +78,7 @@ message ServiceSpec {
 	// instructing Swarm on how this service should work on the particular
 	// instructing Swarm on how this service should work on the particular
 	// network.
 	// network.
 	message NetworkAttachmentConfig {
 	message NetworkAttachmentConfig {
-		// Target specifies the target network for attachement. This value may be a
+		// Target specifies the target network for attachment. This value may be a
 		// network name or identifier. Only identifiers are supported at this time.
 		// network name or identifier. Only identifiers are supported at this time.
 		string target = 1;
 		string target = 1;
 		// Aliases specifies a list of discoverable alternate names for the service on this Target.
 		// Aliases specifies a list of discoverable alternate names for the service on this Target.
@@ -91,12 +91,12 @@ message ServiceSpec {
 	EndpointSpec endpoint = 8;
 	EndpointSpec endpoint = 8;
 }
 }
 
 
-// ReplicatedService set the reconcilation target to certain number of replicas.
+// ReplicatedService sets the reconciliation target to certain number of replicas.
 message ReplicatedService {
 message ReplicatedService {
 	uint64 replicas = 1;
 	uint64 replicas = 1;
 }
 }
 
 
-// GlobalService represent global service.
+// GlobalService represents global service.
 message GlobalService {
 message GlobalService {
 	// Empty message for now.
 	// Empty message for now.
 }
 }
@@ -138,10 +138,13 @@ message ContainerSpec {
 	// executable and the following elements are treated as arguments.
 	// executable and the following elements are treated as arguments.
 	//
 	//
 	// If command is empty, execution will fall back to the image's entrypoint.
 	// If command is empty, execution will fall back to the image's entrypoint.
+	//
+	// Command should only be used when overriding entrypoint.
 	repeated string command = 3;
 	repeated string command = 3;
 
 
 	// Args specifies arguments provided to the image's entrypoint.
 	// Args specifies arguments provided to the image's entrypoint.
-	// Ignored if command is specified.
+	//
+	// If Command and Args are provided, Args will be appended to Command.
 	repeated string args = 4;
 	repeated string args = 4;
 
 
 	// Env specifies the environment variables for the container in NAME=VALUE
 	// Env specifies the environment variables for the container in NAME=VALUE

+ 646 - 194
vendor/src/github.com/docker/swarmkit/api/types.pb.go

@@ -14,6 +14,7 @@
 		ca.proto
 		ca.proto
 		snapshot.proto
 		snapshot.proto
 		raft.proto
 		raft.proto
+		health.proto
 
 
 	It has these top-level messages:
 	It has these top-level messages:
 		Version
 		Version
@@ -40,6 +41,7 @@
 		WeightedPeer
 		WeightedPeer
 		IssuanceStatus
 		IssuanceStatus
 		AcceptancePolicy
 		AcceptancePolicy
+		ExternalCA
 		CAConfig
 		CAConfig
 		OrchestrationConfig
 		OrchestrationConfig
 		DispatcherConfig
 		DispatcherConfig
@@ -132,6 +134,8 @@
 		ResolveAddressResponse
 		ResolveAddressResponse
 		InternalRaftRequest
 		InternalRaftRequest
 		StoreAction
 		StoreAction
+		HealthCheckRequest
+		HealthCheckResponse
 */
 */
 package api
 package api
 
 
@@ -462,6 +466,26 @@ func (x IssuanceStatus_State) String() string {
 }
 }
 func (IssuanceStatus_State) EnumDescriptor() ([]byte, []int) { return fileDescriptorTypes, []int{22, 0} }
 func (IssuanceStatus_State) EnumDescriptor() ([]byte, []int) { return fileDescriptorTypes, []int{22, 0} }
 
 
+type ExternalCA_CAProtocol int32
+
+const (
+	ExternalCA_CAProtocolCFSSL ExternalCA_CAProtocol = 0
+)
+
+var ExternalCA_CAProtocol_name = map[int32]string{
+	0: "CFSSL",
+}
+var ExternalCA_CAProtocol_value = map[string]int32{
+	"CFSSL": 0,
+}
+
+func (x ExternalCA_CAProtocol) String() string {
+	return proto.EnumName(ExternalCA_CAProtocol_name, int32(x))
+}
+func (ExternalCA_CAProtocol) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptorTypes, []int{24, 0}
+}
+
 // Encryption algorithm that can implemented using this key
 // Encryption algorithm that can implemented using this key
 type EncryptionKey_Algorithm int32
 type EncryptionKey_Algorithm int32
 
 
@@ -480,7 +504,7 @@ func (x EncryptionKey_Algorithm) String() string {
 	return proto.EnumName(EncryptionKey_Algorithm_name, int32(x))
 	return proto.EnumName(EncryptionKey_Algorithm_name, int32(x))
 }
 }
 func (EncryptionKey_Algorithm) EnumDescriptor() ([]byte, []int) {
 func (EncryptionKey_Algorithm) EnumDescriptor() ([]byte, []int) {
-	return fileDescriptorTypes, []int{31, 0}
+	return fileDescriptorTypes, []int{32, 0}
 }
 }
 
 
 // Version tracks the last time an object in the store was updated.
 // Version tracks the last time an object in the store was updated.
@@ -955,14 +979,31 @@ func (*AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) Descriptor() ([]byte,
 	return fileDescriptorTypes, []int{23, 0, 0}
 	return fileDescriptorTypes, []int{23, 0, 0}
 }
 }
 
 
+type ExternalCA struct {
+	// Protocol is the protocol used by this external CA.
+	Protocol ExternalCA_CAProtocol `protobuf:"varint,1,opt,name=protocol,proto3,enum=docker.swarmkit.v1.ExternalCA_CAProtocol" json:"protocol,omitempty"`
+	// URL is the URL where the external CA can be reached.
+	URL string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
+	// Options is a set of additional key/value pairs whose interpretation
+	// depends on the specified CA type.
+	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"`
+}
+
+func (m *ExternalCA) Reset()                    { *m = ExternalCA{} }
+func (*ExternalCA) ProtoMessage()               {}
+func (*ExternalCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{24} }
+
 type CAConfig struct {
 type CAConfig struct {
 	// NodeCertExpiry is the duration certificates should be issued for
 	// NodeCertExpiry is the duration certificates should be issued for
 	NodeCertExpiry *docker_swarmkit_v11.Duration `protobuf:"bytes,1,opt,name=node_cert_expiry,json=nodeCertExpiry" json:"node_cert_expiry,omitempty"`
 	NodeCertExpiry *docker_swarmkit_v11.Duration `protobuf:"bytes,1,opt,name=node_cert_expiry,json=nodeCertExpiry" json:"node_cert_expiry,omitempty"`
+	// ExternalCAs is a list of CAs to which a manager node will make
+	// certificate signing requests for node certificates.
+	ExternalCAs []*ExternalCA `protobuf:"bytes,2,rep,name=external_cas,json=externalCas" json:"external_cas,omitempty"`
 }
 }
 
 
 func (m *CAConfig) Reset()                    { *m = CAConfig{} }
 func (m *CAConfig) Reset()                    { *m = CAConfig{} }
 func (*CAConfig) ProtoMessage()               {}
 func (*CAConfig) ProtoMessage()               {}
-func (*CAConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{24} }
+func (*CAConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{25} }
 
 
 // OrchestrationConfig defines cluster-level orchestration settings.
 // OrchestrationConfig defines cluster-level orchestration settings.
 type OrchestrationConfig struct {
 type OrchestrationConfig struct {
@@ -973,7 +1014,7 @@ type OrchestrationConfig struct {
 
 
 func (m *OrchestrationConfig) Reset()                    { *m = OrchestrationConfig{} }
 func (m *OrchestrationConfig) Reset()                    { *m = OrchestrationConfig{} }
 func (*OrchestrationConfig) ProtoMessage()               {}
 func (*OrchestrationConfig) ProtoMessage()               {}
-func (*OrchestrationConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{25} }
+func (*OrchestrationConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{26} }
 
 
 // DispatcherConfig defines cluster-level dispatcher settings.
 // DispatcherConfig defines cluster-level dispatcher settings.
 type DispatcherConfig struct {
 type DispatcherConfig struct {
@@ -984,7 +1025,7 @@ type DispatcherConfig struct {
 
 
 func (m *DispatcherConfig) Reset()                    { *m = DispatcherConfig{} }
 func (m *DispatcherConfig) Reset()                    { *m = DispatcherConfig{} }
 func (*DispatcherConfig) ProtoMessage()               {}
 func (*DispatcherConfig) ProtoMessage()               {}
-func (*DispatcherConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{26} }
+func (*DispatcherConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{27} }
 
 
 // RaftConfig defines raft settings for the cluster.
 // RaftConfig defines raft settings for the cluster.
 type RaftConfig struct {
 type RaftConfig struct {
@@ -1006,7 +1047,7 @@ type RaftConfig struct {
 
 
 func (m *RaftConfig) Reset()                    { *m = RaftConfig{} }
 func (m *RaftConfig) Reset()                    { *m = RaftConfig{} }
 func (*RaftConfig) ProtoMessage()               {}
 func (*RaftConfig) ProtoMessage()               {}
-func (*RaftConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{27} }
+func (*RaftConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{28} }
 
 
 // Placement specifies task distribution constraints.
 // Placement specifies task distribution constraints.
 type Placement struct {
 type Placement struct {
@@ -1016,7 +1057,7 @@ type Placement struct {
 
 
 func (m *Placement) Reset()                    { *m = Placement{} }
 func (m *Placement) Reset()                    { *m = Placement{} }
 func (*Placement) ProtoMessage()               {}
 func (*Placement) ProtoMessage()               {}
-func (*Placement) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{28} }
+func (*Placement) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{29} }
 
 
 type RootCA struct {
 type RootCA struct {
 	// CAKey is the root CA private key.
 	// CAKey is the root CA private key.
@@ -1029,7 +1070,7 @@ type RootCA struct {
 
 
 func (m *RootCA) Reset()                    { *m = RootCA{} }
 func (m *RootCA) Reset()                    { *m = RootCA{} }
 func (*RootCA) ProtoMessage()               {}
 func (*RootCA) ProtoMessage()               {}
-func (*RootCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{29} }
+func (*RootCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{30} }
 
 
 type Certificate struct {
 type Certificate struct {
 	Role        NodeRole       `protobuf:"varint,1,opt,name=role,proto3,enum=docker.swarmkit.v1.NodeRole" json:"role,omitempty"`
 	Role        NodeRole       `protobuf:"varint,1,opt,name=role,proto3,enum=docker.swarmkit.v1.NodeRole" json:"role,omitempty"`
@@ -1042,7 +1083,7 @@ type Certificate struct {
 
 
 func (m *Certificate) Reset()                    { *m = Certificate{} }
 func (m *Certificate) Reset()                    { *m = Certificate{} }
 func (*Certificate) ProtoMessage()               {}
 func (*Certificate) ProtoMessage()               {}
-func (*Certificate) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{30} }
+func (*Certificate) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{31} }
 
 
 // Symmetric keys to encrypt inter-agent communication.
 // Symmetric keys to encrypt inter-agent communication.
 type EncryptionKey struct {
 type EncryptionKey struct {
@@ -1058,7 +1099,7 @@ type EncryptionKey struct {
 
 
 func (m *EncryptionKey) Reset()                    { *m = EncryptionKey{} }
 func (m *EncryptionKey) Reset()                    { *m = EncryptionKey{} }
 func (*EncryptionKey) ProtoMessage()               {}
 func (*EncryptionKey) ProtoMessage()               {}
-func (*EncryptionKey) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{31} }
+func (*EncryptionKey) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{32} }
 
 
 // ManagerStatus provides informations about the state of a manager in the cluster.
 // ManagerStatus provides informations about the state of a manager in the cluster.
 type ManagerStatus struct {
 type ManagerStatus struct {
@@ -1075,7 +1116,7 @@ type ManagerStatus struct {
 
 
 func (m *ManagerStatus) Reset()                    { *m = ManagerStatus{} }
 func (m *ManagerStatus) Reset()                    { *m = ManagerStatus{} }
 func (*ManagerStatus) ProtoMessage()               {}
 func (*ManagerStatus) ProtoMessage()               {}
-func (*ManagerStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{32} }
+func (*ManagerStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{33} }
 
 
 func init() {
 func init() {
 	proto.RegisterType((*Version)(nil), "docker.swarmkit.v1.Version")
 	proto.RegisterType((*Version)(nil), "docker.swarmkit.v1.Version")
@@ -1106,6 +1147,7 @@ func init() {
 	proto.RegisterType((*AcceptancePolicy)(nil), "docker.swarmkit.v1.AcceptancePolicy")
 	proto.RegisterType((*AcceptancePolicy)(nil), "docker.swarmkit.v1.AcceptancePolicy")
 	proto.RegisterType((*AcceptancePolicy_RoleAdmissionPolicy)(nil), "docker.swarmkit.v1.AcceptancePolicy.RoleAdmissionPolicy")
 	proto.RegisterType((*AcceptancePolicy_RoleAdmissionPolicy)(nil), "docker.swarmkit.v1.AcceptancePolicy.RoleAdmissionPolicy")
 	proto.RegisterType((*AcceptancePolicy_RoleAdmissionPolicy_HashedSecret)(nil), "docker.swarmkit.v1.AcceptancePolicy.RoleAdmissionPolicy.HashedSecret")
 	proto.RegisterType((*AcceptancePolicy_RoleAdmissionPolicy_HashedSecret)(nil), "docker.swarmkit.v1.AcceptancePolicy.RoleAdmissionPolicy.HashedSecret")
+	proto.RegisterType((*ExternalCA)(nil), "docker.swarmkit.v1.ExternalCA")
 	proto.RegisterType((*CAConfig)(nil), "docker.swarmkit.v1.CAConfig")
 	proto.RegisterType((*CAConfig)(nil), "docker.swarmkit.v1.CAConfig")
 	proto.RegisterType((*OrchestrationConfig)(nil), "docker.swarmkit.v1.OrchestrationConfig")
 	proto.RegisterType((*OrchestrationConfig)(nil), "docker.swarmkit.v1.OrchestrationConfig")
 	proto.RegisterType((*DispatcherConfig)(nil), "docker.swarmkit.v1.DispatcherConfig")
 	proto.RegisterType((*DispatcherConfig)(nil), "docker.swarmkit.v1.DispatcherConfig")
@@ -1125,6 +1167,7 @@ func init() {
 	proto.RegisterEnum("docker.swarmkit.v1.IPAMConfig_AddressFamily", IPAMConfig_AddressFamily_name, IPAMConfig_AddressFamily_value)
 	proto.RegisterEnum("docker.swarmkit.v1.IPAMConfig_AddressFamily", IPAMConfig_AddressFamily_name, IPAMConfig_AddressFamily_value)
 	proto.RegisterEnum("docker.swarmkit.v1.PortConfig_Protocol", PortConfig_Protocol_name, PortConfig_Protocol_value)
 	proto.RegisterEnum("docker.swarmkit.v1.PortConfig_Protocol", PortConfig_Protocol_name, PortConfig_Protocol_value)
 	proto.RegisterEnum("docker.swarmkit.v1.IssuanceStatus_State", IssuanceStatus_State_name, IssuanceStatus_State_value)
 	proto.RegisterEnum("docker.swarmkit.v1.IssuanceStatus_State", IssuanceStatus_State_name, IssuanceStatus_State_value)
+	proto.RegisterEnum("docker.swarmkit.v1.ExternalCA_CAProtocol", ExternalCA_CAProtocol_name, ExternalCA_CAProtocol_value)
 	proto.RegisterEnum("docker.swarmkit.v1.EncryptionKey_Algorithm", EncryptionKey_Algorithm_name, EncryptionKey_Algorithm_value)
 	proto.RegisterEnum("docker.swarmkit.v1.EncryptionKey_Algorithm", EncryptionKey_Algorithm_name, EncryptionKey_Algorithm_value)
 }
 }
 
 
@@ -1564,6 +1607,26 @@ func (m *AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) Copy() *AcceptancePo
 	return o
 	return o
 }
 }
 
 
+func (m *ExternalCA) Copy() *ExternalCA {
+	if m == nil {
+		return nil
+	}
+
+	o := &ExternalCA{
+		Protocol: m.Protocol,
+		URL:      m.URL,
+	}
+
+	if m.Options != nil {
+		o.Options = make(map[string]string)
+		for k, v := range m.Options {
+			o.Options[k] = v
+		}
+	}
+
+	return o
+}
+
 func (m *CAConfig) Copy() *CAConfig {
 func (m *CAConfig) Copy() *CAConfig {
 	if m == nil {
 	if m == nil {
 		return nil
 		return nil
@@ -1573,6 +1636,13 @@ func (m *CAConfig) Copy() *CAConfig {
 		NodeCertExpiry: m.NodeCertExpiry.Copy(),
 		NodeCertExpiry: m.NodeCertExpiry.Copy(),
 	}
 	}
 
 
+	if m.ExternalCAs != nil {
+		o.ExternalCAs = make([]*ExternalCA, 0, len(m.ExternalCAs))
+		for _, v := range m.ExternalCAs {
+			o.ExternalCAs = append(o.ExternalCAs, v.Copy())
+		}
+	}
+
 	return o
 	return o
 }
 }
 
 
@@ -2122,15 +2192,42 @@ func (this *AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) GoString() string
 	s = append(s, "}")
 	s = append(s, "}")
 	return strings.Join(s, "")
 	return strings.Join(s, "")
 }
 }
+func (this *ExternalCA) GoString() string {
+	if this == nil {
+		return "nil"
+	}
+	s := make([]string, 0, 7)
+	s = append(s, "&api.ExternalCA{")
+	s = append(s, "Protocol: "+fmt.Sprintf("%#v", this.Protocol)+",\n")
+	s = append(s, "URL: "+fmt.Sprintf("%#v", this.URL)+",\n")
+	keysForOptions := make([]string, 0, len(this.Options))
+	for k, _ := range this.Options {
+		keysForOptions = append(keysForOptions, k)
+	}
+	github_com_gogo_protobuf_sortkeys.Strings(keysForOptions)
+	mapStringForOptions := "map[string]string{"
+	for _, k := range keysForOptions {
+		mapStringForOptions += fmt.Sprintf("%#v: %#v,", k, this.Options[k])
+	}
+	mapStringForOptions += "}"
+	if this.Options != nil {
+		s = append(s, "Options: "+mapStringForOptions+",\n")
+	}
+	s = append(s, "}")
+	return strings.Join(s, "")
+}
 func (this *CAConfig) GoString() string {
 func (this *CAConfig) GoString() string {
 	if this == nil {
 	if this == nil {
 		return "nil"
 		return "nil"
 	}
 	}
-	s := make([]string, 0, 5)
+	s := make([]string, 0, 6)
 	s = append(s, "&api.CAConfig{")
 	s = append(s, "&api.CAConfig{")
 	if this.NodeCertExpiry != nil {
 	if this.NodeCertExpiry != nil {
 		s = append(s, "NodeCertExpiry: "+fmt.Sprintf("%#v", this.NodeCertExpiry)+",\n")
 		s = append(s, "NodeCertExpiry: "+fmt.Sprintf("%#v", this.NodeCertExpiry)+",\n")
 	}
 	}
+	if this.ExternalCAs != nil {
+		s = append(s, "ExternalCAs: "+fmt.Sprintf("%#v", this.ExternalCAs)+",\n")
+	}
 	s = append(s, "}")
 	s = append(s, "}")
 	return strings.Join(s, "")
 	return strings.Join(s, "")
 }
 }
@@ -3341,6 +3438,52 @@ func (m *AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) MarshalTo(data []byt
 	return i, nil
 	return i, nil
 }
 }
 
 
+func (m *ExternalCA) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+func (m *ExternalCA) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if m.Protocol != 0 {
+		data[i] = 0x8
+		i++
+		i = encodeVarintTypes(data, i, uint64(m.Protocol))
+	}
+	if len(m.URL) > 0 {
+		data[i] = 0x12
+		i++
+		i = encodeVarintTypes(data, i, uint64(len(m.URL)))
+		i += copy(data[i:], m.URL)
+	}
+	if len(m.Options) > 0 {
+		for k, _ := range m.Options {
+			data[i] = 0x1a
+			i++
+			v := m.Options[k]
+			mapSize := 1 + len(k) + sovTypes(uint64(len(k))) + 1 + len(v) + sovTypes(uint64(len(v)))
+			i = encodeVarintTypes(data, i, uint64(mapSize))
+			data[i] = 0xa
+			i++
+			i = encodeVarintTypes(data, i, uint64(len(k)))
+			i += copy(data[i:], k)
+			data[i] = 0x12
+			i++
+			i = encodeVarintTypes(data, i, uint64(len(v)))
+			i += copy(data[i:], v)
+		}
+	}
+	return i, nil
+}
+
 func (m *CAConfig) Marshal() (data []byte, err error) {
 func (m *CAConfig) Marshal() (data []byte, err error) {
 	size := m.Size()
 	size := m.Size()
 	data = make([]byte, size)
 	data = make([]byte, size)
@@ -3366,6 +3509,18 @@ func (m *CAConfig) MarshalTo(data []byte) (int, error) {
 		}
 		}
 		i += n18
 		i += n18
 	}
 	}
+	if len(m.ExternalCAs) > 0 {
+		for _, msg := range m.ExternalCAs {
+			data[i] = 0x12
+			i++
+			i = encodeVarintTypes(data, i, uint64(msg.Size()))
+			n, err := msg.MarshalTo(data[i:])
+			if err != nil {
+				return 0, err
+			}
+			i += n
+		}
+	}
 	return i, nil
 	return i, nil
 }
 }
 
 
@@ -4161,6 +4316,27 @@ func (m *AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) Size() (n int) {
 	return n
 	return n
 }
 }
 
 
+func (m *ExternalCA) Size() (n int) {
+	var l int
+	_ = l
+	if m.Protocol != 0 {
+		n += 1 + sovTypes(uint64(m.Protocol))
+	}
+	l = len(m.URL)
+	if l > 0 {
+		n += 1 + l + sovTypes(uint64(l))
+	}
+	if len(m.Options) > 0 {
+		for k, v := range m.Options {
+			_ = k
+			_ = v
+			mapEntrySize := 1 + len(k) + sovTypes(uint64(len(k))) + 1 + len(v) + sovTypes(uint64(len(v)))
+			n += mapEntrySize + 1 + sovTypes(uint64(mapEntrySize))
+		}
+	}
+	return n
+}
+
 func (m *CAConfig) Size() (n int) {
 func (m *CAConfig) Size() (n int) {
 	var l int
 	var l int
 	_ = l
 	_ = l
@@ -4168,6 +4344,12 @@ func (m *CAConfig) Size() (n int) {
 		l = m.NodeCertExpiry.Size()
 		l = m.NodeCertExpiry.Size()
 		n += 1 + l + sovTypes(uint64(l))
 		n += 1 + l + sovTypes(uint64(l))
 	}
 	}
+	if len(m.ExternalCAs) > 0 {
+		for _, e := range m.ExternalCAs {
+			l = e.Size()
+			n += 1 + l + sovTypes(uint64(l))
+		}
+	}
 	return n
 	return n
 }
 }
 
 
@@ -4701,12 +4883,35 @@ func (this *AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) String() string {
 	}, "")
 	}, "")
 	return s
 	return s
 }
 }
+func (this *ExternalCA) String() string {
+	if this == nil {
+		return "nil"
+	}
+	keysForOptions := make([]string, 0, len(this.Options))
+	for k, _ := range this.Options {
+		keysForOptions = append(keysForOptions, k)
+	}
+	github_com_gogo_protobuf_sortkeys.Strings(keysForOptions)
+	mapStringForOptions := "map[string]string{"
+	for _, k := range keysForOptions {
+		mapStringForOptions += fmt.Sprintf("%v: %v,", k, this.Options[k])
+	}
+	mapStringForOptions += "}"
+	s := strings.Join([]string{`&ExternalCA{`,
+		`Protocol:` + fmt.Sprintf("%v", this.Protocol) + `,`,
+		`URL:` + fmt.Sprintf("%v", this.URL) + `,`,
+		`Options:` + mapStringForOptions + `,`,
+		`}`,
+	}, "")
+	return s
+}
 func (this *CAConfig) String() string {
 func (this *CAConfig) String() string {
 	if this == nil {
 	if this == nil {
 		return "nil"
 		return "nil"
 	}
 	}
 	s := strings.Join([]string{`&CAConfig{`,
 	s := strings.Join([]string{`&CAConfig{`,
 		`NodeCertExpiry:` + strings.Replace(fmt.Sprintf("%v", this.NodeCertExpiry), "Duration", "docker_swarmkit_v11.Duration", 1) + `,`,
 		`NodeCertExpiry:` + strings.Replace(fmt.Sprintf("%v", this.NodeCertExpiry), "Duration", "docker_swarmkit_v11.Duration", 1) + `,`,
+		`ExternalCAs:` + strings.Replace(fmt.Sprintf("%v", this.ExternalCAs), "ExternalCA", "ExternalCA", 1) + `,`,
 		`}`,
 		`}`,
 	}, "")
 	}, "")
 	return s
 	return s
@@ -8574,6 +8779,215 @@ func (m *AcceptancePolicy_RoleAdmissionPolicy_HashedSecret) Unmarshal(data []byt
 	}
 	}
 	return nil
 	return nil
 }
 }
+func (m *ExternalCA) Unmarshal(data []byte) error {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowTypes
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: ExternalCA: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: ExternalCA: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Protocol", wireType)
+			}
+			m.Protocol = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTypes
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				m.Protocol |= (ExternalCA_CAProtocol(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field URL", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTypes
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthTypes
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.URL = string(data[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Options", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTypes
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthTypes
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			var keykey uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTypes
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				keykey |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			var stringLenmapkey uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTypes
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLenmapkey |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLenmapkey := int(stringLenmapkey)
+			if intStringLenmapkey < 0 {
+				return ErrInvalidLengthTypes
+			}
+			postStringIndexmapkey := iNdEx + intStringLenmapkey
+			if postStringIndexmapkey > l {
+				return io.ErrUnexpectedEOF
+			}
+			mapkey := string(data[iNdEx:postStringIndexmapkey])
+			iNdEx = postStringIndexmapkey
+			var valuekey uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTypes
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				valuekey |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			var stringLenmapvalue uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTypes
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLenmapvalue |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLenmapvalue := int(stringLenmapvalue)
+			if intStringLenmapvalue < 0 {
+				return ErrInvalidLengthTypes
+			}
+			postStringIndexmapvalue := iNdEx + intStringLenmapvalue
+			if postStringIndexmapvalue > l {
+				return io.ErrUnexpectedEOF
+			}
+			mapvalue := string(data[iNdEx:postStringIndexmapvalue])
+			iNdEx = postStringIndexmapvalue
+			if m.Options == nil {
+				m.Options = make(map[string]string)
+			}
+			m.Options[mapkey] = mapvalue
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipTypes(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthTypes
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
 func (m *CAConfig) Unmarshal(data []byte) error {
 func (m *CAConfig) Unmarshal(data []byte) error {
 	l := len(data)
 	l := len(data)
 	iNdEx := 0
 	iNdEx := 0
@@ -8636,6 +9050,37 @@ func (m *CAConfig) Unmarshal(data []byte) error {
 				return err
 				return err
 			}
 			}
 			iNdEx = postIndex
 			iNdEx = postIndex
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ExternalCAs", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTypes
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthTypes
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.ExternalCAs = append(m.ExternalCAs, &ExternalCA{})
+			if err := m.ExternalCAs[len(m.ExternalCAs)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		default:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
 			skippy, err := skipTypes(data[iNdEx:])
 			skippy, err := skipTypes(data[iNdEx:])
@@ -9755,188 +10200,195 @@ var (
 )
 )
 
 
 var fileDescriptorTypes = []byte{
 var fileDescriptorTypes = []byte{
-	// 2925 bytes of a gzipped FileDescriptorProto
+	// 3030 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x58, 0x4d, 0x6c, 0x1b, 0xc7,
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x58, 0x4d, 0x6c, 0x1b, 0xc7,
-	0xf5, 0x37, 0x3f, 0x45, 0x0e, 0x29, 0x89, 0x5e, 0x3b, 0x8e, 0xcc, 0xe8, 0x2f, 0xfb, 0xbf, 0x89,
-	0x1b, 0x37, 0x49, 0x99, 0x58, 0x49, 0x0b, 0x37, 0x41, 0x9b, 0x2c, 0x3f, 0x64, 0xb1, 0x96, 0x28,
-	0x62, 0x48, 0xc9, 0x08, 0x8a, 0x96, 0x58, 0x2d, 0x47, 0xe2, 0x46, 0xcb, 0x5d, 0x76, 0x77, 0x29,
-	0x99, 0x28, 0x0a, 0x38, 0xbd, 0xb4, 0xc8, 0xa9, 0xf7, 0x22, 0x28, 0x8a, 0xf6, 0xda, 0x73, 0x81,
-	0x9e, 0x7c, 0xf4, 0xb1, 0x45, 0x81, 0x22, 0xa7, 0xa0, 0x49, 0x0f, 0xbd, 0x16, 0x68, 0xd1, 0x1c,
-	0xda, 0x43, 0xdf, 0x9b, 0x8f, 0xe5, 0x87, 0xd7, 0x8a, 0xd3, 0xf4, 0x40, 0x70, 0xe7, 0xcd, 0xef,
-	0xbd, 0x99, 0x37, 0xf3, 0xe6, 0xfd, 0xde, 0x0c, 0x29, 0x84, 0x93, 0x11, 0x0b, 0x2a, 0x23, 0xdf,
-	0x0b, 0x3d, 0x4d, 0xeb, 0x7b, 0xd6, 0x09, 0xf3, 0x2b, 0xc1, 0x99, 0xe9, 0x0f, 0x4f, 0xec, 0xb0,
-	0x72, 0x7a, 0xab, 0x7c, 0x35, 0xb4, 0x87, 0x2c, 0x08, 0xcd, 0xe1, 0xe8, 0xd5, 0xe8, 0x4b, 0xc0,
-	0xcb, 0xcf, 0xf6, 0xc7, 0xbe, 0x19, 0xda, 0x9e, 0xfb, 0xaa, 0xfa, 0x90, 0x1d, 0x97, 0x8f, 0xbd,
-	0x63, 0x8f, 0x7f, 0xbe, 0x8a, 0x5f, 0x42, 0xaa, 0x5f, 0x23, 0x4b, 0x07, 0xcc, 0x0f, 0x00, 0xa6,
-	0x5d, 0x26, 0x19, 0xdb, 0xed, 0xb3, 0xfb, 0x6b, 0x89, 0xeb, 0x89, 0x9b, 0x69, 0x2a, 0x1a, 0xfa,
-	0x2f, 0x13, 0xa4, 0x60, 0xb8, 0xae, 0x17, 0x72, 0x5b, 0x81, 0xa6, 0x91, 0xb4, 0x6b, 0x0e, 0x19,
-	0x07, 0xe5, 0x29, 0xff, 0xd6, 0x6a, 0x24, 0xeb, 0x98, 0x87, 0xcc, 0x09, 0xd6, 0x92, 0xd7, 0x53,
-	0x37, 0x0b, 0x9b, 0x2f, 0x57, 0x1e, 0x9f, 0x73, 0x65, 0xc6, 0x48, 0x65, 0x87, 0xa3, 0x1b, 0x6e,
-	0xe8, 0x4f, 0xa8, 0x54, 0x2d, 0x7f, 0x93, 0x14, 0x66, 0xc4, 0x5a, 0x89, 0xa4, 0x4e, 0xd8, 0x44,
-	0x0e, 0x83, 0x9f, 0x38, 0xbf, 0x53, 0xd3, 0x19, 0x33, 0x18, 0x04, 0x65, 0xa2, 0xf1, 0x66, 0xf2,
-	0x76, 0x42, 0x7f, 0x97, 0xe4, 0x29, 0x0b, 0xbc, 0xb1, 0x6f, 0xb1, 0x40, 0xfb, 0x2a, 0xc9, 0xbb,
-	0xa6, 0xeb, 0xf5, 0xac, 0xd1, 0x38, 0xe0, 0xea, 0xa9, 0x6a, 0xf1, 0xd3, 0x8f, 0xaf, 0xe5, 0x5a,
-	0x20, 0xac, 0xb5, 0xf7, 0x03, 0x9a, 0xc3, 0xee, 0x1a, 0xf4, 0x6a, 0xff, 0x4f, 0x8a, 0x43, 0x36,
-	0xf4, 0xfc, 0x49, 0xef, 0x70, 0x12, 0xb2, 0x80, 0x1b, 0x4e, 0xd1, 0x82, 0x90, 0x55, 0x51, 0xa4,
-	0xff, 0x2c, 0x41, 0x2e, 0x2b, 0xdb, 0x94, 0xfd, 0x60, 0x6c, 0xfb, 0x6c, 0xc8, 0xdc, 0x30, 0xd0,
-	0xbe, 0x0e, 0x3e, 0xdb, 0x43, 0x3b, 0x14, 0x63, 0x14, 0x36, 0xff, 0x2f, 0xce, 0xe7, 0x68, 0x56,
-	0x54, 0x82, 0x35, 0x83, 0x14, 0x7d, 0x16, 0x30, 0xff, 0x54, 0xac, 0x04, 0x1f, 0xf2, 0x73, 0x95,
-	0xe7, 0x54, 0xf4, 0x2d, 0x92, 0x6b, 0x3b, 0x66, 0x78, 0xe4, 0xf9, 0x43, 0x4d, 0x27, 0x45, 0xd3,
-	0xb7, 0x06, 0x76, 0xc8, 0xac, 0x70, 0xec, 0xab, 0x5d, 0x99, 0x93, 0x69, 0x57, 0x48, 0xd2, 0x13,
-	0x03, 0xe5, 0xab, 0x59, 0x58, 0x89, 0xe4, 0x5e, 0x87, 0x82, 0x44, 0x7f, 0x8b, 0x5c, 0x6c, 0x3b,
-	0xe3, 0x63, 0xdb, 0xad, 0xb3, 0xc0, 0xf2, 0xed, 0x11, 0x5a, 0xc7, 0xed, 0xc5, 0xe0, 0x53, 0xdb,
-	0x8b, 0xdf, 0xd1, 0x96, 0x27, 0xa7, 0x5b, 0xae, 0xff, 0x24, 0x49, 0x2e, 0x36, 0x5c, 0x50, 0x66,
-	0xb3, 0xda, 0x37, 0xc8, 0x0a, 0xe3, 0xc2, 0xde, 0xa9, 0x08, 0x2a, 0x69, 0x67, 0x59, 0x48, 0x55,
-	0xa4, 0x35, 0x17, 0xe2, 0xe5, 0x56, 0x9c, 0xfb, 0x8f, 0x59, 0x8f, 0x8b, 0x1a, 0xad, 0x41, 0x96,
-	0x46, 0xdc, 0x89, 0x60, 0x2d, 0xc5, 0x6d, 0xdd, 0x88, 0xb3, 0xf5, 0x98, 0x9f, 0xd5, 0xf4, 0xa3,
-	0x8f, 0xaf, 0x5d, 0xa0, 0x4a, 0xf7, 0xcb, 0x04, 0xdf, 0x5f, 0x12, 0x64, 0xb5, 0xe5, 0xf5, 0xe7,
-	0xd6, 0xa1, 0x4c, 0x72, 0x03, 0x2f, 0x08, 0x67, 0x0e, 0x4a, 0xd4, 0xd6, 0x6e, 0x93, 0xdc, 0x48,
-	0x6e, 0x9f, 0xdc, 0xfd, 0xf5, 0xf8, 0x29, 0x0b, 0x0c, 0x8d, 0xd0, 0xda, 0x5b, 0x24, 0xef, 0xab,
-	0x98, 0x00, 0x6f, 0x9f, 0x22, 0x70, 0xa6, 0x78, 0xed, 0x5b, 0x24, 0x2b, 0x36, 0x61, 0x2d, 0xcd,
-	0x35, 0x6f, 0x3c, 0xd5, 0x9a, 0x53, 0xa9, 0xa4, 0x7f, 0x94, 0x20, 0x25, 0x6a, 0x1e, 0x85, 0xbb,
-	0x6c, 0x78, 0xc8, 0xfc, 0x0e, 0x1c, 0x64, 0x38, 0x3f, 0x57, 0x60, 0x1f, 0x99, 0xd9, 0x67, 0x3e,
-	0x77, 0x32, 0x47, 0x65, 0x4b, 0xdb, 0xc7, 0x20, 0x37, 0xad, 0x81, 0x79, 0x68, 0x3b, 0x76, 0x38,
-	0xe1, 0x6e, 0xae, 0xc4, 0xef, 0xf2, 0xa2, 0x4d, 0x98, 0xfc, 0x54, 0x91, 0xce, 0x99, 0xd1, 0xd6,
-	0xc8, 0x12, 0xe4, 0xba, 0xc0, 0x3c, 0x66, 0xdc, 0xfb, 0x3c, 0x55, 0x4d, 0x08, 0xe5, 0xe2, 0xac,
-	0x9e, 0x56, 0x20, 0x4b, 0xfb, 0xad, 0xbb, 0xad, 0xbd, 0x7b, 0xad, 0xd2, 0x05, 0x6d, 0x95, 0x14,
-	0xf6, 0x5b, 0xb4, 0x61, 0xd4, 0xb6, 0x8d, 0xea, 0x4e, 0xa3, 0x94, 0xd0, 0x96, 0x21, 0x5d, 0x44,
-	0xcd, 0xa4, 0xfe, 0x8b, 0x04, 0x21, 0xb8, 0x81, 0xd2, 0xa9, 0x37, 0x49, 0x06, 0xf2, 0x69, 0x28,
-	0x36, 0x6e, 0x65, 0xf3, 0x85, 0xb8, 0x59, 0x4f, 0xe1, 0x15, 0xfc, 0x63, 0x54, 0xa8, 0xcc, 0xce,
-	0x30, 0xb9, 0x38, 0xc3, 0x0c, 0x47, 0xce, 0x4f, 0x2d, 0x47, 0xd2, 0x75, 0xfc, 0x4a, 0x68, 0x79,
-	0x92, 0x81, 0x39, 0xd5, 0xdf, 0x2d, 0x25, 0x21, 0xf8, 0x8a, 0xf5, 0x66, 0xa7, 0xb6, 0xd7, 0x6a,
-	0x35, 0x6a, 0xdd, 0x46, 0xbd, 0x94, 0xd2, 0x6f, 0x90, 0x4c, 0x73, 0x08, 0x56, 0xb4, 0x75, 0x8c,
-	0x80, 0x23, 0xe6, 0x33, 0xd7, 0x52, 0x81, 0x35, 0x15, 0xe8, 0xff, 0x5c, 0x22, 0x99, 0x5d, 0x6f,
-	0xec, 0x86, 0xda, 0xe6, 0xcc, 0x29, 0x5e, 0xd9, 0xdc, 0x88, 0x73, 0x81, 0x03, 0x2b, 0x5d, 0x40,
-	0xc9, 0x53, 0x0e, 0x9b, 0x29, 0x62, 0x45, 0x4e, 0x5d, 0xb6, 0x50, 0x1e, 0x9a, 0xfe, 0x31, 0x0b,
-	0xe5, 0xa2, 0xcb, 0x16, 0xc6, 0xf8, 0x99, 0x6f, 0x87, 0xe6, 0xa1, 0x23, 0x42, 0x2a, 0x47, 0xa3,
-	0xb6, 0xb6, 0x4d, 0x8a, 0x87, 0x40, 0x1f, 0x3d, 0x6f, 0x24, 0xb2, 0x5c, 0xe6, 0xc9, 0x21, 0x27,
-	0xe6, 0x51, 0x05, 0xf4, 0x9e, 0x00, 0xd3, 0xc2, 0xe1, 0xb4, 0xa1, 0xb5, 0xc8, 0xca, 0xa9, 0xe7,
-	0x8c, 0x87, 0x2c, 0xb2, 0x95, 0xe5, 0xb6, 0x5e, 0x7c, 0xb2, 0xad, 0x03, 0x8e, 0x57, 0xd6, 0x96,
-	0x4f, 0x67, 0x9b, 0xe5, 0x1f, 0xa7, 0x48, 0x61, 0x66, 0x30, 0xad, 0x43, 0x0a, 0x40, 0x84, 0x23,
-	0xf3, 0x98, 0x27, 0x57, 0xb9, 0x60, 0xb7, 0x9e, 0x6a, 0xa2, 0x95, 0xf6, 0x54, 0x91, 0xce, 0x5a,
-	0xd1, 0x3f, 0x4c, 0x92, 0xc2, 0x4c, 0xa7, 0xf6, 0x12, 0xc9, 0xd1, 0x36, 0x6d, 0x1e, 0x18, 0xdd,
-	0x46, 0xe9, 0x42, 0x79, 0xfd, 0x83, 0x0f, 0xaf, 0xaf, 0x71, 0x6b, 0xb3, 0x06, 0xda, 0xbe, 0x7d,
-	0x8a, 0xf1, 0x71, 0x93, 0x2c, 0x29, 0x68, 0xa2, 0xfc, 0x1c, 0x40, 0x9f, 0x5d, 0x84, 0xce, 0x20,
-	0x69, 0x67, 0xdb, 0xa0, 0x10, 0x22, 0xc9, 0x78, 0x24, 0xed, 0x0c, 0x4c, 0x9f, 0xf5, 0xb5, 0xaf,
-	0x90, 0xac, 0x04, 0xa6, 0xca, 0x65, 0x00, 0x5e, 0x59, 0x04, 0x4e, 0x71, 0xb4, 0xb3, 0x63, 0x1c,
-	0x34, 0x4a, 0xe9, 0x78, 0x1c, 0xed, 0x38, 0xe6, 0x29, 0xd3, 0x5e, 0x80, 0x60, 0xe6, 0xb0, 0x4c,
-	0xf9, 0x2a, 0xc0, 0x9e, 0x79, 0xcc, 0x1c, 0xa2, 0xca, 0x6b, 0x3f, 0xfd, 0xd5, 0xc6, 0x85, 0xdf,
-	0xfd, 0x7a, 0xa3, 0xb4, 0xd8, 0x5d, 0xfe, 0x47, 0x82, 0x2c, 0xcf, 0xed, 0x12, 0x06, 0xd3, 0xc8,
-	0x1b, 0x8d, 0x1d, 0x75, 0xee, 0x20, 0x98, 0x54, 0x5b, 0xbb, 0xbb, 0xc0, 0x16, 0xaf, 0x3f, 0xe5,
-	0xd6, 0xc7, 0xf2, 0xc5, 0xdb, 0x64, 0xb9, 0x0f, 0xeb, 0xc7, 0xfc, 0x9e, 0xe5, 0xb9, 0x47, 0xf6,
-	0xb1, 0xcc, 0xa3, 0xe5, 0x38, 0x9b, 0x75, 0x0e, 0xa4, 0x45, 0xa1, 0x50, 0xe3, 0xf8, 0x2f, 0xc3,
-	0x14, 0xf7, 0x48, 0x1a, 0xcf, 0x9b, 0xf6, 0x1c, 0x49, 0x57, 0x9b, 0xad, 0x3a, 0x84, 0xc2, 0x45,
-	0x58, 0xbd, 0x65, 0x3e, 0x75, 0xec, 0xc0, 0xd8, 0xd2, 0xae, 0x91, 0xec, 0xc1, 0xde, 0xce, 0xfe,
-	0x2e, 0x6e, 0xff, 0x25, 0xe8, 0x5e, 0x8d, 0xba, 0x85, 0x73, 0xe5, 0x8b, 0x72, 0x59, 0xf3, 0x51,
-	0x87, 0xfe, 0xaf, 0x24, 0x59, 0xa6, 0x58, 0x05, 0xfa, 0x61, 0xdb, 0x73, 0x6c, 0x6b, 0xa2, 0xb5,
-	0x49, 0x1e, 0xfc, 0xeb, 0xdb, 0x33, 0x41, 0xbd, 0xf9, 0x04, 0xaa, 0x98, 0x6a, 0xa9, 0x56, 0x4d,
-	0x69, 0xd2, 0xa9, 0x11, 0x48, 0x29, 0x99, 0x3e, 0x73, 0xcc, 0xc9, 0x79, 0x9c, 0x55, 0x97, 0x15,
-	0x27, 0x15, 0x50, 0x5e, 0x5f, 0x99, 0xf7, 0x7b, 0x66, 0x18, 0xb2, 0xe1, 0x28, 0x14, 0x9c, 0x95,
-	0x86, 0xfa, 0xca, 0xbc, 0x6f, 0x48, 0x91, 0xf6, 0x06, 0xc9, 0x9e, 0x81, 0xdb, 0xde, 0x99, 0xa4,
-	0xa5, 0xf3, 0xed, 0x4a, 0xac, 0xfe, 0x01, 0xb2, 0xd1, 0xc2, 0x64, 0x71, 0x59, 0x5b, 0x7b, 0xad,
-	0x86, 0x5a, 0x56, 0xd9, 0xbf, 0xe7, 0xb6, 0x3c, 0x17, 0x43, 0x96, 0xec, 0xb5, 0x7a, 0x5b, 0x46,
-	0x73, 0x67, 0x9f, 0xe2, 0xd2, 0x5e, 0x06, 0x48, 0x29, 0x82, 0x6c, 0x99, 0xb6, 0x83, 0xa5, 0xd2,
-	0x55, 0x92, 0x32, 0x5a, 0x90, 0x83, 0xcb, 0x25, 0xe8, 0x2e, 0x46, 0xdd, 0x86, 0x3b, 0x99, 0x46,
-	0xf3, 0xe2, 0xb8, 0xfa, 0x7b, 0xa4, 0xb8, 0x3f, 0xea, 0x43, 0xa4, 0x8a, 0x08, 0xd1, 0xae, 0x43,
-	0x4a, 0x31, 0x7d, 0xd3, 0x71, 0x98, 0x63, 0x07, 0x43, 0x59, 0x4d, 0xcf, 0x8a, 0xa0, 0x04, 0x78,
-	0xfa, 0xb5, 0x94, 0x95, 0x8a, 0x50, 0xd0, 0x7f, 0x44, 0x56, 0x61, 0x94, 0xd0, 0x04, 0x4a, 0x56,
-	0x24, 0xbc, 0x49, 0x8a, 0x96, 0x12, 0xf5, 0xec, 0xbe, 0x08, 0xc5, 0xea, 0x2a, 0x14, 0x7a, 0x85,
-	0x08, 0xda, 0xac, 0xd3, 0x42, 0x04, 0x6a, 0xf6, 0xd1, 0xcf, 0x11, 0x40, 0x71, 0xf8, 0x4c, 0x75,
-	0x09, 0xa0, 0xa9, 0x36, 0x40, 0x50, 0x06, 0xab, 0x98, 0x67, 0xf7, 0xed, 0x10, 0x8e, 0x47, 0x5f,
-	0xd0, 0x6c, 0x86, 0xe6, 0x50, 0x50, 0x83, 0xb6, 0xfe, 0x7e, 0x92, 0x90, 0xae, 0x19, 0x9c, 0xc8,
-	0xa1, 0xa1, 0x20, 0x89, 0xae, 0x1f, 0xe7, 0x95, 0xc1, 0x5d, 0x05, 0xa2, 0x53, 0xbc, 0xf6, 0xba,
-	0xe2, 0x59, 0x51, 0x1d, 0xc4, 0x2b, 0xca, 0xb1, 0xe2, 0x08, 0x76, 0xbe, 0x04, 0xc0, 0x83, 0xc8,
-	0x7c, 0x9f, 0x47, 0x11, 0x1c, 0x44, 0xf8, 0x84, 0x5b, 0x49, 0x3e, 0xf2, 0x59, 0x32, 0xd0, 0xf3,
-	0x71, 0x83, 0x2c, 0x2c, 0xe8, 0xf6, 0x05, 0x3a, 0xd5, 0xab, 0x96, 0xc8, 0x8a, 0x0f, 0xc7, 0x0c,
-	0x66, 0xdd, 0x0b, 0x78, 0xb7, 0xfe, 0x47, 0x58, 0x83, 0x66, 0xdb, 0xd8, 0x95, 0xbb, 0x5d, 0x27,
-	0xd9, 0x23, 0x73, 0x68, 0x3b, 0x13, 0x79, 0xcc, 0x5e, 0x89, 0x1b, 0x62, 0x8a, 0xaf, 0x18, 0xfd,
-	0x3e, 0x14, 0x65, 0xc1, 0x16, 0xd7, 0xa1, 0x52, 0x97, 0x93, 0xef, 0xf8, 0xd0, 0x05, 0x92, 0x55,
-	0xe4, 0xcb, 0x5b, 0x98, 0x4c, 0x7c, 0xd3, 0x8d, 0xbc, 0x15, 0x0d, 0x5c, 0x05, 0xc8, 0xa4, 0xec,
-	0x0c, 0x22, 0x48, 0xf8, 0xab, 0x9a, 0x40, 0xbc, 0x39, 0x71, 0x57, 0x60, 0x7d, 0x70, 0x19, 0xb3,
-	0xe5, 0xe7, 0xcd, 0x87, 0x4a, 0xb8, 0x48, 0x93, 0x91, 0x76, 0xf9, 0x2d, 0x9e, 0x52, 0xa6, 0x5d,
-	0x5f, 0x28, 0xd3, 0xbd, 0x46, 0x96, 0xe7, 0xfc, 0x7c, 0xac, 0xea, 0x69, 0xb6, 0x0f, 0xde, 0x28,
-	0xa5, 0xe5, 0xd7, 0x37, 0x4a, 0x59, 0xfd, 0xef, 0x50, 0x84, 0xb5, 0x3d, 0x7e, 0xac, 0x70, 0x55,
-	0xe3, 0x6f, 0x99, 0x39, 0x7e, 0x67, 0xb5, 0x3c, 0x47, 0xc6, 0x4c, 0x6c, 0x11, 0x30, 0xb5, 0x82,
-	0x04, 0xcd, 0xe1, 0x34, 0x52, 0x84, 0xf4, 0x5a, 0x10, 0xf5, 0x4b, 0x6f, 0x04, 0x38, 0xbe, 0xac,
-	0xcb, 0x94, 0x08, 0x11, 0x6a, 0xe2, 0x15, 0x66, 0x34, 0x3e, 0x84, 0x63, 0x3a, 0x60, 0x7d, 0x81,
-	0x49, 0x73, 0xcc, 0x72, 0x24, 0x45, 0x98, 0x5e, 0x87, 0x4b, 0x98, 0xb2, 0xb9, 0x46, 0x52, 0xdd,
-	0x5a, 0x1b, 0xf2, 0xce, 0x2a, 0x64, 0x8d, 0x82, 0x12, 0x83, 0x08, 0x7b, 0xf6, 0xeb, 0x6d, 0x48,
-	0x37, 0x73, 0x3d, 0x20, 0x2a, 0xa7, 0x31, 0x9d, 0xe8, 0x3f, 0x4f, 0x90, 0xac, 0x60, 0x99, 0x58,
-	0x8f, 0x0d, 0xb2, 0xa4, 0xaa, 0x1e, 0x41, 0x7d, 0x2f, 0x3e, 0x99, 0xa6, 0x2a, 0x92, 0xf5, 0xc4,
-	0x3e, 0x2a, 0xbd, 0xf2, 0x9b, 0xa4, 0x38, 0xdb, 0xf1, 0x85, 0x76, 0xf1, 0x87, 0xa4, 0x80, 0x81,
-	0xa2, 0x38, 0x7a, 0x93, 0x64, 0x05, 0x13, 0xca, 0xa3, 0x7e, 0x1e, 0x67, 0x4a, 0x24, 0x64, 0xba,
-	0x25, 0xc1, 0xb3, 0xea, 0x7a, 0xb6, 0x71, 0x7e, 0x38, 0x52, 0x05, 0xd7, 0xdf, 0x26, 0xe9, 0x36,
-	0x03, 0x0b, 0xcf, 0x93, 0x25, 0x17, 0x52, 0xcf, 0x34, 0xb3, 0x11, 0x48, 0x57, 0x59, 0x2c, 0xc0,
-	0x21, 0x63, 0x65, 0xb1, 0x0b, 0xf2, 0x19, 0x2c, 0x9e, 0x09, 0xf1, 0xa6, 0x6e, 0xa8, 0xf8, 0xad,
-	0x77, 0x49, 0xf1, 0x1e, 0xb3, 0x8f, 0x07, 0x21, 0xec, 0x18, 0x1a, 0x7a, 0x85, 0xa4, 0x47, 0x2c,
-	0x9a, 0xfc, 0x5a, 0x6c, 0xe8, 0x40, 0x3f, 0xe5, 0x28, 0x3c, 0x90, 0x67, 0x5c, 0x5b, 0x3e, 0x0a,
-	0xc8, 0x96, 0xfe, 0x9b, 0x24, 0x59, 0x69, 0x06, 0xc1, 0xd8, 0x84, 0x82, 0x5b, 0x66, 0xc1, 0x6f,
-	0xcf, 0x5f, 0x18, 0x6e, 0xc6, 0x7a, 0x38, 0xa7, 0x32, 0x7f, 0x69, 0x90, 0x99, 0x2b, 0x19, 0x65,
-	0x2e, 0xfd, 0x51, 0x42, 0xdd, 0x16, 0x6e, 0xcc, 0x9c, 0x9b, 0xf2, 0x1a, 0x04, 0xd1, 0xe5, 0x59,
-	0x4b, 0x6c, 0xdf, 0x3d, 0x71, 0xbd, 0x33, 0x17, 0x88, 0x16, 0x6e, 0x0f, 0xad, 0xc6, 0x3d, 0x88,
-	0xb4, 0x2b, 0x00, 0xd2, 0xe6, 0x40, 0x94, 0xb9, 0xec, 0x0c, 0x2d, 0xb5, 0x1b, 0xad, 0x7a, 0xb3,
-	0x75, 0x07, 0xe8, 0xed, 0x71, 0x4b, 0x6d, 0x06, 0x74, 0xe6, 0x1e, 0xc3, 0x72, 0x67, 0x9b, 0x9d,
-	0xce, 0x3e, 0x2f, 0x15, 0x9f, 0x05, 0xd4, 0xa5, 0x39, 0x14, 0x36, 0xa0, 0x4e, 0x04, 0x10, 0x32,
-	0x29, 0x80, 0xd2, 0x31, 0x20, 0x24, 0x53, 0x48, 0x20, 0x22, 0xc2, 0xff, 0x9a, 0x24, 0x25, 0xc3,
-	0xb2, 0xd8, 0x28, 0xc4, 0x7e, 0x59, 0x9d, 0x74, 0xb1, 0xda, 0x83, 0x2f, 0x9b, 0xe1, 0xeb, 0x09,
-	0x86, 0xc5, 0xed, 0xd8, 0x17, 0xa3, 0x05, 0xbd, 0x0a, 0xf5, 0x1c, 0x66, 0xf4, 0x87, 0x76, 0x80,
-	0xaf, 0x08, 0x42, 0x46, 0x23, 0x4b, 0xe5, 0x7f, 0x27, 0xc8, 0xa5, 0x18, 0x84, 0xf6, 0x1a, 0x49,
-	0xfb, 0x20, 0x96, 0xdb, 0xb3, 0xfe, 0xa4, 0xfb, 0x1c, 0xaa, 0x52, 0x8e, 0xd4, 0x36, 0x08, 0x31,
-	0xc7, 0xa1, 0x67, 0xf2, 0xf1, 0xf9, 0xc6, 0xe4, 0xe8, 0x8c, 0x44, 0xfb, 0x1e, 0x64, 0x6b, 0x66,
-	0xf9, 0xf2, 0x4a, 0x54, 0xd8, 0x6c, 0xfc, 0xb7, 0xb3, 0xaf, 0x6c, 0x9b, 0x98, 0x51, 0x3a, 0xdc,
-	0x18, 0x95, 0x46, 0xcb, 0x6f, 0x90, 0xe2, 0xac, 0x1c, 0xa3, 0x1b, 0xca, 0x0b, 0x93, 0x3b, 0x50,
-	0xa4, 0xfc, 0x1b, 0x83, 0xc6, 0x74, 0x8e, 0x55, 0xd0, 0xc0, 0xa7, 0x4e, 0x49, 0xae, 0x66, 0xc8,
-	0xf4, 0xb9, 0x45, 0x4a, 0xfc, 0xd0, 0x58, 0xcc, 0x0f, 0x7b, 0xec, 0xfe, 0xc8, 0xf6, 0x27, 0x32,
-	0xee, 0xcf, 0xaf, 0xaf, 0x56, 0x50, 0xab, 0x06, 0x4a, 0x0d, 0xae, 0xa3, 0x1f, 0x90, 0x4b, 0x7b,
-	0xbe, 0x35, 0x00, 0xc6, 0x16, 0x00, 0x69, 0xfe, 0x6d, 0xb2, 0x1e, 0x02, 0x33, 0xf7, 0x06, 0x76,
-	0x10, 0xe2, 0xeb, 0x19, 0x4c, 0x92, 0xb9, 0xd8, 0xdf, 0xe3, 0xaf, 0x5c, 0xe2, 0xd5, 0x8d, 0x5e,
-	0x45, 0xcc, 0xb6, 0x80, 0x50, 0x85, 0xd8, 0x41, 0x80, 0xfe, 0x5d, 0x52, 0xaa, 0xdb, 0xc1, 0xc8,
-	0x0c, 0xc1, 0xb6, 0x2c, 0xac, 0xb5, 0x3b, 0xa4, 0x34, 0x60, 0x50, 0x58, 0x1d, 0x32, 0x13, 0x92,
-	0x33, 0xf3, 0x6d, 0xaf, 0xff, 0x54, 0x73, 0x5e, 0x8d, 0xb4, 0xda, 0x5c, 0x49, 0xff, 0x0c, 0xa8,
-	0x04, 0x9f, 0x15, 0xa4, 0xdd, 0x97, 0xc9, 0xc5, 0xc0, 0x35, 0x47, 0xc1, 0xc0, 0x0b, 0x7b, 0xb6,
-	0x1b, 0xe2, 0x3b, 0x9a, 0x23, 0x8b, 0xb2, 0x92, 0xea, 0x68, 0x4a, 0x39, 0x24, 0x09, 0xed, 0x84,
-	0xb1, 0x51, 0xcf, 0x73, 0xfa, 0x3d, 0xd5, 0x29, 0xde, 0xce, 0x00, 0x8d, 0x3d, 0x7b, 0x4e, 0xbf,
-	0xa3, 0xe4, 0x5a, 0x95, 0x6c, 0x38, 0xde, 0x71, 0x0f, 0x3c, 0xf3, 0x21, 0x00, 0x7b, 0x47, 0x9e,
-	0xdf, 0x0b, 0x1c, 0xef, 0x0c, 0x3e, 0x1c, 0xf8, 0x63, 0xbe, 0xaa, 0x78, 0xcb, 0x80, 0x6a, 0x08,
-	0xd0, 0x96, 0xe7, 0x77, 0xa0, 0x6f, 0x4b, 0x21, 0x90, 0x6f, 0xa6, 0x6e, 0x87, 0xb6, 0x75, 0xa2,
-	0xf8, 0x26, 0x92, 0x76, 0x41, 0x08, 0x47, 0x6e, 0x99, 0x39, 0xcc, 0xe2, 0x8b, 0xcc, 0x51, 0x19,
-	0x8e, 0x2a, 0x2a, 0x21, 0x82, 0xf4, 0xaf, 0x91, 0x7c, 0xdb, 0x31, 0x2d, 0xfe, 0x42, 0x89, 0x65,
-	0x28, 0xe4, 0x52, 0xdc, 0x39, 0xf0, 0x5a, 0x9c, 0xb3, 0x3c, 0x9d, 0x15, 0xe9, 0xef, 0x03, 0xfb,
-	0x50, 0xcf, 0x0b, 0x6b, 0x06, 0x80, 0xb3, 0x96, 0xd9, 0x53, 0xcc, 0x50, 0xac, 0xe6, 0x21, 0xc9,
-	0x66, 0x6a, 0xc6, 0x5d, 0x36, 0xa1, 0x19, 0xcb, 0x84, 0x3f, 0xcc, 0xc3, 0x80, 0xc0, 0x80, 0xe2,
-	0xcb, 0x51, 0x14, 0x79, 0x18, 0x22, 0x0e, 0x24, 0x14, 0x94, 0xf1, 0x1f, 0x8e, 0x5a, 0x51, 0x82,
-	0x7a, 0x03, 0x88, 0x60, 0x51, 0xb5, 0x54, 0x57, 0x00, 0x49, 0x04, 0x12, 0xe3, 0x9a, 0x12, 0x81,
-	0xc6, 0x6f, 0xfd, 0x4f, 0x09, 0x52, 0xc0, 0x86, 0x7d, 0x64, 0x5b, 0x98, 0xf0, 0xbe, 0xf8, 0x61,
-	0x85, 0x5a, 0xd6, 0x0a, 0x7c, 0x39, 0x29, 0x5e, 0xcb, 0xd6, 0x3a, 0x94, 0xa2, 0x4c, 0x7b, 0x07,
-	0xce, 0x29, 0x4f, 0xb8, 0xf2, 0x9c, 0xea, 0x9f, 0x9f, 0x9a, 0x65, 0xb9, 0x2d, 0xf5, 0xf8, 0x22,
-	0x4e, 0x67, 0xc7, 0xb7, 0xa6, 0x48, 0x67, 0x45, 0xf8, 0xba, 0x6a, 0xb9, 0x7c, 0x37, 0xe4, 0xeb,
-	0x6a, 0xad, 0x45, 0x41, 0xa2, 0xff, 0x01, 0xee, 0xb8, 0x0d, 0xd7, 0xf2, 0x27, 0x9c, 0x3d, 0x71,
-	0x05, 0xd7, 0x49, 0x1e, 0xaa, 0xba, 0x60, 0x12, 0xc0, 0xd5, 0x47, 0x3d, 0xde, 0x44, 0x02, 0xad,
-	0x49, 0xf2, 0x70, 0x8a, 0x3d, 0xdf, 0x0e, 0x07, 0x43, 0x59, 0xde, 0xbc, 0x1c, 0xff, 0x44, 0x37,
-	0x63, 0xb3, 0x62, 0x28, 0x15, 0x3a, 0xd5, 0x56, 0x1c, 0x9f, 0xe2, 0x93, 0xe5, 0x1c, 0x0f, 0x17,
-	0x31, 0x07, 0x6a, 0x6e, 0x28, 0x5c, 0x7a, 0x58, 0xca, 0x72, 0x3f, 0xe0, 0x4e, 0x22, 0x65, 0x58,
-	0x9e, 0xeb, 0x3a, 0xc9, 0x47, 0xc6, 0xf0, 0xc9, 0xcc, 0x68, 0x74, 0x7a, 0xb7, 0x36, 0x6f, 0xf7,
-	0xee, 0xd4, 0x76, 0x81, 0x7a, 0x44, 0x32, 0xff, 0x2d, 0xf8, 0xb4, 0x6b, 0xba, 0x50, 0x6e, 0xab,
-	0xcb, 0x07, 0x44, 0x85, 0x0f, 0x47, 0x4d, 0xb1, 0x73, 0x5a, 0x44, 0x05, 0x9e, 0x3e, 0x64, 0x67,
-	0xec, 0x8a, 0x67, 0xe7, 0x99, 0xa7, 0xc3, 0xd4, 0xb9, 0x4f, 0x87, 0xe9, 0xff, 0xc9, 0xd3, 0xe1,
-	0x4b, 0x9f, 0xa5, 0x48, 0x3e, 0xba, 0x4c, 0x60, 0xc8, 0x20, 0x59, 0x5e, 0x10, 0xd7, 0xbc, 0x48,
-	0xde, 0xe2, 0x34, 0x99, 0x37, 0x76, 0x76, 0xf6, 0x6a, 0x06, 0xbe, 0xbc, 0xbd, 0x23, 0xd8, 0x34,
-	0x02, 0x18, 0x70, 0x68, 0x71, 0xd3, 0xfb, 0x9a, 0x3e, 0x65, 0xd3, 0x07, 0xf2, 0x32, 0x19, 0xa1,
-	0x14, 0x95, 0xbe, 0x40, 0x72, 0x46, 0xa7, 0xd3, 0xbc, 0xd3, 0x02, 0x4b, 0x0f, 0x13, 0xe5, 0x67,
-	0x00, 0x74, 0x71, 0x6a, 0x0a, 0x58, 0xe0, 0xd8, 0x05, 0x4b, 0x88, 0xaa, 0xd5, 0x1a, 0x6d, 0x1c,
-	0xef, 0x41, 0x72, 0x11, 0xc5, 0x39, 0x84, 0xbf, 0xcc, 0xe4, 0xdb, 0xb4, 0xd1, 0x36, 0x28, 0x8e,
-	0xf8, 0x30, 0xb9, 0x30, 0xaf, 0xb6, 0xcf, 0xe0, 0x7a, 0x89, 0x63, 0x6e, 0xa8, 0x67, 0xc4, 0x07,
-	0xa9, 0xb2, 0x06, 0x98, 0x95, 0xe9, 0x0d, 0x0a, 0xd6, 0x77, 0x82, 0xa3, 0x75, 0xba, 0x06, 0xed,
-	0x72, 0x33, 0xa9, 0x85, 0xd1, 0x3a, 0x78, 0xaf, 0x45, 0x2b, 0xe0, 0x1d, 0xdd, 0x6f, 0xb5, 0xb8,
-	0x77, 0xe9, 0x05, 0xef, 0xe8, 0xd8, 0x75, 0x11, 0x73, 0x03, 0xe8, 0x66, 0x6f, 0xb7, 0xbd, 0xd3,
-	0xe8, 0x36, 0x4a, 0x0f, 0xd3, 0x0b, 0x13, 0xaa, 0x79, 0xc3, 0x91, 0xc3, 0x42, 0xe1, 0x5e, 0x67,
-	0x7b, 0xbf, 0xcb, 0x5f, 0x39, 0x1f, 0x64, 0x16, 0x07, 0x1c, 0x8c, 0xc3, 0x3e, 0xd6, 0x2f, 0xd7,
-	0xa3, 0x82, 0xe2, 0x61, 0x46, 0xbc, 0x7a, 0x44, 0x18, 0x51, 0x4d, 0xa0, 0x1d, 0xda, 0xf8, 0x8e,
-	0x78, 0x10, 0x7d, 0x90, 0x5d, 0xb0, 0x43, 0xd9, 0x7b, 0x90, 0x05, 0xa1, 0xe6, 0x88, 0xde, 0x46,
-	0xa2, 0xae, 0x97, 0xbe, 0x4f, 0x72, 0x2a, 0x61, 0xc0, 0xea, 0x64, 0xef, 0xed, 0xd1, 0xbb, 0x0d,
-	0x0a, 0x5b, 0xcf, 0x57, 0x47, 0xf5, 0xdc, 0xf3, 0x7c, 0x88, 0x2e, 0x98, 0xc6, 0xd2, 0xae, 0xd1,
-	0x32, 0xee, 0x00, 0x40, 0x3e, 0xbe, 0x28, 0x80, 0x8c, 0xfa, 0x72, 0x49, 0x0e, 0x10, 0xd9, 0xac,
-	0xae, 0x3f, 0xfa, 0x64, 0xe3, 0xc2, 0x47, 0xf0, 0xfb, 0xdb, 0x27, 0x1b, 0x89, 0x07, 0x9f, 0x6e,
-	0x24, 0x1e, 0xc1, 0xef, 0xf7, 0xf0, 0xfb, 0x33, 0xfc, 0x0e, 0xb3, 0xfc, 0xe2, 0xf1, 0xfa, 0x7f,
-	0x02, 0x00, 0x00, 0xff, 0xff, 0x35, 0xa0, 0x81, 0xdd, 0xd2, 0x1b, 0x00, 0x00,
+	0xf5, 0x17, 0x3f, 0x45, 0x0e, 0x29, 0x89, 0x5e, 0x3b, 0x8e, 0xcc, 0xe8, 0x2f, 0xfb, 0xbf, 0x89,
+	0x1b, 0xe7, 0xa3, 0x4c, 0xac, 0xa4, 0x85, 0x9b, 0xa0, 0x4d, 0x96, 0x1f, 0xb2, 0x58, 0x4b, 0x14,
+	0x31, 0x94, 0x64, 0x04, 0x45, 0x4b, 0xac, 0x96, 0x23, 0x71, 0xa3, 0xe5, 0x2e, 0xbb, 0xbb, 0x94,
+	0x4c, 0x14, 0x05, 0x9c, 0x5e, 0x5a, 0xe4, 0xd4, 0x7b, 0x11, 0x04, 0x45, 0x8b, 0xde, 0x7a, 0x2e,
+	0xd0, 0x93, 0x8f, 0x3e, 0xb6, 0x28, 0x50, 0xe4, 0x14, 0x34, 0xe9, 0xa1, 0xd7, 0x02, 0x2d, 0x9a,
+	0x43, 0x7b, 0xe8, 0x7b, 0xf3, 0xb1, 0xfc, 0xf0, 0x5a, 0x71, 0x9a, 0x1c, 0x08, 0xee, 0xbc, 0xf9,
+	0xbd, 0x37, 0xf3, 0xde, 0xbc, 0x79, 0x1f, 0x43, 0x0a, 0xe1, 0x78, 0xc8, 0x82, 0xca, 0xd0, 0xf7,
+	0x42, 0x4f, 0xd3, 0x7a, 0x9e, 0x75, 0xc2, 0xfc, 0x4a, 0x70, 0x66, 0xfa, 0x83, 0x13, 0x3b, 0xac,
+	0x9c, 0xde, 0x2c, 0x5f, 0x09, 0xed, 0x01, 0x0b, 0x42, 0x73, 0x30, 0x7c, 0x25, 0xfa, 0x12, 0xf0,
+	0xf2, 0xd3, 0xbd, 0x91, 0x6f, 0x86, 0xb6, 0xe7, 0xbe, 0xa2, 0x3e, 0xe4, 0xc4, 0xa5, 0x63, 0xef,
+	0xd8, 0xe3, 0x9f, 0xaf, 0xe0, 0x97, 0xa0, 0xea, 0x57, 0xc9, 0xe2, 0x01, 0xf3, 0x03, 0x80, 0x69,
+	0x97, 0x48, 0xc6, 0x76, 0x7b, 0xec, 0xde, 0x6a, 0xe2, 0x5a, 0xe2, 0x46, 0x9a, 0x8a, 0x81, 0xfe,
+	0xcb, 0x04, 0x29, 0x18, 0xae, 0xeb, 0x85, 0x5c, 0x56, 0xa0, 0x69, 0x24, 0xed, 0x9a, 0x03, 0xc6,
+	0x41, 0x79, 0xca, 0xbf, 0xb5, 0x1a, 0xc9, 0x3a, 0xe6, 0x21, 0x73, 0x82, 0xd5, 0xe4, 0xb5, 0xd4,
+	0x8d, 0xc2, 0xc6, 0x4b, 0x95, 0x47, 0xf7, 0x5c, 0x99, 0x12, 0x52, 0xd9, 0xe6, 0xe8, 0x86, 0x1b,
+	0xfa, 0x63, 0x2a, 0x59, 0xcb, 0xdf, 0x22, 0x85, 0x29, 0xb2, 0x56, 0x22, 0xa9, 0x13, 0x36, 0x96,
+	0xcb, 0xe0, 0x27, 0xee, 0xef, 0xd4, 0x74, 0x46, 0x0c, 0x16, 0x41, 0x9a, 0x18, 0xbc, 0x91, 0xbc,
+	0x95, 0xd0, 0xdf, 0x21, 0x79, 0xca, 0x02, 0x6f, 0xe4, 0x5b, 0x2c, 0xd0, 0x5e, 0x20, 0x79, 0xd7,
+	0x74, 0xbd, 0xae, 0x35, 0x1c, 0x05, 0x9c, 0x3d, 0x55, 0x2d, 0x7e, 0xfa, 0xf1, 0xd5, 0x5c, 0x0b,
+	0x88, 0xb5, 0xf6, 0x7e, 0x40, 0x73, 0x38, 0x5d, 0x83, 0x59, 0xed, 0xff, 0x49, 0x71, 0xc0, 0x06,
+	0x9e, 0x3f, 0xee, 0x1e, 0x8e, 0x43, 0x16, 0x70, 0xc1, 0x29, 0x5a, 0x10, 0xb4, 0x2a, 0x92, 0xf4,
+	0x9f, 0x27, 0xc8, 0x25, 0x25, 0x9b, 0xb2, 0x1f, 0x8e, 0x6c, 0x9f, 0x0d, 0x98, 0x1b, 0x06, 0xda,
+	0x37, 0x40, 0x67, 0x7b, 0x60, 0x87, 0x62, 0x8d, 0xc2, 0xc6, 0xff, 0xc5, 0xe9, 0x1c, 0xed, 0x8a,
+	0x4a, 0xb0, 0x66, 0x90, 0xa2, 0xcf, 0x02, 0xe6, 0x9f, 0x0a, 0x4b, 0xf0, 0x25, 0x3f, 0x97, 0x79,
+	0x86, 0x45, 0xdf, 0x24, 0xb9, 0xb6, 0x63, 0x86, 0x47, 0x9e, 0x3f, 0xd0, 0x74, 0x52, 0x34, 0x7d,
+	0xab, 0x6f, 0x87, 0xcc, 0x0a, 0x47, 0xbe, 0x3a, 0x95, 0x19, 0x9a, 0x76, 0x99, 0x24, 0x3d, 0xb1,
+	0x50, 0xbe, 0x9a, 0x05, 0x4b, 0x24, 0x77, 0x3b, 0x14, 0x28, 0xfa, 0x9b, 0xe4, 0x42, 0xdb, 0x19,
+	0x1d, 0xdb, 0x6e, 0x9d, 0x05, 0x96, 0x6f, 0x0f, 0x51, 0x3a, 0x1e, 0x2f, 0x3a, 0x9f, 0x3a, 0x5e,
+	0xfc, 0x8e, 0x8e, 0x3c, 0x39, 0x39, 0x72, 0xfd, 0xa7, 0x49, 0x72, 0xa1, 0xe1, 0x02, 0x33, 0x9b,
+	0xe6, 0xbe, 0x4e, 0x96, 0x19, 0x27, 0x76, 0x4f, 0x85, 0x53, 0x49, 0x39, 0x4b, 0x82, 0xaa, 0x3c,
+	0xad, 0x39, 0xe7, 0x2f, 0x37, 0xe3, 0xd4, 0x7f, 0x44, 0x7a, 0x9c, 0xd7, 0x68, 0x0d, 0xb2, 0x38,
+	0xe4, 0x4a, 0x04, 0xab, 0x29, 0x2e, 0xeb, 0x7a, 0x9c, 0xac, 0x47, 0xf4, 0xac, 0xa6, 0x1f, 0x7e,
+	0x7c, 0x75, 0x81, 0x2a, 0xde, 0x2f, 0xe3, 0x7c, 0x7f, 0x4d, 0x90, 0x95, 0x96, 0xd7, 0x9b, 0xb1,
+	0x43, 0x99, 0xe4, 0xfa, 0x5e, 0x10, 0x4e, 0x5d, 0x94, 0x68, 0xac, 0xdd, 0x22, 0xb9, 0xa1, 0x3c,
+	0x3e, 0x79, 0xfa, 0x6b, 0xf1, 0x5b, 0x16, 0x18, 0x1a, 0xa1, 0xb5, 0x37, 0x49, 0xde, 0x57, 0x3e,
+	0x01, 0xda, 0x3e, 0x81, 0xe3, 0x4c, 0xf0, 0xda, 0xb7, 0x49, 0x56, 0x1c, 0xc2, 0x6a, 0x9a, 0x73,
+	0x5e, 0x7f, 0x22, 0x9b, 0x53, 0xc9, 0xa4, 0x7f, 0x94, 0x20, 0x25, 0x6a, 0x1e, 0x85, 0x3b, 0x6c,
+	0x70, 0xc8, 0xfc, 0x0e, 0x5c, 0x64, 0xb8, 0x3f, 0x97, 0xe1, 0x1c, 0x99, 0xd9, 0x63, 0x3e, 0x57,
+	0x32, 0x47, 0xe5, 0x48, 0xdb, 0x47, 0x27, 0x37, 0xad, 0xbe, 0x79, 0x68, 0x3b, 0x76, 0x38, 0xe6,
+	0x6a, 0x2e, 0xc7, 0x9f, 0xf2, 0xbc, 0x4c, 0xd8, 0xfc, 0x84, 0x91, 0xce, 0x88, 0xd1, 0x56, 0xc9,
+	0x22, 0xc4, 0xba, 0xc0, 0x3c, 0x66, 0x5c, 0xfb, 0x3c, 0x55, 0x43, 0x70, 0xe5, 0xe2, 0x34, 0x9f,
+	0x56, 0x20, 0x8b, 0xfb, 0xad, 0x3b, 0xad, 0xdd, 0xbb, 0xad, 0xd2, 0x82, 0xb6, 0x42, 0x0a, 0xfb,
+	0x2d, 0xda, 0x30, 0x6a, 0x5b, 0x46, 0x75, 0xbb, 0x51, 0x4a, 0x68, 0x4b, 0x10, 0x2e, 0xa2, 0x61,
+	0x52, 0xff, 0x30, 0x41, 0x08, 0x1e, 0xa0, 0x54, 0xea, 0x0d, 0x92, 0x81, 0x78, 0x1a, 0x8a, 0x83,
+	0x5b, 0xde, 0x78, 0x2e, 0x6e, 0xd7, 0x13, 0x78, 0x05, 0xff, 0x18, 0x15, 0x2c, 0xd3, 0x3b, 0x4c,
+	0xce, 0xef, 0x30, 0xc3, 0x91, 0xb3, 0x5b, 0xcb, 0x91, 0x74, 0x1d, 0xbf, 0x12, 0x5a, 0x9e, 0x64,
+	0x60, 0x4f, 0xf5, 0x77, 0x4a, 0x49, 0x70, 0xbe, 0x62, 0xbd, 0xd9, 0xa9, 0xed, 0xb6, 0x5a, 0x8d,
+	0xda, 0x5e, 0xa3, 0x5e, 0x4a, 0xe9, 0xd7, 0x49, 0xa6, 0x39, 0x00, 0x29, 0xda, 0x1a, 0x7a, 0xc0,
+	0x11, 0xf3, 0x99, 0x6b, 0x29, 0xc7, 0x9a, 0x10, 0xf4, 0x7f, 0x2d, 0x92, 0xcc, 0x8e, 0x37, 0x72,
+	0x43, 0x6d, 0x63, 0xea, 0x16, 0x2f, 0x6f, 0xac, 0xc7, 0xa9, 0xc0, 0x81, 0x95, 0x3d, 0x40, 0xc9,
+	0x5b, 0x0e, 0x87, 0x29, 0x7c, 0x45, 0x6e, 0x5d, 0x8e, 0x90, 0x1e, 0x9a, 0xfe, 0x31, 0x0b, 0xa5,
+	0xd1, 0xe5, 0x08, 0x7d, 0xfc, 0xcc, 0xb7, 0x43, 0xf3, 0xd0, 0x11, 0x2e, 0x95, 0xa3, 0xd1, 0x58,
+	0xdb, 0x22, 0xc5, 0x43, 0x48, 0x1f, 0x5d, 0x6f, 0x28, 0xa2, 0x5c, 0xe6, 0xf1, 0x2e, 0x27, 0xf6,
+	0x51, 0x05, 0xf4, 0xae, 0x00, 0xd3, 0xc2, 0xe1, 0x64, 0xa0, 0xb5, 0xc8, 0xf2, 0xa9, 0xe7, 0x8c,
+	0x06, 0x2c, 0x92, 0x95, 0xe5, 0xb2, 0x9e, 0x7f, 0xbc, 0xac, 0x03, 0x8e, 0x57, 0xd2, 0x96, 0x4e,
+	0xa7, 0x87, 0xe5, 0x9f, 0xa4, 0x48, 0x61, 0x6a, 0x31, 0xad, 0x43, 0x0a, 0x90, 0x08, 0x87, 0xe6,
+	0x31, 0x0f, 0xae, 0xd2, 0x60, 0x37, 0x9f, 0x68, 0xa3, 0x95, 0xf6, 0x84, 0x91, 0x4e, 0x4b, 0xd1,
+	0x3f, 0x48, 0x92, 0xc2, 0xd4, 0xa4, 0xf6, 0x22, 0xc9, 0xd1, 0x36, 0x6d, 0x1e, 0x18, 0x7b, 0x8d,
+	0xd2, 0x42, 0x79, 0xed, 0xfd, 0x0f, 0xae, 0xad, 0x72, 0x69, 0xd3, 0x02, 0xda, 0xbe, 0x7d, 0x8a,
+	0xfe, 0x71, 0x83, 0x2c, 0x2a, 0x68, 0xa2, 0xfc, 0x0c, 0x40, 0x9f, 0x9e, 0x87, 0x4e, 0x21, 0x69,
+	0x67, 0xcb, 0xa0, 0xe0, 0x22, 0xc9, 0x78, 0x24, 0xed, 0xf4, 0x4d, 0x9f, 0xf5, 0xb4, 0xaf, 0x91,
+	0xac, 0x04, 0xa6, 0xca, 0x65, 0x00, 0x5e, 0x9e, 0x07, 0x4e, 0x70, 0xb4, 0xb3, 0x6d, 0x1c, 0x34,
+	0x4a, 0xe9, 0x78, 0x1c, 0xed, 0x38, 0xe6, 0x29, 0xd3, 0x9e, 0x03, 0x67, 0xe6, 0xb0, 0x4c, 0xf9,
+	0x0a, 0xc0, 0x9e, 0x7a, 0x44, 0x1c, 0xa2, 0xca, 0xab, 0x3f, 0xfb, 0xd5, 0xfa, 0xc2, 0xef, 0x7f,
+	0xbd, 0x5e, 0x9a, 0x9f, 0x2e, 0xff, 0x33, 0x41, 0x96, 0x66, 0x4e, 0x09, 0x9d, 0x69, 0xe8, 0x0d,
+	0x47, 0x8e, 0xba, 0x77, 0xe0, 0x4c, 0x6a, 0xac, 0xdd, 0x99, 0xcb, 0x16, 0xaf, 0x3d, 0xe1, 0xd1,
+	0xc7, 0xe6, 0x8b, 0xb7, 0xc8, 0x52, 0x0f, 0xec, 0xc7, 0xfc, 0xae, 0xe5, 0xb9, 0x47, 0xf6, 0xb1,
+	0x8c, 0xa3, 0xe5, 0x38, 0x99, 0x75, 0x0e, 0xa4, 0x45, 0xc1, 0x50, 0xe3, 0xf8, 0x2f, 0x93, 0x29,
+	0xee, 0x92, 0x34, 0xde, 0x37, 0xed, 0x19, 0x92, 0xae, 0x36, 0x5b, 0x75, 0x70, 0x85, 0x0b, 0x60,
+	0xbd, 0x25, 0xbe, 0x75, 0x9c, 0x40, 0xdf, 0xd2, 0xae, 0x92, 0xec, 0xc1, 0xee, 0xf6, 0xfe, 0x0e,
+	0x1e, 0xff, 0x45, 0x98, 0x5e, 0x89, 0xa6, 0x85, 0x72, 0xe5, 0x0b, 0xd2, 0xac, 0xf9, 0x68, 0x42,
+	0xff, 0x77, 0x92, 0x2c, 0x51, 0xac, 0x02, 0xfd, 0xb0, 0xed, 0x39, 0xb6, 0x35, 0xd6, 0xda, 0x24,
+	0x0f, 0xfa, 0xf5, 0xec, 0x29, 0xa7, 0xde, 0x78, 0x4c, 0xaa, 0x98, 0x70, 0xa9, 0x51, 0x4d, 0x71,
+	0xd2, 0x89, 0x10, 0x08, 0x29, 0x99, 0x1e, 0x73, 0xcc, 0xf1, 0x79, 0x39, 0xab, 0x2e, 0x2b, 0x4e,
+	0x2a, 0xa0, 0xbc, 0xbe, 0x32, 0xef, 0x75, 0xcd, 0x30, 0x64, 0x83, 0x61, 0x28, 0x72, 0x56, 0x1a,
+	0xea, 0x2b, 0xf3, 0x9e, 0x21, 0x49, 0xda, 0xeb, 0x24, 0x7b, 0x06, 0x6a, 0x7b, 0x67, 0x32, 0x2d,
+	0x9d, 0x2f, 0x57, 0x62, 0xf5, 0xf7, 0x31, 0x1b, 0xcd, 0x6d, 0x16, 0xcd, 0xda, 0xda, 0x6d, 0x35,
+	0x94, 0x59, 0xe5, 0xfc, 0xae, 0xdb, 0xf2, 0x5c, 0x74, 0x59, 0xb2, 0xdb, 0xea, 0x6e, 0x1a, 0xcd,
+	0xed, 0x7d, 0x8a, 0xa6, 0xbd, 0x04, 0x90, 0x52, 0x04, 0xd9, 0x34, 0x6d, 0x07, 0x4b, 0xa5, 0x2b,
+	0x24, 0x65, 0xb4, 0x20, 0x06, 0x97, 0x4b, 0x30, 0x5d, 0x8c, 0xa6, 0x0d, 0x77, 0x3c, 0xf1, 0xe6,
+	0xf9, 0x75, 0xf5, 0x77, 0x49, 0x71, 0x7f, 0xd8, 0x03, 0x4f, 0x15, 0x1e, 0xa2, 0x5d, 0x83, 0x90,
+	0x62, 0xfa, 0xa6, 0xe3, 0x30, 0xc7, 0x0e, 0x06, 0xb2, 0x9a, 0x9e, 0x26, 0x41, 0x09, 0xf0, 0xe4,
+	0xb6, 0x94, 0x95, 0x8a, 0x60, 0xd0, 0x7f, 0x4c, 0x56, 0x60, 0x95, 0xd0, 0x84, 0x94, 0xac, 0x92,
+	0xf0, 0x06, 0x29, 0x5a, 0x8a, 0xd4, 0xb5, 0x7b, 0xc2, 0x15, 0xab, 0x2b, 0x50, 0xe8, 0x15, 0x22,
+	0x68, 0xb3, 0x4e, 0x0b, 0x11, 0xa8, 0xd9, 0x43, 0x3d, 0x87, 0x00, 0xc5, 0xe5, 0x33, 0xd5, 0x45,
+	0x80, 0xa6, 0xda, 0x00, 0x41, 0x1a, 0x58, 0x31, 0xcf, 0xee, 0xd9, 0x21, 0x5c, 0x8f, 0x9e, 0x48,
+	0xb3, 0x19, 0x9a, 0x43, 0x42, 0x0d, 0xc6, 0xfa, 0x7b, 0x49, 0x42, 0xf6, 0xcc, 0xe0, 0x44, 0x2e,
+	0x0d, 0x05, 0x49, 0xd4, 0x7e, 0x9c, 0x57, 0x06, 0xef, 0x29, 0x10, 0x9d, 0xe0, 0xb5, 0xd7, 0x54,
+	0x9e, 0x15, 0xd5, 0x41, 0x3c, 0xa3, 0x5c, 0x2b, 0x2e, 0xc1, 0xce, 0x96, 0x00, 0x78, 0x11, 0x99,
+	0xef, 0x73, 0x2f, 0x82, 0x8b, 0x08, 0x9f, 0xd0, 0x95, 0xe4, 0x23, 0x9d, 0x65, 0x06, 0x7a, 0x36,
+	0x6e, 0x91, 0x39, 0x83, 0x6e, 0x2d, 0xd0, 0x09, 0x5f, 0xb5, 0x44, 0x96, 0x7d, 0xb8, 0x66, 0xb0,
+	0xeb, 0x6e, 0xc0, 0xa7, 0xf5, 0x3f, 0x81, 0x0d, 0x9a, 0x6d, 0x63, 0x47, 0x9e, 0x76, 0x9d, 0x64,
+	0x8f, 0xcc, 0x81, 0xed, 0x8c, 0xe5, 0x35, 0x7b, 0x39, 0x6e, 0x89, 0x09, 0xbe, 0x62, 0xf4, 0x7a,
+	0x50, 0x94, 0x05, 0x9b, 0x9c, 0x87, 0x4a, 0x5e, 0x9e, 0x7c, 0x47, 0x87, 0x2e, 0x24, 0x59, 0x95,
+	0x7c, 0xf9, 0x08, 0x83, 0x89, 0x6f, 0xba, 0x91, 0xb6, 0x62, 0x80, 0x56, 0x80, 0x48, 0xca, 0xce,
+	0xc0, 0x83, 0x84, 0xbe, 0x6a, 0x08, 0x89, 0x37, 0x27, 0x7a, 0x05, 0xd6, 0x03, 0x95, 0x31, 0x5a,
+	0x7e, 0xde, 0x7e, 0xa8, 0x84, 0x8b, 0x30, 0x19, 0x71, 0x97, 0xdf, 0xe4, 0x21, 0x65, 0x32, 0xf5,
+	0x85, 0x22, 0xdd, 0xab, 0x64, 0x69, 0x46, 0xcf, 0x47, 0xaa, 0x9e, 0x66, 0xfb, 0xe0, 0xf5, 0x52,
+	0x5a, 0x7e, 0x7d, 0xb3, 0x94, 0xd5, 0xff, 0x01, 0x45, 0x58, 0xdb, 0xe3, 0xd7, 0x0a, 0xad, 0x1a,
+	0xdf, 0x65, 0xe6, 0x78, 0xcf, 0x6a, 0x79, 0x8e, 0xf4, 0x99, 0xd8, 0x22, 0x60, 0x22, 0x05, 0x13,
+	0x34, 0x87, 0xd3, 0x88, 0x11, 0xc2, 0x6b, 0x41, 0xd4, 0x2f, 0xdd, 0x21, 0xe0, 0xb8, 0x59, 0x97,
+	0x28, 0x11, 0x24, 0xe4, 0xc4, 0x16, 0x66, 0x38, 0x3a, 0x84, 0x6b, 0xda, 0x67, 0x3d, 0x81, 0x49,
+	0x73, 0xcc, 0x52, 0x44, 0x45, 0x98, 0x5e, 0x87, 0x26, 0x4c, 0xc9, 0x5c, 0x25, 0xa9, 0xbd, 0x5a,
+	0x1b, 0xe2, 0xce, 0x0a, 0x44, 0x8d, 0x82, 0x22, 0x03, 0x09, 0x67, 0xf6, 0xeb, 0x6d, 0x08, 0x37,
+	0x33, 0x33, 0x40, 0x2a, 0xa7, 0x31, 0x9c, 0xe8, 0xbf, 0x48, 0x90, 0xac, 0xc8, 0x32, 0xb1, 0x1a,
+	0x1b, 0x64, 0x51, 0x55, 0x3d, 0x22, 0xf5, 0x3d, 0xff, 0xf8, 0x34, 0x55, 0x91, 0x59, 0x4f, 0x9c,
+	0xa3, 0xe2, 0x2b, 0xbf, 0x41, 0x8a, 0xd3, 0x13, 0x5f, 0xe8, 0x14, 0x7f, 0x44, 0x0a, 0xe8, 0x28,
+	0x2a, 0x47, 0x6f, 0x90, 0xac, 0xc8, 0x84, 0xf2, 0xaa, 0x9f, 0x97, 0x33, 0x25, 0x12, 0x22, 0xdd,
+	0xa2, 0xc8, 0xb3, 0xaa, 0x3d, 0x5b, 0x3f, 0xdf, 0x1d, 0xa9, 0x82, 0xeb, 0x6f, 0x91, 0x74, 0x9b,
+	0x81, 0x84, 0x67, 0xc9, 0xa2, 0x0b, 0xa1, 0x67, 0x12, 0xd9, 0x08, 0x84, 0xab, 0x2c, 0x16, 0xe0,
+	0x10, 0xb1, 0xb2, 0x38, 0x05, 0xf1, 0x0c, 0x8c, 0x67, 0x82, 0xbf, 0xa9, 0x0e, 0x15, 0xbf, 0xf5,
+	0x3d, 0x52, 0xbc, 0xcb, 0xec, 0xe3, 0x7e, 0x08, 0x27, 0x86, 0x82, 0x5e, 0x26, 0xe9, 0x21, 0x8b,
+	0x36, 0xbf, 0x1a, 0xeb, 0x3a, 0x30, 0x4f, 0x39, 0x0a, 0x2f, 0xe4, 0x19, 0xe7, 0x96, 0x8f, 0x02,
+	0x72, 0xa4, 0xff, 0x36, 0x49, 0x96, 0x9b, 0x41, 0x30, 0x32, 0xa1, 0xe0, 0x96, 0x51, 0xf0, 0x3b,
+	0xb3, 0x0d, 0xc3, 0x8d, 0x58, 0x0d, 0x67, 0x58, 0x66, 0x9b, 0x06, 0x19, 0xb9, 0x92, 0x51, 0xe4,
+	0xd2, 0x1f, 0x26, 0x54, 0xb7, 0x70, 0x7d, 0xea, 0xde, 0x94, 0x57, 0xc1, 0x89, 0x2e, 0x4d, 0x4b,
+	0x62, 0xfb, 0xee, 0x89, 0xeb, 0x9d, 0xb9, 0x90, 0x68, 0xa1, 0x7b, 0x68, 0x35, 0xee, 0x82, 0xa7,
+	0x5d, 0x06, 0x90, 0x36, 0x03, 0xa2, 0xcc, 0x65, 0x67, 0x28, 0xa9, 0xdd, 0x68, 0xd5, 0x9b, 0xad,
+	0xdb, 0x90, 0xde, 0x1e, 0x95, 0xd4, 0x66, 0x90, 0xce, 0xdc, 0x63, 0x30, 0x77, 0xb6, 0xd9, 0xe9,
+	0xec, 0xf3, 0x52, 0xf1, 0x69, 0x40, 0x5d, 0x9c, 0x41, 0xe1, 0x00, 0xea, 0x44, 0x00, 0x61, 0x26,
+	0x05, 0x50, 0x3a, 0x06, 0x84, 0xc9, 0x14, 0x02, 0x88, 0xf0, 0xf0, 0xbf, 0x25, 0x49, 0xc9, 0xb0,
+	0x2c, 0x36, 0x0c, 0x71, 0x5e, 0x56, 0x27, 0x7b, 0x58, 0xed, 0xc1, 0x97, 0xcd, 0xf0, 0xf5, 0x04,
+	0xdd, 0xe2, 0x56, 0xec, 0x8b, 0xd1, 0x1c, 0x5f, 0x85, 0x7a, 0x0e, 0x33, 0x7a, 0x03, 0x3b, 0xc0,
+	0x57, 0x04, 0x41, 0xa3, 0x91, 0xa4, 0xf2, 0x7f, 0x12, 0xe4, 0x62, 0x0c, 0x42, 0x7b, 0x95, 0xa4,
+	0x7d, 0x20, 0xcb, 0xe3, 0x59, 0x7b, 0x5c, 0x3f, 0x87, 0xac, 0x94, 0x23, 0xb5, 0x75, 0x42, 0xcc,
+	0x51, 0xe8, 0x99, 0x7c, 0x7d, 0x7e, 0x30, 0x39, 0x3a, 0x45, 0xd1, 0xbe, 0x0f, 0xd1, 0x9a, 0x59,
+	0xbe, 0x6c, 0x89, 0x0a, 0x1b, 0x8d, 0xff, 0x75, 0xf7, 0x95, 0x2d, 0x13, 0x23, 0x4a, 0x87, 0x0b,
+	0xa3, 0x52, 0x68, 0xf9, 0x75, 0x52, 0x9c, 0xa6, 0xa3, 0x77, 0x43, 0x79, 0x61, 0x72, 0x05, 0x8a,
+	0x94, 0x7f, 0xa3, 0xd3, 0x98, 0xce, 0xb1, 0x72, 0x1a, 0xf8, 0xd4, 0x3f, 0x84, 0xbc, 0xd4, 0xb8,
+	0x17, 0x32, 0xdf, 0x35, 0x9d, 0x9a, 0xa1, 0x35, 0xa6, 0xa2, 0xa5, 0xd0, 0xfc, 0x85, 0xd8, 0x8e,
+	0x3f, 0xe2, 0xa8, 0xd4, 0x8c, 0x98, 0x78, 0x09, 0x95, 0xc2, 0xc8, 0x77, 0xe4, 0xeb, 0x11, 0xaf,
+	0x14, 0xf6, 0xe9, 0x36, 0x45, 0x1a, 0x3e, 0xbd, 0xa8, 0xe8, 0x94, 0x7a, 0xfc, 0xb3, 0xdf, 0xd4,
+	0x02, 0x5f, 0x7d, 0x84, 0x7a, 0x99, 0x90, 0xc9, 0xae, 0xe1, 0xd8, 0x32, 0xb5, 0xcd, 0x4e, 0x67,
+	0x1b, 0xae, 0x0a, 0xaf, 0x9c, 0x27, 0x53, 0x9c, 0xac, 0xff, 0x26, 0x41, 0x72, 0x35, 0x43, 0x66,
+	0x98, 0x4d, 0x52, 0xe2, 0x71, 0xc5, 0x62, 0x7e, 0xd8, 0x65, 0xf7, 0x86, 0xb6, 0x3f, 0x96, 0xa1,
+	0xe1, 0xfc, 0x12, 0x74, 0x19, 0xb9, 0x6a, 0xc0, 0xd4, 0xe0, 0x3c, 0x1a, 0x25, 0x45, 0x26, 0x55,
+	0xec, 0x5a, 0xa6, 0x0a, 0xd4, 0xeb, 0xe7, 0x9b, 0x42, 0x94, 0x67, 0x93, 0x31, 0x34, 0xbd, 0x4a,
+	0x48, 0xcd, 0x0c, 0xf4, 0x03, 0x72, 0x71, 0xd7, 0xb7, 0xfa, 0x50, 0x28, 0x89, 0x45, 0xe5, 0x96,
+	0xdf, 0x22, 0x6b, 0x21, 0x14, 0x44, 0xdd, 0xbe, 0x1d, 0x84, 0xf8, 0x68, 0x09, 0xbe, 0xc1, 0x5c,
+	0x9c, 0xef, 0xf2, 0xc7, 0x45, 0xf1, 0xd8, 0x49, 0xaf, 0x20, 0x66, 0x4b, 0x40, 0xa8, 0x42, 0x6c,
+	0x23, 0x40, 0xff, 0x1e, 0x29, 0xd5, 0xed, 0x60, 0x68, 0x86, 0x20, 0x5b, 0xf6, 0x33, 0xda, 0x6d,
+	0x52, 0xea, 0x33, 0xa8, 0x67, 0x0f, 0x99, 0x09, 0x39, 0x91, 0xf9, 0xb6, 0xd7, 0x7b, 0x22, 0x3b,
+	0xac, 0x44, 0x5c, 0x6d, 0xce, 0xa4, 0x7f, 0x06, 0x19, 0x1c, 0x5f, 0x73, 0xa4, 0xdc, 0x97, 0xc8,
+	0x85, 0xc0, 0x35, 0x87, 0x41, 0xdf, 0x0b, 0xbb, 0xb6, 0x1b, 0xe2, 0xf3, 0xa5, 0x23, 0x6b, 0xe1,
+	0x92, 0x9a, 0x68, 0x4a, 0x3a, 0xc4, 0x66, 0xed, 0x84, 0xb1, 0x61, 0xd7, 0x73, 0x7a, 0x5d, 0x35,
+	0x29, 0x9e, 0x2c, 0x01, 0x8d, 0x33, 0xbb, 0x4e, 0xaf, 0xa3, 0xe8, 0x5a, 0x95, 0xac, 0x3b, 0xde,
+	0x71, 0x17, 0x34, 0xf3, 0xe1, 0xde, 0x77, 0x8f, 0x3c, 0xbf, 0x1b, 0x38, 0xde, 0x19, 0x7c, 0x38,
+	0xf0, 0xc7, 0x7c, 0xd5, 0x68, 0x94, 0x01, 0xd5, 0x10, 0xa0, 0x4d, 0xcf, 0xef, 0xc0, 0xdc, 0xa6,
+	0x42, 0x60, 0x9a, 0x9f, 0xa8, 0x1d, 0xda, 0xd6, 0x89, 0x4a, 0xf3, 0x11, 0x75, 0x0f, 0x88, 0x10,
+	0xe9, 0x96, 0x98, 0xc3, 0x2c, 0x6e, 0x64, 0x8e, 0xca, 0x70, 0x54, 0x51, 0x11, 0x11, 0xa4, 0x7f,
+	0x9d, 0xe4, 0xdb, 0x8e, 0x69, 0xf1, 0x87, 0x61, 0xac, 0xfe, 0x21, 0x85, 0xe1, 0xc9, 0x81, 0xd6,
+	0x22, 0xbc, 0xe5, 0xe9, 0x34, 0x49, 0x7f, 0x0f, 0x92, 0x3e, 0xf5, 0xbc, 0x10, 0x2e, 0xe9, 0x35,
+	0x92, 0xb5, 0xcc, 0xae, 0x72, 0xf7, 0x62, 0x35, 0x0f, 0x6e, 0x91, 0xa9, 0x19, 0x77, 0xd8, 0x98,
+	0x66, 0x2c, 0x13, 0xfe, 0x30, 0xfd, 0x01, 0x02, 0x9d, 0x94, 0x9b, 0xa3, 0x28, 0xd2, 0x1f, 0x78,
+	0x31, 0x50, 0x28, 0x30, 0xe3, 0x3f, 0x44, 0xb8, 0xa2, 0x04, 0x75, 0xfb, 0x10, 0x38, 0x44, 0xb1,
+	0x58, 0x5d, 0x06, 0x24, 0x11, 0x48, 0x0c, 0x27, 0x94, 0x08, 0x34, 0x7e, 0xeb, 0x7f, 0x4e, 0x90,
+	0x02, 0x0e, 0xec, 0x23, 0xdb, 0xc2, 0x3c, 0xf3, 0xc5, 0x63, 0x24, 0x04, 0x06, 0x2b, 0xf0, 0xe5,
+	0xa6, 0x78, 0x60, 0xa8, 0x75, 0x28, 0x45, 0x9a, 0xf6, 0x36, 0x84, 0x47, 0x9e, 0xe7, 0x64, 0x78,
+	0xd4, 0x3f, 0x3f, 0x23, 0xca, 0x2e, 0x47, 0xf2, 0x71, 0x23, 0x4e, 0x76, 0xc7, 0x8f, 0xa6, 0x48,
+	0xa7, 0x49, 0xf8, 0xa8, 0x6d, 0xb9, 0xfc, 0x34, 0xe4, 0xa3, 0x76, 0xad, 0x45, 0x81, 0xa2, 0xff,
+	0x31, 0x41, 0x96, 0x1a, 0xae, 0xe5, 0x8f, 0x79, 0x48, 0x41, 0x0b, 0xae, 0x91, 0x3c, 0x14, 0xd3,
+	0xc1, 0x38, 0x80, 0x8e, 0x53, 0xbd, 0x99, 0x45, 0x04, 0xad, 0x49, 0xf2, 0x10, 0x3c, 0x3d, 0xdf,
+	0x0e, 0xfb, 0x03, 0x59, 0x55, 0xc6, 0x87, 0xb1, 0x69, 0x99, 0x15, 0x43, 0xb1, 0xd0, 0x09, 0xb7,
+	0x0a, 0x5c, 0x29, 0xbe, 0x59, 0x1e, 0xb8, 0xa0, 0xff, 0x75, 0xa0, 0xd5, 0x81, 0x7a, 0xb1, 0x8b,
+	0x1d, 0x04, 0xd7, 0x03, 0x5a, 0x41, 0x49, 0xc3, 0xae, 0x48, 0xd7, 0x49, 0x3e, 0x12, 0x86, 0x2f,
+	0x95, 0x46, 0xa3, 0xd3, 0xbd, 0xb9, 0x71, 0xab, 0x7b, 0xbb, 0xb6, 0x03, 0x61, 0x4c, 0xe4, 0xd0,
+	0xdf, 0x81, 0x4e, 0x3b, 0xa6, 0x0b, 0x5d, 0x8e, 0xea, 0xf9, 0xc0, 0x2b, 0x7c, 0xb8, 0x6a, 0xaa,
+	0x28, 0x4a, 0x0b, 0xaf, 0xc0, 0xdb, 0x87, 0x45, 0x11, 0x4e, 0xc5, 0x17, 0x45, 0x53, 0x2f, 0xb6,
+	0xa9, 0x73, 0x5f, 0x6c, 0xd3, 0x5f, 0xc9, 0x8b, 0xed, 0x8b, 0x9f, 0xa5, 0x48, 0x3e, 0xea, 0xe1,
+	0xd0, 0x65, 0xb0, 0x46, 0x59, 0x10, 0xdd, 0x75, 0x44, 0x6f, 0xf1, 0xea, 0x24, 0x6f, 0x6c, 0x6f,
+	0xef, 0xd6, 0x0c, 0x7c, 0xf0, 0x7c, 0x5b, 0x14, 0x31, 0x11, 0xc0, 0x80, 0x4b, 0x8b, 0x87, 0xde,
+	0xd3, 0xf4, 0x49, 0x11, 0x73, 0x5f, 0xf6, 0xf0, 0x11, 0x4a, 0x55, 0x30, 0xcf, 0x91, 0x9c, 0xd1,
+	0xe9, 0x34, 0x6f, 0xb7, 0x40, 0xd2, 0x83, 0x44, 0xf9, 0x29, 0x00, 0x5d, 0x98, 0x88, 0x82, 0xe4,
+	0x7b, 0xec, 0x82, 0x24, 0x44, 0xd5, 0x6a, 0x8d, 0x36, 0xae, 0x77, 0x3f, 0x39, 0x8f, 0xe2, 0xa9,
+	0x9b, 0x3f, 0x88, 0xe5, 0xdb, 0xb4, 0xd1, 0x36, 0x28, 0xae, 0xf8, 0x20, 0x39, 0xb7, 0xaf, 0xb6,
+	0xcf, 0xa0, 0xab, 0xc7, 0x35, 0xd7, 0xd5, 0xeb, 0xed, 0xfd, 0x54, 0x59, 0x03, 0xcc, 0xf2, 0xa4,
+	0x71, 0x05, 0xfb, 0x8e, 0x71, 0xb5, 0xce, 0x9e, 0x41, 0xf7, 0xb8, 0x98, 0xd4, 0xdc, 0x6a, 0x1d,
+	0x7c, 0x4e, 0x40, 0x29, 0xa0, 0x1d, 0xdd, 0x6f, 0xb5, 0xb8, 0x76, 0xe9, 0x39, 0xed, 0xe8, 0xc8,
+	0x75, 0x11, 0x73, 0x1d, 0x52, 0xd8, 0xee, 0x4e, 0x7b, 0xbb, 0xb1, 0xd7, 0x28, 0x3d, 0x48, 0xcf,
+	0x6d, 0xa8, 0xe6, 0x0d, 0x86, 0x0e, 0x0b, 0x85, 0x7a, 0x9d, 0xad, 0xfd, 0x3d, 0xfe, 0xb8, 0x7c,
+	0x3f, 0x33, 0xbf, 0x60, 0x7f, 0x14, 0xf6, 0xb0, 0x6c, 0xbc, 0x16, 0xd5, 0x71, 0x0f, 0x32, 0x22,
+	0x65, 0x46, 0x18, 0x51, 0xc4, 0xa1, 0x1c, 0xda, 0xf8, 0xae, 0x78, 0x87, 0xbe, 0x9f, 0x9d, 0x93,
+	0x43, 0xd9, 0xbb, 0x10, 0x05, 0xa1, 0xd4, 0x8b, 0x9e, 0xa4, 0xa2, 0xa9, 0x17, 0x7f, 0x40, 0x72,
+	0x2a, 0x60, 0x80, 0x75, 0xb2, 0x77, 0x77, 0xe9, 0x9d, 0x06, 0x85, 0xa3, 0xe7, 0xd6, 0x51, 0x33,
+	0x77, 0x3d, 0x1f, 0xbc, 0x0b, 0xb6, 0xb1, 0xb8, 0x63, 0xb4, 0x8c, 0xdb, 0x00, 0x90, 0x6f, 0x5e,
+	0x0a, 0x20, 0xbd, 0xbe, 0x5c, 0x92, 0x0b, 0x44, 0x32, 0xab, 0x6b, 0x0f, 0x3f, 0x59, 0x5f, 0xf8,
+	0x08, 0x7e, 0x7f, 0xff, 0x64, 0x3d, 0x71, 0xff, 0xd3, 0xf5, 0xc4, 0x43, 0xf8, 0xfd, 0x01, 0x7e,
+	0x7f, 0x81, 0xdf, 0x61, 0x96, 0xd7, 0x2f, 0xaf, 0xfd, 0x37, 0x00, 0x00, 0xff, 0xff, 0x2c, 0xf4,
+	0xf4, 0x16, 0x49, 0x1d, 0x00, 0x00,
 }
 }

+ 20 - 0
vendor/src/github.com/docker/swarmkit/api/types.proto

@@ -447,9 +447,29 @@ message AcceptancePolicy {
 }
 }
 
 
 
 
+message ExternalCA {
+	enum CAProtocol {
+		CFSSL = 0 [(gogoproto.enumvalue_customname) = "CAProtocolCFSSL"];
+	}
+
+	// Protocol is the protocol used by this external CA.
+	CAProtocol protocol = 1;
+
+	// URL is the URL where the external CA can be reached.
+	string url = 2 [(gogoproto.customname) = "URL"];
+
+	// Options is a set of additional key/value pairs whose interpretation
+	// depends on the specified CA type.
+	map<string, string> options = 3;
+}
+
 message CAConfig {
 message CAConfig {
 	// NodeCertExpiry is the duration certificates should be issued for
 	// NodeCertExpiry is the duration certificates should be issued for
 	Duration node_cert_expiry = 1;
 	Duration node_cert_expiry = 1;
+
+	// ExternalCAs is a list of CAs to which a manager node will make
+	// certificate signing requests for node certificates.
+	repeated ExternalCA external_cas = 2 [(gogoproto.customname) = "ExternalCAs"];
 }
 }
 
 
 // OrchestrationConfig defines cluster-level orchestration settings.
 // OrchestrationConfig defines cluster-level orchestration settings.

+ 52 - 19
vendor/src/github.com/docker/swarmkit/ca/certificates.go

@@ -167,7 +167,16 @@ func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, paths Cert
 	}
 	}
 
 
 	// Get the remote manager to issue a CA signed certificate for this node
 	// Get the remote manager to issue a CA signed certificate for this node
-	signedCert, err := GetRemoteSignedCertificate(ctx, csr, role, secret, rca.Pool, picker, transport, nodeInfo)
+	// Retry up to 5 times in case the manager we first try to contact isn't
+	// responding properly (for example, it may have just been demoted).
+	var signedCert []byte
+	for i := 0; i != 5; i++ {
+		signedCert, err = GetRemoteSignedCertificate(ctx, csr, role, secret, rca.Pool, picker, transport, nodeInfo)
+		if err == nil {
+			break
+		}
+		log.Warningf("error fetching signed node certificate: %v", err)
+	}
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -192,6 +201,12 @@ func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, paths Cert
 		return nil, err
 		return nil, err
 	}
 	}
 
 
+	// Create a valid TLSKeyPair out of the PEM encoded private key and certificate
+	tlsKeyPair, err := tls.X509KeyPair(signedCert, key)
+	if err != nil {
+		return nil, err
+	}
+
 	log.Infof("Downloaded new TLS credentials with role: %s.", role)
 	log.Infof("Downloaded new TLS credentials with role: %s.", role)
 
 
 	// Ensure directory exists
 	// Ensure directory exists
@@ -210,40 +225,50 @@ func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, paths Cert
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	// Create a valid TLSKeyPair out of the PEM encoded private key and certificate
-	tlsKeyPair, err := tls.X509KeyPair(signedCert, key)
-	if err != nil {
-		return nil, err
-	}
-
 	return &tlsKeyPair, nil
 	return &tlsKeyPair, nil
 }
 }
 
 
-// ParseValidateAndSignCSR returns a signed certificate from a particular rootCA and a CSR.
-func (rca *RootCA) ParseValidateAndSignCSR(csrBytes []byte, cn, ou, org string) ([]byte, error) {
-	if !rca.CanSign() {
-		return nil, ErrNoValidSigner
-	}
-
-	// All managers get added the subject-alt-name of CA, so they can be used for cert issuance
+// PrepareCSR creates a CFSSL Sign Request based on the given raw CSR and
+// overrides the Subject and Hosts with the given extra args.
+func PrepareCSR(csrBytes []byte, cn, ou, org string) cfsigner.SignRequest {
+	// All managers get added the subject-alt-name of CA, so they can be
+	// used for cert issuance.
 	hosts := []string{ou}
 	hosts := []string{ou}
 	if ou == ManagerRole {
 	if ou == ManagerRole {
 		hosts = append(hosts, CARole)
 		hosts = append(hosts, CARole)
 	}
 	}
 
 
-	cert, err := rca.Signer.Sign(cfsigner.SignRequest{
+	return cfsigner.SignRequest{
 		Request: string(csrBytes),
 		Request: string(csrBytes),
 		// OU is used for Authentication of the node type. The CN has the random
 		// OU is used for Authentication of the node type. The CN has the random
 		// node ID.
 		// node ID.
 		Subject: &cfsigner.Subject{CN: cn, Names: []cfcsr.Name{{OU: ou, O: org}}},
 		Subject: &cfsigner.Subject{CN: cn, Names: []cfcsr.Name{{OU: ou, O: org}}},
 		// Adding ou as DNS alt name, so clients can connect to ManagerRole and CARole
 		// Adding ou as DNS alt name, so clients can connect to ManagerRole and CARole
 		Hosts: hosts,
 		Hosts: hosts,
-	})
+	}
+}
+
+// ParseValidateAndSignCSR returns a signed certificate from a particular rootCA and a CSR.
+func (rca *RootCA) ParseValidateAndSignCSR(csrBytes []byte, cn, ou, org string) ([]byte, error) {
+	if !rca.CanSign() {
+		return nil, ErrNoValidSigner
+	}
+
+	signRequest := PrepareCSR(csrBytes, cn, ou, org)
+
+	cert, err := rca.Signer.Sign(signRequest)
 	if err != nil {
 	if err != nil {
 		log.Debugf("failed to sign node certificate: %v", err)
 		log.Debugf("failed to sign node certificate: %v", err)
 		return nil, err
 		return nil, err
 	}
 	}
 
 
+	return rca.AppendFirstRootPEM(cert)
+}
+
+// AppendFirstRootPEM appends the first certificate from this RootCA's cert
+// bundle to the given cert bundle (which should already be encoded as a series
+// of PEM-encoded certificate blocks).
+func (rca *RootCA) AppendFirstRootPEM(cert []byte) ([]byte, error) {
 	// Append the first root CA Cert to the certificate, to create a valid chain
 	// Append the first root CA Cert to the certificate, to create a valid chain
 	// Get the first Root CA Cert on the bundle
 	// Get the first Root CA Cert on the bundle
 	firstRootCA, _, err := helpers.ParseOneCertificateFromPEM(rca.Cert)
 	firstRootCA, _, err := helpers.ParseOneCertificateFromPEM(rca.Cert)
@@ -390,7 +415,7 @@ func GetLocalRootCA(baseDir string) (RootCA, error) {
 
 
 	rootCA, err := NewRootCA(cert, key, DefaultNodeCertExpiration)
 	rootCA, err := NewRootCA(cert, key, DefaultNodeCertExpiration)
 	if err == nil {
 	if err == nil {
-		log.Debugf("successfully loaded the signer for the Root CA: %s", paths.RootCA.Cert)
+		log.Debugf("successfully loaded the Root CA: %s", paths.RootCA.Cert)
 	}
 	}
 
 
 	return rootCA, err
 	return rootCA, err
@@ -602,7 +627,7 @@ func GetRemoteSignedCertificate(ctx context.Context, csr []byte, role, secret st
 	}
 	}
 	defer conn.Close()
 	defer conn.Close()
 
 
-	// Create a CAClient to retreive a new Certificate
+	// Create a CAClient to retrieve a new Certificate
 	caClient := api.NewNodeCAClient(conn)
 	caClient := api.NewNodeCAClient(conn)
 
 
 	// Convert our internal string roles into an API role
 	// Convert our internal string roles into an API role
@@ -644,7 +669,15 @@ func GetRemoteSignedCertificate(ctx context.Context, csr []byte, role, secret st
 			if statusResponse.Certificate == nil {
 			if statusResponse.Certificate == nil {
 				return nil, fmt.Errorf("no certificate in CertificateStatus response")
 				return nil, fmt.Errorf("no certificate in CertificateStatus response")
 			}
 			}
-			return statusResponse.Certificate.Certificate, nil
+
+			// The certificate in the response must match the CSR
+			// we submitted. If we are getting a response for a
+			// certificate that was previously issued, we need to
+			// retry until the certificate gets updated per our
+			// current request.
+			if bytes.Equal(statusResponse.Certificate.CSR, csr) {
+				return statusResponse.Certificate.Certificate, nil
+			}
 		}
 		}
 
 
 		// If we're still pending, the issuance failed, or the state is unknown
 		// If we're still pending, the issuance failed, or the state is unknown

+ 41 - 14
vendor/src/github.com/docker/swarmkit/ca/config.go

@@ -45,7 +45,8 @@ const (
 type SecurityConfig struct {
 type SecurityConfig struct {
 	mu sync.Mutex
 	mu sync.Mutex
 
 
-	rootCA *RootCA
+	rootCA     *RootCA
+	externalCA *ExternalCA
 
 
 	ServerTLSCreds *MutableTLSCreds
 	ServerTLSCreds *MutableTLSCreds
 	ClientTLSCreds *MutableTLSCreds
 	ClientTLSCreds *MutableTLSCreds
@@ -60,8 +61,19 @@ type CertificateUpdate struct {
 
 
 // NewSecurityConfig initializes and returns a new SecurityConfig.
 // NewSecurityConfig initializes and returns a new SecurityConfig.
 func NewSecurityConfig(rootCA *RootCA, clientTLSCreds, serverTLSCreds *MutableTLSCreds) *SecurityConfig {
 func NewSecurityConfig(rootCA *RootCA, clientTLSCreds, serverTLSCreds *MutableTLSCreds) *SecurityConfig {
+	// Make a new TLS config for the external CA client without a
+	// ServerName value set.
+	clientTLSConfig := clientTLSCreds.Config()
+
+	externalCATLSConfig := &tls.Config{
+		Certificates: clientTLSConfig.Certificates,
+		RootCAs:      clientTLSConfig.RootCAs,
+		MinVersion:   tls.VersionTLS12,
+	}
+
 	return &SecurityConfig{
 	return &SecurityConfig{
 		rootCA:         rootCA,
 		rootCA:         rootCA,
+		externalCA:     NewExternalCA(rootCA, externalCATLSConfig),
 		ClientTLSCreds: clientTLSCreds,
 		ClientTLSCreds: clientTLSCreds,
 		ServerTLSCreds: serverTLSCreds,
 		ServerTLSCreds: serverTLSCreds,
 	}
 	}
@@ -164,8 +176,18 @@ func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, caHash, secret
 			return nil, err
 			return nil, err
 		}
 		}
 
 
-		// Get the remote CA certificate, verify integrity with the hash provided
-		rootCA, err = GetRemoteCA(ctx, d, picker)
+		// Get the remote CA certificate, verify integrity with the
+		// hash provided. Retry up to 5 times, in case the manager we
+		// first try to contact is not responding properly (it may have
+		// just been demoted, for example).
+
+		for i := 0; i != 5; i++ {
+			rootCA, err = GetRemoteCA(ctx, d, picker)
+			if err == nil {
+				break
+			}
+			log.Warningf("failed to retrieve remote root CA certificate: %v", err)
+		}
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
@@ -180,9 +202,9 @@ func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, caHash, secret
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	// At this point we've successfully loaded the CA details from disk, or successfully
-	// downloaded them remotely.
-	// The next step is to try to load our certificates.
+	// At this point we've successfully loaded the CA details from disk, or
+	// successfully downloaded them remotely. The next step is to try to
+	// load our certificates.
 	clientTLSCreds, serverTLSCreds, err = LoadTLSCreds(rootCA, paths.Node)
 	clientTLSCreds, serverTLSCreds, err = LoadTLSCreds(rootCA, paths.Node)
 	if err != nil {
 	if err != nil {
 		log.Debugf("no valid local TLS credentials found: %v", err)
 		log.Debugf("no valid local TLS credentials found: %v", err)
@@ -204,6 +226,9 @@ func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, caHash, secret
 				}
 				}
 			}
 			}
 			tlsKeyPair, err = rootCA.IssueAndSaveNewCertificates(paths.Node, cn, proposedRole, org)
 			tlsKeyPair, err = rootCA.IssueAndSaveNewCertificates(paths.Node, cn, proposedRole, org)
+			if err != nil {
+				return nil, err
+			}
 		} else {
 		} else {
 			// There was an error loading our Credentials, let's get a new certificate issued
 			// There was an error loading our Credentials, let's get a new certificate issued
 			// Last argument is nil because at this point we don't have any valid TLS creds
 			// Last argument is nil because at this point we don't have any valid TLS creds
@@ -211,7 +236,6 @@ func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, caHash, secret
 			if err != nil {
 			if err != nil {
 				return nil, err
 				return nil, err
 			}
 			}
-
 		}
 		}
 		// Create the Server TLS Credentials for this node. These will not be used by agents.
 		// Create the Server TLS Credentials for this node. These will not be used by agents.
 		serverTLSCreds, err = rootCA.NewServerTLSCredentials(tlsKeyPair)
 		serverTLSCreds, err = rootCA.NewServerTLSCredentials(tlsKeyPair)
@@ -236,12 +260,7 @@ func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, caHash, secret
 		log.Debugf("loaded local TLS credentials: %s.", paths.Node.Cert)
 		log.Debugf("loaded local TLS credentials: %s.", paths.Node.Cert)
 	}
 	}
 
 
-	return &SecurityConfig{
-		rootCA: &rootCA,
-
-		ServerTLSCreds: serverTLSCreds,
-		ClientTLSCreds: clientTLSCreds,
-	}, nil
+	return NewSecurityConfig(&rootCA, clientTLSCreds, serverTLSCreds), nil
 }
 }
 
 
 // RenewTLSConfig will continuously monitor for the necessity of renewing the local certificates, either by
 // RenewTLSConfig will continuously monitor for the necessity of renewing the local certificates, either by
@@ -317,6 +336,14 @@ func RenewTLSConfig(ctx context.Context, s *SecurityConfig, baseCertDir string,
 				updates <- CertificateUpdate{Err: err}
 				updates <- CertificateUpdate{Err: err}
 			}
 			}
 
 
+			// Update the external CA to use the new client TLS
+			// config using a copy without a serverName specified.
+			s.externalCA.UpdateTLSConfig(&tls.Config{
+				Certificates: clientTLSConfig.Certificates,
+				RootCAs:      clientTLSConfig.RootCAs,
+				MinVersion:   tls.VersionTLS12,
+			})
+
 			err = s.ServerTLSCreds.LoadNewTLSConfig(serverTLSConfig)
 			err = s.ServerTLSCreds.LoadNewTLSConfig(serverTLSConfig)
 			if err != nil {
 			if err != nil {
 				log.Debugf("failed to update the server TLS credentials: %v", err)
 				log.Debugf("failed to update the server TLS credentials: %v", err)
@@ -405,7 +432,7 @@ func LoadTLSCreds(rootCA RootCA, paths CertPaths) (*MutableTLSCreds, *MutableTLS
 		}
 		}
 
 
 		keyPair, newErr = tls.X509KeyPair(cert, key)
 		keyPair, newErr = tls.X509KeyPair(cert, key)
-		if err != nil {
+		if newErr != nil {
 			return nil, nil, err
 			return nil, nil, err
 		}
 		}
 	}
 	}

+ 141 - 0
vendor/src/github.com/docker/swarmkit/ca/external.go

@@ -0,0 +1,141 @@
+package ca
+
+import (
+	"bytes"
+	"crypto/tls"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"sync"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/cloudflare/cfssl/api"
+	"github.com/cloudflare/cfssl/signer"
+)
+
+// ErrNoExternalCAURLs is an error used it indicate that an ExternalCA is
+// configured with no URLs to which it can proxy certificate signing requests.
+var ErrNoExternalCAURLs = errors.New("no external CA URLs")
+
+// ExternalCA is able to make certificate signing requests to one of a list
+// remote CFSSL API endpoints.
+type ExternalCA struct {
+	mu     sync.Mutex
+	rootCA *RootCA
+	urls   []string
+	client *http.Client
+}
+
+// NewExternalCA creates a new ExternalCA which uses the given tlsConfig to
+// authenticate to any of the given URLS of CFSSL API endpoints.
+func NewExternalCA(rootCA *RootCA, tlsConfig *tls.Config, urls ...string) *ExternalCA {
+	return &ExternalCA{
+		rootCA: rootCA,
+		urls:   urls,
+		client: &http.Client{
+			Transport: &http.Transport{
+				TLSClientConfig: tlsConfig,
+			},
+		},
+	}
+}
+
+// UpdateTLSConfig updates the HTTP Client for this ExternalCA by creating
+// a new client which uses the given tlsConfig.
+func (eca *ExternalCA) UpdateTLSConfig(tlsConfig *tls.Config) {
+	eca.mu.Lock()
+	defer eca.mu.Unlock()
+
+	eca.client = &http.Client{
+		Transport: &http.Transport{
+			TLSClientConfig: tlsConfig,
+		},
+	}
+}
+
+// UpdateURLs updates the list of CSR API endpoints by setting it to the given
+// urls.
+func (eca *ExternalCA) UpdateURLs(urls ...string) {
+	eca.mu.Lock()
+	defer eca.mu.Unlock()
+
+	eca.urls = urls
+}
+
+// Sign signs a new certificate by proxying the given certificate signing
+// request to an external CFSSL API server.
+func (eca *ExternalCA) Sign(req signer.SignRequest) (cert []byte, err error) {
+	// Get the current HTTP client and list of URLs in a small critical
+	// section. We will use these to make certificate signing requests.
+	eca.mu.Lock()
+	urls := eca.urls
+	client := eca.client
+	eca.mu.Unlock()
+
+	if len(urls) == 0 {
+		return nil, ErrNoExternalCAURLs
+	}
+
+	csrJSON, err := json.Marshal(req)
+	if err != nil {
+		return nil, fmt.Errorf("unable to JSON-encode CFSSL signing request: %s", err)
+	}
+
+	// Try each configured proxy URL. Return after the first success. If
+	// all fail then the last error will be returned.
+	for _, url := range urls {
+		cert, err = makeExternalSignRequest(client, url, csrJSON)
+		if err == nil {
+			return eca.rootCA.AppendFirstRootPEM(cert)
+		}
+
+		log.Debugf("unable to proxy certificate signing request to %s: %s", url, err)
+	}
+
+	return nil, err
+}
+
+func makeExternalSignRequest(client *http.Client, url string, csrJSON []byte) (cert []byte, err error) {
+	resp, err := client.Post(url, "application/json", bytes.NewReader(csrJSON))
+	if err != nil {
+		return nil, fmt.Errorf("unable to perform certificate signing request: %s", err)
+	}
+	defer resp.Body.Close()
+
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return nil, fmt.Errorf("unable to read CSR response body: %s", err)
+	}
+
+	if resp.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf("unexpected status code in CSR response: %d - %s", resp.StatusCode, string(body))
+	}
+
+	var apiResponse api.Response
+	if err := json.Unmarshal(body, &apiResponse); err != nil {
+		log.Debugf("unable to JSON-parse CFSSL API response body: %s", string(body))
+		return nil, fmt.Errorf("unable to parse JSON response: %s", err)
+	}
+
+	if !apiResponse.Success || apiResponse.Result == nil {
+		if len(apiResponse.Errors) > 0 {
+			return nil, fmt.Errorf("response errors: %v", apiResponse.Errors)
+		}
+
+		return nil, fmt.Errorf("certificate signing request failed")
+	}
+
+	result, ok := apiResponse.Result.(map[string]interface{})
+	if !ok {
+		return nil, fmt.Errorf("invalid result type: %T", apiResponse.Result)
+	}
+
+	certPEM, ok := result["certificate"].(string)
+	if !ok {
+		return nil, fmt.Errorf("invalid result certificate field type: %T", result["certificate"])
+	}
+
+	return []byte(certPEM), nil
+}

+ 34 - 9
vendor/src/github.com/docker/swarmkit/ca/server.go

@@ -355,7 +355,7 @@ func (s *Server) Run(ctx context.Context) error {
 	s.mu.Lock()
 	s.mu.Lock()
 	if s.isRunning() {
 	if s.isRunning() {
 		s.mu.Unlock()
 		s.mu.Unlock()
-		return fmt.Errorf("CA signer is stopped")
+		return fmt.Errorf("CA signer is already running")
 	}
 	}
 	s.wg.Add(1)
 	s.wg.Add(1)
 	defer s.wg.Done()
 	defer s.wg.Done()
@@ -443,12 +443,14 @@ func (s *Server) Run(ctx context.Context) error {
 func (s *Server) Stop() error {
 func (s *Server) Stop() error {
 	s.mu.Lock()
 	s.mu.Lock()
 	if !s.isRunning() {
 	if !s.isRunning() {
+		s.mu.Unlock()
 		return fmt.Errorf("CA signer is already stopped")
 		return fmt.Errorf("CA signer is already stopped")
 	}
 	}
 	s.cancel()
 	s.cancel()
 	s.mu.Unlock()
 	s.mu.Unlock()
 	// wait for all handlers to finish their CA deals,
 	// wait for all handlers to finish their CA deals,
 	s.wg.Wait()
 	s.wg.Wait()
+	s.started = make(chan struct{})
 	return nil
 	return nil
 }
 }
 
 
@@ -530,6 +532,21 @@ func (s *Server) updateCluster(ctx context.Context, cluster *api.Cluster) {
 			}).Debugf("Root CA updated successfully")
 			}).Debugf("Root CA updated successfully")
 		}
 		}
 	}
 	}
+
+	// Update our security config with the list of External CA URLs
+	// from the new cluster state.
+
+	// TODO(aaronl): In the future, this will be abstracted with an
+	// ExternalCA interface that has different implementations for
+	// different CA types. At the moment, only CFSSL is supported.
+	var cfsslURLs []string
+	for _, ca := range cluster.Spec.CAConfig.ExternalCAs {
+		if ca.Protocol == api.ExternalCA_CAProtocolCFSSL {
+			cfsslURLs = append(cfsslURLs, ca.URL)
+		}
+	}
+
+	s.securityConfig.externalCA.UpdateURLs(cfsslURLs...)
 }
 }
 
 
 // evaluateAndSignNodeCert implements the logic of which certificates to sign
 // evaluateAndSignNodeCert implements the logic of which certificates to sign
@@ -555,13 +572,8 @@ func (s *Server) evaluateAndSignNodeCert(ctx context.Context, node *api.Node) {
 
 
 // signNodeCert does the bulk of the work for signing a certificate
 // signNodeCert does the bulk of the work for signing a certificate
 func (s *Server) signNodeCert(ctx context.Context, node *api.Node) {
 func (s *Server) signNodeCert(ctx context.Context, node *api.Node) {
-	if !s.securityConfig.RootCA().CanSign() {
-		log.G(ctx).WithFields(logrus.Fields{
-			"node.id": node.ID,
-			"method":  "(*Server).signNodeCert",
-		}).Errorf("no valid signer found")
-		return
-	}
+	rootCA := s.securityConfig.RootCA()
+	externalCA := s.securityConfig.externalCA
 
 
 	node = node.Copy()
 	node = node.Copy()
 	nodeID := node.ID
 	nodeID := node.ID
@@ -576,7 +588,20 @@ func (s *Server) signNodeCert(ctx context.Context, node *api.Node) {
 	}
 	}
 
 
 	// Attempt to sign the CSR
 	// Attempt to sign the CSR
-	cert, err := s.securityConfig.RootCA().ParseValidateAndSignCSR(node.Certificate.CSR, node.Certificate.CN, role, s.securityConfig.ClientTLSCreds.Organization())
+	var (
+		rawCSR = node.Certificate.CSR
+		cn     = node.Certificate.CN
+		ou     = role
+		org    = s.securityConfig.ClientTLSCreds.Organization()
+	)
+
+	// Try using the external CA first.
+	cert, err := externalCA.Sign(PrepareCSR(rawCSR, cn, ou, org))
+	if err == ErrNoExternalCAURLs {
+		// No external CA servers configured. Try using the local CA.
+		cert, err = rootCA.ParseValidateAndSignCSR(rawCSR, cn, ou, org)
+	}
+
 	if err != nil {
 	if err != nil {
 		log.G(ctx).WithFields(logrus.Fields{
 		log.G(ctx).WithFields(logrus.Fields{
 			"node.id": node.ID,
 			"node.id": node.ID,

+ 8 - 0
vendor/src/github.com/docker/swarmkit/ca/transport.go

@@ -124,6 +124,14 @@ func (c *MutableTLSCreds) LoadNewTLSConfig(newConfig *tls.Config) error {
 	return nil
 	return nil
 }
 }
 
 
+// Config returns the current underlying TLS config.
+func (c *MutableTLSCreds) Config() *tls.Config {
+	c.Lock()
+	defer c.Unlock()
+
+	return c.config
+}
+
 // Role returns the OU for the certificate encapsulated in this TransportAuthenticator
 // Role returns the OU for the certificate encapsulated in this TransportAuthenticator
 func (c *MutableTLSCreds) Role() string {
 func (c *MutableTLSCreds) Role() string {
 	c.Lock()
 	c.Lock()

+ 64 - 16
vendor/src/github.com/docker/swarmkit/manager/allocator/network.go

@@ -52,6 +52,16 @@ type networkContext struct {
 	// A table of unallocated tasks which will be revisited if any thing
 	// A table of unallocated tasks which will be revisited if any thing
 	// changes in system state that might help task allocation.
 	// changes in system state that might help task allocation.
 	unallocatedTasks map[string]*api.Task
 	unallocatedTasks map[string]*api.Task
+
+	// A table of unallocated services which will be revisited if
+	// any thing changes in system state that might help service
+	// allocation.
+	unallocatedServices map[string]*api.Service
+
+	// A table of unallocated networks which will be revisited if
+	// any thing changes in system state that might help network
+	// allocation.
+	unallocatedNetworks map[string]*api.Network
 }
 }
 
 
 func (a *Allocator) doNetworkInit(ctx context.Context) error {
 func (a *Allocator) doNetworkInit(ctx context.Context) error {
@@ -61,8 +71,10 @@ func (a *Allocator) doNetworkInit(ctx context.Context) error {
 	}
 	}
 
 
 	nc := &networkContext{
 	nc := &networkContext{
-		nwkAllocator:     na,
-		unallocatedTasks: make(map[string]*api.Task),
+		nwkAllocator:        na,
+		unallocatedTasks:    make(map[string]*api.Task),
+		unallocatedServices: make(map[string]*api.Service),
+		unallocatedNetworks: make(map[string]*api.Network),
 	}
 	}
 
 
 	// Check if we have the ingress network. If not found create
 	// 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) {
 	case state.EventCreateTask, state.EventUpdateTask, state.EventDeleteTask:
 	case state.EventCreateTask, state.EventUpdateTask, state.EventDeleteTask:
 		a.doTaskAlloc(ctx, nc, ev)
 		a.doTaskAlloc(ctx, nc, ev)
 	case state.EventCommit:
 	case state.EventCommit:
+		a.procUnallocatedNetworks(ctx, nc)
+		a.procUnallocatedServices(ctx, nc)
 		a.procUnallocatedTasksNetwork(ctx, nc)
 		a.procUnallocatedTasksNetwork(ctx, nc)
 		return
 		return
 	}
 	}
@@ -554,29 +568,34 @@ func (a *Allocator) allocateNode(ctx context.Context, nc *networkContext, node *
 }
 }
 
 
 func (a *Allocator) allocateService(ctx context.Context, nc *networkContext, s *api.Service) error {
 func (a *Allocator) allocateService(ctx context.Context, nc *networkContext, s *api.Service) error {
-	// The service is trying to expose ports to the external
-	// world. Automatically attach the service to the ingress
-	// network only if it is not already done.
-	if s.Spec.Endpoint != nil && len(s.Spec.Endpoint.Ports) != 0 {
+	if s.Spec.Endpoint != nil {
 		if s.Endpoint == nil {
 		if s.Endpoint == nil {
-			s.Endpoint = &api.Endpoint{}
+			s.Endpoint = &api.Endpoint{
+				Spec: s.Spec.Endpoint.Copy(),
+			}
 		}
 		}
 
 
-		var found bool
-		for _, vip := range s.Endpoint.VirtualIPs {
-			if vip.NetworkID == ingressNetwork.ID {
-				found = true
-				break
+		// The service is trying to expose ports to the external
+		// world. Automatically attach the service to the ingress
+		// network only if it is not already done.
+		if len(s.Spec.Endpoint.Ports) != 0 {
+			var found bool
+			for _, vip := range s.Endpoint.VirtualIPs {
+				if vip.NetworkID == ingressNetwork.ID {
+					found = true
+					break
+				}
 			}
 			}
-		}
 
 
-		if !found {
-			s.Endpoint.VirtualIPs = append(s.Endpoint.VirtualIPs,
-				&api.Endpoint_VirtualIP{NetworkID: ingressNetwork.ID})
+			if !found {
+				s.Endpoint.VirtualIPs = append(s.Endpoint.VirtualIPs,
+					&api.Endpoint_VirtualIP{NetworkID: ingressNetwork.ID})
+			}
 		}
 		}
 	}
 	}
 
 
 	if err := nc.nwkAllocator.ServiceAllocate(s); err != nil {
 	if err := nc.nwkAllocator.ServiceAllocate(s); err != nil {
+		nc.unallocatedServices[s.ID] = s
 		return err
 		return err
 	}
 	}
 
 
@@ -611,6 +630,7 @@ func (a *Allocator) allocateService(ctx context.Context, nc *networkContext, s *
 
 
 func (a *Allocator) allocateNetwork(ctx context.Context, nc *networkContext, n *api.Network) error {
 func (a *Allocator) allocateNetwork(ctx context.Context, nc *networkContext, n *api.Network) error {
 	if err := nc.nwkAllocator.Allocate(n); err != nil {
 	if err := nc.nwkAllocator.Allocate(n); err != nil {
+		nc.unallocatedNetworks[n.ID] = n
 		return fmt.Errorf("failed during network allocation for network %s: %v", n.ID, err)
 		return fmt.Errorf("failed during network allocation for network %s: %v", n.ID, err)
 	}
 	}
 
 
@@ -666,6 +686,8 @@ func (a *Allocator) allocateTask(ctx context.Context, nc *networkContext, tx sto
 			if !nc.nwkAllocator.IsAllocated(n) {
 			if !nc.nwkAllocator.IsAllocated(n) {
 				return nil, fmt.Errorf("network %s attached to task %s not allocated yet", n.ID, t.ID)
 				return nil, fmt.Errorf("network %s attached to task %s not allocated yet", n.ID, t.ID)
 			}
 			}
+
+			na.Network = n
 		}
 		}
 
 
 		if err := nc.nwkAllocator.AllocateTask(t); err != nil {
 		if err := nc.nwkAllocator.AllocateTask(t); err != nil {
@@ -696,6 +718,32 @@ func (a *Allocator) allocateTask(ctx context.Context, nc *networkContext, tx sto
 	return storeT, nil
 	return storeT, nil
 }
 }
 
 
+func (a *Allocator) procUnallocatedNetworks(ctx context.Context, nc *networkContext) {
+	for _, n := range nc.unallocatedNetworks {
+		if !nc.nwkAllocator.IsAllocated(n) {
+			if err := a.allocateNetwork(ctx, nc, n); err != nil {
+				log.G(ctx).Debugf("Failed allocation of unallocated network %s: %v", n.ID, err)
+				continue
+			}
+		}
+
+		delete(nc.unallocatedNetworks, n.ID)
+	}
+}
+
+func (a *Allocator) procUnallocatedServices(ctx context.Context, nc *networkContext) {
+	for _, s := range nc.unallocatedServices {
+		if serviceAllocationNeeded(s, nc) {
+			if err := a.allocateService(ctx, nc, s); err != nil {
+				log.G(ctx).Debugf("Failed allocation of unallocated service %s: %v", s.ID, err)
+				continue
+			}
+		}
+
+		delete(nc.unallocatedServices, s.ID)
+	}
+}
+
 func (a *Allocator) procUnallocatedTasksNetwork(ctx context.Context, nc *networkContext) {
 func (a *Allocator) procUnallocatedTasksNetwork(ctx context.Context, nc *networkContext) {
 	tasks := make([]*api.Task, 0, len(nc.unallocatedTasks))
 	tasks := make([]*api.Task, 0, len(nc.unallocatedTasks))
 
 

+ 10 - 4
vendor/src/github.com/docker/swarmkit/manager/allocator/networkallocator/networkallocator.go

@@ -14,7 +14,10 @@ import (
 )
 )
 
 
 const (
 const (
-	defaultDriver = "overlay"
+	// DefaultDriver defines the name of the driver to be used by
+	// default if a network without any driver name specified is
+	// created.
+	DefaultDriver = "overlay"
 )
 )
 
 
 var (
 var (
@@ -69,7 +72,7 @@ func New() (*NetworkAllocator, error) {
 	}
 	}
 
 
 	// Add the manager component of overlay driver to the registry.
 	// Add the manager component of overlay driver to the registry.
-	if err := reg.AddDriver(defaultDriver, defaultDriverInitFunc, nil); err != nil {
+	if err := reg.AddDriver(DefaultDriver, defaultDriverInitFunc, nil); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
@@ -96,6 +99,7 @@ func (na *NetworkAllocator) Allocate(n *api.Network) error {
 	}
 	}
 
 
 	if err := na.allocateDriverState(n); err != nil {
 	if err := na.allocateDriverState(n); err != nil {
+		na.freePools(n, pools)
 		return fmt.Errorf("failed while allocating driver state for network %s: %v", n.ID, err)
 		return fmt.Errorf("failed while allocating driver state for network %s: %v", n.ID, err)
 	}
 	}
 
 
@@ -146,7 +150,9 @@ func (na *NetworkAllocator) ServiceAllocate(s *api.Service) (err error) {
 	}
 	}
 
 
 	if s.Endpoint == nil {
 	if s.Endpoint == nil {
-		s.Endpoint = &api.Endpoint{}
+		s.Endpoint = &api.Endpoint{
+			Spec: s.Spec.Endpoint.Copy(),
+		}
 	}
 	}
 
 
 	// First allocate VIPs for all the pre-populated endpoint attachments
 	// First allocate VIPs for all the pre-populated endpoint attachments
@@ -520,7 +526,7 @@ func (na *NetworkAllocator) allocateDriverState(n *api.Network) error {
 
 
 // Resolve network driver
 // Resolve network driver
 func (na *NetworkAllocator) resolveDriver(n *api.Network) (driverapi.Driver, string, error) {
 func (na *NetworkAllocator) resolveDriver(n *api.Network) (driverapi.Driver, string, error) {
-	dName := defaultDriver
+	dName := DefaultDriver
 	if n.Spec.DriverConfig != nil && n.Spec.DriverConfig.Name != "" {
 	if n.Spec.DriverConfig != nil && n.Spec.DriverConfig.Name != "" {
 		dName = n.Spec.DriverConfig.Name
 		dName = n.Spec.DriverConfig.Name
 	}
 	}

+ 10 - 0
vendor/src/github.com/docker/swarmkit/manager/controlapi/network.go

@@ -3,8 +3,10 @@ package controlapi
 import (
 import (
 	"net"
 	"net"
 
 
+	"github.com/docker/libnetwork/ipamapi"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/identity"
 	"github.com/docker/swarmkit/identity"
+	"github.com/docker/swarmkit/manager/allocator/networkallocator"
 	"github.com/docker/swarmkit/manager/state/store"
 	"github.com/docker/swarmkit/manager/state/store"
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc"
@@ -57,6 +59,10 @@ func validateIPAM(ipam *api.IPAMOptions) error {
 		return err
 		return err
 	}
 	}
 
 
+	if ipam.Driver != nil && ipam.Driver.Name != ipamapi.DefaultIPAM {
+		return grpc.Errorf(codes.InvalidArgument, "invalid IPAM specified")
+	}
+
 	for _, ipamConf := range ipam.Configs {
 	for _, ipamConf := range ipam.Configs {
 		if err := validateIPAMConfiguration(ipamConf); err != nil {
 		if err := validateIPAMConfiguration(ipamConf); err != nil {
 			return err
 			return err
@@ -79,6 +85,10 @@ func validateNetworkSpec(spec *api.NetworkSpec) error {
 		return err
 		return err
 	}
 	}
 
 
+	if spec.DriverConfig != nil && spec.DriverConfig.Name != networkallocator.DefaultDriver {
+		return grpc.Errorf(codes.InvalidArgument, "invalid driver specified")
+	}
+
 	if err := validateIPAM(spec.IPAM); err != nil {
 	if err := validateIPAM(spec.IPAM); err != nil {
 		return err
 		return err
 	}
 	}

+ 69 - 6
vendor/src/github.com/docker/swarmkit/manager/controlapi/service.go

@@ -8,6 +8,7 @@ import (
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/identity"
 	"github.com/docker/swarmkit/identity"
 	"github.com/docker/swarmkit/manager/state/store"
 	"github.com/docker/swarmkit/manager/state/store"
+	"github.com/docker/swarmkit/protobuf/ptypes"
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/codes"
@@ -15,6 +16,7 @@ import (
 
 
 var (
 var (
 	errNetworkUpdateNotSupported = errors.New("changing network in service is not supported")
 	errNetworkUpdateNotSupported = errors.New("changing network in service is not supported")
+	errModeChangeNotAllowed      = errors.New("service mode change is not allowed")
 )
 )
 
 
 func validateResources(r *api.Resources) error {
 func validateResources(r *api.Resources) error {
@@ -45,21 +47,70 @@ func validateResourceRequirements(r *api.ResourceRequirements) error {
 	return nil
 	return nil
 }
 }
 
 
-func validateServiceSpecTemplate(spec *api.ServiceSpec) error {
-	if err := validateResourceRequirements(spec.Task.Resources); err != nil {
+func validateRestartPolicy(rp *api.RestartPolicy) error {
+	if rp == nil {
+		return nil
+	}
+
+	if rp.Delay != nil {
+		delay, err := ptypes.Duration(rp.Delay)
+		if err != nil {
+			return err
+		}
+		if delay < 0 {
+			return grpc.Errorf(codes.InvalidArgument, "TaskSpec: restart-delay cannot be negative")
+		}
+	}
+
+	if rp.Window != nil {
+		win, err := ptypes.Duration(rp.Window)
+		if err != nil {
+			return err
+		}
+		if win < 0 {
+			return grpc.Errorf(codes.InvalidArgument, "TaskSpec: restart-window cannot be negative")
+		}
+	}
+
+	return nil
+}
+
+func validateUpdate(uc *api.UpdateConfig) error {
+	if uc == nil {
+		return nil
+	}
+
+	delay, err := ptypes.Duration(&uc.Delay)
+	if err != nil {
+		return err
+	}
+
+	if delay < 0 {
+		return grpc.Errorf(codes.InvalidArgument, "TaskSpec: update-delay cannot be negative")
+	}
+
+	return nil
+}
+
+func validateTask(taskSpec api.TaskSpec) error {
+	if err := validateResourceRequirements(taskSpec.Resources); err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	if spec.Task.GetRuntime() == nil {
+	if err := validateRestartPolicy(taskSpec.Restart); err != nil {
+		return err
+	}
+
+	if taskSpec.GetRuntime() == nil {
 		return grpc.Errorf(codes.InvalidArgument, "TaskSpec: missing runtime")
 		return grpc.Errorf(codes.InvalidArgument, "TaskSpec: missing runtime")
 	}
 	}
 
 
-	_, ok := spec.Task.GetRuntime().(*api.TaskSpec_Container)
+	_, ok := taskSpec.GetRuntime().(*api.TaskSpec_Container)
 	if !ok {
 	if !ok {
 		return grpc.Errorf(codes.Unimplemented, "RuntimeSpec: unimplemented runtime in service spec")
 		return grpc.Errorf(codes.Unimplemented, "RuntimeSpec: unimplemented runtime in service spec")
 	}
 	}
 
 
-	container := spec.Task.GetContainer()
+	container := taskSpec.GetContainer()
 	if container == nil {
 	if container == nil {
 		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: missing in service spec")
 		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: missing in service spec")
 	}
 	}
@@ -99,7 +150,13 @@ func validateServiceSpec(spec *api.ServiceSpec) error {
 	if err := validateAnnotations(spec.Annotations); err != nil {
 	if err := validateAnnotations(spec.Annotations); err != nil {
 		return err
 		return err
 	}
 	}
-	if err := validateServiceSpecTemplate(spec); err != nil {
+	if err := validateTask(spec.Task); err != nil {
+		return err
+	}
+	if err := validateUpdate(spec.Update); err != nil {
+		return err
+	}
+	if err := validateEndpointSpec(spec.Endpoint); err != nil {
 		return err
 		return err
 	}
 	}
 	return nil
 	return nil
@@ -179,6 +236,12 @@ func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRe
 			return errNetworkUpdateNotSupported
 			return errNetworkUpdateNotSupported
 		}
 		}
 
 
+		// orchestrator is designed to be stateless, so it should not deal
+		// with service mode change (comparing current config with previous config).
+		// proper way to change service mode is to delete and re-add.
+		if request.Spec != nil && reflect.TypeOf(service.Spec.Mode) != reflect.TypeOf(request.Spec.Mode) {
+			return errModeChangeNotAllowed
+		}
 		service.Meta.Version = *request.ServiceVersion
 		service.Meta.Version = *request.ServiceVersion
 		service.Spec = *request.Spec.Copy()
 		service.Spec = *request.Spec.Copy()
 		return store.UpdateService(tx, service)
 		return store.UpdateService(tx, service)

+ 22 - 12
vendor/src/github.com/docker/swarmkit/manager/dispatcher/dispatcher.go

@@ -29,6 +29,7 @@ const (
 	DefaultHeartBeatPeriod       = 5 * time.Second
 	DefaultHeartBeatPeriod       = 5 * time.Second
 	defaultHeartBeatEpsilon      = 500 * time.Millisecond
 	defaultHeartBeatEpsilon      = 500 * time.Millisecond
 	defaultGracePeriodMultiplier = 3
 	defaultGracePeriodMultiplier = 3
+	defaultRateLimitPeriod       = 16 * time.Second
 
 
 	// maxBatchItems is the threshold of queued writes that should
 	// maxBatchItems is the threshold of queued writes that should
 	// trigger an actual transaction to commit them to the shared store.
 	// trigger an actual transaction to commit them to the shared store.
@@ -59,9 +60,12 @@ var (
 // DefautConfig.
 // DefautConfig.
 type Config struct {
 type Config struct {
 	// Addr configures the address the dispatcher reports to agents.
 	// Addr configures the address the dispatcher reports to agents.
-	Addr                  string
-	HeartbeatPeriod       time.Duration
-	HeartbeatEpsilon      time.Duration
+	Addr             string
+	HeartbeatPeriod  time.Duration
+	HeartbeatEpsilon time.Duration
+	// RateLimitPeriod specifies how often node with same ID can try to register
+	// new session.
+	RateLimitPeriod       time.Duration
 	GracePeriodMultiplier int
 	GracePeriodMultiplier int
 }
 }
 
 
@@ -70,6 +74,7 @@ func DefaultConfig() *Config {
 	return &Config{
 	return &Config{
 		HeartbeatPeriod:       DefaultHeartBeatPeriod,
 		HeartbeatPeriod:       DefaultHeartBeatPeriod,
 		HeartbeatEpsilon:      defaultHeartBeatEpsilon,
 		HeartbeatEpsilon:      defaultHeartBeatEpsilon,
+		RateLimitPeriod:       defaultRateLimitPeriod,
 		GracePeriodMultiplier: defaultGracePeriodMultiplier,
 		GracePeriodMultiplier: defaultGracePeriodMultiplier,
 	}
 	}
 }
 }
@@ -116,12 +121,11 @@ func (b weightedPeerByNodeID) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
 func New(cluster Cluster, c *Config) *Dispatcher {
 func New(cluster Cluster, c *Config) *Dispatcher {
 	return &Dispatcher{
 	return &Dispatcher{
 		addr:                      c.Addr,
 		addr:                      c.Addr,
-		nodes:                     newNodeStore(c.HeartbeatPeriod, c.HeartbeatEpsilon, c.GracePeriodMultiplier),
+		nodes:                     newNodeStore(c.HeartbeatPeriod, c.HeartbeatEpsilon, c.GracePeriodMultiplier, c.RateLimitPeriod),
 		store:                     cluster.MemoryStore(),
 		store:                     cluster.MemoryStore(),
 		cluster:                   cluster,
 		cluster:                   cluster,
 		mgrQueue:                  watch.NewQueue(16),
 		mgrQueue:                  watch.NewQueue(16),
 		keyMgrQueue:               watch.NewQueue(16),
 		keyMgrQueue:               watch.NewQueue(16),
-		lastSeenManagers:          getWeightedPeers(cluster),
 		taskUpdates:               make(map[string]*api.TaskStatus),
 		taskUpdates:               make(map[string]*api.TaskStatus),
 		processTaskUpdatesTrigger: make(chan struct{}, 1),
 		processTaskUpdatesTrigger: make(chan struct{}, 1),
 		config: c,
 		config: c,
@@ -149,12 +153,12 @@ func (d *Dispatcher) Run(ctx context.Context) error {
 	d.mu.Lock()
 	d.mu.Lock()
 	if d.isRunning() {
 	if d.isRunning() {
 		d.mu.Unlock()
 		d.mu.Unlock()
-		return fmt.Errorf("dispatcher is stopped")
+		return fmt.Errorf("dispatcher is already running")
 	}
 	}
 	logger := log.G(ctx).WithField("module", "dispatcher")
 	logger := log.G(ctx).WithField("module", "dispatcher")
 	ctx = log.WithLogger(ctx, logger)
 	ctx = log.WithLogger(ctx, logger)
 	if err := d.markNodesUnknown(ctx); err != nil {
 	if err := d.markNodesUnknown(ctx); err != nil {
-		logger.Errorf("failed to mark all nodes unknown: %v", err)
+		logger.Errorf(`failed to move all nodes to "unknown" state: %v`, err)
 	}
 	}
 	configWatcher, cancel, err := store.ViewAndWatch(
 	configWatcher, cancel, err := store.ViewAndWatch(
 		d.store,
 		d.store,
@@ -177,6 +181,7 @@ func (d *Dispatcher) Run(ctx context.Context) error {
 		state.EventUpdateCluster{},
 		state.EventUpdateCluster{},
 	)
 	)
 	if err != nil {
 	if err != nil {
+		d.mu.Unlock()
 		return err
 		return err
 	}
 	}
 	defer cancel()
 	defer cancel()
@@ -238,6 +243,7 @@ func (d *Dispatcher) Run(ctx context.Context) error {
 func (d *Dispatcher) Stop() error {
 func (d *Dispatcher) Stop() error {
 	d.mu.Lock()
 	d.mu.Lock()
 	if !d.isRunning() {
 	if !d.isRunning() {
+		d.mu.Unlock()
 		return fmt.Errorf("dispatcher is already stopped")
 		return fmt.Errorf("dispatcher is already stopped")
 	}
 	}
 	d.cancel()
 	d.cancel()
@@ -280,20 +286,20 @@ func (d *Dispatcher) markNodesUnknown(ctx context.Context) error {
 				}
 				}
 				node.Status = api.NodeStatus{
 				node.Status = api.NodeStatus{
 					State:   api.NodeStatus_UNKNOWN,
 					State:   api.NodeStatus_UNKNOWN,
-					Message: "Node marked as unknown due to leadership change in cluster",
+					Message: `Node moved to "unknown" state due to leadership change in cluster`,
 				}
 				}
 				nodeID := node.ID
 				nodeID := node.ID
 
 
 				expireFunc := func() {
 				expireFunc := func() {
 					log := log.WithField("node", nodeID)
 					log := log.WithField("node", nodeID)
-					nodeStatus := api.NodeStatus{State: api.NodeStatus_DOWN, Message: "heartbeat failure for unknown node"}
+					nodeStatus := api.NodeStatus{State: api.NodeStatus_DOWN, Message: `heartbeat failure for node in "unknown" state`}
 					log.Debugf("heartbeat expiration for unknown node")
 					log.Debugf("heartbeat expiration for unknown node")
 					if err := d.nodeRemove(nodeID, nodeStatus); err != nil {
 					if err := d.nodeRemove(nodeID, nodeStatus); err != nil {
-						log.WithError(err).Errorf("failed deregistering node after heartbeat expiration for unknown node")
+						log.WithError(err).Errorf(`failed deregistering node after heartbeat expiration for node in "unknown" state`)
 					}
 					}
 				}
 				}
 				if err := d.nodes.AddUnknown(node, expireFunc); err != nil {
 				if err := d.nodes.AddUnknown(node, expireFunc); err != nil {
-					return fmt.Errorf("add unknown node failed: %v", err)
+					return fmt.Errorf(`adding node in "unknown" state to node store failed: %v`, err)
 				}
 				}
 				if err := store.UpdateNode(tx, node); err != nil {
 				if err := store.UpdateNode(tx, node); err != nil {
 					return fmt.Errorf("update failed %v", err)
 					return fmt.Errorf("update failed %v", err)
@@ -301,7 +307,7 @@ func (d *Dispatcher) markNodesUnknown(ctx context.Context) error {
 				return nil
 				return nil
 			})
 			})
 			if err != nil {
 			if err != nil {
-				log.WithField("node", n.ID).WithError(err).Errorf("failed to mark node as unknown")
+				log.WithField("node", n.ID).WithError(err).Errorf(`failed to move node to "unknown" state`)
 			}
 			}
 		}
 		}
 		return nil
 		return nil
@@ -328,6 +334,10 @@ func (d *Dispatcher) register(ctx context.Context, nodeID string, description *a
 		return "", "", err
 		return "", "", err
 	}
 	}
 
 
+	if err := d.nodes.CheckRateLimit(nodeID); err != nil {
+		return "", "", err
+	}
+
 	// create or update node in store
 	// create or update node in store
 	// TODO(stevvooe): Validate node specification.
 	// TODO(stevvooe): Validate node specification.
 	var node *api.Node
 	var node *api.Node

+ 18 - 1
vendor/src/github.com/docker/swarmkit/manager/dispatcher/nodes.go

@@ -15,6 +15,7 @@ import (
 type registeredNode struct {
 type registeredNode struct {
 	SessionID  string
 	SessionID  string
 	Heartbeat  *heartbeat.Heartbeat
 	Heartbeat  *heartbeat.Heartbeat
+	Registered time.Time
 	Node       *api.Node
 	Node       *api.Node
 	Disconnect chan struct{} // signal to disconnect
 	Disconnect chan struct{} // signal to disconnect
 	mu         sync.Mutex
 	mu         sync.Mutex
@@ -41,15 +42,17 @@ func (rn *registeredNode) checkSessionID(sessionID string) error {
 type nodeStore struct {
 type nodeStore struct {
 	periodChooser         *periodChooser
 	periodChooser         *periodChooser
 	gracePeriodMultiplier time.Duration
 	gracePeriodMultiplier time.Duration
+	rateLimitPeriod       time.Duration
 	nodes                 map[string]*registeredNode
 	nodes                 map[string]*registeredNode
 	mu                    sync.RWMutex
 	mu                    sync.RWMutex
 }
 }
 
 
-func newNodeStore(hbPeriod, hbEpsilon time.Duration, graceMultiplier int) *nodeStore {
+func newNodeStore(hbPeriod, hbEpsilon time.Duration, graceMultiplier int, rateLimitPeriod time.Duration) *nodeStore {
 	return &nodeStore{
 	return &nodeStore{
 		nodes:                 make(map[string]*registeredNode),
 		nodes:                 make(map[string]*registeredNode),
 		periodChooser:         newPeriodChooser(hbPeriod, hbEpsilon),
 		periodChooser:         newPeriodChooser(hbPeriod, hbEpsilon),
 		gracePeriodMultiplier: time.Duration(graceMultiplier),
 		gracePeriodMultiplier: time.Duration(graceMultiplier),
+		rateLimitPeriod:       rateLimitPeriod,
 	}
 	}
 }
 }
 
 
@@ -77,6 +80,19 @@ func (s *nodeStore) AddUnknown(n *api.Node, expireFunc func()) error {
 	return nil
 	return nil
 }
 }
 
 
+// CheckRateLimit returs error if node with specified id is allowed to re-register
+// again.
+func (s *nodeStore) CheckRateLimit(id string) error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	if existRn, ok := s.nodes[id]; ok {
+		if time.Since(existRn.Registered) < s.rateLimitPeriod {
+			return grpc.Errorf(codes.Unavailable, "node %s attempted registration too recently", id)
+		}
+	}
+	return nil
+}
+
 // Add adds new node and returns it, it replaces existing without notification.
 // Add adds new node and returns it, it replaces existing without notification.
 func (s *nodeStore) Add(n *api.Node, expireFunc func()) *registeredNode {
 func (s *nodeStore) Add(n *api.Node, expireFunc func()) *registeredNode {
 	s.mu.Lock()
 	s.mu.Lock()
@@ -88,6 +104,7 @@ func (s *nodeStore) Add(n *api.Node, expireFunc func()) *registeredNode {
 	rn := &registeredNode{
 	rn := &registeredNode{
 		SessionID:  identity.NewID(), // session ID is local to the dispatcher.
 		SessionID:  identity.NewID(), // session ID is local to the dispatcher.
 		Node:       n,
 		Node:       n,
+		Registered: time.Now(),
 		Disconnect: make(chan struct{}),
 		Disconnect: make(chan struct{}),
 	}
 	}
 	s.nodes[n.ID] = rn
 	s.nodes[n.ID] = rn

+ 58 - 0
vendor/src/github.com/docker/swarmkit/manager/health/health.go

@@ -0,0 +1,58 @@
+// Package health provides some utility functions to health-check a server. The implementation
+// is based on protobuf. Users need to write their own implementations if other IDLs are used.
+//
+// See original source: https://github.com/grpc/grpc-go/blob/master/health/health.go
+//
+// We use our own implementation of grpc server health check to include the authorization
+// wrapper necessary for the Managers.
+package health
+
+import (
+	"sync"
+
+	"github.com/docker/swarmkit/api"
+	"golang.org/x/net/context"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+)
+
+// Server represents a Health Check server to check
+// if a service is running or not on some host.
+type Server struct {
+	mu sync.Mutex
+	// statusMap stores the serving status of the services this HealthServer monitors.
+	statusMap map[string]api.HealthCheckResponse_ServingStatus
+}
+
+// NewHealthServer creates a new health check server for grpc services.
+func NewHealthServer() *Server {
+	return &Server{
+		statusMap: make(map[string]api.HealthCheckResponse_ServingStatus),
+	}
+}
+
+// Check checks if the grpc server is healthy and running.
+func (s *Server) Check(ctx context.Context, in *api.HealthCheckRequest) (*api.HealthCheckResponse, error) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	if in.Service == "" {
+		// check the server overall health status.
+		return &api.HealthCheckResponse{
+			Status: api.HealthCheckResponse_SERVING,
+		}, nil
+	}
+	if status, ok := s.statusMap[in.Service]; ok {
+		return &api.HealthCheckResponse{
+			Status: status,
+		}, nil
+	}
+	return nil, grpc.Errorf(codes.NotFound, "unknown service")
+}
+
+// SetServingStatus is called when need to reset the serving status of a service
+// or insert a new service entry into the statusMap.
+func (s *Server) SetServingStatus(service string, status api.HealthCheckResponse_ServingStatus) {
+	s.mu.Lock()
+	s.statusMap[service] = status
+	s.mu.Unlock()
+}

+ 7 - 4
vendor/src/github.com/docker/swarmkit/manager/keymanager/keymanager.go

@@ -32,6 +32,8 @@ const (
 
 
 	// DefaultSubsystem is gossip
 	// DefaultSubsystem is gossip
 	DefaultSubsystem = SubsystemGossip
 	DefaultSubsystem = SubsystemGossip
+	// number of keys to mainrain in the key ring.
+	keyringSize = 3
 )
 )
 
 
 // map of subsystems and corresponding encryption algorithm. Initially only
 // map of subsystems and corresponding encryption algorithm. Initially only
@@ -59,7 +61,6 @@ type KeyManager struct {
 	config  *Config
 	config  *Config
 	store   *store.MemoryStore
 	store   *store.MemoryStore
 	keyRing *keyRing
 	keyRing *keyRing
-	ticker  *time.Ticker
 	ctx     context.Context
 	ctx     context.Context
 	cancel  context.CancelFunc
 	cancel  context.CancelFunc
 
 
@@ -72,7 +73,7 @@ func DefaultConfig() *Config {
 		ClusterName:      store.DefaultClusterName,
 		ClusterName:      store.DefaultClusterName,
 		Keylen:           DefaultKeyLen,
 		Keylen:           DefaultKeyLen,
 		RotationInterval: DefaultKeyRotationInterval,
 		RotationInterval: DefaultKeyRotationInterval,
-		Subsystems:       []string{DefaultSubsystem},
+		Subsystems:       []string{SubsystemGossip, SubsystemIPSec},
 	}
 	}
 }
 }
 
 
@@ -148,7 +149,7 @@ func (k *KeyManager) rotateKey(ctx context.Context) error {
 	// We maintain the latest key and the one before in the key ring to allow
 	// We maintain the latest key and the one before in the key ring to allow
 	// agents to communicate without disruption on key change.
 	// agents to communicate without disruption on key change.
 	for subsys, keys := range subsysKeys {
 	for subsys, keys := range subsysKeys {
-		if len(keys) > 1 {
+		if len(keys) == keyringSize {
 			min := 0
 			min := 0
 			for i, key := range keys[1:] {
 			for i, key := range keys[1:] {
 				if key.LamportTime < keys[min].LamportTime {
 				if key.LamportTime < keys[min].LamportTime {
@@ -189,7 +190,9 @@ func (k *KeyManager) Run(ctx context.Context) error {
 	cluster := clusters[0]
 	cluster := clusters[0]
 	if len(cluster.NetworkBootstrapKeys) == 0 {
 	if len(cluster.NetworkBootstrapKeys) == 0 {
 		for _, subsys := range k.config.Subsystems {
 		for _, subsys := range k.config.Subsystems {
-			k.keyRing.keys = append(k.keyRing.keys, k.allocateKey(ctx, subsys))
+			for i := 0; i < keyringSize; i++ {
+				k.keyRing.keys = append(k.keyRing.keys, k.allocateKey(ctx, subsys))
+			}
 		}
 		}
 		if err := k.updateKey(cluster); err != nil {
 		if err := k.updateKey(cluster); err != nil {
 			log.Errorf("store update failed %v", err)
 			log.Errorf("store update failed %v", err)

+ 34 - 19
vendor/src/github.com/docker/swarmkit/manager/manager.go

@@ -19,6 +19,7 @@ import (
 	"github.com/docker/swarmkit/manager/allocator"
 	"github.com/docker/swarmkit/manager/allocator"
 	"github.com/docker/swarmkit/manager/controlapi"
 	"github.com/docker/swarmkit/manager/controlapi"
 	"github.com/docker/swarmkit/manager/dispatcher"
 	"github.com/docker/swarmkit/manager/dispatcher"
+	"github.com/docker/swarmkit/manager/health"
 	"github.com/docker/swarmkit/manager/keymanager"
 	"github.com/docker/swarmkit/manager/keymanager"
 	"github.com/docker/swarmkit/manager/orchestrator"
 	"github.com/docker/swarmkit/manager/orchestrator"
 	"github.com/docker/swarmkit/manager/raftpicker"
 	"github.com/docker/swarmkit/manager/raftpicker"
@@ -39,6 +40,10 @@ const (
 type Config struct {
 type Config struct {
 	SecurityConfig *ca.SecurityConfig
 	SecurityConfig *ca.SecurityConfig
 
 
+	// ExternalCAs is a list of initial CAs to which a manager node
+	// will make certificate signing requests for node certificates.
+	ExternalCAs []*api.ExternalCA
+
 	ProtoAddr map[string]string
 	ProtoAddr map[string]string
 	// ProtoListener will be used for grpc serving if it's not nil,
 	// ProtoListener will be used for grpc serving if it's not nil,
 	// ProtoAddr fields will be used to create listeners otherwise.
 	// ProtoAddr fields will be used to create listeners otherwise.
@@ -83,8 +88,7 @@ type Manager struct {
 	localserver            *grpc.Server
 	localserver            *grpc.Server
 	RaftNode               *raft.Node
 	RaftNode               *raft.Node
 
 
-	mu   sync.Mutex
-	once sync.Once
+	mu sync.Mutex
 
 
 	stopped chan struct{}
 	stopped chan struct{}
 }
 }
@@ -202,13 +206,7 @@ func New(config *Config) (*Manager, error) {
 		ForceNewCluster: config.ForceNewCluster,
 		ForceNewCluster: config.ForceNewCluster,
 		TLSCredentials:  config.SecurityConfig.ClientTLSCreds,
 		TLSCredentials:  config.SecurityConfig.ClientTLSCreds,
 	}
 	}
-	RaftNode, err := raft.NewNode(context.TODO(), newNodeOpts)
-	if err != nil {
-		for _, lis := range listeners {
-			lis.Close()
-		}
-		return nil, fmt.Errorf("can't create raft node: %v", err)
-	}
+	RaftNode := raft.NewNode(context.TODO(), newNodeOpts)
 
 
 	opts := []grpc.ServerOption{
 	opts := []grpc.ServerOption{
 		grpc.Creds(config.SecurityConfig.ServerTLSCreds)}
 		grpc.Creds(config.SecurityConfig.ServerTLSCreds)}
@@ -275,6 +273,10 @@ func (m *Manager) Run(parent context.Context) error {
 				raftCfg.HeartbeatTick = uint32(m.RaftNode.Config.HeartbeatTick)
 				raftCfg.HeartbeatTick = uint32(m.RaftNode.Config.HeartbeatTick)
 
 
 				clusterID := m.config.SecurityConfig.ClientTLSCreds.Organization()
 				clusterID := m.config.SecurityConfig.ClientTLSCreds.Organization()
+
+				initialCAConfig := ca.DefaultCAConfig()
+				initialCAConfig.ExternalCAs = m.config.ExternalCAs
+
 				s.Update(func(tx store.Tx) error {
 				s.Update(func(tx store.Tx) error {
 					// Add a default cluster object to the
 					// Add a default cluster object to the
 					// store. Don't check the error because
 					// store. Don't check the error because
@@ -294,7 +296,7 @@ func (m *Manager) Run(parent context.Context) error {
 								HeartbeatPeriod: ptypes.DurationProto(dispatcher.DefaultHeartBeatPeriod),
 								HeartbeatPeriod: ptypes.DurationProto(dispatcher.DefaultHeartBeatPeriod),
 							},
 							},
 							Raft:     raftCfg,
 							Raft:     raftCfg,
-							CAConfig: ca.DefaultCAConfig(),
+							CAConfig: initialCAConfig,
 						},
 						},
 						RootCA: api.RootCA{
 						RootCA: api.RootCA{
 							CAKey:      rootCA.Key,
 							CAKey:      rootCA.Key,
@@ -327,7 +329,7 @@ func (m *Manager) Run(parent context.Context) error {
 					log.G(ctx).WithError(err).Error("root key-encrypting-key rotation failed")
 					log.G(ctx).WithError(err).Error("root key-encrypting-key rotation failed")
 				}
 				}
 
 
-				m.replicatedOrchestrator = orchestrator.New(s)
+				m.replicatedOrchestrator = orchestrator.NewReplicatedOrchestrator(s)
 				m.globalOrchestrator = orchestrator.NewGlobalOrchestrator(s)
 				m.globalOrchestrator = orchestrator.NewGlobalOrchestrator(s)
 				m.taskReaper = orchestrator.NewTaskReaper(s)
 				m.taskReaper = orchestrator.NewTaskReaper(s)
 				m.scheduler = scheduler.New(s)
 				m.scheduler = scheduler.New(s)
@@ -421,14 +423,6 @@ func (m *Manager) Run(parent context.Context) error {
 		}
 		}
 	}()
 	}()
 
 
-	go func() {
-		err := m.RaftNode.Run(ctx)
-		if err != nil {
-			log.G(ctx).Error(err)
-			m.Stop(ctx)
-		}
-	}()
-
 	proxyOpts := []grpc.DialOption{
 	proxyOpts := []grpc.DialOption{
 		grpc.WithBackoffMaxDelay(2 * time.Second),
 		grpc.WithBackoffMaxDelay(2 * time.Second),
 		grpc.WithTransportCredentials(m.config.SecurityConfig.ClientTLSCreds),
 		grpc.WithTransportCredentials(m.config.SecurityConfig.ClientTLSCreds),
@@ -443,12 +437,14 @@ func (m *Manager) Run(parent context.Context) error {
 	}
 	}
 
 
 	baseControlAPI := controlapi.NewServer(m.RaftNode.MemoryStore(), m.RaftNode)
 	baseControlAPI := controlapi.NewServer(m.RaftNode.MemoryStore(), m.RaftNode)
+	healthServer := health.NewHealthServer()
 
 
 	authenticatedControlAPI := api.NewAuthenticatedWrapperControlServer(baseControlAPI, authorize)
 	authenticatedControlAPI := api.NewAuthenticatedWrapperControlServer(baseControlAPI, authorize)
 	authenticatedDispatcherAPI := api.NewAuthenticatedWrapperDispatcherServer(m.Dispatcher, authorize)
 	authenticatedDispatcherAPI := api.NewAuthenticatedWrapperDispatcherServer(m.Dispatcher, authorize)
 	authenticatedCAAPI := api.NewAuthenticatedWrapperCAServer(m.caserver, authorize)
 	authenticatedCAAPI := api.NewAuthenticatedWrapperCAServer(m.caserver, authorize)
 	authenticatedNodeCAAPI := api.NewAuthenticatedWrapperNodeCAServer(m.caserver, authorize)
 	authenticatedNodeCAAPI := api.NewAuthenticatedWrapperNodeCAServer(m.caserver, authorize)
 	authenticatedRaftAPI := api.NewAuthenticatedWrapperRaftServer(m.RaftNode, authorize)
 	authenticatedRaftAPI := api.NewAuthenticatedWrapperRaftServer(m.RaftNode, authorize)
+	authenticatedHealthAPI := api.NewAuthenticatedWrapperHealthServer(healthServer, authorize)
 	authenticatedRaftMembershipAPI := api.NewAuthenticatedWrapperRaftMembershipServer(m.RaftNode, authorize)
 	authenticatedRaftMembershipAPI := api.NewAuthenticatedWrapperRaftMembershipServer(m.RaftNode, authorize)
 
 
 	proxyDispatcherAPI := api.NewRaftProxyDispatcherServer(authenticatedDispatcherAPI, cs, m.RaftNode, ca.WithMetadataForwardTLSInfo)
 	proxyDispatcherAPI := api.NewRaftProxyDispatcherServer(authenticatedDispatcherAPI, cs, m.RaftNode, ca.WithMetadataForwardTLSInfo)
@@ -470,6 +466,7 @@ func (m *Manager) Run(parent context.Context) error {
 	api.RegisterCAServer(m.server, proxyCAAPI)
 	api.RegisterCAServer(m.server, proxyCAAPI)
 	api.RegisterNodeCAServer(m.server, proxyNodeCAAPI)
 	api.RegisterNodeCAServer(m.server, proxyNodeCAAPI)
 	api.RegisterRaftServer(m.server, authenticatedRaftAPI)
 	api.RegisterRaftServer(m.server, authenticatedRaftAPI)
+	api.RegisterHealthServer(m.server, authenticatedHealthAPI)
 	api.RegisterRaftMembershipServer(m.server, proxyRaftMembershipAPI)
 	api.RegisterRaftMembershipServer(m.server, proxyRaftMembershipAPI)
 	api.RegisterControlServer(m.localserver, localProxyControlAPI)
 	api.RegisterControlServer(m.localserver, localProxyControlAPI)
 	api.RegisterControlServer(m.server, authenticatedControlAPI)
 	api.RegisterControlServer(m.server, authenticatedControlAPI)
@@ -492,6 +489,24 @@ func (m *Manager) Run(parent context.Context) error {
 		}(proto, l)
 		}(proto, l)
 	}
 	}
 
 
+	// Set the raft server as serving for the health server
+	healthServer.SetServingStatus("Raft", api.HealthCheckResponse_SERVING)
+
+	if err := m.RaftNode.JoinAndStart(); err != nil {
+		for _, lis := range m.listeners {
+			lis.Close()
+		}
+		return fmt.Errorf("can't initialize raft node: %v", err)
+	}
+
+	go func() {
+		err := m.RaftNode.Run(ctx)
+		if err != nil {
+			log.G(ctx).Error(err)
+			m.Stop(ctx)
+		}
+	}()
+
 	if err := raft.WaitForLeader(ctx, m.RaftNode); err != nil {
 	if err := raft.WaitForLeader(ctx, m.RaftNode); err != nil {
 		m.server.Stop()
 		m.server.Stop()
 		return err
 		return err

+ 1 - 1
vendor/src/github.com/docker/swarmkit/manager/orchestrator/global.go

@@ -255,7 +255,7 @@ func (g *GlobalOrchestrator) reconcileOneNode(ctx context.Context, node *api.Nod
 		return
 		return
 	}
 	}
 	// typically there are only a few global services on a node
 	// typically there are only a few global services on a node
-	// iterate thru all of them one by one. If raft store visits become a concern,
+	// iterate through all of them one by one. If raft store visits become a concern,
 	// it can be optimized.
 	// it can be optimized.
 	for _, service := range g.globalServices {
 	for _, service := range g.globalServices {
 		g.reconcileServiceOneNode(ctx, service.ID, node.ID)
 		g.reconcileServiceOneNode(ctx, service.ID, node.ID)

+ 5 - 2
vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated.go

@@ -29,8 +29,8 @@ type ReplicatedOrchestrator struct {
 	restarts *RestartSupervisor
 	restarts *RestartSupervisor
 }
 }
 
 
-// New creates a new ReplicatedOrchestrator.
-func New(store *store.MemoryStore) *ReplicatedOrchestrator {
+// NewReplicatedOrchestrator creates a new ReplicatedOrchestrator.
+func NewReplicatedOrchestrator(store *store.MemoryStore) *ReplicatedOrchestrator {
 	restartSupervisor := NewRestartSupervisor(store)
 	restartSupervisor := NewRestartSupervisor(store)
 	updater := NewUpdateSupervisor(store, restartSupervisor)
 	updater := NewUpdateSupervisor(store, restartSupervisor)
 	return &ReplicatedOrchestrator{
 	return &ReplicatedOrchestrator{
@@ -114,6 +114,9 @@ func newTask(service *api.Service, instance uint64) *api.Task {
 			Timestamp: ptypes.MustTimestampProto(time.Now()),
 			Timestamp: ptypes.MustTimestampProto(time.Now()),
 			Message:   "created",
 			Message:   "created",
 		},
 		},
+		Endpoint: &api.Endpoint{
+			Spec: service.Spec.Endpoint.Copy(),
+		},
 		DesiredState: api.TaskStateRunning,
 		DesiredState: api.TaskStateRunning,
 	}
 	}
 }
 }

+ 51 - 4
vendor/src/github.com/docker/swarmkit/manager/orchestrator/services.go

@@ -1,6 +1,8 @@
 package orchestrator
 package orchestrator
 
 
 import (
 import (
+	"sort"
+
 	"github.com/docker/go-events"
 	"github.com/docker/go-events"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/log"
 	"github.com/docker/swarmkit/log"
@@ -68,6 +70,27 @@ func (r *ReplicatedOrchestrator) resolveService(ctx context.Context, task *api.T
 	return service
 	return service
 }
 }
 
 
+type taskWithIndex struct {
+	task *api.Task
+
+	// index is a counter that counts this task as the nth instance of
+	// the service on its node. This is used for sorting the tasks so that
+	// when scaling down we leave tasks more evenly balanced.
+	index int
+}
+
+type tasksByIndex []taskWithIndex
+
+func (ts tasksByIndex) Len() int      { return len(ts) }
+func (ts tasksByIndex) Swap(i, j int) { ts[i], ts[j] = ts[j], ts[i] }
+
+func (ts tasksByIndex) Less(i, j int) bool {
+	if ts[i].index < 0 {
+		return false
+	}
+	return ts[i].index < ts[j].index
+}
+
 func (r *ReplicatedOrchestrator) reconcile(ctx context.Context, service *api.Service) {
 func (r *ReplicatedOrchestrator) reconcile(ctx context.Context, service *api.Service) {
 	var (
 	var (
 		tasks []*api.Task
 		tasks []*api.Task
@@ -97,8 +120,6 @@ func (r *ReplicatedOrchestrator) reconcile(ctx context.Context, service *api.Ser
 	deploy := service.Spec.GetMode().(*api.ServiceSpec_Replicated)
 	deploy := service.Spec.GetMode().(*api.ServiceSpec_Replicated)
 	specifiedInstances := int(deploy.Replicated.Replicas)
 	specifiedInstances := int(deploy.Replicated.Replicas)
 
 
-	// TODO(aaronl): Add support for restart delays.
-
 	switch {
 	switch {
 	case specifiedInstances > numTasks:
 	case specifiedInstances > numTasks:
 		log.G(ctx).Debugf("Service %s was scaled up from %d to %d instances", service.ID, numTasks, specifiedInstances)
 		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
 	case specifiedInstances < numTasks:
 	case specifiedInstances < numTasks:
 		// Update up to N tasks then remove the extra
 		// Update up to N tasks then remove the extra
 		log.G(ctx).Debugf("Service %s was scaled down from %d to %d instances", service.ID, numTasks, specifiedInstances)
 		log.G(ctx).Debugf("Service %s was scaled down from %d to %d instances", service.ID, numTasks, specifiedInstances)
-		r.updater.Update(ctx, service, runningTasks[:specifiedInstances])
+
+		// Preferentially remove tasks on the nodes that have the most
+		// copies of this service, to leave a more balanced result.
+		// Assign each task an index that counts it as the nth copy of
+		// of the service on its node (1, 2, 3, ...), and sort the
+		// tasks by this counter value.
+
+		instancesByNode := make(map[string]int)
+		tasksWithIndices := make(tasksByIndex, 0, numTasks)
+
+		for _, t := range runningTasks {
+			if t.NodeID != "" {
+				instancesByNode[t.NodeID]++
+				tasksWithIndices = append(tasksWithIndices, taskWithIndex{task: t, index: instancesByNode[t.NodeID]})
+			} else {
+				tasksWithIndices = append(tasksWithIndices, taskWithIndex{task: t, index: -1})
+			}
+		}
+
+		sort.Sort(tasksWithIndices)
+
+		sortedTasks := make([]*api.Task, 0, numTasks)
+		for _, t := range tasksWithIndices {
+			sortedTasks = append(sortedTasks, t.task)
+		}
+
+		r.updater.Update(ctx, service, sortedTasks[:specifiedInstances])
 		_, err = r.store.Batch(func(batch *store.Batch) error {
 		_, err = r.store.Batch(func(batch *store.Batch) error {
-			r.removeTasks(ctx, batch, service, runningTasks[specifiedInstances:])
+			r.removeTasks(ctx, batch, service, sortedTasks[specifiedInstances:])
 			return nil
 			return nil
 		})
 		})
 		if err != nil {
 		if err != nil {

+ 5 - 1
vendor/src/github.com/docker/swarmkit/manager/orchestrator/updater.go

@@ -104,7 +104,8 @@ func (u *Updater) Run(ctx context.Context, service *api.Service, tasks []*api.Ta
 	dirtyTasks := []*api.Task{}
 	dirtyTasks := []*api.Task{}
 	for _, t := range tasks {
 	for _, t := range tasks {
 		if !reflect.DeepEqual(service.Spec.Task, t.Spec) ||
 		if !reflect.DeepEqual(service.Spec.Task, t.Spec) ||
-			!reflect.DeepEqual(service.Endpoint, t.Endpoint) {
+			(t.Endpoint != nil &&
+				!reflect.DeepEqual(service.Spec.Endpoint, t.Endpoint.Spec)) {
 			dirtyTasks = append(dirtyTasks, t)
 			dirtyTasks = append(dirtyTasks, t)
 		}
 		}
 	}
 	}
@@ -191,6 +192,9 @@ func (u *Updater) updateTask(ctx context.Context, service *api.Service, original
 		if t == nil {
 		if t == nil {
 			return fmt.Errorf("task %s not found while trying to update it", original.ID)
 			return fmt.Errorf("task %s not found while trying to update it", original.ID)
 		}
 		}
+		if t.DesiredState > api.TaskStateRunning {
+			return fmt.Errorf("task %s was already shut down when reached by updater", original.ID)
+		}
 		t.DesiredState = api.TaskStateShutdown
 		t.DesiredState = api.TaskStateShutdown
 		if err := store.UpdateTask(tx, t); err != nil {
 		if err := store.UpdateTask(tx, t); err != nil {
 			return err
 			return err

+ 1 - 10
vendor/src/github.com/docker/swarmkit/manager/scheduler/indexed_node_heap.go

@@ -48,13 +48,6 @@ func (nh *nodeHeap) alloc(n int) {
 	nh.index = make(map[string]int, n)
 	nh.index = make(map[string]int, n)
 }
 }
 
 
-func (nh *nodeHeap) peek() *NodeInfo {
-	if len(nh.heap) == 0 {
-		return nil
-	}
-	return &nh.heap[0]
-}
-
 // nodeInfo returns the NodeInfo struct for a given node identified by its ID.
 // nodeInfo returns the NodeInfo struct for a given node identified by its ID.
 func (nh *nodeHeap) nodeInfo(nodeID string) NodeInfo {
 func (nh *nodeHeap) nodeInfo(nodeID string) NodeInfo {
 	index, ok := nh.index[nodeID]
 	index, ok := nh.index[nodeID]
@@ -95,9 +88,7 @@ func (nh *nodeHeap) updateNode(n NodeInfo) {
 func (nh *nodeHeap) remove(nodeID string) {
 func (nh *nodeHeap) remove(nodeID string) {
 	index, ok := nh.index[nodeID]
 	index, ok := nh.index[nodeID]
 	if ok {
 	if ok {
-		nh.heap[index].Tasks = nil
-		heap.Fix(nh, index)
-		heap.Pop(nh)
+		heap.Remove(nh, index)
 	}
 	}
 }
 }
 
 

+ 6 - 10
vendor/src/github.com/docker/swarmkit/manager/state/raft/membership/cluster.go

@@ -27,8 +27,6 @@ var (
 // Cluster represents a set of active
 // Cluster represents a set of active
 // raft Members
 // raft Members
 type Cluster struct {
 type Cluster struct {
-	id uint64
-
 	mu      sync.RWMutex
 	mu      sync.RWMutex
 	members map[uint64]*Member
 	members map[uint64]*Member
 
 
@@ -103,17 +101,15 @@ func (c *Cluster) RemoveMember(id uint64) error {
 	c.mu.Lock()
 	c.mu.Lock()
 	defer c.mu.Unlock()
 	defer c.mu.Unlock()
 
 
-	if c.members[id] == nil {
-		return ErrIDNotFound
-	}
-
-	conn := c.members[id].Conn
-	if conn != nil {
-		_ = conn.Close()
+	if c.members[id] != nil {
+		conn := c.members[id].Conn
+		if conn != nil {
+			_ = conn.Close()
+		}
+		delete(c.members, id)
 	}
 	}
 
 
 	c.removed[id] = true
 	c.removed[id] = true
-	delete(c.members, id)
 	return nil
 	return nil
 }
 }
 
 

+ 127 - 50
vendor/src/github.com/docker/swarmkit/manager/state/raft/raft.go

@@ -31,6 +31,11 @@ import (
 )
 )
 
 
 var (
 var (
+	// ErrHealthCheckFailure is returned when there is an issue with the initial handshake which means
+	// that the address provided must be invalid or there is ongoing connectivity issues at join time.
+	ErrHealthCheckFailure = errors.New("raft: could not connect to prospective new cluster member using its advertised address")
+	// ErrNoRaftMember is thrown when the node is not yet part of a raft cluster
+	ErrNoRaftMember = errors.New("raft: node is not yet part of a raft cluster")
 	// ErrConfChangeRefused is returned when there is an issue with the configuration change
 	// ErrConfChangeRefused is returned when there is an issue with the configuration change
 	ErrConfChangeRefused = errors.New("raft: propose configuration change refused")
 	ErrConfChangeRefused = errors.New("raft: propose configuration change refused")
 	// ErrApplyNotSpecified is returned during the creation of a raft node when no apply method was provided
 	// ErrApplyNotSpecified is returned during the creation of a raft node when no apply method was provided
@@ -83,12 +88,13 @@ type Node struct {
 	raftStore   *raft.MemoryStorage
 	raftStore   *raft.MemoryStorage
 	memoryStore *store.MemoryStore
 	memoryStore *store.MemoryStore
 	Config      *raft.Config
 	Config      *raft.Config
+	opts        NewNodeOptions
 	reqIDGen    *idutil.Generator
 	reqIDGen    *idutil.Generator
 	wait        *wait
 	wait        *wait
 	wal         *wal.WAL
 	wal         *wal.WAL
 	snapshotter *snap.Snapshotter
 	snapshotter *snap.Snapshotter
 	wasLeader   bool
 	wasLeader   bool
-	removed     uint32
+	isMember    uint32
 	joinAddr    string
 	joinAddr    string
 
 
 	// waitProp waits for all the proposals to be terminated before
 	// waitProp waits for all the proposals to be terminated before
@@ -103,14 +109,15 @@ type Node struct {
 	appliedIndex  uint64
 	appliedIndex  uint64
 	snapshotIndex uint64
 	snapshotIndex uint64
 
 
-	ticker              clock.Ticker
-	sendTimeout         time.Duration
-	stopCh              chan struct{}
-	doneCh              chan struct{}
+	ticker      clock.Ticker
+	sendTimeout time.Duration
+	stopCh      chan struct{}
+	doneCh      chan struct{}
+	// removeRaftCh notifies about node deletion from raft cluster
+	removeRaftCh        chan struct{}
+	removeRaftOnce      sync.Once
 	leadershipBroadcast *events.Broadcaster
 	leadershipBroadcast *events.Broadcaster
 
 
-	startNodePeers []raft.Peer
-
 	// used to coordinate shutdown
 	// used to coordinate shutdown
 	stopMu sync.RWMutex
 	stopMu sync.RWMutex
 	// used for membership management checks
 	// used for membership management checks
@@ -153,7 +160,7 @@ func init() {
 }
 }
 
 
 // NewNode generates a new Raft node
 // NewNode generates a new Raft node
-func NewNode(ctx context.Context, opts NewNodeOptions) (*Node, error) {
+func NewNode(ctx context.Context, opts NewNodeOptions) *Node {
 	cfg := opts.Config
 	cfg := opts.Config
 	if cfg == nil {
 	if cfg == nil {
 		cfg = DefaultNodeConfig()
 		cfg = DefaultNodeConfig()
@@ -173,6 +180,7 @@ func NewNode(ctx context.Context, opts NewNodeOptions) (*Node, error) {
 		tlsCredentials: opts.TLSCredentials,
 		tlsCredentials: opts.TLSCredentials,
 		raftStore:      raftStore,
 		raftStore:      raftStore,
 		Address:        opts.Addr,
 		Address:        opts.Addr,
+		opts:           opts,
 		Config: &raft.Config{
 		Config: &raft.Config{
 			ElectionTick:    cfg.ElectionTick,
 			ElectionTick:    cfg.ElectionTick,
 			HeartbeatTick:   cfg.HeartbeatTick,
 			HeartbeatTick:   cfg.HeartbeatTick,
@@ -184,6 +192,7 @@ func NewNode(ctx context.Context, opts NewNodeOptions) (*Node, error) {
 		forceNewCluster:     opts.ForceNewCluster,
 		forceNewCluster:     opts.ForceNewCluster,
 		stopCh:              make(chan struct{}),
 		stopCh:              make(chan struct{}),
 		doneCh:              make(chan struct{}),
 		doneCh:              make(chan struct{}),
+		removeRaftCh:        make(chan struct{}),
 		StateDir:            opts.StateDir,
 		StateDir:            opts.StateDir,
 		joinAddr:            opts.JoinAddr,
 		joinAddr:            opts.JoinAddr,
 		sendTimeout:         2 * time.Second,
 		sendTimeout:         2 * time.Second,
@@ -200,13 +209,21 @@ func NewNode(ctx context.Context, opts NewNodeOptions) (*Node, error) {
 		n.sendTimeout = opts.SendTimeout
 		n.sendTimeout = opts.SendTimeout
 	}
 	}
 
 
-	loadAndStartErr := n.loadAndStart(ctx, opts.ForceNewCluster)
+	n.reqIDGen = idutil.NewGenerator(uint16(n.Config.ID), time.Now())
+	n.wait = newWait()
+
+	return n
+}
+
+// JoinAndStart joins and starts the raft server
+func (n *Node) JoinAndStart() error {
+	loadAndStartErr := n.loadAndStart(n.Ctx, n.opts.ForceNewCluster)
 	if loadAndStartErr != nil && loadAndStartErr != errNoWAL {
 	if loadAndStartErr != nil && loadAndStartErr != errNoWAL {
 		n.ticker.Stop()
 		n.ticker.Stop()
-		return nil, loadAndStartErr
+		return loadAndStartErr
 	}
 	}
 
 
-	snapshot, err := raftStore.Snapshot()
+	snapshot, err := n.raftStore.Snapshot()
 	// Snapshot never returns an error
 	// Snapshot never returns an error
 	if err != nil {
 	if err != nil {
 		panic("could not get snapshot of raft store")
 		panic("could not get snapshot of raft store")
@@ -215,14 +232,12 @@ func NewNode(ctx context.Context, opts NewNodeOptions) (*Node, error) {
 	n.confState = snapshot.Metadata.ConfState
 	n.confState = snapshot.Metadata.ConfState
 	n.appliedIndex = snapshot.Metadata.Index
 	n.appliedIndex = snapshot.Metadata.Index
 	n.snapshotIndex = snapshot.Metadata.Index
 	n.snapshotIndex = snapshot.Metadata.Index
-	n.reqIDGen = idutil.NewGenerator(uint16(n.Config.ID), time.Now())
-	n.wait = newWait()
 
 
 	if loadAndStartErr == errNoWAL {
 	if loadAndStartErr == errNoWAL {
 		if n.joinAddr != "" {
 		if n.joinAddr != "" {
 			c, err := n.ConnectToMember(n.joinAddr, 10*time.Second)
 			c, err := n.ConnectToMember(n.joinAddr, 10*time.Second)
 			if err != nil {
 			if err != nil {
-				return nil, err
+				return err
 			}
 			}
 			client := api.NewRaftMembershipClient(c.Conn)
 			client := api.NewRaftMembershipClient(c.Conn)
 			defer func() {
 			defer func() {
@@ -235,40 +250,42 @@ func NewNode(ctx context.Context, opts NewNodeOptions) (*Node, error) {
 				Addr: n.Address,
 				Addr: n.Address,
 			})
 			})
 			if err != nil {
 			if err != nil {
-				return nil, err
+				return err
 			}
 			}
 
 
 			n.Config.ID = resp.RaftID
 			n.Config.ID = resp.RaftID
 
 
-			if _, err := n.createWAL(opts.ID); err != nil {
-				return nil, err
+			if _, err := n.createWAL(n.opts.ID); err != nil {
+				return err
 			}
 			}
 
 
 			n.Node = raft.StartNode(n.Config, []raft.Peer{})
 			n.Node = raft.StartNode(n.Config, []raft.Peer{})
 
 
 			if err := n.registerNodes(resp.Members); err != nil {
 			if err := n.registerNodes(resp.Members); err != nil {
-				return nil, err
+				return err
 			}
 			}
 		} else {
 		} else {
 			// First member in the cluster, self-assign ID
 			// First member in the cluster, self-assign ID
 			n.Config.ID = uint64(rand.Int63()) + 1
 			n.Config.ID = uint64(rand.Int63()) + 1
-			peer, err := n.createWAL(opts.ID)
+			peer, err := n.createWAL(n.opts.ID)
 			if err != nil {
 			if err != nil {
-				return nil, err
+				return err
 			}
 			}
 			n.Node = raft.StartNode(n.Config, []raft.Peer{peer})
 			n.Node = raft.StartNode(n.Config, []raft.Peer{peer})
 			if err := n.Campaign(n.Ctx); err != nil {
 			if err := n.Campaign(n.Ctx); err != nil {
-				return nil, err
+				return err
 			}
 			}
 		}
 		}
-		return n, nil
+		atomic.StoreUint32(&n.isMember, 1)
+		return nil
 	}
 	}
 
 
 	if n.joinAddr != "" {
 	if n.joinAddr != "" {
 		n.Config.Logger.Warning("ignoring request to join cluster, because raft state already exists")
 		n.Config.Logger.Warning("ignoring request to join cluster, because raft state already exists")
 	}
 	}
 	n.Node = raft.RestartNode(n.Config)
 	n.Node = raft.RestartNode(n.Config)
-	return n, nil
+	atomic.StoreUint32(&n.isMember, 1)
+	return nil
 }
 }
 
 
 // DefaultNodeConfig returns the default config for a
 // DefaultNodeConfig returns the default config for a
@@ -377,21 +394,6 @@ func (n *Node) Run(ctx context.Context) error {
 				}
 				}
 			}
 			}
 
 
-			// If the node was removed from other members,
-			// send back an error to the caller to start
-			// the shutdown process.
-			if n.mustStop() {
-				n.stop()
-
-				// Move WAL and snapshot out of the way, since
-				// they are no longer usable.
-				if err := n.moveWALAndSnap(); err != nil {
-					n.Config.Logger.Error(err)
-				}
-
-				return ErrMemberRemoved
-			}
-
 			// Advance the state machine
 			// Advance the state machine
 			n.Advance()
 			n.Advance()
 
 
@@ -400,6 +402,19 @@ func (n *Node) Run(ctx context.Context) error {
 				n.snapshotIndex = snapshotIndex
 				n.snapshotIndex = snapshotIndex
 			}
 			}
 			n.snapshotInProgress = nil
 			n.snapshotInProgress = nil
+		case <-n.removeRaftCh:
+			// If the node was removed from other members,
+			// send back an error to the caller to start
+			// the shutdown process.
+			n.stop()
+
+			// Move WAL and snapshot out of the way, since
+			// they are no longer usable.
+			if err := n.moveWALAndSnap(); err != nil {
+				n.Config.Logger.Error(err)
+			}
+
+			return ErrMemberRemoved
 		case <-n.stopCh:
 		case <-n.stopCh:
 			n.stop()
 			n.stop()
 			return nil
 			return nil
@@ -434,6 +449,7 @@ func (n *Node) stop() {
 		}
 		}
 	}
 	}
 	n.Stop()
 	n.Stop()
+	n.ticker.Stop()
 	if err := n.wal.Close(); err != nil {
 	if err := n.wal.Close(); err != nil {
 		n.Config.Logger.Errorf("raft: error closing WAL: %v", err)
 		n.Config.Logger.Errorf("raft: error closing WAL: %v", err)
 	}
 	}
@@ -442,6 +458,10 @@ func (n *Node) stop() {
 
 
 // IsLeader checks if we are the leader or not
 // IsLeader checks if we are the leader or not
 func (n *Node) IsLeader() bool {
 func (n *Node) IsLeader() bool {
+	if !n.IsMember() {
+		return false
+	}
+
 	if n.Node.Status().Lead == n.Config.ID {
 	if n.Node.Status().Lead == n.Config.ID {
 		return true
 		return true
 	}
 	}
@@ -450,6 +470,9 @@ func (n *Node) IsLeader() bool {
 
 
 // Leader returns the id of the leader
 // Leader returns the id of the leader
 func (n *Node) Leader() uint64 {
 func (n *Node) Leader() uint64 {
+	if !n.IsMember() {
+		return 0
+	}
 	return n.Node.Status().Lead
 	return n.Node.Status().Lead
 }
 }
 
 
@@ -479,7 +502,11 @@ func (n *Node) Join(ctx context.Context, req *api.JoinRequest) (*api.JoinRespons
 	n.membershipLock.Lock()
 	n.membershipLock.Lock()
 	defer n.membershipLock.Unlock()
 	defer n.membershipLock.Unlock()
 
 
-	if n.Node == nil {
+	if !n.IsMember() {
+		return nil, ErrNoRaftMember
+	}
+
+	if n.IsStopped() {
 		log.WithError(ErrStopped).Errorf(ErrStopped.Error())
 		log.WithError(ErrStopped).Errorf(ErrStopped.Error())
 		return nil, ErrStopped
 		return nil, ErrStopped
 	}
 	}
@@ -497,6 +524,12 @@ func (n *Node) Join(ctx context.Context, req *api.JoinRequest) (*api.JoinRespons
 		}
 		}
 	}
 	}
 
 
+	// We do not bother submitting a configuration change for the
+	// new member if we can't contact it back using its address
+	if err := n.checkHealth(ctx, req.Addr, 5*time.Second); err != nil {
+		return nil, err
+	}
+
 	err = n.addMember(ctx, req.Addr, raftID, nodeInfo.NodeID)
 	err = n.addMember(ctx, req.Addr, raftID, nodeInfo.NodeID)
 	if err != nil {
 	if err != nil {
 		log.WithError(err).Errorf("failed to add member")
 		log.WithError(err).Errorf("failed to add member")
@@ -516,6 +549,28 @@ func (n *Node) Join(ctx context.Context, req *api.JoinRequest) (*api.JoinRespons
 	return &api.JoinResponse{Members: nodes, RaftID: raftID}, nil
 	return &api.JoinResponse{Members: nodes, RaftID: raftID}, nil
 }
 }
 
 
+// checkHealth tries to contact an aspiring member through its advertised address
+// and checks if its raft server is running.
+func (n *Node) checkHealth(ctx context.Context, addr string, timeout time.Duration) error {
+	conn, err := dial(addr, "tcp", n.tlsCredentials, timeout)
+	if err != nil {
+		return err
+	}
+
+	client := api.NewHealthClient(conn)
+	defer conn.Close()
+
+	resp, err := client.Check(ctx, &api.HealthCheckRequest{Service: "Raft"})
+	if err != nil {
+		return ErrHealthCheckFailure
+	}
+	if resp != nil && resp.Status != api.HealthCheckResponse_SERVING {
+		return ErrHealthCheckFailure
+	}
+
+	return nil
+}
+
 // addMember submits a configuration change to add a new member on the raft cluster.
 // addMember submits a configuration change to add a new member on the raft cluster.
 func (n *Node) addMember(ctx context.Context, addr string, raftID uint64, nodeID string) error {
 func (n *Node) addMember(ctx context.Context, addr string, raftID uint64, nodeID string) error {
 	node := api.RaftMember{
 	node := api.RaftMember{
@@ -563,7 +618,11 @@ func (n *Node) Leave(ctx context.Context, req *api.LeaveRequest) (*api.LeaveResp
 	n.stopMu.RLock()
 	n.stopMu.RLock()
 	defer n.stopMu.RUnlock()
 	defer n.stopMu.RUnlock()
 
 
-	if n.Node == nil {
+	if !n.IsMember() {
+		return nil, ErrNoRaftMember
+	}
+
+	if n.IsStopped() {
 		return nil, ErrStopped
 		return nil, ErrStopped
 	}
 	}
 
 
@@ -612,7 +671,12 @@ func (n *Node) ProcessRaftMessage(ctx context.Context, msg *api.ProcessRaftMessa
 	// can't stop the raft node while an async RPC is in progress
 	// can't stop the raft node while an async RPC is in progress
 	n.stopMu.RLock()
 	n.stopMu.RLock()
 	defer n.stopMu.RUnlock()
 	defer n.stopMu.RUnlock()
-	if n.Node == nil {
+
+	if !n.IsMember() {
+		return nil, ErrNoRaftMember
+	}
+
+	if n.IsStopped() {
 		return nil, ErrStopped
 		return nil, ErrStopped
 	}
 	}
 
 
@@ -625,6 +689,10 @@ func (n *Node) ProcessRaftMessage(ctx context.Context, msg *api.ProcessRaftMessa
 
 
 // ResolveAddress returns the address reaching for a given node ID.
 // ResolveAddress returns the address reaching for a given node ID.
 func (n *Node) ResolveAddress(ctx context.Context, msg *api.ResolveAddressRequest) (*api.ResolveAddressResponse, error) {
 func (n *Node) ResolveAddress(ctx context.Context, msg *api.ResolveAddressRequest) (*api.ResolveAddressResponse, error) {
+	if !n.IsMember() {
+		return nil, ErrNoRaftMember
+	}
+
 	nodeInfo, err := ca.RemoteNode(ctx)
 	nodeInfo, err := ca.RemoteNode(ctx)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -656,7 +724,7 @@ func (n *Node) LeaderAddr() (string, error) {
 	if err := WaitForLeader(ctx, n); err != nil {
 	if err := WaitForLeader(ctx, n); err != nil {
 		return "", ErrNoClusterLeader
 		return "", ErrNoClusterLeader
 	}
 	}
-	if n.Node == nil {
+	if n.IsStopped() {
 		return "", ErrStopped
 		return "", ErrStopped
 	}
 	}
 	ms := n.cluster.Members()
 	ms := n.cluster.Members()
@@ -671,7 +739,7 @@ func (n *Node) LeaderAddr() (string, error) {
 func (n *Node) registerNode(node *api.RaftMember) error {
 func (n *Node) registerNode(node *api.RaftMember) error {
 	member := &membership.Member{}
 	member := &membership.Member{}
 
 
-	if n.cluster.GetMember(node.RaftID) != nil {
+	if n.cluster.GetMember(node.RaftID) != nil || n.cluster.IsIDRemoved(node.RaftID) {
 		// member already exists
 		// member already exists
 		return nil
 		return nil
 	}
 	}
@@ -760,11 +828,18 @@ func (n *Node) GetMemberlist() map[uint64]*api.RaftMember {
 	return memberlist
 	return memberlist
 }
 }
 
 
-// mustStop checks if the raft node must be stopped
-// because it was removed from the cluster from
-// other members
-func (n *Node) mustStop() bool {
-	return atomic.LoadUint32(&n.removed) == 1
+// IsMember checks if the raft node has effectively joined
+// a cluster of existing members.
+func (n *Node) IsMember() bool {
+	return atomic.LoadUint32(&n.isMember) == 1
+}
+
+// IsStopped checks if the raft node is stopped or not
+func (n *Node) IsStopped() bool {
+	if n.Node == nil {
+		return true
+	}
+	return false
 }
 }
 
 
 // canSubmitProposal defines if any more proposals
 // canSubmitProposal defines if any more proposals
@@ -882,12 +957,14 @@ func (n *Node) sendToMember(members map[uint64]*membership.Member, m raftpb.Mess
 	_, err := conn.ProcessRaftMessage(ctx, &api.ProcessRaftMessageRequest{Message: &m})
 	_, err := conn.ProcessRaftMessage(ctx, &api.ProcessRaftMessageRequest{Message: &m})
 	if err != nil {
 	if err != nil {
 		if grpc.ErrorDesc(err) == ErrMemberRemoved.Error() {
 		if grpc.ErrorDesc(err) == ErrMemberRemoved.Error() {
-			atomic.StoreUint32(&n.removed, 1)
+			n.removeRaftOnce.Do(func() {
+				close(n.removeRaftCh)
+			})
 		}
 		}
 		if m.Type == raftpb.MsgSnap {
 		if m.Type == raftpb.MsgSnap {
 			n.ReportSnapshot(m.To, raft.SnapshotFailure)
 			n.ReportSnapshot(m.To, raft.SnapshotFailure)
 		}
 		}
-		if n.Node == nil {
+		if n.IsStopped() {
 			panic("node is nil")
 			panic("node is nil")
 		}
 		}
 		n.ReportUnreachable(m.To)
 		n.ReportUnreachable(m.To)

+ 37 - 3
vendor/src/github.com/docker/swarmkit/manager/state/raft/storage.go

@@ -162,6 +162,22 @@ func (n *Node) readWAL(ctx context.Context, snapshot *raftpb.Snapshot, forceNewC
 	}
 	}
 	n.Config.ID = raftNode.RaftID
 	n.Config.ID = raftNode.RaftID
 
 
+	// All members that are no longer part of the cluster must be added to
+	// the removed list right away, so that we don't try to connect to them
+	// before processing the configuration change entries, which could make
+	// us get stuck.
+	for _, ent := range ents {
+		if ent.Index <= st.Commit && ent.Type == raftpb.EntryConfChange {
+			var cc raftpb.ConfChange
+			if err := cc.Unmarshal(ent.Data); err != nil {
+				return fmt.Errorf("error unmarshalling config change: %v", err)
+			}
+			if cc.Type == raftpb.ConfChangeRemoveNode {
+				n.cluster.RemoveMember(cc.NodeID)
+			}
+		}
+	}
+
 	if forceNewCluster {
 	if forceNewCluster {
 		// discard the previously uncommitted entries
 		// discard the previously uncommitted entries
 		for i, ent := range ents {
 		for i, ent := range ents {
@@ -174,6 +190,23 @@ func (n *Node) readWAL(ctx context.Context, snapshot *raftpb.Snapshot, forceNewC
 
 
 		// force append the configuration change entries
 		// force append the configuration change entries
 		toAppEnts := createConfigChangeEnts(getIDs(snapshot, ents), uint64(n.Config.ID), st.Term, st.Commit)
 		toAppEnts := createConfigChangeEnts(getIDs(snapshot, ents), uint64(n.Config.ID), st.Term, st.Commit)
+
+		// All members that are being removed as part of the
+		// force-new-cluster process must be added to the
+		// removed list right away, so that we don't try to
+		// connect to them before processing the configuration
+		// change entries, which could make us get stuck.
+		for _, ccEnt := range toAppEnts {
+			if ccEnt.Type == raftpb.EntryConfChange {
+				var cc raftpb.ConfChange
+				if err := cc.Unmarshal(ccEnt.Data); err != nil {
+					return fmt.Errorf("error unmarshalling force-new-cluster config change: %v", err)
+				}
+				if cc.Type == raftpb.ConfChangeRemoveNode {
+					n.cluster.RemoveMember(cc.NodeID)
+				}
+			}
+		}
 		ents = append(ents, toAppEnts...)
 		ents = append(ents, toAppEnts...)
 
 
 		// force commit newly appended entries
 		// force commit newly appended entries
@@ -347,9 +380,10 @@ func (n *Node) restoreFromSnapshot(data []byte, forceNewCluster bool) error {
 				return err
 				return err
 			}
 			}
 		}
 		}
-		for _, removedMember := range snapshot.Membership.Removed {
-			n.cluster.RemoveMember(removedMember)
-		}
+	}
+
+	for _, removedMember := range snapshot.Membership.Removed {
+		n.cluster.RemoveMember(removedMember)
 	}
 	}
 
 
 	return nil
 	return nil

+ 0 - 1
vendor/src/github.com/docker/swarmkit/manager/state/store/memory.go

@@ -23,7 +23,6 @@ const (
 	indexID           = "id"
 	indexID           = "id"
 	indexName         = "name"
 	indexName         = "name"
 	indexServiceID    = "serviceid"
 	indexServiceID    = "serviceid"
-	indexServiceMode  = "servicemode"
 	indexNodeID       = "nodeid"
 	indexNodeID       = "nodeid"
 	indexSlot         = "slot"
 	indexSlot         = "slot"
 	indexCN           = "cn"
 	indexCN           = "cn"

+ 1 - 1
vendor/src/github.com/docker/swarmkit/picker/picker.go

@@ -272,7 +272,7 @@ func (p *Picker) PickAddr() (string, error) {
 	p.mu.Lock()
 	p.mu.Lock()
 	p.peer = peer
 	p.peer = peer
 	p.mu.Unlock()
 	p.mu.Unlock()
-	return p.peer.Addr, err
+	return peer.Addr, err
 }
 }
 
 
 // State returns the connectivity state of the underlying connections.
 // State returns the connectivity state of the underlying connections.