Browse code

Vendor swarmkit @27fbaef4ceed6

Adds a new task runtime to support network attachmemt for plain old
docker containers so that they can participate multi-host networks and
get access to services.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>

Jana Radhakrishnan authored on 2016/08/23 14:30:01
Showing 60 changed files
... ...
@@ -72,7 +72,7 @@ clone git github.com/imdario/mergo 0.2.1
72 72
 
73 73
 #get libnetwork packages
74 74
 clone git github.com/docker/libnetwork 82fb373e3eaa4e9bbb5b5ac148b0a3a71f80fca6
75
-clone git github.com/docker/go-events afb2b9f2c23f33ada1a22b03651775fdc65a5089
75
+clone git github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
76 76
 clone git github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
77 77
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
78 78
 clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
... ...
@@ -85,7 +85,7 @@ clone git github.com/vishvananda/netlink e73bad418fd727ed3a02830b1af1ad0283a1de6
85 85
 clone git github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
86 86
 clone git github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
87 87
 clone git github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
88
-clone git github.com/coreos/etcd 06e2338108fdc694349aed923f4a7e45cf0cec1f
88
+clone git github.com/coreos/etcd 3a49cbb769ebd8d1dd25abb1e83386e9883a5707
89 89
 clone git github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
90 90
 clone git github.com/hashicorp/consul v0.5.2
91 91
 clone git github.com/boltdb/bolt v1.2.1
... ...
@@ -144,11 +144,11 @@ clone git github.com/docker/docker-credential-helpers v0.3.0
144 144
 clone git github.com/docker/containerd 8508d2bec90b96403143a1104cdcbd56f6aeb361
145 145
 
146 146
 # cluster
147
-clone git github.com/docker/swarmkit 8a761950fb4d9251c335dc6149a8a02756cb3b10
147
+clone git github.com/docker/swarmkit 27fbaef4ceed648bb575969ccc9083a6e104a719
148 148
 clone git github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9
149 149
 clone git github.com/gogo/protobuf 43a2e0b1c32252bfbbdf81f7faa7a88fb3fa4028
150
-clone git github.com/cloudflare/cfssl b895b0549c0ff676f92cf09ba971ae02bb41367b
151
-clone git github.com/google/certificate-transparency 025a5cab06f6a819c455d9fdc9e2a1b6d0982284
150
+clone git github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
151
+clone git github.com/google/certificate-transparency 0f6e3d1d1ba4d03fdaab7cd716f36255c2e48341
152 152
 clone git golang.org/x/crypto 3fbbcd23f1cb824e69491a5930cfeff09b12f4d2 https://github.com/golang/crypto.git
153 153
 clone git golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb https://github.com/golang/time.git
154 154
 clone git github.com/mreiferson/go-httpclient 63fe23f7434723dc904c901043af07931f293c47
... ...
@@ -69,3 +69,7 @@ JSON dictionary:
69 69
 or
70 70
 
71 71
     {"driver":"postgres","data_source":"postgres://user:password@host/db"}
72
+ 
73
+or
74
+
75
+    {"driver":"mysql","data_source":"user:password@tcp(hostname:3306)/db?parseTime=true"}
... ...
@@ -2,6 +2,7 @@
2 2
 package config
3 3
 
4 4
 import (
5
+	"crypto/tls"
5 6
 	"crypto/x509"
6 7
 	"encoding/asn1"
7 8
 	"encoding/json"
... ...
@@ -59,26 +60,35 @@ type AuthRemote struct {
59 59
 	AuthKeyName string `json:"auth_key"`
60 60
 }
61 61
 
62
+// CAConstraint specifies various CA constraints on the signed certificate.
63
+// CAConstraint would verify against (and override) the CA
64
+// extensions in the given CSR.
65
+type CAConstraint struct {
66
+	IsCA           bool `json:"is_ca"`
67
+	MaxPathLen     int  `json:"max_path_len"`
68
+	MaxPathLenZero bool `json:"max_path_len_zero"`
69
+}
70
+
62 71
 // A SigningProfile stores information that the CA needs to store
63 72
 // signature policy.
64 73
 type SigningProfile struct {
65
-	Usage               []string   `json:"usages"`
66
-	IssuerURL           []string   `json:"issuer_urls"`
67
-	OCSP                string     `json:"ocsp_url"`
68
-	CRL                 string     `json:"crl_url"`
69
-	CA                  bool       `json:"is_ca"`
70
-	OCSPNoCheck         bool       `json:"ocsp_no_check"`
71
-	ExpiryString        string     `json:"expiry"`
72
-	BackdateString      string     `json:"backdate"`
73
-	AuthKeyName         string     `json:"auth_key"`
74
-	RemoteName          string     `json:"remote"`
75
-	NotBefore           time.Time  `json:"not_before"`
76
-	NotAfter            time.Time  `json:"not_after"`
77
-	NameWhitelistString string     `json:"name_whitelist"`
78
-	AuthRemote          AuthRemote `json:"auth_remote"`
79
-	CTLogServers        []string   `json:"ct_log_servers"`
80
-	AllowedExtensions   []OID      `json:"allowed_extensions"`
81
-	CertStore           string     `json:"cert_store"`
74
+	Usage               []string     `json:"usages"`
75
+	IssuerURL           []string     `json:"issuer_urls"`
76
+	OCSP                string       `json:"ocsp_url"`
77
+	CRL                 string       `json:"crl_url"`
78
+	CAConstraint        CAConstraint `json:"ca_constraint"`
79
+	OCSPNoCheck         bool         `json:"ocsp_no_check"`
80
+	ExpiryString        string       `json:"expiry"`
81
+	BackdateString      string       `json:"backdate"`
82
+	AuthKeyName         string       `json:"auth_key"`
83
+	RemoteName          string       `json:"remote"`
84
+	NotBefore           time.Time    `json:"not_before"`
85
+	NotAfter            time.Time    `json:"not_after"`
86
+	NameWhitelistString string       `json:"name_whitelist"`
87
+	AuthRemote          AuthRemote   `json:"auth_remote"`
88
+	CTLogServers        []string     `json:"ct_log_servers"`
89
+	AllowedExtensions   []OID        `json:"allowed_extensions"`
90
+	CertStore           string       `json:"cert_store"`
82 91
 
83 92
 	Policies                    []CertificatePolicy
84 93
 	Expiry                      time.Duration
... ...
@@ -86,6 +96,8 @@ type SigningProfile struct {
86 86
 	Provider                    auth.Provider
87 87
 	RemoteProvider              auth.Provider
88 88
 	RemoteServer                string
89
+	RemoteCAs                   *x509.CertPool
90
+	ClientCert                  *tls.Certificate
89 91
 	CSRWhitelist                *CSRWhitelist
90 92
 	NameWhitelist               *regexp.Regexp
91 93
 	ExtensionWhitelist          map[string]bool
... ...
@@ -303,6 +315,44 @@ func (p *Signing) OverrideRemotes(remote string) error {
303 303
 	return nil
304 304
 }
305 305
 
306
+// SetClientCertKeyPairFromFile updates the properties to set client certificates for mutual
307
+// authenticated TLS remote requests
308
+func (p *Signing) SetClientCertKeyPairFromFile(certFile string, keyFile string) error {
309
+	if certFile != "" && keyFile != "" {
310
+		cert, err := helpers.LoadClientCertificate(certFile, keyFile)
311
+		if err != nil {
312
+			return err
313
+		}
314
+		for _, profile := range p.Profiles {
315
+			profile.ClientCert = cert
316
+		}
317
+		p.Default.ClientCert = cert
318
+	}
319
+	return nil
320
+}
321
+
322
+// SetRemoteCAsFromFile reads root CAs from file and updates the properties to set remote CAs for TLS
323
+// remote requests
324
+func (p *Signing) SetRemoteCAsFromFile(caFile string) error {
325
+	if caFile != "" {
326
+		remoteCAs, err := helpers.LoadPEMCertPool(caFile)
327
+		if err != nil {
328
+			return err
329
+		}
330
+		p.SetRemoteCAs(remoteCAs)
331
+	}
332
+	return nil
333
+}
334
+
335
+// SetRemoteCAs updates the properties to set remote CAs for TLS
336
+// remote requests
337
+func (p *Signing) SetRemoteCAs(remoteCAs *x509.CertPool) {
338
+	for _, profile := range p.Profiles {
339
+		profile.RemoteCAs = remoteCAs
340
+	}
341
+	p.Default.RemoteCAs = remoteCAs
342
+}
343
+
306 344
 // NeedsRemoteSigner returns true if one of the profiles has a remote set
307 345
 func (p *Signing) NeedsRemoteSigner() bool {
308 346
 	for _, profile := range p.Profiles {
... ...
@@ -360,6 +410,11 @@ func (p *SigningProfile) validProfile(isDefault bool) bool {
360 360
 		return false
361 361
 	}
362 362
 
363
+	if p.AuthRemote.RemoteName == "" && p.AuthRemote.AuthKeyName != "" {
364
+		log.Debugf("invalid auth remote profile: no remote signer specified")
365
+		return false
366
+	}
367
+
363 368
 	if p.RemoteName != "" {
364 369
 		log.Debugf("validate remote profile")
365 370
 
... ...
@@ -375,6 +430,7 @@ func (p *SigningProfile) validProfile(isDefault bool) bool {
375 375
 
376 376
 		if p.AuthRemote.RemoteName != "" {
377 377
 			log.Debugf("invalid remote profile: auth remote is also specified")
378
+			return false
378 379
 		}
379 380
 	} else if p.AuthRemote.RemoteName != "" {
380 381
 		log.Debugf("validate auth remote profile")
... ...
@@ -409,6 +465,43 @@ func (p *SigningProfile) validProfile(isDefault bool) bool {
409 409
 	return true
410 410
 }
411 411
 
412
+// This checks if the SigningProfile object contains configurations that are only effective with a local signer
413
+// which has access to CA private key.
414
+func (p *SigningProfile) hasLocalConfig() bool {
415
+	if p.Usage != nil ||
416
+		p.IssuerURL != nil ||
417
+		p.OCSP != "" ||
418
+		p.ExpiryString != "" ||
419
+		p.BackdateString != "" ||
420
+		p.CAConstraint.IsCA != false ||
421
+		!p.NotBefore.IsZero() ||
422
+		!p.NotAfter.IsZero() ||
423
+		p.NameWhitelistString != "" ||
424
+		len(p.CTLogServers) != 0 {
425
+		return true
426
+	}
427
+	return false
428
+}
429
+
430
+// warnSkippedSettings prints a log warning message about skipped settings
431
+// in a SigningProfile, usually due to remote signer.
432
+func (p *Signing) warnSkippedSettings() {
433
+	const warningMessage = `The configuration value by "usages", "issuer_urls", "ocsp_url", "crl_url", "ca_constraint", "expiry", "backdate", "not_before", "not_after", "cert_store" and "ct_log_servers" are skipped`
434
+	if p == nil {
435
+		return
436
+	}
437
+
438
+	if (p.Default.RemoteName != "" || p.Default.AuthRemote.RemoteName != "") && p.Default.hasLocalConfig() {
439
+		log.Warning("default profile points to a remote signer: ", warningMessage)
440
+	}
441
+
442
+	for name, profile := range p.Profiles {
443
+		if (profile.RemoteName != "" || profile.AuthRemote.RemoteName != "") && profile.hasLocalConfig() {
444
+			log.Warningf("Profiles[%s] points to a remote signer: %s", name, warningMessage)
445
+		}
446
+	}
447
+}
448
+
412 449
 // Signing codifies the signature configuration policy for a CA.
413 450
 type Signing struct {
414 451
 	Profiles map[string]*SigningProfile `json:"profiles"`
... ...
@@ -450,6 +543,9 @@ func (p *Signing) Valid() bool {
450 450
 			return false
451 451
 		}
452 452
 	}
453
+
454
+	p.warnSkippedSettings()
455
+
453 456
 	return true
454 457
 }
455 458
 
... ...
@@ -149,6 +149,8 @@ const (
149 149
 
150 150
 	// UnknownProfile indicates that the profile does not exist.
151 151
 	UnknownProfile // 54XX
152
+
153
+	UnmatchedWhitelist // 55xx
152 154
 )
153 155
 
154 156
 // The following are API client related errors, and should be
... ...
@@ -313,6 +315,8 @@ func New(category Category, reason Reason) *Error {
313 313
 			msg = "Policy violation request"
314 314
 		case UnknownProfile:
315 315
 			msg = "Unknown policy profile"
316
+		case UnmatchedWhitelist:
317
+			msg = "Request does not match policy whitelist"
316 318
 		default:
317 319
 			panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category PolicyError.",
318 320
 				reason))
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"crypto/ecdsa"
9 9
 	"crypto/elliptic"
10 10
 	"crypto/rsa"
11
+	"crypto/tls"
11 12
 	"crypto/x509"
12 13
 	"encoding/asn1"
13 14
 	"encoding/pem"
... ...
@@ -311,11 +312,23 @@ func ParseOneCertificateFromPEM(certsPEM []byte) ([]*x509.Certificate, []byte, e
311 311
 
312 312
 // LoadPEMCertPool loads a pool of PEM certificates from file.
313 313
 func LoadPEMCertPool(certsFile string) (*x509.CertPool, error) {
314
+	if certsFile == "" {
315
+		return nil, nil
316
+	}
314 317
 	pemCerts, err := ioutil.ReadFile(certsFile)
315 318
 	if err != nil {
316 319
 		return nil, err
317 320
 	}
318 321
 
322
+	return PEMToCertPool(pemCerts)
323
+}
324
+
325
+// PEMToCertPool concerts PEM certificates to a CertPool.
326
+func PEMToCertPool(pemCerts []byte) (*x509.CertPool, error) {
327
+	if len(pemCerts) == 0 {
328
+		return nil, nil
329
+	}
330
+
319 331
 	certPool := x509.NewCertPool()
320 332
 	if !certPool.AppendCertsFromPEM(pemCerts) {
321 333
 		return nil, errors.New("failed to load cert pool")
... ...
@@ -477,3 +490,29 @@ func SignerAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
477 477
 		return x509.UnknownSignatureAlgorithm
478 478
 	}
479 479
 }
480
+
481
+// LoadClientCertificate load key/certificate from pem files
482
+func LoadClientCertificate(certFile string, keyFile string) (*tls.Certificate, error) {
483
+	if certFile != "" && keyFile != "" {
484
+		cert, err := tls.LoadX509KeyPair(certFile, keyFile)
485
+		if err != nil {
486
+			log.Critical("Unable to read client certificate from file: %s or key from file: %s", certFile, keyFile)
487
+			return nil, err
488
+		}
489
+		log.Debug("Client certificate loaded ")
490
+		return &cert, nil
491
+	}
492
+	return nil, nil
493
+}
494
+
495
+// CreateTLSConfig creates a tls.Config object from certs and roots
496
+func CreateTLSConfig(remoteCAs *x509.CertPool, cert *tls.Certificate) *tls.Config {
497
+	var certs []tls.Certificate
498
+	if cert != nil {
499
+		certs = []tls.Certificate{*cert}
500
+	}
501
+	return &tls.Config{
502
+		Certificates: certs,
503
+		RootCAs:      remoteCAs,
504
+	}
505
+}
... ...
@@ -48,13 +48,16 @@ func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
48 48
 		if req.CA.Expiry != "" {
49 49
 			policy.Default.ExpiryString = req.CA.Expiry
50 50
 			policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
51
+			if err != nil {
52
+				return
53
+			}
51 54
 		}
52 55
 
53
-		signer.MaxPathLen = req.CA.PathLength
56
+		policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength
54 57
 		if req.CA.PathLength != 0 && req.CA.PathLenZero == true {
55 58
 			log.Infof("ignore invalid 'pathlenzero' value")
56 59
 		} else {
57
-			signer.MaxPathLenZero = req.CA.PathLenZero
60
+			policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero
58 61
 		}
59 62
 	}
60 63
 
... ...
@@ -72,12 +75,11 @@ func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
72 72
 		return
73 73
 	}
74 74
 
75
-	s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), nil)
75
+	s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy)
76 76
 	if err != nil {
77 77
 		log.Errorf("failed to create signer: %v", err)
78 78
 		return
79 79
 	}
80
-	s.SetPolicy(policy)
81 80
 
82 81
 	signReq := signer.SignRequest{Hosts: req.Hosts, Request: string(csrPEM)}
83 82
 	cert, err = s.Sign(signReq)
... ...
@@ -143,11 +145,11 @@ func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPE
143 143
 			}
144 144
 		}
145 145
 
146
-		signer.MaxPathLen = req.CA.PathLength
146
+		policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength
147 147
 		if req.CA.PathLength != 0 && req.CA.PathLenZero == true {
148 148
 			log.Infof("ignore invalid 'pathlenzero' value")
149 149
 		} else {
150
-			signer.MaxPathLenZero = req.CA.PathLenZero
150
+			policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero
151 151
 		}
152 152
 	}
153 153
 
... ...
@@ -156,12 +158,11 @@ func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPE
156 156
 		return nil, nil, err
157 157
 	}
158 158
 
159
-	s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), nil)
159
+	s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy)
160 160
 	if err != nil {
161 161
 		log.Errorf("failed to create signer: %v", err)
162 162
 		return
163 163
 	}
164
-	s.SetPolicy(policy)
165 164
 
166 165
 	signReq := signer.SignRequest{Request: string(csrPEM)}
167 166
 	cert, err = s.Sign(signReq)
... ...
@@ -217,7 +218,7 @@ var CAPolicy = func() *config.Signing {
217 217
 			Usage:        []string{"cert sign", "crl sign"},
218 218
 			ExpiryString: "43800h",
219 219
 			Expiry:       5 * helpers.OneYear,
220
-			CA:           true,
220
+			CAConstraint: config.CAConstraint{IsCA: true},
221 221
 		},
222 222
 	}
223 223
 }
... ...
@@ -6,7 +6,6 @@
6 6
 package log
7 7
 
8 8
 import (
9
-	"flag"
10 9
 	"fmt"
11 10
 	"log"
12 11
 	"os"
... ...
@@ -63,13 +62,6 @@ func SetLogger(logger SyslogWriter) {
63 63
 	syslogWriter = logger
64 64
 }
65 65
 
66
-func init() {
67
-	// Only define loglevel flag once.
68
-	if flag.Lookup("loglevel") == nil {
69
-		flag.IntVar(&Level, "loglevel", LevelInfo, "Log level (0 = DEBUG, 5 = FATAL)")
70
-	}
71
-}
72
-
73 66
 func print(l int, msg string) {
74 67
 	if l >= Level {
75 68
 		if syslogWriter != nil {
... ...
@@ -115,9 +115,6 @@ func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile
115 115
 		template.EmailAddresses = nil
116 116
 		s.ca = template
117 117
 		initRoot = true
118
-	} else if template.IsCA {
119
-		template.DNSNames = nil
120
-		template.EmailAddresses = nil
121 118
 	}
122 119
 
123 120
 	derBytes, err := x509.CreateCertificate(rand.Reader, template, s.ca, template.PublicKey, s.priv)
... ...
@@ -250,18 +247,21 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
250 250
 	}
251 251
 
252 252
 	if safeTemplate.IsCA {
253
-		if !profile.CA {
254
-			return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest)
253
+		if !profile.CAConstraint.IsCA {
254
+			log.Error("local signer policy disallows issuing CA certificate")
255
+			return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest)
255 256
 		}
256 257
 
257 258
 		if s.ca != nil && s.ca.MaxPathLen > 0 {
258 259
 			if safeTemplate.MaxPathLen >= s.ca.MaxPathLen {
260
+				log.Error("local signer certificate disallows CA MaxPathLen extending")
259 261
 				// do not sign a cert with pathlen > current
260
-				return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest)
262
+				return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest)
261 263
 			}
262 264
 		} else if s.ca != nil && s.ca.MaxPathLen == 0 && s.ca.MaxPathLenZero {
265
+			log.Error("local signer certificate disallows issuing CA certificate")
263 266
 			// signer has pathlen of 0, do not sign more intermediate CAs
264
-			return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest)
267
+			return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest)
265 268
 		}
266 269
 	}
267 270
 
... ...
@@ -272,17 +272,17 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
272 272
 	if profile.NameWhitelist != nil {
273 273
 		if safeTemplate.Subject.CommonName != "" {
274 274
 			if profile.NameWhitelist.Find([]byte(safeTemplate.Subject.CommonName)) == nil {
275
-				return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
275
+				return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
276 276
 			}
277 277
 		}
278 278
 		for _, name := range safeTemplate.DNSNames {
279 279
 			if profile.NameWhitelist.Find([]byte(name)) == nil {
280
-				return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
280
+				return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
281 281
 			}
282 282
 		}
283 283
 		for _, name := range safeTemplate.EmailAddresses {
284 284
 			if profile.NameWhitelist.Find([]byte(name)) == nil {
285
-				return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
285
+				return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
286 286
 			}
287 287
 		}
288 288
 	}
... ...
@@ -352,7 +352,7 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
352 352
 
353 353
 		for _, server := range profile.CTLogServers {
354 354
 			log.Infof("submitting poisoned precertificate to %s", server)
355
-			var ctclient = client.New(server)
355
+			var ctclient = client.New(server, nil)
356 356
 			var resp *ct.SignedCertificateTimestamp
357 357
 			resp, err = ctclient.AddPreChain(prechain)
358 358
 			if err != nil {
... ...
@@ -23,12 +23,6 @@ import (
23 23
 	"github.com/cloudflare/cfssl/info"
24 24
 )
25 25
 
26
-// MaxPathLen is the default path length for a new CA certificate.
27
-var MaxPathLen = 2
28
-
29
-// MaxPathLenZero indicates whether a new CA certificate has pathlen=0
30
-var MaxPathLenZero = false
31
-
32 26
 // Subject contains the information that should be used to override the
33 27
 // subject information when signing a certificate.
34 28
 type Subject struct {
... ...
@@ -294,7 +288,15 @@ func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.Si
294 294
 	template.KeyUsage = ku
295 295
 	template.ExtKeyUsage = eku
296 296
 	template.BasicConstraintsValid = true
297
-	template.IsCA = profile.CA
297
+	template.IsCA = profile.CAConstraint.IsCA
298
+	if template.IsCA {
299
+		template.MaxPathLen = profile.CAConstraint.MaxPathLen
300
+		if template.MaxPathLen == 0 {
301
+			template.MaxPathLenZero = profile.CAConstraint.MaxPathLenZero
302
+		}
303
+		template.DNSNames = nil
304
+		template.EmailAddresses = nil
305
+	}
298 306
 	template.SubjectKeyId = ski
299 307
 
300 308
 	if ocspURL != "" {
... ...
@@ -96,3 +96,26 @@ func Exist(name string) bool {
96 96
 	_, err := os.Stat(name)
97 97
 	return err == nil
98 98
 }
99
+
100
+// ZeroToEnd zeros a file starting from SEEK_CUR to its SEEK_END. May temporarily
101
+// shorten the length of the file.
102
+func ZeroToEnd(f *os.File) error {
103
+	// TODO: support FALLOC_FL_ZERO_RANGE
104
+	off, err := f.Seek(0, os.SEEK_CUR)
105
+	if err != nil {
106
+		return err
107
+	}
108
+	lenf, lerr := f.Seek(0, os.SEEK_END)
109
+	if lerr != nil {
110
+		return lerr
111
+	}
112
+	if err = f.Truncate(off); err != nil {
113
+		return err
114
+	}
115
+	// make sure blocks remain allocated
116
+	if err = Preallocate(f, lenf, true); err != nil {
117
+		return err
118
+	}
119
+	_, err = f.Seek(off, os.SEEK_SET)
120
+	return err
121
+}
... ...
@@ -232,7 +232,7 @@ func (l *raftLog) term(i uint64) (uint64, error) {
232 232
 	if err == nil {
233 233
 		return t, nil
234 234
 	}
235
-	if err == ErrCompacted {
235
+	if err == ErrCompacted || err == ErrUnavailable {
236 236
 		return 0, err
237 237
 	}
238 238
 	panic(err) // TODO(bdarnell)
... ...
@@ -339,7 +339,7 @@ func (l *raftLog) mustCheckOutOfBounds(lo, hi uint64) error {
339 339
 		return ErrCompacted
340 340
 	}
341 341
 
342
-	length := l.lastIndex() - fi + 1
342
+	length := l.lastIndex() + 1 - fi
343 343
 	if lo < fi || hi > fi+length {
344 344
 		l.logger.Panicf("slice[%d,%d) out of bound [%d,%d]", lo, hi, fi, l.lastIndex())
345 345
 	}
... ...
@@ -144,6 +144,9 @@ type Node interface {
144 144
 	// to match MemoryStorage.Compact.
145 145
 	ApplyConfChange(cc pb.ConfChange) *pb.ConfState
146 146
 
147
+	// TransferLeadership attempts to transfer leadership to the given transferee.
148
+	TransferLeadership(ctx context.Context, lead, transferee uint64)
149
+
147 150
 	// ReadIndex request a read state. The read state will be set in the ready.
148 151
 	// Read state has a read index. Once the application advances further than the read
149 152
 	// index, any linearizable read requests issued before the read request can be
... ...
@@ -485,6 +488,15 @@ func (n *node) ReportSnapshot(id uint64, status SnapshotStatus) {
485 485
 	}
486 486
 }
487 487
 
488
+func (n *node) TransferLeadership(ctx context.Context, lead, transferee uint64) {
489
+	select {
490
+	// manually set 'from' and 'to', so that leader can voluntarily transfers its leadership
491
+	case n.recvc <- pb.Message{Type: pb.MsgTransferLeader, From: transferee, To: lead}:
492
+	case <-n.done:
493
+	case <-ctx.Done():
494
+	}
495
+}
496
+
488 497
 func (n *node) ReadIndex(ctx context.Context, rctx []byte) error {
489 498
 	return n.step(ctx, pb.Message{Type: pb.MsgReadIndex, Entries: []pb.Entry{{Data: rctx}}})
490 499
 }
... ...
@@ -590,11 +590,6 @@ func (r *raft) Step(m pb.Message) error {
590 590
 		}
591 591
 		return nil
592 592
 	}
593
-	if m.Type == pb.MsgTransferLeader {
594
-		if r.state != StateLeader {
595
-			r.logger.Debugf("%x [term %d state %v] ignoring MsgTransferLeader to %x", r.id, r.Term, r.state, m.From)
596
-		}
597
-	}
598 593
 
599 594
 	switch {
600 595
 	case m.Term == 0:
... ...
@@ -874,6 +869,13 @@ func stepFollower(r *raft, m pb.Message) {
874 874
 				r.id, r.raftLog.lastTerm(), r.raftLog.lastIndex(), r.Vote, m.From, m.LogTerm, m.Index, r.Term)
875 875
 			r.send(pb.Message{To: m.From, Type: pb.MsgVoteResp, Reject: true})
876 876
 		}
877
+	case pb.MsgTransferLeader:
878
+		if r.lead == None {
879
+			r.logger.Infof("%x no leader at term %d; dropping leader transfer msg", r.id, r.Term)
880
+			return
881
+		}
882
+		m.To = r.lead
883
+		r.send(m)
877 884
 	case pb.MsgTimeoutNow:
878 885
 		r.logger.Infof("%x [term %d] received MsgTimeoutNow from %x and starts an election to get leadership.", r.id, r.Term, m.From)
879 886
 		r.campaign(campaignTransfer)
... ...
@@ -130,6 +130,9 @@ func (ms *MemoryStorage) Term(i uint64) (uint64, error) {
130 130
 	if i < offset {
131 131
 		return 0, ErrCompacted
132 132
 	}
133
+	if int(i-offset) >= len(ms.ents) {
134
+		return 0, ErrUnavailable
135
+	}
133 136
 	return ms.ents[i-offset].Term, nil
134 137
 }
135 138
 
... ...
@@ -48,7 +48,7 @@ func max(a, b uint64) uint64 {
48 48
 
49 49
 func IsLocalMsg(msgt pb.MessageType) bool {
50 50
 	return msgt == pb.MsgHup || msgt == pb.MsgBeat || msgt == pb.MsgUnreachable ||
51
-		msgt == pb.MsgSnapStatus || msgt == pb.MsgCheckQuorum || msgt == pb.MsgTransferLeader
51
+		msgt == pb.MsgSnapStatus || msgt == pb.MsgCheckQuorum
52 52
 }
53 53
 
54 54
 func IsResponseMsg(msgt pb.MessageType) bool {
... ...
@@ -131,22 +131,7 @@ func Create(dirpath string, metadata []byte) (*WAL, error) {
131 131
 		return nil, err
132 132
 	}
133 133
 
134
-	// rename of directory with locked files doesn't work on windows; close
135
-	// the WAL to release the locks so the directory can be renamed
136
-	w.Close()
137
-	if err := os.Rename(tmpdirpath, dirpath); err != nil {
138
-		return nil, err
139
-	}
140
-	// reopen and relock
141
-	newWAL, oerr := Open(dirpath, walpb.Snapshot{})
142
-	if oerr != nil {
143
-		return nil, oerr
144
-	}
145
-	if _, _, _, err := newWAL.ReadAll(); err != nil {
146
-		newWAL.Close()
147
-		return nil, err
148
-	}
149
-	return newWAL, nil
134
+	return w.renameWal(tmpdirpath)
150 135
 }
151 136
 
152 137
 // Open opens the WAL at the given snap.
... ...
@@ -301,6 +286,18 @@ func (w *WAL) ReadAll() (metadata []byte, state raftpb.HardState, ents []raftpb.
301 301
 			state.Reset()
302 302
 			return nil, state, nil, err
303 303
 		}
304
+		// decodeRecord() will return io.EOF if it detects a zero record,
305
+		// but this zero record may be followed by non-zero records from
306
+		// a torn write. Overwriting some of these non-zero records, but
307
+		// not all, will cause CRC errors on WAL open. Since the records
308
+		// were never fully synced to disk in the first place, it's safe
309
+		// to zero them out to avoid any CRC errors from new writes.
310
+		if _, err = w.tail().Seek(w.decoder.lastOffset(), os.SEEK_SET); err != nil {
311
+			return nil, state, nil, err
312
+		}
313
+		if err = fileutil.ZeroToEnd(w.tail().File); err != nil {
314
+			return nil, state, nil, err
315
+		}
304 316
 	}
305 317
 
306 318
 	err = nil
... ...
@@ -319,7 +316,6 @@ func (w *WAL) ReadAll() (metadata []byte, state raftpb.HardState, ents []raftpb.
319 319
 
320 320
 	if w.tail() != nil {
321 321
 		// create encoder (chain crc with the decoder), enable appending
322
-		_, err = w.tail().Seek(w.decoder.lastOffset(), os.SEEK_SET)
323 322
 		w.encoder = newEncoder(w.tail(), w.decoder.lastCRC())
324 323
 	}
325 324
 	w.decoder = nil
326 325
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+// Copyright 2016 The etcd Authors
1
+//
2
+// Licensed under the Apache License, Version 2.0 (the "License");
3
+// you may not use this file except in compliance with the License.
4
+// You may obtain a copy of the License at
5
+//
6
+//     http://www.apache.org/licenses/LICENSE-2.0
7
+//
8
+// Unless required by applicable law or agreed to in writing, software
9
+// distributed under the License is distributed on an "AS IS" BASIS,
10
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+// See the License for the specific language governing permissions and
12
+// limitations under the License.
13
+
14
+// +build !windows
15
+
16
+package wal
17
+
18
+import "os"
19
+
20
+func (w *WAL) renameWal(tmpdirpath string) (*WAL, error) {
21
+	// On non-Windows platforms, hold the lock while renaming. Releasing
22
+	// the lock and trying to reacquire it quickly can be flaky because
23
+	// it's possible the process will fork to spawn a process while this is
24
+	// happening. The fds are set up as close-on-exec by the Go runtime,
25
+	// but there is a window between the fork and the exec where another
26
+	// process holds the lock.
27
+
28
+	if err := os.RemoveAll(w.dir); err != nil {
29
+		return nil, err
30
+	}
31
+	if err := os.Rename(tmpdirpath, w.dir); err != nil {
32
+		return nil, err
33
+	}
34
+
35
+	w.fp = newFilePipeline(w.dir, SegmentSizeBytes)
36
+	return w, nil
37
+}
0 38
new file mode 100644
... ...
@@ -0,0 +1,41 @@
0
+// Copyright 2016 The etcd Authors
1
+//
2
+// Licensed under the Apache License, Version 2.0 (the "License");
3
+// you may not use this file except in compliance with the License.
4
+// You may obtain a copy of the License at
5
+//
6
+//     http://www.apache.org/licenses/LICENSE-2.0
7
+//
8
+// Unless required by applicable law or agreed to in writing, software
9
+// distributed under the License is distributed on an "AS IS" BASIS,
10
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+// See the License for the specific language governing permissions and
12
+// limitations under the License.
13
+
14
+package wal
15
+
16
+import (
17
+	"os"
18
+
19
+	"github.com/coreos/etcd/wal/walpb"
20
+)
21
+
22
+func (w *WAL) renameWal(tmpdirpath string) (*WAL, error) {
23
+	// rename of directory with locked files doesn't work on
24
+	// windows; close the WAL to release the locks so the directory
25
+	// can be renamed
26
+	w.Close()
27
+	if err := os.Rename(tmpdirpath, w.dir); err != nil {
28
+		return nil, err
29
+	}
30
+	// reopen and relock
31
+	newWAL, oerr := Open(w.dir, walpb.Snapshot{})
32
+	if oerr != nil {
33
+		return nil, oerr
34
+	}
35
+	if _, _, _, err := newWAL.ReadAll(); err != nil {
36
+		newWAL.Close()
37
+		return nil, err
38
+	}
39
+	return newWAL, nil
40
+}
... ...
@@ -7,7 +7,7 @@ import (
7 7
 )
8 8
 
9 9
 // NewTCPSocket creates a TCP socket listener with the specified address and
10
-// the specified tls configuration. If TLSConfig is set, will encapsulate the
10
+// and the specified tls configuration. If TLSConfig is set, will encapsulate the
11 11
 // TCP listener inside a TLS one.
12 12
 func NewTCPSocket(addr string, tlsConfig *tls.Config) (net.Listener, error) {
13 13
 	l, err := net.Listen("tcp", addr)
... ...
@@ -1,6 +1,11 @@
1 1
 package events
2 2
 
3
-import "github.com/Sirupsen/logrus"
3
+import (
4
+	"fmt"
5
+	"sync"
6
+
7
+	"github.com/Sirupsen/logrus"
8
+)
4 9
 
5 10
 // Broadcaster sends events to multiple, reliable Sinks. The goal of this
6 11
 // component is to dispatch events to configured endpoints. Reliability can be
... ...
@@ -10,7 +15,10 @@ type Broadcaster struct {
10 10
 	events  chan Event
11 11
 	adds    chan configureRequest
12 12
 	removes chan configureRequest
13
-	closed  chan chan struct{}
13
+
14
+	shutdown chan struct{}
15
+	closed   chan struct{}
16
+	once     sync.Once
14 17
 }
15 18
 
16 19
 // NewBroadcaster appends one or more sinks to the list of sinks. The
... ...
@@ -19,11 +27,12 @@ type Broadcaster struct {
19 19
 // its own. Use of EventQueue and RetryingSink should be used here.
20 20
 func NewBroadcaster(sinks ...Sink) *Broadcaster {
21 21
 	b := Broadcaster{
22
-		sinks:   sinks,
23
-		events:  make(chan Event),
24
-		adds:    make(chan configureRequest),
25
-		removes: make(chan configureRequest),
26
-		closed:  make(chan chan struct{}),
22
+		sinks:    sinks,
23
+		events:   make(chan Event),
24
+		adds:     make(chan configureRequest),
25
+		removes:  make(chan configureRequest),
26
+		shutdown: make(chan struct{}),
27
+		closed:   make(chan struct{}),
27 28
 	}
28 29
 
29 30
 	// Start the broadcaster
... ...
@@ -82,24 +91,19 @@ func (b *Broadcaster) configure(ch chan configureRequest, sink Sink) error {
82 82
 // Close the broadcaster, ensuring that all messages are flushed to the
83 83
 // underlying sink before returning.
84 84
 func (b *Broadcaster) Close() error {
85
-	select {
86
-	case <-b.closed:
87
-		// already closed
88
-		return ErrSinkClosed
89
-	default:
90
-		// do a little chan handoff dance to synchronize closing
91
-		closed := make(chan struct{})
92
-		b.closed <- closed
93
-		close(b.closed)
94
-		<-closed
95
-		return nil
96
-	}
85
+	b.once.Do(func() {
86
+		close(b.shutdown)
87
+	})
88
+
89
+	<-b.closed
90
+	return nil
97 91
 }
98 92
 
99 93
 // run is the main broadcast loop, started when the broadcaster is created.
100 94
 // Under normal conditions, it waits for events on the event channel. After
101 95
 // Close is called, this goroutine will exit.
102 96
 func (b *Broadcaster) run() {
97
+	defer close(b.closed)
103 98
 	remove := func(target Sink) {
104 99
 		for i, sink := range b.sinks {
105 100
 			if sink == target {
... ...
@@ -143,7 +147,7 @@ func (b *Broadcaster) run() {
143 143
 		case request := <-b.removes:
144 144
 			remove(request.sink)
145 145
 			request.response <- nil
146
-		case closing := <-b.closed:
146
+		case <-b.shutdown:
147 147
 			// close all the underlying sinks
148 148
 			for _, sink := range b.sinks {
149 149
 				if err := sink.Close(); err != nil && err != ErrSinkClosed {
... ...
@@ -151,8 +155,24 @@ func (b *Broadcaster) run() {
151 151
 						Errorf("broadcaster: closing sink failed")
152 152
 				}
153 153
 			}
154
-			closing <- struct{}{}
155 154
 			return
156 155
 		}
157 156
 	}
158 157
 }
158
+
159
+func (b Broadcaster) String() string {
160
+	// Serialize copy of this broadcaster without the sync.Once, to avoid
161
+	// a data race.
162
+
163
+	b2 := map[string]interface{}{
164
+		"sinks":   b.sinks,
165
+		"events":  b.events,
166
+		"adds":    b.adds,
167
+		"removes": b.removes,
168
+
169
+		"shutdown": b.shutdown,
170
+		"closed":   b.closed,
171
+	}
172
+
173
+	return fmt.Sprint(b2)
174
+}
... ...
@@ -1,5 +1,10 @@
1 1
 package events
2 2
 
3
+import (
4
+	"fmt"
5
+	"sync"
6
+)
7
+
3 8
 // Channel provides a sink that can be listened on. The writer and channel
4 9
 // listener must operate in separate goroutines.
5 10
 //
... ...
@@ -8,6 +13,7 @@ type Channel struct {
8 8
 	C chan Event
9 9
 
10 10
 	closed chan struct{}
11
+	once   sync.Once
11 12
 }
12 13
 
13 14
 // NewChannel returns a channel. If buffer is zero, the channel is
... ...
@@ -37,11 +43,19 @@ func (ch *Channel) Write(event Event) error {
37 37
 
38 38
 // Close the channel sink.
39 39
 func (ch *Channel) Close() error {
40
-	select {
41
-	case <-ch.closed:
42
-		return ErrSinkClosed
43
-	default:
40
+	ch.once.Do(func() {
44 41
 		close(ch.closed)
45
-		return nil
42
+	})
43
+
44
+	return nil
45
+}
46
+
47
+func (ch Channel) String() string {
48
+	// Serialize a copy of the Channel that doesn't contain the sync.Once,
49
+	// to avoid a data race.
50
+	ch2 := map[string]interface{}{
51
+		"C":      ch.C,
52
+		"closed": ch.closed,
46 53
 	}
54
+	return fmt.Sprint(ch2)
47 55
 }
... ...
@@ -44,7 +44,7 @@ func (f *Filter) Write(event Event) error {
44 44
 func (f *Filter) Close() error {
45 45
 	// TODO(stevvooe): Not all sinks should have Close.
46 46
 	if f.closed {
47
-		return ErrSinkClosed
47
+		return nil
48 48
 	}
49 49
 
50 50
 	f.closed = true
... ...
@@ -52,7 +52,7 @@ func (eq *Queue) Close() error {
52 52
 	defer eq.mu.Unlock()
53 53
 
54 54
 	if eq.closed {
55
-		return ErrSinkClosed
55
+		return nil
56 56
 	}
57 57
 
58 58
 	// set closed flag
... ...
@@ -1,6 +1,7 @@
1 1
 package events
2 2
 
3 3
 import (
4
+	"fmt"
4 5
 	"math/rand"
5 6
 	"sync"
6 7
 	"sync/atomic"
... ...
@@ -18,6 +19,7 @@ type RetryingSink struct {
18 18
 	sink     Sink
19 19
 	strategy RetryStrategy
20 20
 	closed   chan struct{}
21
+	once     sync.Once
21 22
 }
22 23
 
23 24
 // NewRetryingSink returns a sink that will retry writes to a sink, backing
... ...
@@ -81,13 +83,22 @@ retry:
81 81
 
82 82
 // Close closes the sink and the underlying sink.
83 83
 func (rs *RetryingSink) Close() error {
84
-	select {
85
-	case <-rs.closed:
86
-		return ErrSinkClosed
87
-	default:
84
+	rs.once.Do(func() {
88 85
 		close(rs.closed)
89
-		return rs.sink.Close()
86
+	})
87
+
88
+	return nil
89
+}
90
+
91
+func (rs RetryingSink) String() string {
92
+	// Serialize a copy of the RetryingSink without the sync.Once, to avoid
93
+	// a data race.
94
+	rs2 := map[string]interface{}{
95
+		"sink":     rs.sink,
96
+		"strategy": rs.strategy,
97
+		"closed":   rs.closed,
90 98
 	}
99
+	return fmt.Sprint(rs2)
91 100
 }
92 101
 
93 102
 // RetryStrategy defines a strategy for retrying event sink writes.
... ...
@@ -6,7 +6,7 @@ import (
6 6
 	"github.com/boltdb/bolt"
7 7
 	"github.com/docker/swarmkit/agent/exec"
8 8
 	"github.com/docker/swarmkit/api"
9
-	"github.com/docker/swarmkit/picker"
9
+	"github.com/docker/swarmkit/remotes"
10 10
 	"google.golang.org/grpc/credentials"
11 11
 )
12 12
 
... ...
@@ -17,7 +17,7 @@ type Config struct {
17 17
 
18 18
 	// Managers provides the manager backend used by the agent. It will be
19 19
 	// updated with managers weights as observed by the agent.
20
-	Managers picker.Remotes
20
+	Managers remotes.Remotes
21 21
 
22 22
 	// Executor specifies the executor to use for the agent.
23 23
 	Executor exec.Executor
... ...
@@ -21,7 +21,7 @@ import (
21 21
 	"github.com/docker/swarmkit/ioutils"
22 22
 	"github.com/docker/swarmkit/log"
23 23
 	"github.com/docker/swarmkit/manager"
24
-	"github.com/docker/swarmkit/picker"
24
+	"github.com/docker/swarmkit/remotes"
25 25
 	"golang.org/x/net/context"
26 26
 	"google.golang.org/grpc"
27 27
 	"google.golang.org/grpc/credentials"
... ...
@@ -178,7 +178,7 @@ func (n *Node) run(ctx context.Context) (err error) {
178 178
 	if n.config.JoinAddr != "" || n.config.ForceNewCluster {
179 179
 		n.remotes = newPersistentRemotes(filepath.Join(n.config.StateDir, stateFilename))
180 180
 		if n.config.JoinAddr != "" {
181
-			n.remotes.Observe(api.Peer{Addr: n.config.JoinAddr}, picker.DefaultObservationWeight)
181
+			n.remotes.Observe(api.Peer{Addr: n.config.JoinAddr}, remotes.DefaultObservationWeight)
182 182
 		}
183 183
 	}
184 184
 
... ...
@@ -204,7 +204,7 @@ func (n *Node) run(ctx context.Context) (err error) {
204 204
 	}()
205 205
 
206 206
 	certDir := filepath.Join(n.config.StateDir, "certificates")
207
-	securityConfig, err := ca.LoadOrCreateSecurityConfig(ctx, certDir, n.config.JoinToken, ca.ManagerRole, picker.NewPicker(n.remotes), issueResponseChan)
207
+	securityConfig, err := ca.LoadOrCreateSecurityConfig(ctx, certDir, n.config.JoinToken, ca.ManagerRole, n.remotes, issueResponseChan)
208 208
 	if err != nil {
209 209
 		return err
210 210
 	}
... ...
@@ -256,7 +256,7 @@ func (n *Node) run(ctx context.Context) (err error) {
256 256
 		}
257 257
 	}()
258 258
 
259
-	updates := ca.RenewTLSConfig(ctx, securityConfig, certDir, picker.NewPicker(n.remotes), forceCertRenewal)
259
+	updates := ca.RenewTLSConfig(ctx, securityConfig, certDir, n.remotes, forceCertRenewal)
260 260
 	go func() {
261 261
 		for {
262 262
 			select {
... ...
@@ -533,31 +533,29 @@ func (n *Node) initManagerConnection(ctx context.Context, ready chan<- struct{})
533 533
 	if err != nil {
534 534
 		return err
535 535
 	}
536
-	state := grpc.Idle
536
+	client := api.NewHealthClient(conn)
537 537
 	for {
538
-		s, err := conn.WaitForStateChange(ctx, state)
538
+		resp, err := client.Check(ctx, &api.HealthCheckRequest{Service: "ControlAPI"})
539 539
 		if err != nil {
540
-			n.setControlSocket(nil)
541 540
 			return err
542 541
 		}
543
-		if s == grpc.Ready {
544
-			n.setControlSocket(conn)
545
-			if ready != nil {
546
-				close(ready)
547
-				ready = nil
548
-			}
549
-		} else if state == grpc.Shutdown {
550
-			n.setControlSocket(nil)
542
+		if resp.Status == api.HealthCheckResponse_SERVING {
543
+			break
551 544
 		}
552
-		state = s
545
+		time.Sleep(500 * time.Millisecond)
546
+	}
547
+	n.setControlSocket(conn)
548
+	if ready != nil {
549
+		close(ready)
553 550
 	}
551
+	return nil
554 552
 }
555 553
 
556
-func (n *Node) waitRole(ctx context.Context, role string) {
554
+func (n *Node) waitRole(ctx context.Context, role string) error {
557 555
 	n.roleCond.L.Lock()
558 556
 	if role == n.role {
559 557
 		n.roleCond.L.Unlock()
560
-		return
558
+		return nil
561 559
 	}
562 560
 	finishCh := make(chan struct{})
563 561
 	defer close(finishCh)
... ...
@@ -572,18 +570,24 @@ func (n *Node) waitRole(ctx context.Context, role string) {
572 572
 	defer n.roleCond.L.Unlock()
573 573
 	for role != n.role {
574 574
 		n.roleCond.Wait()
575
-		if ctx.Err() != nil {
576
-			return
575
+		select {
576
+		case <-ctx.Done():
577
+			if ctx.Err() != nil {
578
+				return ctx.Err()
579
+			}
580
+		default:
577 581
 		}
578 582
 	}
583
+
584
+	return nil
579 585
 }
580 586
 
581 587
 func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig, ready chan struct{}) error {
582 588
 	for {
583
-		n.waitRole(ctx, ca.ManagerRole)
584
-		if ctx.Err() != nil {
585
-			return ctx.Err()
589
+		if err := n.waitRole(ctx, ca.ManagerRole); err != nil {
590
+			return err
586 591
 		}
592
+
587 593
 		remoteAddr, _ := n.remotes.Select(n.nodeID)
588 594
 		m, err := manager.New(&manager.Config{
589 595
 			ForceNewCluster: n.config.ForceNewCluster,
... ...
@@ -620,14 +624,14 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
620 620
 			go func(ready chan struct{}) {
621 621
 				select {
622 622
 				case <-ready:
623
-					n.remotes.Observe(api.Peer{NodeID: n.nodeID, Addr: n.config.ListenRemoteAPI}, picker.DefaultObservationWeight)
623
+					n.remotes.Observe(api.Peer{NodeID: n.nodeID, Addr: n.config.ListenRemoteAPI}, remotes.DefaultObservationWeight)
624 624
 				case <-connCtx.Done():
625 625
 				}
626 626
 			}(ready)
627 627
 			ready = nil
628 628
 		}
629 629
 
630
-		n.waitRole(ctx, ca.AgentRole)
630
+		err = n.waitRole(ctx, ca.AgentRole)
631 631
 
632 632
 		n.Lock()
633 633
 		n.manager = nil
... ...
@@ -641,6 +645,7 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
641 641
 			<-done
642 642
 		}
643 643
 		connCancel()
644
+		n.setControlSocket(nil)
644 645
 
645 646
 		if err != nil {
646 647
 			return err
... ...
@@ -651,15 +656,15 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
651 651
 type persistentRemotes struct {
652 652
 	sync.RWMutex
653 653
 	c *sync.Cond
654
-	picker.Remotes
654
+	remotes.Remotes
655 655
 	storePath      string
656 656
 	lastSavedState []api.Peer
657 657
 }
658 658
 
659
-func newPersistentRemotes(f string, remotes ...api.Peer) *persistentRemotes {
659
+func newPersistentRemotes(f string, peers ...api.Peer) *persistentRemotes {
660 660
 	pr := &persistentRemotes{
661 661
 		storePath: f,
662
-		Remotes:   picker.NewRemotes(remotes...),
662
+		Remotes:   remotes.NewRemotes(peers...),
663 663
 	}
664 664
 	pr.c = sync.NewCond(pr.RLocker())
665 665
 	return pr
... ...
@@ -79,6 +79,9 @@ func (sr *statusReporter) run(ctx context.Context) {
79 79
 	done := make(chan struct{})
80 80
 	defer close(done)
81 81
 
82
+	sr.mu.Lock() // released during wait, below.
83
+	defer sr.mu.Unlock()
84
+
82 85
 	go func() {
83 86
 		select {
84 87
 		case <-ctx.Done():
... ...
@@ -88,27 +91,29 @@ func (sr *statusReporter) run(ctx context.Context) {
88 88
 		}
89 89
 	}()
90 90
 
91
-	sr.mu.Lock() // released during wait, below.
92
-	defer sr.mu.Unlock()
93
-
94 91
 	for {
95 92
 		if len(sr.statuses) == 0 {
96 93
 			sr.cond.Wait()
97 94
 		}
98 95
 
99
-		for taskID, status := range sr.statuses {
100
-			if sr.closed {
101
-				// TODO(stevvooe): Add support here for waiting until all
102
-				// statuses are flushed before shutting down.
103
-				return
104
-			}
96
+		if sr.closed {
97
+			// TODO(stevvooe): Add support here for waiting until all
98
+			// statuses are flushed before shutting down.
99
+			return
100
+		}
105 101
 
102
+		for taskID, status := range sr.statuses {
106 103
 			delete(sr.statuses, taskID) // delete the entry, while trying to send.
107 104
 
108 105
 			sr.mu.Unlock()
109 106
 			err := sr.reporter.UpdateTaskStatus(ctx, taskID, status)
110 107
 			sr.mu.Lock()
111 108
 
109
+			// reporter might be closed during UpdateTaskStatus call
110
+			if sr.closed {
111
+				return
112
+			}
113
+
112 114
 			if err != nil {
113 115
 				log.G(ctx).WithError(err).Error("failed reporting status to agent")
114 116
 
115 117
new file mode 100644
... ...
@@ -0,0 +1,69 @@
0
+package agent
1
+
2
+import (
3
+	"github.com/docker/swarmkit/api"
4
+	"golang.org/x/net/context"
5
+)
6
+
7
+type resourceAllocator struct {
8
+	agent *Agent
9
+}
10
+
11
+// ResourceAllocator is an interface to allocate resource such as
12
+// network attachments from a worker node.
13
+type ResourceAllocator interface {
14
+	// AttachNetwork creates a network attachment in the manager
15
+	// given a target network and a unique ID representing the
16
+	// connecting entity and optionally a list of ipv4/ipv6
17
+	// addresses to be assigned to the attachment. AttachNetwork
18
+	// returns a unique ID for the attachment if successfull or an
19
+	// error in case of failure.
20
+	AttachNetwork(ctx context.Context, id, target string, addresses []string) (string, error)
21
+
22
+	// DetachNetworks deletes a network attachment for the passed
23
+	// attachment ID. The attachment ID is obtained from a
24
+	// previous AttachNetwork call.
25
+	DetachNetwork(ctx context.Context, aID string) error
26
+}
27
+
28
+// AttachNetwork creates a network attachment.
29
+func (r *resourceAllocator) AttachNetwork(ctx context.Context, id, target string, addresses []string) (string, error) {
30
+	var taskID string
31
+	if err := r.agent.withSession(ctx, func(session *session) error {
32
+		client := api.NewResourceAllocatorClient(session.conn)
33
+		r, err := client.AttachNetwork(ctx, &api.AttachNetworkRequest{
34
+			Config: &api.NetworkAttachmentConfig{
35
+				Target:    target,
36
+				Addresses: addresses,
37
+			},
38
+			ContainerID: id,
39
+		})
40
+		if err != nil {
41
+			return err
42
+		}
43
+		taskID = r.AttachmentID
44
+		return nil
45
+	}); err != nil {
46
+		return "", err
47
+	}
48
+
49
+	return taskID, nil
50
+}
51
+
52
+// DetachNetwork deletes a network attachment.
53
+func (r *resourceAllocator) DetachNetwork(ctx context.Context, aID string) error {
54
+	return r.agent.withSession(ctx, func(session *session) error {
55
+		client := api.NewResourceAllocatorClient(session.conn)
56
+		_, err := client.DetachNetwork(ctx, &api.DetachNetworkRequest{
57
+			AttachmentID: aID,
58
+		})
59
+
60
+		return err
61
+	})
62
+}
63
+
64
+// ResourceAllocator provides an interface to access resource
65
+// allocation methods such as AttachNetwork and DetachNetwork.
66
+func (a *Agent) ResourceAllocator() ResourceAllocator {
67
+	return &resourceAllocator{agent: a}
68
+}
... ...
@@ -6,8 +6,8 @@ import (
6 6
 
7 7
 	"github.com/docker/swarmkit/api"
8 8
 	"github.com/docker/swarmkit/log"
9
-	"github.com/docker/swarmkit/picker"
10 9
 	"github.com/docker/swarmkit/protobuf/ptypes"
10
+	"github.com/docker/swarmkit/remotes"
11 11
 	"golang.org/x/net/context"
12 12
 	"google.golang.org/grpc"
13 13
 	"google.golang.org/grpc/codes"
... ...
@@ -307,7 +307,7 @@ func (s *session) close() error {
307 307
 		return errSessionClosed
308 308
 	default:
309 309
 		if s.conn != nil {
310
-			s.agent.config.Managers.ObserveIfExists(api.Peer{Addr: s.addr}, -picker.DefaultObservationWeight)
310
+			s.agent.config.Managers.ObserveIfExists(api.Peer{Addr: s.addr}, -remotes.DefaultObservationWeight)
311 311
 			s.conn.Close()
312 312
 		}
313 313
 		close(s.closed)
... ...
@@ -134,8 +134,6 @@ func (w *worker) Assign(ctx context.Context, tasks []*api.Task) error {
134 134
 				if err := PutTaskStatus(tx, task.ID, &task.Status); err != nil {
135 135
 					return err
136 136
 				}
137
-
138
-				status = &task.Status
139 137
 			} else {
140 138
 				task.Status = *status // overwrite the stale manager status with ours.
141 139
 			}
... ...
@@ -181,7 +179,7 @@ func (w *worker) Listen(ctx context.Context, reporter StatusReporter) {
181 181
 	go func() {
182 182
 		<-ctx.Done()
183 183
 		w.mu.Lock()
184
-		defer w.mu.Lock()
184
+		defer w.mu.Unlock()
185 185
 		delete(w.listeners, key) // remove the listener if the context is closed.
186 186
 	}()
187 187
 
... ...
@@ -1,3 +1,3 @@
1 1
 package api
2 2
 
3
-//go:generate protoc -I.:../protobuf:../vendor:../vendor/github.com/gogo/protobuf --gogoswarm_out=plugins=grpc+deepcopy+raftproxy+authenticatedwrapper,import_path=github.com/docker/swarmkit/api,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto,Mtimestamp/timestamp.proto=github.com/docker/swarmkit/api/timestamp,Mduration/duration.proto=github.com/docker/swarmkit/api/duration,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor,Mplugin/plugin.proto=github.com/docker/swarmkit/protobuf/plugin:. types.proto specs.proto objects.proto control.proto dispatcher.proto ca.proto snapshot.proto raft.proto health.proto
3
+//go:generate protoc -I.:../protobuf:../vendor:../vendor/github.com/gogo/protobuf --gogoswarm_out=plugins=grpc+deepcopy+raftproxy+authenticatedwrapper,import_path=github.com/docker/swarmkit/api,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto,Mtimestamp/timestamp.proto=github.com/docker/swarmkit/api/timestamp,Mduration/duration.proto=github.com/docker/swarmkit/api/duration,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor,Mplugin/plugin.proto=github.com/docker/swarmkit/protobuf/plugin:. types.proto specs.proto objects.proto control.proto dispatcher.proto ca.proto snapshot.proto raft.proto health.proto resource.proto
4 4
new file mode 100644
... ...
@@ -0,0 +1,1105 @@
0
+// Code generated by protoc-gen-gogo.
1
+// source: resource.proto
2
+// DO NOT EDIT!
3
+
4
+package api
5
+
6
+import proto "github.com/gogo/protobuf/proto"
7
+import fmt "fmt"
8
+import math "math"
9
+import _ "github.com/gogo/protobuf/gogoproto"
10
+import _ "github.com/docker/swarmkit/protobuf/plugin"
11
+
12
+import strings "strings"
13
+import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto"
14
+import sort "sort"
15
+import strconv "strconv"
16
+import reflect "reflect"
17
+
18
+import (
19
+	context "golang.org/x/net/context"
20
+	grpc "google.golang.org/grpc"
21
+)
22
+
23
+import raftpicker "github.com/docker/swarmkit/manager/raftpicker"
24
+import codes "google.golang.org/grpc/codes"
25
+import metadata "google.golang.org/grpc/metadata"
26
+import transport "google.golang.org/grpc/transport"
27
+
28
+import io "io"
29
+
30
+// Reference imports to suppress errors if they are not otherwise used.
31
+var _ = proto.Marshal
32
+var _ = fmt.Errorf
33
+var _ = math.Inf
34
+
35
+type AttachNetworkRequest struct {
36
+	Config      *NetworkAttachmentConfig `protobuf:"bytes,1,opt,name=config" json:"config,omitempty"`
37
+	ContainerID string                   `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"`
38
+}
39
+
40
+func (m *AttachNetworkRequest) Reset()                    { *m = AttachNetworkRequest{} }
41
+func (*AttachNetworkRequest) ProtoMessage()               {}
42
+func (*AttachNetworkRequest) Descriptor() ([]byte, []int) { return fileDescriptorResource, []int{0} }
43
+
44
+type AttachNetworkResponse struct {
45
+	AttachmentID string `protobuf:"bytes,1,opt,name=attachment_id,json=attachmentId,proto3" json:"attachment_id,omitempty"`
46
+}
47
+
48
+func (m *AttachNetworkResponse) Reset()                    { *m = AttachNetworkResponse{} }
49
+func (*AttachNetworkResponse) ProtoMessage()               {}
50
+func (*AttachNetworkResponse) Descriptor() ([]byte, []int) { return fileDescriptorResource, []int{1} }
51
+
52
+type DetachNetworkRequest struct {
53
+	AttachmentID string `protobuf:"bytes,1,opt,name=attachment_id,json=attachmentId,proto3" json:"attachment_id,omitempty"`
54
+}
55
+
56
+func (m *DetachNetworkRequest) Reset()                    { *m = DetachNetworkRequest{} }
57
+func (*DetachNetworkRequest) ProtoMessage()               {}
58
+func (*DetachNetworkRequest) Descriptor() ([]byte, []int) { return fileDescriptorResource, []int{2} }
59
+
60
+type DetachNetworkResponse struct {
61
+}
62
+
63
+func (m *DetachNetworkResponse) Reset()                    { *m = DetachNetworkResponse{} }
64
+func (*DetachNetworkResponse) ProtoMessage()               {}
65
+func (*DetachNetworkResponse) Descriptor() ([]byte, []int) { return fileDescriptorResource, []int{3} }
66
+
67
+func init() {
68
+	proto.RegisterType((*AttachNetworkRequest)(nil), "docker.swarmkit.v1.AttachNetworkRequest")
69
+	proto.RegisterType((*AttachNetworkResponse)(nil), "docker.swarmkit.v1.AttachNetworkResponse")
70
+	proto.RegisterType((*DetachNetworkRequest)(nil), "docker.swarmkit.v1.DetachNetworkRequest")
71
+	proto.RegisterType((*DetachNetworkResponse)(nil), "docker.swarmkit.v1.DetachNetworkResponse")
72
+}
73
+
74
+type authenticatedWrapperResourceAllocatorServer struct {
75
+	local     ResourceAllocatorServer
76
+	authorize func(context.Context, []string) error
77
+}
78
+
79
+func NewAuthenticatedWrapperResourceAllocatorServer(local ResourceAllocatorServer, authorize func(context.Context, []string) error) ResourceAllocatorServer {
80
+	return &authenticatedWrapperResourceAllocatorServer{
81
+		local:     local,
82
+		authorize: authorize,
83
+	}
84
+}
85
+
86
+func (p *authenticatedWrapperResourceAllocatorServer) AttachNetwork(ctx context.Context, r *AttachNetworkRequest) (*AttachNetworkResponse, error) {
87
+
88
+	if err := p.authorize(ctx, []string{"swarm-worker", "swarm-manager"}); err != nil {
89
+		return nil, err
90
+	}
91
+	return p.local.AttachNetwork(ctx, r)
92
+}
93
+
94
+func (p *authenticatedWrapperResourceAllocatorServer) DetachNetwork(ctx context.Context, r *DetachNetworkRequest) (*DetachNetworkResponse, error) {
95
+
96
+	if err := p.authorize(ctx, []string{"swarm-worker", "swarm-manager"}); err != nil {
97
+		return nil, err
98
+	}
99
+	return p.local.DetachNetwork(ctx, r)
100
+}
101
+
102
+func (m *AttachNetworkRequest) Copy() *AttachNetworkRequest {
103
+	if m == nil {
104
+		return nil
105
+	}
106
+
107
+	o := &AttachNetworkRequest{
108
+		Config:      m.Config.Copy(),
109
+		ContainerID: m.ContainerID,
110
+	}
111
+
112
+	return o
113
+}
114
+
115
+func (m *AttachNetworkResponse) Copy() *AttachNetworkResponse {
116
+	if m == nil {
117
+		return nil
118
+	}
119
+
120
+	o := &AttachNetworkResponse{
121
+		AttachmentID: m.AttachmentID,
122
+	}
123
+
124
+	return o
125
+}
126
+
127
+func (m *DetachNetworkRequest) Copy() *DetachNetworkRequest {
128
+	if m == nil {
129
+		return nil
130
+	}
131
+
132
+	o := &DetachNetworkRequest{
133
+		AttachmentID: m.AttachmentID,
134
+	}
135
+
136
+	return o
137
+}
138
+
139
+func (m *DetachNetworkResponse) Copy() *DetachNetworkResponse {
140
+	if m == nil {
141
+		return nil
142
+	}
143
+
144
+	o := &DetachNetworkResponse{}
145
+
146
+	return o
147
+}
148
+
149
+func (this *AttachNetworkRequest) GoString() string {
150
+	if this == nil {
151
+		return "nil"
152
+	}
153
+	s := make([]string, 0, 6)
154
+	s = append(s, "&api.AttachNetworkRequest{")
155
+	if this.Config != nil {
156
+		s = append(s, "Config: "+fmt.Sprintf("%#v", this.Config)+",\n")
157
+	}
158
+	s = append(s, "ContainerID: "+fmt.Sprintf("%#v", this.ContainerID)+",\n")
159
+	s = append(s, "}")
160
+	return strings.Join(s, "")
161
+}
162
+func (this *AttachNetworkResponse) GoString() string {
163
+	if this == nil {
164
+		return "nil"
165
+	}
166
+	s := make([]string, 0, 5)
167
+	s = append(s, "&api.AttachNetworkResponse{")
168
+	s = append(s, "AttachmentID: "+fmt.Sprintf("%#v", this.AttachmentID)+",\n")
169
+	s = append(s, "}")
170
+	return strings.Join(s, "")
171
+}
172
+func (this *DetachNetworkRequest) GoString() string {
173
+	if this == nil {
174
+		return "nil"
175
+	}
176
+	s := make([]string, 0, 5)
177
+	s = append(s, "&api.DetachNetworkRequest{")
178
+	s = append(s, "AttachmentID: "+fmt.Sprintf("%#v", this.AttachmentID)+",\n")
179
+	s = append(s, "}")
180
+	return strings.Join(s, "")
181
+}
182
+func (this *DetachNetworkResponse) GoString() string {
183
+	if this == nil {
184
+		return "nil"
185
+	}
186
+	s := make([]string, 0, 4)
187
+	s = append(s, "&api.DetachNetworkResponse{")
188
+	s = append(s, "}")
189
+	return strings.Join(s, "")
190
+}
191
+func valueToGoStringResource(v interface{}, typ string) string {
192
+	rv := reflect.ValueOf(v)
193
+	if rv.IsNil() {
194
+		return "nil"
195
+	}
196
+	pv := reflect.Indirect(rv).Interface()
197
+	return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv)
198
+}
199
+func extensionToGoStringResource(e map[int32]github_com_gogo_protobuf_proto.Extension) string {
200
+	if e == nil {
201
+		return "nil"
202
+	}
203
+	s := "map[int32]proto.Extension{"
204
+	keys := make([]int, 0, len(e))
205
+	for k := range e {
206
+		keys = append(keys, int(k))
207
+	}
208
+	sort.Ints(keys)
209
+	ss := []string{}
210
+	for _, k := range keys {
211
+		ss = append(ss, strconv.Itoa(k)+": "+e[int32(k)].GoString())
212
+	}
213
+	s += strings.Join(ss, ",") + "}"
214
+	return s
215
+}
216
+
217
+// Reference imports to suppress errors if they are not otherwise used.
218
+var _ context.Context
219
+var _ grpc.ClientConn
220
+
221
+// This is a compile-time assertion to ensure that this generated file
222
+// is compatible with the grpc package it is being compiled against.
223
+const _ = grpc.SupportPackageIsVersion2
224
+
225
+// Client API for ResourceAllocator service
226
+
227
+type ResourceAllocatorClient interface {
228
+	AttachNetwork(ctx context.Context, in *AttachNetworkRequest, opts ...grpc.CallOption) (*AttachNetworkResponse, error)
229
+	DetachNetwork(ctx context.Context, in *DetachNetworkRequest, opts ...grpc.CallOption) (*DetachNetworkResponse, error)
230
+}
231
+
232
+type resourceAllocatorClient struct {
233
+	cc *grpc.ClientConn
234
+}
235
+
236
+func NewResourceAllocatorClient(cc *grpc.ClientConn) ResourceAllocatorClient {
237
+	return &resourceAllocatorClient{cc}
238
+}
239
+
240
+func (c *resourceAllocatorClient) AttachNetwork(ctx context.Context, in *AttachNetworkRequest, opts ...grpc.CallOption) (*AttachNetworkResponse, error) {
241
+	out := new(AttachNetworkResponse)
242
+	err := grpc.Invoke(ctx, "/docker.swarmkit.v1.ResourceAllocator/AttachNetwork", in, out, c.cc, opts...)
243
+	if err != nil {
244
+		return nil, err
245
+	}
246
+	return out, nil
247
+}
248
+
249
+func (c *resourceAllocatorClient) DetachNetwork(ctx context.Context, in *DetachNetworkRequest, opts ...grpc.CallOption) (*DetachNetworkResponse, error) {
250
+	out := new(DetachNetworkResponse)
251
+	err := grpc.Invoke(ctx, "/docker.swarmkit.v1.ResourceAllocator/DetachNetwork", in, out, c.cc, opts...)
252
+	if err != nil {
253
+		return nil, err
254
+	}
255
+	return out, nil
256
+}
257
+
258
+// Server API for ResourceAllocator service
259
+
260
+type ResourceAllocatorServer interface {
261
+	AttachNetwork(context.Context, *AttachNetworkRequest) (*AttachNetworkResponse, error)
262
+	DetachNetwork(context.Context, *DetachNetworkRequest) (*DetachNetworkResponse, error)
263
+}
264
+
265
+func RegisterResourceAllocatorServer(s *grpc.Server, srv ResourceAllocatorServer) {
266
+	s.RegisterService(&_ResourceAllocator_serviceDesc, srv)
267
+}
268
+
269
+func _ResourceAllocator_AttachNetwork_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
270
+	in := new(AttachNetworkRequest)
271
+	if err := dec(in); err != nil {
272
+		return nil, err
273
+	}
274
+	if interceptor == nil {
275
+		return srv.(ResourceAllocatorServer).AttachNetwork(ctx, in)
276
+	}
277
+	info := &grpc.UnaryServerInfo{
278
+		Server:     srv,
279
+		FullMethod: "/docker.swarmkit.v1.ResourceAllocator/AttachNetwork",
280
+	}
281
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
282
+		return srv.(ResourceAllocatorServer).AttachNetwork(ctx, req.(*AttachNetworkRequest))
283
+	}
284
+	return interceptor(ctx, in, info, handler)
285
+}
286
+
287
+func _ResourceAllocator_DetachNetwork_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
288
+	in := new(DetachNetworkRequest)
289
+	if err := dec(in); err != nil {
290
+		return nil, err
291
+	}
292
+	if interceptor == nil {
293
+		return srv.(ResourceAllocatorServer).DetachNetwork(ctx, in)
294
+	}
295
+	info := &grpc.UnaryServerInfo{
296
+		Server:     srv,
297
+		FullMethod: "/docker.swarmkit.v1.ResourceAllocator/DetachNetwork",
298
+	}
299
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
300
+		return srv.(ResourceAllocatorServer).DetachNetwork(ctx, req.(*DetachNetworkRequest))
301
+	}
302
+	return interceptor(ctx, in, info, handler)
303
+}
304
+
305
+var _ResourceAllocator_serviceDesc = grpc.ServiceDesc{
306
+	ServiceName: "docker.swarmkit.v1.ResourceAllocator",
307
+	HandlerType: (*ResourceAllocatorServer)(nil),
308
+	Methods: []grpc.MethodDesc{
309
+		{
310
+			MethodName: "AttachNetwork",
311
+			Handler:    _ResourceAllocator_AttachNetwork_Handler,
312
+		},
313
+		{
314
+			MethodName: "DetachNetwork",
315
+			Handler:    _ResourceAllocator_DetachNetwork_Handler,
316
+		},
317
+	},
318
+	Streams: []grpc.StreamDesc{},
319
+}
320
+
321
+func (m *AttachNetworkRequest) Marshal() (data []byte, err error) {
322
+	size := m.Size()
323
+	data = make([]byte, size)
324
+	n, err := m.MarshalTo(data)
325
+	if err != nil {
326
+		return nil, err
327
+	}
328
+	return data[:n], nil
329
+}
330
+
331
+func (m *AttachNetworkRequest) MarshalTo(data []byte) (int, error) {
332
+	var i int
333
+	_ = i
334
+	var l int
335
+	_ = l
336
+	if m.Config != nil {
337
+		data[i] = 0xa
338
+		i++
339
+		i = encodeVarintResource(data, i, uint64(m.Config.Size()))
340
+		n1, err := m.Config.MarshalTo(data[i:])
341
+		if err != nil {
342
+			return 0, err
343
+		}
344
+		i += n1
345
+	}
346
+	if len(m.ContainerID) > 0 {
347
+		data[i] = 0x12
348
+		i++
349
+		i = encodeVarintResource(data, i, uint64(len(m.ContainerID)))
350
+		i += copy(data[i:], m.ContainerID)
351
+	}
352
+	return i, nil
353
+}
354
+
355
+func (m *AttachNetworkResponse) Marshal() (data []byte, err error) {
356
+	size := m.Size()
357
+	data = make([]byte, size)
358
+	n, err := m.MarshalTo(data)
359
+	if err != nil {
360
+		return nil, err
361
+	}
362
+	return data[:n], nil
363
+}
364
+
365
+func (m *AttachNetworkResponse) MarshalTo(data []byte) (int, error) {
366
+	var i int
367
+	_ = i
368
+	var l int
369
+	_ = l
370
+	if len(m.AttachmentID) > 0 {
371
+		data[i] = 0xa
372
+		i++
373
+		i = encodeVarintResource(data, i, uint64(len(m.AttachmentID)))
374
+		i += copy(data[i:], m.AttachmentID)
375
+	}
376
+	return i, nil
377
+}
378
+
379
+func (m *DetachNetworkRequest) Marshal() (data []byte, err error) {
380
+	size := m.Size()
381
+	data = make([]byte, size)
382
+	n, err := m.MarshalTo(data)
383
+	if err != nil {
384
+		return nil, err
385
+	}
386
+	return data[:n], nil
387
+}
388
+
389
+func (m *DetachNetworkRequest) MarshalTo(data []byte) (int, error) {
390
+	var i int
391
+	_ = i
392
+	var l int
393
+	_ = l
394
+	if len(m.AttachmentID) > 0 {
395
+		data[i] = 0xa
396
+		i++
397
+		i = encodeVarintResource(data, i, uint64(len(m.AttachmentID)))
398
+		i += copy(data[i:], m.AttachmentID)
399
+	}
400
+	return i, nil
401
+}
402
+
403
+func (m *DetachNetworkResponse) Marshal() (data []byte, err error) {
404
+	size := m.Size()
405
+	data = make([]byte, size)
406
+	n, err := m.MarshalTo(data)
407
+	if err != nil {
408
+		return nil, err
409
+	}
410
+	return data[:n], nil
411
+}
412
+
413
+func (m *DetachNetworkResponse) MarshalTo(data []byte) (int, error) {
414
+	var i int
415
+	_ = i
416
+	var l int
417
+	_ = l
418
+	return i, nil
419
+}
420
+
421
+func encodeFixed64Resource(data []byte, offset int, v uint64) int {
422
+	data[offset] = uint8(v)
423
+	data[offset+1] = uint8(v >> 8)
424
+	data[offset+2] = uint8(v >> 16)
425
+	data[offset+3] = uint8(v >> 24)
426
+	data[offset+4] = uint8(v >> 32)
427
+	data[offset+5] = uint8(v >> 40)
428
+	data[offset+6] = uint8(v >> 48)
429
+	data[offset+7] = uint8(v >> 56)
430
+	return offset + 8
431
+}
432
+func encodeFixed32Resource(data []byte, offset int, v uint32) int {
433
+	data[offset] = uint8(v)
434
+	data[offset+1] = uint8(v >> 8)
435
+	data[offset+2] = uint8(v >> 16)
436
+	data[offset+3] = uint8(v >> 24)
437
+	return offset + 4
438
+}
439
+func encodeVarintResource(data []byte, offset int, v uint64) int {
440
+	for v >= 1<<7 {
441
+		data[offset] = uint8(v&0x7f | 0x80)
442
+		v >>= 7
443
+		offset++
444
+	}
445
+	data[offset] = uint8(v)
446
+	return offset + 1
447
+}
448
+
449
+type raftProxyResourceAllocatorServer struct {
450
+	local        ResourceAllocatorServer
451
+	connSelector raftpicker.Interface
452
+	cluster      raftpicker.RaftCluster
453
+	ctxMods      []func(context.Context) (context.Context, error)
454
+}
455
+
456
+func NewRaftProxyResourceAllocatorServer(local ResourceAllocatorServer, connSelector raftpicker.Interface, cluster raftpicker.RaftCluster, ctxMod func(context.Context) (context.Context, error)) ResourceAllocatorServer {
457
+	redirectChecker := func(ctx context.Context) (context.Context, error) {
458
+		s, ok := transport.StreamFromContext(ctx)
459
+		if !ok {
460
+			return ctx, grpc.Errorf(codes.InvalidArgument, "remote addr is not found in context")
461
+		}
462
+		addr := s.ServerTransport().RemoteAddr().String()
463
+		md, ok := metadata.FromContext(ctx)
464
+		if ok && len(md["redirect"]) != 0 {
465
+			return ctx, grpc.Errorf(codes.ResourceExhausted, "more than one redirect to leader from: %s", md["redirect"])
466
+		}
467
+		if !ok {
468
+			md = metadata.New(map[string]string{})
469
+		}
470
+		md["redirect"] = append(md["redirect"], addr)
471
+		return metadata.NewContext(ctx, md), nil
472
+	}
473
+	mods := []func(context.Context) (context.Context, error){redirectChecker}
474
+	mods = append(mods, ctxMod)
475
+
476
+	return &raftProxyResourceAllocatorServer{
477
+		local:        local,
478
+		cluster:      cluster,
479
+		connSelector: connSelector,
480
+		ctxMods:      mods,
481
+	}
482
+}
483
+func (p *raftProxyResourceAllocatorServer) runCtxMods(ctx context.Context) (context.Context, error) {
484
+	var err error
485
+	for _, mod := range p.ctxMods {
486
+		ctx, err = mod(ctx)
487
+		if err != nil {
488
+			return ctx, err
489
+		}
490
+	}
491
+	return ctx, nil
492
+}
493
+
494
+func (p *raftProxyResourceAllocatorServer) AttachNetwork(ctx context.Context, r *AttachNetworkRequest) (*AttachNetworkResponse, error) {
495
+
496
+	if p.cluster.IsLeader() {
497
+		return p.local.AttachNetwork(ctx, r)
498
+	}
499
+	ctx, err := p.runCtxMods(ctx)
500
+	if err != nil {
501
+		return nil, err
502
+	}
503
+	conn, err := p.connSelector.Conn()
504
+	if err != nil {
505
+		return nil, err
506
+	}
507
+
508
+	defer func() {
509
+		if err != nil {
510
+			errStr := err.Error()
511
+			if strings.Contains(errStr, grpc.ErrClientConnClosing.Error()) ||
512
+				strings.Contains(errStr, grpc.ErrClientConnTimeout.Error()) ||
513
+				strings.Contains(errStr, "connection error") ||
514
+				grpc.Code(err) == codes.Internal {
515
+				p.connSelector.Reset()
516
+			}
517
+		}
518
+	}()
519
+
520
+	return NewResourceAllocatorClient(conn).AttachNetwork(ctx, r)
521
+}
522
+
523
+func (p *raftProxyResourceAllocatorServer) DetachNetwork(ctx context.Context, r *DetachNetworkRequest) (*DetachNetworkResponse, error) {
524
+
525
+	if p.cluster.IsLeader() {
526
+		return p.local.DetachNetwork(ctx, r)
527
+	}
528
+	ctx, err := p.runCtxMods(ctx)
529
+	if err != nil {
530
+		return nil, err
531
+	}
532
+	conn, err := p.connSelector.Conn()
533
+	if err != nil {
534
+		return nil, err
535
+	}
536
+
537
+	defer func() {
538
+		if err != nil {
539
+			errStr := err.Error()
540
+			if strings.Contains(errStr, grpc.ErrClientConnClosing.Error()) ||
541
+				strings.Contains(errStr, grpc.ErrClientConnTimeout.Error()) ||
542
+				strings.Contains(errStr, "connection error") ||
543
+				grpc.Code(err) == codes.Internal {
544
+				p.connSelector.Reset()
545
+			}
546
+		}
547
+	}()
548
+
549
+	return NewResourceAllocatorClient(conn).DetachNetwork(ctx, r)
550
+}
551
+
552
+func (m *AttachNetworkRequest) Size() (n int) {
553
+	var l int
554
+	_ = l
555
+	if m.Config != nil {
556
+		l = m.Config.Size()
557
+		n += 1 + l + sovResource(uint64(l))
558
+	}
559
+	l = len(m.ContainerID)
560
+	if l > 0 {
561
+		n += 1 + l + sovResource(uint64(l))
562
+	}
563
+	return n
564
+}
565
+
566
+func (m *AttachNetworkResponse) Size() (n int) {
567
+	var l int
568
+	_ = l
569
+	l = len(m.AttachmentID)
570
+	if l > 0 {
571
+		n += 1 + l + sovResource(uint64(l))
572
+	}
573
+	return n
574
+}
575
+
576
+func (m *DetachNetworkRequest) Size() (n int) {
577
+	var l int
578
+	_ = l
579
+	l = len(m.AttachmentID)
580
+	if l > 0 {
581
+		n += 1 + l + sovResource(uint64(l))
582
+	}
583
+	return n
584
+}
585
+
586
+func (m *DetachNetworkResponse) Size() (n int) {
587
+	var l int
588
+	_ = l
589
+	return n
590
+}
591
+
592
+func sovResource(x uint64) (n int) {
593
+	for {
594
+		n++
595
+		x >>= 7
596
+		if x == 0 {
597
+			break
598
+		}
599
+	}
600
+	return n
601
+}
602
+func sozResource(x uint64) (n int) {
603
+	return sovResource(uint64((x << 1) ^ uint64((int64(x) >> 63))))
604
+}
605
+func (this *AttachNetworkRequest) String() string {
606
+	if this == nil {
607
+		return "nil"
608
+	}
609
+	s := strings.Join([]string{`&AttachNetworkRequest{`,
610
+		`Config:` + strings.Replace(fmt.Sprintf("%v", this.Config), "NetworkAttachmentConfig", "NetworkAttachmentConfig", 1) + `,`,
611
+		`ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`,
612
+		`}`,
613
+	}, "")
614
+	return s
615
+}
616
+func (this *AttachNetworkResponse) String() string {
617
+	if this == nil {
618
+		return "nil"
619
+	}
620
+	s := strings.Join([]string{`&AttachNetworkResponse{`,
621
+		`AttachmentID:` + fmt.Sprintf("%v", this.AttachmentID) + `,`,
622
+		`}`,
623
+	}, "")
624
+	return s
625
+}
626
+func (this *DetachNetworkRequest) String() string {
627
+	if this == nil {
628
+		return "nil"
629
+	}
630
+	s := strings.Join([]string{`&DetachNetworkRequest{`,
631
+		`AttachmentID:` + fmt.Sprintf("%v", this.AttachmentID) + `,`,
632
+		`}`,
633
+	}, "")
634
+	return s
635
+}
636
+func (this *DetachNetworkResponse) String() string {
637
+	if this == nil {
638
+		return "nil"
639
+	}
640
+	s := strings.Join([]string{`&DetachNetworkResponse{`,
641
+		`}`,
642
+	}, "")
643
+	return s
644
+}
645
+func valueToStringResource(v interface{}) string {
646
+	rv := reflect.ValueOf(v)
647
+	if rv.IsNil() {
648
+		return "nil"
649
+	}
650
+	pv := reflect.Indirect(rv).Interface()
651
+	return fmt.Sprintf("*%v", pv)
652
+}
653
+func (m *AttachNetworkRequest) Unmarshal(data []byte) error {
654
+	l := len(data)
655
+	iNdEx := 0
656
+	for iNdEx < l {
657
+		preIndex := iNdEx
658
+		var wire uint64
659
+		for shift := uint(0); ; shift += 7 {
660
+			if shift >= 64 {
661
+				return ErrIntOverflowResource
662
+			}
663
+			if iNdEx >= l {
664
+				return io.ErrUnexpectedEOF
665
+			}
666
+			b := data[iNdEx]
667
+			iNdEx++
668
+			wire |= (uint64(b) & 0x7F) << shift
669
+			if b < 0x80 {
670
+				break
671
+			}
672
+		}
673
+		fieldNum := int32(wire >> 3)
674
+		wireType := int(wire & 0x7)
675
+		if wireType == 4 {
676
+			return fmt.Errorf("proto: AttachNetworkRequest: wiretype end group for non-group")
677
+		}
678
+		if fieldNum <= 0 {
679
+			return fmt.Errorf("proto: AttachNetworkRequest: illegal tag %d (wire type %d)", fieldNum, wire)
680
+		}
681
+		switch fieldNum {
682
+		case 1:
683
+			if wireType != 2 {
684
+				return fmt.Errorf("proto: wrong wireType = %d for field Config", wireType)
685
+			}
686
+			var msglen int
687
+			for shift := uint(0); ; shift += 7 {
688
+				if shift >= 64 {
689
+					return ErrIntOverflowResource
690
+				}
691
+				if iNdEx >= l {
692
+					return io.ErrUnexpectedEOF
693
+				}
694
+				b := data[iNdEx]
695
+				iNdEx++
696
+				msglen |= (int(b) & 0x7F) << shift
697
+				if b < 0x80 {
698
+					break
699
+				}
700
+			}
701
+			if msglen < 0 {
702
+				return ErrInvalidLengthResource
703
+			}
704
+			postIndex := iNdEx + msglen
705
+			if postIndex > l {
706
+				return io.ErrUnexpectedEOF
707
+			}
708
+			if m.Config == nil {
709
+				m.Config = &NetworkAttachmentConfig{}
710
+			}
711
+			if err := m.Config.Unmarshal(data[iNdEx:postIndex]); err != nil {
712
+				return err
713
+			}
714
+			iNdEx = postIndex
715
+		case 2:
716
+			if wireType != 2 {
717
+				return fmt.Errorf("proto: wrong wireType = %d for field ContainerID", wireType)
718
+			}
719
+			var stringLen uint64
720
+			for shift := uint(0); ; shift += 7 {
721
+				if shift >= 64 {
722
+					return ErrIntOverflowResource
723
+				}
724
+				if iNdEx >= l {
725
+					return io.ErrUnexpectedEOF
726
+				}
727
+				b := data[iNdEx]
728
+				iNdEx++
729
+				stringLen |= (uint64(b) & 0x7F) << shift
730
+				if b < 0x80 {
731
+					break
732
+				}
733
+			}
734
+			intStringLen := int(stringLen)
735
+			if intStringLen < 0 {
736
+				return ErrInvalidLengthResource
737
+			}
738
+			postIndex := iNdEx + intStringLen
739
+			if postIndex > l {
740
+				return io.ErrUnexpectedEOF
741
+			}
742
+			m.ContainerID = string(data[iNdEx:postIndex])
743
+			iNdEx = postIndex
744
+		default:
745
+			iNdEx = preIndex
746
+			skippy, err := skipResource(data[iNdEx:])
747
+			if err != nil {
748
+				return err
749
+			}
750
+			if skippy < 0 {
751
+				return ErrInvalidLengthResource
752
+			}
753
+			if (iNdEx + skippy) > l {
754
+				return io.ErrUnexpectedEOF
755
+			}
756
+			iNdEx += skippy
757
+		}
758
+	}
759
+
760
+	if iNdEx > l {
761
+		return io.ErrUnexpectedEOF
762
+	}
763
+	return nil
764
+}
765
+func (m *AttachNetworkResponse) Unmarshal(data []byte) error {
766
+	l := len(data)
767
+	iNdEx := 0
768
+	for iNdEx < l {
769
+		preIndex := iNdEx
770
+		var wire uint64
771
+		for shift := uint(0); ; shift += 7 {
772
+			if shift >= 64 {
773
+				return ErrIntOverflowResource
774
+			}
775
+			if iNdEx >= l {
776
+				return io.ErrUnexpectedEOF
777
+			}
778
+			b := data[iNdEx]
779
+			iNdEx++
780
+			wire |= (uint64(b) & 0x7F) << shift
781
+			if b < 0x80 {
782
+				break
783
+			}
784
+		}
785
+		fieldNum := int32(wire >> 3)
786
+		wireType := int(wire & 0x7)
787
+		if wireType == 4 {
788
+			return fmt.Errorf("proto: AttachNetworkResponse: wiretype end group for non-group")
789
+		}
790
+		if fieldNum <= 0 {
791
+			return fmt.Errorf("proto: AttachNetworkResponse: illegal tag %d (wire type %d)", fieldNum, wire)
792
+		}
793
+		switch fieldNum {
794
+		case 1:
795
+			if wireType != 2 {
796
+				return fmt.Errorf("proto: wrong wireType = %d for field AttachmentID", wireType)
797
+			}
798
+			var stringLen uint64
799
+			for shift := uint(0); ; shift += 7 {
800
+				if shift >= 64 {
801
+					return ErrIntOverflowResource
802
+				}
803
+				if iNdEx >= l {
804
+					return io.ErrUnexpectedEOF
805
+				}
806
+				b := data[iNdEx]
807
+				iNdEx++
808
+				stringLen |= (uint64(b) & 0x7F) << shift
809
+				if b < 0x80 {
810
+					break
811
+				}
812
+			}
813
+			intStringLen := int(stringLen)
814
+			if intStringLen < 0 {
815
+				return ErrInvalidLengthResource
816
+			}
817
+			postIndex := iNdEx + intStringLen
818
+			if postIndex > l {
819
+				return io.ErrUnexpectedEOF
820
+			}
821
+			m.AttachmentID = string(data[iNdEx:postIndex])
822
+			iNdEx = postIndex
823
+		default:
824
+			iNdEx = preIndex
825
+			skippy, err := skipResource(data[iNdEx:])
826
+			if err != nil {
827
+				return err
828
+			}
829
+			if skippy < 0 {
830
+				return ErrInvalidLengthResource
831
+			}
832
+			if (iNdEx + skippy) > l {
833
+				return io.ErrUnexpectedEOF
834
+			}
835
+			iNdEx += skippy
836
+		}
837
+	}
838
+
839
+	if iNdEx > l {
840
+		return io.ErrUnexpectedEOF
841
+	}
842
+	return nil
843
+}
844
+func (m *DetachNetworkRequest) Unmarshal(data []byte) error {
845
+	l := len(data)
846
+	iNdEx := 0
847
+	for iNdEx < l {
848
+		preIndex := iNdEx
849
+		var wire uint64
850
+		for shift := uint(0); ; shift += 7 {
851
+			if shift >= 64 {
852
+				return ErrIntOverflowResource
853
+			}
854
+			if iNdEx >= l {
855
+				return io.ErrUnexpectedEOF
856
+			}
857
+			b := data[iNdEx]
858
+			iNdEx++
859
+			wire |= (uint64(b) & 0x7F) << shift
860
+			if b < 0x80 {
861
+				break
862
+			}
863
+		}
864
+		fieldNum := int32(wire >> 3)
865
+		wireType := int(wire & 0x7)
866
+		if wireType == 4 {
867
+			return fmt.Errorf("proto: DetachNetworkRequest: wiretype end group for non-group")
868
+		}
869
+		if fieldNum <= 0 {
870
+			return fmt.Errorf("proto: DetachNetworkRequest: illegal tag %d (wire type %d)", fieldNum, wire)
871
+		}
872
+		switch fieldNum {
873
+		case 1:
874
+			if wireType != 2 {
875
+				return fmt.Errorf("proto: wrong wireType = %d for field AttachmentID", wireType)
876
+			}
877
+			var stringLen uint64
878
+			for shift := uint(0); ; shift += 7 {
879
+				if shift >= 64 {
880
+					return ErrIntOverflowResource
881
+				}
882
+				if iNdEx >= l {
883
+					return io.ErrUnexpectedEOF
884
+				}
885
+				b := data[iNdEx]
886
+				iNdEx++
887
+				stringLen |= (uint64(b) & 0x7F) << shift
888
+				if b < 0x80 {
889
+					break
890
+				}
891
+			}
892
+			intStringLen := int(stringLen)
893
+			if intStringLen < 0 {
894
+				return ErrInvalidLengthResource
895
+			}
896
+			postIndex := iNdEx + intStringLen
897
+			if postIndex > l {
898
+				return io.ErrUnexpectedEOF
899
+			}
900
+			m.AttachmentID = string(data[iNdEx:postIndex])
901
+			iNdEx = postIndex
902
+		default:
903
+			iNdEx = preIndex
904
+			skippy, err := skipResource(data[iNdEx:])
905
+			if err != nil {
906
+				return err
907
+			}
908
+			if skippy < 0 {
909
+				return ErrInvalidLengthResource
910
+			}
911
+			if (iNdEx + skippy) > l {
912
+				return io.ErrUnexpectedEOF
913
+			}
914
+			iNdEx += skippy
915
+		}
916
+	}
917
+
918
+	if iNdEx > l {
919
+		return io.ErrUnexpectedEOF
920
+	}
921
+	return nil
922
+}
923
+func (m *DetachNetworkResponse) Unmarshal(data []byte) error {
924
+	l := len(data)
925
+	iNdEx := 0
926
+	for iNdEx < l {
927
+		preIndex := iNdEx
928
+		var wire uint64
929
+		for shift := uint(0); ; shift += 7 {
930
+			if shift >= 64 {
931
+				return ErrIntOverflowResource
932
+			}
933
+			if iNdEx >= l {
934
+				return io.ErrUnexpectedEOF
935
+			}
936
+			b := data[iNdEx]
937
+			iNdEx++
938
+			wire |= (uint64(b) & 0x7F) << shift
939
+			if b < 0x80 {
940
+				break
941
+			}
942
+		}
943
+		fieldNum := int32(wire >> 3)
944
+		wireType := int(wire & 0x7)
945
+		if wireType == 4 {
946
+			return fmt.Errorf("proto: DetachNetworkResponse: wiretype end group for non-group")
947
+		}
948
+		if fieldNum <= 0 {
949
+			return fmt.Errorf("proto: DetachNetworkResponse: illegal tag %d (wire type %d)", fieldNum, wire)
950
+		}
951
+		switch fieldNum {
952
+		default:
953
+			iNdEx = preIndex
954
+			skippy, err := skipResource(data[iNdEx:])
955
+			if err != nil {
956
+				return err
957
+			}
958
+			if skippy < 0 {
959
+				return ErrInvalidLengthResource
960
+			}
961
+			if (iNdEx + skippy) > l {
962
+				return io.ErrUnexpectedEOF
963
+			}
964
+			iNdEx += skippy
965
+		}
966
+	}
967
+
968
+	if iNdEx > l {
969
+		return io.ErrUnexpectedEOF
970
+	}
971
+	return nil
972
+}
973
+func skipResource(data []byte) (n int, err error) {
974
+	l := len(data)
975
+	iNdEx := 0
976
+	for iNdEx < l {
977
+		var wire uint64
978
+		for shift := uint(0); ; shift += 7 {
979
+			if shift >= 64 {
980
+				return 0, ErrIntOverflowResource
981
+			}
982
+			if iNdEx >= l {
983
+				return 0, io.ErrUnexpectedEOF
984
+			}
985
+			b := data[iNdEx]
986
+			iNdEx++
987
+			wire |= (uint64(b) & 0x7F) << shift
988
+			if b < 0x80 {
989
+				break
990
+			}
991
+		}
992
+		wireType := int(wire & 0x7)
993
+		switch wireType {
994
+		case 0:
995
+			for shift := uint(0); ; shift += 7 {
996
+				if shift >= 64 {
997
+					return 0, ErrIntOverflowResource
998
+				}
999
+				if iNdEx >= l {
1000
+					return 0, io.ErrUnexpectedEOF
1001
+				}
1002
+				iNdEx++
1003
+				if data[iNdEx-1] < 0x80 {
1004
+					break
1005
+				}
1006
+			}
1007
+			return iNdEx, nil
1008
+		case 1:
1009
+			iNdEx += 8
1010
+			return iNdEx, nil
1011
+		case 2:
1012
+			var length int
1013
+			for shift := uint(0); ; shift += 7 {
1014
+				if shift >= 64 {
1015
+					return 0, ErrIntOverflowResource
1016
+				}
1017
+				if iNdEx >= l {
1018
+					return 0, io.ErrUnexpectedEOF
1019
+				}
1020
+				b := data[iNdEx]
1021
+				iNdEx++
1022
+				length |= (int(b) & 0x7F) << shift
1023
+				if b < 0x80 {
1024
+					break
1025
+				}
1026
+			}
1027
+			iNdEx += length
1028
+			if length < 0 {
1029
+				return 0, ErrInvalidLengthResource
1030
+			}
1031
+			return iNdEx, nil
1032
+		case 3:
1033
+			for {
1034
+				var innerWire uint64
1035
+				var start int = iNdEx
1036
+				for shift := uint(0); ; shift += 7 {
1037
+					if shift >= 64 {
1038
+						return 0, ErrIntOverflowResource
1039
+					}
1040
+					if iNdEx >= l {
1041
+						return 0, io.ErrUnexpectedEOF
1042
+					}
1043
+					b := data[iNdEx]
1044
+					iNdEx++
1045
+					innerWire |= (uint64(b) & 0x7F) << shift
1046
+					if b < 0x80 {
1047
+						break
1048
+					}
1049
+				}
1050
+				innerWireType := int(innerWire & 0x7)
1051
+				if innerWireType == 4 {
1052
+					break
1053
+				}
1054
+				next, err := skipResource(data[start:])
1055
+				if err != nil {
1056
+					return 0, err
1057
+				}
1058
+				iNdEx = start + next
1059
+			}
1060
+			return iNdEx, nil
1061
+		case 4:
1062
+			return iNdEx, nil
1063
+		case 5:
1064
+			iNdEx += 4
1065
+			return iNdEx, nil
1066
+		default:
1067
+			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
1068
+		}
1069
+	}
1070
+	panic("unreachable")
1071
+}
1072
+
1073
+var (
1074
+	ErrInvalidLengthResource = fmt.Errorf("proto: negative length found during unmarshaling")
1075
+	ErrIntOverflowResource   = fmt.Errorf("proto: integer overflow")
1076
+)
1077
+
1078
+var fileDescriptorResource = []byte{
1079
+	// 373 bytes of a gzipped FileDescriptorProto
1080
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x2b, 0x4a, 0x2d, 0xce,
1081
+	0x2f, 0x2d, 0x4a, 0x4e, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x4a, 0xc9, 0x4f, 0xce,
1082
+	0x4e, 0x2d, 0xd2, 0x2b, 0x2e, 0x4f, 0x2c, 0xca, 0xcd, 0xce, 0x2c, 0xd1, 0x2b, 0x33, 0x94, 0xe2,
1083
+	0x2e, 0xa9, 0x2c, 0x48, 0x2d, 0x86, 0x28, 0x90, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x33, 0xf5,
1084
+	0x41, 0x2c, 0xa8, 0xa8, 0x70, 0x41, 0x4e, 0x69, 0x7a, 0x66, 0x9e, 0x3e, 0x84, 0x82, 0x08, 0x2a,
1085
+	0xf5, 0x33, 0x72, 0x89, 0x38, 0x96, 0x94, 0x24, 0x26, 0x67, 0xf8, 0xa5, 0x96, 0x94, 0xe7, 0x17,
1086
+	0x65, 0x07, 0xa5, 0x16, 0x96, 0xa6, 0x16, 0x97, 0x08, 0x39, 0x73, 0xb1, 0x25, 0xe7, 0xe7, 0xa5,
1087
+	0x65, 0xa6, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x1b, 0x69, 0xeb, 0x61, 0xda, 0xaa, 0x07, 0xd5,
1088
+	0x03, 0x31, 0x20, 0x37, 0x35, 0xaf, 0xc4, 0x19, 0xac, 0x25, 0x08, 0xaa, 0x55, 0xc8, 0x88, 0x8b,
1089
+	0x27, 0x39, 0x3f, 0xaf, 0x24, 0x31, 0x33, 0x2f, 0xb5, 0x28, 0x3e, 0x33, 0x45, 0x82, 0x49, 0x81,
1090
+	0x51, 0x83, 0xd3, 0x89, 0xff, 0xd1, 0x3d, 0x79, 0x6e, 0x67, 0x98, 0xb8, 0xa7, 0x4b, 0x10, 0x37,
1091
+	0x5c, 0x91, 0x67, 0x8a, 0x92, 0x1f, 0x97, 0x28, 0x9a, 0x83, 0x8a, 0x0b, 0xf2, 0xf3, 0x8a, 0x53,
1092
+	0x85, 0x4c, 0xb9, 0x78, 0x13, 0xe1, 0x16, 0x81, 0x4c, 0x63, 0x04, 0x9b, 0x26, 0xf0, 0xe8, 0x9e,
1093
+	0x3c, 0x0f, 0xc2, 0x05, 0x9e, 0x2e, 0x41, 0x3c, 0x08, 0x65, 0x9e, 0x29, 0x4a, 0xbe, 0x5c, 0x22,
1094
+	0x2e, 0xa9, 0x58, 0x3c, 0x48, 0xa6, 0x71, 0xe2, 0x5c, 0xa2, 0x68, 0xc6, 0x41, 0x9c, 0x67, 0xb4,
1095
+	0x9a, 0x89, 0x4b, 0x30, 0x08, 0x1a, 0x51, 0x8e, 0x39, 0x39, 0xf9, 0xc9, 0x89, 0x25, 0xf9, 0x45,
1096
+	0x42, 0x9d, 0x8c, 0x5c, 0xbc, 0x28, 0xde, 0x11, 0xd2, 0xc0, 0x16, 0x90, 0xd8, 0xa2, 0x40, 0x4a,
1097
+	0x93, 0x08, 0x95, 0x10, 0xcb, 0x95, 0x94, 0x4f, 0xad, 0x7b, 0x37, 0x83, 0x49, 0x96, 0x8b, 0x07,
1098
+	0xac, 0x54, 0x17, 0x24, 0x97, 0x5a, 0xc4, 0xc5, 0x0b, 0xe1, 0xe5, 0x26, 0xe6, 0x25, 0xa6, 0xa7,
1099
+	0x42, 0xdc, 0x82, 0xe2, 0x76, 0xec, 0x6e, 0xc1, 0x16, 0x5a, 0xd8, 0xdd, 0x82, 0x35, 0x20, 0x88,
1100
+	0x72, 0x8b, 0x93, 0xcc, 0x89, 0x87, 0x72, 0x0c, 0x37, 0x1e, 0xca, 0x31, 0x7c, 0x78, 0x28, 0xc7,
1101
+	0xd8, 0xf0, 0x48, 0x8e, 0xf1, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92,
1102
+	0x63, 0x4c, 0x62, 0x03, 0x27, 0x4e, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xef, 0x94, 0x58,
1103
+	0xde, 0xfa, 0x02, 0x00, 0x00,
1104
+}
0 1105
new file mode 100644
... ...
@@ -0,0 +1,34 @@
0
+syntax = "proto3";
1
+
2
+package docker.swarmkit.v1;
3
+
4
+import "types.proto";
5
+import "gogoproto/gogo.proto";
6
+import "plugin/plugin.proto";
7
+
8
+// Allocator is the API provided by a manager group for agents to control the allocation of certain entities.
9
+//
10
+// API methods on this service are used only by agent nodes.
11
+service ResourceAllocator {
12
+	rpc AttachNetwork(AttachNetworkRequest) returns (AttachNetworkResponse) {
13
+		option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-worker" roles: "swarm-manager" };
14
+	};
15
+	rpc DetachNetwork(DetachNetworkRequest) returns (DetachNetworkResponse) {
16
+		option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-worker" roles: "swarm-manager" };
17
+	};
18
+}
19
+
20
+message AttachNetworkRequest {
21
+	NetworkAttachmentConfig config = 1;
22
+	string container_id = 2 [(gogoproto.customname) = "ContainerID"];
23
+}
24
+
25
+message AttachNetworkResponse {
26
+	string attachment_id = 1 [(gogoproto.customname) = "AttachmentID"];
27
+}
28
+
29
+message DetachNetworkRequest {
30
+	string attachment_id = 1 [(gogoproto.customname) = "AttachmentID"];
31
+}
32
+
33
+message DetachNetworkResponse {}
... ...
@@ -107,7 +107,7 @@ func (x EndpointSpec_ResolutionMode) String() string {
107 107
 	return proto.EnumName(EndpointSpec_ResolutionMode_name, int32(x))
108 108
 }
109 109
 func (EndpointSpec_ResolutionMode) EnumDescriptor() ([]byte, []int) {
110
-	return fileDescriptorSpecs, []int{6, 0}
110
+	return fileDescriptorSpecs, []int{7, 0}
111 111
 }
112 112
 
113 113
 type NodeSpec struct {
... ...
@@ -140,8 +140,8 @@ type ServiceSpec struct {
140 140
 	//	*ServiceSpec_Global
141 141
 	Mode isServiceSpec_Mode `protobuf_oneof:"mode"`
142 142
 	// UpdateConfig controls the rate and policy of updates.
143
-	Update   *UpdateConfig                          `protobuf:"bytes,6,opt,name=update" json:"update,omitempty"`
144
-	Networks []*ServiceSpec_NetworkAttachmentConfig `protobuf:"bytes,7,rep,name=networks" json:"networks,omitempty"`
143
+	Update   *UpdateConfig              `protobuf:"bytes,6,opt,name=update" json:"update,omitempty"`
144
+	Networks []*NetworkAttachmentConfig `protobuf:"bytes,7,rep,name=networks" json:"networks,omitempty"`
145 145
 	// Service endpoint specifies the user provided configuration
146 146
 	// to properly discover and load balance a service.
147 147
 	Endpoint *EndpointSpec `protobuf:"bytes,8,opt,name=endpoint" json:"endpoint,omitempty"`
... ...
@@ -262,25 +262,6 @@ func _ServiceSpec_OneofSizer(msg proto.Message) (n int) {
262 262
 	return n
263 263
 }
264 264
 
265
-// NetworkAttachmentConfig specifies how a service should be attached to a particular network.
266
-//
267
-// For now, this is a simple struct, but this can include future information
268
-// instructing Swarm on how this service should work on the particular
269
-// network.
270
-type ServiceSpec_NetworkAttachmentConfig struct {
271
-	// Target specifies the target network for attachment. This value may be a
272
-	// network name or identifier. Only identifiers are supported at this time.
273
-	Target string `protobuf:"bytes,1,opt,name=target,proto3" json:"target,omitempty"`
274
-	// Aliases specifies a list of discoverable alternate names for the service on this Target.
275
-	Aliases []string `protobuf:"bytes,2,rep,name=aliases" json:"aliases,omitempty"`
276
-}
277
-
278
-func (m *ServiceSpec_NetworkAttachmentConfig) Reset()      { *m = ServiceSpec_NetworkAttachmentConfig{} }
279
-func (*ServiceSpec_NetworkAttachmentConfig) ProtoMessage() {}
280
-func (*ServiceSpec_NetworkAttachmentConfig) Descriptor() ([]byte, []int) {
281
-	return fileDescriptorSpecs, []int{1, 0}
282
-}
283
-
284 265
 // ReplicatedService sets the reconciliation target to certain number of replicas.
285 266
 type ReplicatedService struct {
286 267
 	Replicas uint64 `protobuf:"varint,1,opt,name=replicas,proto3" json:"replicas,omitempty"`
... ...
@@ -300,6 +281,7 @@ func (*GlobalService) Descriptor() ([]byte, []int) { return fileDescriptorSpecs,
300 300
 
301 301
 type TaskSpec struct {
302 302
 	// Types that are valid to be assigned to Runtime:
303
+	//	*TaskSpec_Attachment
303 304
 	//	*TaskSpec_Container
304 305
 	Runtime isTaskSpec_Runtime `protobuf_oneof:"runtime"`
305 306
 	// Resource requirements for the container.
... ...
@@ -311,6 +293,10 @@ type TaskSpec struct {
311 311
 	// LogDriver specifies the log driver to use for the task. Any runtime will
312 312
 	// direct logs into the specified driver for the duration of the task.
313 313
 	LogDriver *Driver `protobuf:"bytes,6,opt,name=log_driver,json=logDriver" json:"log_driver,omitempty"`
314
+	// Networks specifies the list of network attachment
315
+	// configurations (which specify the network and per-network
316
+	// aliases) that this task spec is bound to.
317
+	Networks []*NetworkAttachmentConfig `protobuf:"bytes,7,rep,name=networks" json:"networks,omitempty"`
314 318
 }
315 319
 
316 320
 func (m *TaskSpec) Reset()                    { *m = TaskSpec{} }
... ...
@@ -323,11 +309,15 @@ type isTaskSpec_Runtime interface {
323 323
 	Size() int
324 324
 }
325 325
 
326
+type TaskSpec_Attachment struct {
327
+	Attachment *NetworkAttachmentSpec `protobuf:"bytes,8,opt,name=attachment,oneof"`
328
+}
326 329
 type TaskSpec_Container struct {
327 330
 	Container *ContainerSpec `protobuf:"bytes,1,opt,name=container,oneof"`
328 331
 }
329 332
 
330
-func (*TaskSpec_Container) isTaskSpec_Runtime() {}
333
+func (*TaskSpec_Attachment) isTaskSpec_Runtime() {}
334
+func (*TaskSpec_Container) isTaskSpec_Runtime()  {}
331 335
 
332 336
 func (m *TaskSpec) GetRuntime() isTaskSpec_Runtime {
333 337
 	if m != nil {
... ...
@@ -336,6 +326,13 @@ func (m *TaskSpec) GetRuntime() isTaskSpec_Runtime {
336 336
 	return nil
337 337
 }
338 338
 
339
+func (m *TaskSpec) GetAttachment() *NetworkAttachmentSpec {
340
+	if x, ok := m.GetRuntime().(*TaskSpec_Attachment); ok {
341
+		return x.Attachment
342
+	}
343
+	return nil
344
+}
345
+
339 346
 func (m *TaskSpec) GetContainer() *ContainerSpec {
340 347
 	if x, ok := m.GetRuntime().(*TaskSpec_Container); ok {
341 348
 		return x.Container
... ...
@@ -346,6 +343,7 @@ func (m *TaskSpec) GetContainer() *ContainerSpec {
346 346
 // XXX_OneofFuncs is for the internal use of the proto package.
347 347
 func (*TaskSpec) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
348 348
 	return _TaskSpec_OneofMarshaler, _TaskSpec_OneofUnmarshaler, _TaskSpec_OneofSizer, []interface{}{
349
+		(*TaskSpec_Attachment)(nil),
349 350
 		(*TaskSpec_Container)(nil),
350 351
 	}
351 352
 }
... ...
@@ -354,6 +352,11 @@ func _TaskSpec_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
354 354
 	m := msg.(*TaskSpec)
355 355
 	// runtime
356 356
 	switch x := m.Runtime.(type) {
357
+	case *TaskSpec_Attachment:
358
+		_ = b.EncodeVarint(8<<3 | proto.WireBytes)
359
+		if err := b.EncodeMessage(x.Attachment); err != nil {
360
+			return err
361
+		}
357 362
 	case *TaskSpec_Container:
358 363
 		_ = b.EncodeVarint(1<<3 | proto.WireBytes)
359 364
 		if err := b.EncodeMessage(x.Container); err != nil {
... ...
@@ -369,6 +372,14 @@ func _TaskSpec_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
369 369
 func _TaskSpec_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
370 370
 	m := msg.(*TaskSpec)
371 371
 	switch tag {
372
+	case 8: // runtime.attachment
373
+		if wire != proto.WireBytes {
374
+			return true, proto.ErrInternalBadWireType
375
+		}
376
+		msg := new(NetworkAttachmentSpec)
377
+		err := b.DecodeMessage(msg)
378
+		m.Runtime = &TaskSpec_Attachment{msg}
379
+		return true, err
372 380
 	case 1: // runtime.container
373 381
 		if wire != proto.WireBytes {
374 382
 			return true, proto.ErrInternalBadWireType
... ...
@@ -386,6 +397,11 @@ func _TaskSpec_OneofSizer(msg proto.Message) (n int) {
386 386
 	m := msg.(*TaskSpec)
387 387
 	// runtime
388 388
 	switch x := m.Runtime.(type) {
389
+	case *TaskSpec_Attachment:
390
+		s := proto.Size(x.Attachment)
391
+		n += proto.SizeVarint(8<<3 | proto.WireBytes)
392
+		n += proto.SizeVarint(uint64(s))
393
+		n += s
389 394
 	case *TaskSpec_Container:
390 395
 		s := proto.Size(x.Container)
391 396
 		n += proto.SizeVarint(1<<3 | proto.WireBytes)
... ...
@@ -398,6 +414,18 @@ func _TaskSpec_OneofSizer(msg proto.Message) (n int) {
398 398
 	return n
399 399
 }
400 400
 
401
+// NetworkAttachmentSpec specifies runtime parameters required to attach
402
+// a container to a network.
403
+type NetworkAttachmentSpec struct {
404
+	// ContainerID spcifies a unique ID of the container for which
405
+	// this attachment is for.
406
+	ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"`
407
+}
408
+
409
+func (m *NetworkAttachmentSpec) Reset()                    { *m = NetworkAttachmentSpec{} }
410
+func (*NetworkAttachmentSpec) ProtoMessage()               {}
411
+func (*NetworkAttachmentSpec) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{5} }
412
+
401 413
 // Container specifies runtime parameters for a container.
402 414
 type ContainerSpec struct {
403 415
 	// image defines the image reference, as specified in the
... ...
@@ -449,7 +477,7 @@ type ContainerSpec struct {
449 449
 
450 450
 func (m *ContainerSpec) Reset()                    { *m = ContainerSpec{} }
451 451
 func (*ContainerSpec) ProtoMessage()               {}
452
-func (*ContainerSpec) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{5} }
452
+func (*ContainerSpec) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{6} }
453 453
 
454 454
 // PullOptions allows one to parameterize an image pull.
455 455
 type ContainerSpec_PullOptions struct {
... ...
@@ -463,7 +491,7 @@ type ContainerSpec_PullOptions struct {
463 463
 func (m *ContainerSpec_PullOptions) Reset()      { *m = ContainerSpec_PullOptions{} }
464 464
 func (*ContainerSpec_PullOptions) ProtoMessage() {}
465 465
 func (*ContainerSpec_PullOptions) Descriptor() ([]byte, []int) {
466
-	return fileDescriptorSpecs, []int{5, 1}
466
+	return fileDescriptorSpecs, []int{6, 1}
467 467
 }
468 468
 
469 469
 // EndpointSpec defines the properties that can be configured to
... ...
@@ -477,7 +505,7 @@ type EndpointSpec struct {
477 477
 
478 478
 func (m *EndpointSpec) Reset()                    { *m = EndpointSpec{} }
479 479
 func (*EndpointSpec) ProtoMessage()               {}
480
-func (*EndpointSpec) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{6} }
480
+func (*EndpointSpec) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{7} }
481 481
 
482 482
 // NetworkSpec specifies user defined network parameters.
483 483
 type NetworkSpec struct {
... ...
@@ -490,11 +518,19 @@ type NetworkSpec struct {
490 490
 	// accomplished by disabling the default gateway or through other means.
491 491
 	Internal bool         `protobuf:"varint,4,opt,name=internal,proto3" json:"internal,omitempty"`
492 492
 	IPAM     *IPAMOptions `protobuf:"bytes,5,opt,name=ipam" json:"ipam,omitempty"`
493
+	// Attachable allows external(to swarm) entities to manually
494
+	// attach to this network. With this flag enabled, external
495
+	// entities such as containers running in an worker node in
496
+	// the cluster can manually attach to this network and access
497
+	// the services attached to this network. If this flag is not
498
+	// enabled(default case) no manual attachment to this network
499
+	// can happen.
500
+	Attachable bool `protobuf:"varint,6,opt,name=attachable,proto3" json:"attachable,omitempty"`
493 501
 }
494 502
 
495 503
 func (m *NetworkSpec) Reset()                    { *m = NetworkSpec{} }
496 504
 func (*NetworkSpec) ProtoMessage()               {}
497
-func (*NetworkSpec) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{7} }
505
+func (*NetworkSpec) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{8} }
498 506
 
499 507
 // ClusterSpec specifies global cluster settings.
500 508
 type ClusterSpec struct {
... ...
@@ -517,15 +553,15 @@ type ClusterSpec struct {
517 517
 
518 518
 func (m *ClusterSpec) Reset()                    { *m = ClusterSpec{} }
519 519
 func (*ClusterSpec) ProtoMessage()               {}
520
-func (*ClusterSpec) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{8} }
520
+func (*ClusterSpec) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{9} }
521 521
 
522 522
 func init() {
523 523
 	proto.RegisterType((*NodeSpec)(nil), "docker.swarmkit.v1.NodeSpec")
524 524
 	proto.RegisterType((*ServiceSpec)(nil), "docker.swarmkit.v1.ServiceSpec")
525
-	proto.RegisterType((*ServiceSpec_NetworkAttachmentConfig)(nil), "docker.swarmkit.v1.ServiceSpec.NetworkAttachmentConfig")
526 525
 	proto.RegisterType((*ReplicatedService)(nil), "docker.swarmkit.v1.ReplicatedService")
527 526
 	proto.RegisterType((*GlobalService)(nil), "docker.swarmkit.v1.GlobalService")
528 527
 	proto.RegisterType((*TaskSpec)(nil), "docker.swarmkit.v1.TaskSpec")
528
+	proto.RegisterType((*NetworkAttachmentSpec)(nil), "docker.swarmkit.v1.NetworkAttachmentSpec")
529 529
 	proto.RegisterType((*ContainerSpec)(nil), "docker.swarmkit.v1.ContainerSpec")
530 530
 	proto.RegisterType((*ContainerSpec_PullOptions)(nil), "docker.swarmkit.v1.ContainerSpec.PullOptions")
531 531
 	proto.RegisterType((*EndpointSpec)(nil), "docker.swarmkit.v1.EndpointSpec")
... ...
@@ -564,7 +600,7 @@ func (m *ServiceSpec) Copy() *ServiceSpec {
564 564
 	}
565 565
 
566 566
 	if m.Networks != nil {
567
-		o.Networks = make([]*ServiceSpec_NetworkAttachmentConfig, 0, len(m.Networks))
567
+		o.Networks = make([]*NetworkAttachmentConfig, 0, len(m.Networks))
568 568
 		for _, v := range m.Networks {
569 569
 			o.Networks = append(o.Networks, v.Copy())
570 570
 		}
... ...
@@ -588,25 +624,6 @@ func (m *ServiceSpec) Copy() *ServiceSpec {
588 588
 	return o
589 589
 }
590 590
 
591
-func (m *ServiceSpec_NetworkAttachmentConfig) Copy() *ServiceSpec_NetworkAttachmentConfig {
592
-	if m == nil {
593
-		return nil
594
-	}
595
-
596
-	o := &ServiceSpec_NetworkAttachmentConfig{
597
-		Target: m.Target,
598
-	}
599
-
600
-	if m.Aliases != nil {
601
-		o.Aliases = make([]string, 0, len(m.Aliases))
602
-		for _, v := range m.Aliases {
603
-			o.Aliases = append(o.Aliases, v)
604
-		}
605
-	}
606
-
607
-	return o
608
-}
609
-
610 591
 func (m *ReplicatedService) Copy() *ReplicatedService {
611 592
 	if m == nil {
612 593
 		return nil
... ...
@@ -641,7 +658,20 @@ func (m *TaskSpec) Copy() *TaskSpec {
641 641
 		LogDriver: m.LogDriver.Copy(),
642 642
 	}
643 643
 
644
+	if m.Networks != nil {
645
+		o.Networks = make([]*NetworkAttachmentConfig, 0, len(m.Networks))
646
+		for _, v := range m.Networks {
647
+			o.Networks = append(o.Networks, v.Copy())
648
+		}
649
+	}
650
+
644 651
 	switch m.Runtime.(type) {
652
+	case *TaskSpec_Attachment:
653
+		i := &TaskSpec_Attachment{
654
+			Attachment: m.GetAttachment().Copy(),
655
+		}
656
+
657
+		o.Runtime = i
645 658
 	case *TaskSpec_Container:
646 659
 		i := &TaskSpec_Container{
647 660
 			Container: m.GetContainer().Copy(),
... ...
@@ -653,6 +683,18 @@ func (m *TaskSpec) Copy() *TaskSpec {
653 653
 	return o
654 654
 }
655 655
 
656
+func (m *NetworkAttachmentSpec) Copy() *NetworkAttachmentSpec {
657
+	if m == nil {
658
+		return nil
659
+	}
660
+
661
+	o := &NetworkAttachmentSpec{
662
+		ContainerID: m.ContainerID,
663
+	}
664
+
665
+	return o
666
+}
667
+
656 668
 func (m *ContainerSpec) Copy() *ContainerSpec {
657 669
 	if m == nil {
658 670
 		return nil
... ...
@@ -753,6 +795,7 @@ func (m *NetworkSpec) Copy() *NetworkSpec {
753 753
 		Ipv6Enabled:  m.Ipv6Enabled,
754 754
 		Internal:     m.Internal,
755 755
 		IPAM:         m.IPAM.Copy(),
756
+		Attachable:   m.Attachable,
756 757
 	}
757 758
 
758 759
 	return o
... ...
@@ -828,17 +871,6 @@ func (this *ServiceSpec_Global) GoString() string {
828 828
 		`Global:` + fmt.Sprintf("%#v", this.Global) + `}`}, ", ")
829 829
 	return s
830 830
 }
831
-func (this *ServiceSpec_NetworkAttachmentConfig) GoString() string {
832
-	if this == nil {
833
-		return "nil"
834
-	}
835
-	s := make([]string, 0, 6)
836
-	s = append(s, "&api.ServiceSpec_NetworkAttachmentConfig{")
837
-	s = append(s, "Target: "+fmt.Sprintf("%#v", this.Target)+",\n")
838
-	s = append(s, "Aliases: "+fmt.Sprintf("%#v", this.Aliases)+",\n")
839
-	s = append(s, "}")
840
-	return strings.Join(s, "")
841
-}
842 831
 func (this *ReplicatedService) GoString() string {
843 832
 	if this == nil {
844 833
 		return "nil"
... ...
@@ -862,7 +894,7 @@ func (this *TaskSpec) GoString() string {
862 862
 	if this == nil {
863 863
 		return "nil"
864 864
 	}
865
-	s := make([]string, 0, 9)
865
+	s := make([]string, 0, 11)
866 866
 	s = append(s, "&api.TaskSpec{")
867 867
 	if this.Runtime != nil {
868 868
 		s = append(s, "Runtime: "+fmt.Sprintf("%#v", this.Runtime)+",\n")
... ...
@@ -879,9 +911,20 @@ func (this *TaskSpec) GoString() string {
879 879
 	if this.LogDriver != nil {
880 880
 		s = append(s, "LogDriver: "+fmt.Sprintf("%#v", this.LogDriver)+",\n")
881 881
 	}
882
+	if this.Networks != nil {
883
+		s = append(s, "Networks: "+fmt.Sprintf("%#v", this.Networks)+",\n")
884
+	}
882 885
 	s = append(s, "}")
883 886
 	return strings.Join(s, "")
884 887
 }
888
+func (this *TaskSpec_Attachment) GoString() string {
889
+	if this == nil {
890
+		return "nil"
891
+	}
892
+	s := strings.Join([]string{`&api.TaskSpec_Attachment{` +
893
+		`Attachment:` + fmt.Sprintf("%#v", this.Attachment) + `}`}, ", ")
894
+	return s
895
+}
885 896
 func (this *TaskSpec_Container) GoString() string {
886 897
 	if this == nil {
887 898
 		return "nil"
... ...
@@ -890,6 +933,16 @@ func (this *TaskSpec_Container) GoString() string {
890 890
 		`Container:` + fmt.Sprintf("%#v", this.Container) + `}`}, ", ")
891 891
 	return s
892 892
 }
893
+func (this *NetworkAttachmentSpec) GoString() string {
894
+	if this == nil {
895
+		return "nil"
896
+	}
897
+	s := make([]string, 0, 5)
898
+	s = append(s, "&api.NetworkAttachmentSpec{")
899
+	s = append(s, "ContainerID: "+fmt.Sprintf("%#v", this.ContainerID)+",\n")
900
+	s = append(s, "}")
901
+	return strings.Join(s, "")
902
+}
893 903
 func (this *ContainerSpec) GoString() string {
894 904
 	if this == nil {
895 905
 		return "nil"
... ...
@@ -955,7 +1008,7 @@ func (this *NetworkSpec) GoString() string {
955 955
 	if this == nil {
956 956
 		return "nil"
957 957
 	}
958
-	s := make([]string, 0, 9)
958
+	s := make([]string, 0, 10)
959 959
 	s = append(s, "&api.NetworkSpec{")
960 960
 	s = append(s, "Annotations: "+strings.Replace(this.Annotations.GoString(), `&`, ``, 1)+",\n")
961 961
 	if this.DriverConfig != nil {
... ...
@@ -966,6 +1019,7 @@ func (this *NetworkSpec) GoString() string {
966 966
 	if this.IPAM != nil {
967 967
 		s = append(s, "IPAM: "+fmt.Sprintf("%#v", this.IPAM)+",\n")
968 968
 	}
969
+	s = append(s, "Attachable: "+fmt.Sprintf("%#v", this.Attachable)+",\n")
969 970
 	s = append(s, "}")
970 971
 	return strings.Join(s, "")
971 972
 }
... ...
@@ -1152,45 +1206,6 @@ func (m *ServiceSpec_Global) MarshalTo(data []byte) (int, error) {
1152 1152
 	}
1153 1153
 	return i, nil
1154 1154
 }
1155
-func (m *ServiceSpec_NetworkAttachmentConfig) Marshal() (data []byte, err error) {
1156
-	size := m.Size()
1157
-	data = make([]byte, size)
1158
-	n, err := m.MarshalTo(data)
1159
-	if err != nil {
1160
-		return nil, err
1161
-	}
1162
-	return data[:n], nil
1163
-}
1164
-
1165
-func (m *ServiceSpec_NetworkAttachmentConfig) MarshalTo(data []byte) (int, error) {
1166
-	var i int
1167
-	_ = i
1168
-	var l int
1169
-	_ = l
1170
-	if len(m.Target) > 0 {
1171
-		data[i] = 0xa
1172
-		i++
1173
-		i = encodeVarintSpecs(data, i, uint64(len(m.Target)))
1174
-		i += copy(data[i:], m.Target)
1175
-	}
1176
-	if len(m.Aliases) > 0 {
1177
-		for _, s := range m.Aliases {
1178
-			data[i] = 0x12
1179
-			i++
1180
-			l = len(s)
1181
-			for l >= 1<<7 {
1182
-				data[i] = uint8(uint64(l)&0x7f | 0x80)
1183
-				l >>= 7
1184
-				i++
1185
-			}
1186
-			data[i] = uint8(l)
1187
-			i++
1188
-			i += copy(data[i:], s)
1189
-		}
1190
-	}
1191
-	return i, nil
1192
-}
1193
-
1194 1155
 func (m *ReplicatedService) Marshal() (data []byte, err error) {
1195 1156
 	size := m.Size()
1196 1157
 	data = make([]byte, size)
... ...
@@ -1294,6 +1309,18 @@ func (m *TaskSpec) MarshalTo(data []byte) (int, error) {
1294 1294
 		}
1295 1295
 		i += n13
1296 1296
 	}
1297
+	if len(m.Networks) > 0 {
1298
+		for _, msg := range m.Networks {
1299
+			data[i] = 0x3a
1300
+			i++
1301
+			i = encodeVarintSpecs(data, i, uint64(msg.Size()))
1302
+			n, err := msg.MarshalTo(data[i:])
1303
+			if err != nil {
1304
+				return 0, err
1305
+			}
1306
+			i += n
1307
+		}
1308
+	}
1297 1309
 	return i, nil
1298 1310
 }
1299 1311
 
... ...
@@ -1311,6 +1338,44 @@ func (m *TaskSpec_Container) MarshalTo(data []byte) (int, error) {
1311 1311
 	}
1312 1312
 	return i, nil
1313 1313
 }
1314
+func (m *TaskSpec_Attachment) MarshalTo(data []byte) (int, error) {
1315
+	i := 0
1316
+	if m.Attachment != nil {
1317
+		data[i] = 0x42
1318
+		i++
1319
+		i = encodeVarintSpecs(data, i, uint64(m.Attachment.Size()))
1320
+		n15, err := m.Attachment.MarshalTo(data[i:])
1321
+		if err != nil {
1322
+			return 0, err
1323
+		}
1324
+		i += n15
1325
+	}
1326
+	return i, nil
1327
+}
1328
+func (m *NetworkAttachmentSpec) Marshal() (data []byte, err error) {
1329
+	size := m.Size()
1330
+	data = make([]byte, size)
1331
+	n, err := m.MarshalTo(data)
1332
+	if err != nil {
1333
+		return nil, err
1334
+	}
1335
+	return data[:n], nil
1336
+}
1337
+
1338
+func (m *NetworkAttachmentSpec) MarshalTo(data []byte) (int, error) {
1339
+	var i int
1340
+	_ = i
1341
+	var l int
1342
+	_ = l
1343
+	if len(m.ContainerID) > 0 {
1344
+		data[i] = 0xa
1345
+		i++
1346
+		i = encodeVarintSpecs(data, i, uint64(len(m.ContainerID)))
1347
+		i += copy(data[i:], m.ContainerID)
1348
+	}
1349
+	return i, nil
1350
+}
1351
+
1314 1352
 func (m *ContainerSpec) Marshal() (data []byte, err error) {
1315 1353
 	size := m.Size()
1316 1354
 	data = make([]byte, size)
... ...
@@ -1422,21 +1487,21 @@ func (m *ContainerSpec) MarshalTo(data []byte) (int, error) {
1422 1422
 		data[i] = 0x4a
1423 1423
 		i++
1424 1424
 		i = encodeVarintSpecs(data, i, uint64(m.StopGracePeriod.Size()))
1425
-		n15, err := m.StopGracePeriod.MarshalTo(data[i:])
1425
+		n16, err := m.StopGracePeriod.MarshalTo(data[i:])
1426 1426
 		if err != nil {
1427 1427
 			return 0, err
1428 1428
 		}
1429
-		i += n15
1429
+		i += n16
1430 1430
 	}
1431 1431
 	if m.PullOptions != nil {
1432 1432
 		data[i] = 0x52
1433 1433
 		i++
1434 1434
 		i = encodeVarintSpecs(data, i, uint64(m.PullOptions.Size()))
1435
-		n16, err := m.PullOptions.MarshalTo(data[i:])
1435
+		n17, err := m.PullOptions.MarshalTo(data[i:])
1436 1436
 		if err != nil {
1437 1437
 			return 0, err
1438 1438
 		}
1439
-		i += n16
1439
+		i += n17
1440 1440
 	}
1441 1441
 	if len(m.Groups) > 0 {
1442 1442
 		for _, s := range m.Groups {
... ...
@@ -1535,20 +1600,20 @@ func (m *NetworkSpec) MarshalTo(data []byte) (int, error) {
1535 1535
 	data[i] = 0xa
1536 1536
 	i++
1537 1537
 	i = encodeVarintSpecs(data, i, uint64(m.Annotations.Size()))
1538
-	n17, err := m.Annotations.MarshalTo(data[i:])
1538
+	n18, err := m.Annotations.MarshalTo(data[i:])
1539 1539
 	if err != nil {
1540 1540
 		return 0, err
1541 1541
 	}
1542
-	i += n17
1542
+	i += n18
1543 1543
 	if m.DriverConfig != nil {
1544 1544
 		data[i] = 0x12
1545 1545
 		i++
1546 1546
 		i = encodeVarintSpecs(data, i, uint64(m.DriverConfig.Size()))
1547
-		n18, err := m.DriverConfig.MarshalTo(data[i:])
1547
+		n19, err := m.DriverConfig.MarshalTo(data[i:])
1548 1548
 		if err != nil {
1549 1549
 			return 0, err
1550 1550
 		}
1551
-		i += n18
1551
+		i += n19
1552 1552
 	}
1553 1553
 	if m.Ipv6Enabled {
1554 1554
 		data[i] = 0x18
... ...
@@ -1574,11 +1639,21 @@ func (m *NetworkSpec) MarshalTo(data []byte) (int, error) {
1574 1574
 		data[i] = 0x2a
1575 1575
 		i++
1576 1576
 		i = encodeVarintSpecs(data, i, uint64(m.IPAM.Size()))
1577
-		n19, err := m.IPAM.MarshalTo(data[i:])
1577
+		n20, err := m.IPAM.MarshalTo(data[i:])
1578 1578
 		if err != nil {
1579 1579
 			return 0, err
1580 1580
 		}
1581
-		i += n19
1581
+		i += n20
1582
+	}
1583
+	if m.Attachable {
1584
+		data[i] = 0x30
1585
+		i++
1586
+		if m.Attachable {
1587
+			data[i] = 1
1588
+		} else {
1589
+			data[i] = 0
1590
+		}
1591
+		i++
1582 1592
 	}
1583 1593
 	return i, nil
1584 1594
 }
... ...
@@ -1601,59 +1676,59 @@ func (m *ClusterSpec) MarshalTo(data []byte) (int, error) {
1601 1601
 	data[i] = 0xa
1602 1602
 	i++
1603 1603
 	i = encodeVarintSpecs(data, i, uint64(m.Annotations.Size()))
1604
-	n20, err := m.Annotations.MarshalTo(data[i:])
1604
+	n21, err := m.Annotations.MarshalTo(data[i:])
1605 1605
 	if err != nil {
1606 1606
 		return 0, err
1607 1607
 	}
1608
-	i += n20
1608
+	i += n21
1609 1609
 	data[i] = 0x12
1610 1610
 	i++
1611 1611
 	i = encodeVarintSpecs(data, i, uint64(m.AcceptancePolicy.Size()))
1612
-	n21, err := m.AcceptancePolicy.MarshalTo(data[i:])
1612
+	n22, err := m.AcceptancePolicy.MarshalTo(data[i:])
1613 1613
 	if err != nil {
1614 1614
 		return 0, err
1615 1615
 	}
1616
-	i += n21
1616
+	i += n22
1617 1617
 	data[i] = 0x1a
1618 1618
 	i++
1619 1619
 	i = encodeVarintSpecs(data, i, uint64(m.Orchestration.Size()))
1620
-	n22, err := m.Orchestration.MarshalTo(data[i:])
1620
+	n23, err := m.Orchestration.MarshalTo(data[i:])
1621 1621
 	if err != nil {
1622 1622
 		return 0, err
1623 1623
 	}
1624
-	i += n22
1624
+	i += n23
1625 1625
 	data[i] = 0x22
1626 1626
 	i++
1627 1627
 	i = encodeVarintSpecs(data, i, uint64(m.Raft.Size()))
1628
-	n23, err := m.Raft.MarshalTo(data[i:])
1628
+	n24, err := m.Raft.MarshalTo(data[i:])
1629 1629
 	if err != nil {
1630 1630
 		return 0, err
1631 1631
 	}
1632
-	i += n23
1632
+	i += n24
1633 1633
 	data[i] = 0x2a
1634 1634
 	i++
1635 1635
 	i = encodeVarintSpecs(data, i, uint64(m.Dispatcher.Size()))
1636
-	n24, err := m.Dispatcher.MarshalTo(data[i:])
1636
+	n25, err := m.Dispatcher.MarshalTo(data[i:])
1637 1637
 	if err != nil {
1638 1638
 		return 0, err
1639 1639
 	}
1640
-	i += n24
1640
+	i += n25
1641 1641
 	data[i] = 0x32
1642 1642
 	i++
1643 1643
 	i = encodeVarintSpecs(data, i, uint64(m.CAConfig.Size()))
1644
-	n25, err := m.CAConfig.MarshalTo(data[i:])
1644
+	n26, err := m.CAConfig.MarshalTo(data[i:])
1645 1645
 	if err != nil {
1646 1646
 		return 0, err
1647 1647
 	}
1648
-	i += n25
1648
+	i += n26
1649 1649
 	data[i] = 0x3a
1650 1650
 	i++
1651 1651
 	i = encodeVarintSpecs(data, i, uint64(m.TaskDefaults.Size()))
1652
-	n26, err := m.TaskDefaults.MarshalTo(data[i:])
1652
+	n27, err := m.TaskDefaults.MarshalTo(data[i:])
1653 1653
 	if err != nil {
1654 1654
 		return 0, err
1655 1655
 	}
1656
-	i += n26
1656
+	i += n27
1657 1657
 	return i, nil
1658 1658
 }
1659 1659
 
... ...
@@ -1747,22 +1822,6 @@ func (m *ServiceSpec_Global) Size() (n int) {
1747 1747
 	}
1748 1748
 	return n
1749 1749
 }
1750
-func (m *ServiceSpec_NetworkAttachmentConfig) Size() (n int) {
1751
-	var l int
1752
-	_ = l
1753
-	l = len(m.Target)
1754
-	if l > 0 {
1755
-		n += 1 + l + sovSpecs(uint64(l))
1756
-	}
1757
-	if len(m.Aliases) > 0 {
1758
-		for _, s := range m.Aliases {
1759
-			l = len(s)
1760
-			n += 1 + l + sovSpecs(uint64(l))
1761
-		}
1762
-	}
1763
-	return n
1764
-}
1765
-
1766 1750
 func (m *ReplicatedService) Size() (n int) {
1767 1751
 	var l int
1768 1752
 	_ = l
... ...
@@ -1800,6 +1859,12 @@ func (m *TaskSpec) Size() (n int) {
1800 1800
 		l = m.LogDriver.Size()
1801 1801
 		n += 1 + l + sovSpecs(uint64(l))
1802 1802
 	}
1803
+	if len(m.Networks) > 0 {
1804
+		for _, e := range m.Networks {
1805
+			l = e.Size()
1806
+			n += 1 + l + sovSpecs(uint64(l))
1807
+		}
1808
+	}
1803 1809
 	return n
1804 1810
 }
1805 1811
 
... ...
@@ -1812,6 +1877,25 @@ func (m *TaskSpec_Container) Size() (n int) {
1812 1812
 	}
1813 1813
 	return n
1814 1814
 }
1815
+func (m *TaskSpec_Attachment) Size() (n int) {
1816
+	var l int
1817
+	_ = l
1818
+	if m.Attachment != nil {
1819
+		l = m.Attachment.Size()
1820
+		n += 1 + l + sovSpecs(uint64(l))
1821
+	}
1822
+	return n
1823
+}
1824
+func (m *NetworkAttachmentSpec) Size() (n int) {
1825
+	var l int
1826
+	_ = l
1827
+	l = len(m.ContainerID)
1828
+	if l > 0 {
1829
+		n += 1 + l + sovSpecs(uint64(l))
1830
+	}
1831
+	return n
1832
+}
1833
+
1815 1834
 func (m *ContainerSpec) Size() (n int) {
1816 1835
 	var l int
1817 1836
 	_ = l
... ...
@@ -1920,6 +2004,9 @@ func (m *NetworkSpec) Size() (n int) {
1920 1920
 		l = m.IPAM.Size()
1921 1921
 		n += 1 + l + sovSpecs(uint64(l))
1922 1922
 	}
1923
+	if m.Attachable {
1924
+		n += 2
1925
+	}
1923 1926
 	return n
1924 1927
 }
1925 1928
 
... ...
@@ -1978,7 +2065,7 @@ func (this *ServiceSpec) String() string {
1978 1978
 		`Task:` + strings.Replace(strings.Replace(this.Task.String(), "TaskSpec", "TaskSpec", 1), `&`, ``, 1) + `,`,
1979 1979
 		`Mode:` + fmt.Sprintf("%v", this.Mode) + `,`,
1980 1980
 		`Update:` + strings.Replace(fmt.Sprintf("%v", this.Update), "UpdateConfig", "UpdateConfig", 1) + `,`,
1981
-		`Networks:` + strings.Replace(fmt.Sprintf("%v", this.Networks), "ServiceSpec_NetworkAttachmentConfig", "ServiceSpec_NetworkAttachmentConfig", 1) + `,`,
1981
+		`Networks:` + strings.Replace(fmt.Sprintf("%v", this.Networks), "NetworkAttachmentConfig", "NetworkAttachmentConfig", 1) + `,`,
1982 1982
 		`Endpoint:` + strings.Replace(fmt.Sprintf("%v", this.Endpoint), "EndpointSpec", "EndpointSpec", 1) + `,`,
1983 1983
 		`}`,
1984 1984
 	}, "")
... ...
@@ -2004,17 +2091,6 @@ func (this *ServiceSpec_Global) String() string {
2004 2004
 	}, "")
2005 2005
 	return s
2006 2006
 }
2007
-func (this *ServiceSpec_NetworkAttachmentConfig) String() string {
2008
-	if this == nil {
2009
-		return "nil"
2010
-	}
2011
-	s := strings.Join([]string{`&ServiceSpec_NetworkAttachmentConfig{`,
2012
-		`Target:` + fmt.Sprintf("%v", this.Target) + `,`,
2013
-		`Aliases:` + fmt.Sprintf("%v", this.Aliases) + `,`,
2014
-		`}`,
2015
-	}, "")
2016
-	return s
2017
-}
2018 2007
 func (this *ReplicatedService) String() string {
2019 2008
 	if this == nil {
2020 2009
 		return "nil"
... ...
@@ -2044,6 +2120,7 @@ func (this *TaskSpec) String() string {
2044 2044
 		`Restart:` + strings.Replace(fmt.Sprintf("%v", this.Restart), "RestartPolicy", "RestartPolicy", 1) + `,`,
2045 2045
 		`Placement:` + strings.Replace(fmt.Sprintf("%v", this.Placement), "Placement", "Placement", 1) + `,`,
2046 2046
 		`LogDriver:` + strings.Replace(fmt.Sprintf("%v", this.LogDriver), "Driver", "Driver", 1) + `,`,
2047
+		`Networks:` + strings.Replace(fmt.Sprintf("%v", this.Networks), "NetworkAttachmentConfig", "NetworkAttachmentConfig", 1) + `,`,
2047 2048
 		`}`,
2048 2049
 	}, "")
2049 2050
 	return s
... ...
@@ -2058,6 +2135,26 @@ func (this *TaskSpec_Container) String() string {
2058 2058
 	}, "")
2059 2059
 	return s
2060 2060
 }
2061
+func (this *TaskSpec_Attachment) String() string {
2062
+	if this == nil {
2063
+		return "nil"
2064
+	}
2065
+	s := strings.Join([]string{`&TaskSpec_Attachment{`,
2066
+		`Attachment:` + strings.Replace(fmt.Sprintf("%v", this.Attachment), "NetworkAttachmentSpec", "NetworkAttachmentSpec", 1) + `,`,
2067
+		`}`,
2068
+	}, "")
2069
+	return s
2070
+}
2071
+func (this *NetworkAttachmentSpec) String() string {
2072
+	if this == nil {
2073
+		return "nil"
2074
+	}
2075
+	s := strings.Join([]string{`&NetworkAttachmentSpec{`,
2076
+		`ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`,
2077
+		`}`,
2078
+	}, "")
2079
+	return s
2080
+}
2061 2081
 func (this *ContainerSpec) String() string {
2062 2082
 	if this == nil {
2063 2083
 		return "nil"
... ...
@@ -2119,6 +2216,7 @@ func (this *NetworkSpec) String() string {
2119 2119
 		`Ipv6Enabled:` + fmt.Sprintf("%v", this.Ipv6Enabled) + `,`,
2120 2120
 		`Internal:` + fmt.Sprintf("%v", this.Internal) + `,`,
2121 2121
 		`IPAM:` + strings.Replace(fmt.Sprintf("%v", this.IPAM), "IPAMOptions", "IPAMOptions", 1) + `,`,
2122
+		`Attachable:` + fmt.Sprintf("%v", this.Attachable) + `,`,
2122 2123
 		`}`,
2123 2124
 	}, "")
2124 2125
 	return s
... ...
@@ -2496,7 +2594,7 @@ func (m *ServiceSpec) Unmarshal(data []byte) error {
2496 2496
 			if postIndex > l {
2497 2497
 				return io.ErrUnexpectedEOF
2498 2498
 			}
2499
-			m.Networks = append(m.Networks, &ServiceSpec_NetworkAttachmentConfig{})
2499
+			m.Networks = append(m.Networks, &NetworkAttachmentConfig{})
2500 2500
 			if err := m.Networks[len(m.Networks)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
2501 2501
 				return err
2502 2502
 			}
... ...
@@ -2555,114 +2653,6 @@ func (m *ServiceSpec) Unmarshal(data []byte) error {
2555 2555
 	}
2556 2556
 	return nil
2557 2557
 }
2558
-func (m *ServiceSpec_NetworkAttachmentConfig) Unmarshal(data []byte) error {
2559
-	l := len(data)
2560
-	iNdEx := 0
2561
-	for iNdEx < l {
2562
-		preIndex := iNdEx
2563
-		var wire uint64
2564
-		for shift := uint(0); ; shift += 7 {
2565
-			if shift >= 64 {
2566
-				return ErrIntOverflowSpecs
2567
-			}
2568
-			if iNdEx >= l {
2569
-				return io.ErrUnexpectedEOF
2570
-			}
2571
-			b := data[iNdEx]
2572
-			iNdEx++
2573
-			wire |= (uint64(b) & 0x7F) << shift
2574
-			if b < 0x80 {
2575
-				break
2576
-			}
2577
-		}
2578
-		fieldNum := int32(wire >> 3)
2579
-		wireType := int(wire & 0x7)
2580
-		if wireType == 4 {
2581
-			return fmt.Errorf("proto: NetworkAttachmentConfig: wiretype end group for non-group")
2582
-		}
2583
-		if fieldNum <= 0 {
2584
-			return fmt.Errorf("proto: NetworkAttachmentConfig: illegal tag %d (wire type %d)", fieldNum, wire)
2585
-		}
2586
-		switch fieldNum {
2587
-		case 1:
2588
-			if wireType != 2 {
2589
-				return fmt.Errorf("proto: wrong wireType = %d for field Target", wireType)
2590
-			}
2591
-			var stringLen uint64
2592
-			for shift := uint(0); ; shift += 7 {
2593
-				if shift >= 64 {
2594
-					return ErrIntOverflowSpecs
2595
-				}
2596
-				if iNdEx >= l {
2597
-					return io.ErrUnexpectedEOF
2598
-				}
2599
-				b := data[iNdEx]
2600
-				iNdEx++
2601
-				stringLen |= (uint64(b) & 0x7F) << shift
2602
-				if b < 0x80 {
2603
-					break
2604
-				}
2605
-			}
2606
-			intStringLen := int(stringLen)
2607
-			if intStringLen < 0 {
2608
-				return ErrInvalidLengthSpecs
2609
-			}
2610
-			postIndex := iNdEx + intStringLen
2611
-			if postIndex > l {
2612
-				return io.ErrUnexpectedEOF
2613
-			}
2614
-			m.Target = string(data[iNdEx:postIndex])
2615
-			iNdEx = postIndex
2616
-		case 2:
2617
-			if wireType != 2 {
2618
-				return fmt.Errorf("proto: wrong wireType = %d for field Aliases", wireType)
2619
-			}
2620
-			var stringLen uint64
2621
-			for shift := uint(0); ; shift += 7 {
2622
-				if shift >= 64 {
2623
-					return ErrIntOverflowSpecs
2624
-				}
2625
-				if iNdEx >= l {
2626
-					return io.ErrUnexpectedEOF
2627
-				}
2628
-				b := data[iNdEx]
2629
-				iNdEx++
2630
-				stringLen |= (uint64(b) & 0x7F) << shift
2631
-				if b < 0x80 {
2632
-					break
2633
-				}
2634
-			}
2635
-			intStringLen := int(stringLen)
2636
-			if intStringLen < 0 {
2637
-				return ErrInvalidLengthSpecs
2638
-			}
2639
-			postIndex := iNdEx + intStringLen
2640
-			if postIndex > l {
2641
-				return io.ErrUnexpectedEOF
2642
-			}
2643
-			m.Aliases = append(m.Aliases, string(data[iNdEx:postIndex]))
2644
-			iNdEx = postIndex
2645
-		default:
2646
-			iNdEx = preIndex
2647
-			skippy, err := skipSpecs(data[iNdEx:])
2648
-			if err != nil {
2649
-				return err
2650
-			}
2651
-			if skippy < 0 {
2652
-				return ErrInvalidLengthSpecs
2653
-			}
2654
-			if (iNdEx + skippy) > l {
2655
-				return io.ErrUnexpectedEOF
2656
-			}
2657
-			iNdEx += skippy
2658
-		}
2659
-	}
2660
-
2661
-	if iNdEx > l {
2662
-		return io.ErrUnexpectedEOF
2663
-	}
2664
-	return nil
2665
-}
2666 2558
 func (m *ReplicatedService) Unmarshal(data []byte) error {
2667 2559
 	l := len(data)
2668 2560
 	iNdEx := 0
... ...
@@ -2975,6 +2965,148 @@ func (m *TaskSpec) Unmarshal(data []byte) error {
2975 2975
 				return err
2976 2976
 			}
2977 2977
 			iNdEx = postIndex
2978
+		case 7:
2979
+			if wireType != 2 {
2980
+				return fmt.Errorf("proto: wrong wireType = %d for field Networks", wireType)
2981
+			}
2982
+			var msglen int
2983
+			for shift := uint(0); ; shift += 7 {
2984
+				if shift >= 64 {
2985
+					return ErrIntOverflowSpecs
2986
+				}
2987
+				if iNdEx >= l {
2988
+					return io.ErrUnexpectedEOF
2989
+				}
2990
+				b := data[iNdEx]
2991
+				iNdEx++
2992
+				msglen |= (int(b) & 0x7F) << shift
2993
+				if b < 0x80 {
2994
+					break
2995
+				}
2996
+			}
2997
+			if msglen < 0 {
2998
+				return ErrInvalidLengthSpecs
2999
+			}
3000
+			postIndex := iNdEx + msglen
3001
+			if postIndex > l {
3002
+				return io.ErrUnexpectedEOF
3003
+			}
3004
+			m.Networks = append(m.Networks, &NetworkAttachmentConfig{})
3005
+			if err := m.Networks[len(m.Networks)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
3006
+				return err
3007
+			}
3008
+			iNdEx = postIndex
3009
+		case 8:
3010
+			if wireType != 2 {
3011
+				return fmt.Errorf("proto: wrong wireType = %d for field Attachment", wireType)
3012
+			}
3013
+			var msglen int
3014
+			for shift := uint(0); ; shift += 7 {
3015
+				if shift >= 64 {
3016
+					return ErrIntOverflowSpecs
3017
+				}
3018
+				if iNdEx >= l {
3019
+					return io.ErrUnexpectedEOF
3020
+				}
3021
+				b := data[iNdEx]
3022
+				iNdEx++
3023
+				msglen |= (int(b) & 0x7F) << shift
3024
+				if b < 0x80 {
3025
+					break
3026
+				}
3027
+			}
3028
+			if msglen < 0 {
3029
+				return ErrInvalidLengthSpecs
3030
+			}
3031
+			postIndex := iNdEx + msglen
3032
+			if postIndex > l {
3033
+				return io.ErrUnexpectedEOF
3034
+			}
3035
+			v := &NetworkAttachmentSpec{}
3036
+			if err := v.Unmarshal(data[iNdEx:postIndex]); err != nil {
3037
+				return err
3038
+			}
3039
+			m.Runtime = &TaskSpec_Attachment{v}
3040
+			iNdEx = postIndex
3041
+		default:
3042
+			iNdEx = preIndex
3043
+			skippy, err := skipSpecs(data[iNdEx:])
3044
+			if err != nil {
3045
+				return err
3046
+			}
3047
+			if skippy < 0 {
3048
+				return ErrInvalidLengthSpecs
3049
+			}
3050
+			if (iNdEx + skippy) > l {
3051
+				return io.ErrUnexpectedEOF
3052
+			}
3053
+			iNdEx += skippy
3054
+		}
3055
+	}
3056
+
3057
+	if iNdEx > l {
3058
+		return io.ErrUnexpectedEOF
3059
+	}
3060
+	return nil
3061
+}
3062
+func (m *NetworkAttachmentSpec) Unmarshal(data []byte) error {
3063
+	l := len(data)
3064
+	iNdEx := 0
3065
+	for iNdEx < l {
3066
+		preIndex := iNdEx
3067
+		var wire uint64
3068
+		for shift := uint(0); ; shift += 7 {
3069
+			if shift >= 64 {
3070
+				return ErrIntOverflowSpecs
3071
+			}
3072
+			if iNdEx >= l {
3073
+				return io.ErrUnexpectedEOF
3074
+			}
3075
+			b := data[iNdEx]
3076
+			iNdEx++
3077
+			wire |= (uint64(b) & 0x7F) << shift
3078
+			if b < 0x80 {
3079
+				break
3080
+			}
3081
+		}
3082
+		fieldNum := int32(wire >> 3)
3083
+		wireType := int(wire & 0x7)
3084
+		if wireType == 4 {
3085
+			return fmt.Errorf("proto: NetworkAttachmentSpec: wiretype end group for non-group")
3086
+		}
3087
+		if fieldNum <= 0 {
3088
+			return fmt.Errorf("proto: NetworkAttachmentSpec: illegal tag %d (wire type %d)", fieldNum, wire)
3089
+		}
3090
+		switch fieldNum {
3091
+		case 1:
3092
+			if wireType != 2 {
3093
+				return fmt.Errorf("proto: wrong wireType = %d for field ContainerID", wireType)
3094
+			}
3095
+			var stringLen uint64
3096
+			for shift := uint(0); ; shift += 7 {
3097
+				if shift >= 64 {
3098
+					return ErrIntOverflowSpecs
3099
+				}
3100
+				if iNdEx >= l {
3101
+					return io.ErrUnexpectedEOF
3102
+				}
3103
+				b := data[iNdEx]
3104
+				iNdEx++
3105
+				stringLen |= (uint64(b) & 0x7F) << shift
3106
+				if b < 0x80 {
3107
+					break
3108
+				}
3109
+			}
3110
+			intStringLen := int(stringLen)
3111
+			if intStringLen < 0 {
3112
+				return ErrInvalidLengthSpecs
3113
+			}
3114
+			postIndex := iNdEx + intStringLen
3115
+			if postIndex > l {
3116
+				return io.ErrUnexpectedEOF
3117
+			}
3118
+			m.ContainerID = string(data[iNdEx:postIndex])
3119
+			iNdEx = postIndex
2978 3120
 		default:
2979 3121
 			iNdEx = preIndex
2980 3122
 			skippy, err := skipSpecs(data[iNdEx:])
... ...
@@ -3801,6 +3933,26 @@ func (m *NetworkSpec) Unmarshal(data []byte) error {
3801 3801
 				return err
3802 3802
 			}
3803 3803
 			iNdEx = postIndex
3804
+		case 6:
3805
+			if wireType != 0 {
3806
+				return fmt.Errorf("proto: wrong wireType = %d for field Attachable", wireType)
3807
+			}
3808
+			var v int
3809
+			for shift := uint(0); ; shift += 7 {
3810
+				if shift >= 64 {
3811
+					return ErrIntOverflowSpecs
3812
+				}
3813
+				if iNdEx >= l {
3814
+					return io.ErrUnexpectedEOF
3815
+				}
3816
+				b := data[iNdEx]
3817
+				iNdEx++
3818
+				v |= (int(b) & 0x7F) << shift
3819
+				if b < 0x80 {
3820
+					break
3821
+				}
3822
+			}
3823
+			m.Attachable = bool(v != 0)
3804 3824
 		default:
3805 3825
 			iNdEx = preIndex
3806 3826
 			skippy, err := skipSpecs(data[iNdEx:])
... ...
@@ -4188,91 +4340,93 @@ var (
4188 4188
 )
4189 4189
 
4190 4190
 var fileDescriptorSpecs = []byte{
4191
-	// 1361 bytes of a gzipped FileDescriptorProto
4192
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x57, 0x4d, 0x6f, 0x1b, 0xb7,
4193
-	0x16, 0xd5, 0xd8, 0x63, 0x59, 0xba, 0x23, 0x27, 0x0a, 0x91, 0x97, 0x4c, 0x94, 0x3c, 0x59, 0xd1,
4194
-	0xcb, 0x4b, 0xdd, 0x02, 0x95, 0x5b, 0xb5, 0xc8, 0x47, 0xd3, 0xa2, 0x95, 0x25, 0xd5, 0x71, 0x53,
4195
-	0x3b, 0x02, 0x9d, 0x04, 0xe8, 0x4a, 0xa0, 0x67, 0x68, 0x99, 0xf0, 0x68, 0x38, 0xe5, 0x70, 0x14,
4196
-	0x78, 0xd7, 0x65, 0xe0, 0x45, 0x77, 0x5d, 0x7a, 0x55, 0xa0, 0xcb, 0x2e, 0xfb, 0x1b, 0xb2, 0xec,
4197
-	0xa6, 0x40, 0x57, 0x41, 0xe3, 0x5f, 0x50, 0xa0, 0x7f, 0xa0, 0x20, 0x87, 0xfa, 0x6a, 0xc6, 0x49,
4198
-	0x17, 0xd9, 0x91, 0x57, 0xe7, 0x1c, 0xde, 0xb9, 0x3c, 0xbc, 0xa4, 0xc0, 0x89, 0x23, 0xea, 0xc5,
4199
-	0x8d, 0x48, 0x70, 0xc9, 0x11, 0xf2, 0xb9, 0x77, 0x48, 0x45, 0x23, 0x7e, 0x4a, 0xc4, 0xf0, 0x90,
4200
-	0xc9, 0xc6, 0xe8, 0xc3, 0x8a, 0x23, 0x8f, 0x22, 0x6a, 0x00, 0x95, 0x8b, 0x03, 0x3e, 0xe0, 0x7a,
4201
-	0xb8, 0xae, 0x46, 0x26, 0x7a, 0xd9, 0x4f, 0x04, 0x91, 0x8c, 0x87, 0xeb, 0xe3, 0x41, 0xfa, 0x43,
4202
-	0xfd, 0x7b, 0x1b, 0x0a, 0x3b, 0xdc, 0xa7, 0xbb, 0x11, 0xf5, 0xd0, 0x26, 0x38, 0x24, 0x0c, 0xb9,
4203
-	0xd4, 0x80, 0xd8, 0xb5, 0x6a, 0xd6, 0x9a, 0xd3, 0x5c, 0x6d, 0xbc, 0xba, 0x64, 0xa3, 0x35, 0x85,
4204
-	0x6d, 0xd8, 0xcf, 0x5f, 0xac, 0xe6, 0xf0, 0x2c, 0x13, 0x7d, 0x00, 0xb6, 0xe0, 0x01, 0x75, 0x17,
4205
-	0x6a, 0xd6, 0xda, 0xb9, 0xe6, 0xb5, 0x2c, 0x05, 0xb5, 0x28, 0xe6, 0x01, 0xc5, 0x1a, 0x89, 0x36,
4206
-	0x01, 0x86, 0x74, 0xb8, 0x47, 0x45, 0x7c, 0xc0, 0x22, 0x77, 0x51, 0xf3, 0xde, 0x39, 0x8b, 0xa7,
4207
-	0x92, 0x6d, 0x6c, 0x4f, 0xe0, 0x78, 0x86, 0x8a, 0xb6, 0xa1, 0x44, 0x46, 0x84, 0x05, 0x64, 0x8f,
4208
-	0x05, 0x4c, 0x1e, 0xb9, 0xb6, 0x96, 0x7a, 0xf7, 0xb5, 0x52, 0xad, 0x19, 0x02, 0x9e, 0xa3, 0xd7,
4209
-	0x7d, 0x80, 0xe9, 0x42, 0xe8, 0x26, 0x2c, 0xf7, 0xba, 0x3b, 0x9d, 0xad, 0x9d, 0xcd, 0x72, 0xae,
4210
-	0x72, 0xe5, 0xf8, 0xa4, 0xf6, 0x1f, 0xa5, 0x31, 0x05, 0xf4, 0x68, 0xe8, 0xb3, 0x70, 0x80, 0xd6,
4211
-	0xa0, 0xd0, 0x6a, 0xb7, 0xbb, 0xbd, 0x47, 0xdd, 0x4e, 0xd9, 0xaa, 0x54, 0x8e, 0x4f, 0x6a, 0x97,
4212
-	0xe6, 0x81, 0x2d, 0xcf, 0xa3, 0x91, 0xa4, 0x7e, 0xc5, 0x7e, 0xf6, 0x63, 0x35, 0x57, 0x7f, 0x66,
4213
-	0x41, 0x69, 0x36, 0x09, 0x74, 0x13, 0xf2, 0xad, 0xf6, 0xa3, 0xad, 0x27, 0xdd, 0x72, 0x6e, 0x4a,
4214
-	0x9f, 0x45, 0xb4, 0x3c, 0xc9, 0x46, 0x14, 0xdd, 0x80, 0xa5, 0x5e, 0xeb, 0xf1, 0x6e, 0xb7, 0x6c,
4215
-	0x4d, 0xd3, 0x99, 0x85, 0xf5, 0x48, 0x12, 0x6b, 0x54, 0x07, 0xb7, 0xb6, 0x76, 0xca, 0x0b, 0xd9,
4216
-	0xa8, 0x8e, 0x20, 0x2c, 0x34, 0xa9, 0xfc, 0x62, 0x83, 0xb3, 0x4b, 0xc5, 0x88, 0x79, 0x6f, 0xd9,
4217
-	0x13, 0xb7, 0xc0, 0x96, 0x24, 0x3e, 0xd4, 0x9e, 0x70, 0xb2, 0x3d, 0xf1, 0x88, 0xc4, 0x87, 0x6a,
4218
-	0x51, 0x43, 0xd7, 0x78, 0xe5, 0x0c, 0x41, 0xa3, 0x80, 0x79, 0x44, 0x52, 0x5f, 0x3b, 0xc3, 0x69,
4219
-	0xfe, 0x3f, 0x8b, 0x8d, 0x27, 0x28, 0x93, 0xff, 0xfd, 0x1c, 0x9e, 0xa1, 0xa2, 0x7b, 0x90, 0x1f,
4220
-	0x04, 0x7c, 0x8f, 0x04, 0xda, 0x13, 0x4e, 0xf3, 0x7a, 0x96, 0xc8, 0xa6, 0x46, 0x4c, 0x05, 0x0c,
4221
-	0x05, 0xdd, 0x81, 0x7c, 0x12, 0xf9, 0x44, 0x52, 0x37, 0xaf, 0xc9, 0xb5, 0x2c, 0xf2, 0x63, 0x8d,
4222
-	0x68, 0xf3, 0x70, 0x9f, 0x0d, 0xb0, 0xc1, 0xa3, 0x5d, 0x28, 0x84, 0x54, 0x3e, 0xe5, 0xe2, 0x30,
4223
-	0x76, 0x97, 0x6b, 0x8b, 0x6b, 0x4e, 0xf3, 0x76, 0x16, 0x77, 0xa6, 0xe6, 0x8d, 0x9d, 0x14, 0xdf,
4224
-	0x92, 0x92, 0x78, 0x07, 0x43, 0x1a, 0x4a, 0x23, 0x39, 0x11, 0x42, 0x9f, 0x42, 0x81, 0x86, 0x7e,
4225
-	0xc4, 0x59, 0x28, 0xdd, 0xc2, 0xd9, 0x09, 0x75, 0x0d, 0x46, 0xa9, 0xe2, 0x09, 0xa3, 0xf2, 0x00,
4226
-	0x2e, 0x9f, 0xb1, 0x04, 0xba, 0x04, 0x79, 0x49, 0xc4, 0x80, 0x4a, 0xbd, 0xd3, 0x45, 0x6c, 0x66,
4227
-	0xc8, 0x85, 0x65, 0x12, 0x30, 0x12, 0xd3, 0xd8, 0x5d, 0xa8, 0x2d, 0xae, 0x15, 0xf1, 0x78, 0xba,
4228
-	0x91, 0x07, 0x7b, 0xc8, 0x7d, 0x5a, 0x5f, 0x87, 0x0b, 0xaf, 0xec, 0x00, 0xaa, 0x40, 0xc1, 0xec,
4229
-	0x40, 0x6a, 0x1d, 0x1b, 0x4f, 0xe6, 0xf5, 0xf3, 0xb0, 0x32, 0x57, 0xed, 0xfa, 0x6f, 0x0b, 0x50,
4230
-	0x18, 0x5b, 0x00, 0xb5, 0xa0, 0xe8, 0xf1, 0x50, 0x12, 0x16, 0x52, 0x61, 0x5c, 0x97, 0xb9, 0x61,
4231
-	0xed, 0x31, 0x48, 0xb1, 0xee, 0xe7, 0xf0, 0x94, 0x85, 0xbe, 0x84, 0xa2, 0xa0, 0x31, 0x4f, 0x84,
4232
-	0xa7, 0xb3, 0x56, 0x12, 0x6b, 0xd9, 0xc6, 0x49, 0x41, 0x98, 0x7e, 0x9b, 0x30, 0x41, 0x55, 0x35,
4233
-	0x62, 0x3c, 0xa5, 0xa2, 0x7b, 0xb0, 0x2c, 0x68, 0x2c, 0x89, 0x90, 0xaf, 0x73, 0x0e, 0x4e, 0x21,
4234
-	0x3d, 0x1e, 0x30, 0xef, 0x08, 0x8f, 0x19, 0xe8, 0x1e, 0x14, 0xa3, 0x80, 0x78, 0x5a, 0xd5, 0x5d,
4235
-	0xd2, 0xf4, 0xff, 0x66, 0xd1, 0x7b, 0x63, 0x10, 0x9e, 0xe2, 0xd1, 0x5d, 0x80, 0x80, 0x0f, 0xfa,
4236
-	0xbe, 0x60, 0x23, 0x2a, 0x8c, 0xf3, 0x2a, 0x59, 0xec, 0x8e, 0x46, 0xe0, 0x62, 0xc0, 0x07, 0xe9,
4237
-	0x70, 0xa3, 0x08, 0xcb, 0x22, 0x09, 0x25, 0x1b, 0xd2, 0xfa, 0xcf, 0x36, 0xac, 0xcc, 0x95, 0x09,
4238
-	0x5d, 0x84, 0x25, 0x36, 0x24, 0x03, 0x6a, 0x36, 0x39, 0x9d, 0xa0, 0x2e, 0xe4, 0x03, 0xb2, 0x47,
4239
-	0x83, 0x74, 0x8b, 0x9d, 0xe6, 0xfb, 0x6f, 0xac, 0x77, 0xe3, 0x6b, 0x8d, 0xef, 0x86, 0x52, 0x1c,
4240
-	0x61, 0x43, 0x56, 0x56, 0xf1, 0xf8, 0x70, 0x48, 0x42, 0x75, 0x5a, 0xb5, 0x55, 0xcc, 0x14, 0x21,
4241
-	0xb0, 0x89, 0x18, 0xc4, 0xae, 0xad, 0xc3, 0x7a, 0x8c, 0xca, 0xb0, 0x48, 0xc3, 0x91, 0xbb, 0xa4,
4242
-	0x43, 0x6a, 0xa8, 0x22, 0x3e, 0x4b, 0xbf, 0xb6, 0x88, 0xd5, 0x50, 0xf1, 0x92, 0x98, 0x0a, 0x77,
4243
-	0x59, 0x87, 0xf4, 0x18, 0xdd, 0x86, 0xfc, 0x90, 0x27, 0xa1, 0x8c, 0xdd, 0x82, 0x4e, 0xf6, 0x4a,
4244
-	0x56, 0xb2, 0xdb, 0x0a, 0x61, 0xba, 0x89, 0x81, 0xa3, 0xfb, 0x70, 0x21, 0x96, 0x3c, 0xea, 0x0f,
4245
-	0x04, 0xf1, 0x68, 0x3f, 0xa2, 0x82, 0x71, 0xdf, 0x2d, 0x9e, 0xdd, 0x94, 0x3a, 0xe6, 0xc2, 0xc4,
4246
-	0xe7, 0x15, 0x6d, 0x53, 0xb1, 0x7a, 0x9a, 0x84, 0x7a, 0x50, 0x8a, 0x92, 0x20, 0xe8, 0xf3, 0x28,
4247
-	0xed, 0x8d, 0xa0, 0x45, 0xfe, 0x45, 0xd5, 0x7a, 0x49, 0x10, 0x3c, 0x4c, 0x49, 0xd8, 0x89, 0xa6,
4248
-	0x13, 0x75, 0xfa, 0x06, 0x82, 0x27, 0x51, 0xec, 0x3a, 0xba, 0x1e, 0x66, 0x56, 0xb9, 0x0b, 0xce,
4249
-	0x4c, 0xa5, 0x55, 0x85, 0x0e, 0xe9, 0x91, 0xd9, 0x3c, 0x35, 0x54, 0x1b, 0x3a, 0x22, 0x41, 0x92,
4250
-	0xde, 0xb8, 0x45, 0x9c, 0x4e, 0x3e, 0x59, 0xb8, 0x63, 0x55, 0x9a, 0xe0, 0xcc, 0x2c, 0x87, 0xfe,
4251
-	0x07, 0x2b, 0x82, 0x0e, 0x58, 0x2c, 0xc5, 0x51, 0x9f, 0x24, 0xf2, 0xc0, 0xfd, 0x42, 0x13, 0x4a,
4252
-	0xe3, 0x60, 0x2b, 0x91, 0x07, 0xf5, 0xbf, 0x2c, 0x28, 0xcd, 0xb6, 0x0e, 0xd4, 0x4e, 0xcf, 0xb8,
4253
-	0x5e, 0xf1, 0x5c, 0x73, 0xfd, 0x4d, 0xad, 0x46, 0x9f, 0xa8, 0x20, 0x51, 0x2b, 0x6e, 0xab, 0x6b,
4254
-	0x5e, 0x93, 0xd1, 0xc7, 0xb0, 0x14, 0x71, 0x21, 0xc7, 0xee, 0xaa, 0x66, 0x9e, 0x02, 0x2e, 0xc6,
4255
-	0xcd, 0x2e, 0x05, 0xd7, 0x0f, 0xe0, 0xdc, 0xbc, 0x1a, 0xba, 0x01, 0x8b, 0x4f, 0xb6, 0x7a, 0xe5,
4256
-	0x5c, 0xe5, 0xea, 0xf1, 0x49, 0xed, 0xf2, 0xfc, 0x8f, 0x4f, 0x98, 0x90, 0x09, 0x09, 0xb6, 0x7a,
4257
-	0xe8, 0x3d, 0x58, 0xea, 0xec, 0xec, 0x62, 0x5c, 0xb6, 0x2a, 0xab, 0xc7, 0x27, 0xb5, 0xab, 0xf3,
4258
-	0x38, 0xf5, 0x13, 0x4f, 0x42, 0x1f, 0xf3, 0xbd, 0xc9, 0xcd, 0xf7, 0xc3, 0x02, 0x38, 0xa6, 0x2d,
4259
-	0xbe, 0xdd, 0x9b, 0xef, 0x73, 0x58, 0x49, 0x4f, 0x70, 0xdf, 0xd3, 0x9f, 0x66, 0x7a, 0xd1, 0xeb,
4260
-	0x0e, 0x72, 0x29, 0x25, 0x98, 0xa6, 0x7c, 0x1d, 0x4a, 0x2c, 0x1a, 0xdd, 0xea, 0xd3, 0x90, 0xec,
4261
-	0x05, 0xe6, 0x12, 0x2c, 0x60, 0x47, 0xc5, 0xba, 0x69, 0x48, 0x35, 0x5a, 0x16, 0x4a, 0x2a, 0x42,
4262
-	0x73, 0xbd, 0x15, 0xf0, 0x64, 0x8e, 0x3e, 0x03, 0x9b, 0x45, 0x64, 0x68, 0xba, 0x4f, 0xe6, 0x17,
4263
-	0x6c, 0xf5, 0x5a, 0xdb, 0xc6, 0x22, 0x1b, 0x85, 0xd3, 0x17, 0xab, 0xb6, 0x0a, 0x60, 0x4d, 0xab,
4264
-	0xff, 0x64, 0x83, 0xd3, 0x0e, 0x92, 0x58, 0x9a, 0xe6, 0xf1, 0xd6, 0xea, 0xf2, 0x0d, 0x5c, 0x20,
4265
-	0xfa, 0x1d, 0x44, 0x42, 0x75, 0x12, 0x75, 0xe3, 0x34, 0xb5, 0xb9, 0x91, 0x29, 0x37, 0x01, 0xa7,
4266
-	0x4d, 0x76, 0x23, 0xaf, 0x34, 0x5d, 0x0b, 0x97, 0xc9, 0x3f, 0x7e, 0x41, 0xbb, 0xb0, 0xc2, 0x85,
4267
-	0x77, 0x40, 0x63, 0x99, 0x1e, 0x5e, 0xf3, 0x6e, 0xc8, 0x7c, 0x51, 0x3e, 0x9c, 0x05, 0xa6, 0x15,
4268
-	0x37, 0xd9, 0xce, 0x6b, 0xa0, 0x3b, 0x60, 0x0b, 0xb2, 0x3f, 0xbe, 0x04, 0x32, 0xfd, 0x8b, 0xc9,
4269
-	0xbe, 0x9c, 0x93, 0xd0, 0x0c, 0xf4, 0x15, 0x80, 0xcf, 0xe2, 0x88, 0x48, 0xef, 0x80, 0x0a, 0xb3,
4270
-	0x0f, 0x99, 0x9f, 0xd8, 0x99, 0xa0, 0xe6, 0x54, 0x66, 0xd8, 0xe8, 0x01, 0x14, 0x3d, 0x32, 0x76,
4271
-	0x52, 0xfe, 0xec, 0xbe, 0xd5, 0x6e, 0x19, 0x89, 0xb2, 0x92, 0x38, 0x7d, 0xb1, 0x5a, 0x18, 0x47,
4272
-	0x70, 0xc1, 0x23, 0xc6, 0x59, 0x0f, 0x60, 0x45, 0x3d, 0xb2, 0xfa, 0x3e, 0xdd, 0x27, 0x49, 0x20,
4273
-	0x63, 0xdd, 0x62, 0xcf, 0x78, 0x4c, 0xa8, 0xab, 0xb9, 0x63, 0x70, 0x26, 0xaf, 0x92, 0x9c, 0x8d,
4274
-	0x5d, 0x7b, 0xfe, 0xb2, 0x9a, 0xfb, 0xfd, 0x65, 0x35, 0xf7, 0xe7, 0xcb, 0xaa, 0xf5, 0xdd, 0x69,
4275
-	0xd5, 0x7a, 0x7e, 0x5a, 0xb5, 0x7e, 0x3d, 0xad, 0x5a, 0x7f, 0x9c, 0x56, 0xad, 0xbd, 0xbc, 0xfe,
4276
-	0xc3, 0xf1, 0xd1, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa4, 0x46, 0x7c, 0xf6, 0xcf, 0x0c, 0x00,
4277
-	0x00,
4191
+	// 1397 bytes of a gzipped FileDescriptorProto
4192
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x57, 0x4f, 0x6f, 0xdb, 0xc6,
4193
+	0x12, 0x17, 0x6d, 0x5a, 0x96, 0x86, 0x72, 0xa2, 0x2c, 0xf2, 0x87, 0x51, 0xf2, 0x64, 0x45, 0x2f,
4194
+	0x2f, 0xcf, 0x79, 0x0f, 0xb5, 0x5b, 0xb5, 0x48, 0x93, 0xa6, 0x45, 0x2b, 0x4b, 0xaa, 0xa3, 0xba,
4195
+	0x76, 0x84, 0x75, 0x12, 0xa0, 0x27, 0x61, 0x4d, 0xae, 0x65, 0xc2, 0x14, 0x97, 0x5d, 0x2e, 0x15,
4196
+	0xf8, 0xd6, 0x63, 0xe0, 0x43, 0xbf, 0x81, 0x4f, 0x05, 0x7a, 0xec, 0xad, 0xdf, 0x21, 0xc7, 0x1e,
4197
+	0x7b, 0x32, 0x6a, 0x5f, 0x7b, 0x29, 0xd0, 0x2f, 0x50, 0xec, 0x72, 0x25, 0x51, 0x0d, 0x9d, 0x04,
4198
+	0x68, 0x6e, 0xbb, 0xc3, 0xdf, 0x6f, 0x76, 0x34, 0xf3, 0xdb, 0x99, 0x15, 0x58, 0x51, 0x48, 0x9d,
4199
+	0x68, 0x35, 0xe4, 0x4c, 0x30, 0x84, 0x5c, 0xe6, 0x1c, 0x50, 0xbe, 0x1a, 0x3d, 0x27, 0x7c, 0x78,
4200
+	0xe0, 0x89, 0xd5, 0xd1, 0x07, 0x15, 0x4b, 0x1c, 0x86, 0x54, 0x03, 0x2a, 0x97, 0x07, 0x6c, 0xc0,
4201
+	0xd4, 0x72, 0x4d, 0xae, 0xb4, 0xf5, 0x9a, 0x1b, 0x73, 0x22, 0x3c, 0x16, 0xac, 0x8d, 0x17, 0xc9,
4202
+	0x87, 0xfa, 0xf7, 0x26, 0x14, 0xb6, 0x99, 0x4b, 0x77, 0x42, 0xea, 0xa0, 0x0d, 0xb0, 0x48, 0x10,
4203
+	0x30, 0xa1, 0x00, 0x91, 0x6d, 0xd4, 0x8c, 0x15, 0xab, 0xb1, 0xbc, 0xfa, 0xea, 0x91, 0xab, 0xcd,
4204
+	0x29, 0x6c, 0xdd, 0x7c, 0x79, 0xb2, 0x9c, 0xc3, 0x69, 0x26, 0x7a, 0x1f, 0x4c, 0xce, 0x7c, 0x6a,
4205
+	0xcf, 0xd5, 0x8c, 0x95, 0x0b, 0x8d, 0x9b, 0x59, 0x1e, 0xe4, 0xa1, 0x98, 0xf9, 0x14, 0x2b, 0x24,
4206
+	0xda, 0x00, 0x18, 0xd2, 0xe1, 0x2e, 0xe5, 0xd1, 0xbe, 0x17, 0xda, 0xf3, 0x8a, 0xf7, 0xdf, 0xf3,
4207
+	0x78, 0x32, 0xd8, 0xd5, 0xad, 0x09, 0x1c, 0xa7, 0xa8, 0x68, 0x0b, 0x4a, 0x64, 0x44, 0x3c, 0x9f,
4208
+	0xec, 0x7a, 0xbe, 0x27, 0x0e, 0x6d, 0x53, 0xb9, 0xba, 0xfb, 0x5a, 0x57, 0xcd, 0x14, 0x01, 0xcf,
4209
+	0xd0, 0xeb, 0x2e, 0xc0, 0xf4, 0x20, 0x74, 0x07, 0x16, 0x7b, 0x9d, 0xed, 0x76, 0x77, 0x7b, 0xa3,
4210
+	0x9c, 0xab, 0x5c, 0x3f, 0x3a, 0xae, 0x5d, 0x91, 0x3e, 0xa6, 0x80, 0x1e, 0x0d, 0x5c, 0x2f, 0x18,
4211
+	0xa0, 0x15, 0x28, 0x34, 0x5b, 0xad, 0x4e, 0xef, 0x49, 0xa7, 0x5d, 0x36, 0x2a, 0x95, 0xa3, 0xe3,
4212
+	0xda, 0xd5, 0x59, 0x60, 0xd3, 0x71, 0x68, 0x28, 0xa8, 0x5b, 0x31, 0x5f, 0xfc, 0x50, 0xcd, 0xd5,
4213
+	0x5f, 0x18, 0x50, 0x4a, 0x07, 0x81, 0xee, 0x40, 0xbe, 0xd9, 0x7a, 0xd2, 0x7d, 0xd6, 0x29, 0xe7,
4214
+	0xa6, 0xf4, 0x34, 0xa2, 0xe9, 0x08, 0x6f, 0x44, 0xd1, 0x6d, 0x58, 0xe8, 0x35, 0x9f, 0xee, 0x74,
4215
+	0xca, 0xc6, 0x34, 0x9c, 0x34, 0xac, 0x47, 0xe2, 0x48, 0xa1, 0xda, 0xb8, 0xd9, 0xdd, 0x2e, 0xcf,
4216
+	0x65, 0xa3, 0xda, 0x9c, 0x78, 0x81, 0x0e, 0xe5, 0x74, 0x1e, 0xac, 0x1d, 0xca, 0x47, 0x9e, 0xf3,
4217
+	0x8e, 0x35, 0x71, 0x0f, 0x4c, 0x41, 0xa2, 0x03, 0xa5, 0x09, 0x2b, 0x5b, 0x13, 0x4f, 0x48, 0x74,
4218
+	0x20, 0x0f, 0xd5, 0x74, 0x85, 0x97, 0xca, 0xe0, 0x34, 0xf4, 0x3d, 0x87, 0x08, 0xea, 0x2a, 0x65,
4219
+	0x58, 0x8d, 0xff, 0x64, 0xb1, 0xf1, 0x04, 0xa5, 0xe3, 0x7f, 0x94, 0xc3, 0x29, 0x2a, 0x7a, 0x08,
4220
+	0xf9, 0x81, 0xcf, 0x76, 0x89, 0xaf, 0x34, 0x61, 0x35, 0x6e, 0x65, 0x39, 0xd9, 0x50, 0x88, 0xa9,
4221
+	0x03, 0x4d, 0x41, 0xf7, 0x21, 0x1f, 0x87, 0x2e, 0x11, 0xd4, 0xce, 0x2b, 0x72, 0x2d, 0x8b, 0xfc,
4222
+	0x54, 0x21, 0x5a, 0x2c, 0xd8, 0xf3, 0x06, 0x58, 0xe3, 0xd1, 0x26, 0x14, 0x02, 0x2a, 0x9e, 0x33,
4223
+	0x7e, 0x10, 0xd9, 0x8b, 0xb5, 0xf9, 0x15, 0xab, 0xf1, 0xff, 0x4c, 0x31, 0x26, 0x98, 0xa6, 0x10,
4224
+	0xc4, 0xd9, 0x1f, 0xd2, 0x40, 0x24, 0x6e, 0xd6, 0xe7, 0x6c, 0x03, 0x4f, 0x1c, 0xa0, 0x4f, 0xa1,
4225
+	0x40, 0x03, 0x37, 0x64, 0x5e, 0x20, 0xec, 0xc2, 0xf9, 0x81, 0x74, 0x34, 0x46, 0x26, 0x13, 0x4f,
4226
+	0x18, 0xeb, 0x79, 0x30, 0x87, 0xcc, 0xa5, 0xf5, 0x35, 0xb8, 0xf4, 0x4a, 0xb2, 0x50, 0x05, 0x0a,
4227
+	0x3a, 0x59, 0x49, 0x95, 0x4d, 0x3c, 0xd9, 0xd7, 0x2f, 0xc2, 0xd2, 0x4c, 0x62, 0xea, 0xbf, 0xcf,
4228
+	0x43, 0x61, 0x5c, 0x2d, 0xd4, 0x84, 0xa2, 0xc3, 0x02, 0x41, 0xbc, 0x80, 0x72, 0x2d, 0x90, 0xcc,
4229
+	0xdc, 0xb6, 0xc6, 0x20, 0xc9, 0x7a, 0x94, 0xc3, 0x53, 0x16, 0xfa, 0x12, 0x8a, 0x9c, 0x46, 0x2c,
4230
+	0xe6, 0x0e, 0x8d, 0xb4, 0x42, 0x56, 0xb2, 0x6b, 0x9c, 0x80, 0x30, 0xfd, 0x36, 0xf6, 0x38, 0x95,
4231
+	0x79, 0x8a, 0xf0, 0x94, 0x8a, 0x1e, 0xc2, 0x22, 0xa7, 0x91, 0x20, 0x5c, 0xbc, 0xae, 0xc8, 0x38,
4232
+	0x81, 0xf4, 0x98, 0xef, 0x39, 0x87, 0x78, 0xcc, 0x40, 0x0f, 0xa1, 0x18, 0xfa, 0xc4, 0x51, 0x5e,
4233
+	0xed, 0x05, 0x45, 0xff, 0x57, 0x16, 0xbd, 0x37, 0x06, 0xe1, 0x29, 0x1e, 0x3d, 0x00, 0xf0, 0xd9,
4234
+	0xa0, 0xef, 0x72, 0x6f, 0x44, 0xb9, 0x16, 0x49, 0x25, 0x8b, 0xdd, 0x56, 0x08, 0x5c, 0xf4, 0xd9,
4235
+	0x20, 0x59, 0xa2, 0x8d, 0x7f, 0xa4, 0x90, 0x94, 0x3a, 0x36, 0x01, 0xc8, 0xe4, 0xab, 0xd6, 0xc7,
4236
+	0xdd, 0xb7, 0x72, 0xa5, 0x2b, 0x92, 0xa2, 0xaf, 0x17, 0x61, 0x91, 0xc7, 0x81, 0xf0, 0x86, 0xb4,
4237
+	0xbe, 0x09, 0x57, 0x32, 0x19, 0xa8, 0x01, 0xa5, 0x49, 0x0d, 0xfb, 0x9e, 0xab, 0x8a, 0x5f, 0x5c,
4238
+	0xbf, 0x78, 0x76, 0xb2, 0x6c, 0x4d, 0x8a, 0xdd, 0x6d, 0x63, 0x6b, 0x02, 0xea, 0xba, 0xf5, 0x9f,
4239
+	0x4c, 0x58, 0x9a, 0x51, 0x02, 0xba, 0x0c, 0x0b, 0xde, 0x90, 0x0c, 0x68, 0x42, 0xc7, 0xc9, 0x06,
4240
+	0x75, 0x20, 0xef, 0x93, 0x5d, 0xea, 0x4b, 0x3d, 0xc8, 0x9c, 0xbc, 0xf7, 0x46, 0x49, 0xad, 0x7e,
4241
+	0xad, 0xf0, 0x9d, 0x40, 0xf0, 0x43, 0xac, 0xc9, 0xc8, 0x86, 0x45, 0x87, 0x0d, 0x87, 0x24, 0x90,
4242
+	0xbd, 0x63, 0x7e, 0xa5, 0x88, 0xc7, 0x5b, 0x84, 0xc0, 0x24, 0x7c, 0x10, 0xd9, 0xa6, 0x32, 0xab,
4243
+	0x35, 0x2a, 0xc3, 0x3c, 0x0d, 0x46, 0xf6, 0x82, 0x32, 0xc9, 0xa5, 0xb4, 0xb8, 0x5e, 0x52, 0xd0,
4244
+	0x22, 0x96, 0x4b, 0xc9, 0x8b, 0x23, 0xca, 0xed, 0x45, 0x65, 0x52, 0x6b, 0xf4, 0x31, 0xe4, 0x87,
4245
+	0x2c, 0x0e, 0x44, 0x64, 0x17, 0x54, 0xb0, 0xd7, 0xb3, 0x82, 0xdd, 0x92, 0x08, 0xdd, 0xdb, 0x34,
4246
+	0x1c, 0x3d, 0x82, 0x4b, 0x91, 0x60, 0x61, 0x7f, 0xc0, 0x89, 0x43, 0xfb, 0x21, 0xe5, 0x1e, 0x73,
4247
+	0xed, 0xe2, 0xf9, 0x2d, 0xb2, 0xad, 0xc7, 0x37, 0xbe, 0x28, 0x69, 0x1b, 0x92, 0xd5, 0x53, 0x24,
4248
+	0xd4, 0x83, 0x52, 0x18, 0xfb, 0x7e, 0x9f, 0x85, 0x49, 0xa7, 0x06, 0xe5, 0xe4, 0x2d, 0xb2, 0xd6,
4249
+	0x8b, 0x7d, 0xff, 0x71, 0x42, 0xc2, 0x56, 0x38, 0xdd, 0xa0, 0xab, 0x90, 0x1f, 0x70, 0x16, 0x87,
4250
+	0x91, 0x6d, 0xa9, 0x7c, 0xe8, 0x5d, 0xe5, 0x01, 0x58, 0xa9, 0x4c, 0xcb, 0x0c, 0x1d, 0xd0, 0x43,
4251
+	0x5d, 0x3c, 0xb9, 0x94, 0x05, 0x1d, 0x11, 0x3f, 0x4e, 0xe6, 0x7f, 0x11, 0x27, 0x9b, 0x4f, 0xe6,
4252
+	0xee, 0x1b, 0x95, 0x06, 0x58, 0xa9, 0xe3, 0xd0, 0xbf, 0x61, 0x89, 0xd3, 0x81, 0x17, 0x09, 0x7e,
4253
+	0xd8, 0x27, 0xb1, 0xd8, 0xb7, 0xbf, 0x50, 0x84, 0xd2, 0xd8, 0xd8, 0x8c, 0xc5, 0x7e, 0xfd, 0x4f,
4254
+	0x03, 0x4a, 0xe9, 0x86, 0x86, 0x5a, 0x49, 0x1b, 0x53, 0x27, 0x5e, 0x68, 0xac, 0xbd, 0xa9, 0x01,
4255
+	0xaa, 0xa6, 0xe1, 0xc7, 0xf2, 0xc4, 0x2d, 0xf9, 0xe8, 0x50, 0x64, 0xf4, 0x11, 0x2c, 0x84, 0x8c,
4256
+	0x8b, 0xb1, 0xba, 0xaa, 0x99, 0x17, 0x9d, 0xf1, 0xf1, 0x25, 0x4b, 0xc0, 0xf5, 0x7d, 0xb8, 0x30,
4257
+	0xeb, 0x0d, 0xdd, 0x86, 0xf9, 0x67, 0xdd, 0x5e, 0x39, 0x57, 0xb9, 0x71, 0x74, 0x5c, 0xbb, 0x36,
4258
+	0xfb, 0xf1, 0x99, 0xc7, 0x45, 0x4c, 0xfc, 0x6e, 0x0f, 0xfd, 0x0f, 0x16, 0xda, 0xdb, 0x3b, 0x18,
4259
+	0x97, 0x8d, 0xca, 0xf2, 0xd1, 0x71, 0xed, 0xc6, 0x2c, 0x4e, 0x7e, 0x62, 0x71, 0xe0, 0x62, 0xb6,
4260
+	0x3b, 0x99, 0xc3, 0x3f, 0xcf, 0x81, 0xa5, 0x2f, 0xdd, 0xbb, 0x9d, 0xc3, 0x9f, 0xc3, 0x52, 0xd2,
4261
+	0xa4, 0xfa, 0x8e, 0xfa, 0x69, 0xba, 0xdd, 0xbe, 0xae, 0x57, 0x95, 0x12, 0x42, 0x92, 0x0a, 0x74,
4262
+	0x0b, 0x4a, 0x5e, 0x38, 0xba, 0xd7, 0xa7, 0x01, 0xd9, 0xf5, 0xf5, 0x48, 0x2e, 0x60, 0x4b, 0xda,
4263
+	0x3a, 0x89, 0x49, 0xce, 0x12, 0x2f, 0x10, 0x94, 0x07, 0x7a, 0xd8, 0x16, 0xf0, 0x64, 0x8f, 0x3e,
4264
+	0x03, 0xd3, 0x0b, 0xc9, 0x50, 0x37, 0xd8, 0xcc, 0x5f, 0xd0, 0xed, 0x35, 0xb7, 0xb4, 0x44, 0xd6,
4265
+	0x0b, 0x67, 0x27, 0xcb, 0xa6, 0x34, 0x60, 0x45, 0x43, 0xd5, 0x71, 0x8f, 0x93, 0x27, 0xa9, 0x6b,
4266
+	0x59, 0xc0, 0x29, 0x4b, 0xfd, 0x47, 0x13, 0xac, 0x96, 0x1f, 0x47, 0x42, 0x37, 0x97, 0x77, 0x96,
4267
+	0xb7, 0x6f, 0xe0, 0x12, 0x51, 0xaf, 0x36, 0x12, 0xc8, 0x9b, 0xaa, 0x66, 0x87, 0xce, 0xdd, 0xed,
4268
+	0x4c, 0x77, 0x13, 0x70, 0x32, 0x67, 0xd6, 0xf3, 0xd2, 0xa7, 0x6d, 0xe0, 0x32, 0xf9, 0xdb, 0x17,
4269
+	0xb4, 0x03, 0x4b, 0x8c, 0x3b, 0xfb, 0x34, 0x12, 0xc9, 0xe5, 0xd6, 0xaf, 0x9c, 0xcc, 0xf7, 0xef,
4270
+	0xe3, 0x34, 0x50, 0xbf, 0x11, 0x92, 0x68, 0x67, 0x7d, 0xa0, 0xfb, 0x60, 0x72, 0xb2, 0x37, 0x9e,
4271
+	0x83, 0x99, 0xfa, 0xc6, 0x64, 0x4f, 0xcc, 0xb8, 0x50, 0x0c, 0xf4, 0x15, 0x80, 0xeb, 0x45, 0x21,
4272
+	0x11, 0xce, 0x3e, 0xe5, 0xba, 0x4e, 0x99, 0x3f, 0xb1, 0x3d, 0x41, 0xcd, 0x78, 0x49, 0xb1, 0xd1,
4273
+	0x26, 0x14, 0x1d, 0x32, 0x56, 0x5a, 0xfe, 0xfc, 0xbe, 0xd6, 0x6a, 0x6a, 0x17, 0x65, 0xe9, 0xe2,
4274
+	0xec, 0x64, 0xb9, 0x30, 0xb6, 0xe0, 0x82, 0x43, 0xb4, 0xf2, 0x36, 0x61, 0x49, 0x3e, 0x09, 0xfb,
4275
+	0x2e, 0xdd, 0x23, 0xb1, 0x2f, 0x22, 0xd5, 0x82, 0xcf, 0x79, 0x02, 0xc9, 0xd7, 0x49, 0x5b, 0xe3,
4276
+	0x74, 0x5c, 0x25, 0x91, 0xb6, 0xdd, 0x7c, 0x79, 0x5a, 0xcd, 0xfd, 0x7a, 0x5a, 0xcd, 0xfd, 0x71,
4277
+	0x5a, 0x35, 0xbe, 0x3b, 0xab, 0x1a, 0x2f, 0xcf, 0xaa, 0xc6, 0x2f, 0x67, 0x55, 0xe3, 0xb7, 0xb3,
4278
+	0xaa, 0xb1, 0x9b, 0x57, 0x7f, 0x8f, 0x3e, 0xfc, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x70, 0x4c, 0x36,
4279
+	0xfc, 0x7d, 0x0d, 0x00, 0x00,
4278 4280
 }
... ...
@@ -72,19 +72,7 @@ message ServiceSpec {
72 72
 	// UpdateConfig controls the rate and policy of updates.
73 73
 	UpdateConfig update = 6;
74 74
 
75
-	// NetworkAttachmentConfig specifies how a service should be attached to a particular network.
76
-	//
77
-	// For now, this is a simple struct, but this can include future information
78
-	// instructing Swarm on how this service should work on the particular
79
-	// network.
80
-	message NetworkAttachmentConfig {
81
-		// Target specifies the target network for attachment. This value may be a
82
-		// network name or identifier. Only identifiers are supported at this time.
83
-		string target = 1;
84
-		// Aliases specifies a list of discoverable alternate names for the service on this Target.
85
-		repeated string aliases = 2;
86
-	}
87
-	repeated NetworkAttachmentConfig networks = 7;
75
+	repeated NetworkAttachmentConfig networks = 7 [deprecated=true];
88 76
 
89 77
 	// Service endpoint specifies the user provided configuration
90 78
 	// to properly discover and load balance a service.
... ...
@@ -103,6 +91,7 @@ message GlobalService {
103 103
 
104 104
 message TaskSpec {
105 105
 	oneof runtime {
106
+		NetworkAttachmentSpec attachment = 8;
106 107
 		ContainerSpec container = 1;
107 108
 	}
108 109
 
... ...
@@ -118,6 +107,19 @@ message TaskSpec {
118 118
 	// LogDriver specifies the log driver to use for the task. Any runtime will
119 119
 	// direct logs into the specified driver for the duration of the task.
120 120
 	Driver log_driver = 6;
121
+
122
+	// Networks specifies the list of network attachment
123
+	// configurations (which specify the network and per-network
124
+	// aliases) that this task spec is bound to.
125
+	repeated NetworkAttachmentConfig networks = 7;
126
+}
127
+
128
+// NetworkAttachmentSpec specifies runtime parameters required to attach
129
+// a container to a network.
130
+message NetworkAttachmentSpec {
131
+	// ContainerID spcifies a unique ID of the container for which
132
+	// this attachment is for.
133
+	string container_id = 1 [(gogoproto.customname) = "ContainerID"];
121 134
 }
122 135
 
123 136
 // Container specifies runtime parameters for a container.
... ...
@@ -234,6 +236,15 @@ message NetworkSpec {
234 234
 	bool internal = 4;
235 235
 
236 236
 	IPAMOptions ipam = 5 [(gogoproto.customname) = "IPAM"];
237
+
238
+	// Attachable allows external(to swarm) entities to manually
239
+	// attach to this network. With this flag enabled, external
240
+	// entities such as containers running in an worker node in
241
+	// the cluster can manually attach to this network and access
242
+	// the services attached to this network. If this flag is not
243
+	// enabled(default case) no manual attachment to this network
244
+	// can happen.
245
+	bool attachable = 6;
237 246
 }
238 247
 
239 248
 // ClusterSpec specifies global cluster settings.
... ...
@@ -15,6 +15,7 @@
15 15
 		snapshot.proto
16 16
 		raft.proto
17 17
 		health.proto
18
+		resource.proto
18 19
 
19 20
 	It has these top-level messages:
20 21
 		Version
... ...
@@ -34,6 +35,7 @@
34 34
 		UpdateStatus
35 35
 		ContainerStatus
36 36
 		TaskStatus
37
+		NetworkAttachmentConfig
37 38
 		IPAMConfig
38 39
 		PortConfig
39 40
 		Driver
... ...
@@ -59,6 +61,7 @@
59 59
 		ReplicatedService
60 60
 		GlobalService
61 61
 		TaskSpec
62
+		NetworkAttachmentSpec
62 63
 		ContainerSpec
63 64
 		EndpointSpec
64 65
 		NetworkSpec
... ...
@@ -140,6 +143,10 @@
140 140
 		StoreAction
141 141
 		HealthCheckRequest
142 142
 		HealthCheckResponse
143
+		AttachNetworkRequest
144
+		AttachNetworkResponse
145
+		DetachNetworkRequest
146
+		DetachNetworkResponse
143 147
 */
144 148
 package api
145 149
 
... ...
@@ -473,7 +480,7 @@ func (x IPAMConfig_AddressFamily) String() string {
473 473
 	return proto.EnumName(IPAMConfig_AddressFamily_name, int32(x))
474 474
 }
475 475
 func (IPAMConfig_AddressFamily) EnumDescriptor() ([]byte, []int) {
476
-	return fileDescriptorTypes, []int{17, 0}
476
+	return fileDescriptorTypes, []int{18, 0}
477 477
 }
478 478
 
479 479
 type PortConfig_Protocol int32
... ...
@@ -495,7 +502,7 @@ var PortConfig_Protocol_value = map[string]int32{
495 495
 func (x PortConfig_Protocol) String() string {
496 496
 	return proto.EnumName(PortConfig_Protocol_name, int32(x))
497 497
 }
498
-func (PortConfig_Protocol) EnumDescriptor() ([]byte, []int) { return fileDescriptorTypes, []int{18, 0} }
498
+func (PortConfig_Protocol) EnumDescriptor() ([]byte, []int) { return fileDescriptorTypes, []int{19, 0} }
499 499
 
500 500
 type IssuanceStatus_State int32
501 501
 
... ...
@@ -525,7 +532,7 @@ var IssuanceStatus_State_value = map[string]int32{
525 525
 func (x IssuanceStatus_State) String() string {
526 526
 	return proto.EnumName(IssuanceStatus_State_name, int32(x))
527 527
 }
528
-func (IssuanceStatus_State) EnumDescriptor() ([]byte, []int) { return fileDescriptorTypes, []int{23, 0} }
528
+func (IssuanceStatus_State) EnumDescriptor() ([]byte, []int) { return fileDescriptorTypes, []int{24, 0} }
529 529
 
530 530
 type ExternalCA_CAProtocol int32
531 531
 
... ...
@@ -544,7 +551,7 @@ func (x ExternalCA_CAProtocol) String() string {
544 544
 	return proto.EnumName(ExternalCA_CAProtocol_name, int32(x))
545 545
 }
546 546
 func (ExternalCA_CAProtocol) EnumDescriptor() ([]byte, []int) {
547
-	return fileDescriptorTypes, []int{25, 0}
547
+	return fileDescriptorTypes, []int{26, 0}
548 548
 }
549 549
 
550 550
 // Encryption algorithm that can implemented using this key
... ...
@@ -565,7 +572,7 @@ func (x EncryptionKey_Algorithm) String() string {
565 565
 	return proto.EnumName(EncryptionKey_Algorithm_name, int32(x))
566 566
 }
567 567
 func (EncryptionKey_Algorithm) EnumDescriptor() ([]byte, []int) {
568
-	return fileDescriptorTypes, []int{35, 0}
568
+	return fileDescriptorTypes, []int{36, 0}
569 569
 }
570 570
 
571 571
 // Version tracks the last time an object in the store was updated.
... ...
@@ -952,6 +959,27 @@ func _TaskStatus_OneofSizer(msg proto.Message) (n int) {
952 952
 	return n
953 953
 }
954 954
 
955
+// NetworkAttachmentConfig specifies how a service should be attached to a particular network.
956
+//
957
+// For now, this is a simple struct, but this can include future information
958
+// instructing Swarm on how this service should work on the particular
959
+// network.
960
+type NetworkAttachmentConfig struct {
961
+	// Target specifies the target network for attachment. This value may be a
962
+	// network name or identifier. Only identifiers are supported at this time.
963
+	Target string `protobuf:"bytes,1,opt,name=target,proto3" json:"target,omitempty"`
964
+	// Aliases specifies a list of discoverable alternate names for the service on this Target.
965
+	Aliases []string `protobuf:"bytes,2,rep,name=aliases" json:"aliases,omitempty"`
966
+	// Addresses specifies a list of ipv4 and ipv6 addresses
967
+	// preferred. If these addresses are not available then the
968
+	// attachment might fail.
969
+	Addresses []string `protobuf:"bytes,3,rep,name=addresses" json:"addresses,omitempty"`
970
+}
971
+
972
+func (m *NetworkAttachmentConfig) Reset()                    { *m = NetworkAttachmentConfig{} }
973
+func (*NetworkAttachmentConfig) ProtoMessage()               {}
974
+func (*NetworkAttachmentConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{17} }
975
+
955 976
 // IPAMConfig specifies parameters for IP Address Management.
956 977
 type IPAMConfig struct {
957 978
 	Family IPAMConfig_AddressFamily `protobuf:"varint,1,opt,name=family,proto3,enum=docker.swarmkit.v1.IPAMConfig_AddressFamily" json:"family,omitempty"`
... ...
@@ -971,7 +999,7 @@ type IPAMConfig struct {
971 971
 
972 972
 func (m *IPAMConfig) Reset()                    { *m = IPAMConfig{} }
973 973
 func (*IPAMConfig) ProtoMessage()               {}
974
-func (*IPAMConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{17} }
974
+func (*IPAMConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{18} }
975 975
 
976 976
 // PortConfig specifies an exposed port which can be
977 977
 // addressed using the given name. This can be later queried
... ...
@@ -996,7 +1024,7 @@ type PortConfig struct {
996 996
 
997 997
 func (m *PortConfig) Reset()                    { *m = PortConfig{} }
998 998
 func (*PortConfig) ProtoMessage()               {}
999
-func (*PortConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{18} }
999
+func (*PortConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{19} }
1000 1000
 
1001 1001
 // Driver is a generic driver type to be used throughout the API. For now, a
1002 1002
 // driver is simply a name and set of options. The field contents depend on the
... ...
@@ -1009,7 +1037,7 @@ type Driver struct {
1009 1009
 
1010 1010
 func (m *Driver) Reset()                    { *m = Driver{} }
1011 1011
 func (*Driver) ProtoMessage()               {}
1012
-func (*Driver) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{19} }
1012
+func (*Driver) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{20} }
1013 1013
 
1014 1014
 type IPAMOptions struct {
1015 1015
 	Driver  *Driver       `protobuf:"bytes,1,opt,name=driver" json:"driver,omitempty"`
... ...
@@ -1018,7 +1046,7 @@ type IPAMOptions struct {
1018 1018
 
1019 1019
 func (m *IPAMOptions) Reset()                    { *m = IPAMOptions{} }
1020 1020
 func (*IPAMOptions) ProtoMessage()               {}
1021
-func (*IPAMOptions) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{20} }
1021
+func (*IPAMOptions) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{21} }
1022 1022
 
1023 1023
 // Peer should be used anywhere where we are describing a remote peer.
1024 1024
 type Peer struct {
... ...
@@ -1028,7 +1056,7 @@ type Peer struct {
1028 1028
 
1029 1029
 func (m *Peer) Reset()                    { *m = Peer{} }
1030 1030
 func (*Peer) ProtoMessage()               {}
1031
-func (*Peer) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{21} }
1031
+func (*Peer) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{22} }
1032 1032
 
1033 1033
 // WeightedPeer should be used anywhere where we are describing a remote peer
1034 1034
 // with a weight.
... ...
@@ -1039,7 +1067,7 @@ type WeightedPeer struct {
1039 1039
 
1040 1040
 func (m *WeightedPeer) Reset()                    { *m = WeightedPeer{} }
1041 1041
 func (*WeightedPeer) ProtoMessage()               {}
1042
-func (*WeightedPeer) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{22} }
1042
+func (*WeightedPeer) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{23} }
1043 1043
 
1044 1044
 type IssuanceStatus struct {
1045 1045
 	State IssuanceStatus_State `protobuf:"varint,1,opt,name=state,proto3,enum=docker.swarmkit.v1.IssuanceStatus_State" json:"state,omitempty"`
... ...
@@ -1051,7 +1079,7 @@ type IssuanceStatus struct {
1051 1051
 
1052 1052
 func (m *IssuanceStatus) Reset()                    { *m = IssuanceStatus{} }
1053 1053
 func (*IssuanceStatus) ProtoMessage()               {}
1054
-func (*IssuanceStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{23} }
1054
+func (*IssuanceStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{24} }
1055 1055
 
1056 1056
 type AcceptancePolicy struct {
1057 1057
 	Policies []*AcceptancePolicy_RoleAdmissionPolicy `protobuf:"bytes,1,rep,name=policies" json:"policies,omitempty"`
... ...
@@ -1059,7 +1087,7 @@ type AcceptancePolicy struct {
1059 1059
 
1060 1060
 func (m *AcceptancePolicy) Reset()                    { *m = AcceptancePolicy{} }
1061 1061
 func (*AcceptancePolicy) ProtoMessage()               {}
1062
-func (*AcceptancePolicy) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{24} }
1062
+func (*AcceptancePolicy) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{25} }
1063 1063
 
1064 1064
 type AcceptancePolicy_RoleAdmissionPolicy struct {
1065 1065
 	Role NodeRole `protobuf:"varint,1,opt,name=role,proto3,enum=docker.swarmkit.v1.NodeRole" json:"role,omitempty"`
... ...
@@ -1074,7 +1102,7 @@ type AcceptancePolicy_RoleAdmissionPolicy struct {
1074 1074
 func (m *AcceptancePolicy_RoleAdmissionPolicy) Reset()      { *m = AcceptancePolicy_RoleAdmissionPolicy{} }
1075 1075
 func (*AcceptancePolicy_RoleAdmissionPolicy) ProtoMessage() {}
1076 1076
 func (*AcceptancePolicy_RoleAdmissionPolicy) Descriptor() ([]byte, []int) {
1077
-	return fileDescriptorTypes, []int{24, 0}
1077
+	return fileDescriptorTypes, []int{25, 0}
1078 1078
 }
1079 1079
 
1080 1080
 type AcceptancePolicy_RoleAdmissionPolicy_Secret struct {
... ...
@@ -1089,7 +1117,7 @@ func (m *AcceptancePolicy_RoleAdmissionPolicy_Secret) Reset() {
1089 1089
 }
1090 1090
 func (*AcceptancePolicy_RoleAdmissionPolicy_Secret) ProtoMessage() {}
1091 1091
 func (*AcceptancePolicy_RoleAdmissionPolicy_Secret) Descriptor() ([]byte, []int) {
1092
-	return fileDescriptorTypes, []int{24, 0, 0}
1092
+	return fileDescriptorTypes, []int{25, 0, 0}
1093 1093
 }
1094 1094
 
1095 1095
 type ExternalCA struct {
... ...
@@ -1104,7 +1132,7 @@ type ExternalCA struct {
1104 1104
 
1105 1105
 func (m *ExternalCA) Reset()                    { *m = ExternalCA{} }
1106 1106
 func (*ExternalCA) ProtoMessage()               {}
1107
-func (*ExternalCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{25} }
1107
+func (*ExternalCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{26} }
1108 1108
 
1109 1109
 type CAConfig struct {
1110 1110
 	// NodeCertExpiry is the duration certificates should be issued for
... ...
@@ -1116,7 +1144,7 @@ type CAConfig struct {
1116 1116
 
1117 1117
 func (m *CAConfig) Reset()                    { *m = CAConfig{} }
1118 1118
 func (*CAConfig) ProtoMessage()               {}
1119
-func (*CAConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{26} }
1119
+func (*CAConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{27} }
1120 1120
 
1121 1121
 // OrchestrationConfig defines cluster-level orchestration settings.
1122 1122
 type OrchestrationConfig struct {
... ...
@@ -1127,7 +1155,7 @@ type OrchestrationConfig struct {
1127 1127
 
1128 1128
 func (m *OrchestrationConfig) Reset()                    { *m = OrchestrationConfig{} }
1129 1129
 func (*OrchestrationConfig) ProtoMessage()               {}
1130
-func (*OrchestrationConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{27} }
1130
+func (*OrchestrationConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{28} }
1131 1131
 
1132 1132
 // TaskDefaults specifies default values for task creation.
1133 1133
 type TaskDefaults struct {
... ...
@@ -1141,7 +1169,7 @@ type TaskDefaults struct {
1141 1141
 
1142 1142
 func (m *TaskDefaults) Reset()                    { *m = TaskDefaults{} }
1143 1143
 func (*TaskDefaults) ProtoMessage()               {}
1144
-func (*TaskDefaults) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{28} }
1144
+func (*TaskDefaults) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{29} }
1145 1145
 
1146 1146
 // DispatcherConfig defines cluster-level dispatcher settings.
1147 1147
 type DispatcherConfig struct {
... ...
@@ -1152,7 +1180,7 @@ type DispatcherConfig struct {
1152 1152
 
1153 1153
 func (m *DispatcherConfig) Reset()                    { *m = DispatcherConfig{} }
1154 1154
 func (*DispatcherConfig) ProtoMessage()               {}
1155
-func (*DispatcherConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{29} }
1155
+func (*DispatcherConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{30} }
1156 1156
 
1157 1157
 // RaftConfig defines raft settings for the cluster.
1158 1158
 type RaftConfig struct {
... ...
@@ -1174,7 +1202,7 @@ type RaftConfig struct {
1174 1174
 
1175 1175
 func (m *RaftConfig) Reset()                    { *m = RaftConfig{} }
1176 1176
 func (*RaftConfig) ProtoMessage()               {}
1177
-func (*RaftConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{30} }
1177
+func (*RaftConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{31} }
1178 1178
 
1179 1179
 // Placement specifies task distribution constraints.
1180 1180
 type Placement struct {
... ...
@@ -1184,7 +1212,7 @@ type Placement struct {
1184 1184
 
1185 1185
 func (m *Placement) Reset()                    { *m = Placement{} }
1186 1186
 func (*Placement) ProtoMessage()               {}
1187
-func (*Placement) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{31} }
1187
+func (*Placement) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{32} }
1188 1188
 
1189 1189
 // JoinToken contains the join tokens for workers and managers.
1190 1190
 type JoinTokens struct {
... ...
@@ -1196,7 +1224,7 @@ type JoinTokens struct {
1196 1196
 
1197 1197
 func (m *JoinTokens) Reset()                    { *m = JoinTokens{} }
1198 1198
 func (*JoinTokens) ProtoMessage()               {}
1199
-func (*JoinTokens) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{32} }
1199
+func (*JoinTokens) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{33} }
1200 1200
 
1201 1201
 type RootCA struct {
1202 1202
 	// CAKey is the root CA private key.
... ...
@@ -1211,7 +1239,7 @@ type RootCA struct {
1211 1211
 
1212 1212
 func (m *RootCA) Reset()                    { *m = RootCA{} }
1213 1213
 func (*RootCA) ProtoMessage()               {}
1214
-func (*RootCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{33} }
1214
+func (*RootCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{34} }
1215 1215
 
1216 1216
 type Certificate struct {
1217 1217
 	Role        NodeRole       `protobuf:"varint,1,opt,name=role,proto3,enum=docker.swarmkit.v1.NodeRole" json:"role,omitempty"`
... ...
@@ -1224,7 +1252,7 @@ type Certificate struct {
1224 1224
 
1225 1225
 func (m *Certificate) Reset()                    { *m = Certificate{} }
1226 1226
 func (*Certificate) ProtoMessage()               {}
1227
-func (*Certificate) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{34} }
1227
+func (*Certificate) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{35} }
1228 1228
 
1229 1229
 // Symmetric keys to encrypt inter-agent communication.
1230 1230
 type EncryptionKey struct {
... ...
@@ -1240,7 +1268,7 @@ type EncryptionKey struct {
1240 1240
 
1241 1241
 func (m *EncryptionKey) Reset()                    { *m = EncryptionKey{} }
1242 1242
 func (*EncryptionKey) ProtoMessage()               {}
1243
-func (*EncryptionKey) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{35} }
1243
+func (*EncryptionKey) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{36} }
1244 1244
 
1245 1245
 // ManagerStatus provides informations about the state of a manager in the cluster.
1246 1246
 type ManagerStatus struct {
... ...
@@ -1257,7 +1285,7 @@ type ManagerStatus struct {
1257 1257
 
1258 1258
 func (m *ManagerStatus) Reset()                    { *m = ManagerStatus{} }
1259 1259
 func (*ManagerStatus) ProtoMessage()               {}
1260
-func (*ManagerStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{36} }
1260
+func (*ManagerStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{37} }
1261 1261
 
1262 1262
 func init() {
1263 1263
 	proto.RegisterType((*Version)(nil), "docker.swarmkit.v1.Version")
... ...
@@ -1280,6 +1308,7 @@ func init() {
1280 1280
 	proto.RegisterType((*UpdateStatus)(nil), "docker.swarmkit.v1.UpdateStatus")
1281 1281
 	proto.RegisterType((*ContainerStatus)(nil), "docker.swarmkit.v1.ContainerStatus")
1282 1282
 	proto.RegisterType((*TaskStatus)(nil), "docker.swarmkit.v1.TaskStatus")
1283
+	proto.RegisterType((*NetworkAttachmentConfig)(nil), "docker.swarmkit.v1.NetworkAttachmentConfig")
1283 1284
 	proto.RegisterType((*IPAMConfig)(nil), "docker.swarmkit.v1.IPAMConfig")
1284 1285
 	proto.RegisterType((*PortConfig)(nil), "docker.swarmkit.v1.PortConfig")
1285 1286
 	proto.RegisterType((*Driver)(nil), "docker.swarmkit.v1.Driver")
... ...
@@ -1626,6 +1655,32 @@ func (m *TaskStatus) Copy() *TaskStatus {
1626 1626
 	return o
1627 1627
 }
1628 1628
 
1629
+func (m *NetworkAttachmentConfig) Copy() *NetworkAttachmentConfig {
1630
+	if m == nil {
1631
+		return nil
1632
+	}
1633
+
1634
+	o := &NetworkAttachmentConfig{
1635
+		Target: m.Target,
1636
+	}
1637
+
1638
+	if m.Aliases != nil {
1639
+		o.Aliases = make([]string, 0, len(m.Aliases))
1640
+		for _, v := range m.Aliases {
1641
+			o.Aliases = append(o.Aliases, v)
1642
+		}
1643
+	}
1644
+
1645
+	if m.Addresses != nil {
1646
+		o.Addresses = make([]string, 0, len(m.Addresses))
1647
+		for _, v := range m.Addresses {
1648
+			o.Addresses = append(o.Addresses, v)
1649
+		}
1650
+	}
1651
+
1652
+	return o
1653
+}
1654
+
1629 1655
 func (m *IPAMConfig) Copy() *IPAMConfig {
1630 1656
 	if m == nil {
1631 1657
 		return nil
... ...
@@ -2278,6 +2333,18 @@ func (this *TaskStatus_Container) GoString() string {
2278 2278
 		`Container:` + fmt.Sprintf("%#v", this.Container) + `}`}, ", ")
2279 2279
 	return s
2280 2280
 }
2281
+func (this *NetworkAttachmentConfig) GoString() string {
2282
+	if this == nil {
2283
+		return "nil"
2284
+	}
2285
+	s := make([]string, 0, 7)
2286
+	s = append(s, "&api.NetworkAttachmentConfig{")
2287
+	s = append(s, "Target: "+fmt.Sprintf("%#v", this.Target)+",\n")
2288
+	s = append(s, "Aliases: "+fmt.Sprintf("%#v", this.Aliases)+",\n")
2289
+	s = append(s, "Addresses: "+fmt.Sprintf("%#v", this.Addresses)+",\n")
2290
+	s = append(s, "}")
2291
+	return strings.Join(s, "")
2292
+}
2281 2293
 func (this *IPAMConfig) GoString() string {
2282 2294
 	if this == nil {
2283 2295
 		return "nil"
... ...
@@ -3416,6 +3483,60 @@ func (m *TaskStatus_Container) MarshalTo(data []byte) (int, error) {
3416 3416
 	}
3417 3417
 	return i, nil
3418 3418
 }
3419
+func (m *NetworkAttachmentConfig) Marshal() (data []byte, err error) {
3420
+	size := m.Size()
3421
+	data = make([]byte, size)
3422
+	n, err := m.MarshalTo(data)
3423
+	if err != nil {
3424
+		return nil, err
3425
+	}
3426
+	return data[:n], nil
3427
+}
3428
+
3429
+func (m *NetworkAttachmentConfig) MarshalTo(data []byte) (int, error) {
3430
+	var i int
3431
+	_ = i
3432
+	var l int
3433
+	_ = l
3434
+	if len(m.Target) > 0 {
3435
+		data[i] = 0xa
3436
+		i++
3437
+		i = encodeVarintTypes(data, i, uint64(len(m.Target)))
3438
+		i += copy(data[i:], m.Target)
3439
+	}
3440
+	if len(m.Aliases) > 0 {
3441
+		for _, s := range m.Aliases {
3442
+			data[i] = 0x12
3443
+			i++
3444
+			l = len(s)
3445
+			for l >= 1<<7 {
3446
+				data[i] = uint8(uint64(l)&0x7f | 0x80)
3447
+				l >>= 7
3448
+				i++
3449
+			}
3450
+			data[i] = uint8(l)
3451
+			i++
3452
+			i += copy(data[i:], s)
3453
+		}
3454
+	}
3455
+	if len(m.Addresses) > 0 {
3456
+		for _, s := range m.Addresses {
3457
+			data[i] = 0x1a
3458
+			i++
3459
+			l = len(s)
3460
+			for l >= 1<<7 {
3461
+				data[i] = uint8(uint64(l)&0x7f | 0x80)
3462
+				l >>= 7
3463
+				i++
3464
+			}
3465
+			data[i] = uint8(l)
3466
+			i++
3467
+			i += copy(data[i:], s)
3468
+		}
3469
+	}
3470
+	return i, nil
3471
+}
3472
+
3419 3473
 func (m *IPAMConfig) Marshal() (data []byte, err error) {
3420 3474
 	size := m.Size()
3421 3475
 	data = make([]byte, size)
... ...
@@ -4609,6 +4730,28 @@ func (m *TaskStatus_Container) Size() (n int) {
4609 4609
 	}
4610 4610
 	return n
4611 4611
 }
4612
+func (m *NetworkAttachmentConfig) Size() (n int) {
4613
+	var l int
4614
+	_ = l
4615
+	l = len(m.Target)
4616
+	if l > 0 {
4617
+		n += 1 + l + sovTypes(uint64(l))
4618
+	}
4619
+	if len(m.Aliases) > 0 {
4620
+		for _, s := range m.Aliases {
4621
+			l = len(s)
4622
+			n += 1 + l + sovTypes(uint64(l))
4623
+		}
4624
+	}
4625
+	if len(m.Addresses) > 0 {
4626
+		for _, s := range m.Addresses {
4627
+			l = len(s)
4628
+			n += 1 + l + sovTypes(uint64(l))
4629
+		}
4630
+	}
4631
+	return n
4632
+}
4633
+
4612 4634
 func (m *IPAMConfig) Size() (n int) {
4613 4635
 	var l int
4614 4636
 	_ = l
... ...
@@ -5257,6 +5400,18 @@ func (this *TaskStatus_Container) String() string {
5257 5257
 	}, "")
5258 5258
 	return s
5259 5259
 }
5260
+func (this *NetworkAttachmentConfig) String() string {
5261
+	if this == nil {
5262
+		return "nil"
5263
+	}
5264
+	s := strings.Join([]string{`&NetworkAttachmentConfig{`,
5265
+		`Target:` + fmt.Sprintf("%v", this.Target) + `,`,
5266
+		`Aliases:` + fmt.Sprintf("%v", this.Aliases) + `,`,
5267
+		`Addresses:` + fmt.Sprintf("%v", this.Addresses) + `,`,
5268
+		`}`,
5269
+	}, "")
5270
+	return s
5271
+}
5260 5272
 func (this *IPAMConfig) String() string {
5261 5273
 	if this == nil {
5262 5274
 		return "nil"
... ...
@@ -8286,6 +8441,143 @@ func (m *TaskStatus) Unmarshal(data []byte) error {
8286 8286
 	}
8287 8287
 	return nil
8288 8288
 }
8289
+func (m *NetworkAttachmentConfig) Unmarshal(data []byte) error {
8290
+	l := len(data)
8291
+	iNdEx := 0
8292
+	for iNdEx < l {
8293
+		preIndex := iNdEx
8294
+		var wire uint64
8295
+		for shift := uint(0); ; shift += 7 {
8296
+			if shift >= 64 {
8297
+				return ErrIntOverflowTypes
8298
+			}
8299
+			if iNdEx >= l {
8300
+				return io.ErrUnexpectedEOF
8301
+			}
8302
+			b := data[iNdEx]
8303
+			iNdEx++
8304
+			wire |= (uint64(b) & 0x7F) << shift
8305
+			if b < 0x80 {
8306
+				break
8307
+			}
8308
+		}
8309
+		fieldNum := int32(wire >> 3)
8310
+		wireType := int(wire & 0x7)
8311
+		if wireType == 4 {
8312
+			return fmt.Errorf("proto: NetworkAttachmentConfig: wiretype end group for non-group")
8313
+		}
8314
+		if fieldNum <= 0 {
8315
+			return fmt.Errorf("proto: NetworkAttachmentConfig: illegal tag %d (wire type %d)", fieldNum, wire)
8316
+		}
8317
+		switch fieldNum {
8318
+		case 1:
8319
+			if wireType != 2 {
8320
+				return fmt.Errorf("proto: wrong wireType = %d for field Target", wireType)
8321
+			}
8322
+			var stringLen uint64
8323
+			for shift := uint(0); ; shift += 7 {
8324
+				if shift >= 64 {
8325
+					return ErrIntOverflowTypes
8326
+				}
8327
+				if iNdEx >= l {
8328
+					return io.ErrUnexpectedEOF
8329
+				}
8330
+				b := data[iNdEx]
8331
+				iNdEx++
8332
+				stringLen |= (uint64(b) & 0x7F) << shift
8333
+				if b < 0x80 {
8334
+					break
8335
+				}
8336
+			}
8337
+			intStringLen := int(stringLen)
8338
+			if intStringLen < 0 {
8339
+				return ErrInvalidLengthTypes
8340
+			}
8341
+			postIndex := iNdEx + intStringLen
8342
+			if postIndex > l {
8343
+				return io.ErrUnexpectedEOF
8344
+			}
8345
+			m.Target = string(data[iNdEx:postIndex])
8346
+			iNdEx = postIndex
8347
+		case 2:
8348
+			if wireType != 2 {
8349
+				return fmt.Errorf("proto: wrong wireType = %d for field Aliases", wireType)
8350
+			}
8351
+			var stringLen uint64
8352
+			for shift := uint(0); ; shift += 7 {
8353
+				if shift >= 64 {
8354
+					return ErrIntOverflowTypes
8355
+				}
8356
+				if iNdEx >= l {
8357
+					return io.ErrUnexpectedEOF
8358
+				}
8359
+				b := data[iNdEx]
8360
+				iNdEx++
8361
+				stringLen |= (uint64(b) & 0x7F) << shift
8362
+				if b < 0x80 {
8363
+					break
8364
+				}
8365
+			}
8366
+			intStringLen := int(stringLen)
8367
+			if intStringLen < 0 {
8368
+				return ErrInvalidLengthTypes
8369
+			}
8370
+			postIndex := iNdEx + intStringLen
8371
+			if postIndex > l {
8372
+				return io.ErrUnexpectedEOF
8373
+			}
8374
+			m.Aliases = append(m.Aliases, string(data[iNdEx:postIndex]))
8375
+			iNdEx = postIndex
8376
+		case 3:
8377
+			if wireType != 2 {
8378
+				return fmt.Errorf("proto: wrong wireType = %d for field Addresses", wireType)
8379
+			}
8380
+			var stringLen uint64
8381
+			for shift := uint(0); ; shift += 7 {
8382
+				if shift >= 64 {
8383
+					return ErrIntOverflowTypes
8384
+				}
8385
+				if iNdEx >= l {
8386
+					return io.ErrUnexpectedEOF
8387
+				}
8388
+				b := data[iNdEx]
8389
+				iNdEx++
8390
+				stringLen |= (uint64(b) & 0x7F) << shift
8391
+				if b < 0x80 {
8392
+					break
8393
+				}
8394
+			}
8395
+			intStringLen := int(stringLen)
8396
+			if intStringLen < 0 {
8397
+				return ErrInvalidLengthTypes
8398
+			}
8399
+			postIndex := iNdEx + intStringLen
8400
+			if postIndex > l {
8401
+				return io.ErrUnexpectedEOF
8402
+			}
8403
+			m.Addresses = append(m.Addresses, string(data[iNdEx:postIndex]))
8404
+			iNdEx = postIndex
8405
+		default:
8406
+			iNdEx = preIndex
8407
+			skippy, err := skipTypes(data[iNdEx:])
8408
+			if err != nil {
8409
+				return err
8410
+			}
8411
+			if skippy < 0 {
8412
+				return ErrInvalidLengthTypes
8413
+			}
8414
+			if (iNdEx + skippy) > l {
8415
+				return io.ErrUnexpectedEOF
8416
+			}
8417
+			iNdEx += skippy
8418
+		}
8419
+	}
8420
+
8421
+	if iNdEx > l {
8422
+		return io.ErrUnexpectedEOF
8423
+	}
8424
+	return nil
8425
+}
8289 8426
 func (m *IPAMConfig) Unmarshal(data []byte) error {
8290 8427
 	l := len(data)
8291 8428
 	iNdEx := 0
... ...
@@ -11256,218 +11548,221 @@ var (
11256 11256
 )
11257 11257
 
11258 11258
 var fileDescriptorTypes = []byte{
11259
-	// 3398 bytes of a gzipped FileDescriptorProto
11259
+	// 3442 bytes of a gzipped FileDescriptorProto
11260 11260
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x59, 0x4d, 0x6c, 0x1b, 0x49,
11261 11261
 	0x76, 0x16, 0x7f, 0x45, 0x3e, 0x52, 0x72, 0xbb, 0xec, 0xf5, 0xc8, 0x1c, 0x8f, 0xc4, 0x69, 0x8f,
11262 11262
 	0x77, 0xbc, 0xb3, 0x13, 0xce, 0x8c, 0x66, 0x13, 0x78, 0xc7, 0xc9, 0xce, 0xb4, 0x48, 0xca, 0xe6,
11263
-	0x5a, 0xa2, 0x88, 0xa2, 0x68, 0x63, 0x10, 0x20, 0x44, 0xa9, 0xbb, 0x44, 0xf5, 0xa8, 0xd9, 0xc5,
11263
+	0x5a, 0xa2, 0x88, 0x22, 0x69, 0x63, 0x10, 0x20, 0x44, 0xa9, 0xbb, 0x44, 0xf6, 0xa8, 0xd9, 0xc5,
11264 11264
 	0x74, 0x17, 0x25, 0x33, 0x41, 0x00, 0x27, 0x97, 0x04, 0x3a, 0xe5, 0x1e, 0x08, 0x8b, 0x20, 0x41,
11265 11265
 	0x6e, 0x39, 0xe4, 0x14, 0x20, 0x27, 0x1f, 0xe7, 0xb8, 0x41, 0x80, 0x60, 0x91, 0x00, 0x42, 0x46,
11266
-	0x39, 0xe6, 0xb2, 0x40, 0x0e, 0x7b, 0x48, 0x0e, 0x41, 0xfd, 0x74, 0xb3, 0x49, 0xd3, 0x1a, 0x4f,
11267
-	0x76, 0x4f, 0xec, 0x7a, 0xf5, 0xbd, 0x57, 0xef, 0x55, 0xbd, 0x7a, 0xf5, 0x55, 0x11, 0x4a, 0x7c,
11268
-	0x32, 0xa2, 0x61, 0x6d, 0x14, 0x30, 0xce, 0x10, 0x72, 0x98, 0x7d, 0x4c, 0x83, 0x5a, 0x78, 0x4a,
11269
-	0x82, 0xe1, 0xb1, 0xcb, 0x6b, 0x27, 0x9f, 0x54, 0x6e, 0x73, 0x77, 0x48, 0x43, 0x4e, 0x86, 0xa3,
11270
-	0x8f, 0xe2, 0x2f, 0x05, 0xaf, 0xbc, 0xe5, 0x8c, 0x03, 0xc2, 0x5d, 0xe6, 0x7f, 0x14, 0x7d, 0xe8,
11271
-	0x8e, 0x9b, 0x03, 0x36, 0x60, 0xf2, 0xf3, 0x23, 0xf1, 0xa5, 0xa4, 0xe6, 0x06, 0x2c, 0x3f, 0xa5,
11272
-	0x41, 0xe8, 0x32, 0x1f, 0xdd, 0x84, 0x9c, 0xeb, 0x3b, 0xf4, 0xf9, 0x5a, 0xaa, 0x9a, 0xba, 0x9f,
11273
-	0xc5, 0xaa, 0x61, 0xfe, 0x75, 0x0a, 0x4a, 0x96, 0xef, 0x33, 0x2e, 0x6d, 0x85, 0x08, 0x41, 0xd6,
11274
-	0x27, 0x43, 0x2a, 0x41, 0x45, 0x2c, 0xbf, 0x51, 0x1d, 0xf2, 0x1e, 0x39, 0xa0, 0x5e, 0xb8, 0x96,
11275
-	0xae, 0x66, 0xee, 0x97, 0x36, 0x7f, 0x58, 0x7b, 0xd5, 0xe7, 0x5a, 0xc2, 0x48, 0x6d, 0x47, 0xa2,
11276
-	0x9b, 0x3e, 0x0f, 0x26, 0x58, 0xab, 0x56, 0x7e, 0x0c, 0xa5, 0x84, 0x18, 0x19, 0x90, 0x39, 0xa6,
11277
-	0x13, 0x3d, 0x8c, 0xf8, 0x14, 0xfe, 0x9d, 0x10, 0x6f, 0x4c, 0xd7, 0xd2, 0x52, 0xa6, 0x1a, 0x9f,
11278
-	0xa5, 0x1f, 0xa4, 0xcc, 0x2f, 0xa1, 0x88, 0x69, 0xc8, 0xc6, 0x81, 0x4d, 0x43, 0xf4, 0x03, 0x28,
11279
-	0xfa, 0xc4, 0x67, 0x7d, 0x7b, 0x34, 0x0e, 0xa5, 0x7a, 0x66, 0xab, 0x7c, 0x79, 0xb1, 0x51, 0x68,
11280
-	0x13, 0x9f, 0xd5, 0x3b, 0xbd, 0x10, 0x17, 0x44, 0x77, 0x7d, 0x34, 0x0e, 0xd1, 0xbb, 0x50, 0x1e,
11281
-	0xd2, 0x21, 0x0b, 0x26, 0xfd, 0x83, 0x09, 0xa7, 0xa1, 0x34, 0x9c, 0xc1, 0x25, 0x25, 0xdb, 0x12,
11282
-	0x22, 0xf3, 0x2f, 0x53, 0x70, 0x33, 0xb2, 0x8d, 0xe9, 0x1f, 0x8e, 0xdd, 0x80, 0x0e, 0xa9, 0xcf,
11283
-	0x43, 0xf4, 0xdb, 0x90, 0xf7, 0xdc, 0xa1, 0xcb, 0xd5, 0x18, 0xa5, 0xcd, 0x77, 0x16, 0xc5, 0x1c,
11284
-	0x7b, 0x85, 0x35, 0x18, 0x59, 0x50, 0x0e, 0x68, 0x48, 0x83, 0x13, 0x35, 0x13, 0x72, 0xc8, 0x6f,
11285
-	0x55, 0x9e, 0x51, 0x31, 0xb7, 0xa1, 0xd0, 0xf1, 0x08, 0x3f, 0x64, 0xc1, 0x10, 0x99, 0x50, 0x26,
11286
-	0x81, 0x7d, 0xe4, 0x72, 0x6a, 0xf3, 0x71, 0x10, 0xad, 0xca, 0x8c, 0x0c, 0xdd, 0x82, 0x34, 0x53,
11287
-	0x03, 0x15, 0xb7, 0xf2, 0x97, 0x17, 0x1b, 0xe9, 0xbd, 0x2e, 0x4e, 0xb3, 0xd0, 0x7c, 0x08, 0xd7,
11288
-	0x3b, 0xde, 0x78, 0xe0, 0xfa, 0x0d, 0x1a, 0xda, 0x81, 0x3b, 0x12, 0xd6, 0xc5, 0xf2, 0x8a, 0xe4,
11289
-	0x8b, 0x96, 0x57, 0x7c, 0xc7, 0x4b, 0x9e, 0x9e, 0x2e, 0xb9, 0xf9, 0xe7, 0x69, 0xb8, 0xde, 0xf4,
11290
-	0x07, 0xae, 0x4f, 0x93, 0xda, 0xf7, 0x60, 0x95, 0x4a, 0x61, 0xff, 0x44, 0x25, 0x95, 0xb6, 0xb3,
11291
-	0xa2, 0xa4, 0x51, 0xa6, 0xb5, 0xe6, 0xf2, 0xe5, 0x93, 0x45, 0xe1, 0xbf, 0x62, 0x7d, 0x51, 0xd6,
11292
-	0xa0, 0x26, 0x2c, 0x8f, 0x64, 0x10, 0xe1, 0x5a, 0x46, 0xda, 0xba, 0xb7, 0xc8, 0xd6, 0x2b, 0x71,
11293
-	0x6e, 0x65, 0xbf, 0xbe, 0xd8, 0x58, 0xc2, 0x91, 0xee, 0xaf, 0x93, 0x7c, 0xff, 0x99, 0x82, 0x6b,
11294
-	0x6d, 0xe6, 0xcc, 0xcc, 0x43, 0x05, 0x0a, 0x47, 0x2c, 0xe4, 0x89, 0x8d, 0x12, 0xb7, 0xd1, 0x03,
11295
-	0x28, 0x8c, 0xf4, 0xf2, 0xe9, 0xd5, 0xbf, 0xb3, 0xd8, 0x65, 0x85, 0xc1, 0x31, 0x1a, 0x3d, 0x84,
11296
-	0x62, 0x10, 0xe5, 0xc4, 0x5a, 0xe6, 0x4d, 0x12, 0x67, 0x8a, 0x47, 0xbf, 0x07, 0x79, 0xb5, 0x08,
11297
-	0x6b, 0x59, 0xa9, 0x79, 0xef, 0x8d, 0xe6, 0x1c, 0x6b, 0x25, 0xf3, 0x17, 0x29, 0x30, 0x30, 0x39,
11298
-	0xe4, 0xbb, 0x74, 0x78, 0x40, 0x83, 0x2e, 0x27, 0x7c, 0x1c, 0xa2, 0x5b, 0x90, 0xf7, 0x28, 0x71,
11299
-	0x68, 0x20, 0x83, 0x2c, 0x60, 0xdd, 0x42, 0x3d, 0x91, 0xe4, 0xc4, 0x3e, 0x22, 0x07, 0xae, 0xe7,
11300
-	0xf2, 0x89, 0x0c, 0x73, 0x75, 0xf1, 0x2a, 0xcf, 0xdb, 0xac, 0xe1, 0x84, 0x22, 0x9e, 0x31, 0x83,
11301
-	0xd6, 0x60, 0x79, 0x48, 0xc3, 0x90, 0x0c, 0xa8, 0x8c, 0xbe, 0x88, 0xa3, 0xa6, 0xf9, 0x10, 0xca,
11302
-	0x49, 0x3d, 0x54, 0x82, 0xe5, 0x5e, 0xfb, 0x49, 0x7b, 0xef, 0x59, 0xdb, 0x58, 0x42, 0xd7, 0xa0,
11303
-	0xd4, 0x6b, 0xe3, 0xa6, 0x55, 0x7f, 0x6c, 0x6d, 0xed, 0x34, 0x8d, 0x14, 0x5a, 0x81, 0xe2, 0xb4,
11304
-	0x99, 0x36, 0x7f, 0x96, 0x02, 0x10, 0x0b, 0xa8, 0x83, 0xfa, 0x0c, 0x72, 0x21, 0x27, 0x5c, 0x2d,
11305
-	0xdc, 0xea, 0xe6, 0x7b, 0x8b, 0xbc, 0x9e, 0xc2, 0x6b, 0xe2, 0x87, 0x62, 0xa5, 0x92, 0xf4, 0x30,
11306
-	0x3d, 0xef, 0x61, 0x4e, 0x22, 0x67, 0x5d, 0x2b, 0x40, 0xb6, 0x21, 0xbe, 0x52, 0xa8, 0x08, 0x39,
11307
-	0xdc, 0xb4, 0x1a, 0x5f, 0x1a, 0x69, 0x64, 0x40, 0xb9, 0xd1, 0xea, 0xd6, 0xf7, 0xda, 0xed, 0x66,
11308
-	0x7d, 0xbf, 0xd9, 0x30, 0x32, 0xe6, 0x3d, 0xc8, 0xb5, 0x86, 0x64, 0x40, 0xd1, 0x1d, 0x91, 0x01,
11309
-	0x87, 0x34, 0xa0, 0xbe, 0x1d, 0x25, 0xd6, 0x54, 0x60, 0xfe, 0xbc, 0x08, 0xb9, 0x5d, 0x36, 0xf6,
11310
-	0x39, 0xda, 0x4c, 0xec, 0xe2, 0xd5, 0xcd, 0xf5, 0x45, 0x21, 0x48, 0x60, 0x6d, 0x7f, 0x32, 0xa2,
11311
-	0x7a, 0x97, 0xdf, 0x82, 0xbc, 0xca, 0x15, 0xed, 0xba, 0x6e, 0x09, 0x39, 0x27, 0xc1, 0x80, 0x72,
11312
-	0x3d, 0xe9, 0xba, 0x85, 0xee, 0x43, 0x21, 0xa0, 0xc4, 0x61, 0xbe, 0x37, 0x91, 0x29, 0x55, 0x50,
11313
-	0x65, 0x16, 0x53, 0xe2, 0xec, 0xf9, 0xde, 0x04, 0xc7, 0xbd, 0xe8, 0x31, 0x94, 0x0f, 0x5c, 0xdf,
11314
-	0xe9, 0xb3, 0x91, 0xaa, 0x79, 0xb9, 0xd7, 0x27, 0xa0, 0xf2, 0x6a, 0xcb, 0xf5, 0x9d, 0x3d, 0x05,
11315
-	0xc6, 0xa5, 0x83, 0x69, 0x03, 0xb5, 0x61, 0xf5, 0x84, 0x79, 0xe3, 0x21, 0x8d, 0x6d, 0xe5, 0xa5,
11316
-	0xad, 0xf7, 0x5f, 0x6f, 0xeb, 0xa9, 0xc4, 0x47, 0xd6, 0x56, 0x4e, 0x92, 0x4d, 0xf4, 0x04, 0x56,
11317
-	0xf8, 0x70, 0x74, 0x18, 0xc6, 0xe6, 0x96, 0xa5, 0xb9, 0xef, 0x5f, 0x31, 0x61, 0x02, 0x1e, 0x59,
11318
-	0x2b, 0xf3, 0x44, 0xab, 0xf2, 0x67, 0x19, 0x28, 0x25, 0x3c, 0x47, 0x5d, 0x28, 0x8d, 0x02, 0x36,
11319
-	0x22, 0x03, 0x59, 0xb7, 0xf5, 0x5a, 0x7c, 0xf2, 0x46, 0x51, 0xd7, 0x3a, 0x53, 0x45, 0x9c, 0xb4,
11320
-	0x62, 0x9e, 0xa7, 0xa1, 0x94, 0xe8, 0x44, 0x1f, 0x40, 0x01, 0x77, 0x70, 0xeb, 0xa9, 0xb5, 0xdf,
11321
-	0x34, 0x96, 0x2a, 0x77, 0xce, 0xce, 0xab, 0x6b, 0xd2, 0x5a, 0xd2, 0x40, 0x27, 0x70, 0x4f, 0x44,
11322
-	0xea, 0xdd, 0x87, 0xe5, 0x08, 0x9a, 0xaa, 0xbc, 0x7d, 0x76, 0x5e, 0x7d, 0x6b, 0x1e, 0x9a, 0x40,
11323
-	0xe2, 0xee, 0x63, 0x0b, 0x37, 0x1b, 0x46, 0x7a, 0x31, 0x12, 0x77, 0x8f, 0x48, 0x40, 0x1d, 0xf4,
11324
-	0x7d, 0xc8, 0x6b, 0x60, 0xa6, 0x52, 0x39, 0x3b, 0xaf, 0xde, 0x9a, 0x07, 0x4e, 0x71, 0xb8, 0xbb,
11325
-	0x63, 0x3d, 0x6d, 0x1a, 0xd9, 0xc5, 0x38, 0xdc, 0xf5, 0xc8, 0x09, 0x45, 0xef, 0x41, 0x4e, 0xc1,
11326
-	0x72, 0x95, 0xdb, 0x67, 0xe7, 0xd5, 0xef, 0xbd, 0x62, 0x4e, 0xa0, 0x2a, 0x6b, 0x7f, 0xf1, 0x37,
11327
-	0xeb, 0x4b, 0xff, 0xf4, 0xb7, 0xeb, 0xc6, 0x7c, 0x77, 0xe5, 0x7f, 0x53, 0xb0, 0x32, 0xb3, 0xe4,
11328
-	0xc8, 0x84, 0xbc, 0xcf, 0x6c, 0x36, 0x52, 0xe5, 0xbc, 0xb0, 0x05, 0x97, 0x17, 0x1b, 0xf9, 0x36,
11329
-	0xab, 0xb3, 0xd1, 0x04, 0xeb, 0x1e, 0xf4, 0x64, 0xee, 0x40, 0xfa, 0xf4, 0x0d, 0xf3, 0x69, 0xe1,
11330
-	0x91, 0xf4, 0x39, 0xac, 0x38, 0x81, 0x7b, 0x42, 0x83, 0xbe, 0xcd, 0xfc, 0x43, 0x77, 0xa0, 0x4b,
11331
-	0x75, 0x65, 0x91, 0xcd, 0x86, 0x04, 0xe2, 0xb2, 0x52, 0xa8, 0x4b, 0xfc, 0xaf, 0x71, 0x18, 0x55,
11332
-	0x9e, 0x42, 0x39, 0x99, 0xa1, 0xe8, 0x1d, 0x80, 0xd0, 0xfd, 0x23, 0xaa, 0xf9, 0x8d, 0x64, 0x43,
11333
-	0xb8, 0x28, 0x24, 0x92, 0xdd, 0xa0, 0xf7, 0x21, 0x3b, 0x64, 0x8e, 0xb2, 0x93, 0xdb, 0xba, 0x21,
11334
-	0xce, 0xc4, 0x7f, 0xbb, 0xd8, 0x28, 0xb1, 0xb0, 0xb6, 0xed, 0x7a, 0x74, 0x97, 0x39, 0x14, 0x4b,
11335
-	0x80, 0x79, 0x02, 0x59, 0x51, 0x2a, 0xd0, 0xdb, 0x90, 0xdd, 0x6a, 0xb5, 0x1b, 0xc6, 0x52, 0xe5,
11336
-	0xfa, 0xd9, 0x79, 0x75, 0x45, 0x4e, 0x89, 0xe8, 0x10, 0xb9, 0x8b, 0x36, 0x20, 0xff, 0x74, 0x6f,
11337
-	0xa7, 0xb7, 0x2b, 0xd2, 0xeb, 0xc6, 0xd9, 0x79, 0xf5, 0x5a, 0xdc, 0xad, 0x26, 0x0d, 0xbd, 0x03,
11338
-	0xb9, 0xfd, 0xdd, 0xce, 0x76, 0xd7, 0x48, 0x57, 0xd0, 0xd9, 0x79, 0x75, 0x35, 0xee, 0x97, 0x3e,
11339
-	0x57, 0xae, 0xeb, 0x55, 0x2d, 0xc6, 0x72, 0xf3, 0x7f, 0xd2, 0xb0, 0x82, 0x05, 0xbf, 0x0d, 0x78,
11340
-	0x87, 0x79, 0xae, 0x3d, 0x41, 0x1d, 0x28, 0xda, 0xcc, 0x77, 0xdc, 0xc4, 0x9e, 0xda, 0x7c, 0xcd,
11341
-	0x21, 0x38, 0xd5, 0x8a, 0x5a, 0xf5, 0x48, 0x13, 0x4f, 0x8d, 0xa0, 0x4d, 0xc8, 0x39, 0xd4, 0x23,
11342
-	0x93, 0xab, 0x4e, 0xe3, 0x86, 0xe6, 0xd2, 0x58, 0x41, 0x25, 0x73, 0x24, 0xcf, 0xfb, 0x84, 0x73,
11343
-	0x3a, 0x1c, 0x71, 0x75, 0x1a, 0x67, 0x71, 0x69, 0x48, 0x9e, 0x5b, 0x5a, 0x84, 0x7e, 0x04, 0xf9,
11344
-	0x53, 0xd7, 0x77, 0xd8, 0xa9, 0x3e, 0x70, 0xaf, 0xb6, 0xab, 0xb1, 0xe6, 0x99, 0x38, 0x67, 0xe7,
11345
-	0x9c, 0x15, 0xb3, 0xde, 0xde, 0x6b, 0x37, 0xa3, 0x59, 0xd7, 0xfd, 0x7b, 0x7e, 0x9b, 0xf9, 0x62,
11346
-	0xc7, 0xc0, 0x5e, 0xbb, 0xbf, 0x6d, 0xb5, 0x76, 0x7a, 0x58, 0xcc, 0xfc, 0xcd, 0xb3, 0xf3, 0xaa,
11347
-	0x11, 0x43, 0xb6, 0x89, 0xeb, 0x09, 0x12, 0x78, 0x1b, 0x32, 0x56, 0xfb, 0x4b, 0x23, 0x5d, 0x31,
11348
-	0xce, 0xce, 0xab, 0xe5, 0xb8, 0xdb, 0xf2, 0x27, 0xd3, 0xcd, 0x34, 0x3f, 0xae, 0xf9, 0x5f, 0x29,
11349
-	0x28, 0xf7, 0x46, 0x0e, 0xe1, 0x54, 0x65, 0x26, 0xaa, 0x42, 0x69, 0x44, 0x02, 0xe2, 0x79, 0xd4,
11350
-	0x73, 0xc3, 0xa1, 0xbe, 0x28, 0x24, 0x45, 0xe8, 0xc1, 0x77, 0x98, 0x4c, 0x4d, 0xc2, 0xf4, 0x94,
11351
-	0xf6, 0x60, 0xf5, 0x50, 0x39, 0xdb, 0x27, 0xb6, 0x5c, 0xdd, 0x8c, 0x5c, 0xdd, 0xda, 0x22, 0x13,
11352
-	0x49, 0xaf, 0x6a, 0x3a, 0x46, 0x4b, 0x6a, 0xe1, 0x95, 0xc3, 0x64, 0xd3, 0xbc, 0x0f, 0x2b, 0x33,
11353
-	0xfd, 0xe2, 0xa4, 0xed, 0x58, 0xbd, 0x6e, 0xd3, 0x58, 0x42, 0x65, 0x28, 0xd4, 0xf7, 0xda, 0xfb,
11354
-	0xad, 0x76, 0xaf, 0x69, 0xa4, 0xcc, 0x7f, 0x48, 0x47, 0xd1, 0x6a, 0x26, 0xb0, 0x35, 0xcb, 0x04,
11355
-	0x3e, 0x7c, 0xbd, 0x23, 0x9a, 0x0b, 0x4c, 0x1b, 0x31, 0x23, 0xf8, 0x5d, 0x00, 0x39, 0xa9, 0xd4,
11356
-	0xe9, 0x13, 0x7e, 0x15, 0xdb, 0xdf, 0x8f, 0xee, 0x71, 0xb8, 0xa8, 0x15, 0x2c, 0x8e, 0xbe, 0x80,
11357
-	0xb2, 0xcd, 0x86, 0x23, 0x8f, 0x6a, 0xfd, 0xcc, 0x9b, 0xe8, 0x97, 0x62, 0x15, 0x8b, 0x27, 0x19,
11358
-	0x49, 0x76, 0x96, 0x91, 0xd4, 0xa1, 0x94, 0xf0, 0x77, 0x96, 0x97, 0x94, 0xa1, 0xd0, 0xeb, 0x34,
11359
-	0xac, 0xfd, 0x56, 0xfb, 0x91, 0x91, 0x42, 0x00, 0x79, 0x39, 0x63, 0x0d, 0x23, 0x2d, 0xb8, 0x53,
11360
-	0x7d, 0x6f, 0xb7, 0xb3, 0xd3, 0x54, 0xcc, 0xe4, 0x4f, 0xe0, 0x5a, 0x9d, 0xf9, 0x9c, 0xb8, 0x7e,
11361
-	0x4c, 0x0a, 0x37, 0x85, 0xcf, 0x5a, 0xd4, 0x77, 0x1d, 0x55, 0xb7, 0xb6, 0xae, 0x5d, 0x5e, 0x6c,
11362
-	0x94, 0x62, 0x68, 0xab, 0x21, 0xbc, 0x8c, 0x1a, 0x8e, 0xc8, 0xce, 0x91, 0xeb, 0xe8, 0x32, 0xb4,
11363
-	0x7c, 0x79, 0xb1, 0x91, 0xe9, 0xb4, 0x1a, 0x58, 0xc8, 0xd0, 0xdb, 0x50, 0xa4, 0xcf, 0x5d, 0xde,
11364
-	0xb7, 0x45, 0x9d, 0x12, 0xf1, 0xe7, 0x70, 0x41, 0x08, 0xea, 0xa2, 0x2c, 0xfd, 0x69, 0x1a, 0x60,
11365
-	0x9f, 0x84, 0xc7, 0x7a, 0xe8, 0x87, 0x50, 0x8c, 0xaf, 0xc3, 0x57, 0x5d, 0xcb, 0x12, 0x73, 0x1d,
11366
-	0xe3, 0xd1, 0xa7, 0xd1, 0x6a, 0x2b, 0xb6, 0xba, 0x58, 0x51, 0x8f, 0xb5, 0x88, 0xf0, 0xcd, 0x52,
11367
-	0x52, 0x51, 0xb5, 0x69, 0x10, 0xe8, 0x49, 0x17, 0x9f, 0xa8, 0x2e, 0x2b, 0x97, 0x8a, 0x59, 0x73,
11368
-	0xa0, 0xbb, 0x8b, 0x06, 0x99, 0x9b, 0xd0, 0xc7, 0x4b, 0x78, 0xaa, 0xb7, 0x65, 0xc0, 0x6a, 0x30,
11369
-	0xf6, 0x85, 0xd7, 0xfd, 0x50, 0x76, 0x9b, 0xff, 0x92, 0x06, 0x68, 0x75, 0xac, 0x5d, 0xbd, 0x45,
11370
-	0x1b, 0x90, 0x3f, 0x24, 0x43, 0xd7, 0x9b, 0x5c, 0x95, 0xb5, 0x53, 0x7c, 0xcd, 0x72, 0x9c, 0x80,
11371
-	0x86, 0xe1, 0xb6, 0xd4, 0xc1, 0x5a, 0x57, 0x92, 0xc1, 0xf1, 0x81, 0x4f, 0x79, 0x4c, 0x06, 0x65,
11372
-	0x4b, 0x9c, 0x3c, 0x01, 0xf1, 0xe3, 0x68, 0x55, 0x43, 0xcc, 0xc2, 0x80, 0x70, 0x7a, 0x4a, 0x26,
11373
-	0x51, 0x92, 0xe9, 0x26, 0x7a, 0x2c, 0x48, 0xa2, 0xb8, 0xbb, 0x52, 0x67, 0x2d, 0x27, 0x8f, 0xd6,
11374
-	0x6f, 0xf3, 0x07, 0x6b, 0xb8, 0x3a, 0x53, 0x63, 0xed, 0xca, 0x43, 0x79, 0x10, 0x4c, 0xbb, 0xbe,
11375
-	0xd3, 0x1d, 0xed, 0x63, 0x58, 0x99, 0x89, 0xf3, 0x15, 0x16, 0xde, 0xea, 0x3c, 0xfd, 0x91, 0x91,
11376
-	0xd5, 0x5f, 0xbf, 0x63, 0xe4, 0xcd, 0xff, 0x4e, 0x01, 0x74, 0x98, 0x2c, 0x86, 0x62, 0x56, 0x17,
11377
-	0xbf, 0x7a, 0x14, 0xe4, 0x1b, 0x8a, 0xcd, 0x3c, 0x9d, 0x33, 0x0b, 0x69, 0xe8, 0xd4, 0x8a, 0x60,
11378
-	0x75, 0x12, 0x8e, 0x63, 0x45, 0xb4, 0x01, 0x25, 0xc5, 0xa7, 0xfb, 0x23, 0x16, 0xa8, 0x0d, 0xbe,
11379
-	0x82, 0x41, 0x89, 0x84, 0xa6, 0xb8, 0x52, 0x8f, 0xc6, 0x07, 0x9e, 0x1b, 0x1e, 0x51, 0x47, 0x61,
11380
-	0xb2, 0x12, 0xb3, 0x12, 0x4b, 0x05, 0xcc, 0x6c, 0x40, 0x21, 0xb2, 0x8e, 0xd6, 0x20, 0xb3, 0x5f,
11381
-	0xef, 0x18, 0x4b, 0x95, 0x6b, 0x67, 0xe7, 0xd5, 0x52, 0x24, 0xde, 0xaf, 0x77, 0x44, 0x4f, 0xaf,
11382
-	0xd1, 0x31, 0x52, 0xb3, 0x3d, 0xbd, 0x46, 0xa7, 0x92, 0x15, 0x87, 0x80, 0xf9, 0x57, 0x29, 0xc8,
11383
-	0x2b, 0x4a, 0xb2, 0x30, 0x62, 0x0b, 0x96, 0x23, 0xa2, 0xac, 0x78, 0xd2, 0xfb, 0xaf, 0xe7, 0x34,
11384
-	0x35, 0x4d, 0x41, 0xd4, 0x3a, 0x46, 0x7a, 0x95, 0xcf, 0xa0, 0x9c, 0xec, 0xf8, 0x4e, 0xab, 0xf8,
11385
-	0xc7, 0x50, 0x12, 0x89, 0x12, 0x71, 0x9b, 0x4d, 0xc8, 0x2b, 0xda, 0xa4, 0xb7, 0xfa, 0x55, 0x04,
11386
-	0x4b, 0x23, 0xd1, 0x03, 0x58, 0x56, 0xa4, 0x2c, 0x7a, 0x2e, 0x58, 0xbf, 0x3a, 0x1d, 0x71, 0x04,
11387
-	0x37, 0x3f, 0x87, 0x6c, 0x87, 0xd2, 0x00, 0xdd, 0x85, 0x65, 0x9f, 0x39, 0x74, 0x5a, 0xd9, 0x34,
11388
-	0x9f, 0x74, 0x68, 0xab, 0x21, 0xf8, 0xa4, 0x43, 0x5b, 0x8e, 0x98, 0x3c, 0xe2, 0x38, 0x41, 0xf4,
11389
-	0x62, 0x22, 0xbe, 0xcd, 0x7d, 0x28, 0x3f, 0xa3, 0xee, 0xe0, 0x88, 0x53, 0x47, 0x1a, 0xfa, 0x10,
11390
-	0xb2, 0x23, 0x1a, 0x3b, 0xbf, 0xb6, 0x30, 0x75, 0x28, 0x0d, 0xb0, 0x44, 0x89, 0x0d, 0x79, 0x2a,
11391
-	0xb5, 0xf5, 0x23, 0x95, 0x6e, 0x99, 0x7f, 0x9f, 0x86, 0xd5, 0x56, 0x18, 0x8e, 0x89, 0x6f, 0x47,
11392
-	0xc7, 0xd6, 0x4f, 0x66, 0x8f, 0xad, 0xfb, 0x0b, 0x23, 0x9c, 0x51, 0x99, 0xbd, 0xc4, 0xea, 0xca,
11393
-	0x95, 0x8e, 0x2b, 0x97, 0xf9, 0x75, 0x2a, 0xba, 0xbd, 0xde, 0x4b, 0xec, 0x9b, 0xca, 0xda, 0xd9,
11394
-	0x79, 0xf5, 0x66, 0xd2, 0x12, 0xed, 0xf9, 0xc7, 0x3e, 0x3b, 0xf5, 0xd1, 0xbb, 0xe2, 0x36, 0xdb,
11395
-	0x6e, 0x3e, 0x33, 0x52, 0x95, 0x5b, 0x67, 0xe7, 0x55, 0x34, 0x03, 0xc2, 0xd4, 0xa7, 0xa7, 0xc2,
11396
-	0x52, 0xa7, 0xd9, 0x6e, 0x88, 0x13, 0x26, 0xbd, 0xc0, 0x52, 0x87, 0xfa, 0x8e, 0xeb, 0x0f, 0xd0,
11397
-	0x5d, 0xc8, 0xb7, 0xba, 0xdd, 0x9e, 0xbc, 0x5f, 0xbc, 0x75, 0x76, 0x5e, 0xbd, 0x31, 0x83, 0x12,
11398
-	0x0d, 0xea, 0x08, 0x90, 0xe0, 0x3f, 0xcd, 0x86, 0x91, 0x5d, 0x00, 0x12, 0xc7, 0x3f, 0x75, 0x74,
11399
-	0x86, 0xff, 0x7b, 0x1a, 0x0c, 0xcb, 0xb6, 0xe9, 0x88, 0x8b, 0x7e, 0xcd, 0x29, 0xf7, 0xa1, 0x30,
11400
-	0x12, 0x5f, 0xae, 0xe4, 0xc8, 0x22, 0x2d, 0x1e, 0x2c, 0x7c, 0xc1, 0x9c, 0xd3, 0xab, 0x61, 0xe6,
11401
-	0x51, 0xcb, 0x19, 0xba, 0x61, 0x28, 0xee, 0x4e, 0x52, 0x86, 0x63, 0x4b, 0x95, 0x5f, 0xa6, 0xe0,
11402
-	0xc6, 0x02, 0x04, 0xfa, 0x18, 0xb2, 0x01, 0xf3, 0xa2, 0xe5, 0xb9, 0xf3, 0xba, 0xf7, 0x05, 0xa1,
11403
-	0x8a, 0x25, 0x12, 0xad, 0x03, 0x90, 0x31, 0x67, 0x44, 0x8e, 0x2f, 0x17, 0xa6, 0x80, 0x13, 0x12,
11404
-	0xf4, 0x0c, 0xf2, 0x21, 0xb5, 0x03, 0x1a, 0x11, 0x84, 0xcf, 0xff, 0xbf, 0xde, 0xd7, 0xba, 0xd2,
11405
-	0x0c, 0xd6, 0xe6, 0x2a, 0x35, 0xc8, 0x2b, 0x89, 0xc8, 0x68, 0x87, 0x70, 0x22, 0x9d, 0x2e, 0x63,
11406
-	0xf9, 0x2d, 0x12, 0x85, 0x78, 0x83, 0x28, 0x51, 0x88, 0x37, 0x30, 0x7f, 0x96, 0x06, 0x68, 0x3e,
11407
-	0xe7, 0x34, 0xf0, 0x89, 0x57, 0xb7, 0x50, 0x33, 0x51, 0x21, 0x55, 0xb4, 0x3f, 0x58, 0xf8, 0xea,
11408
-	0x14, 0x6b, 0xd4, 0xea, 0xd6, 0x82, 0x1a, 0x79, 0x1b, 0x32, 0xe3, 0xc0, 0xd3, 0x2f, 0x98, 0x92,
11409
-	0x1d, 0xf4, 0xf0, 0x0e, 0x16, 0x32, 0xd4, 0x9c, 0x56, 0xa4, 0xcc, 0xeb, 0x9f, 0x9e, 0x13, 0x03,
11410
-	0xfc, 0xe6, 0xab, 0xd2, 0x87, 0x00, 0x53, 0xaf, 0xd1, 0x3a, 0xe4, 0xea, 0xdb, 0xdd, 0xee, 0x8e,
11411
-	0xb1, 0xa4, 0xae, 0x40, 0xd3, 0x2e, 0x29, 0x36, 0xff, 0x2e, 0x05, 0x85, 0xba, 0xa5, 0x4f, 0x95,
11412
-	0x6d, 0x30, 0x64, 0x2d, 0xb1, 0x69, 0xc0, 0xfb, 0xf4, 0xf9, 0xc8, 0x0d, 0x26, 0xba, 0x1c, 0x5c,
11413
-	0x7d, 0x59, 0x58, 0x15, 0x5a, 0x75, 0x1a, 0xf0, 0xa6, 0xd4, 0x41, 0x18, 0xca, 0x54, 0x87, 0xd8,
11414
-	0xb7, 0x49, 0x54, 0x9c, 0xd7, 0xaf, 0x9e, 0x0a, 0x45, 0xc9, 0xa6, 0xed, 0x10, 0x97, 0x22, 0x23,
11415
-	0x75, 0x12, 0x9a, 0x4f, 0xe1, 0xc6, 0x5e, 0x60, 0x1f, 0xd1, 0x90, 0xab, 0x41, 0xb5, 0xcb, 0x9f,
11416
-	0xc3, 0x1d, 0x4e, 0xc2, 0xe3, 0xfe, 0x91, 0x1b, 0x72, 0x16, 0x4c, 0xfa, 0x01, 0xe5, 0xd4, 0x17,
11417
-	0xfd, 0x7d, 0xf9, 0xc0, 0xad, 0xaf, 0x98, 0xb7, 0x05, 0xe6, 0xb1, 0x82, 0xe0, 0x08, 0xb1, 0x23,
11418
-	0x00, 0x66, 0x0b, 0xca, 0x82, 0x45, 0x35, 0xe8, 0x21, 0x19, 0x7b, 0x3c, 0x44, 0x3f, 0x06, 0xf0,
11419
-	0xd8, 0xa0, 0xff, 0xc6, 0x95, 0xbc, 0xe8, 0xb1, 0x81, 0xfa, 0x34, 0x7f, 0x1f, 0x8c, 0x86, 0x1b,
11420
-	0x8e, 0x08, 0xb7, 0x8f, 0xa2, 0xbb, 0x33, 0x7a, 0x04, 0xc6, 0x11, 0x25, 0x01, 0x3f, 0xa0, 0x84,
11421
-	0xf7, 0x47, 0x34, 0x70, 0x99, 0xf3, 0x46, 0x53, 0x7a, 0x2d, 0xd6, 0xea, 0x48, 0x25, 0xf3, 0x57,
11422
-	0x29, 0x00, 0x4c, 0x0e, 0x23, 0x02, 0xf0, 0x43, 0xb8, 0x1e, 0xfa, 0x64, 0x14, 0x1e, 0x31, 0xde,
11423
-	0x77, 0x7d, 0x4e, 0x83, 0x13, 0xe2, 0xe9, 0xfb, 0x8f, 0x11, 0x75, 0xb4, 0xb4, 0x1c, 0x7d, 0x08,
11424
-	0xe8, 0x98, 0xd2, 0x51, 0x9f, 0x79, 0x4e, 0x3f, 0xea, 0x54, 0x2f, 0xf0, 0x59, 0x6c, 0x88, 0x9e,
11425
-	0x3d, 0xcf, 0xe9, 0x46, 0x72, 0xb4, 0x05, 0xeb, 0x62, 0x06, 0xa8, 0xcf, 0x03, 0x97, 0x86, 0xfd,
11426
-	0x43, 0x16, 0xf4, 0x43, 0x8f, 0x9d, 0xf6, 0x0f, 0x99, 0xe7, 0xb1, 0x53, 0x1a, 0x44, 0xb7, 0xcb,
11427
-	0x8a, 0xc7, 0x06, 0x4d, 0x05, 0xda, 0x66, 0x41, 0xd7, 0x63, 0xa7, 0xdb, 0x11, 0x42, 0xb0, 0x84,
11428
-	0x69, 0xd8, 0xdc, 0xb5, 0x8f, 0x23, 0x96, 0x10, 0x4b, 0xf7, 0x5d, 0xfb, 0x18, 0xdd, 0x85, 0x15,
11429
-	0xea, 0x51, 0x79, 0x0f, 0x52, 0xa8, 0x9c, 0x44, 0x95, 0x23, 0xa1, 0x00, 0x99, 0xbf, 0x05, 0xc5,
11430
-	0x8e, 0x47, 0x6c, 0xf9, 0x3f, 0x87, 0xb8, 0xf1, 0xd9, 0xcc, 0x17, 0x49, 0xe0, 0xfa, 0x5c, 0x55,
11431
-	0xc7, 0x22, 0x4e, 0x8a, 0xcc, 0x9f, 0x00, 0xfc, 0x94, 0xb9, 0xfe, 0x3e, 0x3b, 0xa6, 0xbe, 0x7c,
11432
-	0x12, 0x3e, 0x65, 0xc1, 0xb1, 0x5e, 0xca, 0x22, 0xd6, 0x2d, 0x49, 0x94, 0x89, 0x4f, 0x06, 0x34,
11433
-	0x88, 0x5f, 0x46, 0x55, 0x53, 0x1c, 0x2e, 0x79, 0xcc, 0x18, 0xaf, 0x5b, 0xa8, 0x0a, 0x79, 0x9b,
11434
-	0xf4, 0xa3, 0x9d, 0x57, 0xde, 0x2a, 0x5e, 0x5e, 0x6c, 0xe4, 0xea, 0xd6, 0x13, 0x3a, 0xc1, 0x39,
11435
-	0x9b, 0x3c, 0xa1, 0x13, 0x71, 0xfa, 0xda, 0x44, 0xee, 0x17, 0x69, 0xa6, 0xac, 0x4e, 0xdf, 0xba,
11436
-	0x25, 0x36, 0x03, 0xce, 0xdb, 0x44, 0xfc, 0xa2, 0x8f, 0xa1, 0xac, 0x41, 0xfd, 0x23, 0x12, 0x1e,
11437
-	0x29, 0xae, 0xba, 0xb5, 0x7a, 0x79, 0xb1, 0x01, 0x0a, 0xf9, 0x98, 0x84, 0x47, 0x18, 0x14, 0x5a,
11438
-	0x7c, 0xa3, 0x26, 0x94, 0xbe, 0x62, 0xae, 0xdf, 0xe7, 0x32, 0x08, 0x7d, 0x61, 0x5f, 0xb8, 0x7f,
11439
-	0xa6, 0xa1, 0xea, 0xdb, 0x2b, 0x7c, 0x15, 0x4b, 0xcc, 0x7f, 0x4d, 0x41, 0x49, 0xd8, 0x74, 0x0f,
11440
-	0x5d, 0x5b, 0x9c, 0x96, 0xdf, 0xbd, 0xd2, 0xdf, 0x86, 0x8c, 0x1d, 0x06, 0x3a, 0x36, 0x59, 0xea,
11441
-	0xea, 0x5d, 0x8c, 0x85, 0x0c, 0x7d, 0x01, 0x79, 0xc5, 0xf8, 0x75, 0x91, 0x37, 0xbf, 0xfd, 0x5c,
11442
-	0xd7, 0x2e, 0x6a, 0x3d, 0xb9, 0x96, 0x53, 0xef, 0x64, 0x94, 0x65, 0x9c, 0x14, 0xa1, 0x5b, 0x90,
11443
-	0xb6, 0x7d, 0x99, 0x14, 0xfa, 0xaf, 0xa2, 0x7a, 0x1b, 0xa7, 0x6d, 0xdf, 0xfc, 0xe7, 0x14, 0xac,
11444
-	0x34, 0x7d, 0x3b, 0x98, 0xc8, 0x22, 0x29, 0x16, 0xe2, 0x0e, 0x14, 0xc3, 0xf1, 0x41, 0x38, 0x09,
11445
-	0x39, 0x1d, 0x46, 0x2f, 0xd1, 0xb1, 0x00, 0xb5, 0xa0, 0x48, 0xbc, 0x01, 0x0b, 0x5c, 0x7e, 0x34,
11446
-	0xd4, 0xdc, 0x78, 0x71, 0x61, 0x4e, 0xda, 0xac, 0x59, 0x91, 0x0a, 0x9e, 0x6a, 0x47, 0xa5, 0x38,
11447
-	0x23, 0x9d, 0x95, 0xa5, 0xf8, 0x5d, 0x28, 0x7b, 0x64, 0x28, 0xa8, 0x70, 0x5f, 0xdc, 0x83, 0x64,
11448
-	0x1c, 0x59, 0x5c, 0xd2, 0x32, 0x71, 0xb7, 0x33, 0x4d, 0x28, 0xc6, 0xc6, 0xd0, 0x35, 0x28, 0x59,
11449
-	0xcd, 0x6e, 0xff, 0x93, 0xcd, 0x07, 0xfd, 0x47, 0xf5, 0x5d, 0x63, 0x49, 0x33, 0x81, 0x7f, 0x4c,
11450
-	0xc1, 0xca, 0xae, 0xca, 0x41, 0x4d, 0x9c, 0xee, 0xc2, 0x72, 0x40, 0x0e, 0x79, 0x44, 0xed, 0xb2,
11451
-	0x2a, 0xb9, 0x44, 0x11, 0x10, 0xd4, 0x4e, 0x74, 0x2d, 0xa6, 0x76, 0x89, 0xff, 0x41, 0x32, 0x57,
11452
-	0xfe, 0x0f, 0x92, 0xfd, 0x8d, 0xfc, 0x0f, 0xf2, 0xc1, 0xaf, 0x32, 0x50, 0x8c, 0x6f, 0xa2, 0x22,
11453
-	0x65, 0x04, 0xd3, 0x5a, 0x52, 0x2f, 0x3b, 0xb1, 0xbc, 0x2d, 0x39, 0x56, 0xd1, 0xda, 0xd9, 0xd9,
11454
-	0xab, 0x5b, 0xe2, 0xb2, 0xfe, 0x85, 0xa2, 0x62, 0x31, 0xc0, 0xf2, 0x3c, 0x26, 0x16, 0xdd, 0x41,
11455
-	0xe6, 0x94, 0x8a, 0xbd, 0xd0, 0xef, 0x47, 0x31, 0x2a, 0xe2, 0x61, 0xef, 0x41, 0xc1, 0xea, 0x76,
11456
-	0x5b, 0x8f, 0xda, 0xcd, 0x86, 0xf1, 0x32, 0x55, 0xf9, 0xde, 0xd9, 0x79, 0xf5, 0xfa, 0xd4, 0x54,
11457
-	0x18, 0xba, 0x03, 0x9f, 0x3a, 0x12, 0x55, 0xaf, 0x37, 0x3b, 0x62, 0xbc, 0x17, 0xe9, 0x79, 0x94,
11458
-	0x24, 0x20, 0xf2, 0x2d, 0xb8, 0xd8, 0xc1, 0xcd, 0x8e, 0x85, 0xc5, 0x88, 0x2f, 0xd3, 0x73, 0x7e,
11459
-	0x75, 0x02, 0x3a, 0x22, 0x81, 0x18, 0x73, 0x3d, 0xfa, 0x4f, 0xe4, 0x45, 0x46, 0xbd, 0x17, 0x4e,
11460
-	0xaf, 0xdf, 0x94, 0x38, 0x13, 0x31, 0x5a, 0x77, 0xdf, 0xc2, 0xf2, 0x95, 0xe2, 0x65, 0x66, 0x6e,
11461
-	0xb4, 0x2e, 0x27, 0x01, 0x17, 0x56, 0x4c, 0x58, 0xc6, 0xbd, 0x76, 0x5b, 0x46, 0x97, 0x9d, 0x8b,
11462
-	0x0e, 0x8f, 0x7d, 0x5f, 0x60, 0xee, 0x41, 0x21, 0x7a, 0xd5, 0x30, 0x5e, 0x66, 0xe7, 0x1c, 0xaa,
11463
-	0x47, 0xcf, 0x29, 0x72, 0xc0, 0xc7, 0xbd, 0x7d, 0xf9, 0x97, 0xcd, 0x8b, 0xdc, 0xfc, 0x80, 0x47,
11464
-	0x63, 0xee, 0x08, 0xf2, 0x5b, 0x8d, 0xd9, 0xe8, 0xcb, 0x9c, 0x22, 0x01, 0x31, 0x46, 0x51, 0x51,
11465
-	0x61, 0x07, 0x37, 0x7f, 0xaa, 0xfe, 0xdd, 0x79, 0x91, 0x9f, 0xb3, 0x83, 0xe9, 0x57, 0xd4, 0xe6,
11466
-	0xd4, 0x99, 0x3e, 0x87, 0xc6, 0x5d, 0x1f, 0xfc, 0x01, 0x14, 0xa2, 0x82, 0x81, 0xd6, 0x21, 0xff,
11467
-	0x6c, 0x0f, 0x3f, 0x69, 0x62, 0x63, 0x49, 0xcd, 0x4e, 0xd4, 0xf3, 0x4c, 0x55, 0xdc, 0x2a, 0x2c,
11468
-	0xef, 0x5a, 0x6d, 0xeb, 0x51, 0x13, 0x47, 0xcf, 0xb1, 0x11, 0x40, 0x67, 0x7d, 0xc5, 0xd0, 0x03,
11469
-	0xc4, 0x36, 0xb7, 0xee, 0x7c, 0xfd, 0xcd, 0xfa, 0xd2, 0x2f, 0xbe, 0x59, 0x5f, 0xfa, 0xe5, 0x37,
11470
-	0xeb, 0xa9, 0x17, 0x97, 0xeb, 0xa9, 0xaf, 0x2f, 0xd7, 0x53, 0x3f, 0xbf, 0x5c, 0x4f, 0xfd, 0xc7,
11471
-	0xe5, 0x7a, 0xea, 0x20, 0x2f, 0x19, 0xd9, 0xa7, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0x84, 0x8b,
11472
-	0x50, 0xe8, 0x9f, 0x20, 0x00, 0x00,
11266
+	0x39, 0xe6, 0xb2, 0x40, 0x0e, 0x7b, 0x48, 0x0e, 0x41, 0xfd, 0x74, 0xf3, 0xc7, 0xb4, 0xc6, 0x93,
11267
+	0xdd, 0x13, 0xbb, 0x5e, 0x7d, 0xef, 0xd5, 0xab, 0xaa, 0x57, 0xaf, 0xbe, 0x57, 0x84, 0x02, 0x9f,
11268
+	0x8c, 0x68, 0x58, 0x19, 0x05, 0x8c, 0x33, 0x84, 0x1c, 0x66, 0x1f, 0xd3, 0xa0, 0x12, 0x9e, 0x92,
11269
+	0x60, 0x78, 0xec, 0xf2, 0xca, 0xc9, 0x27, 0xa5, 0xdb, 0xdc, 0x1d, 0xd2, 0x90, 0x93, 0xe1, 0xe8,
11270
+	0xa3, 0xf8, 0x4b, 0xc1, 0x4b, 0x6f, 0x39, 0xe3, 0x80, 0x70, 0x97, 0xf9, 0x1f, 0x45, 0x1f, 0xba,
11271
+	0xe3, 0x66, 0x9f, 0xf5, 0x99, 0xfc, 0xfc, 0x48, 0x7c, 0x29, 0xa9, 0xb9, 0x05, 0xab, 0x4f, 0x69,
11272
+	0x10, 0xba, 0xcc, 0x47, 0x37, 0x21, 0xe3, 0xfa, 0x0e, 0x7d, 0xbe, 0x91, 0x28, 0x27, 0xee, 0xa7,
11273
+	0xb1, 0x6a, 0x98, 0x7f, 0x9d, 0x80, 0x82, 0xe5, 0xfb, 0x8c, 0x4b, 0x5b, 0x21, 0x42, 0x90, 0xf6,
11274
+	0xc9, 0x90, 0x4a, 0x50, 0x1e, 0xcb, 0x6f, 0x54, 0x85, 0xac, 0x47, 0x0e, 0xa9, 0x17, 0x6e, 0x24,
11275
+	0xcb, 0xa9, 0xfb, 0x85, 0xed, 0x1f, 0x56, 0x5e, 0xf5, 0xb9, 0x32, 0x63, 0xa4, 0xb2, 0x27, 0xd1,
11276
+	0x75, 0x9f, 0x07, 0x13, 0xac, 0x55, 0x4b, 0x3f, 0x86, 0xc2, 0x8c, 0x18, 0x19, 0x90, 0x3a, 0xa6,
11277
+	0x13, 0x3d, 0x8c, 0xf8, 0x14, 0xfe, 0x9d, 0x10, 0x6f, 0x4c, 0x37, 0x92, 0x52, 0xa6, 0x1a, 0x9f,
11278
+	0x25, 0x1f, 0x24, 0xcc, 0x2f, 0x21, 0x8f, 0x69, 0xc8, 0xc6, 0x81, 0x4d, 0x43, 0xf4, 0x03, 0xc8,
11279
+	0xfb, 0xc4, 0x67, 0x3d, 0x7b, 0x34, 0x0e, 0xa5, 0x7a, 0x6a, 0xa7, 0x78, 0x79, 0xb1, 0x95, 0x6b,
11280
+	0x12, 0x9f, 0x55, 0x5b, 0xdd, 0x10, 0xe7, 0x44, 0x77, 0x75, 0x34, 0x0e, 0xd1, 0xbb, 0x50, 0x1c,
11281
+	0xd2, 0x21, 0x0b, 0x26, 0xbd, 0xc3, 0x09, 0xa7, 0xa1, 0x34, 0x9c, 0xc2, 0x05, 0x25, 0xdb, 0x11,
11282
+	0x22, 0xf3, 0x2f, 0x13, 0x70, 0x33, 0xb2, 0x8d, 0xe9, 0x1f, 0x8e, 0xdd, 0x80, 0x0e, 0xa9, 0xcf,
11283
+	0x43, 0xf4, 0xdb, 0x90, 0xf5, 0xdc, 0xa1, 0xcb, 0xd5, 0x18, 0x85, 0xed, 0x77, 0x96, 0xcd, 0x39,
11284
+	0xf6, 0x0a, 0x6b, 0x30, 0xb2, 0xa0, 0x18, 0xd0, 0x90, 0x06, 0x27, 0x6a, 0x25, 0xe4, 0x90, 0xdf,
11285
+	0xaa, 0x3c, 0xa7, 0x62, 0xee, 0x42, 0xae, 0xe5, 0x11, 0x7e, 0xc4, 0x82, 0x21, 0x32, 0xa1, 0x48,
11286
+	0x02, 0x7b, 0xe0, 0x72, 0x6a, 0xf3, 0x71, 0x10, 0xed, 0xca, 0x9c, 0x0c, 0xdd, 0x82, 0x24, 0x53,
11287
+	0x03, 0xe5, 0x77, 0xb2, 0x97, 0x17, 0x5b, 0xc9, 0x83, 0x36, 0x4e, 0xb2, 0xd0, 0x7c, 0x08, 0xd7,
11288
+	0x5b, 0xde, 0xb8, 0xef, 0xfa, 0x35, 0x1a, 0xda, 0x81, 0x3b, 0x12, 0xd6, 0xc5, 0xf6, 0x8a, 0xe0,
11289
+	0x8b, 0xb6, 0x57, 0x7c, 0xc7, 0x5b, 0x9e, 0x9c, 0x6e, 0xb9, 0xf9, 0xe7, 0x49, 0xb8, 0x5e, 0xf7,
11290
+	0xfb, 0xae, 0x4f, 0x67, 0xb5, 0xef, 0xc1, 0x3a, 0x95, 0xc2, 0xde, 0x89, 0x0a, 0x2a, 0x6d, 0x67,
11291
+	0x4d, 0x49, 0xa3, 0x48, 0x6b, 0x2c, 0xc4, 0xcb, 0x27, 0xcb, 0xa6, 0xff, 0x8a, 0xf5, 0x65, 0x51,
11292
+	0x83, 0xea, 0xb0, 0x3a, 0x92, 0x93, 0x08, 0x37, 0x52, 0xd2, 0xd6, 0xbd, 0x65, 0xb6, 0x5e, 0x99,
11293
+	0xe7, 0x4e, 0xfa, 0xeb, 0x8b, 0xad, 0x15, 0x1c, 0xe9, 0xfe, 0x3a, 0xc1, 0xf7, 0x9f, 0x09, 0xb8,
11294
+	0xd6, 0x64, 0xce, 0xdc, 0x3a, 0x94, 0x20, 0x37, 0x60, 0x21, 0x9f, 0x39, 0x28, 0x71, 0x1b, 0x3d,
11295
+	0x80, 0xdc, 0x48, 0x6f, 0x9f, 0xde, 0xfd, 0x3b, 0xcb, 0x5d, 0x56, 0x18, 0x1c, 0xa3, 0xd1, 0x43,
11296
+	0xc8, 0x07, 0x51, 0x4c, 0x6c, 0xa4, 0xde, 0x24, 0x70, 0xa6, 0x78, 0xf4, 0x7b, 0x90, 0x55, 0x9b,
11297
+	0xb0, 0x91, 0x96, 0x9a, 0xf7, 0xde, 0x68, 0xcd, 0xb1, 0x56, 0x32, 0x7f, 0x91, 0x00, 0x03, 0x93,
11298
+	0x23, 0xbe, 0x4f, 0x87, 0x87, 0x34, 0x68, 0x73, 0xc2, 0xc7, 0x21, 0xba, 0x05, 0x59, 0x8f, 0x12,
11299
+	0x87, 0x06, 0x72, 0x92, 0x39, 0xac, 0x5b, 0xa8, 0x2b, 0x82, 0x9c, 0xd8, 0x03, 0x72, 0xe8, 0x7a,
11300
+	0x2e, 0x9f, 0xc8, 0x69, 0xae, 0x2f, 0xdf, 0xe5, 0x45, 0x9b, 0x15, 0x3c, 0xa3, 0x88, 0xe7, 0xcc,
11301
+	0xa0, 0x0d, 0x58, 0x1d, 0xd2, 0x30, 0x24, 0x7d, 0x2a, 0x67, 0x9f, 0xc7, 0x51, 0xd3, 0x7c, 0x08,
11302
+	0xc5, 0x59, 0x3d, 0x54, 0x80, 0xd5, 0x6e, 0xf3, 0x49, 0xf3, 0xe0, 0x59, 0xd3, 0x58, 0x41, 0xd7,
11303
+	0xa0, 0xd0, 0x6d, 0xe2, 0xba, 0x55, 0x7d, 0x6c, 0xed, 0xec, 0xd5, 0x8d, 0x04, 0x5a, 0x83, 0xfc,
11304
+	0xb4, 0x99, 0x34, 0x7f, 0x96, 0x00, 0x10, 0x1b, 0xa8, 0x27, 0xf5, 0x19, 0x64, 0x42, 0x4e, 0xb8,
11305
+	0xda, 0xb8, 0xf5, 0xed, 0xf7, 0x96, 0x79, 0x3d, 0x85, 0x57, 0xc4, 0x0f, 0xc5, 0x4a, 0x65, 0xd6,
11306
+	0xc3, 0xe4, 0xa2, 0x87, 0x19, 0x89, 0x9c, 0x77, 0x2d, 0x07, 0xe9, 0x9a, 0xf8, 0x4a, 0xa0, 0x3c,
11307
+	0x64, 0x70, 0xdd, 0xaa, 0x7d, 0x69, 0x24, 0x91, 0x01, 0xc5, 0x5a, 0xa3, 0x5d, 0x3d, 0x68, 0x36,
11308
+	0xeb, 0xd5, 0x4e, 0xbd, 0x66, 0xa4, 0xcc, 0x7b, 0x90, 0x69, 0x0c, 0x49, 0x9f, 0xa2, 0x3b, 0x22,
11309
+	0x02, 0x8e, 0x68, 0x40, 0x7d, 0x3b, 0x0a, 0xac, 0xa9, 0xc0, 0xfc, 0x79, 0x1e, 0x32, 0xfb, 0x6c,
11310
+	0xec, 0x73, 0xb4, 0x3d, 0x73, 0x8a, 0xd7, 0xb7, 0x37, 0x97, 0x4d, 0x41, 0x02, 0x2b, 0x9d, 0xc9,
11311
+	0x88, 0xea, 0x53, 0x7e, 0x0b, 0xb2, 0x2a, 0x56, 0xb4, 0xeb, 0xba, 0x25, 0xe4, 0x9c, 0x04, 0x7d,
11312
+	0xca, 0xf5, 0xa2, 0xeb, 0x16, 0xba, 0x0f, 0xb9, 0x80, 0x12, 0x87, 0xf9, 0xde, 0x44, 0x86, 0x54,
11313
+	0x4e, 0xa5, 0x59, 0x4c, 0x89, 0x73, 0xe0, 0x7b, 0x13, 0x1c, 0xf7, 0xa2, 0xc7, 0x50, 0x3c, 0x74,
11314
+	0x7d, 0xa7, 0xc7, 0x46, 0x2a, 0xe7, 0x65, 0x5e, 0x1f, 0x80, 0xca, 0xab, 0x1d, 0xd7, 0x77, 0x0e,
11315
+	0x14, 0x18, 0x17, 0x0e, 0xa7, 0x0d, 0xd4, 0x84, 0xf5, 0x13, 0xe6, 0x8d, 0x87, 0x34, 0xb6, 0x95,
11316
+	0x95, 0xb6, 0xde, 0x7f, 0xbd, 0xad, 0xa7, 0x12, 0x1f, 0x59, 0x5b, 0x3b, 0x99, 0x6d, 0xa2, 0x27,
11317
+	0xb0, 0xc6, 0x87, 0xa3, 0xa3, 0x30, 0x36, 0xb7, 0x2a, 0xcd, 0x7d, 0xff, 0x8a, 0x05, 0x13, 0xf0,
11318
+	0xc8, 0x5a, 0x91, 0xcf, 0xb4, 0x4a, 0x7f, 0x96, 0x82, 0xc2, 0x8c, 0xe7, 0xa8, 0x0d, 0x85, 0x51,
11319
+	0xc0, 0x46, 0xa4, 0x2f, 0xf3, 0xb6, 0xde, 0x8b, 0x4f, 0xde, 0x68, 0xd6, 0x95, 0xd6, 0x54, 0x11,
11320
+	0xcf, 0x5a, 0x31, 0xcf, 0x93, 0x50, 0x98, 0xe9, 0x44, 0x1f, 0x40, 0x0e, 0xb7, 0x70, 0xe3, 0xa9,
11321
+	0xd5, 0xa9, 0x1b, 0x2b, 0xa5, 0x3b, 0x67, 0xe7, 0xe5, 0x0d, 0x69, 0x6d, 0xd6, 0x40, 0x2b, 0x70,
11322
+	0x4f, 0x44, 0xe8, 0xdd, 0x87, 0xd5, 0x08, 0x9a, 0x28, 0xbd, 0x7d, 0x76, 0x5e, 0x7e, 0x6b, 0x11,
11323
+	0x3a, 0x83, 0xc4, 0xed, 0xc7, 0x16, 0xae, 0xd7, 0x8c, 0xe4, 0x72, 0x24, 0x6e, 0x0f, 0x48, 0x40,
11324
+	0x1d, 0xf4, 0x7d, 0xc8, 0x6a, 0x60, 0xaa, 0x54, 0x3a, 0x3b, 0x2f, 0xdf, 0x5a, 0x04, 0x4e, 0x71,
11325
+	0xb8, 0xbd, 0x67, 0x3d, 0xad, 0x1b, 0xe9, 0xe5, 0x38, 0xdc, 0xf6, 0xc8, 0x09, 0x45, 0xef, 0x41,
11326
+	0x46, 0xc1, 0x32, 0xa5, 0xdb, 0x67, 0xe7, 0xe5, 0xef, 0xbd, 0x62, 0x4e, 0xa0, 0x4a, 0x1b, 0x7f,
11327
+	0xf1, 0x37, 0x9b, 0x2b, 0xff, 0xf4, 0xb7, 0x9b, 0xc6, 0x62, 0x77, 0xe9, 0x7f, 0x13, 0xb0, 0x36,
11328
+	0xb7, 0xe5, 0xc8, 0x84, 0xac, 0xcf, 0x6c, 0x36, 0x52, 0xe9, 0x3c, 0xb7, 0x03, 0x97, 0x17, 0x5b,
11329
+	0xd9, 0x26, 0xab, 0xb2, 0xd1, 0x04, 0xeb, 0x1e, 0xf4, 0x64, 0xe1, 0x42, 0xfa, 0xf4, 0x0d, 0xe3,
11330
+	0x69, 0xe9, 0x95, 0xf4, 0x39, 0xac, 0x39, 0x81, 0x7b, 0x42, 0x83, 0x9e, 0xcd, 0xfc, 0x23, 0xb7,
11331
+	0xaf, 0x53, 0x75, 0x69, 0x99, 0xcd, 0x9a, 0x04, 0xe2, 0xa2, 0x52, 0xa8, 0x4a, 0xfc, 0xaf, 0x71,
11332
+	0x19, 0x95, 0x9e, 0x42, 0x71, 0x36, 0x42, 0xd1, 0x3b, 0x00, 0xa1, 0xfb, 0x47, 0x54, 0xf3, 0x1b,
11333
+	0xc9, 0x86, 0x70, 0x5e, 0x48, 0x24, 0xbb, 0x41, 0xef, 0x43, 0x7a, 0xc8, 0x1c, 0x65, 0x27, 0xb3,
11334
+	0x73, 0x43, 0xdc, 0x89, 0xff, 0x76, 0xb1, 0x55, 0x60, 0x61, 0x65, 0xd7, 0xf5, 0xe8, 0x3e, 0x73,
11335
+	0x28, 0x96, 0x00, 0xf3, 0x04, 0xd2, 0x22, 0x55, 0xa0, 0xb7, 0x21, 0xbd, 0xd3, 0x68, 0xd6, 0x8c,
11336
+	0x95, 0xd2, 0xf5, 0xb3, 0xf3, 0xf2, 0x9a, 0x5c, 0x12, 0xd1, 0x21, 0x62, 0x17, 0x6d, 0x41, 0xf6,
11337
+	0xe9, 0xc1, 0x5e, 0x77, 0x5f, 0x84, 0xd7, 0x8d, 0xb3, 0xf3, 0xf2, 0xb5, 0xb8, 0x5b, 0x2d, 0x1a,
11338
+	0x7a, 0x07, 0x32, 0x9d, 0xfd, 0xd6, 0x6e, 0xdb, 0x48, 0x96, 0xd0, 0xd9, 0x79, 0x79, 0x3d, 0xee,
11339
+	0x97, 0x3e, 0x97, 0xae, 0xeb, 0x5d, 0xcd, 0xc7, 0x72, 0xf3, 0x7f, 0x92, 0xb0, 0x86, 0x05, 0xbf,
11340
+	0x0d, 0x78, 0x8b, 0x79, 0xae, 0x3d, 0x41, 0x2d, 0xc8, 0xdb, 0xcc, 0x77, 0xdc, 0x99, 0x33, 0xb5,
11341
+	0xfd, 0x9a, 0x4b, 0x70, 0xaa, 0x15, 0xb5, 0xaa, 0x91, 0x26, 0x9e, 0x1a, 0x41, 0xdb, 0x90, 0x71,
11342
+	0xa8, 0x47, 0x26, 0x57, 0xdd, 0xc6, 0x35, 0xcd, 0xa5, 0xb1, 0x82, 0x4a, 0xe6, 0x48, 0x9e, 0xf7,
11343
+	0x08, 0xe7, 0x74, 0x38, 0xe2, 0xea, 0x36, 0x4e, 0xe3, 0xc2, 0x90, 0x3c, 0xb7, 0xb4, 0x08, 0xfd,
11344
+	0x08, 0xb2, 0xa7, 0xae, 0xef, 0xb0, 0x53, 0x7d, 0xe1, 0x5e, 0x6d, 0x57, 0x63, 0xcd, 0x33, 0x71,
11345
+	0xcf, 0x2e, 0x38, 0x2b, 0x56, 0xbd, 0x79, 0xd0, 0xac, 0x47, 0xab, 0xae, 0xfb, 0x0f, 0xfc, 0x26,
11346
+	0xf3, 0xc5, 0x89, 0x81, 0x83, 0x66, 0x6f, 0xd7, 0x6a, 0xec, 0x75, 0xb1, 0x58, 0xf9, 0x9b, 0x67,
11347
+	0xe7, 0x65, 0x23, 0x86, 0xec, 0x12, 0xd7, 0x13, 0x24, 0xf0, 0x36, 0xa4, 0xac, 0xe6, 0x97, 0x46,
11348
+	0xb2, 0x64, 0x9c, 0x9d, 0x97, 0x8b, 0x71, 0xb7, 0xe5, 0x4f, 0xa6, 0x87, 0x69, 0x71, 0x5c, 0xf3,
11349
+	0xbf, 0x12, 0x50, 0xec, 0x8e, 0x1c, 0xc2, 0xa9, 0x8a, 0x4c, 0x54, 0x86, 0xc2, 0x88, 0x04, 0xc4,
11350
+	0xf3, 0xa8, 0xe7, 0x86, 0x43, 0x5d, 0x28, 0xcc, 0x8a, 0xd0, 0x83, 0xef, 0xb0, 0x98, 0x9a, 0x84,
11351
+	0xe9, 0x25, 0xed, 0xc2, 0xfa, 0x91, 0x72, 0xb6, 0x47, 0x6c, 0xb9, 0xbb, 0x29, 0xb9, 0xbb, 0x95,
11352
+	0x65, 0x26, 0x66, 0xbd, 0xaa, 0xe8, 0x39, 0x5a, 0x52, 0x0b, 0xaf, 0x1d, 0xcd, 0x36, 0xcd, 0xfb,
11353
+	0xb0, 0x36, 0xd7, 0x2f, 0x6e, 0xda, 0x96, 0xd5, 0x6d, 0xd7, 0x8d, 0x15, 0x54, 0x84, 0x5c, 0xf5,
11354
+	0xa0, 0xd9, 0x69, 0x34, 0xbb, 0x75, 0x23, 0x61, 0xfe, 0x43, 0x32, 0x9a, 0xad, 0x66, 0x02, 0x3b,
11355
+	0xf3, 0x4c, 0xe0, 0xc3, 0xd7, 0x3b, 0xa2, 0xb9, 0xc0, 0xb4, 0x11, 0x33, 0x82, 0xdf, 0x05, 0x90,
11356
+	0x8b, 0x4a, 0x9d, 0x1e, 0xe1, 0x57, 0xb1, 0xfd, 0x4e, 0x54, 0xc7, 0xe1, 0xbc, 0x56, 0xb0, 0x38,
11357
+	0xfa, 0x02, 0x8a, 0x36, 0x1b, 0x8e, 0x3c, 0xaa, 0xf5, 0x53, 0x6f, 0xa2, 0x5f, 0x88, 0x55, 0x2c,
11358
+	0x3e, 0xcb, 0x48, 0xd2, 0xf3, 0x8c, 0xa4, 0x0a, 0x85, 0x19, 0x7f, 0xe7, 0x79, 0x49, 0x11, 0x72,
11359
+	0xdd, 0x56, 0xcd, 0xea, 0x34, 0x9a, 0x8f, 0x8c, 0x04, 0x02, 0xc8, 0xca, 0x15, 0xab, 0x19, 0x49,
11360
+	0xc1, 0x9d, 0xaa, 0x07, 0xfb, 0xad, 0xbd, 0xba, 0x62, 0x26, 0x7f, 0x02, 0xd7, 0xaa, 0xcc, 0xe7,
11361
+	0xc4, 0xf5, 0x63, 0x52, 0xb8, 0x2d, 0x7c, 0xd6, 0xa2, 0x9e, 0xeb, 0xa8, 0xbc, 0xb5, 0x73, 0xed,
11362
+	0xf2, 0x62, 0xab, 0x10, 0x43, 0x1b, 0x35, 0xe1, 0x65, 0xd4, 0x70, 0x44, 0x74, 0x8e, 0x5c, 0x47,
11363
+	0xa7, 0xa1, 0xd5, 0xcb, 0x8b, 0xad, 0x54, 0xab, 0x51, 0xc3, 0x42, 0x86, 0xde, 0x86, 0x3c, 0x7d,
11364
+	0xee, 0xf2, 0x9e, 0x2d, 0xf2, 0x94, 0x98, 0x7f, 0x06, 0xe7, 0x84, 0xa0, 0x2a, 0xd2, 0xd2, 0x9f,
11365
+	0x26, 0x01, 0x3a, 0x24, 0x3c, 0xd6, 0x43, 0x3f, 0x84, 0x7c, 0x5c, 0x0e, 0x5f, 0x55, 0x96, 0xcd,
11366
+	0xac, 0x75, 0x8c, 0x47, 0x9f, 0x46, 0xbb, 0xad, 0xd8, 0xea, 0x72, 0x45, 0x3d, 0xd6, 0x32, 0xc2,
11367
+	0x37, 0x4f, 0x49, 0x45, 0xd6, 0xa6, 0x41, 0xa0, 0x17, 0x5d, 0x7c, 0xa2, 0xaa, 0xcc, 0x5c, 0x6a,
11368
+	0xce, 0x9a, 0x03, 0xdd, 0x5d, 0x36, 0xc8, 0xc2, 0x82, 0x3e, 0x5e, 0xc1, 0x53, 0xbd, 0x1d, 0x03,
11369
+	0xd6, 0x83, 0xb1, 0x2f, 0xbc, 0xee, 0x85, 0xb2, 0xdb, 0x74, 0xe1, 0xad, 0x26, 0xe5, 0xa7, 0x2c,
11370
+	0x38, 0xb6, 0x38, 0x27, 0xf6, 0x40, 0x94, 0xa7, 0xfa, 0xb8, 0x4e, 0xa9, 0x5b, 0x62, 0x8e, 0xba,
11371
+	0x6d, 0xc0, 0x2a, 0xf1, 0x5c, 0x12, 0x52, 0x75, 0xdf, 0xe5, 0x71, 0xd4, 0x14, 0x04, 0x93, 0x38,
11372
+	0x4e, 0x40, 0xc3, 0x90, 0xaa, 0x82, 0x2a, 0x8f, 0xa7, 0x02, 0xf3, 0x5f, 0x92, 0x00, 0x8d, 0x96,
11373
+	0xb5, 0xaf, 0xcd, 0xd7, 0x20, 0x7b, 0x44, 0x86, 0xae, 0x37, 0xb9, 0xea, 0x80, 0x4c, 0xf1, 0x15,
11374
+	0x4b, 0x19, 0xda, 0x95, 0x3a, 0x58, 0xeb, 0x4a, 0xde, 0x39, 0x3e, 0xf4, 0x29, 0x8f, 0x79, 0xa7,
11375
+	0x6c, 0x89, 0x4b, 0x2e, 0x20, 0x7e, 0xbc, 0xb0, 0xaa, 0x21, 0x5c, 0xef, 0x13, 0x4e, 0x4f, 0xc9,
11376
+	0x24, 0x8a, 0x67, 0xdd, 0x44, 0x8f, 0x05, 0x1f, 0x15, 0x65, 0x32, 0x75, 0x36, 0x32, 0xf2, 0x16,
11377
+	0xff, 0x36, 0x7f, 0xb0, 0x86, 0xab, 0xeb, 0x3b, 0xd6, 0x2e, 0x3d, 0x94, 0x77, 0xce, 0xb4, 0xeb,
11378
+	0x3b, 0x95, 0x83, 0x1f, 0xc3, 0xda, 0xdc, 0x3c, 0x5f, 0x21, 0xfc, 0x8d, 0xd6, 0xd3, 0x1f, 0x19,
11379
+	0x69, 0xfd, 0xf5, 0x3b, 0x46, 0xd6, 0xfc, 0xef, 0x04, 0x40, 0x8b, 0x05, 0xd1, 0xa6, 0x2d, 0x7f,
11380
+	0x60, 0xc9, 0xc9, 0xe7, 0x1a, 0x9b, 0x79, 0x3a, 0x3c, 0x97, 0x32, 0xde, 0xa9, 0x15, 0x41, 0x20,
11381
+	0x25, 0x1c, 0xc7, 0x8a, 0x68, 0x0b, 0x0a, 0x6a, 0xff, 0x7b, 0x23, 0x16, 0xa8, 0x5c, 0xb2, 0x86,
11382
+	0x41, 0x89, 0x84, 0xa6, 0xa8, 0xde, 0x47, 0xe3, 0x43, 0xcf, 0x0d, 0x07, 0xd4, 0x51, 0x98, 0xb4,
11383
+	0xc4, 0xac, 0xc5, 0x52, 0x01, 0x33, 0x6b, 0x90, 0x8b, 0xac, 0xa3, 0x0d, 0x48, 0x75, 0xaa, 0x2d,
11384
+	0x63, 0xa5, 0x74, 0xed, 0xec, 0xbc, 0x5c, 0x88, 0xc4, 0x9d, 0x6a, 0x4b, 0xf4, 0x74, 0x6b, 0x2d,
11385
+	0x23, 0x31, 0xdf, 0xd3, 0xad, 0xb5, 0x4a, 0x69, 0x71, 0xdf, 0x98, 0x7f, 0x95, 0x80, 0xac, 0x62,
11386
+	0x3f, 0x4b, 0x67, 0x6c, 0xc1, 0x6a, 0xc4, 0xc9, 0x15, 0x25, 0x7b, 0xff, 0xf5, 0xf4, 0xa9, 0xa2,
11387
+	0xd9, 0x8e, 0xda, 0xc7, 0x48, 0xaf, 0xf4, 0x19, 0x14, 0x67, 0x3b, 0xbe, 0xd3, 0x2e, 0xfe, 0x31,
11388
+	0x14, 0x44, 0xa0, 0x44, 0x34, 0x6a, 0x1b, 0xb2, 0x8a, 0xa1, 0xe9, 0xac, 0x72, 0x15, 0x97, 0xd3,
11389
+	0x48, 0xf4, 0x00, 0x56, 0x15, 0xff, 0x8b, 0x5e, 0x26, 0x36, 0xaf, 0x0e, 0x47, 0x1c, 0xc1, 0xcd,
11390
+	0xcf, 0x21, 0xdd, 0xa2, 0x34, 0x40, 0x77, 0x61, 0xd5, 0x67, 0x0e, 0x9d, 0x26, 0x51, 0x4d, 0x5d,
11391
+	0x1d, 0xda, 0xa8, 0x09, 0xea, 0xea, 0xd0, 0x86, 0x23, 0x16, 0x4f, 0x1c, 0xd0, 0xe8, 0x71, 0x46,
11392
+	0x7c, 0x9b, 0x1d, 0x28, 0x3e, 0xa3, 0x6e, 0x7f, 0xc0, 0xa9, 0x23, 0x0d, 0x7d, 0x08, 0xe9, 0x11,
11393
+	0x8d, 0x9d, 0xdf, 0x58, 0x1a, 0x3a, 0x94, 0x06, 0x58, 0xa2, 0xc4, 0x81, 0x3c, 0x95, 0xda, 0xfa,
11394
+	0x3d, 0x4c, 0xb7, 0xcc, 0xbf, 0x4f, 0xc2, 0x7a, 0x23, 0x0c, 0xc7, 0xc4, 0xb7, 0xa3, 0x1b, 0xf2,
11395
+	0x27, 0xf3, 0x37, 0xe4, 0xfd, 0xa5, 0x33, 0x9c, 0x53, 0x99, 0xaf, 0x97, 0x75, 0x92, 0x4c, 0xc6,
11396
+	0x49, 0xd2, 0xfc, 0x3a, 0x11, 0x15, 0xca, 0xf7, 0x66, 0xce, 0x4d, 0x69, 0xe3, 0xec, 0xbc, 0x7c,
11397
+	0x73, 0xd6, 0x12, 0xed, 0xfa, 0xc7, 0x3e, 0x3b, 0xf5, 0xd1, 0xbb, 0xa2, 0x70, 0x6e, 0xd6, 0x9f,
11398
+	0x19, 0x89, 0xd2, 0xad, 0xb3, 0xf3, 0x32, 0x9a, 0x03, 0x61, 0xea, 0xd3, 0x53, 0x61, 0xa9, 0x55,
11399
+	0x6f, 0xd6, 0xc4, 0x65, 0x96, 0x5c, 0x62, 0xa9, 0x45, 0x7d, 0xc7, 0xf5, 0xfb, 0xe8, 0x2e, 0x64,
11400
+	0x1b, 0xed, 0x76, 0x57, 0x96, 0x32, 0x6f, 0x9d, 0x9d, 0x97, 0x6f, 0xcc, 0xa1, 0x44, 0x83, 0x3a,
11401
+	0x02, 0x24, 0xa8, 0x56, 0xbd, 0x66, 0xa4, 0x97, 0x80, 0x04, 0xd3, 0xa0, 0x8e, 0x8e, 0xf0, 0x7f,
11402
+	0x4f, 0x82, 0x61, 0xd9, 0x36, 0x1d, 0x71, 0xd1, 0xaf, 0xe9, 0x6b, 0x07, 0x72, 0x23, 0xf1, 0xe5,
11403
+	0x4a, 0x3a, 0x2e, 0xc2, 0xe2, 0xc1, 0xd2, 0xc7, 0xd2, 0x05, 0xbd, 0x0a, 0x66, 0x1e, 0xb5, 0x9c,
11404
+	0xa1, 0x1b, 0x86, 0xa2, 0x4c, 0x93, 0x32, 0x1c, 0x5b, 0x2a, 0xfd, 0x32, 0x01, 0x37, 0x96, 0x20,
11405
+	0xd0, 0xc7, 0x90, 0x0e, 0x98, 0x17, 0x6d, 0xcf, 0x9d, 0xd7, 0x3d, 0x65, 0x08, 0x55, 0x2c, 0x91,
11406
+	0x68, 0x13, 0x80, 0x8c, 0x39, 0x23, 0x72, 0x7c, 0xb9, 0x31, 0x39, 0x3c, 0x23, 0x41, 0xcf, 0x20,
11407
+	0x1b, 0x52, 0x3b, 0xa0, 0x11, 0x17, 0xf9, 0xfc, 0xff, 0xeb, 0x7d, 0xa5, 0x2d, 0xcd, 0x60, 0x6d,
11408
+	0xae, 0x54, 0x81, 0xac, 0x92, 0x88, 0x88, 0x76, 0x08, 0x27, 0xd2, 0xe9, 0x22, 0x96, 0xdf, 0x22,
11409
+	0x50, 0x88, 0xd7, 0x8f, 0x02, 0x85, 0x78, 0x7d, 0xf3, 0x67, 0x49, 0x80, 0xfa, 0x73, 0x4e, 0x03,
11410
+	0x9f, 0x78, 0x55, 0x0b, 0xd5, 0x67, 0x32, 0xa4, 0x9a, 0xed, 0x0f, 0x96, 0x3e, 0x70, 0xc5, 0x1a,
11411
+	0x95, 0xaa, 0xb5, 0x24, 0x47, 0xde, 0x86, 0xd4, 0x38, 0xf0, 0xf4, 0x63, 0xa9, 0x24, 0x22, 0x5d,
11412
+	0xbc, 0x87, 0x85, 0x0c, 0xd5, 0xa7, 0x19, 0x29, 0xf5, 0xfa, 0x57, 0xee, 0x99, 0x01, 0x7e, 0xf3,
11413
+	0x59, 0xe9, 0x43, 0x80, 0xa9, 0xd7, 0x68, 0x13, 0x32, 0xd5, 0xdd, 0x76, 0x7b, 0xcf, 0x58, 0x51,
11414
+	0xd5, 0xd6, 0xb4, 0x4b, 0x8a, 0xcd, 0xbf, 0x4b, 0x40, 0xae, 0x6a, 0xe9, 0x5b, 0x65, 0x17, 0x0c,
11415
+	0x99, 0x4b, 0x6c, 0x1a, 0xf0, 0x1e, 0x7d, 0x3e, 0x72, 0x83, 0x89, 0x4e, 0x07, 0x57, 0xd7, 0x25,
11416
+	0xeb, 0x42, 0xab, 0x4a, 0x03, 0x5e, 0x97, 0x3a, 0x08, 0x43, 0x91, 0xea, 0x29, 0xf6, 0x6c, 0x12,
11417
+	0x25, 0xe7, 0xcd, 0xab, 0x97, 0x42, 0xb1, 0xbf, 0x69, 0x3b, 0xc4, 0x85, 0xc8, 0x48, 0x95, 0x84,
11418
+	0xe6, 0x53, 0xb8, 0x71, 0x10, 0xd8, 0x03, 0x1a, 0x72, 0x35, 0xa8, 0x76, 0xf9, 0x73, 0xb8, 0xc3,
11419
+	0x49, 0x78, 0xdc, 0x1b, 0xb8, 0x21, 0x67, 0xc1, 0xa4, 0x17, 0x50, 0x4e, 0x7d, 0xd1, 0xdf, 0x93,
11420
+	0x6f, 0xe9, 0xba, 0x9a, 0xbd, 0x2d, 0x30, 0x8f, 0x15, 0x04, 0x47, 0x88, 0x3d, 0x01, 0x30, 0x1b,
11421
+	0x50, 0x14, 0x84, 0xad, 0x46, 0x8f, 0xc8, 0xd8, 0xe3, 0x21, 0xfa, 0x31, 0x80, 0xc7, 0xfa, 0xbd,
11422
+	0x37, 0xce, 0xe4, 0x79, 0x8f, 0xf5, 0xd5, 0xa7, 0xf9, 0xfb, 0x60, 0xd4, 0xdc, 0x70, 0x44, 0xb8,
11423
+	0x3d, 0x88, 0xca, 0x74, 0xf4, 0x08, 0x8c, 0x01, 0x25, 0x01, 0x3f, 0xa4, 0x84, 0xf7, 0x46, 0x34,
11424
+	0x70, 0x99, 0xf3, 0x46, 0x4b, 0x7a, 0x2d, 0xd6, 0x6a, 0x49, 0x25, 0xf3, 0x57, 0x09, 0x00, 0x4c,
11425
+	0x8e, 0x22, 0x02, 0xf0, 0x43, 0xb8, 0x1e, 0xfa, 0x64, 0x14, 0x0e, 0x18, 0xef, 0xb9, 0x3e, 0xa7,
11426
+	0xc1, 0x09, 0xf1, 0x74, 0xa9, 0x65, 0x44, 0x1d, 0x0d, 0x2d, 0x47, 0x1f, 0x02, 0x3a, 0xa6, 0x74,
11427
+	0xd4, 0x63, 0x9e, 0xd3, 0x8b, 0x3a, 0xd5, 0x63, 0x7f, 0x1a, 0x1b, 0xa2, 0xe7, 0xc0, 0x73, 0xda,
11428
+	0x91, 0x1c, 0xed, 0xc0, 0xa6, 0x58, 0x01, 0xea, 0xf3, 0xc0, 0xa5, 0x61, 0xef, 0x88, 0x05, 0xbd,
11429
+	0xd0, 0x63, 0xa7, 0xbd, 0x23, 0xe6, 0x79, 0xec, 0x94, 0x06, 0x51, 0x21, 0x5b, 0xf2, 0x58, 0xbf,
11430
+	0xae, 0x40, 0xbb, 0x2c, 0x68, 0x7b, 0xec, 0x74, 0x37, 0x42, 0x08, 0x96, 0x30, 0x9d, 0x36, 0x77,
11431
+	0xed, 0xe3, 0x88, 0x25, 0xc4, 0xd2, 0x8e, 0x6b, 0x1f, 0xa3, 0xbb, 0xb0, 0x46, 0x3d, 0x2a, 0x4b,
11432
+	0x2e, 0x85, 0xca, 0x48, 0x54, 0x31, 0x12, 0x0a, 0x90, 0xf9, 0x5b, 0x90, 0x6f, 0x79, 0xc4, 0x96,
11433
+	0x7f, 0xa9, 0x88, 0xe2, 0xd2, 0x66, 0xbe, 0x08, 0x02, 0xd7, 0xe7, 0x2a, 0x3b, 0xe6, 0xf1, 0xac,
11434
+	0xc8, 0xfc, 0x09, 0xc0, 0x4f, 0x99, 0xeb, 0x77, 0xd8, 0x31, 0xf5, 0xe5, 0xeb, 0xb3, 0x60, 0xbd,
11435
+	0x7a, 0x2b, 0xf3, 0x58, 0xb7, 0x24, 0x27, 0x27, 0x3e, 0xe9, 0xd3, 0x20, 0x7e, 0x84, 0x55, 0x4d,
11436
+	0x71, 0xb9, 0x64, 0x31, 0x63, 0xbc, 0x6a, 0xa1, 0x32, 0x64, 0x6d, 0xd2, 0x8b, 0x4e, 0x5e, 0x71,
11437
+	0x27, 0x7f, 0x79, 0xb1, 0x95, 0xa9, 0x5a, 0x4f, 0xe8, 0x04, 0x67, 0x6c, 0xf2, 0x84, 0x4e, 0xc4,
11438
+	0xed, 0x6b, 0x13, 0x79, 0x5e, 0xa4, 0x99, 0xa2, 0xba, 0x7d, 0xab, 0x96, 0x38, 0x0c, 0x38, 0x6b,
11439
+	0x13, 0xf1, 0x8b, 0x3e, 0x86, 0xa2, 0x06, 0xf5, 0x06, 0x24, 0x1c, 0x28, 0xae, 0xba, 0xb3, 0x7e,
11440
+	0x79, 0xb1, 0x05, 0x0a, 0xf9, 0x98, 0x84, 0x03, 0x0c, 0x0a, 0x2d, 0xbe, 0x51, 0x1d, 0x0a, 0x5f,
11441
+	0x31, 0xd7, 0xef, 0x71, 0x39, 0x09, 0xfd, 0x36, 0xb0, 0xf4, 0xfc, 0x4c, 0xa7, 0xaa, 0x0b, 0x65,
11442
+	0xf8, 0x2a, 0x96, 0x98, 0xff, 0x9a, 0x80, 0x82, 0xb0, 0xe9, 0x1e, 0xb9, 0xb6, 0xb8, 0x2d, 0xbf,
11443
+	0x7b, 0xa6, 0xbf, 0x0d, 0x29, 0x3b, 0x0c, 0xf4, 0xdc, 0x64, 0xaa, 0xab, 0xb6, 0x31, 0x16, 0x32,
11444
+	0xf4, 0x05, 0x64, 0x55, 0x71, 0xa1, 0x93, 0xbc, 0xf9, 0xed, 0xf7, 0xba, 0x76, 0x51, 0xeb, 0xc9,
11445
+	0xbd, 0x9c, 0x7a, 0x27, 0x67, 0x59, 0xc4, 0xb3, 0x22, 0x74, 0x0b, 0x92, 0xb6, 0x2f, 0x83, 0x42,
11446
+	0xff, 0x2b, 0x55, 0x6d, 0xe2, 0xa4, 0xed, 0x9b, 0xff, 0x9c, 0x80, 0xb5, 0xba, 0x6f, 0x07, 0x13,
11447
+	0x99, 0x24, 0xc5, 0x46, 0xdc, 0x81, 0x7c, 0x38, 0x3e, 0x0c, 0x27, 0x21, 0xa7, 0xc3, 0xe8, 0xd1,
11448
+	0x3b, 0x16, 0xa0, 0x06, 0xe4, 0x89, 0xd7, 0x67, 0x81, 0xcb, 0x07, 0x43, 0xcd, 0x8d, 0x97, 0x27,
11449
+	0xe6, 0x59, 0x9b, 0x15, 0x2b, 0x52, 0xc1, 0x53, 0xed, 0x28, 0x15, 0xa7, 0xa4, 0xb3, 0x32, 0x15,
11450
+	0xbf, 0x0b, 0x45, 0x8f, 0x0c, 0x05, 0x15, 0xee, 0x89, 0x92, 0x4b, 0xce, 0x23, 0x8d, 0x0b, 0x5a,
11451
+	0x26, 0xca, 0x48, 0xd3, 0x84, 0x7c, 0x6c, 0x0c, 0x5d, 0x83, 0x82, 0x55, 0x6f, 0xf7, 0x3e, 0xd9,
11452
+	0x7e, 0xd0, 0x7b, 0x54, 0xdd, 0x37, 0x56, 0x34, 0x13, 0xf8, 0xc7, 0x04, 0xac, 0xed, 0xab, 0x18,
11453
+	0xd4, 0xc4, 0xe9, 0x2e, 0xac, 0x06, 0xe4, 0x88, 0x47, 0xd4, 0x2e, 0xad, 0x82, 0x4b, 0x24, 0x01,
11454
+	0x41, 0xed, 0x44, 0xd7, 0x72, 0x6a, 0x37, 0xf3, 0x97, 0x4b, 0xea, 0xca, 0xbf, 0x5c, 0xd2, 0xbf,
11455
+	0x91, 0xbf, 0x5c, 0x3e, 0xf8, 0x55, 0x0a, 0xf2, 0x71, 0xd1, 0x2b, 0x42, 0x46, 0x30, 0xad, 0x15,
11456
+	0xf5, 0x88, 0x14, 0xcb, 0x9b, 0x92, 0x63, 0xe5, 0xad, 0xbd, 0xbd, 0x83, 0xaa, 0xd5, 0xa9, 0xd7,
11457
+	0x8c, 0x2f, 0x14, 0x15, 0x8b, 0x01, 0x96, 0xe7, 0x31, 0xb1, 0xe9, 0x0e, 0x32, 0xa7, 0x54, 0xec,
11458
+	0x85, 0x7e, 0xaa, 0x8a, 0x51, 0x11, 0x0f, 0x7b, 0x0f, 0x72, 0x56, 0xbb, 0xdd, 0x78, 0xd4, 0xac,
11459
+	0xd7, 0x8c, 0x97, 0x89, 0xd2, 0xf7, 0xce, 0xce, 0xcb, 0xd7, 0xa7, 0xa6, 0xc2, 0xd0, 0xed, 0xfb,
11460
+	0xd4, 0x91, 0xa8, 0x6a, 0xb5, 0xde, 0x12, 0xe3, 0xbd, 0x48, 0x2e, 0xa2, 0x24, 0x01, 0x91, 0xcf,
11461
+	0xce, 0xf9, 0x16, 0xae, 0xb7, 0x2c, 0x2c, 0x46, 0x7c, 0x99, 0x5c, 0xf0, 0xab, 0x15, 0xd0, 0x11,
11462
+	0x09, 0xc4, 0x98, 0x9b, 0xd1, 0xdf, 0x2f, 0x2f, 0x52, 0xea, 0x69, 0x72, 0x5a, 0xe9, 0x53, 0xe2,
11463
+	0x4c, 0xc4, 0x68, 0xed, 0x8e, 0x85, 0xe5, 0x83, 0xc8, 0xcb, 0xd4, 0xc2, 0x68, 0x6d, 0x4e, 0x02,
11464
+	0x2e, 0xac, 0x98, 0xb0, 0x8a, 0xbb, 0xcd, 0xa6, 0x9c, 0x5d, 0x7a, 0x61, 0x76, 0x78, 0xec, 0xfb,
11465
+	0x02, 0x73, 0x0f, 0x72, 0xd1, 0x03, 0x8a, 0xf1, 0x32, 0xbd, 0xe0, 0x50, 0x35, 0x7a, 0xb9, 0x91,
11466
+	0x03, 0x3e, 0xee, 0x76, 0xe4, 0xbf, 0x43, 0x2f, 0x32, 0x8b, 0x03, 0x0e, 0xc6, 0xdc, 0x11, 0xe4,
11467
+	0xb7, 0x1c, 0xb3, 0xd1, 0x97, 0x19, 0x45, 0x02, 0x62, 0x8c, 0xa2, 0xa2, 0xc2, 0x0e, 0xae, 0xff,
11468
+	0x54, 0xfd, 0x91, 0xf4, 0x22, 0xbb, 0x60, 0x07, 0xd3, 0xaf, 0xa8, 0xcd, 0xa9, 0x33, 0x7d, 0x79,
11469
+	0x8d, 0xbb, 0x3e, 0xf8, 0x03, 0xc8, 0x45, 0x09, 0x03, 0x6d, 0x42, 0xf6, 0xd9, 0x01, 0x7e, 0x52,
11470
+	0xc7, 0xc6, 0x8a, 0x5a, 0x9d, 0xa8, 0xe7, 0x99, 0xca, 0xb8, 0x65, 0x58, 0xdd, 0xb7, 0x9a, 0xd6,
11471
+	0xa3, 0x3a, 0x8e, 0x5e, 0x7e, 0x23, 0x80, 0x8e, 0xfa, 0x92, 0xa1, 0x07, 0x88, 0x6d, 0xee, 0xdc,
11472
+	0xf9, 0xfa, 0x9b, 0xcd, 0x95, 0x5f, 0x7c, 0xb3, 0xb9, 0xf2, 0xcb, 0x6f, 0x36, 0x13, 0x2f, 0x2e,
11473
+	0x37, 0x13, 0x5f, 0x5f, 0x6e, 0x26, 0x7e, 0x7e, 0xb9, 0x99, 0xf8, 0x8f, 0xcb, 0xcd, 0xc4, 0x61,
11474
+	0x56, 0x32, 0xb2, 0x4f, 0xff, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x7d, 0xe8, 0x50, 0x18, 0x0a, 0x21,
11475
+	0x00, 0x00,
11473 11476
 }
... ...
@@ -407,6 +407,23 @@ message TaskStatus {
407 407
 	}
408 408
 }
409 409
 
410
+// NetworkAttachmentConfig specifies how a service should be attached to a particular network.
411
+//
412
+// For now, this is a simple struct, but this can include future information
413
+// instructing Swarm on how this service should work on the particular
414
+// network.
415
+message NetworkAttachmentConfig {
416
+	// Target specifies the target network for attachment. This value may be a
417
+	// network name or identifier. Only identifiers are supported at this time.
418
+	string target = 1;
419
+	// Aliases specifies a list of discoverable alternate names for the service on this Target.
420
+	repeated string aliases = 2;
421
+	// Addresses specifies a list of ipv4 and ipv6 addresses
422
+	// preferred. If these addresses are not available then the
423
+	// attachment might fail.
424
+	repeated string addresses = 3;
425
+}
426
+
410 427
 // IPAMConfig specifies parameters for IP Address Management.
411 428
 message IPAMConfig {
412 429
 	// TODO(stevvooe): It may make more sense to manage IPAM and network
... ...
@@ -28,7 +28,7 @@ import (
28 28
 	"github.com/docker/swarmkit/api"
29 29
 	"github.com/docker/swarmkit/identity"
30 30
 	"github.com/docker/swarmkit/ioutils"
31
-	"github.com/docker/swarmkit/picker"
31
+	"github.com/docker/swarmkit/remotes"
32 32
 	"golang.org/x/net/context"
33 33
 	"google.golang.org/grpc"
34 34
 	"google.golang.org/grpc/credentials"
... ...
@@ -155,7 +155,7 @@ func (rca *RootCA) IssueAndSaveNewCertificates(paths CertPaths, cn, ou, org stri
155 155
 
156 156
 // RequestAndSaveNewCertificates gets new certificates issued, either by signing them locally if a signer is
157 157
 // available, or by requesting them from the remote server at remoteAddr.
158
-func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, paths CertPaths, token string, picker *picker.Picker, transport credentials.TransportAuthenticator, nodeInfo chan<- api.IssueNodeCertificateResponse) (*tls.Certificate, error) {
158
+func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, paths CertPaths, token string, remotes remotes.Remotes, transport credentials.TransportAuthenticator, nodeInfo chan<- api.IssueNodeCertificateResponse) (*tls.Certificate, error) {
159 159
 	// Create a new key/pair and CSR for the new manager
160 160
 	// Write the new CSR and the new key to a temporary location so we can survive crashes on rotation
161 161
 	tempPaths := genTempPaths(paths)
... ...
@@ -170,7 +170,7 @@ func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, paths Cert
170 170
 	// responding properly (for example, it may have just been demoted).
171 171
 	var signedCert []byte
172 172
 	for i := 0; i != 5; i++ {
173
-		signedCert, err = GetRemoteSignedCertificate(ctx, csr, token, rca.Pool, picker, transport, nodeInfo)
173
+		signedCert, err = GetRemoteSignedCertificate(ctx, csr, token, rca.Pool, remotes, transport, nodeInfo)
174 174
 		if err == nil {
175 175
 			break
176 176
 		}
... ...
@@ -423,33 +423,38 @@ func GetLocalRootCA(baseDir string) (RootCA, error) {
423 423
 }
424 424
 
425 425
 // GetRemoteCA returns the remote endpoint's CA certificate
426
-func GetRemoteCA(ctx context.Context, d digest.Digest, picker *picker.Picker) (RootCA, error) {
427
-	// We need a valid picker to be able to Dial to a remote CA
428
-	if picker == nil {
429
-		return RootCA{}, fmt.Errorf("valid remote address picker required")
430
-	}
431
-
426
+func GetRemoteCA(ctx context.Context, d digest.Digest, r remotes.Remotes) (RootCA, error) {
432 427
 	// This TLS Config is intentionally using InsecureSkipVerify. Either we're
433 428
 	// doing TOFU, in which case we don't validate the remote CA, or we're using
434 429
 	// a user supplied hash to check the integrity of the CA certificate.
435 430
 	insecureCreds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})
436 431
 	opts := []grpc.DialOption{
437 432
 		grpc.WithTransportCredentials(insecureCreds),
438
-		grpc.WithBackoffMaxDelay(10 * time.Second),
439
-		grpc.WithPicker(picker)}
433
+		grpc.WithTimeout(5 * time.Second),
434
+		grpc.WithBackoffMaxDelay(5 * time.Second),
435
+	}
440 436
 
441
-	firstAddr, err := picker.PickAddr()
437
+	peer, err := r.Select()
442 438
 	if err != nil {
443 439
 		return RootCA{}, err
444 440
 	}
445 441
 
446
-	conn, err := grpc.Dial(firstAddr, opts...)
442
+	conn, err := grpc.Dial(peer.Addr, opts...)
447 443
 	if err != nil {
448 444
 		return RootCA{}, err
449 445
 	}
450 446
 	defer conn.Close()
451 447
 
452 448
 	client := api.NewCAClient(conn)
449
+	ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
450
+	defer cancel()
451
+	defer func() {
452
+		if err != nil {
453
+			r.Observe(peer, -remotes.DefaultObservationWeight)
454
+			return
455
+		}
456
+		r.Observe(peer, remotes.DefaultObservationWeight)
457
+	}()
453 458
 	response, err := client.GetRootCACertificate(ctx, &api.GetRootCACertificateRequest{})
454 459
 	if err != nil {
455 460
 		return RootCA{}, err
... ...
@@ -596,16 +601,12 @@ func GenerateAndWriteNewKey(paths CertPaths) (csr, key []byte, err error) {
596 596
 	return
597 597
 }
598 598
 
599
-// GetRemoteSignedCertificate submits a CSR to a remote CA server address
600
-// available through a picker, and that is part of a CA identified by a
601
-// specific certificate pool.
602
-func GetRemoteSignedCertificate(ctx context.Context, csr []byte, token string, rootCAPool *x509.CertPool, picker *picker.Picker, creds credentials.TransportAuthenticator, nodeInfo chan<- api.IssueNodeCertificateResponse) ([]byte, error) {
599
+// GetRemoteSignedCertificate submits a CSR to a remote CA server address,
600
+// and that is part of a CA identified by a specific certificate pool.
601
+func GetRemoteSignedCertificate(ctx context.Context, csr []byte, token string, rootCAPool *x509.CertPool, r remotes.Remotes, creds credentials.TransportAuthenticator, nodeInfo chan<- api.IssueNodeCertificateResponse) ([]byte, error) {
603 602
 	if rootCAPool == nil {
604 603
 		return nil, fmt.Errorf("valid root CA pool required")
605 604
 	}
606
-	if picker == nil {
607
-		return nil, fmt.Errorf("valid remote address picker required")
608
-	}
609 605
 
610 606
 	if creds == nil {
611 607
 		// This is our only non-MTLS request, and it happens when we are boostraping our TLS certs
... ...
@@ -613,17 +614,18 @@ func GetRemoteSignedCertificate(ctx context.Context, csr []byte, token string, r
613 613
 		creds = credentials.NewTLS(&tls.Config{ServerName: CARole, RootCAs: rootCAPool})
614 614
 	}
615 615
 
616
-	opts := []grpc.DialOption{
617
-		grpc.WithTransportCredentials(creds),
618
-		grpc.WithBackoffMaxDelay(10 * time.Second),
619
-		grpc.WithPicker(picker)}
620
-
621
-	firstAddr, err := picker.PickAddr()
616
+	peer, err := r.Select()
622 617
 	if err != nil {
623 618
 		return nil, err
624 619
 	}
625 620
 
626
-	conn, err := grpc.Dial(firstAddr, opts...)
621
+	opts := []grpc.DialOption{
622
+		grpc.WithTransportCredentials(creds),
623
+		grpc.WithTimeout(5 * time.Second),
624
+		grpc.WithBackoffMaxDelay(5 * time.Second),
625
+	}
626
+
627
+	conn, err := grpc.Dial(peer.Addr, opts...)
627 628
 	if err != nil {
628 629
 		return nil, err
629 630
 	}
... ...
@@ -655,8 +657,11 @@ func GetRemoteSignedCertificate(ctx context.Context, csr []byte, token string, r
655 655
 	// Exponential backoff with Max of 30 seconds to wait for a new retry
656 656
 	for {
657 657
 		// Send the Request and retrieve the certificate
658
+		ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
659
+		defer cancel()
658 660
 		statusResponse, err := caClient.NodeCertificateStatus(ctx, statusRequest)
659 661
 		if err != nil {
662
+			r.Observe(peer, -remotes.DefaultObservationWeight)
660 663
 			return nil, err
661 664
 		}
662 665
 
... ...
@@ -672,6 +677,7 @@ func GetRemoteSignedCertificate(ctx context.Context, csr []byte, token string, r
672 672
 			// retry until the certificate gets updated per our
673 673
 			// current request.
674 674
 			if bytes.Equal(statusResponse.Certificate.CSR, csr) {
675
+				r.Observe(peer, remotes.DefaultObservationWeight)
675 676
 				return statusResponse.Certificate.Certificate, nil
676 677
 			}
677 678
 		}
... ...
@@ -20,7 +20,7 @@ import (
20 20
 	"github.com/docker/distribution/digest"
21 21
 	"github.com/docker/swarmkit/api"
22 22
 	"github.com/docker/swarmkit/identity"
23
-	"github.com/docker/swarmkit/picker"
23
+	"github.com/docker/swarmkit/remotes"
24 24
 
25 25
 	"golang.org/x/net/context"
26 26
 )
... ...
@@ -183,7 +183,7 @@ func getCAHashFromToken(token string) (digest.Digest, error) {
183 183
 // LoadOrCreateSecurityConfig encapsulates the security logic behind joining a cluster.
184 184
 // Every node requires at least a set of TLS certificates with which to join the cluster with.
185 185
 // In the case of a manager, these certificates will be used both for client and server credentials.
186
-func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, token, proposedRole string, picker *picker.Picker, nodeInfo chan<- api.IssueNodeCertificateResponse) (*SecurityConfig, error) {
186
+func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, token, proposedRole string, remotes remotes.Remotes, nodeInfo chan<- api.IssueNodeCertificateResponse) (*SecurityConfig, error) {
187 187
 	paths := NewConfigPaths(baseCertDir)
188 188
 
189 189
 	var (
... ...
@@ -217,7 +217,7 @@ func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, token, propose
217 217
 		// just been demoted, for example).
218 218
 
219 219
 		for i := 0; i != 5; i++ {
220
-			rootCA, err = GetRemoteCA(ctx, d, picker)
220
+			rootCA, err = GetRemoteCA(ctx, d, remotes)
221 221
 			if err == nil {
222 222
 				break
223 223
 			}
... ...
@@ -267,7 +267,7 @@ func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, token, propose
267 267
 		} else {
268 268
 			// There was an error loading our Credentials, let's get a new certificate issued
269 269
 			// Last argument is nil because at this point we don't have any valid TLS creds
270
-			tlsKeyPair, err = rootCA.RequestAndSaveNewCertificates(ctx, paths.Node, token, picker, nil, nodeInfo)
270
+			tlsKeyPair, err = rootCA.RequestAndSaveNewCertificates(ctx, paths.Node, token, remotes, nil, nodeInfo)
271 271
 			if err != nil {
272 272
 				return nil, err
273 273
 			}
... ...
@@ -300,7 +300,7 @@ func LoadOrCreateSecurityConfig(ctx context.Context, baseCertDir, token, propose
300 300
 
301 301
 // RenewTLSConfig will continuously monitor for the necessity of renewing the local certificates, either by
302 302
 // issuing them locally if key-material is available, or requesting them from a remote CA.
303
-func RenewTLSConfig(ctx context.Context, s *SecurityConfig, baseCertDir string, picker *picker.Picker, renew <-chan struct{}) <-chan CertificateUpdate {
303
+func RenewTLSConfig(ctx context.Context, s *SecurityConfig, baseCertDir string, remotes remotes.Remotes, renew <-chan struct{}) <-chan CertificateUpdate {
304 304
 	paths := NewConfigPaths(baseCertDir)
305 305
 	updates := make(chan CertificateUpdate)
306 306
 
... ...
@@ -344,7 +344,7 @@ func RenewTLSConfig(ctx context.Context, s *SecurityConfig, baseCertDir string,
344 344
 			tlsKeyPair, err := rootCA.RequestAndSaveNewCertificates(ctx,
345 345
 				paths.Node,
346 346
 				"",
347
-				picker,
347
+				remotes,
348 348
 				s.ClientTLSCreds,
349 349
 				nil)
350 350
 			if err != nil {
... ...
@@ -165,7 +165,7 @@ func (a *Allocator) doNetworkInit(ctx context.Context) error {
165 165
 		nodes, err = store.FindNodes(tx, store.All)
166 166
 	})
167 167
 	if err != nil {
168
-		return fmt.Errorf("error listing all services in store while trying to allocate during init: %v", err)
168
+		return fmt.Errorf("error listing all nodes in store while trying to allocate during init: %v", err)
169 169
 	}
170 170
 
171 171
 	for _, node := range nodes {
... ...
@@ -420,9 +420,9 @@ func taskUpdateEndpoint(t *api.Task, endpoint *api.Endpoint) {
420 420
 }
421 421
 
422 422
 func (a *Allocator) taskCreateNetworkAttachments(t *api.Task, s *api.Service) {
423
-	// If service is nil or if task network attachments have
424
-	// already been filled in no need to do anything else.
425
-	if s == nil || len(t.Networks) != 0 {
423
+	// If task network attachments have already been filled in no
424
+	// need to do anything else.
425
+	if len(t.Networks) != 0 {
426 426
 		return
427 427
 	}
428 428
 
... ...
@@ -431,19 +431,31 @@ func (a *Allocator) taskCreateNetworkAttachments(t *api.Task, s *api.Service) {
431 431
 	// The service to which this task belongs is trying to expose
432 432
 	// ports to the external world. Automatically attach the task
433 433
 	// to the ingress network.
434
-	if s.Spec.Endpoint != nil && len(s.Spec.Endpoint.Ports) != 0 {
434
+	if s != nil && s.Spec.Endpoint != nil && len(s.Spec.Endpoint.Ports) != 0 {
435 435
 		networks = append(networks, &api.NetworkAttachment{Network: a.netCtx.ingressNetwork})
436 436
 	}
437 437
 
438 438
 	a.store.View(func(tx store.ReadTx) {
439
-		for _, na := range s.Spec.Networks {
439
+		// Always prefer NetworkAttachmentConfig in the TaskSpec
440
+		specNetworks := t.Spec.Networks
441
+		if len(specNetworks) == 0 && s != nil && len(s.Spec.Networks) != 0 {
442
+			specNetworks = s.Spec.Networks
443
+		}
444
+
445
+		for _, na := range specNetworks {
440 446
 			n := store.GetNetwork(tx, na.Target)
441 447
 			if n != nil {
442 448
 				var aliases []string
449
+				var addresses []string
450
+
443 451
 				for _, a := range na.Aliases {
444 452
 					aliases = append(aliases, a)
445 453
 				}
446
-				networks = append(networks, &api.NetworkAttachment{Network: n, Aliases: aliases})
454
+				for _, a := range na.Addresses {
455
+					addresses = append(addresses, a)
456
+				}
457
+
458
+				networks = append(networks, &api.NetworkAttachment{Network: n, Aliases: aliases, Addresses: addresses})
447 459
 			}
448 460
 		}
449 461
 	})
... ...
@@ -508,12 +520,12 @@ func (a *Allocator) doTaskAlloc(ctx context.Context, nc *networkContext, ev even
508 508
 				return
509 509
 			}
510 510
 		}
511
-
512
-		// Populate network attachments in the task
513
-		// based on service spec.
514
-		a.taskCreateNetworkAttachments(t, s)
515 511
 	}
516 512
 
513
+	// Populate network attachments in the task
514
+	// based on service spec.
515
+	a.taskCreateNetworkAttachments(t, s)
516
+
517 517
 	nc.unallocatedTasks[t.ID] = t
518 518
 }
519 519
 
... ...
@@ -197,8 +197,14 @@ func (na *NetworkAllocator) ServiceAllocate(s *api.Service) (err error) {
197 197
 		}
198 198
 	}
199 199
 
200
+	// Always prefer NetworkAttachmentConfig in the TaskSpec
201
+	specNetworks := s.Spec.Task.Networks
202
+	if len(specNetworks) == 0 && s != nil && len(s.Spec.Networks) != 0 {
203
+		specNetworks = s.Spec.Networks
204
+	}
205
+
200 206
 outer:
201
-	for _, nAttach := range s.Spec.Networks {
207
+	for _, nAttach := range specNetworks {
202 208
 		for _, vip := range s.Endpoint.VirtualIPs {
203 209
 			if vip.NetworkID == nAttach.Target {
204 210
 				continue outer
... ...
@@ -286,7 +292,7 @@ func (na *NetworkAllocator) IsTaskAllocated(t *api.Task) bool {
286 286
 func (na *NetworkAllocator) IsServiceAllocated(s *api.Service) bool {
287 287
 	// If endpoint mode is VIP and allocator does not have the
288 288
 	// service in VIP allocated set then it is not allocated.
289
-	if len(s.Spec.Networks) != 0 &&
289
+	if (len(s.Spec.Task.Networks) != 0 || len(s.Spec.Networks) != 0) &&
290 290
 		(s.Spec.Endpoint == nil ||
291 291
 			s.Spec.Endpoint.Mode == api.ResolutionModeVirtualIP) {
292 292
 		if _, ok := na.services[s.ID]; !ok {
... ...
@@ -527,7 +533,11 @@ func (na *NetworkAllocator) allocateNetworkIPs(nAttach *api.NetworkAttachment) e
527 527
 			var err error
528 528
 			addr, _, err = net.ParseCIDR(rawAddr)
529 529
 			if err != nil {
530
-				return err
530
+				addr = net.ParseIP(rawAddr)
531
+
532
+				if addr == nil {
533
+					return fmt.Errorf("could not parse address string %s: %v", rawAddr, err)
534
+				}
531 535
 			}
532 536
 		}
533 537
 
... ...
@@ -171,7 +171,12 @@ func (s *Server) RemoveNetwork(ctx context.Context, request *api.RemoveNetworkRe
171 171
 	}
172 172
 
173 173
 	for _, s := range services {
174
-		for _, na := range s.Spec.Networks {
174
+		specNetworks := s.Spec.Task.Networks
175
+		if len(specNetworks) == 0 {
176
+			specNetworks = s.Spec.Networks
177
+		}
178
+
179
+		for _, na := range specNetworks {
175 180
 			if na.Target == request.NetworkID {
176 181
 				return nil, grpc.Errorf(codes.FailedPrecondition, "network %s is in use", request.NetworkID)
177 182
 			}
... ...
@@ -327,8 +327,20 @@ func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRe
327 327
 			return nil
328 328
 		}
329 329
 		// temporary disable network update
330
-		if request.Spec != nil && !reflect.DeepEqual(request.Spec.Networks, service.Spec.Networks) {
331
-			return errNetworkUpdateNotSupported
330
+		if request.Spec != nil {
331
+			requestSpecNetworks := request.Spec.Task.Networks
332
+			if len(requestSpecNetworks) == 0 {
333
+				requestSpecNetworks = request.Spec.Networks
334
+			}
335
+
336
+			specNetworks := service.Spec.Task.Networks
337
+			if len(specNetworks) == 0 {
338
+				specNetworks = service.Spec.Networks
339
+			}
340
+
341
+			if !reflect.DeepEqual(requestSpecNetworks, specNetworks) {
342
+				return errNetworkUpdateNotSupported
343
+			}
332 344
 		}
333 345
 
334 346
 		// orchestrator is designed to be stateless, so it should not deal
... ...
@@ -19,8 +19,8 @@ import (
19 19
 	"github.com/docker/swarmkit/manager/state"
20 20
 	"github.com/docker/swarmkit/manager/state/store"
21 21
 	"github.com/docker/swarmkit/manager/state/watch"
22
-	"github.com/docker/swarmkit/picker"
23 22
 	"github.com/docker/swarmkit/protobuf/ptypes"
23
+	"github.com/docker/swarmkit/remotes"
24 24
 	"golang.org/x/net/context"
25 25
 )
26 26
 
... ...
@@ -153,7 +153,7 @@ func getWeightedPeers(cluster Cluster) []*api.WeightedPeer {
153 153
 			// TODO(stevvooe): Calculate weight of manager selection based on
154 154
 			// cluster-level observations, such as number of connections and
155 155
 			// load.
156
-			Weight: picker.DefaultObservationWeight,
156
+			Weight: remotes.DefaultObservationWeight,
157 157
 		})
158 158
 	}
159 159
 	return mgrs
... ...
@@ -209,7 +209,7 @@ func (d *Dispatcher) Run(ctx context.Context) error {
209 209
 		for _, p := range peers {
210 210
 			mgrs = append(mgrs, &api.WeightedPeer{
211 211
 				Peer:   p,
212
-				Weight: picker.DefaultObservationWeight,
212
+				Weight: remotes.DefaultObservationWeight,
213 213
 			})
214 214
 		}
215 215
 		d.mu.Lock()
... ...
@@ -854,7 +854,7 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
854 854
 
855 855
 	for {
856 856
 		// After each message send, we need to check the nodes sessionID hasn't
857
-		// changed. If it has, we will the stream and make the node
857
+		// changed. If it has, we will shut down the stream and make the node
858 858
 		// re-register.
859 859
 		node, err := d.nodes.GetWithSession(nodeID, sessionID)
860 860
 		if err != nil {
... ...
@@ -86,7 +86,7 @@ func (s *nodeStore) AddUnknown(n *api.Node, expireFunc func()) error {
86 86
 	return nil
87 87
 }
88 88
 
89
-// CheckRateLimit returs error if node with specified id is allowed to re-register
89
+// CheckRateLimit returns error if node with specified id is allowed to re-register
90 90
 // again.
91 91
 func (s *nodeStore) CheckRateLimit(id string) error {
92 92
 	s.mu.Lock()
... ...
@@ -24,6 +24,7 @@ import (
24 24
 	"github.com/docker/swarmkit/manager/keymanager"
25 25
 	"github.com/docker/swarmkit/manager/orchestrator"
26 26
 	"github.com/docker/swarmkit/manager/raftpicker"
27
+	"github.com/docker/swarmkit/manager/resourceapi"
27 28
 	"github.com/docker/swarmkit/manager/scheduler"
28 29
 	"github.com/docker/swarmkit/manager/state/raft"
29 30
 	"github.com/docker/swarmkit/manager/state/store"
... ...
@@ -275,9 +276,12 @@ func (m *Manager) Run(parent context.Context) error {
275 275
 	}
276 276
 
277 277
 	baseControlAPI := controlapi.NewServer(m.RaftNode.MemoryStore(), m.RaftNode, m.config.SecurityConfig.RootCA())
278
+	baseResourceAPI := resourceapi.New(m.RaftNode.MemoryStore())
278 279
 	healthServer := health.NewHealthServer()
280
+	localHealthServer := health.NewHealthServer()
279 281
 
280 282
 	authenticatedControlAPI := api.NewAuthenticatedWrapperControlServer(baseControlAPI, authorize)
283
+	authenticatedResourceAPI := api.NewAuthenticatedWrapperResourceAllocatorServer(baseResourceAPI, authorize)
281 284
 	authenticatedDispatcherAPI := api.NewAuthenticatedWrapperDispatcherServer(m.Dispatcher, authorize)
282 285
 	authenticatedCAAPI := api.NewAuthenticatedWrapperCAServer(m.caserver, authorize)
283 286
 	authenticatedNodeCAAPI := api.NewAuthenticatedWrapperNodeCAServer(m.caserver, authorize)
... ...
@@ -289,6 +293,7 @@ func (m *Manager) Run(parent context.Context) error {
289 289
 	proxyCAAPI := api.NewRaftProxyCAServer(authenticatedCAAPI, cs, m.RaftNode, ca.WithMetadataForwardTLSInfo)
290 290
 	proxyNodeCAAPI := api.NewRaftProxyNodeCAServer(authenticatedNodeCAAPI, cs, m.RaftNode, ca.WithMetadataForwardTLSInfo)
291 291
 	proxyRaftMembershipAPI := api.NewRaftProxyRaftMembershipServer(authenticatedRaftMembershipAPI, cs, m.RaftNode, ca.WithMetadataForwardTLSInfo)
292
+	proxyResourceAPI := api.NewRaftProxyResourceAllocatorServer(authenticatedResourceAPI, cs, m.RaftNode, ca.WithMetadataForwardTLSInfo)
292 293
 
293 294
 	// localProxyControlAPI is a special kind of proxy. It is only wired up
294 295
 	// to receive requests from a trusted local socket, and these requests
... ...
@@ -306,10 +311,13 @@ func (m *Manager) Run(parent context.Context) error {
306 306
 	api.RegisterRaftServer(m.server, authenticatedRaftAPI)
307 307
 	api.RegisterHealthServer(m.server, authenticatedHealthAPI)
308 308
 	api.RegisterRaftMembershipServer(m.server, proxyRaftMembershipAPI)
309
-	api.RegisterControlServer(m.localserver, localProxyControlAPI)
310 309
 	api.RegisterControlServer(m.server, authenticatedControlAPI)
310
+	api.RegisterResourceAllocatorServer(m.server, proxyResourceAPI)
311 311
 	api.RegisterDispatcherServer(m.server, proxyDispatcherAPI)
312 312
 
313
+	api.RegisterControlServer(m.localserver, localProxyControlAPI)
314
+	api.RegisterHealthServer(m.localserver, localHealthServer)
315
+
313 316
 	errServe := make(chan error, 2)
314 317
 	for proto, l := range m.listeners {
315 318
 		go m.serveListener(ctx, errServe, proto, l)
... ...
@@ -317,11 +325,14 @@ func (m *Manager) Run(parent context.Context) error {
317 317
 
318 318
 	// Set the raft server as serving for the health server
319 319
 	healthServer.SetServingStatus("Raft", api.HealthCheckResponse_SERVING)
320
+	localHealthServer.SetServingStatus("ControlAPI", api.HealthCheckResponse_SERVING)
321
+
322
+	defer func() {
323
+		m.server.Stop()
324
+		m.localserver.Stop()
325
+	}()
320 326
 
321 327
 	if err := m.RaftNode.JoinAndStart(); err != nil {
322
-		for _, lis := range m.listeners {
323
-			lis.Close()
324
-		}
325 328
 		return fmt.Errorf("can't initialize raft node: %v", err)
326 329
 	}
327 330
 
... ...
@@ -336,13 +347,11 @@ func (m *Manager) Run(parent context.Context) error {
336 336
 	}()
337 337
 
338 338
 	if err := raft.WaitForLeader(ctx, m.RaftNode); err != nil {
339
-		m.server.Stop()
340 339
 		return err
341 340
 	}
342 341
 
343 342
 	c, err := raft.WaitForCluster(ctx, m.RaftNode)
344 343
 	if err != nil {
345
-		m.server.Stop()
346 344
 		return err
347 345
 	}
348 346
 	raftConfig := c.Spec.Raft
... ...
@@ -527,29 +536,31 @@ func (m *Manager) rotateRootCAKEK(ctx context.Context, clusterID string) error {
527 527
 
528 528
 }
529 529
 
530
-// handleLeadershipEvents reads out and discards all of the messages when the manager is stopped,
531
-// otherwise it handles the is leader event or is follower event.
530
+// handleLeadershipEvents handles the is leader event or is follower event.
532 531
 func (m *Manager) handleLeadershipEvents(ctx context.Context, leadershipCh chan events.Event) {
533
-	for leadershipEvent := range leadershipCh {
534
-		// read out and discard all of the messages when we've stopped
535
-		// don't acquire the mutex yet. if stopped is closed, we don't need
536
-		// this stops this loop from starving Run()'s attempt to Lock
532
+	for {
537 533
 		select {
538
-		case <-m.stopped:
539
-			continue
540
-		default:
541
-			// do nothing, we're not stopped
542
-		}
543
-		// we're not stopping so NOW acquire the mutex
544
-		m.mu.Lock()
545
-		newState := leadershipEvent.(raft.LeadershipState)
534
+		case leadershipEvent := <-leadershipCh:
535
+			m.mu.Lock()
536
+			select {
537
+			case <-m.stopped:
538
+				m.mu.Unlock()
539
+				return
540
+			default:
541
+			}
542
+			newState := leadershipEvent.(raft.LeadershipState)
546 543
 
547
-		if newState == raft.IsLeader {
548
-			m.becomeLeader(ctx)
549
-		} else if newState == raft.IsFollower {
550
-			m.becomeFollower()
544
+			if newState == raft.IsLeader {
545
+				m.becomeLeader(ctx)
546
+			} else if newState == raft.IsFollower {
547
+				m.becomeFollower()
548
+			}
549
+			m.mu.Unlock()
550
+		case <-m.stopped:
551
+			return
552
+		case <-ctx.Done():
553
+			return
551 554
 		}
552
-		m.mu.Unlock()
553 555
 	}
554 556
 }
555 557
 
... ...
@@ -609,7 +620,7 @@ func (m *Manager) becomeLeader(ctx context.Context) {
609 609
 	m.globalOrchestrator = orchestrator.NewGlobalOrchestrator(s)
610 610
 	m.taskReaper = orchestrator.NewTaskReaper(s)
611 611
 	m.scheduler = scheduler.New(s)
612
-	m.keyManager = keymanager.New(m.RaftNode.MemoryStore(), keymanager.DefaultConfig())
612
+	m.keyManager = keymanager.New(s, keymanager.DefaultConfig())
613 613
 
614 614
 	// TODO(stevvooe): Allocate a context that can be used to
615 615
 	// shutdown underlying manager processes when leadership is
... ...
@@ -288,16 +288,8 @@ func (u *Updater) updateTask(ctx context.Context, slot slot, updated *api.Task)
288 288
 			return err
289 289
 		}
290 290
 
291
-		u.removeOldTasks(ctx, batch, slot)
292
-
293
-		for _, t := range slot {
294
-			if t.DesiredState == api.TaskStateRunning {
295
-				// Wait for the old task to stop or time out, and then set the new one
296
-				// to RUNNING.
297
-				delayStartCh = u.restarts.DelayStart(ctx, nil, t, updated.ID, 0, true)
298
-				break
299
-			}
300
-		}
291
+		oldTask := u.removeOldTasks(ctx, batch, slot)
292
+		delayStartCh = u.restarts.DelayStart(ctx, nil, oldTask, updated.ID, 0, true)
301 293
 
302 294
 		return nil
303 295
 
... ...
@@ -333,34 +325,29 @@ func (u *Updater) useExistingTask(ctx context.Context, slot slot, existing *api.
333 333
 		}
334 334
 	}
335 335
 	if len(removeTasks) != 0 || existing.DesiredState != api.TaskStateRunning {
336
+		var delayStartCh <-chan struct{}
336 337
 		_, err := u.store.Batch(func(batch *store.Batch) error {
337
-			u.removeOldTasks(ctx, batch, removeTasks)
338
+			oldTask := u.removeOldTasks(ctx, batch, removeTasks)
338 339
 
339 340
 			if existing.DesiredState != api.TaskStateRunning {
340
-				err := batch.Update(func(tx store.Tx) error {
341
-					t := store.GetTask(tx, existing.ID)
342
-					if t == nil {
343
-						return fmt.Errorf("task %s not found while trying to start it", existing.ID)
344
-					}
345
-					if t.DesiredState >= api.TaskStateRunning {
346
-						return fmt.Errorf("task %s was already started when reached by updater", existing.ID)
347
-					}
348
-					t.DesiredState = api.TaskStateRunning
349
-					return store.UpdateTask(tx, t)
350
-				})
351
-				if err != nil {
352
-					log.G(ctx).WithError(err).Errorf("starting task %s failed", existing.ID)
353
-				}
341
+				delayStartCh = u.restarts.DelayStart(ctx, nil, oldTask, existing.ID, 0, true)
354 342
 			}
355 343
 			return nil
356 344
 		})
357 345
 		if err != nil {
358 346
 			log.G(ctx).WithError(err).Error("updater batch transaction failed")
359 347
 		}
348
+
349
+		if delayStartCh != nil {
350
+			<-delayStartCh
351
+		}
360 352
 	}
361 353
 }
362 354
 
363
-func (u *Updater) removeOldTasks(ctx context.Context, batch *store.Batch, removeTasks []*api.Task) {
355
+// removeOldTasks shuts down the given tasks and returns one of the tasks that
356
+// was shut down, or nil.
357
+func (u *Updater) removeOldTasks(ctx context.Context, batch *store.Batch, removeTasks []*api.Task) *api.Task {
358
+	var removedTask *api.Task
364 359
 	for _, original := range removeTasks {
365 360
 		err := batch.Update(func(tx store.Tx) error {
366 361
 			t := store.GetTask(tx, original.ID)
... ...
@@ -375,8 +362,12 @@ func (u *Updater) removeOldTasks(ctx context.Context, batch *store.Batch, remove
375 375
 		})
376 376
 		if err != nil {
377 377
 			log.G(ctx).WithError(err).Errorf("shutting down stale task %s failed", original.ID)
378
+		} else {
379
+			removedTask = original
378 380
 		}
379 381
 	}
382
+
383
+	return removedTask
380 384
 }
381 385
 
382 386
 func (u *Updater) isTaskDirty(t *api.Task) bool {
383 387
new file mode 100644
... ...
@@ -0,0 +1,124 @@
0
+package resourceapi
1
+
2
+import (
3
+	"errors"
4
+	"time"
5
+
6
+	"github.com/docker/swarmkit/api"
7
+	"github.com/docker/swarmkit/ca"
8
+	"github.com/docker/swarmkit/identity"
9
+	"github.com/docker/swarmkit/manager/state/store"
10
+	"github.com/docker/swarmkit/protobuf/ptypes"
11
+	"golang.org/x/net/context"
12
+	"google.golang.org/grpc"
13
+	"google.golang.org/grpc/codes"
14
+)
15
+
16
+var (
17
+	errInvalidArgument = errors.New("invalid argument")
18
+)
19
+
20
+// ResourceAllocator handles resource allocation of cluster entities.
21
+type ResourceAllocator struct {
22
+	store *store.MemoryStore
23
+}
24
+
25
+// New returns an instance of the allocator
26
+func New(store *store.MemoryStore) *ResourceAllocator {
27
+	return &ResourceAllocator{store: store}
28
+}
29
+
30
+// AttachNetwork allows the node to request the resources
31
+// allocation needed for a network attachment on the specific node.
32
+// - Returns `InvalidArgument` if the Spec is malformed.
33
+// - Returns `NotFound` if the Network is not found.
34
+// - Returns `PermissionDenied` if the Network is not manually attachable.
35
+// - Returns an error if the creation fails.
36
+func (ra *ResourceAllocator) AttachNetwork(ctx context.Context, request *api.AttachNetworkRequest) (*api.AttachNetworkResponse, error) {
37
+	nodeInfo, err := ca.RemoteNode(ctx)
38
+	if err != nil {
39
+		return nil, err
40
+	}
41
+
42
+	var network *api.Network
43
+	ra.store.View(func(tx store.ReadTx) {
44
+		network = store.GetNetwork(tx, request.Config.Target)
45
+		if network == nil {
46
+			if networks, err := store.FindNetworks(tx, store.ByName(request.Config.Target)); err == nil && len(networks) == 1 {
47
+				network = networks[0]
48
+			}
49
+		}
50
+	})
51
+	if network == nil {
52
+		return nil, grpc.Errorf(codes.NotFound, "network %s not found", request.Config.Target)
53
+	}
54
+
55
+	if !network.Spec.Attachable {
56
+		return nil, grpc.Errorf(codes.PermissionDenied, "network %s not manually attachable", request.Config.Target)
57
+	}
58
+
59
+	t := &api.Task{
60
+		ID:     identity.NewID(),
61
+		NodeID: nodeInfo.NodeID,
62
+		Spec: api.TaskSpec{
63
+			Runtime: &api.TaskSpec_Attachment{
64
+				Attachment: &api.NetworkAttachmentSpec{
65
+					ContainerID: request.ContainerID,
66
+				},
67
+			},
68
+			Networks: []*api.NetworkAttachmentConfig{
69
+				{
70
+					Target:    network.ID,
71
+					Addresses: request.Config.Addresses,
72
+				},
73
+			},
74
+		},
75
+		Status: api.TaskStatus{
76
+			State:     api.TaskStateNew,
77
+			Timestamp: ptypes.MustTimestampProto(time.Now()),
78
+			Message:   "created",
79
+		},
80
+		DesiredState: api.TaskStateRunning,
81
+		// TODO: Add Network attachment.
82
+	}
83
+
84
+	if err := ra.store.Update(func(tx store.Tx) error {
85
+		return store.CreateTask(tx, t)
86
+	}); err != nil {
87
+		return nil, err
88
+	}
89
+
90
+	return &api.AttachNetworkResponse{AttachmentID: t.ID}, nil
91
+}
92
+
93
+// DetachNetwork allows the node to request the release of
94
+// the resources associated to the network attachment.
95
+// - Returns `InvalidArgument` if attachment ID is not provided.
96
+// - Returns `NotFound` if the attachment is not found.
97
+// - Returns an error if the deletion fails.
98
+func (ra *ResourceAllocator) DetachNetwork(ctx context.Context, request *api.DetachNetworkRequest) (*api.DetachNetworkResponse, error) {
99
+	if request.AttachmentID == "" {
100
+		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
101
+	}
102
+
103
+	nodeInfo, err := ca.RemoteNode(ctx)
104
+	if err != nil {
105
+		return nil, err
106
+	}
107
+
108
+	if err := ra.store.Update(func(tx store.Tx) error {
109
+		t := store.GetTask(tx, request.AttachmentID)
110
+		if t == nil {
111
+			return grpc.Errorf(codes.NotFound, "attachment %s not found", request.AttachmentID)
112
+		}
113
+		if t.NodeID != nodeInfo.NodeID {
114
+			return grpc.Errorf(codes.PermissionDenied, "attachment %s doesn't belong to this node", request.AttachmentID)
115
+		}
116
+
117
+		return store.DeleteTask(tx, request.AttachmentID)
118
+	}); err != nil {
119
+		return nil, err
120
+	}
121
+
122
+	return &api.DetachNetworkResponse{}, nil
123
+}
... ...
@@ -33,7 +33,8 @@ type Cluster struct {
33 33
 
34 34
 	// removed contains the list of removed Members,
35 35
 	// those ids cannot be reused
36
-	removed map[uint64]bool
36
+	removed        map[uint64]bool
37
+	heartbeatTicks int
37 38
 
38 39
 	PeersBroadcast *watch.Queue
39 40
 }
... ...
@@ -43,21 +44,40 @@ type Member struct {
43 43
 	*api.RaftMember
44 44
 
45 45
 	api.RaftClient
46
-	Conn *grpc.ClientConn
46
+	Conn   *grpc.ClientConn
47
+	tick   int
48
+	active bool
47 49
 }
48 50
 
49
-// NewCluster creates a new Cluster neighbors
50
-// list for a raft Member
51
-func NewCluster() *Cluster {
51
+// NewCluster creates a new Cluster neighbors list for a raft Member.
52
+// Member marked as inactive if there was no call ReportActive for heartbeatInterval.
53
+func NewCluster(heartbeatTicks int) *Cluster {
52 54
 	// TODO(abronan): generate Cluster ID for federation
53 55
 
54 56
 	return &Cluster{
55 57
 		members:        make(map[uint64]*Member),
56 58
 		removed:        make(map[uint64]bool),
59
+		heartbeatTicks: heartbeatTicks,
57 60
 		PeersBroadcast: watch.NewQueue(),
58 61
 	}
59 62
 }
60 63
 
64
+// Tick increases ticks for all members. After heartbeatTicks node marked as
65
+// inactive.
66
+func (c *Cluster) Tick() {
67
+	c.mu.Lock()
68
+	defer c.mu.Unlock()
69
+	for _, m := range c.members {
70
+		if !m.active {
71
+			continue
72
+		}
73
+		m.tick++
74
+		if m.tick > c.heartbeatTicks {
75
+			m.active = false
76
+		}
77
+	}
78
+}
79
+
61 80
 // Members returns the list of raft Members in the Cluster.
62 81
 func (c *Cluster) Members() map[uint64]*Member {
63 82
 	members := make(map[uint64]*Member)
... ...
@@ -106,26 +126,42 @@ func (c *Cluster) AddMember(member *Member) error {
106 106
 	if c.removed[member.RaftID] {
107 107
 		return ErrIDRemoved
108 108
 	}
109
+	member.active = true
110
+	member.tick = 0
109 111
 
110 112
 	c.members[member.RaftID] = member
113
+
111 114
 	c.broadcastUpdate()
112 115
 	return nil
113 116
 }
114 117
 
115
-// RemoveMember removes a node from the Cluster Memberlist.
118
+// RemoveMember removes a node from the Cluster Memberlist, and adds it to
119
+// the removed list.
116 120
 func (c *Cluster) RemoveMember(id uint64) error {
117 121
 	c.mu.Lock()
118 122
 	defer c.mu.Unlock()
123
+	c.removed[id] = true
124
+
125
+	return c.clearMember(id)
126
+}
119 127
 
120
-	if c.members[id] != nil {
121
-		conn := c.members[id].Conn
122
-		if conn != nil {
123
-			_ = conn.Close()
128
+// ClearMember removes a node from the Cluster Memberlist, but does NOT add it
129
+// to the removed list.
130
+func (c *Cluster) ClearMember(id uint64) error {
131
+	c.mu.Lock()
132
+	defer c.mu.Unlock()
133
+
134
+	return c.clearMember(id)
135
+}
136
+
137
+func (c *Cluster) clearMember(id uint64) error {
138
+	m, ok := c.members[id]
139
+	if ok {
140
+		if m.Conn != nil {
141
+			m.Conn.Close()
124 142
 		}
125 143
 		delete(c.members, id)
126 144
 	}
127
-
128
-	c.removed[id] = true
129 145
 	c.broadcastUpdate()
130 146
 	return nil
131 147
 }
... ...
@@ -152,7 +188,6 @@ func (c *Cluster) ReplaceMemberConnection(id uint64, oldConn *Member, newConn *M
152 152
 	newMember := *oldMember
153 153
 	newMember.Conn = newConn.Conn
154 154
 	newMember.RaftClient = newConn.RaftClient
155
-
156 155
 	c.members[id] = &newMember
157 156
 
158 157
 	return nil
... ...
@@ -168,11 +203,40 @@ func (c *Cluster) IsIDRemoved(id uint64) bool {
168 168
 // Clear resets the list of active Members and removed Members.
169 169
 func (c *Cluster) Clear() {
170 170
 	c.mu.Lock()
171
+	for _, member := range c.members {
172
+		if member.Conn != nil {
173
+			member.Conn.Close()
174
+		}
175
+	}
176
+
171 177
 	c.members = make(map[uint64]*Member)
172 178
 	c.removed = make(map[uint64]bool)
173 179
 	c.mu.Unlock()
174 180
 }
175 181
 
182
+// ReportActive reports that member is acive (called ProcessRaftMessage),
183
+func (c *Cluster) ReportActive(id uint64) {
184
+	c.mu.Lock()
185
+	defer c.mu.Unlock()
186
+	m, ok := c.members[id]
187
+	if !ok {
188
+		return
189
+	}
190
+	m.tick = 0
191
+	m.active = true
192
+}
193
+
194
+// Active returns true if node is active.
195
+func (c *Cluster) Active(id uint64) bool {
196
+	c.mu.RLock()
197
+	defer c.mu.RUnlock()
198
+	m, ok := c.members[id]
199
+	if !ok {
200
+		return false
201
+	}
202
+	return m.active
203
+}
204
+
176 205
 // ValidateConfigurationChange takes a proposed ConfChange and
177 206
 // ensures that it is valid.
178 207
 func (c *Cluster) ValidateConfigurationChange(cc raftpb.ConfChange) error {
... ...
@@ -223,8 +287,7 @@ func (c *Cluster) CanRemoveMember(from uint64, id uint64) bool {
223 223
 			continue
224 224
 		}
225 225
 
226
-		connState, err := m.Conn.State()
227
-		if err == nil && connState == grpc.Ready {
226
+		if c.Active(m.RaftID) {
228 227
 			nreachable++
229 228
 		}
230 229
 	}
... ...
@@ -86,7 +86,6 @@ type Node struct {
86 86
 
87 87
 	Address  string
88 88
 	StateDir string
89
-	Error    error
90 89
 
91 90
 	raftStore           *raft.MemoryStorage
92 91
 	memoryStore         *store.MemoryStore
... ...
@@ -119,6 +118,7 @@ type Node struct {
119 119
 	leadershipBroadcast *watch.Queue
120 120
 
121 121
 	// used to coordinate shutdown
122
+	// Lock should be used only in stop(), all other functions should use RLock.
122 123
 	stopMu sync.RWMutex
123 124
 	// used for membership management checks
124 125
 	membershipLock sync.Mutex
... ...
@@ -176,7 +176,7 @@ func NewNode(ctx context.Context, opts NewNodeOptions) *Node {
176 176
 	n := &Node{
177 177
 		Ctx:            ctx,
178 178
 		cancel:         cancel,
179
-		cluster:        membership.NewCluster(),
179
+		cluster:        membership.NewCluster(cfg.ElectionTick),
180 180
 		tlsCredentials: opts.TLSCredentials,
181 181
 		raftStore:      raftStore,
182 182
 		Address:        opts.Addr,
... ...
@@ -224,10 +224,15 @@ func NewNode(ctx context.Context, opts NewNodeOptions) *Node {
224 224
 }
225 225
 
226 226
 // JoinAndStart joins and starts the raft server
227
-func (n *Node) JoinAndStart() error {
227
+func (n *Node) JoinAndStart() (err error) {
228
+	defer func() {
229
+		if err != nil {
230
+			n.done()
231
+		}
232
+	}()
233
+
228 234
 	loadAndStartErr := n.loadAndStart(n.Ctx, n.opts.ForceNewCluster)
229 235
 	if loadAndStartErr != nil && loadAndStartErr != errNoWAL {
230
-		n.ticker.Stop()
231 236
 		return loadAndStartErr
232 237
 	}
233 238
 
... ...
@@ -270,6 +275,9 @@ func (n *Node) JoinAndStart() error {
270 270
 			n.Node = raft.StartNode(n.Config, []raft.Peer{})
271 271
 
272 272
 			if err := n.registerNodes(resp.Members); err != nil {
273
+				if walErr := n.wal.Close(); err != nil {
274
+					n.Config.Logger.Errorf("raft: error closing WAL: %v", walErr)
275
+				}
273 276
 				return err
274 277
 			}
275 278
 		} else {
... ...
@@ -281,6 +289,9 @@ func (n *Node) JoinAndStart() error {
281 281
 			}
282 282
 			n.Node = raft.StartNode(n.Config, []raft.Peer{peer})
283 283
 			if err := n.Campaign(n.Ctx); err != nil {
284
+				if walErr := n.wal.Close(); err != nil {
285
+					n.Config.Logger.Errorf("raft: error closing WAL: %v", walErr)
286
+				}
284 287
 				return err
285 288
 			}
286 289
 		}
... ...
@@ -324,15 +335,24 @@ func (n *Node) MemoryStore() *store.MemoryStore {
324 324
 	return n.memoryStore
325 325
 }
326 326
 
327
+func (n *Node) done() {
328
+	n.cluster.Clear()
329
+
330
+	n.ticker.Stop()
331
+	n.leadershipBroadcast.Close()
332
+	n.cluster.PeersBroadcast.Close()
333
+	n.memoryStore.Close()
334
+
335
+	close(n.doneCh)
336
+}
337
+
327 338
 // Run is the main loop for a Raft node, it goes along the state machine,
328 339
 // acting on the messages received from other Raft nodes in the cluster.
329 340
 //
330 341
 // Before running the main loop, it first starts the raft node based on saved
331 342
 // cluster state. If no saved state exists, it starts a single-node cluster.
332 343
 func (n *Node) Run(ctx context.Context) error {
333
-	defer func() {
334
-		close(n.doneCh)
335
-	}()
344
+	defer n.done()
336 345
 
337 346
 	wasLeader := false
338 347
 
... ...
@@ -340,7 +360,7 @@ func (n *Node) Run(ctx context.Context) error {
340 340
 		select {
341 341
 		case <-n.ticker.C():
342 342
 			n.Tick()
343
-
343
+			n.cluster.Tick()
344 344
 		case rd := <-n.Ready():
345 345
 			raftConfig := DefaultRaftConfig()
346 346
 			n.memoryStore.View(func(readTx store.ReadTx) {
... ...
@@ -453,9 +473,6 @@ func (n *Node) Run(ctx context.Context) error {
453 453
 			return ErrMemberRemoved
454 454
 		case <-n.stopCh:
455 455
 			n.stop()
456
-			n.leadershipBroadcast.Close()
457
-			n.cluster.PeersBroadcast.Close()
458
-			n.memoryStore.Close()
459 456
 			return nil
460 457
 		}
461 458
 	}
... ...
@@ -481,13 +498,6 @@ func (n *Node) stop() {
481 481
 	n.waitProp.Wait()
482 482
 	n.asyncTasks.Wait()
483 483
 
484
-	members := n.cluster.Members()
485
-	for _, member := range members {
486
-		if member.Conn != nil {
487
-			_ = member.Conn.Close()
488
-		}
489
-	}
490
-
491 484
 	n.Stop()
492 485
 	n.ticker.Stop()
493 486
 	if err := n.wal.Close(); err != nil {
... ...
@@ -517,20 +527,26 @@ func (n *Node) IsLeader() bool {
517 517
 	return n.isLeader()
518 518
 }
519 519
 
520
-// leader returns the id of the leader, without the protection of lock
520
+// leader returns the id of the leader, without the protection of lock and
521
+// membership check, so it's caller task.
521 522
 func (n *Node) leader() uint64 {
522
-	if !n.IsMember() {
523
-		return 0
524
-	}
525 523
 	return n.Node.Status().Lead
526 524
 }
527 525
 
528 526
 // Leader returns the id of the leader, with the protection of lock
529
-func (n *Node) Leader() uint64 {
527
+func (n *Node) Leader() (uint64, error) {
530 528
 	n.stopMu.RLock()
531 529
 	defer n.stopMu.RUnlock()
532 530
 
533
-	return n.leader()
531
+	if !n.IsMember() {
532
+		return 0, ErrNoRaftMember
533
+	}
534
+	leader := n.leader()
535
+	if leader == 0 {
536
+		return 0, ErrNoClusterLeader
537
+	}
538
+
539
+	return leader, nil
534 540
 }
535 541
 
536 542
 // ReadyForProposals returns true if the node has broadcasted a message
... ...
@@ -760,6 +776,8 @@ func (n *Node) ProcessRaftMessage(ctx context.Context, msg *api.ProcessRaftMessa
760 760
 		return nil, ErrMemberRemoved
761 761
 	}
762 762
 
763
+	n.cluster.ReportActive(msg.Message.From)
764
+
763 765
 	if msg.Message.Type == raftpb.MsgProp {
764 766
 		// We don't accepted forwarded proposals. Our
765 767
 		// current architecture depends on only the leader
... ...
@@ -923,15 +941,17 @@ func (n *Node) SubscribePeers() (q chan events.Event, cancel func()) {
923 923
 func (n *Node) GetMemberlist() map[uint64]*api.RaftMember {
924 924
 	memberlist := make(map[uint64]*api.RaftMember)
925 925
 	members := n.cluster.Members()
926
-	leaderID := n.Leader()
926
+	leaderID, err := n.Leader()
927
+	if err != nil {
928
+		leaderID = 0
929
+	}
927 930
 
928 931
 	for id, member := range members {
929 932
 		reachability := api.RaftMemberStatus_REACHABLE
930 933
 		leader := false
931 934
 
932 935
 		if member.RaftID != n.Config.ID {
933
-			connState, err := member.Conn.State()
934
-			if err != nil || connState != grpc.Ready {
936
+			if !n.cluster.Active(member.RaftID) {
935 937
 				reachability = api.RaftMemberStatus_UNREACHABLE
936 938
 			}
937 939
 		}
... ...
@@ -1111,7 +1131,10 @@ func (n *Node) sendToMember(members map[uint64]*membership.Member, m raftpb.Mess
1111 1111
 		if err != nil {
1112 1112
 			n.Config.Logger.Errorf("could connect to member ID %x at %s: %v", m.To, conn.Addr, err)
1113 1113
 		} else {
1114
-			n.cluster.ReplaceMemberConnection(m.To, conn, newConn)
1114
+			err = n.cluster.ReplaceMemberConnection(m.To, conn, newConn)
1115
+			if err != nil {
1116
+				newConn.Conn.Close()
1117
+			}
1115 1118
 		}
1116 1119
 	} else if m.Type == raftpb.MsgSnap {
1117 1120
 		n.ReportSnapshot(m.To, raft.SnapshotFinish)
... ...
@@ -1129,12 +1152,14 @@ type applyResult struct {
1129 1129
 // an error or until the raft node finalizes all the proposals on node
1130 1130
 // shutdown.
1131 1131
 func (n *Node) processInternalRaftRequest(ctx context.Context, r *api.InternalRaftRequest, cb func()) (proto.Message, error) {
1132
-	n.waitProp.Add(1)
1133
-	defer n.waitProp.Done()
1134
-
1132
+	n.stopMu.RLock()
1135 1133
 	if !n.canSubmitProposal() {
1134
+		n.stopMu.RUnlock()
1136 1135
 		return nil, ErrStopped
1137 1136
 	}
1137
+	n.waitProp.Add(1)
1138
+	defer n.waitProp.Done()
1139
+	n.stopMu.RUnlock()
1138 1140
 
1139 1141
 	r.ID = n.reqIDGen.Next()
1140 1142
 
... ...
@@ -445,18 +445,24 @@ func (n *Node) restoreFromSnapshot(data []byte, forceNewCluster bool) error {
445 445
 		return err
446 446
 	}
447 447
 
448
-	n.cluster.Clear()
448
+	oldMembers := n.cluster.Members()
449 449
 
450 450
 	if !forceNewCluster {
451 451
 		for _, member := range snapshot.Membership.Members {
452 452
 			if err := n.registerNode(&api.RaftMember{RaftID: member.RaftID, NodeID: member.NodeID, Addr: member.Addr}); err != nil {
453 453
 				return err
454 454
 			}
455
+			delete(oldMembers, member.RaftID)
455 456
 		}
456 457
 	}
457 458
 
458 459
 	for _, removedMember := range snapshot.Membership.Removed {
459 460
 		n.cluster.RemoveMember(removedMember)
461
+		delete(oldMembers, removedMember)
462
+	}
463
+
464
+	for member := range oldMembers {
465
+		n.cluster.ClearMember(member)
460 466
 	}
461 467
 
462 468
 	return nil
... ...
@@ -35,19 +35,19 @@ func Register(server *grpc.Server, node *Node) {
35 35
 // WaitForLeader waits until node observe some leader in cluster. It returns
36 36
 // error if ctx was cancelled before leader appeared.
37 37
 func WaitForLeader(ctx context.Context, n *Node) error {
38
-	l := n.Leader()
39
-	if l != 0 {
38
+	_, err := n.Leader()
39
+	if err == nil {
40 40
 		return nil
41 41
 	}
42 42
 	ticker := time.NewTicker(50 * time.Millisecond)
43 43
 	defer ticker.Stop()
44
-	for l == 0 {
44
+	for err != nil {
45 45
 		select {
46 46
 		case <-ticker.C:
47 47
 		case <-ctx.Done():
48 48
 			return ctx.Err()
49 49
 		}
50
-		l = n.Leader()
50
+		_, err = n.Leader()
51 51
 	}
52 52
 	return nil
53 53
 }
54 54
deleted file mode 100644
... ...
@@ -1,337 +0,0 @@
1
-package picker
2
-
3
-import (
4
-	"fmt"
5
-	"math"
6
-	"math/rand"
7
-	"sort"
8
-	"sync"
9
-
10
-	"github.com/docker/swarmkit/api"
11
-	"golang.org/x/net/context"
12
-	"google.golang.org/grpc"
13
-	"google.golang.org/grpc/transport"
14
-)
15
-
16
-var errRemotesUnavailable = fmt.Errorf("no remote hosts provided")
17
-
18
-// DefaultObservationWeight provides a weight to use for positive observations
19
-// that will balance well under repeated observations.
20
-const DefaultObservationWeight = 10
21
-
22
-// Remotes keeps track of remote addresses by weight, informed by
23
-// observations.
24
-type Remotes interface {
25
-	// Weight returns the remotes with their current weights.
26
-	Weights() map[api.Peer]int
27
-
28
-	// Select a remote from the set of available remotes with optionally
29
-	// excluding ID or address.
30
-	Select(...string) (api.Peer, error)
31
-
32
-	// Observe records an experience with a particular remote. A positive weight
33
-	// indicates a good experience and a negative weight a bad experience.
34
-	//
35
-	// The observation will be used to calculate a moving weight, which is
36
-	// implementation dependent. This method will be called such that repeated
37
-	// observations of the same master in each session request are favored.
38
-	Observe(peer api.Peer, weight int)
39
-
40
-	// ObserveIfExists records an experience with a particular remote if when a
41
-	// remote exists.
42
-	ObserveIfExists(peer api.Peer, weight int)
43
-
44
-	// Remove the remote from the list completely.
45
-	Remove(addrs ...api.Peer)
46
-}
47
-
48
-// NewRemotes returns a Remotes instance with the provided set of addresses.
49
-// Entries provided are heavily weighted initially.
50
-func NewRemotes(peers ...api.Peer) Remotes {
51
-	mwr := &remotesWeightedRandom{
52
-		remotes: make(map[api.Peer]int),
53
-	}
54
-
55
-	for _, peer := range peers {
56
-		mwr.Observe(peer, DefaultObservationWeight)
57
-	}
58
-
59
-	return mwr
60
-}
61
-
62
-type remotesWeightedRandom struct {
63
-	remotes map[api.Peer]int
64
-	mu      sync.Mutex
65
-
66
-	// workspace to avoid reallocation. these get lazily allocated when
67
-	// selecting values.
68
-	cdf   []float64
69
-	peers []api.Peer
70
-}
71
-
72
-func (mwr *remotesWeightedRandom) Weights() map[api.Peer]int {
73
-	mwr.mu.Lock()
74
-	defer mwr.mu.Unlock()
75
-
76
-	ms := make(map[api.Peer]int, len(mwr.remotes))
77
-	for addr, weight := range mwr.remotes {
78
-		ms[addr] = weight
79
-	}
80
-
81
-	return ms
82
-}
83
-
84
-func (mwr *remotesWeightedRandom) Select(excludes ...string) (api.Peer, error) {
85
-	mwr.mu.Lock()
86
-	defer mwr.mu.Unlock()
87
-
88
-	// NOTE(stevvooe): We then use a weighted random selection algorithm
89
-	// (http://stackoverflow.com/questions/4463561/weighted-random-selection-from-array)
90
-	// to choose the master to connect to.
91
-	//
92
-	// It is possible that this is insufficient. The following may inform a
93
-	// better solution:
94
-
95
-	// https://github.com/LK4D4/sample
96
-	//
97
-	// The first link applies exponential distribution weight choice reservior
98
-	// sampling. This may be relevant if we view the master selection as a
99
-	// distributed reservior sampling problem.
100
-
101
-	// bias to zero-weighted remotes have same probability. otherwise, we
102
-	// always select first entry when all are zero.
103
-	const bias = 0.001
104
-
105
-	// clear out workspace
106
-	mwr.cdf = mwr.cdf[:0]
107
-	mwr.peers = mwr.peers[:0]
108
-
109
-	cum := 0.0
110
-	// calculate CDF over weights
111
-Loop:
112
-	for peer, weight := range mwr.remotes {
113
-		for _, exclude := range excludes {
114
-			if peer.NodeID == exclude || peer.Addr == exclude {
115
-				// if this peer is excluded, ignore it by continuing the loop to label Loop
116
-				continue Loop
117
-			}
118
-		}
119
-		if weight < 0 {
120
-			// treat these as zero, to keep there selection unlikely.
121
-			weight = 0
122
-		}
123
-
124
-		cum += float64(weight) + bias
125
-		mwr.cdf = append(mwr.cdf, cum)
126
-		mwr.peers = append(mwr.peers, peer)
127
-	}
128
-
129
-	if len(mwr.peers) == 0 {
130
-		return api.Peer{}, errRemotesUnavailable
131
-	}
132
-
133
-	r := mwr.cdf[len(mwr.cdf)-1] * rand.Float64()
134
-	i := sort.SearchFloat64s(mwr.cdf, r)
135
-
136
-	return mwr.peers[i], nil
137
-}
138
-
139
-func (mwr *remotesWeightedRandom) Observe(peer api.Peer, weight int) {
140
-	mwr.mu.Lock()
141
-	defer mwr.mu.Unlock()
142
-
143
-	mwr.observe(peer, float64(weight))
144
-}
145
-
146
-func (mwr *remotesWeightedRandom) ObserveIfExists(peer api.Peer, weight int) {
147
-	mwr.mu.Lock()
148
-	defer mwr.mu.Unlock()
149
-
150
-	if _, ok := mwr.remotes[peer]; !ok {
151
-		return
152
-	}
153
-
154
-	mwr.observe(peer, float64(weight))
155
-}
156
-
157
-func (mwr *remotesWeightedRandom) Remove(addrs ...api.Peer) {
158
-	mwr.mu.Lock()
159
-	defer mwr.mu.Unlock()
160
-
161
-	for _, addr := range addrs {
162
-		delete(mwr.remotes, addr)
163
-	}
164
-}
165
-
166
-const (
167
-	// remoteWeightSmoothingFactor for exponential smoothing. This adjusts how
168
-	// much of the // observation and old value we are using to calculate the new value.
169
-	// See
170
-	// https://en.wikipedia.org/wiki/Exponential_smoothing#Basic_exponential_smoothing
171
-	// for details.
172
-	remoteWeightSmoothingFactor = 0.5
173
-	remoteWeightMax             = 1 << 8
174
-)
175
-
176
-func clip(x float64) float64 {
177
-	if math.IsNaN(x) {
178
-		// treat garbage as such
179
-		// acts like a no-op for us.
180
-		return 0
181
-	}
182
-	return math.Max(math.Min(remoteWeightMax, x), -remoteWeightMax)
183
-}
184
-
185
-func (mwr *remotesWeightedRandom) observe(peer api.Peer, weight float64) {
186
-
187
-	// While we have a decent, ad-hoc approach here to weight subsequent
188
-	// observations, we may want to look into applying forward decay:
189
-	//
190
-	//  http://dimacs.rutgers.edu/~graham/pubs/papers/fwddecay.pdf
191
-	//
192
-	// We need to get better data from behavior in a cluster.
193
-
194
-	// makes the math easier to read below
195
-	var (
196
-		w0 = float64(mwr.remotes[peer])
197
-		w1 = clip(weight)
198
-	)
199
-	const α = remoteWeightSmoothingFactor
200
-
201
-	// Multiply the new value to current value, and appy smoothing against the old
202
-	// value.
203
-	wn := clip(α*w1 + (1-α)*w0)
204
-
205
-	mwr.remotes[peer] = int(math.Ceil(wn))
206
-}
207
-
208
-// Picker implements a grpc Picker
209
-type Picker struct {
210
-	r    Remotes
211
-	peer api.Peer // currently selected remote peer
212
-	conn *grpc.Conn
213
-	mu   sync.Mutex
214
-}
215
-
216
-var _ grpc.Picker = &Picker{}
217
-
218
-// NewPicker returns a Picker
219
-func NewPicker(r Remotes, initial ...string) *Picker {
220
-	var peer api.Peer
221
-	if len(initial) == 0 {
222
-		peer, _ = r.Select() // empty in case of error
223
-	} else {
224
-		peer = api.Peer{Addr: initial[0]}
225
-	}
226
-	return &Picker{r: r, peer: peer}
227
-}
228
-
229
-// Init does initial processing for the Picker, e.g., initiate some connections.
230
-func (p *Picker) Init(cc *grpc.ClientConn) error {
231
-	p.mu.Lock()
232
-	peer := p.peer
233
-	p.mu.Unlock()
234
-
235
-	p.r.ObserveIfExists(peer, DefaultObservationWeight)
236
-	c, err := grpc.NewConn(cc)
237
-	if err != nil {
238
-		return err
239
-	}
240
-
241
-	p.mu.Lock()
242
-	p.conn = c
243
-	p.mu.Unlock()
244
-	return nil
245
-}
246
-
247
-// Pick blocks until either a transport.ClientTransport is ready for the upcoming RPC
248
-// or some error happens.
249
-func (p *Picker) Pick(ctx context.Context) (transport.ClientTransport, error) {
250
-	p.mu.Lock()
251
-	peer := p.peer
252
-	p.mu.Unlock()
253
-	transport, err := p.conn.Wait(ctx)
254
-	if err != nil {
255
-		p.r.ObserveIfExists(peer, -DefaultObservationWeight)
256
-	}
257
-
258
-	return transport, err
259
-}
260
-
261
-// PickAddr picks a peer address for connecting. This will be called repeated for
262
-// connecting/reconnecting.
263
-func (p *Picker) PickAddr() (string, error) {
264
-	p.mu.Lock()
265
-	peer := p.peer
266
-	p.mu.Unlock()
267
-
268
-	p.r.ObserveIfExists(peer, -DefaultObservationWeight) // downweight the current addr
269
-
270
-	var err error
271
-	peer, err = p.r.Select()
272
-	if err != nil {
273
-		return "", err
274
-	}
275
-
276
-	p.mu.Lock()
277
-	p.peer = peer
278
-	p.mu.Unlock()
279
-	return peer.Addr, err
280
-}
281
-
282
-// State returns the connectivity state of the underlying connections.
283
-func (p *Picker) State() (grpc.ConnectivityState, error) {
284
-	return p.conn.State(), nil
285
-}
286
-
287
-// WaitForStateChange blocks until the state changes to something other than
288
-// the sourceState. It returns the new state or error.
289
-func (p *Picker) WaitForStateChange(ctx context.Context, sourceState grpc.ConnectivityState) (grpc.ConnectivityState, error) {
290
-	p.mu.Lock()
291
-	conn := p.conn
292
-	peer := p.peer
293
-	p.mu.Unlock()
294
-
295
-	state, err := conn.WaitForStateChange(ctx, sourceState)
296
-	if err != nil {
297
-		return state, err
298
-	}
299
-
300
-	// TODO(stevvooe): We may want to actually score the transition by checking
301
-	// sourceState.
302
-
303
-	// TODO(stevvooe): This is questionable, but we'll see how it works.
304
-	switch state {
305
-	case grpc.Idle:
306
-		p.r.ObserveIfExists(peer, DefaultObservationWeight)
307
-	case grpc.Connecting:
308
-		p.r.ObserveIfExists(peer, DefaultObservationWeight)
309
-	case grpc.Ready:
310
-		p.r.ObserveIfExists(peer, DefaultObservationWeight)
311
-	case grpc.TransientFailure:
312
-		p.r.ObserveIfExists(peer, -DefaultObservationWeight)
313
-	case grpc.Shutdown:
314
-		p.r.ObserveIfExists(peer, -DefaultObservationWeight)
315
-	}
316
-
317
-	return state, err
318
-}
319
-
320
-// Reset the current connection and force a reconnect to another address.
321
-func (p *Picker) Reset() error {
322
-	p.mu.Lock()
323
-	conn := p.conn
324
-	p.mu.Unlock()
325
-
326
-	conn.NotifyReset()
327
-	return nil
328
-}
329
-
330
-// Close closes all the Conn's owned by this Picker.
331
-func (p *Picker) Close() error {
332
-	p.mu.Lock()
333
-	conn := p.conn
334
-	p.mu.Unlock()
335
-
336
-	return conn.Close()
337
-}
338 1
new file mode 100644
... ...
@@ -0,0 +1,203 @@
0
+package remotes
1
+
2
+import (
3
+	"fmt"
4
+	"math"
5
+	"math/rand"
6
+	"sort"
7
+	"sync"
8
+
9
+	"github.com/docker/swarmkit/api"
10
+)
11
+
12
+var errRemotesUnavailable = fmt.Errorf("no remote hosts provided")
13
+
14
+// DefaultObservationWeight provides a weight to use for positive observations
15
+// that will balance well under repeated observations.
16
+const DefaultObservationWeight = 10
17
+
18
+// Remotes keeps track of remote addresses by weight, informed by
19
+// observations.
20
+type Remotes interface {
21
+	// Weight returns the remotes with their current weights.
22
+	Weights() map[api.Peer]int
23
+
24
+	// Select a remote from the set of available remotes with optionally
25
+	// excluding ID or address.
26
+	Select(...string) (api.Peer, error)
27
+
28
+	// Observe records an experience with a particular remote. A positive weight
29
+	// indicates a good experience and a negative weight a bad experience.
30
+	//
31
+	// The observation will be used to calculate a moving weight, which is
32
+	// implementation dependent. This method will be called such that repeated
33
+	// observations of the same master in each session request are favored.
34
+	Observe(peer api.Peer, weight int)
35
+
36
+	// ObserveIfExists records an experience with a particular remote if when a
37
+	// remote exists.
38
+	ObserveIfExists(peer api.Peer, weight int)
39
+
40
+	// Remove the remote from the list completely.
41
+	Remove(addrs ...api.Peer)
42
+}
43
+
44
+// NewRemotes returns a Remotes instance with the provided set of addresses.
45
+// Entries provided are heavily weighted initially.
46
+func NewRemotes(peers ...api.Peer) Remotes {
47
+	mwr := &remotesWeightedRandom{
48
+		remotes: make(map[api.Peer]int),
49
+	}
50
+
51
+	for _, peer := range peers {
52
+		mwr.Observe(peer, DefaultObservationWeight)
53
+	}
54
+
55
+	return mwr
56
+}
57
+
58
+type remotesWeightedRandom struct {
59
+	remotes map[api.Peer]int
60
+	mu      sync.Mutex
61
+
62
+	// workspace to avoid reallocation. these get lazily allocated when
63
+	// selecting values.
64
+	cdf   []float64
65
+	peers []api.Peer
66
+}
67
+
68
+func (mwr *remotesWeightedRandom) Weights() map[api.Peer]int {
69
+	mwr.mu.Lock()
70
+	defer mwr.mu.Unlock()
71
+
72
+	ms := make(map[api.Peer]int, len(mwr.remotes))
73
+	for addr, weight := range mwr.remotes {
74
+		ms[addr] = weight
75
+	}
76
+
77
+	return ms
78
+}
79
+
80
+func (mwr *remotesWeightedRandom) Select(excludes ...string) (api.Peer, error) {
81
+	mwr.mu.Lock()
82
+	defer mwr.mu.Unlock()
83
+
84
+	// NOTE(stevvooe): We then use a weighted random selection algorithm
85
+	// (http://stackoverflow.com/questions/4463561/weighted-random-selection-from-array)
86
+	// to choose the master to connect to.
87
+	//
88
+	// It is possible that this is insufficient. The following may inform a
89
+	// better solution:
90
+
91
+	// https://github.com/LK4D4/sample
92
+	//
93
+	// The first link applies exponential distribution weight choice reservior
94
+	// sampling. This may be relevant if we view the master selection as a
95
+	// distributed reservior sampling problem.
96
+
97
+	// bias to zero-weighted remotes have same probability. otherwise, we
98
+	// always select first entry when all are zero.
99
+	const bias = 0.001
100
+
101
+	// clear out workspace
102
+	mwr.cdf = mwr.cdf[:0]
103
+	mwr.peers = mwr.peers[:0]
104
+
105
+	cum := 0.0
106
+	// calculate CDF over weights
107
+Loop:
108
+	for peer, weight := range mwr.remotes {
109
+		for _, exclude := range excludes {
110
+			if peer.NodeID == exclude || peer.Addr == exclude {
111
+				// if this peer is excluded, ignore it by continuing the loop to label Loop
112
+				continue Loop
113
+			}
114
+		}
115
+		if weight < 0 {
116
+			// treat these as zero, to keep there selection unlikely.
117
+			weight = 0
118
+		}
119
+
120
+		cum += float64(weight) + bias
121
+		mwr.cdf = append(mwr.cdf, cum)
122
+		mwr.peers = append(mwr.peers, peer)
123
+	}
124
+
125
+	if len(mwr.peers) == 0 {
126
+		return api.Peer{}, errRemotesUnavailable
127
+	}
128
+
129
+	r := mwr.cdf[len(mwr.cdf)-1] * rand.Float64()
130
+	i := sort.SearchFloat64s(mwr.cdf, r)
131
+
132
+	return mwr.peers[i], nil
133
+}
134
+
135
+func (mwr *remotesWeightedRandom) Observe(peer api.Peer, weight int) {
136
+	mwr.mu.Lock()
137
+	defer mwr.mu.Unlock()
138
+
139
+	mwr.observe(peer, float64(weight))
140
+}
141
+
142
+func (mwr *remotesWeightedRandom) ObserveIfExists(peer api.Peer, weight int) {
143
+	mwr.mu.Lock()
144
+	defer mwr.mu.Unlock()
145
+
146
+	if _, ok := mwr.remotes[peer]; !ok {
147
+		return
148
+	}
149
+
150
+	mwr.observe(peer, float64(weight))
151
+}
152
+
153
+func (mwr *remotesWeightedRandom) Remove(addrs ...api.Peer) {
154
+	mwr.mu.Lock()
155
+	defer mwr.mu.Unlock()
156
+
157
+	for _, addr := range addrs {
158
+		delete(mwr.remotes, addr)
159
+	}
160
+}
161
+
162
+const (
163
+	// remoteWeightSmoothingFactor for exponential smoothing. This adjusts how
164
+	// much of the // observation and old value we are using to calculate the new value.
165
+	// See
166
+	// https://en.wikipedia.org/wiki/Exponential_smoothing#Basic_exponential_smoothing
167
+	// for details.
168
+	remoteWeightSmoothingFactor = 0.5
169
+	remoteWeightMax             = 1 << 8
170
+)
171
+
172
+func clip(x float64) float64 {
173
+	if math.IsNaN(x) {
174
+		// treat garbage as such
175
+		// acts like a no-op for us.
176
+		return 0
177
+	}
178
+	return math.Max(math.Min(remoteWeightMax, x), -remoteWeightMax)
179
+}
180
+
181
+func (mwr *remotesWeightedRandom) observe(peer api.Peer, weight float64) {
182
+
183
+	// While we have a decent, ad-hoc approach here to weight subsequent
184
+	// observations, we may want to look into applying forward decay:
185
+	//
186
+	//  http://dimacs.rutgers.edu/~graham/pubs/papers/fwddecay.pdf
187
+	//
188
+	// We need to get better data from behavior in a cluster.
189
+
190
+	// makes the math easier to read below
191
+	var (
192
+		w0 = float64(mwr.remotes[peer])
193
+		w1 = clip(weight)
194
+	)
195
+	const α = remoteWeightSmoothingFactor
196
+
197
+	// Multiply the new value to current value, and appy smoothing against the old
198
+	// value.
199
+	wn := clip(α*w1 + (1-α)*w0)
200
+
201
+	mwr.remotes[peer] = int(math.Ceil(wn))
202
+}
... ...
@@ -17,7 +17,6 @@ import (
17 17
 	"time"
18 18
 
19 19
 	"github.com/google/certificate-transparency/go"
20
-	"github.com/mreiferson/go-httpclient"
21 20
 	"golang.org/x/net/context"
22 21
 )
23 22
 
... ...
@@ -25,6 +24,7 @@ import (
25 25
 const (
26 26
 	AddChainPath    = "/ct/v1/add-chain"
27 27
 	AddPreChainPath = "/ct/v1/add-pre-chain"
28
+	AddJSONPath     = "/ct/v1/add-json"
28 29
 	GetSTHPath      = "/ct/v1/get-sth"
29 30
 	GetEntriesPath  = "/ct/v1/get-entries"
30 31
 )
... ...
@@ -57,6 +57,12 @@ type addChainResponse struct {
57 57
 	Signature  string     `json:"signature"`   // Log signature for this SCT
58 58
 }
59 59
 
60
+// addJSONRequest represents the JSON request body sent ot the add-json CT
61
+// method.
62
+type addJSONRequest struct {
63
+	Data interface{} `json:"data"`
64
+}
65
+
60 66
 // getSTHResponse respresents the JSON response to the get-sth CT method
61 67
 type getSTHResponse struct {
62 68
 	TreeSize          uint64 `json:"tree_size"`           // Number of certs in the current tree
... ...
@@ -102,18 +108,12 @@ type getEntryAndProofResponse struct {
102 102
 // New constructs a new LogClient instance.
103 103
 // |uri| is the base URI of the CT log instance to interact with, e.g.
104 104
 // http://ct.googleapis.com/pilot
105
-func New(uri string) *LogClient {
106
-	var c LogClient
107
-	c.uri = uri
108
-	transport := &httpclient.Transport{
109
-		ConnectTimeout:        10 * time.Second,
110
-		RequestTimeout:        30 * time.Second,
111
-		ResponseHeaderTimeout: 30 * time.Second,
112
-		MaxIdleConnsPerHost:   10,
113
-		DisableKeepAlives:     false,
105
+// |hc| is the underlying client to be used for HTTP requests to the CT log.
106
+func New(uri string, hc *http.Client) *LogClient {
107
+	if hc == nil {
108
+		hc = new(http.Client)
114 109
 	}
115
-	c.httpClient = &http.Client{Transport: transport}
116
-	return &c
110
+	return &LogClient{uri: uri, httpClient: hc}
117 111
 }
118 112
 
119 113
 // Makes a HTTP call to |uri|, and attempts to parse the response as a JSON
... ...
@@ -154,7 +154,6 @@ func (c *LogClient) postAndParse(uri string, req interface{}, res interface{}) (
154 154
 	if err != nil {
155 155
 		return nil, "", err
156 156
 	}
157
-	httpReq.Header.Set("Keep-Alive", "timeout=15, max=100")
158 157
 	httpReq.Header.Set("Content-Type", "application/json")
159 158
 	resp, err := c.httpClient.Do(httpReq)
160 159
 	// Read all of the body, if there is one, so that the http.Client can do
... ...
@@ -277,6 +276,37 @@ func (c *LogClient) AddChainWithContext(ctx context.Context, chain []ct.ASN1Cert
277 277
 	return c.addChainWithRetry(ctx, AddChainPath, chain)
278 278
 }
279 279
 
280
+func (c *LogClient) AddJSON(data interface{}) (*ct.SignedCertificateTimestamp, error) {
281
+	req := addJSONRequest{
282
+		Data: data,
283
+	}
284
+	var resp addChainResponse
285
+	_, _, err := c.postAndParse(c.uri+AddJSONPath, &req, &resp)
286
+	if err != nil {
287
+		return nil, err
288
+	}
289
+	rawLogID, err := base64.StdEncoding.DecodeString(resp.ID)
290
+	if err != nil {
291
+		return nil, err
292
+	}
293
+	rawSignature, err := base64.StdEncoding.DecodeString(resp.Signature)
294
+	if err != nil {
295
+		return nil, err
296
+	}
297
+	ds, err := ct.UnmarshalDigitallySigned(bytes.NewReader(rawSignature))
298
+	if err != nil {
299
+		return nil, err
300
+	}
301
+	var logID ct.SHA256Hash
302
+	copy(logID[:], rawLogID)
303
+	return &ct.SignedCertificateTimestamp{
304
+		SCTVersion: resp.SCTVersion,
305
+		LogID:      logID,
306
+		Timestamp:  resp.Timestamp,
307
+		Extensions: ct.CTExtensions(resp.Extensions),
308
+		Signature:  *ds}, nil
309
+}
310
+
280 311
 // GetSTH retrieves the current STH from the log.
281 312
 // Returns a populated SignedTreeHead, or a non-nil error.
282 313
 func (c *LogClient) GetSTH() (sth *ct.SignedTreeHead, err error) {
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"bytes"
5 5
 	"container/list"
6 6
 	"crypto"
7
+	"encoding/asn1"
7 8
 	"encoding/binary"
8 9
 	"errors"
9 10
 	"fmt"
... ...
@@ -23,6 +24,8 @@ const (
23 23
 const (
24 24
 	MaxCertificateLength = (1 << 24) - 1
25 25
 	MaxExtensionsLength  = (1 << 16) - 1
26
+	MaxSCTInListLength   = (1 << 16) - 1
27
+	MaxSCTListLength     = (1 << 16) - 1
26 28
 )
27 29
 
28 30
 func writeUint(w io.Writer, value uint64, numBytes int) error {
... ...
@@ -80,13 +83,12 @@ func readVarBytes(r io.Reader, numLenBytes int) ([]byte, error) {
80 80
 		return nil, err
81 81
 	}
82 82
 	data := make([]byte, l)
83
-	n, err := r.Read(data)
84
-	if err != nil {
83
+	if n, err := io.ReadFull(r, data); err != nil {
84
+		if err == io.EOF || err == io.ErrUnexpectedEOF {
85
+			return nil, fmt.Errorf("short read: expected %d but got %d", l, n)
86
+		}
85 87
 		return nil, err
86 88
 	}
87
-	if n != int(l) {
88
-		return nil, fmt.Errorf("short read: expected %d but got %d", l, n)
89
-	}
90 89
 	return data, nil
91 90
 }
92 91
 
... ...
@@ -510,3 +512,52 @@ func SerializeSTHSignatureInput(sth SignedTreeHead) ([]byte, error) {
510 510
 		return nil, fmt.Errorf("unsupported STH version %d", sth.Version)
511 511
 	}
512 512
 }
513
+
514
+// SCTListSerializedLength determines the length of the required buffer should a SCT List need to be serialized
515
+func SCTListSerializedLength(scts []SignedCertificateTimestamp) (int, error) {
516
+	if len(scts) == 0 {
517
+		return 0, fmt.Errorf("SCT List empty")
518
+	}
519
+
520
+	sctListLen := 0
521
+	for i, sct := range scts {
522
+		n, err := sct.SerializedLength()
523
+		if err != nil {
524
+			return 0, fmt.Errorf("unable to determine length of SCT in position %d: %v", i, err)
525
+		}
526
+		if n > MaxSCTInListLength {
527
+			return 0, fmt.Errorf("SCT in position %d too large: %d", i, n)
528
+		}
529
+		sctListLen += 2 + n
530
+	}
531
+
532
+	return sctListLen, nil
533
+}
534
+
535
+// SerializeSCTList serializes the passed-in slice of SignedCertificateTimestamp into a
536
+// byte slice as a SignedCertificateTimestampList (see RFC6962 Section 3.3)
537
+func SerializeSCTList(scts []SignedCertificateTimestamp) ([]byte, error) {
538
+	size, err := SCTListSerializedLength(scts)
539
+	if err != nil {
540
+		return nil, err
541
+	}
542
+	fullSize := 2 + size // 2 bytes for length + size of SCT list
543
+	if fullSize > MaxSCTListLength {
544
+		return nil, fmt.Errorf("SCT List too large to serialize: %d", fullSize)
545
+	}
546
+	buf := new(bytes.Buffer)
547
+	buf.Grow(fullSize)
548
+	if err = writeUint(buf, uint64(size), 2); err != nil {
549
+		return nil, err
550
+	}
551
+	for _, sct := range scts {
552
+		serialized, err := SerializeSCT(sct)
553
+		if err != nil {
554
+			return nil, err
555
+		}
556
+		if err = writeVarBytes(buf, serialized, 2); err != nil {
557
+			return nil, err
558
+		}
559
+	}
560
+	return asn1.Marshal(buf.Bytes()) // transform to Octet String
561
+}
513 562
deleted file mode 100644
... ...
@@ -1 +0,0 @@
1
-*.sw[op]
2 1
deleted file mode 100644
... ...
@@ -1,11 +0,0 @@
1
-language: go
2
-go:
3
-  - 1.1
4
-install:
5
-  - go get github.com/bmizerany/assert
6
-script:
7
-  - pushd $TRAVIS_BUILD_DIR
8
-  - go test
9
-  - popd
10
-notifications:
11
-  email: false
12 1
deleted file mode 100644
... ...
@@ -1,41 +0,0 @@
1
-## go-httpclient
2
-
3
-**requires Go 1.1+** as of `v0.4.0` the API has been completely re-written for Go 1.1 (for a Go
4
-1.0.x compatible release see [1adef50](https://github.com/mreiferson/go-httpclient/tree/1adef50))
5
-
6
-[![Build
7
-Status](https://secure.travis-ci.org/mreiferson/go-httpclient.png?branch=master)](http://travis-ci.org/mreiferson/go-httpclient)
8
-
9
-Provides an HTTP Transport that implements the `RoundTripper` interface and
10
-can be used as a built in replacement for the standard library's, providing:
11
-
12
- * connection timeouts
13
- * request timeouts
14
-
15
-This is a thin wrapper around `http.Transport` that sets dial timeouts and uses
16
-Go's internal timer scheduler to call the Go 1.1+ `CancelRequest()` API.
17
-
18
-### Example
19
-
20
-```go
21
-transport := &httpclient.Transport{
22
-    ConnectTimeout:        1*time.Second,
23
-    RequestTimeout:        10*time.Second,
24
-    ResponseHeaderTimeout: 5*time.Second,
25
-}
26
-defer transport.Close()
27
-
28
-client := &http.Client{Transport: transport}
29
-req, _ := http.NewRequest("GET", "http://127.0.0.1/test", nil)
30
-resp, err := client.Do(req)
31
-if err != nil {
32
-    return err
33
-}
34
-defer resp.Body.Close()
35
-```
36
-
37
-*Note:* you will want to re-use a single client object rather than creating one for each request, otherwise you will end up [leaking connections](https://code.google.com/p/go/issues/detail?id=4049#c3).
38
-
39
-### Reference Docs
40
-
41
-For API docs see [godoc](http://godoc.org/github.com/mreiferson/go-httpclient).
42 1
deleted file mode 100644
... ...
@@ -1,237 +0,0 @@
1
-/*
2
-Provides an HTTP Transport that implements the `RoundTripper` interface and
3
-can be used as a built in replacement for the standard library's, providing:
4
-
5
-	* connection timeouts
6
-	* request timeouts
7
-
8
-This is a thin wrapper around `http.Transport` that sets dial timeouts and uses
9
-Go's internal timer scheduler to call the Go 1.1+ `CancelRequest()` API.
10
-*/
11
-package httpclient
12
-
13
-import (
14
-	"crypto/tls"
15
-	"errors"
16
-	"io"
17
-	"net"
18
-	"net/http"
19
-	"net/url"
20
-	"sync"
21
-	"time"
22
-)
23
-
24
-// returns the current version of the package
25
-func Version() string {
26
-	return "0.4.1"
27
-}
28
-
29
-// Transport implements the RoundTripper interface and can be used as a replacement
30
-// for Go's built in http.Transport implementing end-to-end request timeouts.
31
-//
32
-// 	transport := &httpclient.Transport{
33
-// 	    ConnectTimeout: 1*time.Second,
34
-// 	    ResponseHeaderTimeout: 5*time.Second,
35
-// 	    RequestTimeout: 10*time.Second,
36
-// 	}
37
-// 	defer transport.Close()
38
-//
39
-// 	client := &http.Client{Transport: transport}
40
-// 	req, _ := http.NewRequest("GET", "http://127.0.0.1/test", nil)
41
-// 	resp, err := client.Do(req)
42
-// 	if err != nil {
43
-// 	    return err
44
-// 	}
45
-// 	defer resp.Body.Close()
46
-//
47
-type Transport struct {
48
-	// Proxy specifies a function to return a proxy for a given
49
-	// *http.Request. If the function returns a non-nil error, the
50
-	// request is aborted with the provided error.
51
-	// If Proxy is nil or returns a nil *url.URL, no proxy is used.
52
-	Proxy func(*http.Request) (*url.URL, error)
53
-
54
-	// Dial specifies the dial function for creating TCP
55
-	// connections. This will override the Transport's ConnectTimeout and
56
-	// ReadWriteTimeout settings.
57
-	// If Dial is nil, a dialer is generated on demand matching the Transport's
58
-	// options.
59
-	Dial func(network, addr string) (net.Conn, error)
60
-
61
-	// TLSClientConfig specifies the TLS configuration to use with
62
-	// tls.Client. If nil, the default configuration is used.
63
-	TLSClientConfig *tls.Config
64
-
65
-	// DisableKeepAlives, if true, prevents re-use of TCP connections
66
-	// between different HTTP requests.
67
-	DisableKeepAlives bool
68
-
69
-	// DisableCompression, if true, prevents the Transport from
70
-	// requesting compression with an "Accept-Encoding: gzip"
71
-	// request header when the Request contains no existing
72
-	// Accept-Encoding value. If the Transport requests gzip on
73
-	// its own and gets a gzipped response, it's transparently
74
-	// decoded in the Response.Body. However, if the user
75
-	// explicitly requested gzip it is not automatically
76
-	// uncompressed.
77
-	DisableCompression bool
78
-
79
-	// MaxIdleConnsPerHost, if non-zero, controls the maximum idle
80
-	// (keep-alive) to keep per-host.  If zero,
81
-	// http.DefaultMaxIdleConnsPerHost is used.
82
-	MaxIdleConnsPerHost int
83
-
84
-	// ConnectTimeout, if non-zero, is the maximum amount of time a dial will wait for
85
-	// a connect to complete.
86
-	ConnectTimeout time.Duration
87
-
88
-	// ResponseHeaderTimeout, if non-zero, specifies the amount of
89
-	// time to wait for a server's response headers after fully
90
-	// writing the request (including its body, if any). This
91
-	// time does not include the time to read the response body.
92
-	ResponseHeaderTimeout time.Duration
93
-
94
-	// RequestTimeout, if non-zero, specifies the amount of time for the entire
95
-	// request to complete (including all of the above timeouts + entire response body).
96
-	// This should never be less than the sum total of the above two timeouts.
97
-	RequestTimeout time.Duration
98
-
99
-	// ReadWriteTimeout, if non-zero, will set a deadline for every Read and
100
-	// Write operation on the request connection.
101
-	ReadWriteTimeout time.Duration
102
-
103
-	// TCPWriteBufferSize, the size of the operating system's write
104
-	// buffer associated with the connection.
105
-	TCPWriteBufferSize int
106
-
107
-	// TCPReadBuffserSize, the size of the operating system's read
108
-	// buffer associated with the connection.
109
-	TCPReadBufferSize int
110
-
111
-	starter   sync.Once
112
-	transport *http.Transport
113
-}
114
-
115
-// Close cleans up the Transport, currently a no-op
116
-func (t *Transport) Close() error {
117
-	return nil
118
-}
119
-
120
-func (t *Transport) lazyStart() {
121
-	if t.Dial == nil {
122
-		t.Dial = func(netw, addr string) (net.Conn, error) {
123
-			c, err := net.DialTimeout(netw, addr, t.ConnectTimeout)
124
-			if err != nil {
125
-				return nil, err
126
-			}
127
-
128
-			if t.TCPReadBufferSize != 0 || t.TCPWriteBufferSize != 0 {
129
-				if tcpCon, ok := c.(*net.TCPConn); ok {
130
-					if t.TCPWriteBufferSize != 0 {
131
-						if err = tcpCon.SetWriteBuffer(t.TCPWriteBufferSize); err != nil {
132
-							return nil, err
133
-						}
134
-					}
135
-					if t.TCPReadBufferSize != 0 {
136
-						if err = tcpCon.SetReadBuffer(t.TCPReadBufferSize); err != nil {
137
-							return nil, err
138
-						}
139
-					}
140
-				} else {
141
-					err = errors.New("Not Tcp Connection")
142
-					return nil, err
143
-				}
144
-			}
145
-
146
-			if t.ReadWriteTimeout > 0 {
147
-				timeoutConn := &rwTimeoutConn{
148
-					TCPConn:   c.(*net.TCPConn),
149
-					rwTimeout: t.ReadWriteTimeout,
150
-				}
151
-				return timeoutConn, nil
152
-			}
153
-			return c, nil
154
-		}
155
-	}
156
-
157
-	t.transport = &http.Transport{
158
-		Dial:                  t.Dial,
159
-		Proxy:                 t.Proxy,
160
-		TLSClientConfig:       t.TLSClientConfig,
161
-		DisableKeepAlives:     t.DisableKeepAlives,
162
-		DisableCompression:    t.DisableCompression,
163
-		MaxIdleConnsPerHost:   t.MaxIdleConnsPerHost,
164
-		ResponseHeaderTimeout: t.ResponseHeaderTimeout,
165
-	}
166
-}
167
-
168
-func (t *Transport) CancelRequest(req *http.Request) {
169
-	t.starter.Do(t.lazyStart)
170
-
171
-	t.transport.CancelRequest(req)
172
-}
173
-
174
-func (t *Transport) CloseIdleConnections() {
175
-	t.starter.Do(t.lazyStart)
176
-
177
-	t.transport.CloseIdleConnections()
178
-}
179
-
180
-func (t *Transport) RegisterProtocol(scheme string, rt http.RoundTripper) {
181
-	t.starter.Do(t.lazyStart)
182
-
183
-	t.transport.RegisterProtocol(scheme, rt)
184
-}
185
-
186
-func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
187
-	t.starter.Do(t.lazyStart)
188
-
189
-	if t.RequestTimeout > 0 {
190
-		timer := time.AfterFunc(t.RequestTimeout, func() {
191
-			t.transport.CancelRequest(req)
192
-		})
193
-
194
-		resp, err = t.transport.RoundTrip(req)
195
-		if err != nil {
196
-			timer.Stop()
197
-		} else {
198
-			resp.Body = &bodyCloseInterceptor{ReadCloser: resp.Body, timer: timer}
199
-		}
200
-	} else {
201
-		resp, err = t.transport.RoundTrip(req)
202
-	}
203
-
204
-	return
205
-}
206
-
207
-type bodyCloseInterceptor struct {
208
-	io.ReadCloser
209
-	timer *time.Timer
210
-}
211
-
212
-func (bci *bodyCloseInterceptor) Close() error {
213
-	bci.timer.Stop()
214
-	return bci.ReadCloser.Close()
215
-}
216
-
217
-// A net.Conn that sets a deadline for every Read or Write operation
218
-type rwTimeoutConn struct {
219
-	*net.TCPConn
220
-	rwTimeout time.Duration
221
-}
222
-
223
-func (c *rwTimeoutConn) Read(b []byte) (int, error) {
224
-	err := c.TCPConn.SetDeadline(time.Now().Add(c.rwTimeout))
225
-	if err != nil {
226
-		return 0, err
227
-	}
228
-	return c.TCPConn.Read(b)
229
-}
230
-
231
-func (c *rwTimeoutConn) Write(b []byte) (int, error) {
232
-	err := c.TCPConn.SetDeadline(time.Now().Add(c.rwTimeout))
233
-	if err != nil {
234
-		return 0, err
235
-	}
236
-	return c.TCPConn.Write(b)
237
-}