Allow multiple handlers to support network plugins in swarm-mode
| ... | ... |
@@ -362,9 +362,8 @@ func (daemon *Daemon) GetNetworkDriverList() []string {
|
| 362 | 362 |
return nil |
| 363 | 363 |
} |
| 364 | 364 |
|
| 365 |
- // TODO: Replace this with proper libnetwork API |
|
| 366 |
- pluginList := []string{"overlay"}
|
|
| 367 |
- pluginMap := map[string]bool{"overlay": true}
|
|
| 365 |
+ pluginList := daemon.netController.BuiltinDrivers() |
|
| 366 |
+ pluginMap := make(map[string]bool) |
|
| 368 | 367 |
|
| 369 | 368 |
networks := daemon.netController.Networks() |
| 370 | 369 |
|
| ... | ... |
@@ -146,7 +146,7 @@ clone git github.com/docker/docker-credential-helpers v0.3.0 |
| 146 | 146 |
clone git github.com/docker/containerd 52ef1ceb4b660c42cf4ea9013180a5663968d4c7 |
| 147 | 147 |
|
| 148 | 148 |
# cluster |
| 149 |
-clone git github.com/docker/swarmkit 7e63bdefb94e5bea2641e8bdebae2cfa61a0ed44 |
|
| 149 |
+clone git github.com/docker/swarmkit 1fed8d2a2ccd2a9b6d6fb864d4ad3461fc6dc3eb |
|
| 150 | 150 |
clone git github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9 |
| 151 | 151 |
clone git github.com/gogo/protobuf v0.3 |
| 152 | 152 |
clone git github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a |
| ... | ... |
@@ -2,6 +2,7 @@ package main |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 |
+ "net/http/httptest" |
|
| 5 | 6 |
"os" |
| 6 | 7 |
"path/filepath" |
| 7 | 8 |
"sync" |
| ... | ... |
@@ -240,6 +241,7 @@ func init() {
|
| 240 | 240 |
} |
| 241 | 241 |
|
| 242 | 242 |
type DockerSwarmSuite struct {
|
| 243 |
+ server *httptest.Server |
|
| 243 | 244 |
ds *DockerSuite |
| 244 | 245 |
daemons []*SwarmDaemon |
| 245 | 246 |
daemonsLock sync.Mutex // protect access to daemons |
| ... | ... |
@@ -3,13 +3,22 @@ |
| 3 | 3 |
package main |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
+ "encoding/json" |
|
| 7 |
+ "fmt" |
|
| 6 | 8 |
"io/ioutil" |
| 9 |
+ "net/http" |
|
| 10 |
+ "net/http/httptest" |
|
| 11 |
+ "os" |
|
| 7 | 12 |
"strings" |
| 8 | 13 |
"time" |
| 9 | 14 |
|
| 10 | 15 |
"github.com/docker/docker/api/types/swarm" |
| 11 | 16 |
"github.com/docker/docker/pkg/integration/checker" |
| 17 |
+ "github.com/docker/libnetwork/driverapi" |
|
| 18 |
+ "github.com/docker/libnetwork/ipamapi" |
|
| 19 |
+ remoteipam "github.com/docker/libnetwork/ipams/remote/api" |
|
| 12 | 20 |
"github.com/go-check/check" |
| 21 |
+ "github.com/vishvananda/netlink" |
|
| 13 | 22 |
) |
| 14 | 23 |
|
| 15 | 24 |
func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) {
|
| ... | ... |
@@ -364,3 +373,198 @@ func (s *DockerSwarmSuite) TestPsListContainersFilterIsTask(c *check.C) {
|
| 364 | 364 |
c.Assert(lines, checker.HasLen, 1) |
| 365 | 365 |
c.Assert(lines[0], checker.Not(checker.Equals), bareID, check.Commentf("Expected not %s, but got it for is-task label, output %q", bareID, out))
|
| 366 | 366 |
} |
| 367 |
+ |
|
| 368 |
+const globalNetworkPlugin = "global-network-plugin" |
|
| 369 |
+const globalIPAMPlugin = "global-ipam-plugin" |
|
| 370 |
+ |
|
| 371 |
+func (s *DockerSwarmSuite) SetUpSuite(c *check.C) {
|
|
| 372 |
+ mux := http.NewServeMux() |
|
| 373 |
+ s.server = httptest.NewServer(mux) |
|
| 374 |
+ c.Assert(s.server, check.NotNil, check.Commentf("Failed to start an HTTP Server"))
|
|
| 375 |
+ setupRemoteGlobalNetworkPlugin(c, mux, s.server.URL, globalNetworkPlugin, globalIPAMPlugin) |
|
| 376 |
+} |
|
| 377 |
+ |
|
| 378 |
+func setupRemoteGlobalNetworkPlugin(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) {
|
|
| 379 |
+ |
|
| 380 |
+ mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
|
|
| 381 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 382 |
+ fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
|
|
| 383 |
+ }) |
|
| 384 |
+ |
|
| 385 |
+ // Network driver implementation |
|
| 386 |
+ mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 387 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 388 |
+ fmt.Fprintf(w, `{"Scope":"global"}`)
|
|
| 389 |
+ }) |
|
| 390 |
+ |
|
| 391 |
+ mux.HandleFunc(fmt.Sprintf("/%s.AllocateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 392 |
+ err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest) |
|
| 393 |
+ if err != nil {
|
|
| 394 |
+ http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) |
|
| 395 |
+ return |
|
| 396 |
+ } |
|
| 397 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 398 |
+ fmt.Fprintf(w, "null") |
|
| 399 |
+ }) |
|
| 400 |
+ |
|
| 401 |
+ mux.HandleFunc(fmt.Sprintf("/%s.FreeNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 402 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 403 |
+ fmt.Fprintf(w, "null") |
|
| 404 |
+ }) |
|
| 405 |
+ |
|
| 406 |
+ mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 407 |
+ err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest) |
|
| 408 |
+ if err != nil {
|
|
| 409 |
+ http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) |
|
| 410 |
+ return |
|
| 411 |
+ } |
|
| 412 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 413 |
+ fmt.Fprintf(w, "null") |
|
| 414 |
+ }) |
|
| 415 |
+ |
|
| 416 |
+ mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 417 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 418 |
+ fmt.Fprintf(w, "null") |
|
| 419 |
+ }) |
|
| 420 |
+ |
|
| 421 |
+ mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 422 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 423 |
+ fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
|
|
| 424 |
+ }) |
|
| 425 |
+ |
|
| 426 |
+ mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 427 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 428 |
+ |
|
| 429 |
+ veth := &netlink.Veth{
|
|
| 430 |
+ LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"}
|
|
| 431 |
+ if err := netlink.LinkAdd(veth); err != nil {
|
|
| 432 |
+ fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`)
|
|
| 433 |
+ } else {
|
|
| 434 |
+ fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
|
|
| 435 |
+ } |
|
| 436 |
+ }) |
|
| 437 |
+ |
|
| 438 |
+ mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 439 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 440 |
+ fmt.Fprintf(w, "null") |
|
| 441 |
+ }) |
|
| 442 |
+ |
|
| 443 |
+ mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 444 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 445 |
+ if link, err := netlink.LinkByName("cnt0"); err == nil {
|
|
| 446 |
+ netlink.LinkDel(link) |
|
| 447 |
+ } |
|
| 448 |
+ fmt.Fprintf(w, "null") |
|
| 449 |
+ }) |
|
| 450 |
+ |
|
| 451 |
+ // IPAM Driver implementation |
|
| 452 |
+ var ( |
|
| 453 |
+ poolRequest remoteipam.RequestPoolRequest |
|
| 454 |
+ poolReleaseReq remoteipam.ReleasePoolRequest |
|
| 455 |
+ addressRequest remoteipam.RequestAddressRequest |
|
| 456 |
+ addressReleaseReq remoteipam.ReleaseAddressRequest |
|
| 457 |
+ lAS = "localAS" |
|
| 458 |
+ gAS = "globalAS" |
|
| 459 |
+ pool = "172.28.0.0/16" |
|
| 460 |
+ poolID = lAS + "/" + pool |
|
| 461 |
+ gw = "172.28.255.254/16" |
|
| 462 |
+ ) |
|
| 463 |
+ |
|
| 464 |
+ mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 465 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 466 |
+ fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
|
|
| 467 |
+ }) |
|
| 468 |
+ |
|
| 469 |
+ mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 470 |
+ err := json.NewDecoder(r.Body).Decode(&poolRequest) |
|
| 471 |
+ if err != nil {
|
|
| 472 |
+ http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) |
|
| 473 |
+ return |
|
| 474 |
+ } |
|
| 475 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 476 |
+ if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS {
|
|
| 477 |
+ fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
|
|
| 478 |
+ } else if poolRequest.Pool != "" && poolRequest.Pool != pool {
|
|
| 479 |
+ fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
|
|
| 480 |
+ } else {
|
|
| 481 |
+ fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
|
|
| 482 |
+ } |
|
| 483 |
+ }) |
|
| 484 |
+ |
|
| 485 |
+ mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 486 |
+ err := json.NewDecoder(r.Body).Decode(&addressRequest) |
|
| 487 |
+ if err != nil {
|
|
| 488 |
+ http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) |
|
| 489 |
+ return |
|
| 490 |
+ } |
|
| 491 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 492 |
+ // make sure libnetwork is now querying on the expected pool id |
|
| 493 |
+ if addressRequest.PoolID != poolID {
|
|
| 494 |
+ fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
|
|
| 495 |
+ } else if addressRequest.Address != "" {
|
|
| 496 |
+ fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`)
|
|
| 497 |
+ } else {
|
|
| 498 |
+ fmt.Fprintf(w, `{"Address":"`+gw+`"}`)
|
|
| 499 |
+ } |
|
| 500 |
+ }) |
|
| 501 |
+ |
|
| 502 |
+ mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 503 |
+ err := json.NewDecoder(r.Body).Decode(&addressReleaseReq) |
|
| 504 |
+ if err != nil {
|
|
| 505 |
+ http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) |
|
| 506 |
+ return |
|
| 507 |
+ } |
|
| 508 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 509 |
+ // make sure libnetwork is now asking to release the expected address from the expected poolid |
|
| 510 |
+ if addressRequest.PoolID != poolID {
|
|
| 511 |
+ fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
|
|
| 512 |
+ } else if addressReleaseReq.Address != gw {
|
|
| 513 |
+ fmt.Fprintf(w, `{"Error":"unknown address"}`)
|
|
| 514 |
+ } else {
|
|
| 515 |
+ fmt.Fprintf(w, "null") |
|
| 516 |
+ } |
|
| 517 |
+ }) |
|
| 518 |
+ |
|
| 519 |
+ mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 520 |
+ err := json.NewDecoder(r.Body).Decode(&poolReleaseReq) |
|
| 521 |
+ if err != nil {
|
|
| 522 |
+ http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest) |
|
| 523 |
+ return |
|
| 524 |
+ } |
|
| 525 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 526 |
+ // make sure libnetwork is now asking to release the expected poolid |
|
| 527 |
+ if addressRequest.PoolID != poolID {
|
|
| 528 |
+ fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
|
|
| 529 |
+ } else {
|
|
| 530 |
+ fmt.Fprintf(w, "null") |
|
| 531 |
+ } |
|
| 532 |
+ }) |
|
| 533 |
+ |
|
| 534 |
+ err := os.MkdirAll("/etc/docker/plugins", 0755)
|
|
| 535 |
+ c.Assert(err, checker.IsNil) |
|
| 536 |
+ |
|
| 537 |
+ fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
|
|
| 538 |
+ err = ioutil.WriteFile(fileName, []byte(url), 0644) |
|
| 539 |
+ c.Assert(err, checker.IsNil) |
|
| 540 |
+ |
|
| 541 |
+ ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
|
|
| 542 |
+ err = ioutil.WriteFile(ipamFileName, []byte(url), 0644) |
|
| 543 |
+ c.Assert(err, checker.IsNil) |
|
| 544 |
+} |
|
| 545 |
+ |
|
| 546 |
+func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *check.C) {
|
|
| 547 |
+ d := s.AddDaemon(c, true, true) |
|
| 548 |
+ |
|
| 549 |
+ out, err := d.Cmd("network", "create", "-d", globalNetworkPlugin, "foo")
|
|
| 550 |
+ c.Assert(err, checker.IsNil) |
|
| 551 |
+ c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") |
|
| 552 |
+ |
|
| 553 |
+ name := "top" |
|
| 554 |
+ out, err = d.Cmd("service", "create", "--name", name, "--network", "foo", "busybox", "top")
|
|
| 555 |
+ c.Assert(err, checker.IsNil) |
|
| 556 |
+ c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") |
|
| 557 |
+ |
|
| 558 |
+ out, err = d.Cmd("service", "inspect", "--format", "{{range .Spec.Networks}}{{.Target}}{{end}}", name)
|
|
| 559 |
+ c.Assert(err, checker.IsNil) |
|
| 560 |
+ c.Assert(strings.TrimSpace(out), checker.Equals, "foo") |
|
| 561 |
+} |
| ... | ... |
@@ -43,7 +43,7 @@ type plugins struct {
|
| 43 | 43 |
|
| 44 | 44 |
var ( |
| 45 | 45 |
storage = plugins{plugins: make(map[string]*Plugin)}
|
| 46 |
- extpointHandlers = make(map[string]func(string, *Client)) |
|
| 46 |
+ extpointHandlers = make(map[string][]func(string, *Client)) |
|
| 47 | 47 |
) |
| 48 | 48 |
|
| 49 | 49 |
// Manifest lists what a plugin implements. |
| ... | ... |
@@ -129,11 +129,13 @@ func (p *Plugin) activateWithLock() error {
|
| 129 | 129 |
p.Manifest = m |
| 130 | 130 |
|
| 131 | 131 |
for _, iface := range m.Implements {
|
| 132 |
- handler, handled := extpointHandlers[iface] |
|
| 132 |
+ handlers, handled := extpointHandlers[iface] |
|
| 133 | 133 |
if !handled {
|
| 134 | 134 |
continue |
| 135 | 135 |
} |
| 136 |
- handler(p.name, p.client) |
|
| 136 |
+ for _, handler := range handlers {
|
|
| 137 |
+ handler(p.name, p.client) |
|
| 138 |
+ } |
|
| 137 | 139 |
} |
| 138 | 140 |
return nil |
| 139 | 141 |
} |
| ... | ... |
@@ -226,7 +228,16 @@ func Get(name, imp string) (*Plugin, error) {
|
| 226 | 226 |
|
| 227 | 227 |
// Handle adds the specified function to the extpointHandlers. |
| 228 | 228 |
func Handle(iface string, fn func(string, *Client)) {
|
| 229 |
- extpointHandlers[iface] = fn |
|
| 229 |
+ handlers, ok := extpointHandlers[iface] |
|
| 230 |
+ if !ok {
|
|
| 231 |
+ handlers = []func(string, *Client){}
|
|
| 232 |
+ } |
|
| 233 |
+ |
|
| 234 |
+ handlers = append(handlers, fn) |
|
| 235 |
+ extpointHandlers[iface] = handlers |
|
| 236 |
+ for _, p := range storage.plugins {
|
|
| 237 |
+ p.activated = false |
|
| 238 |
+ } |
|
| 230 | 239 |
} |
| 231 | 240 |
|
| 232 | 241 |
// GetAll returns all the plugins for the specified implementation |
| ... | ... |
@@ -15,7 +15,7 @@ type Store struct {
|
| 15 | 15 |
/* handlers are necessary for transition path of legacy plugins |
| 16 | 16 |
* to the new model. Legacy plugins use Handle() for registering an |
| 17 | 17 |
* activation callback.*/ |
| 18 |
- handlers map[string]func(string, *plugins.Client) |
|
| 18 |
+ handlers map[string][]func(string, *plugins.Client) |
|
| 19 | 19 |
nameToID map[string]string |
| 20 | 20 |
plugindb string |
| 21 | 21 |
} |
| ... | ... |
@@ -24,7 +24,7 @@ type Store struct {
|
| 24 | 24 |
func NewStore(libRoot string) *Store {
|
| 25 | 25 |
return &Store{
|
| 26 | 26 |
plugins: make(map[string]*v2.Plugin), |
| 27 |
- handlers: make(map[string]func(string, *plugins.Client)), |
|
| 27 |
+ handlers: make(map[string][]func(string, *plugins.Client)), |
|
| 28 | 28 |
nameToID: make(map[string]string), |
| 29 | 29 |
plugindb: filepath.Join(libRoot, "plugins", "plugins.json"), |
| 30 | 30 |
} |
| ... | ... |
@@ -218,7 +218,12 @@ func (ps *Store) Handle(capability string, callback func(string, *plugins.Client |
| 218 | 218 |
|
| 219 | 219 |
// Register callback with new plugin model. |
| 220 | 220 |
ps.Lock() |
| 221 |
- ps.handlers[pluginType] = callback |
|
| 221 |
+ handlers, ok := ps.handlers[pluginType] |
|
| 222 |
+ if !ok {
|
|
| 223 |
+ handlers = []func(string, *plugins.Client){}
|
|
| 224 |
+ } |
|
| 225 |
+ handlers = append(handlers, callback) |
|
| 226 |
+ ps.handlers[pluginType] = handlers |
|
| 222 | 227 |
ps.Unlock() |
| 223 | 228 |
|
| 224 | 229 |
// Register callback with legacy plugin model. |
| ... | ... |
@@ -230,7 +235,7 @@ func (ps *Store) Handle(capability string, callback func(string, *plugins.Client |
| 230 | 230 |
// CallHandler calls the registered callback. It is invoked during plugin enable. |
| 231 | 231 |
func (ps *Store) CallHandler(p *v2.Plugin) {
|
| 232 | 232 |
for _, typ := range p.GetTypes() {
|
| 233 |
- if handler := ps.handlers[typ.String()]; handler != nil {
|
|
| 233 |
+ for _, handler := range ps.handlers[typ.String()] {
|
|
| 234 | 234 |
handler(p.Name(), p.Client()) |
| 235 | 235 |
} |
| 236 | 236 |
} |
| ... | ... |
@@ -171,11 +171,12 @@ func (a *Agent) run(ctx context.Context) {
|
| 171 | 171 |
case msg := <-session.assignments: |
| 172 | 172 |
switch msg.Type {
|
| 173 | 173 |
case api.AssignmentsMessage_COMPLETE: |
| 174 |
- if err := a.worker.AssignTasks(ctx, msg.UpdateTasks); err != nil {
|
|
| 174 |
+ // Need to assign secrets before tasks, because tasks might depend on new secrets |
|
| 175 |
+ if err := a.worker.Assign(ctx, msg.Changes); err != nil {
|
|
| 175 | 176 |
log.G(ctx).WithError(err).Error("failed to synchronize worker assignments")
|
| 176 | 177 |
} |
| 177 | 178 |
case api.AssignmentsMessage_INCREMENTAL: |
| 178 |
- if err := a.worker.UpdateTasks(ctx, msg.UpdateTasks, msg.RemoveTasks); err != nil {
|
|
| 179 |
+ if err := a.worker.Update(ctx, msg.Changes); err != nil {
|
|
| 179 | 180 |
log.G(ctx).WithError(err).Error("failed to update worker assignments")
|
| 180 | 181 |
} |
| 181 | 182 |
} |
| ... | ... |
@@ -101,6 +101,21 @@ type Node struct {
|
| 101 | 101 |
roleChangeReq chan api.NodeRole // used to send role updates from the dispatcher api on promotion/demotion |
| 102 | 102 |
} |
| 103 | 103 |
|
| 104 |
+// RemoteAPIAddr returns address on which remote manager api listens. |
|
| 105 |
+// Returns nil if node is not manager. |
|
| 106 |
+func (n *Node) RemoteAPIAddr() (string, error) {
|
|
| 107 |
+ n.RLock() |
|
| 108 |
+ defer n.RUnlock() |
|
| 109 |
+ if n.manager == nil {
|
|
| 110 |
+ return "", errors.Errorf("node is not manager")
|
|
| 111 |
+ } |
|
| 112 |
+ addr := n.manager.Addr() |
|
| 113 |
+ if addr == nil {
|
|
| 114 |
+ return "", errors.Errorf("manager addr is not set")
|
|
| 115 |
+ } |
|
| 116 |
+ return addr.String(), nil |
|
| 117 |
+} |
|
| 118 |
+ |
|
| 104 | 119 |
// NewNode returns new Node instance. |
| 105 | 120 |
func NewNode(c *NodeConfig) (*Node, error) {
|
| 106 | 121 |
if err := os.MkdirAll(c.StateDir, 0700); err != nil {
|
| ... | ... |
@@ -627,7 +642,12 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig |
| 627 | 627 |
go func(ready chan struct{}) {
|
| 628 | 628 |
select {
|
| 629 | 629 |
case <-ready: |
| 630 |
- n.remotes.Observe(api.Peer{NodeID: n.NodeID(), Addr: n.config.ListenRemoteAPI}, remotes.DefaultObservationWeight)
|
|
| 630 |
+ addr, err := n.RemoteAPIAddr() |
|
| 631 |
+ if err != nil {
|
|
| 632 |
+ log.G(ctx).WithError(err).Errorf("get remote api addr")
|
|
| 633 |
+ } else {
|
|
| 634 |
+ n.remotes.Observe(api.Peer{NodeID: n.NodeID(), Addr: addr}, remotes.DefaultObservationWeight)
|
|
| 635 |
+ } |
|
| 631 | 636 |
case <-connCtx.Done(): |
| 632 | 637 |
} |
| 633 | 638 |
}(ready) |
| 634 | 639 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,53 @@ |
| 0 |
+package agent |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "sync" |
|
| 4 |
+ |
|
| 5 |
+ "github.com/docker/swarmkit/api" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+// secrets is a map that keeps all the currenty available secrets to the agent |
|
| 9 |
+// mapped by secret ID |
|
| 10 |
+type secrets struct {
|
|
| 11 |
+ mu sync.RWMutex |
|
| 12 |
+ m map[string]api.Secret |
|
| 13 |
+} |
|
| 14 |
+ |
|
| 15 |
+func newSecrets() *secrets {
|
|
| 16 |
+ return &secrets{
|
|
| 17 |
+ m: make(map[string]api.Secret), |
|
| 18 |
+ } |
|
| 19 |
+} |
|
| 20 |
+ |
|
| 21 |
+// Get returns a secret by ID. If the secret doesn't exist, returns nil. |
|
| 22 |
+func (s *secrets) Get(secretID string) api.Secret {
|
|
| 23 |
+ s.mu.RLock() |
|
| 24 |
+ defer s.mu.RUnlock() |
|
| 25 |
+ return s.m[secretID] |
|
| 26 |
+} |
|
| 27 |
+ |
|
| 28 |
+// Add adds one or more secrets to the secret map |
|
| 29 |
+func (s *secrets) Add(secrets ...api.Secret) {
|
|
| 30 |
+ s.mu.Lock() |
|
| 31 |
+ defer s.mu.Unlock() |
|
| 32 |
+ for _, secret := range secrets {
|
|
| 33 |
+ s.m[secret.ID] = secret |
|
| 34 |
+ } |
|
| 35 |
+} |
|
| 36 |
+ |
|
| 37 |
+// Remove removes one or more secrets by ID from the secret map. Succeeds |
|
| 38 |
+// whether or not the given IDs are in the map. |
|
| 39 |
+func (s *secrets) Remove(secrets []string) {
|
|
| 40 |
+ s.mu.Lock() |
|
| 41 |
+ defer s.mu.Unlock() |
|
| 42 |
+ for _, secret := range secrets {
|
|
| 43 |
+ delete(s.m, secret) |
|
| 44 |
+ } |
|
| 45 |
+} |
|
| 46 |
+ |
|
| 47 |
+// Reset removes all the secrets |
|
| 48 |
+func (s *secrets) Reset() {
|
|
| 49 |
+ s.mu.Lock() |
|
| 50 |
+ defer s.mu.Unlock() |
|
| 51 |
+ s.m = make(map[string]api.Secret) |
|
| 52 |
+} |
| ... | ... |
@@ -252,12 +252,26 @@ func (s *session) watch(ctx context.Context) error {
|
| 252 | 252 |
} |
| 253 | 253 |
} |
| 254 | 254 |
if tasksWatch != nil {
|
| 255 |
+ // When falling back to Tasks because of an old managers, we wrap the tasks in assignments. |
|
| 255 | 256 |
var taskResp *api.TasksMessage |
| 257 |
+ var assignmentChanges []*api.AssignmentChange |
|
| 256 | 258 |
taskResp, err = tasksWatch.Recv() |
| 257 | 259 |
if err != nil {
|
| 258 | 260 |
return err |
| 259 | 261 |
} |
| 260 |
- resp = &api.AssignmentsMessage{Type: api.AssignmentsMessage_COMPLETE, UpdateTasks: taskResp.Tasks}
|
|
| 262 |
+ for _, t := range taskResp.Tasks {
|
|
| 263 |
+ taskChange := &api.AssignmentChange{
|
|
| 264 |
+ Assignment: &api.Assignment{
|
|
| 265 |
+ Item: &api.Assignment_Task{
|
|
| 266 |
+ Task: t, |
|
| 267 |
+ }, |
|
| 268 |
+ }, |
|
| 269 |
+ Action: api.AssignmentChange_AssignmentActionUpdate, |
|
| 270 |
+ } |
|
| 271 |
+ |
|
| 272 |
+ assignmentChanges = append(assignmentChanges, taskChange) |
|
| 273 |
+ } |
|
| 274 |
+ resp = &api.AssignmentsMessage{Type: api.AssignmentsMessage_COMPLETE, Changes: assignmentChanges}
|
|
| 261 | 275 |
} |
| 262 | 276 |
|
| 263 | 277 |
// If there seems to be a gap in the stream, let's break out of the inner for and |
| ... | ... |
@@ -17,13 +17,13 @@ type Worker interface {
|
| 17 | 17 |
// Init prepares the worker for task assignment. |
| 18 | 18 |
Init(ctx context.Context) error |
| 19 | 19 |
|
| 20 |
- // AssignTasks assigns a complete set of tasks to a worker. Any task not included in |
|
| 20 |
+ // Assign assigns a complete set of tasks and secrets to a worker. Any task or secrets not included in |
|
| 21 | 21 |
// this set will be removed. |
| 22 |
- AssignTasks(ctx context.Context, tasks []*api.Task) error |
|
| 22 |
+ Assign(ctx context.Context, assignments []*api.AssignmentChange) error |
|
| 23 | 23 |
|
| 24 |
- // UpdateTasks updates an incremental set of tasks to the worker. Any task not included |
|
| 24 |
+ // Updates updates an incremental set of tasks or secrets of the worker. Any task/secret not included |
|
| 25 | 25 |
// either in added or removed will remain untouched. |
| 26 |
- UpdateTasks(ctx context.Context, added []*api.Task, removed []string) error |
|
| 26 |
+ Update(ctx context.Context, assignments []*api.AssignmentChange) error |
|
| 27 | 27 |
|
| 28 | 28 |
// Listen to updates about tasks controlled by the worker. When first |
| 29 | 29 |
// called, the reporter will receive all updates for all tasks controlled |
| ... | ... |
@@ -42,6 +42,7 @@ type worker struct {
|
| 42 | 42 |
db *bolt.DB |
| 43 | 43 |
executor exec.Executor |
| 44 | 44 |
listeners map[*statusReporterKey]struct{}
|
| 45 |
+ secrets *secrets |
|
| 45 | 46 |
|
| 46 | 47 |
taskManagers map[string]*taskManager |
| 47 | 48 |
mu sync.RWMutex |
| ... | ... |
@@ -53,6 +54,7 @@ func newWorker(db *bolt.DB, executor exec.Executor) *worker {
|
| 53 | 53 |
executor: executor, |
| 54 | 54 |
listeners: make(map[*statusReporterKey]struct{}),
|
| 55 | 55 |
taskManagers: make(map[string]*taskManager), |
| 56 |
+ secrets: newSecrets(), |
|
| 56 | 57 |
} |
| 57 | 58 |
} |
| 58 | 59 |
|
| ... | ... |
@@ -90,37 +92,70 @@ func (w *worker) Init(ctx context.Context) error {
|
| 90 | 90 |
}) |
| 91 | 91 |
} |
| 92 | 92 |
|
| 93 |
-// AssignTasks assigns the set of tasks to the worker. Any tasks not previously known will |
|
| 94 |
-// be started. Any tasks that are in the task set and already running will be |
|
| 95 |
-// updated, if possible. Any tasks currently running on the |
|
| 96 |
-// worker outside the task set will be terminated. |
|
| 97 |
-func (w *worker) AssignTasks(ctx context.Context, tasks []*api.Task) error {
|
|
| 93 |
+// Assign assigns a full set of tasks and secrets to the worker. |
|
| 94 |
+// Any tasks not previously known will be started. Any tasks that are in the task set |
|
| 95 |
+// and already running will be updated, if possible. Any tasks currently running on |
|
| 96 |
+// the worker outside the task set will be terminated. |
|
| 97 |
+// Any secrets not in the set of assignments will be removed. |
|
| 98 |
+func (w *worker) Assign(ctx context.Context, assignments []*api.AssignmentChange) error {
|
|
| 98 | 99 |
w.mu.Lock() |
| 99 | 100 |
defer w.mu.Unlock() |
| 100 | 101 |
|
| 101 | 102 |
log.G(ctx).WithFields(logrus.Fields{
|
| 102 |
- "len(tasks)": len(tasks), |
|
| 103 |
- }).Debug("(*worker).AssignTasks")
|
|
| 103 |
+ "len(assignments)": len(assignments), |
|
| 104 |
+ }).Debug("(*worker).Assign")
|
|
| 104 | 105 |
|
| 105 |
- return reconcileTaskState(ctx, w, tasks, nil, true) |
|
| 106 |
+ // Need to update secrets before tasks, because tasks might depend on new secrets |
|
| 107 |
+ err := reconcileSecrets(ctx, w, assignments, true) |
|
| 108 |
+ if err != nil {
|
|
| 109 |
+ return err |
|
| 110 |
+ } |
|
| 111 |
+ |
|
| 112 |
+ return reconcileTaskState(ctx, w, assignments, true) |
|
| 106 | 113 |
} |
| 107 | 114 |
|
| 108 |
-// UpdateTasks the set of tasks to the worker. |
|
| 115 |
+// Update updates the set of tasks and secret for the worker. |
|
| 109 | 116 |
// Tasks in the added set will be added to the worker, and tasks in the removed set |
| 110 | 117 |
// will be removed from the worker |
| 111 |
-func (w *worker) UpdateTasks(ctx context.Context, added []*api.Task, removed []string) error {
|
|
| 118 |
+// Serets in the added set will be added to the worker, and secrets in the removed set |
|
| 119 |
+// will be removed from the worker. |
|
| 120 |
+func (w *worker) Update(ctx context.Context, assignments []*api.AssignmentChange) error {
|
|
| 112 | 121 |
w.mu.Lock() |
| 113 | 122 |
defer w.mu.Unlock() |
| 114 | 123 |
|
| 115 | 124 |
log.G(ctx).WithFields(logrus.Fields{
|
| 116 |
- "len(added)": len(added), |
|
| 117 |
- "len(removed)": len(removed), |
|
| 118 |
- }).Debug("(*worker).UpdateTasks")
|
|
| 125 |
+ "len(assignments)": len(assignments), |
|
| 126 |
+ }).Debug("(*worker).Update")
|
|
| 127 |
+ |
|
| 128 |
+ err := reconcileSecrets(ctx, w, assignments, false) |
|
| 129 |
+ if err != nil {
|
|
| 130 |
+ return err |
|
| 131 |
+ } |
|
| 119 | 132 |
|
| 120 |
- return reconcileTaskState(ctx, w, added, removed, false) |
|
| 133 |
+ return reconcileTaskState(ctx, w, assignments, false) |
|
| 121 | 134 |
} |
| 122 | 135 |
|
| 123 |
-func reconcileTaskState(ctx context.Context, w *worker, added []*api.Task, removed []string, fullSnapshot bool) error {
|
|
| 136 |
+func reconcileTaskState(ctx context.Context, w *worker, assignments []*api.AssignmentChange, fullSnapshot bool) error {
|
|
| 137 |
+ var ( |
|
| 138 |
+ updatedTasks []*api.Task |
|
| 139 |
+ removedTasks []*api.Task |
|
| 140 |
+ ) |
|
| 141 |
+ for _, a := range assignments {
|
|
| 142 |
+ if t := a.Assignment.GetTask(); t != nil {
|
|
| 143 |
+ switch a.Action {
|
|
| 144 |
+ case api.AssignmentChange_AssignmentActionUpdate: |
|
| 145 |
+ updatedTasks = append(updatedTasks, t) |
|
| 146 |
+ case api.AssignmentChange_AssignmentActionRemove: |
|
| 147 |
+ removedTasks = append(removedTasks, t) |
|
| 148 |
+ } |
|
| 149 |
+ } |
|
| 150 |
+ } |
|
| 151 |
+ |
|
| 152 |
+ log.G(ctx).WithFields(logrus.Fields{
|
|
| 153 |
+ "len(updatedTasks)": len(updatedTasks), |
|
| 154 |
+ "len(removedTasks)": len(removedTasks), |
|
| 155 |
+ }).Debug("(*worker).reconcileTaskState")
|
|
| 156 |
+ |
|
| 124 | 157 |
tx, err := w.db.Begin(true) |
| 125 | 158 |
if err != nil {
|
| 126 | 159 |
log.G(ctx).WithError(err).Error("failed starting transaction against task database")
|
| ... | ... |
@@ -130,7 +165,7 @@ func reconcileTaskState(ctx context.Context, w *worker, added []*api.Task, remov |
| 130 | 130 |
|
| 131 | 131 |
assigned := map[string]struct{}{}
|
| 132 | 132 |
|
| 133 |
- for _, task := range added {
|
|
| 133 |
+ for _, task := range updatedTasks {
|
|
| 134 | 134 |
log.G(ctx).WithFields( |
| 135 | 135 |
logrus.Fields{
|
| 136 | 136 |
"task.id": task.ID, |
| ... | ... |
@@ -202,15 +237,15 @@ func reconcileTaskState(ctx context.Context, w *worker, added []*api.Task, remov |
| 202 | 202 |
} else {
|
| 203 | 203 |
// If this was an incremental set of assignments, we're going to remove only the tasks |
| 204 | 204 |
// in the removed set |
| 205 |
- for _, taskID := range removed {
|
|
| 206 |
- err := removeTaskAssignment(taskID) |
|
| 205 |
+ for _, task := range removedTasks {
|
|
| 206 |
+ err := removeTaskAssignment(task.ID) |
|
| 207 | 207 |
if err != nil {
|
| 208 | 208 |
continue |
| 209 | 209 |
} |
| 210 | 210 |
|
| 211 |
- tm, ok := w.taskManagers[taskID] |
|
| 211 |
+ tm, ok := w.taskManagers[task.ID] |
|
| 212 | 212 |
if ok {
|
| 213 |
- delete(w.taskManagers, taskID) |
|
| 213 |
+ delete(w.taskManagers, task.ID) |
|
| 214 | 214 |
go closeManager(tm) |
| 215 | 215 |
} |
| 216 | 216 |
} |
| ... | ... |
@@ -219,6 +254,39 @@ func reconcileTaskState(ctx context.Context, w *worker, added []*api.Task, remov |
| 219 | 219 |
return tx.Commit() |
| 220 | 220 |
} |
| 221 | 221 |
|
| 222 |
+func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.AssignmentChange, fullSnapshot bool) error {
|
|
| 223 |
+ var ( |
|
| 224 |
+ updatedSecrets []api.Secret |
|
| 225 |
+ removedSecrets []string |
|
| 226 |
+ ) |
|
| 227 |
+ for _, a := range assignments {
|
|
| 228 |
+ if s := a.Assignment.GetSecret(); s != nil {
|
|
| 229 |
+ switch a.Action {
|
|
| 230 |
+ case api.AssignmentChange_AssignmentActionUpdate: |
|
| 231 |
+ updatedSecrets = append(updatedSecrets, *s) |
|
| 232 |
+ case api.AssignmentChange_AssignmentActionRemove: |
|
| 233 |
+ removedSecrets = append(removedSecrets, s.ID) |
|
| 234 |
+ } |
|
| 235 |
+ |
|
| 236 |
+ } |
|
| 237 |
+ } |
|
| 238 |
+ |
|
| 239 |
+ log.G(ctx).WithFields(logrus.Fields{
|
|
| 240 |
+ "len(updatedSecrets)": len(updatedSecrets), |
|
| 241 |
+ "len(removedSecrets)": len(removedSecrets), |
|
| 242 |
+ }).Debug("(*worker).reconcileSecrets")
|
|
| 243 |
+ |
|
| 244 |
+ // If this was a complete set of secrets, we're going to clear the secrets map and add all of them |
|
| 245 |
+ if fullSnapshot {
|
|
| 246 |
+ w.secrets.Reset() |
|
| 247 |
+ } else {
|
|
| 248 |
+ w.secrets.Remove(removedSecrets) |
|
| 249 |
+ } |
|
| 250 |
+ w.secrets.Add(updatedSecrets...) |
|
| 251 |
+ |
|
| 252 |
+ return nil |
|
| 253 |
+} |
|
| 254 |
+ |
|
| 222 | 255 |
func (w *worker) Listen(ctx context.Context, reporter StatusReporter) {
|
| 223 | 256 |
w.mu.Lock() |
| 224 | 257 |
defer w.mu.Unlock() |
| ... | ... |
@@ -35,6 +35,29 @@ var _ = proto.Marshal |
| 35 | 35 |
var _ = fmt.Errorf |
| 36 | 36 |
var _ = math.Inf |
| 37 | 37 |
|
| 38 |
+type AssignmentChange_AssignmentAction int32 |
|
| 39 |
+ |
|
| 40 |
+const ( |
|
| 41 |
+ AssignmentChange_AssignmentActionUpdate AssignmentChange_AssignmentAction = 0 |
|
| 42 |
+ AssignmentChange_AssignmentActionRemove AssignmentChange_AssignmentAction = 1 |
|
| 43 |
+) |
|
| 44 |
+ |
|
| 45 |
+var AssignmentChange_AssignmentAction_name = map[int32]string{
|
|
| 46 |
+ 0: "UPDATE", |
|
| 47 |
+ 1: "REMOVE", |
|
| 48 |
+} |
|
| 49 |
+var AssignmentChange_AssignmentAction_value = map[string]int32{
|
|
| 50 |
+ "UPDATE": 0, |
|
| 51 |
+ "REMOVE": 1, |
|
| 52 |
+} |
|
| 53 |
+ |
|
| 54 |
+func (x AssignmentChange_AssignmentAction) String() string {
|
|
| 55 |
+ return proto.EnumName(AssignmentChange_AssignmentAction_name, int32(x)) |
|
| 56 |
+} |
|
| 57 |
+func (AssignmentChange_AssignmentAction) EnumDescriptor() ([]byte, []int) {
|
|
| 58 |
+ return fileDescriptorDispatcher, []int{10, 0}
|
|
| 59 |
+} |
|
| 60 |
+ |
|
| 38 | 61 |
// AssignmentType specifies whether this assignment message carries |
| 39 | 62 |
// the full state, or is an update to an existing state. |
| 40 | 63 |
type AssignmentsMessage_Type int32 |
| ... | ... |
@@ -57,7 +80,7 @@ func (x AssignmentsMessage_Type) String() string {
|
| 57 | 57 |
return proto.EnumName(AssignmentsMessage_Type_name, int32(x)) |
| 58 | 58 |
} |
| 59 | 59 |
func (AssignmentsMessage_Type) EnumDescriptor() ([]byte, []int) {
|
| 60 |
- return fileDescriptorDispatcher, []int{9, 0}
|
|
| 60 |
+ return fileDescriptorDispatcher, []int{11, 0}
|
|
| 61 | 61 |
} |
| 62 | 62 |
|
| 63 | 63 |
// SessionRequest starts a session. |
| ... | ... |
@@ -214,6 +237,137 @@ func (m *AssignmentsRequest) Reset() { *m = AssignmentsReques
|
| 214 | 214 |
func (*AssignmentsRequest) ProtoMessage() {}
|
| 215 | 215 |
func (*AssignmentsRequest) Descriptor() ([]byte, []int) { return fileDescriptorDispatcher, []int{8} }
|
| 216 | 216 |
|
| 217 |
+type Assignment struct {
|
|
| 218 |
+ // Types that are valid to be assigned to Item: |
|
| 219 |
+ // *Assignment_Task |
|
| 220 |
+ // *Assignment_Secret |
|
| 221 |
+ Item isAssignment_Item `protobuf_oneof:"item"` |
|
| 222 |
+} |
|
| 223 |
+ |
|
| 224 |
+func (m *Assignment) Reset() { *m = Assignment{} }
|
|
| 225 |
+func (*Assignment) ProtoMessage() {}
|
|
| 226 |
+func (*Assignment) Descriptor() ([]byte, []int) { return fileDescriptorDispatcher, []int{9} }
|
|
| 227 |
+ |
|
| 228 |
+type isAssignment_Item interface {
|
|
| 229 |
+ isAssignment_Item() |
|
| 230 |
+ MarshalTo([]byte) (int, error) |
|
| 231 |
+ Size() int |
|
| 232 |
+} |
|
| 233 |
+ |
|
| 234 |
+type Assignment_Task struct {
|
|
| 235 |
+ Task *Task `protobuf:"bytes,1,opt,name=task,oneof"` |
|
| 236 |
+} |
|
| 237 |
+type Assignment_Secret struct {
|
|
| 238 |
+ Secret *Secret `protobuf:"bytes,2,opt,name=secret,oneof"` |
|
| 239 |
+} |
|
| 240 |
+ |
|
| 241 |
+func (*Assignment_Task) isAssignment_Item() {}
|
|
| 242 |
+func (*Assignment_Secret) isAssignment_Item() {}
|
|
| 243 |
+ |
|
| 244 |
+func (m *Assignment) GetItem() isAssignment_Item {
|
|
| 245 |
+ if m != nil {
|
|
| 246 |
+ return m.Item |
|
| 247 |
+ } |
|
| 248 |
+ return nil |
|
| 249 |
+} |
|
| 250 |
+ |
|
| 251 |
+func (m *Assignment) GetTask() *Task {
|
|
| 252 |
+ if x, ok := m.GetItem().(*Assignment_Task); ok {
|
|
| 253 |
+ return x.Task |
|
| 254 |
+ } |
|
| 255 |
+ return nil |
|
| 256 |
+} |
|
| 257 |
+ |
|
| 258 |
+func (m *Assignment) GetSecret() *Secret {
|
|
| 259 |
+ if x, ok := m.GetItem().(*Assignment_Secret); ok {
|
|
| 260 |
+ return x.Secret |
|
| 261 |
+ } |
|
| 262 |
+ return nil |
|
| 263 |
+} |
|
| 264 |
+ |
|
| 265 |
+// XXX_OneofFuncs is for the internal use of the proto package. |
|
| 266 |
+func (*Assignment) 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{}) {
|
|
| 267 |
+ return _Assignment_OneofMarshaler, _Assignment_OneofUnmarshaler, _Assignment_OneofSizer, []interface{}{
|
|
| 268 |
+ (*Assignment_Task)(nil), |
|
| 269 |
+ (*Assignment_Secret)(nil), |
|
| 270 |
+ } |
|
| 271 |
+} |
|
| 272 |
+ |
|
| 273 |
+func _Assignment_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
|
|
| 274 |
+ m := msg.(*Assignment) |
|
| 275 |
+ // item |
|
| 276 |
+ switch x := m.Item.(type) {
|
|
| 277 |
+ case *Assignment_Task: |
|
| 278 |
+ _ = b.EncodeVarint(1<<3 | proto.WireBytes) |
|
| 279 |
+ if err := b.EncodeMessage(x.Task); err != nil {
|
|
| 280 |
+ return err |
|
| 281 |
+ } |
|
| 282 |
+ case *Assignment_Secret: |
|
| 283 |
+ _ = b.EncodeVarint(2<<3 | proto.WireBytes) |
|
| 284 |
+ if err := b.EncodeMessage(x.Secret); err != nil {
|
|
| 285 |
+ return err |
|
| 286 |
+ } |
|
| 287 |
+ case nil: |
|
| 288 |
+ default: |
|
| 289 |
+ return fmt.Errorf("Assignment.Item has unexpected type %T", x)
|
|
| 290 |
+ } |
|
| 291 |
+ return nil |
|
| 292 |
+} |
|
| 293 |
+ |
|
| 294 |
+func _Assignment_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
|
|
| 295 |
+ m := msg.(*Assignment) |
|
| 296 |
+ switch tag {
|
|
| 297 |
+ case 1: // item.task |
|
| 298 |
+ if wire != proto.WireBytes {
|
|
| 299 |
+ return true, proto.ErrInternalBadWireType |
|
| 300 |
+ } |
|
| 301 |
+ msg := new(Task) |
|
| 302 |
+ err := b.DecodeMessage(msg) |
|
| 303 |
+ m.Item = &Assignment_Task{msg}
|
|
| 304 |
+ return true, err |
|
| 305 |
+ case 2: // item.secret |
|
| 306 |
+ if wire != proto.WireBytes {
|
|
| 307 |
+ return true, proto.ErrInternalBadWireType |
|
| 308 |
+ } |
|
| 309 |
+ msg := new(Secret) |
|
| 310 |
+ err := b.DecodeMessage(msg) |
|
| 311 |
+ m.Item = &Assignment_Secret{msg}
|
|
| 312 |
+ return true, err |
|
| 313 |
+ default: |
|
| 314 |
+ return false, nil |
|
| 315 |
+ } |
|
| 316 |
+} |
|
| 317 |
+ |
|
| 318 |
+func _Assignment_OneofSizer(msg proto.Message) (n int) {
|
|
| 319 |
+ m := msg.(*Assignment) |
|
| 320 |
+ // item |
|
| 321 |
+ switch x := m.Item.(type) {
|
|
| 322 |
+ case *Assignment_Task: |
|
| 323 |
+ s := proto.Size(x.Task) |
|
| 324 |
+ n += proto.SizeVarint(1<<3 | proto.WireBytes) |
|
| 325 |
+ n += proto.SizeVarint(uint64(s)) |
|
| 326 |
+ n += s |
|
| 327 |
+ case *Assignment_Secret: |
|
| 328 |
+ s := proto.Size(x.Secret) |
|
| 329 |
+ n += proto.SizeVarint(2<<3 | proto.WireBytes) |
|
| 330 |
+ n += proto.SizeVarint(uint64(s)) |
|
| 331 |
+ n += s |
|
| 332 |
+ case nil: |
|
| 333 |
+ default: |
|
| 334 |
+ panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
|
|
| 335 |
+ } |
|
| 336 |
+ return n |
|
| 337 |
+} |
|
| 338 |
+ |
|
| 339 |
+type AssignmentChange struct {
|
|
| 340 |
+ Assignment *Assignment `protobuf:"bytes,1,opt,name=assignment" json:"assignment,omitempty"` |
|
| 341 |
+ Action AssignmentChange_AssignmentAction `protobuf:"varint,2,opt,name=action,proto3,enum=docker.swarmkit.v1.AssignmentChange_AssignmentAction" json:"action,omitempty"` |
|
| 342 |
+} |
|
| 343 |
+ |
|
| 344 |
+func (m *AssignmentChange) Reset() { *m = AssignmentChange{} }
|
|
| 345 |
+func (*AssignmentChange) ProtoMessage() {}
|
|
| 346 |
+func (*AssignmentChange) Descriptor() ([]byte, []int) { return fileDescriptorDispatcher, []int{10} }
|
|
| 347 |
+ |
|
| 217 | 348 |
type AssignmentsMessage struct {
|
| 218 | 349 |
Type AssignmentsMessage_Type `protobuf:"varint,1,opt,name=type,proto3,enum=docker.swarmkit.v1.AssignmentsMessage_Type" json:"type,omitempty"` |
| 219 | 350 |
// AppliesTo references the previous ResultsIn value, to chain |
| ... | ... |
@@ -226,28 +380,13 @@ type AssignmentsMessage struct {
|
| 226 | 226 |
// match against the next message's AppliesTo value and protect |
| 227 | 227 |
// against missed messages. |
| 228 | 228 |
ResultsIn string `protobuf:"bytes,3,opt,name=results_in,json=resultsIn,proto3" json:"results_in,omitempty"` |
| 229 |
- // UpdateTasks is a set of new or updated tasks to run on this node. |
|
| 230 |
- // In the first assignments message, it contains all of the tasks |
|
| 231 |
- // to run on this node. Tasks outside of this set running on the node |
|
| 232 |
- // should be terminated. |
|
| 233 |
- UpdateTasks []*Task `protobuf:"bytes,4,rep,name=update_tasks,json=updateTasks" json:"update_tasks,omitempty"` |
|
| 234 |
- // RemoveTasks is a set of previously-assigned task IDs to remove from the |
|
| 235 |
- // assignment set. It is not used in the first assignments message of |
|
| 236 |
- // a stream. |
|
| 237 |
- RemoveTasks []string `protobuf:"bytes,5,rep,name=remove_tasks,json=removeTasks" json:"remove_tasks,omitempty"` |
|
| 238 |
- // UpdateSecrets is a set of new or updated secrets for this node. |
|
| 239 |
- // In the first assignments message, it contains all of the secrets |
|
| 240 |
- // the node needs for itself and its assigned tasks. |
|
| 241 |
- UpdateSecrets []*Secret `protobuf:"bytes,6,rep,name=update_secrets,json=updateSecrets" json:"update_secrets,omitempty"` |
|
| 242 |
- // RemoveSecrets is a set of previously-assigned secret names to remove |
|
| 243 |
- // from memory. It is not used in the first assignments message of |
|
| 244 |
- // a stream. |
|
| 245 |
- RemoveSecrets []string `protobuf:"bytes,7,rep,name=remove_secrets,json=removeSecrets" json:"remove_secrets,omitempty"` |
|
| 229 |
+ // AssignmentChange is a set of changes to apply on this node. |
|
| 230 |
+ Changes []*AssignmentChange `protobuf:"bytes,4,rep,name=changes" json:"changes,omitempty"` |
|
| 246 | 231 |
} |
| 247 | 232 |
|
| 248 | 233 |
func (m *AssignmentsMessage) Reset() { *m = AssignmentsMessage{} }
|
| 249 | 234 |
func (*AssignmentsMessage) ProtoMessage() {}
|
| 250 |
-func (*AssignmentsMessage) Descriptor() ([]byte, []int) { return fileDescriptorDispatcher, []int{9} }
|
|
| 235 |
+func (*AssignmentsMessage) Descriptor() ([]byte, []int) { return fileDescriptorDispatcher, []int{11} }
|
|
| 251 | 236 |
|
| 252 | 237 |
func init() {
|
| 253 | 238 |
proto.RegisterType((*SessionRequest)(nil), "docker.swarmkit.v1.SessionRequest") |
| ... | ... |
@@ -260,7 +399,10 @@ func init() {
|
| 260 | 260 |
proto.RegisterType((*TasksRequest)(nil), "docker.swarmkit.v1.TasksRequest") |
| 261 | 261 |
proto.RegisterType((*TasksMessage)(nil), "docker.swarmkit.v1.TasksMessage") |
| 262 | 262 |
proto.RegisterType((*AssignmentsRequest)(nil), "docker.swarmkit.v1.AssignmentsRequest") |
| 263 |
+ proto.RegisterType((*Assignment)(nil), "docker.swarmkit.v1.Assignment") |
|
| 264 |
+ proto.RegisterType((*AssignmentChange)(nil), "docker.swarmkit.v1.AssignmentChange") |
|
| 263 | 265 |
proto.RegisterType((*AssignmentsMessage)(nil), "docker.swarmkit.v1.AssignmentsMessage") |
| 266 |
+ proto.RegisterEnum("docker.swarmkit.v1.AssignmentChange_AssignmentAction", AssignmentChange_AssignmentAction_name, AssignmentChange_AssignmentAction_value)
|
|
| 264 | 267 |
proto.RegisterEnum("docker.swarmkit.v1.AssignmentsMessage_Type", AssignmentsMessage_Type_name, AssignmentsMessage_Type_value)
|
| 265 | 268 |
} |
| 266 | 269 |
|
| ... | ... |
@@ -463,42 +605,59 @@ func (m *AssignmentsRequest) Copy() *AssignmentsRequest {
|
| 463 | 463 |
return o |
| 464 | 464 |
} |
| 465 | 465 |
|
| 466 |
-func (m *AssignmentsMessage) Copy() *AssignmentsMessage {
|
|
| 466 |
+func (m *Assignment) Copy() *Assignment {
|
|
| 467 | 467 |
if m == nil {
|
| 468 | 468 |
return nil |
| 469 | 469 |
} |
| 470 | 470 |
|
| 471 |
- o := &AssignmentsMessage{
|
|
| 472 |
- Type: m.Type, |
|
| 473 |
- AppliesTo: m.AppliesTo, |
|
| 474 |
- ResultsIn: m.ResultsIn, |
|
| 475 |
- } |
|
| 471 |
+ o := &Assignment{}
|
|
| 476 | 472 |
|
| 477 |
- if m.UpdateTasks != nil {
|
|
| 478 |
- o.UpdateTasks = make([]*Task, 0, len(m.UpdateTasks)) |
|
| 479 |
- for _, v := range m.UpdateTasks {
|
|
| 480 |
- o.UpdateTasks = append(o.UpdateTasks, v.Copy()) |
|
| 473 |
+ switch m.Item.(type) {
|
|
| 474 |
+ case *Assignment_Task: |
|
| 475 |
+ i := &Assignment_Task{
|
|
| 476 |
+ Task: m.GetTask().Copy(), |
|
| 481 | 477 |
} |
| 482 |
- } |
|
| 483 | 478 |
|
| 484 |
- if m.RemoveTasks != nil {
|
|
| 485 |
- o.RemoveTasks = make([]string, 0, len(m.RemoveTasks)) |
|
| 486 |
- for _, v := range m.RemoveTasks {
|
|
| 487 |
- o.RemoveTasks = append(o.RemoveTasks, v) |
|
| 479 |
+ o.Item = i |
|
| 480 |
+ case *Assignment_Secret: |
|
| 481 |
+ i := &Assignment_Secret{
|
|
| 482 |
+ Secret: m.GetSecret().Copy(), |
|
| 488 | 483 |
} |
| 484 |
+ |
|
| 485 |
+ o.Item = i |
|
| 489 | 486 |
} |
| 490 | 487 |
|
| 491 |
- if m.UpdateSecrets != nil {
|
|
| 492 |
- o.UpdateSecrets = make([]*Secret, 0, len(m.UpdateSecrets)) |
|
| 493 |
- for _, v := range m.UpdateSecrets {
|
|
| 494 |
- o.UpdateSecrets = append(o.UpdateSecrets, v.Copy()) |
|
| 495 |
- } |
|
| 488 |
+ return o |
|
| 489 |
+} |
|
| 490 |
+ |
|
| 491 |
+func (m *AssignmentChange) Copy() *AssignmentChange {
|
|
| 492 |
+ if m == nil {
|
|
| 493 |
+ return nil |
|
| 494 |
+ } |
|
| 495 |
+ |
|
| 496 |
+ o := &AssignmentChange{
|
|
| 497 |
+ Assignment: m.Assignment.Copy(), |
|
| 498 |
+ Action: m.Action, |
|
| 499 |
+ } |
|
| 500 |
+ |
|
| 501 |
+ return o |
|
| 502 |
+} |
|
| 503 |
+ |
|
| 504 |
+func (m *AssignmentsMessage) Copy() *AssignmentsMessage {
|
|
| 505 |
+ if m == nil {
|
|
| 506 |
+ return nil |
|
| 507 |
+ } |
|
| 508 |
+ |
|
| 509 |
+ o := &AssignmentsMessage{
|
|
| 510 |
+ Type: m.Type, |
|
| 511 |
+ AppliesTo: m.AppliesTo, |
|
| 512 |
+ ResultsIn: m.ResultsIn, |
|
| 496 | 513 |
} |
| 497 | 514 |
|
| 498 |
- if m.RemoveSecrets != nil {
|
|
| 499 |
- o.RemoveSecrets = make([]string, 0, len(m.RemoveSecrets)) |
|
| 500 |
- for _, v := range m.RemoveSecrets {
|
|
| 501 |
- o.RemoveSecrets = append(o.RemoveSecrets, v) |
|
| 515 |
+ if m.Changes != nil {
|
|
| 516 |
+ o.Changes = make([]*AssignmentChange, 0, len(m.Changes)) |
|
| 517 |
+ for _, v := range m.Changes {
|
|
| 518 |
+ o.Changes = append(o.Changes, v.Copy()) |
|
| 502 | 519 |
} |
| 503 | 520 |
} |
| 504 | 521 |
|
| ... | ... |
@@ -624,23 +783,59 @@ func (this *AssignmentsRequest) GoString() string {
|
| 624 | 624 |
s = append(s, "}") |
| 625 | 625 |
return strings.Join(s, "") |
| 626 | 626 |
} |
| 627 |
+func (this *Assignment) GoString() string {
|
|
| 628 |
+ if this == nil {
|
|
| 629 |
+ return "nil" |
|
| 630 |
+ } |
|
| 631 |
+ s := make([]string, 0, 6) |
|
| 632 |
+ s = append(s, "&api.Assignment{")
|
|
| 633 |
+ if this.Item != nil {
|
|
| 634 |
+ s = append(s, "Item: "+fmt.Sprintf("%#v", this.Item)+",\n")
|
|
| 635 |
+ } |
|
| 636 |
+ s = append(s, "}") |
|
| 637 |
+ return strings.Join(s, "") |
|
| 638 |
+} |
|
| 639 |
+func (this *Assignment_Task) GoString() string {
|
|
| 640 |
+ if this == nil {
|
|
| 641 |
+ return "nil" |
|
| 642 |
+ } |
|
| 643 |
+ s := strings.Join([]string{`&api.Assignment_Task{` +
|
|
| 644 |
+ `Task:` + fmt.Sprintf("%#v", this.Task) + `}`}, ", ")
|
|
| 645 |
+ return s |
|
| 646 |
+} |
|
| 647 |
+func (this *Assignment_Secret) GoString() string {
|
|
| 648 |
+ if this == nil {
|
|
| 649 |
+ return "nil" |
|
| 650 |
+ } |
|
| 651 |
+ s := strings.Join([]string{`&api.Assignment_Secret{` +
|
|
| 652 |
+ `Secret:` + fmt.Sprintf("%#v", this.Secret) + `}`}, ", ")
|
|
| 653 |
+ return s |
|
| 654 |
+} |
|
| 655 |
+func (this *AssignmentChange) GoString() string {
|
|
| 656 |
+ if this == nil {
|
|
| 657 |
+ return "nil" |
|
| 658 |
+ } |
|
| 659 |
+ s := make([]string, 0, 6) |
|
| 660 |
+ s = append(s, "&api.AssignmentChange{")
|
|
| 661 |
+ if this.Assignment != nil {
|
|
| 662 |
+ s = append(s, "Assignment: "+fmt.Sprintf("%#v", this.Assignment)+",\n")
|
|
| 663 |
+ } |
|
| 664 |
+ s = append(s, "Action: "+fmt.Sprintf("%#v", this.Action)+",\n")
|
|
| 665 |
+ s = append(s, "}") |
|
| 666 |
+ return strings.Join(s, "") |
|
| 667 |
+} |
|
| 627 | 668 |
func (this *AssignmentsMessage) GoString() string {
|
| 628 | 669 |
if this == nil {
|
| 629 | 670 |
return "nil" |
| 630 | 671 |
} |
| 631 |
- s := make([]string, 0, 11) |
|
| 672 |
+ s := make([]string, 0, 8) |
|
| 632 | 673 |
s = append(s, "&api.AssignmentsMessage{")
|
| 633 | 674 |
s = append(s, "Type: "+fmt.Sprintf("%#v", this.Type)+",\n")
|
| 634 | 675 |
s = append(s, "AppliesTo: "+fmt.Sprintf("%#v", this.AppliesTo)+",\n")
|
| 635 | 676 |
s = append(s, "ResultsIn: "+fmt.Sprintf("%#v", this.ResultsIn)+",\n")
|
| 636 |
- if this.UpdateTasks != nil {
|
|
| 637 |
- s = append(s, "UpdateTasks: "+fmt.Sprintf("%#v", this.UpdateTasks)+",\n")
|
|
| 677 |
+ if this.Changes != nil {
|
|
| 678 |
+ s = append(s, "Changes: "+fmt.Sprintf("%#v", this.Changes)+",\n")
|
|
| 638 | 679 |
} |
| 639 |
- s = append(s, "RemoveTasks: "+fmt.Sprintf("%#v", this.RemoveTasks)+",\n")
|
|
| 640 |
- if this.UpdateSecrets != nil {
|
|
| 641 |
- s = append(s, "UpdateSecrets: "+fmt.Sprintf("%#v", this.UpdateSecrets)+",\n")
|
|
| 642 |
- } |
|
| 643 |
- s = append(s, "RemoveSecrets: "+fmt.Sprintf("%#v", this.RemoveSecrets)+",\n")
|
|
| 644 | 680 |
s = append(s, "}") |
| 645 | 681 |
return strings.Join(s, "") |
| 646 | 682 |
} |
| ... | ... |
@@ -1313,6 +1508,92 @@ func (m *AssignmentsRequest) MarshalTo(data []byte) (int, error) {
|
| 1313 | 1313 |
return i, nil |
| 1314 | 1314 |
} |
| 1315 | 1315 |
|
| 1316 |
+func (m *Assignment) Marshal() (data []byte, err error) {
|
|
| 1317 |
+ size := m.Size() |
|
| 1318 |
+ data = make([]byte, size) |
|
| 1319 |
+ n, err := m.MarshalTo(data) |
|
| 1320 |
+ if err != nil {
|
|
| 1321 |
+ return nil, err |
|
| 1322 |
+ } |
|
| 1323 |
+ return data[:n], nil |
|
| 1324 |
+} |
|
| 1325 |
+ |
|
| 1326 |
+func (m *Assignment) MarshalTo(data []byte) (int, error) {
|
|
| 1327 |
+ var i int |
|
| 1328 |
+ _ = i |
|
| 1329 |
+ var l int |
|
| 1330 |
+ _ = l |
|
| 1331 |
+ if m.Item != nil {
|
|
| 1332 |
+ nn5, err := m.Item.MarshalTo(data[i:]) |
|
| 1333 |
+ if err != nil {
|
|
| 1334 |
+ return 0, err |
|
| 1335 |
+ } |
|
| 1336 |
+ i += nn5 |
|
| 1337 |
+ } |
|
| 1338 |
+ return i, nil |
|
| 1339 |
+} |
|
| 1340 |
+ |
|
| 1341 |
+func (m *Assignment_Task) MarshalTo(data []byte) (int, error) {
|
|
| 1342 |
+ i := 0 |
|
| 1343 |
+ if m.Task != nil {
|
|
| 1344 |
+ data[i] = 0xa |
|
| 1345 |
+ i++ |
|
| 1346 |
+ i = encodeVarintDispatcher(data, i, uint64(m.Task.Size())) |
|
| 1347 |
+ n6, err := m.Task.MarshalTo(data[i:]) |
|
| 1348 |
+ if err != nil {
|
|
| 1349 |
+ return 0, err |
|
| 1350 |
+ } |
|
| 1351 |
+ i += n6 |
|
| 1352 |
+ } |
|
| 1353 |
+ return i, nil |
|
| 1354 |
+} |
|
| 1355 |
+func (m *Assignment_Secret) MarshalTo(data []byte) (int, error) {
|
|
| 1356 |
+ i := 0 |
|
| 1357 |
+ if m.Secret != nil {
|
|
| 1358 |
+ data[i] = 0x12 |
|
| 1359 |
+ i++ |
|
| 1360 |
+ i = encodeVarintDispatcher(data, i, uint64(m.Secret.Size())) |
|
| 1361 |
+ n7, err := m.Secret.MarshalTo(data[i:]) |
|
| 1362 |
+ if err != nil {
|
|
| 1363 |
+ return 0, err |
|
| 1364 |
+ } |
|
| 1365 |
+ i += n7 |
|
| 1366 |
+ } |
|
| 1367 |
+ return i, nil |
|
| 1368 |
+} |
|
| 1369 |
+func (m *AssignmentChange) Marshal() (data []byte, err error) {
|
|
| 1370 |
+ size := m.Size() |
|
| 1371 |
+ data = make([]byte, size) |
|
| 1372 |
+ n, err := m.MarshalTo(data) |
|
| 1373 |
+ if err != nil {
|
|
| 1374 |
+ return nil, err |
|
| 1375 |
+ } |
|
| 1376 |
+ return data[:n], nil |
|
| 1377 |
+} |
|
| 1378 |
+ |
|
| 1379 |
+func (m *AssignmentChange) MarshalTo(data []byte) (int, error) {
|
|
| 1380 |
+ var i int |
|
| 1381 |
+ _ = i |
|
| 1382 |
+ var l int |
|
| 1383 |
+ _ = l |
|
| 1384 |
+ if m.Assignment != nil {
|
|
| 1385 |
+ data[i] = 0xa |
|
| 1386 |
+ i++ |
|
| 1387 |
+ i = encodeVarintDispatcher(data, i, uint64(m.Assignment.Size())) |
|
| 1388 |
+ n8, err := m.Assignment.MarshalTo(data[i:]) |
|
| 1389 |
+ if err != nil {
|
|
| 1390 |
+ return 0, err |
|
| 1391 |
+ } |
|
| 1392 |
+ i += n8 |
|
| 1393 |
+ } |
|
| 1394 |
+ if m.Action != 0 {
|
|
| 1395 |
+ data[i] = 0x10 |
|
| 1396 |
+ i++ |
|
| 1397 |
+ i = encodeVarintDispatcher(data, i, uint64(m.Action)) |
|
| 1398 |
+ } |
|
| 1399 |
+ return i, nil |
|
| 1400 |
+} |
|
| 1401 |
+ |
|
| 1316 | 1402 |
func (m *AssignmentsMessage) Marshal() (data []byte, err error) {
|
| 1317 | 1403 |
size := m.Size() |
| 1318 | 1404 |
data = make([]byte, size) |
| ... | ... |
@@ -1345,8 +1626,8 @@ func (m *AssignmentsMessage) MarshalTo(data []byte) (int, error) {
|
| 1345 | 1345 |
i = encodeVarintDispatcher(data, i, uint64(len(m.ResultsIn))) |
| 1346 | 1346 |
i += copy(data[i:], m.ResultsIn) |
| 1347 | 1347 |
} |
| 1348 |
- if len(m.UpdateTasks) > 0 {
|
|
| 1349 |
- for _, msg := range m.UpdateTasks {
|
|
| 1348 |
+ if len(m.Changes) > 0 {
|
|
| 1349 |
+ for _, msg := range m.Changes {
|
|
| 1350 | 1350 |
data[i] = 0x22 |
| 1351 | 1351 |
i++ |
| 1352 | 1352 |
i = encodeVarintDispatcher(data, i, uint64(msg.Size())) |
| ... | ... |
@@ -1357,48 +1638,6 @@ func (m *AssignmentsMessage) MarshalTo(data []byte) (int, error) {
|
| 1357 | 1357 |
i += n |
| 1358 | 1358 |
} |
| 1359 | 1359 |
} |
| 1360 |
- if len(m.RemoveTasks) > 0 {
|
|
| 1361 |
- for _, s := range m.RemoveTasks {
|
|
| 1362 |
- data[i] = 0x2a |
|
| 1363 |
- i++ |
|
| 1364 |
- l = len(s) |
|
| 1365 |
- for l >= 1<<7 {
|
|
| 1366 |
- data[i] = uint8(uint64(l)&0x7f | 0x80) |
|
| 1367 |
- l >>= 7 |
|
| 1368 |
- i++ |
|
| 1369 |
- } |
|
| 1370 |
- data[i] = uint8(l) |
|
| 1371 |
- i++ |
|
| 1372 |
- i += copy(data[i:], s) |
|
| 1373 |
- } |
|
| 1374 |
- } |
|
| 1375 |
- if len(m.UpdateSecrets) > 0 {
|
|
| 1376 |
- for _, msg := range m.UpdateSecrets {
|
|
| 1377 |
- data[i] = 0x32 |
|
| 1378 |
- i++ |
|
| 1379 |
- i = encodeVarintDispatcher(data, i, uint64(msg.Size())) |
|
| 1380 |
- n, err := msg.MarshalTo(data[i:]) |
|
| 1381 |
- if err != nil {
|
|
| 1382 |
- return 0, err |
|
| 1383 |
- } |
|
| 1384 |
- i += n |
|
| 1385 |
- } |
|
| 1386 |
- } |
|
| 1387 |
- if len(m.RemoveSecrets) > 0 {
|
|
| 1388 |
- for _, s := range m.RemoveSecrets {
|
|
| 1389 |
- data[i] = 0x3a |
|
| 1390 |
- i++ |
|
| 1391 |
- l = len(s) |
|
| 1392 |
- for l >= 1<<7 {
|
|
| 1393 |
- data[i] = uint8(uint64(l)&0x7f | 0x80) |
|
| 1394 |
- l >>= 7 |
|
| 1395 |
- i++ |
|
| 1396 |
- } |
|
| 1397 |
- data[i] = uint8(l) |
|
| 1398 |
- i++ |
|
| 1399 |
- i += copy(data[i:], s) |
|
| 1400 |
- } |
|
| 1401 |
- } |
|
| 1402 | 1360 |
return i, nil |
| 1403 | 1361 |
} |
| 1404 | 1362 |
|
| ... | ... |
@@ -1789,6 +2028,46 @@ func (m *AssignmentsRequest) Size() (n int) {
|
| 1789 | 1789 |
return n |
| 1790 | 1790 |
} |
| 1791 | 1791 |
|
| 1792 |
+func (m *Assignment) Size() (n int) {
|
|
| 1793 |
+ var l int |
|
| 1794 |
+ _ = l |
|
| 1795 |
+ if m.Item != nil {
|
|
| 1796 |
+ n += m.Item.Size() |
|
| 1797 |
+ } |
|
| 1798 |
+ return n |
|
| 1799 |
+} |
|
| 1800 |
+ |
|
| 1801 |
+func (m *Assignment_Task) Size() (n int) {
|
|
| 1802 |
+ var l int |
|
| 1803 |
+ _ = l |
|
| 1804 |
+ if m.Task != nil {
|
|
| 1805 |
+ l = m.Task.Size() |
|
| 1806 |
+ n += 1 + l + sovDispatcher(uint64(l)) |
|
| 1807 |
+ } |
|
| 1808 |
+ return n |
|
| 1809 |
+} |
|
| 1810 |
+func (m *Assignment_Secret) Size() (n int) {
|
|
| 1811 |
+ var l int |
|
| 1812 |
+ _ = l |
|
| 1813 |
+ if m.Secret != nil {
|
|
| 1814 |
+ l = m.Secret.Size() |
|
| 1815 |
+ n += 1 + l + sovDispatcher(uint64(l)) |
|
| 1816 |
+ } |
|
| 1817 |
+ return n |
|
| 1818 |
+} |
|
| 1819 |
+func (m *AssignmentChange) Size() (n int) {
|
|
| 1820 |
+ var l int |
|
| 1821 |
+ _ = l |
|
| 1822 |
+ if m.Assignment != nil {
|
|
| 1823 |
+ l = m.Assignment.Size() |
|
| 1824 |
+ n += 1 + l + sovDispatcher(uint64(l)) |
|
| 1825 |
+ } |
|
| 1826 |
+ if m.Action != 0 {
|
|
| 1827 |
+ n += 1 + sovDispatcher(uint64(m.Action)) |
|
| 1828 |
+ } |
|
| 1829 |
+ return n |
|
| 1830 |
+} |
|
| 1831 |
+ |
|
| 1792 | 1832 |
func (m *AssignmentsMessage) Size() (n int) {
|
| 1793 | 1833 |
var l int |
| 1794 | 1834 |
_ = l |
| ... | ... |
@@ -1803,30 +2082,12 @@ func (m *AssignmentsMessage) Size() (n int) {
|
| 1803 | 1803 |
if l > 0 {
|
| 1804 | 1804 |
n += 1 + l + sovDispatcher(uint64(l)) |
| 1805 | 1805 |
} |
| 1806 |
- if len(m.UpdateTasks) > 0 {
|
|
| 1807 |
- for _, e := range m.UpdateTasks {
|
|
| 1806 |
+ if len(m.Changes) > 0 {
|
|
| 1807 |
+ for _, e := range m.Changes {
|
|
| 1808 | 1808 |
l = e.Size() |
| 1809 | 1809 |
n += 1 + l + sovDispatcher(uint64(l)) |
| 1810 | 1810 |
} |
| 1811 | 1811 |
} |
| 1812 |
- if len(m.RemoveTasks) > 0 {
|
|
| 1813 |
- for _, s := range m.RemoveTasks {
|
|
| 1814 |
- l = len(s) |
|
| 1815 |
- n += 1 + l + sovDispatcher(uint64(l)) |
|
| 1816 |
- } |
|
| 1817 |
- } |
|
| 1818 |
- if len(m.UpdateSecrets) > 0 {
|
|
| 1819 |
- for _, e := range m.UpdateSecrets {
|
|
| 1820 |
- l = e.Size() |
|
| 1821 |
- n += 1 + l + sovDispatcher(uint64(l)) |
|
| 1822 |
- } |
|
| 1823 |
- } |
|
| 1824 |
- if len(m.RemoveSecrets) > 0 {
|
|
| 1825 |
- for _, s := range m.RemoveSecrets {
|
|
| 1826 |
- l = len(s) |
|
| 1827 |
- n += 1 + l + sovDispatcher(uint64(l)) |
|
| 1828 |
- } |
|
| 1829 |
- } |
|
| 1830 | 1812 |
return n |
| 1831 | 1813 |
} |
| 1832 | 1814 |
|
| ... | ... |
@@ -1948,6 +2209,47 @@ func (this *AssignmentsRequest) String() string {
|
| 1948 | 1948 |
}, "") |
| 1949 | 1949 |
return s |
| 1950 | 1950 |
} |
| 1951 |
+func (this *Assignment) String() string {
|
|
| 1952 |
+ if this == nil {
|
|
| 1953 |
+ return "nil" |
|
| 1954 |
+ } |
|
| 1955 |
+ s := strings.Join([]string{`&Assignment{`,
|
|
| 1956 |
+ `Item:` + fmt.Sprintf("%v", this.Item) + `,`,
|
|
| 1957 |
+ `}`, |
|
| 1958 |
+ }, "") |
|
| 1959 |
+ return s |
|
| 1960 |
+} |
|
| 1961 |
+func (this *Assignment_Task) String() string {
|
|
| 1962 |
+ if this == nil {
|
|
| 1963 |
+ return "nil" |
|
| 1964 |
+ } |
|
| 1965 |
+ s := strings.Join([]string{`&Assignment_Task{`,
|
|
| 1966 |
+ `Task:` + strings.Replace(fmt.Sprintf("%v", this.Task), "Task", "Task", 1) + `,`,
|
|
| 1967 |
+ `}`, |
|
| 1968 |
+ }, "") |
|
| 1969 |
+ return s |
|
| 1970 |
+} |
|
| 1971 |
+func (this *Assignment_Secret) String() string {
|
|
| 1972 |
+ if this == nil {
|
|
| 1973 |
+ return "nil" |
|
| 1974 |
+ } |
|
| 1975 |
+ s := strings.Join([]string{`&Assignment_Secret{`,
|
|
| 1976 |
+ `Secret:` + strings.Replace(fmt.Sprintf("%v", this.Secret), "Secret", "Secret", 1) + `,`,
|
|
| 1977 |
+ `}`, |
|
| 1978 |
+ }, "") |
|
| 1979 |
+ return s |
|
| 1980 |
+} |
|
| 1981 |
+func (this *AssignmentChange) String() string {
|
|
| 1982 |
+ if this == nil {
|
|
| 1983 |
+ return "nil" |
|
| 1984 |
+ } |
|
| 1985 |
+ s := strings.Join([]string{`&AssignmentChange{`,
|
|
| 1986 |
+ `Assignment:` + strings.Replace(fmt.Sprintf("%v", this.Assignment), "Assignment", "Assignment", 1) + `,`,
|
|
| 1987 |
+ `Action:` + fmt.Sprintf("%v", this.Action) + `,`,
|
|
| 1988 |
+ `}`, |
|
| 1989 |
+ }, "") |
|
| 1990 |
+ return s |
|
| 1991 |
+} |
|
| 1951 | 1992 |
func (this *AssignmentsMessage) String() string {
|
| 1952 | 1993 |
if this == nil {
|
| 1953 | 1994 |
return "nil" |
| ... | ... |
@@ -1956,10 +2258,7 @@ func (this *AssignmentsMessage) String() string {
|
| 1956 | 1956 |
`Type:` + fmt.Sprintf("%v", this.Type) + `,`,
|
| 1957 | 1957 |
`AppliesTo:` + fmt.Sprintf("%v", this.AppliesTo) + `,`,
|
| 1958 | 1958 |
`ResultsIn:` + fmt.Sprintf("%v", this.ResultsIn) + `,`,
|
| 1959 |
- `UpdateTasks:` + strings.Replace(fmt.Sprintf("%v", this.UpdateTasks), "Task", "Task", 1) + `,`,
|
|
| 1960 |
- `RemoveTasks:` + fmt.Sprintf("%v", this.RemoveTasks) + `,`,
|
|
| 1961 |
- `UpdateSecrets:` + strings.Replace(fmt.Sprintf("%v", this.UpdateSecrets), "Secret", "Secret", 1) + `,`,
|
|
| 1962 |
- `RemoveSecrets:` + fmt.Sprintf("%v", this.RemoveSecrets) + `,`,
|
|
| 1959 |
+ `Changes:` + strings.Replace(fmt.Sprintf("%v", this.Changes), "AssignmentChange", "AssignmentChange", 1) + `,`,
|
|
| 1963 | 1960 |
`}`, |
| 1964 | 1961 |
}, "") |
| 1965 | 1962 |
return s |
| ... | ... |
@@ -2928,7 +3227,7 @@ func (m *AssignmentsRequest) Unmarshal(data []byte) error {
|
| 2928 | 2928 |
} |
| 2929 | 2929 |
return nil |
| 2930 | 2930 |
} |
| 2931 |
-func (m *AssignmentsMessage) Unmarshal(data []byte) error {
|
|
| 2931 |
+func (m *Assignment) Unmarshal(data []byte) error {
|
|
| 2932 | 2932 |
l := len(data) |
| 2933 | 2933 |
iNdEx := 0 |
| 2934 | 2934 |
for iNdEx < l {
|
| ... | ... |
@@ -2951,17 +3250,17 @@ func (m *AssignmentsMessage) Unmarshal(data []byte) error {
|
| 2951 | 2951 |
fieldNum := int32(wire >> 3) |
| 2952 | 2952 |
wireType := int(wire & 0x7) |
| 2953 | 2953 |
if wireType == 4 {
|
| 2954 |
- return fmt.Errorf("proto: AssignmentsMessage: wiretype end group for non-group")
|
|
| 2954 |
+ return fmt.Errorf("proto: Assignment: wiretype end group for non-group")
|
|
| 2955 | 2955 |
} |
| 2956 | 2956 |
if fieldNum <= 0 {
|
| 2957 |
- return fmt.Errorf("proto: AssignmentsMessage: illegal tag %d (wire type %d)", fieldNum, wire)
|
|
| 2957 |
+ return fmt.Errorf("proto: Assignment: illegal tag %d (wire type %d)", fieldNum, wire)
|
|
| 2958 | 2958 |
} |
| 2959 | 2959 |
switch fieldNum {
|
| 2960 | 2960 |
case 1: |
| 2961 |
- if wireType != 0 {
|
|
| 2962 |
- return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
|
|
| 2961 |
+ if wireType != 2 {
|
|
| 2962 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Task", wireType)
|
|
| 2963 | 2963 |
} |
| 2964 |
- m.Type = 0 |
|
| 2964 |
+ var msglen int |
|
| 2965 | 2965 |
for shift := uint(0); ; shift += 7 {
|
| 2966 | 2966 |
if shift >= 64 {
|
| 2967 | 2967 |
return ErrIntOverflowDispatcher |
| ... | ... |
@@ -2971,16 +3270,29 @@ func (m *AssignmentsMessage) Unmarshal(data []byte) error {
|
| 2971 | 2971 |
} |
| 2972 | 2972 |
b := data[iNdEx] |
| 2973 | 2973 |
iNdEx++ |
| 2974 |
- m.Type |= (AssignmentsMessage_Type(b) & 0x7F) << shift |
|
| 2974 |
+ msglen |= (int(b) & 0x7F) << shift |
|
| 2975 | 2975 |
if b < 0x80 {
|
| 2976 | 2976 |
break |
| 2977 | 2977 |
} |
| 2978 | 2978 |
} |
| 2979 |
+ if msglen < 0 {
|
|
| 2980 |
+ return ErrInvalidLengthDispatcher |
|
| 2981 |
+ } |
|
| 2982 |
+ postIndex := iNdEx + msglen |
|
| 2983 |
+ if postIndex > l {
|
|
| 2984 |
+ return io.ErrUnexpectedEOF |
|
| 2985 |
+ } |
|
| 2986 |
+ v := &Task{}
|
|
| 2987 |
+ if err := v.Unmarshal(data[iNdEx:postIndex]); err != nil {
|
|
| 2988 |
+ return err |
|
| 2989 |
+ } |
|
| 2990 |
+ m.Item = &Assignment_Task{v}
|
|
| 2991 |
+ iNdEx = postIndex |
|
| 2979 | 2992 |
case 2: |
| 2980 | 2993 |
if wireType != 2 {
|
| 2981 |
- return fmt.Errorf("proto: wrong wireType = %d for field AppliesTo", wireType)
|
|
| 2994 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Secret", wireType)
|
|
| 2982 | 2995 |
} |
| 2983 |
- var stringLen uint64 |
|
| 2996 |
+ var msglen int |
|
| 2984 | 2997 |
for shift := uint(0); ; shift += 7 {
|
| 2985 | 2998 |
if shift >= 64 {
|
| 2986 | 2999 |
return ErrIntOverflowDispatcher |
| ... | ... |
@@ -2990,26 +3302,79 @@ func (m *AssignmentsMessage) Unmarshal(data []byte) error {
|
| 2990 | 2990 |
} |
| 2991 | 2991 |
b := data[iNdEx] |
| 2992 | 2992 |
iNdEx++ |
| 2993 |
- stringLen |= (uint64(b) & 0x7F) << shift |
|
| 2993 |
+ msglen |= (int(b) & 0x7F) << shift |
|
| 2994 | 2994 |
if b < 0x80 {
|
| 2995 | 2995 |
break |
| 2996 | 2996 |
} |
| 2997 | 2997 |
} |
| 2998 |
- intStringLen := int(stringLen) |
|
| 2999 |
- if intStringLen < 0 {
|
|
| 2998 |
+ if msglen < 0 {
|
|
| 3000 | 2999 |
return ErrInvalidLengthDispatcher |
| 3001 | 3000 |
} |
| 3002 |
- postIndex := iNdEx + intStringLen |
|
| 3001 |
+ postIndex := iNdEx + msglen |
|
| 3003 | 3002 |
if postIndex > l {
|
| 3004 | 3003 |
return io.ErrUnexpectedEOF |
| 3005 | 3004 |
} |
| 3006 |
- m.AppliesTo = string(data[iNdEx:postIndex]) |
|
| 3005 |
+ v := &Secret{}
|
|
| 3006 |
+ if err := v.Unmarshal(data[iNdEx:postIndex]); err != nil {
|
|
| 3007 |
+ return err |
|
| 3008 |
+ } |
|
| 3009 |
+ m.Item = &Assignment_Secret{v}
|
|
| 3007 | 3010 |
iNdEx = postIndex |
| 3008 |
- case 3: |
|
| 3011 |
+ default: |
|
| 3012 |
+ iNdEx = preIndex |
|
| 3013 |
+ skippy, err := skipDispatcher(data[iNdEx:]) |
|
| 3014 |
+ if err != nil {
|
|
| 3015 |
+ return err |
|
| 3016 |
+ } |
|
| 3017 |
+ if skippy < 0 {
|
|
| 3018 |
+ return ErrInvalidLengthDispatcher |
|
| 3019 |
+ } |
|
| 3020 |
+ if (iNdEx + skippy) > l {
|
|
| 3021 |
+ return io.ErrUnexpectedEOF |
|
| 3022 |
+ } |
|
| 3023 |
+ iNdEx += skippy |
|
| 3024 |
+ } |
|
| 3025 |
+ } |
|
| 3026 |
+ |
|
| 3027 |
+ if iNdEx > l {
|
|
| 3028 |
+ return io.ErrUnexpectedEOF |
|
| 3029 |
+ } |
|
| 3030 |
+ return nil |
|
| 3031 |
+} |
|
| 3032 |
+func (m *AssignmentChange) Unmarshal(data []byte) error {
|
|
| 3033 |
+ l := len(data) |
|
| 3034 |
+ iNdEx := 0 |
|
| 3035 |
+ for iNdEx < l {
|
|
| 3036 |
+ preIndex := iNdEx |
|
| 3037 |
+ var wire uint64 |
|
| 3038 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 3039 |
+ if shift >= 64 {
|
|
| 3040 |
+ return ErrIntOverflowDispatcher |
|
| 3041 |
+ } |
|
| 3042 |
+ if iNdEx >= l {
|
|
| 3043 |
+ return io.ErrUnexpectedEOF |
|
| 3044 |
+ } |
|
| 3045 |
+ b := data[iNdEx] |
|
| 3046 |
+ iNdEx++ |
|
| 3047 |
+ wire |= (uint64(b) & 0x7F) << shift |
|
| 3048 |
+ if b < 0x80 {
|
|
| 3049 |
+ break |
|
| 3050 |
+ } |
|
| 3051 |
+ } |
|
| 3052 |
+ fieldNum := int32(wire >> 3) |
|
| 3053 |
+ wireType := int(wire & 0x7) |
|
| 3054 |
+ if wireType == 4 {
|
|
| 3055 |
+ return fmt.Errorf("proto: AssignmentChange: wiretype end group for non-group")
|
|
| 3056 |
+ } |
|
| 3057 |
+ if fieldNum <= 0 {
|
|
| 3058 |
+ return fmt.Errorf("proto: AssignmentChange: illegal tag %d (wire type %d)", fieldNum, wire)
|
|
| 3059 |
+ } |
|
| 3060 |
+ switch fieldNum {
|
|
| 3061 |
+ case 1: |
|
| 3009 | 3062 |
if wireType != 2 {
|
| 3010 |
- return fmt.Errorf("proto: wrong wireType = %d for field ResultsIn", wireType)
|
|
| 3063 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Assignment", wireType)
|
|
| 3011 | 3064 |
} |
| 3012 |
- var stringLen uint64 |
|
| 3065 |
+ var msglen int |
|
| 3013 | 3066 |
for shift := uint(0); ; shift += 7 {
|
| 3014 | 3067 |
if shift >= 64 {
|
| 3015 | 3068 |
return ErrIntOverflowDispatcher |
| ... | ... |
@@ -3019,26 +3384,30 @@ func (m *AssignmentsMessage) Unmarshal(data []byte) error {
|
| 3019 | 3019 |
} |
| 3020 | 3020 |
b := data[iNdEx] |
| 3021 | 3021 |
iNdEx++ |
| 3022 |
- stringLen |= (uint64(b) & 0x7F) << shift |
|
| 3022 |
+ msglen |= (int(b) & 0x7F) << shift |
|
| 3023 | 3023 |
if b < 0x80 {
|
| 3024 | 3024 |
break |
| 3025 | 3025 |
} |
| 3026 | 3026 |
} |
| 3027 |
- intStringLen := int(stringLen) |
|
| 3028 |
- if intStringLen < 0 {
|
|
| 3027 |
+ if msglen < 0 {
|
|
| 3029 | 3028 |
return ErrInvalidLengthDispatcher |
| 3030 | 3029 |
} |
| 3031 |
- postIndex := iNdEx + intStringLen |
|
| 3030 |
+ postIndex := iNdEx + msglen |
|
| 3032 | 3031 |
if postIndex > l {
|
| 3033 | 3032 |
return io.ErrUnexpectedEOF |
| 3034 | 3033 |
} |
| 3035 |
- m.ResultsIn = string(data[iNdEx:postIndex]) |
|
| 3034 |
+ if m.Assignment == nil {
|
|
| 3035 |
+ m.Assignment = &Assignment{}
|
|
| 3036 |
+ } |
|
| 3037 |
+ if err := m.Assignment.Unmarshal(data[iNdEx:postIndex]); err != nil {
|
|
| 3038 |
+ return err |
|
| 3039 |
+ } |
|
| 3036 | 3040 |
iNdEx = postIndex |
| 3037 |
- case 4: |
|
| 3038 |
- if wireType != 2 {
|
|
| 3039 |
- return fmt.Errorf("proto: wrong wireType = %d for field UpdateTasks", wireType)
|
|
| 3041 |
+ case 2: |
|
| 3042 |
+ if wireType != 0 {
|
|
| 3043 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Action", wireType)
|
|
| 3040 | 3044 |
} |
| 3041 |
- var msglen int |
|
| 3045 |
+ m.Action = 0 |
|
| 3042 | 3046 |
for shift := uint(0); ; shift += 7 {
|
| 3043 | 3047 |
if shift >= 64 {
|
| 3044 | 3048 |
return ErrIntOverflowDispatcher |
| ... | ... |
@@ -3048,26 +3417,83 @@ func (m *AssignmentsMessage) Unmarshal(data []byte) error {
|
| 3048 | 3048 |
} |
| 3049 | 3049 |
b := data[iNdEx] |
| 3050 | 3050 |
iNdEx++ |
| 3051 |
- msglen |= (int(b) & 0x7F) << shift |
|
| 3051 |
+ m.Action |= (AssignmentChange_AssignmentAction(b) & 0x7F) << shift |
|
| 3052 | 3052 |
if b < 0x80 {
|
| 3053 | 3053 |
break |
| 3054 | 3054 |
} |
| 3055 | 3055 |
} |
| 3056 |
- if msglen < 0 {
|
|
| 3056 |
+ default: |
|
| 3057 |
+ iNdEx = preIndex |
|
| 3058 |
+ skippy, err := skipDispatcher(data[iNdEx:]) |
|
| 3059 |
+ if err != nil {
|
|
| 3060 |
+ return err |
|
| 3061 |
+ } |
|
| 3062 |
+ if skippy < 0 {
|
|
| 3057 | 3063 |
return ErrInvalidLengthDispatcher |
| 3058 | 3064 |
} |
| 3059 |
- postIndex := iNdEx + msglen |
|
| 3060 |
- if postIndex > l {
|
|
| 3065 |
+ if (iNdEx + skippy) > l {
|
|
| 3061 | 3066 |
return io.ErrUnexpectedEOF |
| 3062 | 3067 |
} |
| 3063 |
- m.UpdateTasks = append(m.UpdateTasks, &Task{})
|
|
| 3064 |
- if err := m.UpdateTasks[len(m.UpdateTasks)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
|
|
| 3065 |
- return err |
|
| 3068 |
+ iNdEx += skippy |
|
| 3069 |
+ } |
|
| 3070 |
+ } |
|
| 3071 |
+ |
|
| 3072 |
+ if iNdEx > l {
|
|
| 3073 |
+ return io.ErrUnexpectedEOF |
|
| 3074 |
+ } |
|
| 3075 |
+ return nil |
|
| 3076 |
+} |
|
| 3077 |
+func (m *AssignmentsMessage) Unmarshal(data []byte) error {
|
|
| 3078 |
+ l := len(data) |
|
| 3079 |
+ iNdEx := 0 |
|
| 3080 |
+ for iNdEx < l {
|
|
| 3081 |
+ preIndex := iNdEx |
|
| 3082 |
+ var wire uint64 |
|
| 3083 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 3084 |
+ if shift >= 64 {
|
|
| 3085 |
+ return ErrIntOverflowDispatcher |
|
| 3066 | 3086 |
} |
| 3067 |
- iNdEx = postIndex |
|
| 3068 |
- case 5: |
|
| 3087 |
+ if iNdEx >= l {
|
|
| 3088 |
+ return io.ErrUnexpectedEOF |
|
| 3089 |
+ } |
|
| 3090 |
+ b := data[iNdEx] |
|
| 3091 |
+ iNdEx++ |
|
| 3092 |
+ wire |= (uint64(b) & 0x7F) << shift |
|
| 3093 |
+ if b < 0x80 {
|
|
| 3094 |
+ break |
|
| 3095 |
+ } |
|
| 3096 |
+ } |
|
| 3097 |
+ fieldNum := int32(wire >> 3) |
|
| 3098 |
+ wireType := int(wire & 0x7) |
|
| 3099 |
+ if wireType == 4 {
|
|
| 3100 |
+ return fmt.Errorf("proto: AssignmentsMessage: wiretype end group for non-group")
|
|
| 3101 |
+ } |
|
| 3102 |
+ if fieldNum <= 0 {
|
|
| 3103 |
+ return fmt.Errorf("proto: AssignmentsMessage: illegal tag %d (wire type %d)", fieldNum, wire)
|
|
| 3104 |
+ } |
|
| 3105 |
+ switch fieldNum {
|
|
| 3106 |
+ case 1: |
|
| 3107 |
+ if wireType != 0 {
|
|
| 3108 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
|
|
| 3109 |
+ } |
|
| 3110 |
+ m.Type = 0 |
|
| 3111 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 3112 |
+ if shift >= 64 {
|
|
| 3113 |
+ return ErrIntOverflowDispatcher |
|
| 3114 |
+ } |
|
| 3115 |
+ if iNdEx >= l {
|
|
| 3116 |
+ return io.ErrUnexpectedEOF |
|
| 3117 |
+ } |
|
| 3118 |
+ b := data[iNdEx] |
|
| 3119 |
+ iNdEx++ |
|
| 3120 |
+ m.Type |= (AssignmentsMessage_Type(b) & 0x7F) << shift |
|
| 3121 |
+ if b < 0x80 {
|
|
| 3122 |
+ break |
|
| 3123 |
+ } |
|
| 3124 |
+ } |
|
| 3125 |
+ case 2: |
|
| 3069 | 3126 |
if wireType != 2 {
|
| 3070 |
- return fmt.Errorf("proto: wrong wireType = %d for field RemoveTasks", wireType)
|
|
| 3127 |
+ return fmt.Errorf("proto: wrong wireType = %d for field AppliesTo", wireType)
|
|
| 3071 | 3128 |
} |
| 3072 | 3129 |
var stringLen uint64 |
| 3073 | 3130 |
for shift := uint(0); ; shift += 7 {
|
| ... | ... |
@@ -3092,13 +3518,13 @@ func (m *AssignmentsMessage) Unmarshal(data []byte) error {
|
| 3092 | 3092 |
if postIndex > l {
|
| 3093 | 3093 |
return io.ErrUnexpectedEOF |
| 3094 | 3094 |
} |
| 3095 |
- m.RemoveTasks = append(m.RemoveTasks, string(data[iNdEx:postIndex])) |
|
| 3095 |
+ m.AppliesTo = string(data[iNdEx:postIndex]) |
|
| 3096 | 3096 |
iNdEx = postIndex |
| 3097 |
- case 6: |
|
| 3097 |
+ case 3: |
|
| 3098 | 3098 |
if wireType != 2 {
|
| 3099 |
- return fmt.Errorf("proto: wrong wireType = %d for field UpdateSecrets", wireType)
|
|
| 3099 |
+ return fmt.Errorf("proto: wrong wireType = %d for field ResultsIn", wireType)
|
|
| 3100 | 3100 |
} |
| 3101 |
- var msglen int |
|
| 3101 |
+ var stringLen uint64 |
|
| 3102 | 3102 |
for shift := uint(0); ; shift += 7 {
|
| 3103 | 3103 |
if shift >= 64 {
|
| 3104 | 3104 |
return ErrIntOverflowDispatcher |
| ... | ... |
@@ -3108,28 +3534,26 @@ func (m *AssignmentsMessage) Unmarshal(data []byte) error {
|
| 3108 | 3108 |
} |
| 3109 | 3109 |
b := data[iNdEx] |
| 3110 | 3110 |
iNdEx++ |
| 3111 |
- msglen |= (int(b) & 0x7F) << shift |
|
| 3111 |
+ stringLen |= (uint64(b) & 0x7F) << shift |
|
| 3112 | 3112 |
if b < 0x80 {
|
| 3113 | 3113 |
break |
| 3114 | 3114 |
} |
| 3115 | 3115 |
} |
| 3116 |
- if msglen < 0 {
|
|
| 3116 |
+ intStringLen := int(stringLen) |
|
| 3117 |
+ if intStringLen < 0 {
|
|
| 3117 | 3118 |
return ErrInvalidLengthDispatcher |
| 3118 | 3119 |
} |
| 3119 |
- postIndex := iNdEx + msglen |
|
| 3120 |
+ postIndex := iNdEx + intStringLen |
|
| 3120 | 3121 |
if postIndex > l {
|
| 3121 | 3122 |
return io.ErrUnexpectedEOF |
| 3122 | 3123 |
} |
| 3123 |
- m.UpdateSecrets = append(m.UpdateSecrets, &Secret{})
|
|
| 3124 |
- if err := m.UpdateSecrets[len(m.UpdateSecrets)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
|
|
| 3125 |
- return err |
|
| 3126 |
- } |
|
| 3124 |
+ m.ResultsIn = string(data[iNdEx:postIndex]) |
|
| 3127 | 3125 |
iNdEx = postIndex |
| 3128 |
- case 7: |
|
| 3126 |
+ case 4: |
|
| 3129 | 3127 |
if wireType != 2 {
|
| 3130 |
- return fmt.Errorf("proto: wrong wireType = %d for field RemoveSecrets", wireType)
|
|
| 3128 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Changes", wireType)
|
|
| 3131 | 3129 |
} |
| 3132 |
- var stringLen uint64 |
|
| 3130 |
+ var msglen int |
|
| 3133 | 3131 |
for shift := uint(0); ; shift += 7 {
|
| 3134 | 3132 |
if shift >= 64 {
|
| 3135 | 3133 |
return ErrIntOverflowDispatcher |
| ... | ... |
@@ -3139,20 +3563,22 @@ func (m *AssignmentsMessage) Unmarshal(data []byte) error {
|
| 3139 | 3139 |
} |
| 3140 | 3140 |
b := data[iNdEx] |
| 3141 | 3141 |
iNdEx++ |
| 3142 |
- stringLen |= (uint64(b) & 0x7F) << shift |
|
| 3142 |
+ msglen |= (int(b) & 0x7F) << shift |
|
| 3143 | 3143 |
if b < 0x80 {
|
| 3144 | 3144 |
break |
| 3145 | 3145 |
} |
| 3146 | 3146 |
} |
| 3147 |
- intStringLen := int(stringLen) |
|
| 3148 |
- if intStringLen < 0 {
|
|
| 3147 |
+ if msglen < 0 {
|
|
| 3149 | 3148 |
return ErrInvalidLengthDispatcher |
| 3150 | 3149 |
} |
| 3151 |
- postIndex := iNdEx + intStringLen |
|
| 3150 |
+ postIndex := iNdEx + msglen |
|
| 3152 | 3151 |
if postIndex > l {
|
| 3153 | 3152 |
return io.ErrUnexpectedEOF |
| 3154 | 3153 |
} |
| 3155 |
- m.RemoveSecrets = append(m.RemoveSecrets, string(data[iNdEx:postIndex])) |
|
| 3154 |
+ m.Changes = append(m.Changes, &AssignmentChange{})
|
|
| 3155 |
+ if err := m.Changes[len(m.Changes)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
|
|
| 3156 |
+ return err |
|
| 3157 |
+ } |
|
| 3156 | 3158 |
iNdEx = postIndex |
| 3157 | 3159 |
default: |
| 3158 | 3160 |
iNdEx = preIndex |
| ... | ... |
@@ -3283,59 +3709,64 @@ var ( |
| 3283 | 3283 |
func init() { proto.RegisterFile("dispatcher.proto", fileDescriptorDispatcher) }
|
| 3284 | 3284 |
|
| 3285 | 3285 |
var fileDescriptorDispatcher = []byte{
|
| 3286 |
- // 858 bytes of a gzipped FileDescriptorProto |
|
| 3287 |
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x56, 0x41, 0x6f, 0x1b, 0x45, |
|
| 3288 |
- 0x14, 0xce, 0xd8, 0x8e, 0x53, 0xbf, 0xb5, 0x83, 0x19, 0x2a, 0xba, 0xb2, 0x5a, 0xc7, 0xdd, 0x90, |
|
| 3289 |
- 0x28, 0x52, 0x83, 0x53, 0x8c, 0xc4, 0x01, 0x22, 0x20, 0xae, 0x2d, 0x61, 0xb5, 0x49, 0xab, 0x8d, |
|
| 3290 |
- 0xa1, 0x47, 0x6b, 0xe3, 0x7d, 0x72, 0x17, 0x27, 0x3b, 0xcb, 0xcc, 0x6c, 0x8b, 0x0f, 0x48, 0x48, |
|
| 3291 |
- 0x14, 0x89, 0x23, 0xe2, 0xd4, 0x5f, 0xc1, 0xef, 0x88, 0x38, 0x71, 0xe4, 0x14, 0x11, 0xff, 0x00, |
|
| 3292 |
- 0xc4, 0x4f, 0x40, 0xbb, 0x33, 0xeb, 0x18, 0x67, 0xdd, 0x38, 0x39, 0x65, 0xe7, 0xcd, 0xf7, 0x7d, |
|
| 3293 |
- 0xef, 0xd3, 0x7b, 0xf3, 0x5e, 0x0c, 0x65, 0xd7, 0x13, 0x81, 0x23, 0xfb, 0x2f, 0x90, 0xd7, 0x03, |
|
| 3294 |
- 0xce, 0x24, 0xa3, 0xd4, 0x65, 0xfd, 0x21, 0xf2, 0xba, 0x78, 0xe5, 0xf0, 0x93, 0xa1, 0x27, 0xeb, |
|
| 3295 |
- 0x2f, 0x3f, 0xaa, 0x18, 0x72, 0x14, 0xa0, 0x50, 0x80, 0x4a, 0x89, 0x1d, 0x7d, 0x8b, 0x7d, 0x99, |
|
| 3296 |
- 0x1c, 0x6f, 0x0f, 0xd8, 0x80, 0xc5, 0x9f, 0x3b, 0xd1, 0x97, 0x8e, 0xbe, 0x17, 0x1c, 0x87, 0x03, |
|
| 3297 |
- 0xcf, 0xdf, 0x51, 0x7f, 0x74, 0xf0, 0x8e, 0x1b, 0x72, 0x47, 0x7a, 0xcc, 0xdf, 0x49, 0x3e, 0xd4, |
|
| 3298 |
- 0x85, 0xf5, 0x33, 0x81, 0xd5, 0x43, 0x14, 0xc2, 0x63, 0xbe, 0x8d, 0xdf, 0x85, 0x28, 0x24, 0x6d, |
|
| 3299 |
- 0x83, 0xe1, 0xa2, 0xe8, 0x73, 0x2f, 0x88, 0x70, 0x26, 0xa9, 0x91, 0x2d, 0xa3, 0xb1, 0x5e, 0xbf, |
|
| 3300 |
- 0x6c, 0xae, 0x7e, 0xc0, 0x5c, 0x6c, 0x5d, 0x40, 0xed, 0x69, 0x1e, 0xdd, 0x06, 0x10, 0x4a, 0xb8, |
|
| 3301 |
- 0xe7, 0xb9, 0x66, 0xa6, 0x46, 0xb6, 0x0a, 0xcd, 0xd2, 0xf8, 0x6c, 0xad, 0xa0, 0xd3, 0x75, 0x5a, |
|
| 3302 |
- 0x76, 0x41, 0x03, 0x3a, 0xae, 0xf5, 0x53, 0x66, 0xe2, 0x63, 0x1f, 0x85, 0x70, 0x06, 0x38, 0x23, |
|
| 3303 |
- 0x40, 0xde, 0x2e, 0x40, 0xb7, 0x21, 0xe7, 0x33, 0x17, 0xe3, 0x44, 0x46, 0xc3, 0x9c, 0x67, 0xd7, |
|
| 3304 |
- 0x8e, 0x51, 0x74, 0x17, 0x6e, 0x9d, 0x38, 0xbe, 0x33, 0x40, 0x2e, 0xcc, 0x6c, 0x2d, 0xbb, 0x65, |
|
| 3305 |
- 0x34, 0x6a, 0x69, 0x8c, 0xe7, 0xe8, 0x0d, 0x5e, 0x48, 0x74, 0x9f, 0x21, 0x72, 0x7b, 0xc2, 0xa0, |
|
| 3306 |
- 0xcf, 0xe1, 0x7d, 0x1f, 0xe5, 0x2b, 0xc6, 0x87, 0xbd, 0x23, 0xc6, 0xa4, 0x90, 0xdc, 0x09, 0x7a, |
|
| 3307 |
- 0x43, 0x1c, 0x09, 0x33, 0x17, 0x6b, 0xdd, 0x4f, 0xd3, 0x6a, 0xfb, 0x7d, 0x3e, 0x8a, 0x4b, 0xf3, |
|
| 3308 |
- 0x18, 0x47, 0xf6, 0x6d, 0x2d, 0xd0, 0x4c, 0xf8, 0x8f, 0x71, 0x24, 0xac, 0x2f, 0xa1, 0xfc, 0x15, |
|
| 3309 |
- 0x3a, 0x5c, 0x1e, 0xa1, 0x23, 0x93, 0x76, 0x5c, 0xab, 0x0c, 0xd6, 0x53, 0x78, 0x77, 0x4a, 0x41, |
|
| 3310 |
- 0x04, 0xcc, 0x17, 0x48, 0x3f, 0x85, 0x7c, 0x80, 0xdc, 0x63, 0xae, 0x6e, 0xe6, 0xdd, 0x34, 0x7f, |
|
| 3311 |
- 0x2d, 0xfd, 0x30, 0x9a, 0xb9, 0xd3, 0xb3, 0xb5, 0x25, 0x5b, 0x33, 0xac, 0x5f, 0x33, 0x70, 0xe7, |
|
| 3312 |
- 0xeb, 0xc0, 0x75, 0x24, 0x76, 0x1d, 0x31, 0x3c, 0x94, 0x8e, 0x0c, 0xc5, 0x8d, 0xac, 0xd1, 0x6f, |
|
| 3313 |
- 0x60, 0x25, 0x8c, 0x85, 0x92, 0x92, 0xef, 0xa6, 0xd9, 0x98, 0x93, 0xab, 0x7e, 0x11, 0x51, 0x08, |
|
| 3314 |
- 0x3b, 0x11, 0xab, 0x30, 0x28, 0xcf, 0x5e, 0xd2, 0x75, 0x58, 0x91, 0x8e, 0x18, 0x5e, 0xd8, 0x82, |
|
| 3315 |
- 0xf1, 0xd9, 0x5a, 0x3e, 0x82, 0x75, 0x5a, 0x76, 0x3e, 0xba, 0xea, 0xb8, 0xf4, 0x13, 0xc8, 0x8b, |
|
| 3316 |
- 0x98, 0xa4, 0x1f, 0x4d, 0x35, 0xcd, 0xcf, 0x94, 0x13, 0x8d, 0xb6, 0x2a, 0x60, 0x5e, 0x76, 0xa9, |
|
| 3317 |
- 0x4a, 0x6d, 0xed, 0x42, 0x31, 0x8a, 0xde, 0xac, 0x44, 0xd6, 0xe7, 0x9a, 0x9d, 0x8c, 0x40, 0x1d, |
|
| 3318 |
- 0x96, 0x23, 0xaf, 0xc2, 0x24, 0x71, 0xc1, 0xcc, 0x79, 0x06, 0x6d, 0x05, 0xb3, 0x9a, 0x40, 0xf7, |
|
| 3319 |
- 0x84, 0xf0, 0x06, 0xfe, 0x09, 0xfa, 0xf2, 0x86, 0x1e, 0x5e, 0x67, 0xff, 0x27, 0x92, 0x58, 0xf9, |
|
| 3320 |
- 0x02, 0x72, 0xd1, 0x2a, 0x8a, 0xe9, 0xab, 0x8d, 0x07, 0x69, 0x4e, 0x2e, 0xb3, 0xea, 0xdd, 0x51, |
|
| 3321 |
- 0x80, 0x76, 0x4c, 0xa4, 0xf7, 0x00, 0x9c, 0x20, 0x38, 0xf6, 0x50, 0xf4, 0x24, 0x53, 0xfb, 0xc0, |
|
| 3322 |
- 0x2e, 0xe8, 0x48, 0x97, 0x45, 0xd7, 0x1c, 0x45, 0x78, 0x2c, 0x45, 0xcf, 0xf3, 0xcd, 0xac, 0xba, |
|
| 3323 |
- 0xd6, 0x91, 0x8e, 0x4f, 0x3f, 0x83, 0xa2, 0xea, 0x77, 0x4f, 0x15, 0x24, 0x77, 0x45, 0x41, 0x8c, |
|
| 3324 |
- 0x70, 0xd2, 0x21, 0x41, 0xef, 0x43, 0x91, 0xe3, 0x09, 0x7b, 0x99, 0x90, 0x97, 0x6b, 0xd9, 0xad, |
|
| 3325 |
- 0x82, 0x6d, 0xa8, 0x98, 0x82, 0xec, 0xc1, 0xaa, 0xd6, 0x17, 0xd8, 0xe7, 0x28, 0x85, 0x99, 0x8f, |
|
| 3326 |
- 0x33, 0x54, 0xd2, 0x32, 0x1c, 0xc6, 0x10, 0xbb, 0xa4, 0x18, 0xea, 0x24, 0xe8, 0x06, 0xac, 0xea, |
|
| 3327 |
- 0x2c, 0x89, 0xc4, 0x4a, 0x9c, 0xa7, 0xa4, 0xa2, 0x1a, 0x66, 0x6d, 0x40, 0x2e, 0xaa, 0x0a, 0x2d, |
|
| 3328 |
- 0xc2, 0xad, 0x47, 0x4f, 0xf7, 0x9f, 0x3d, 0x69, 0x77, 0xdb, 0xe5, 0x25, 0xfa, 0x0e, 0x18, 0x9d, |
|
| 3329 |
- 0x83, 0x47, 0x76, 0x7b, 0xbf, 0x7d, 0xd0, 0xdd, 0x7b, 0x52, 0x26, 0x8d, 0x37, 0xcb, 0x00, 0xad, |
|
| 3330 |
- 0xc9, 0x7f, 0x08, 0xfa, 0x3d, 0xac, 0xe8, 0x6e, 0x51, 0x2b, 0xdd, 0xd2, 0xf4, 0x0e, 0xaf, 0xbc, |
|
| 3331 |
- 0x0d, 0xa3, 0x7b, 0x63, 0xad, 0xff, 0xf1, 0xfb, 0x3f, 0x6f, 0x32, 0xf7, 0xa0, 0x18, 0x63, 0x3e, |
|
| 3332 |
- 0x8c, 0xb6, 0x11, 0x72, 0x28, 0xa9, 0x93, 0xde, 0x75, 0x0f, 0x09, 0xfd, 0x01, 0x0a, 0x93, 0x8d, |
|
| 3333 |
- 0x42, 0x3f, 0x48, 0xd3, 0x9d, 0x5d, 0x59, 0x95, 0x8d, 0x2b, 0x50, 0x7a, 0x56, 0x16, 0x31, 0x40, |
|
| 3334 |
- 0x7f, 0x23, 0x50, 0x9e, 0x9d, 0x36, 0xfa, 0xe0, 0x1a, 0x9b, 0xa3, 0xb2, 0xbd, 0x18, 0xf8, 0x3a, |
|
| 3335 |
- 0xa6, 0x42, 0x58, 0x56, 0xcf, 0xa6, 0x36, 0xef, 0x01, 0x4e, 0xb2, 0xcf, 0x47, 0x24, 0x7d, 0xd8, |
|
| 3336 |
- 0x5c, 0x20, 0xe3, 0x2f, 0x19, 0xf2, 0x90, 0xd0, 0xd7, 0x04, 0x8c, 0xa9, 0x21, 0xa3, 0x9b, 0x57, |
|
| 3337 |
- 0x4c, 0x61, 0xe2, 0x61, 0x73, 0xb1, 0x69, 0x5d, 0xf0, 0x45, 0x34, 0xef, 0x9e, 0x9e, 0x57, 0x97, |
|
| 3338 |
- 0xfe, 0x3a, 0xaf, 0x2e, 0xfd, 0x7b, 0x5e, 0x25, 0x3f, 0x8e, 0xab, 0xe4, 0x74, 0x5c, 0x25, 0x7f, |
|
| 3339 |
- 0x8e, 0xab, 0xe4, 0xef, 0x71, 0x95, 0x1c, 0xe5, 0xe3, 0x1f, 0x16, 0x1f, 0xff, 0x17, 0x00, 0x00, |
|
| 3340 |
- 0xff, 0xff, 0xf5, 0xa0, 0x46, 0x49, 0xe0, 0x08, 0x00, 0x00, |
|
| 3286 |
+ // 939 bytes of a gzipped FileDescriptorProto |
|
| 3287 |
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x56, 0x4f, 0x6f, 0xdb, 0xc6, |
|
| 3288 |
+ 0x13, 0xd5, 0xca, 0x32, 0x1d, 0x8f, 0x6c, 0xff, 0xf4, 0xdb, 0x06, 0x89, 0x40, 0x24, 0xb2, 0x4a, |
|
| 3289 |
+ 0x37, 0x82, 0x81, 0xb8, 0x72, 0xaa, 0xfe, 0x39, 0x14, 0x86, 0x5b, 0xcb, 0x12, 0x60, 0x21, 0x91, |
|
| 3290 |
+ 0x6d, 0xac, 0x95, 0xe4, 0x28, 0x50, 0xe2, 0x40, 0x66, 0x65, 0x71, 0x59, 0xee, 0x2a, 0xa9, 0x0a, |
|
| 3291 |
+ 0x14, 0x28, 0xd0, 0x06, 0x28, 0x7a, 0x2a, 0x7a, 0xca, 0xa5, 0x5f, 0xa1, 0x9f, 0xc3, 0xe8, 0xa9, |
|
| 3292 |
+ 0xc7, 0x9e, 0x8c, 0x5a, 0x1f, 0xa0, 0xe8, 0xb9, 0xa7, 0x82, 0xe4, 0x52, 0x52, 0x15, 0xca, 0x91, |
|
| 3293 |
+ 0x7d, 0x12, 0x39, 0xf3, 0xde, 0xcc, 0xe3, 0xec, 0xf0, 0x51, 0x90, 0xb1, 0x6c, 0xe1, 0x9a, 0xb2, |
|
| 3294 |
+ 0x7d, 0x8a, 0x5e, 0xd1, 0xf5, 0xb8, 0xe4, 0x94, 0x5a, 0xbc, 0xdd, 0x45, 0xaf, 0x28, 0x5e, 0x9a, |
|
| 3295 |
+ 0x5e, 0xaf, 0x6b, 0xcb, 0xe2, 0x8b, 0x0f, 0xf4, 0xb4, 0x1c, 0xb8, 0x28, 0x42, 0x80, 0xbe, 0xca, |
|
| 3296 |
+ 0x5b, 0x5f, 0x60, 0x5b, 0x46, 0xb7, 0xb7, 0x3b, 0xbc, 0xc3, 0x83, 0xcb, 0x6d, 0xff, 0x4a, 0x45, |
|
| 3297 |
+ 0xdf, 0x71, 0xcf, 0xfa, 0x1d, 0xdb, 0xd9, 0x0e, 0x7f, 0x54, 0xf0, 0xae, 0xd5, 0xf7, 0x4c, 0x69, |
|
| 3298 |
+ 0x73, 0x67, 0x3b, 0xba, 0x08, 0x13, 0xc6, 0x2b, 0x02, 0x6b, 0x27, 0x28, 0x84, 0xcd, 0x1d, 0x86, |
|
| 3299 |
+ 0x5f, 0xf6, 0x51, 0x48, 0x5a, 0x85, 0xb4, 0x85, 0xa2, 0xed, 0xd9, 0xae, 0x8f, 0xcb, 0x92, 0x3c, |
|
| 3300 |
+ 0xd9, 0x4c, 0x97, 0x36, 0x8a, 0x6f, 0x8a, 0x2b, 0x1e, 0x72, 0x0b, 0x2b, 0x63, 0x28, 0x9b, 0xe4, |
|
| 3301 |
+ 0xd1, 0x2d, 0x00, 0x11, 0x16, 0x6e, 0xda, 0x56, 0x36, 0x99, 0x27, 0x9b, 0xcb, 0xe5, 0xd5, 0xe1, |
|
| 3302 |
+ 0xc5, 0xfa, 0xb2, 0x6a, 0x57, 0xab, 0xb0, 0x65, 0x05, 0xa8, 0x59, 0xc6, 0x77, 0xc9, 0x91, 0x8e, |
|
| 3303 |
+ 0x3a, 0x0a, 0x61, 0x76, 0x70, 0xaa, 0x00, 0xb9, 0xba, 0x00, 0xdd, 0x82, 0x94, 0xc3, 0x2d, 0x0c, |
|
| 3304 |
+ 0x1a, 0xa5, 0x4b, 0xd9, 0x59, 0x72, 0x59, 0x80, 0xa2, 0x3b, 0x70, 0xab, 0x67, 0x3a, 0x66, 0x07, |
|
| 3305 |
+ 0x3d, 0x91, 0x5d, 0xc8, 0x2f, 0x6c, 0xa6, 0x4b, 0xf9, 0x38, 0xc6, 0x73, 0xb4, 0x3b, 0xa7, 0x12, |
|
| 3306 |
+ 0xad, 0x63, 0x44, 0x8f, 0x8d, 0x18, 0xf4, 0x39, 0xdc, 0x71, 0x50, 0xbe, 0xe4, 0x5e, 0xb7, 0xd9, |
|
| 3307 |
+ 0xe2, 0x5c, 0x0a, 0xe9, 0x99, 0x6e, 0xb3, 0x8b, 0x03, 0x91, 0x4d, 0x05, 0xb5, 0xde, 0x8d, 0xab, |
|
| 3308 |
+ 0x55, 0x75, 0xda, 0xde, 0x20, 0x18, 0xcd, 0x63, 0x1c, 0xb0, 0xdb, 0xaa, 0x40, 0x39, 0xe2, 0x3f, |
|
| 3309 |
+ 0xc6, 0x81, 0x30, 0x3e, 0x87, 0xcc, 0x01, 0x9a, 0x9e, 0x6c, 0xa1, 0x29, 0xa3, 0xe3, 0xb8, 0xd6, |
|
| 3310 |
+ 0x18, 0x8c, 0x23, 0xf8, 0xff, 0x44, 0x05, 0xe1, 0x72, 0x47, 0x20, 0xfd, 0x14, 0x34, 0x17, 0x3d, |
|
| 3311 |
+ 0x9b, 0x5b, 0xea, 0x30, 0xef, 0xc5, 0xe9, 0xab, 0xa8, 0xc5, 0x28, 0xa7, 0xce, 0x2f, 0xd6, 0x13, |
|
| 3312 |
+ 0x4c, 0x31, 0x8c, 0x9f, 0x92, 0x70, 0xf7, 0xa9, 0x6b, 0x99, 0x12, 0x1b, 0xa6, 0xe8, 0x9e, 0x48, |
|
| 3313 |
+ 0x53, 0xf6, 0xc5, 0x8d, 0xa4, 0xd1, 0x67, 0xb0, 0xd4, 0x0f, 0x0a, 0x45, 0x23, 0xdf, 0x89, 0x93, |
|
| 3314 |
+ 0x31, 0xa3, 0x57, 0x71, 0x1c, 0x09, 0x11, 0x2c, 0x2a, 0xa6, 0x73, 0xc8, 0x4c, 0x27, 0xe9, 0x06, |
|
| 3315 |
+ 0x2c, 0x49, 0x53, 0x74, 0xc7, 0xb2, 0x60, 0x78, 0xb1, 0xae, 0xf9, 0xb0, 0x5a, 0x85, 0x69, 0x7e, |
|
| 3316 |
+ 0xaa, 0x66, 0xd1, 0x4f, 0x40, 0x13, 0x01, 0x49, 0x2d, 0x4d, 0x2e, 0x4e, 0xcf, 0x84, 0x12, 0x85, |
|
| 3317 |
+ 0x36, 0x74, 0xc8, 0xbe, 0xa9, 0x32, 0x1c, 0xb5, 0xb1, 0x03, 0x2b, 0x7e, 0xf4, 0x66, 0x23, 0x32, |
|
| 3318 |
+ 0x76, 0x15, 0x3b, 0x7a, 0x05, 0x8a, 0xb0, 0xe8, 0x6b, 0x15, 0x59, 0x12, 0x0c, 0x2c, 0x3b, 0x4b, |
|
| 3319 |
+ 0x20, 0x0b, 0x61, 0x46, 0x19, 0xe8, 0x9e, 0x10, 0x76, 0xc7, 0xe9, 0xa1, 0x23, 0x6f, 0xa8, 0xe1, |
|
| 3320 |
+ 0x6b, 0x80, 0x71, 0x0d, 0x5a, 0x84, 0x94, 0x5f, 0x5a, 0x2d, 0xce, 0x4c, 0x01, 0x07, 0x09, 0x16, |
|
| 3321 |
+ 0xe0, 0xe8, 0x47, 0xa0, 0x09, 0x6c, 0x7b, 0x28, 0xd5, 0x4c, 0xf5, 0x38, 0xc6, 0x49, 0x80, 0x38, |
|
| 3322 |
+ 0x48, 0x30, 0x85, 0x2d, 0x6b, 0x90, 0xb2, 0x25, 0xf6, 0x8c, 0x57, 0x49, 0xc8, 0x8c, 0x9b, 0xef, |
|
| 3323 |
+ 0x9f, 0x9a, 0x4e, 0x07, 0xe9, 0x2e, 0x80, 0x39, 0x8a, 0x29, 0x21, 0xb1, 0x47, 0x35, 0x66, 0xb2, |
|
| 3324 |
+ 0x09, 0x06, 0xad, 0x83, 0x66, 0xb6, 0x03, 0x2b, 0xf3, 0x25, 0xad, 0x95, 0x3e, 0xbe, 0x9a, 0x1b, |
|
| 3325 |
+ 0x76, 0x9d, 0x08, 0xec, 0x05, 0x64, 0xa6, 0x8a, 0x18, 0xad, 0x49, 0x89, 0x61, 0x8e, 0x16, 0x40, |
|
| 3326 |
+ 0x7b, 0x7a, 0x5c, 0xd9, 0x6b, 0x54, 0x33, 0x09, 0x5d, 0xff, 0xf1, 0x97, 0xfc, 0x9d, 0x69, 0x84, |
|
| 3327 |
+ 0x5a, 0xcb, 0x02, 0x68, 0xac, 0x5a, 0x3f, 0x7a, 0x56, 0xcd, 0x90, 0x78, 0x1c, 0xc3, 0x1e, 0x7f, |
|
| 3328 |
+ 0x81, 0xc6, 0x3f, 0xe4, 0x3f, 0x07, 0x19, 0xad, 0xc3, 0x67, 0x90, 0xf2, 0x3f, 0x07, 0xc1, 0x0c, |
|
| 3329 |
+ 0xd6, 0x4a, 0x0f, 0xaf, 0x7e, 0x8e, 0x88, 0x55, 0x6c, 0x0c, 0x5c, 0x64, 0x01, 0x91, 0xde, 0x07, |
|
| 3330 |
+ 0x30, 0x5d, 0xf7, 0xcc, 0x46, 0xd1, 0x94, 0x3c, 0xf4, 0x64, 0xb6, 0xac, 0x22, 0x0d, 0xee, 0xa7, |
|
| 3331 |
+ 0x3d, 0x14, 0xfd, 0x33, 0x29, 0x9a, 0xb6, 0x93, 0x5d, 0x08, 0xd3, 0x2a, 0x52, 0x73, 0xe8, 0x2e, |
|
| 3332 |
+ 0x2c, 0xb5, 0x83, 0xe1, 0x44, 0x3e, 0xf7, 0xde, 0x3c, 0x93, 0x64, 0x11, 0xc9, 0x78, 0x00, 0x29, |
|
| 3333 |
+ 0x5f, 0x0b, 0x5d, 0x81, 0x5b, 0xfb, 0x47, 0xf5, 0xe3, 0x27, 0x55, 0x7f, 0x5e, 0xf4, 0x7f, 0x90, |
|
| 3334 |
+ 0xae, 0x1d, 0xee, 0xb3, 0x6a, 0xbd, 0x7a, 0xd8, 0xd8, 0x7b, 0x92, 0x21, 0xa5, 0xd7, 0x8b, 0x00, |
|
| 3335 |
+ 0x95, 0xd1, 0xb7, 0x91, 0x7e, 0x05, 0x4b, 0x6a, 0x4f, 0xa9, 0x11, 0xbf, 0x4c, 0x93, 0x5f, 0x2f, |
|
| 3336 |
+ 0xfd, 0x2a, 0x8c, 0x9a, 0x88, 0xb1, 0xf1, 0xdb, 0xaf, 0x7f, 0xbd, 0x4e, 0xde, 0x87, 0x95, 0x00, |
|
| 3337 |
+ 0xf3, 0xbe, 0xef, 0xc3, 0xe8, 0xc1, 0x6a, 0x78, 0xa7, 0x5c, 0xfe, 0x11, 0xa1, 0xdf, 0xc0, 0xf2, |
|
| 3338 |
+ 0xc8, 0x4b, 0x69, 0xec, 0xb3, 0x4e, 0x9b, 0xb5, 0xfe, 0xe0, 0x2d, 0x28, 0xe5, 0x12, 0xf3, 0x08, |
|
| 3339 |
+ 0xa0, 0x3f, 0x13, 0xc8, 0x4c, 0xfb, 0x0c, 0x7d, 0x78, 0x0d, 0xcf, 0xd4, 0xb7, 0xe6, 0x03, 0x5f, |
|
| 3340 |
+ 0x47, 0x54, 0x1f, 0x16, 0x03, 0x87, 0xa2, 0xf9, 0x59, 0x56, 0x30, 0xea, 0x3e, 0x1b, 0x11, 0x9d, |
|
| 3341 |
+ 0x43, 0x61, 0x8e, 0x8e, 0x3f, 0x24, 0xc9, 0x23, 0x42, 0xbf, 0x27, 0x90, 0x9e, 0x58, 0x6d, 0x5a, |
|
| 3342 |
+ 0x78, 0xcb, 0xee, 0x47, 0x1a, 0x0a, 0xf3, 0xbd, 0x23, 0x73, 0x6e, 0x44, 0xf9, 0xde, 0xf9, 0x65, |
|
| 3343 |
+ 0x2e, 0xf1, 0xc7, 0x65, 0x2e, 0xf1, 0xf7, 0x65, 0x8e, 0x7c, 0x3b, 0xcc, 0x91, 0xf3, 0x61, 0x8e, |
|
| 3344 |
+ 0xfc, 0x3e, 0xcc, 0x91, 0x3f, 0x87, 0x39, 0xd2, 0xd2, 0x82, 0xbf, 0x54, 0x1f, 0xfe, 0x1b, 0x00, |
|
| 3345 |
+ 0x00, 0xff, 0xff, 0x1d, 0x6e, 0x3d, 0x14, 0xda, 0x09, 0x00, 0x00, |
|
| 3341 | 3346 |
} |
| ... | ... |
@@ -170,6 +170,23 @@ message AssignmentsRequest {
|
| 170 | 170 |
string session_id = 1 [(gogoproto.customname) = "SessionID"]; |
| 171 | 171 |
} |
| 172 | 172 |
|
| 173 |
+message Assignment {
|
|
| 174 |
+ oneof item {
|
|
| 175 |
+ Task task = 1; |
|
| 176 |
+ Secret secret = 2; |
|
| 177 |
+ } |
|
| 178 |
+} |
|
| 179 |
+ |
|
| 180 |
+message AssignmentChange {
|
|
| 181 |
+ enum AssignmentAction {
|
|
| 182 |
+ UPDATE = 0 [(gogoproto.enumvalue_customname) = "AssignmentActionUpdate"]; |
|
| 183 |
+ REMOVE = 1 [(gogoproto.enumvalue_customname) = "AssignmentActionRemove"]; |
|
| 184 |
+ } |
|
| 185 |
+ |
|
| 186 |
+ Assignment assignment = 1; |
|
| 187 |
+ AssignmentAction action = 2; |
|
| 188 |
+} |
|
| 189 |
+ |
|
| 173 | 190 |
message AssignmentsMessage {
|
| 174 | 191 |
// AssignmentType specifies whether this assignment message carries |
| 175 | 192 |
// the full state, or is an update to an existing state. |
| ... | ... |
@@ -192,24 +209,6 @@ message AssignmentsMessage {
|
| 192 | 192 |
// against missed messages. |
| 193 | 193 |
string results_in = 3; |
| 194 | 194 |
|
| 195 |
- // UpdateTasks is a set of new or updated tasks to run on this node. |
|
| 196 |
- // In the first assignments message, it contains all of the tasks |
|
| 197 |
- // to run on this node. Tasks outside of this set running on the node |
|
| 198 |
- // should be terminated. |
|
| 199 |
- repeated Task update_tasks = 4; |
|
| 200 |
- |
|
| 201 |
- // RemoveTasks is a set of previously-assigned task IDs to remove from the |
|
| 202 |
- // assignment set. It is not used in the first assignments message of |
|
| 203 |
- // a stream. |
|
| 204 |
- repeated string remove_tasks = 5; |
|
| 205 |
- |
|
| 206 |
- // UpdateSecrets is a set of new or updated secrets for this node. |
|
| 207 |
- // In the first assignments message, it contains all of the secrets |
|
| 208 |
- // the node needs for itself and its assigned tasks. |
|
| 209 |
- repeated Secret update_secrets = 6; |
|
| 210 |
- |
|
| 211 |
- // RemoveSecrets is a set of previously-assigned secret names to remove |
|
| 212 |
- // from memory. It is not used in the first assignments message of |
|
| 213 |
- // a stream. |
|
| 214 |
- repeated string remove_secrets = 7; |
|
| 195 |
+ // AssignmentChange is a set of changes to apply on this node. |
|
| 196 |
+ repeated AssignmentChange changes = 4; |
|
| 215 | 197 |
} |
| ... | ... |
@@ -473,7 +473,7 @@ type ContainerSpec struct {
|
| 473 | 473 |
StopGracePeriod *docker_swarmkit_v11.Duration `protobuf:"bytes,9,opt,name=stop_grace_period,json=stopGracePeriod" json:"stop_grace_period,omitempty"` |
| 474 | 474 |
// PullOptions parameterize the behavior of image pulls. |
| 475 | 475 |
PullOptions *ContainerSpec_PullOptions `protobuf:"bytes,10,opt,name=pull_options,json=pullOptions" json:"pull_options,omitempty"` |
| 476 |
- // Secrets contains references to zero or more secrets that |
|
| 476 |
+ // SecretReference contains references to zero or more secrets that |
|
| 477 | 477 |
// will be exposed to the container. |
| 478 | 478 |
Secrets []*SecretReference `protobuf:"bytes,12,rep,name=secrets" json:"secrets,omitempty"` |
| 479 | 479 |
} |
| ... | ... |
@@ -189,7 +189,7 @@ message ContainerSpec {
|
| 189 | 189 |
// PullOptions parameterize the behavior of image pulls. |
| 190 | 190 |
PullOptions pull_options = 10; |
| 191 | 191 |
|
| 192 |
- // Secrets contains references to zero or more secrets that |
|
| 192 |
+ // SecretReference contains references to zero or more secrets that |
|
| 193 | 193 |
// will be exposed to the container. |
| 194 | 194 |
repeated SecretReference secrets = 12; |
| 195 | 195 |
} |
| ... | ... |
@@ -133,6 +133,8 @@ |
| 133 | 133 |
TasksRequest |
| 134 | 134 |
TasksMessage |
| 135 | 135 |
AssignmentsRequest |
| 136 |
+ Assignment |
|
| 137 |
+ AssignmentChange |
|
| 136 | 138 |
AssignmentsMessage |
| 137 | 139 |
NodeCertificateStatusRequest |
| 138 | 140 |
NodeCertificateStatusResponse |
| ... | ... |
@@ -1053,8 +1055,8 @@ func _TaskStatus_OneofSizer(msg proto.Message) (n int) {
|
| 1053 | 1053 |
// instructing Swarm on how this service should work on the particular |
| 1054 | 1054 |
// network. |
| 1055 | 1055 |
type NetworkAttachmentConfig struct {
|
| 1056 |
- // Target specifies the target network for attachment. This value may be a |
|
| 1057 |
- // network name or identifier. Only identifiers are supported at this time. |
|
| 1056 |
+ // Target specifies the target network for attachment. This value must be a |
|
| 1057 |
+ // network ID. |
|
| 1058 | 1058 |
Target string `protobuf:"bytes,1,opt,name=target,proto3" json:"target,omitempty"` |
| 1059 | 1059 |
// Aliases specifies a list of discoverable alternate names for the service on this Target. |
| 1060 | 1060 |
Aliases []string `protobuf:"bytes,2,rep,name=aliases" json:"aliases,omitempty"` |
| ... | ... |
@@ -447,8 +447,8 @@ message TaskStatus {
|
| 447 | 447 |
// instructing Swarm on how this service should work on the particular |
| 448 | 448 |
// network. |
| 449 | 449 |
message NetworkAttachmentConfig {
|
| 450 |
- // Target specifies the target network for attachment. This value may be a |
|
| 451 |
- // network name or identifier. Only identifiers are supported at this time. |
|
| 450 |
+ // Target specifies the target network for attachment. This value must be a |
|
| 451 |
+ // network ID. |
|
| 452 | 452 |
string target = 1; |
| 453 | 453 |
// Aliases specifies a list of discoverable alternate names for the service on this Target. |
| 454 | 454 |
repeated string aliases = 2; |
| 455 | 455 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,23 @@ |
| 0 |
+package networkallocator |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "github.com/docker/libnetwork/drvregistry" |
|
| 4 |
+ "github.com/docker/libnetwork/ipamapi" |
|
| 5 |
+ builtinIpam "github.com/docker/libnetwork/ipams/builtin" |
|
| 6 |
+ nullIpam "github.com/docker/libnetwork/ipams/null" |
|
| 7 |
+ remoteIpam "github.com/docker/libnetwork/ipams/remote" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+func initIPAMDrivers(r *drvregistry.DrvRegistry) error {
|
|
| 11 |
+ for _, fn := range [](func(ipamapi.Callback, interface{}, interface{}) error){
|
|
| 12 |
+ builtinIpam.Init, |
|
| 13 |
+ remoteIpam.Init, |
|
| 14 |
+ nullIpam.Init, |
|
| 15 |
+ } {
|
|
| 16 |
+ if err := fn(r, nil, nil); err != nil {
|
|
| 17 |
+ return err |
|
| 18 |
+ } |
|
| 19 |
+ } |
|
| 20 |
+ |
|
| 21 |
+ return nil |
|
| 22 |
+} |
| 0 | 23 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,13 @@ |
| 0 |
+package networkallocator |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "github.com/docker/libnetwork/drivers/overlay/ovmanager" |
|
| 4 |
+ "github.com/docker/libnetwork/drivers/remote" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+func getInitializers() []initializer {
|
|
| 8 |
+ return []initializer{
|
|
| 9 |
+ {remote.Init, "remote"},
|
|
| 10 |
+ {ovmanager.Init, "overlay"},
|
|
| 11 |
+ } |
|
| 12 |
+} |
| ... | ... |
@@ -4,12 +4,11 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"net" |
| 6 | 6 |
|
| 7 |
+ "github.com/docker/docker/pkg/plugins" |
|
| 8 |
+ "github.com/docker/libnetwork/datastore" |
|
| 7 | 9 |
"github.com/docker/libnetwork/driverapi" |
| 8 |
- "github.com/docker/libnetwork/drivers/overlay/ovmanager" |
|
| 9 | 10 |
"github.com/docker/libnetwork/drvregistry" |
| 10 | 11 |
"github.com/docker/libnetwork/ipamapi" |
| 11 |
- builtinIpam "github.com/docker/libnetwork/ipams/builtin" |
|
| 12 |
- nullIpam "github.com/docker/libnetwork/ipams/null" |
|
| 13 | 12 |
"github.com/docker/swarmkit/api" |
| 14 | 13 |
"github.com/docker/swarmkit/log" |
| 15 | 14 |
"github.com/pkg/errors" |
| ... | ... |
@@ -23,10 +22,6 @@ const ( |
| 23 | 23 |
DefaultDriver = "overlay" |
| 24 | 24 |
) |
| 25 | 25 |
|
| 26 |
-var ( |
|
| 27 |
- defaultDriverInitFunc = ovmanager.Init |
|
| 28 |
-) |
|
| 29 |
- |
|
| 30 | 26 |
// NetworkAllocator acts as the controller for all network related operations |
| 31 | 27 |
// like managing network and IPAM drivers and also creating and |
| 32 | 28 |
// deleting networks and the associated resources. |
| ... | ... |
@@ -68,6 +63,11 @@ type network struct {
|
| 68 | 68 |
endpoints map[string]string |
| 69 | 69 |
} |
| 70 | 70 |
|
| 71 |
+type initializer struct {
|
|
| 72 |
+ fn drvregistry.InitFunc |
|
| 73 |
+ ntype string |
|
| 74 |
+} |
|
| 75 |
+ |
|
| 71 | 76 |
// New returns a new NetworkAllocator handle |
| 72 | 77 |
func New() (*NetworkAllocator, error) {
|
| 73 | 78 |
na := &NetworkAllocator{
|
| ... | ... |
@@ -84,18 +84,12 @@ func New() (*NetworkAllocator, error) {
|
| 84 | 84 |
return nil, err |
| 85 | 85 |
} |
| 86 | 86 |
|
| 87 |
- // Add the manager component of overlay driver to the registry. |
|
| 88 |
- if err := reg.AddDriver(DefaultDriver, defaultDriverInitFunc, nil); err != nil {
|
|
| 87 |
+ if err := initializeDrivers(reg); err != nil {
|
|
| 89 | 88 |
return nil, err |
| 90 | 89 |
} |
| 91 | 90 |
|
| 92 |
- for _, fn := range [](func(ipamapi.Callback, interface{}, interface{}) error){
|
|
| 93 |
- builtinIpam.Init, |
|
| 94 |
- nullIpam.Init, |
|
| 95 |
- } {
|
|
| 96 |
- if err := fn(reg, nil, nil); err != nil {
|
|
| 97 |
- return nil, err |
|
| 98 |
- } |
|
| 91 |
+ if err = initIPAMDrivers(reg); err != nil {
|
|
| 92 |
+ return nil, err |
|
| 99 | 93 |
} |
| 100 | 94 |
|
| 101 | 95 |
pa, err := newPortAllocator() |
| ... | ... |
@@ -631,14 +625,33 @@ func (na *NetworkAllocator) resolveDriver(n *api.Network) (driverapi.Driver, str |
| 631 | 631 |
dName = n.Spec.DriverConfig.Name |
| 632 | 632 |
} |
| 633 | 633 |
|
| 634 |
- d, _ := na.drvRegistry.Driver(dName) |
|
| 634 |
+ d, drvcap := na.drvRegistry.Driver(dName) |
|
| 635 | 635 |
if d == nil {
|
| 636 |
- return nil, "", fmt.Errorf("could not resolve network driver %s", dName)
|
|
| 636 |
+ var err error |
|
| 637 |
+ err = na.loadDriver(dName) |
|
| 638 |
+ if err != nil {
|
|
| 639 |
+ return nil, "", err |
|
| 640 |
+ } |
|
| 641 |
+ |
|
| 642 |
+ d, drvcap = na.drvRegistry.Driver(dName) |
|
| 643 |
+ if d == nil {
|
|
| 644 |
+ return nil, "", fmt.Errorf("could not resolve network driver %s", dName)
|
|
| 645 |
+ } |
|
| 646 |
+ |
|
| 647 |
+ } |
|
| 648 |
+ |
|
| 649 |
+ if drvcap.DataScope != datastore.GlobalScope {
|
|
| 650 |
+ return nil, "", fmt.Errorf("swarm can allocate network resources only for global scoped networks. network driver (%s) is scoped %s", dName, drvcap.DataScope)
|
|
| 637 | 651 |
} |
| 638 | 652 |
|
| 639 | 653 |
return d, dName, nil |
| 640 | 654 |
} |
| 641 | 655 |
|
| 656 |
+func (na *NetworkAllocator) loadDriver(name string) error {
|
|
| 657 |
+ _, err := plugins.Get(name, driverapi.NetworkPluginEndpointType) |
|
| 658 |
+ return err |
|
| 659 |
+} |
|
| 660 |
+ |
|
| 642 | 661 |
// Resolve the IPAM driver |
| 643 | 662 |
func (na *NetworkAllocator) resolveIPAM(n *api.Network) (ipamapi.Ipam, string, error) {
|
| 644 | 663 |
dName := ipamapi.DefaultIPAM |
| ... | ... |
@@ -746,3 +759,12 @@ func (na *NetworkAllocator) allocatePools(n *api.Network) (map[string]string, er |
| 746 | 746 |
|
| 747 | 747 |
return pools, nil |
| 748 | 748 |
} |
| 749 |
+ |
|
| 750 |
+func initializeDrivers(reg *drvregistry.DrvRegistry) error {
|
|
| 751 |
+ for _, i := range getInitializers() {
|
|
| 752 |
+ if err := reg.AddDriver(i.ntype, i.fn, nil); err != nil {
|
|
| 753 |
+ return err |
|
| 754 |
+ } |
|
| 755 |
+ } |
|
| 756 |
+ return nil |
|
| 757 |
+} |
| 749 | 758 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,164 @@ |
| 0 |
+package constraint |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "regexp" |
|
| 5 |
+ "strings" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/docker/swarmkit/api" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+const ( |
|
| 11 |
+ eq = iota |
|
| 12 |
+ noteq |
|
| 13 |
+ |
|
| 14 |
+ nodeLabelPrefix = "node.labels." |
|
| 15 |
+ engineLabelPrefix = "engine.labels." |
|
| 16 |
+) |
|
| 17 |
+ |
|
| 18 |
+var ( |
|
| 19 |
+ alphaNumeric = regexp.MustCompile(`^(?i)[a-z_][a-z0-9\-_.]+$`) |
|
| 20 |
+ // value can be alphanumeric and some special characters. it shouldn't container |
|
| 21 |
+ // current or future operators like '>, <, ~', etc. |
|
| 22 |
+ valuePattern = regexp.MustCompile(`^(?i)[a-z0-9:\-_\s\.\*\(\)\?\+\[\]\\\^\$\|\/]+$`) |
|
| 23 |
+ |
|
| 24 |
+ // operators defines list of accepted operators |
|
| 25 |
+ operators = []string{"==", "!="}
|
|
| 26 |
+) |
|
| 27 |
+ |
|
| 28 |
+// Constraint defines a constraint. |
|
| 29 |
+type Constraint struct {
|
|
| 30 |
+ key string |
|
| 31 |
+ operator int |
|
| 32 |
+ exp string |
|
| 33 |
+} |
|
| 34 |
+ |
|
| 35 |
+// Parse parses list of constraints. |
|
| 36 |
+func Parse(env []string) ([]Constraint, error) {
|
|
| 37 |
+ exprs := []Constraint{}
|
|
| 38 |
+ for _, e := range env {
|
|
| 39 |
+ found := false |
|
| 40 |
+ // each expr is in the form of "key op value" |
|
| 41 |
+ for i, op := range operators {
|
|
| 42 |
+ if !strings.Contains(e, op) {
|
|
| 43 |
+ continue |
|
| 44 |
+ } |
|
| 45 |
+ // split with the op |
|
| 46 |
+ parts := strings.SplitN(e, op, 2) |
|
| 47 |
+ |
|
| 48 |
+ if len(parts) < 2 {
|
|
| 49 |
+ return nil, fmt.Errorf("invalid expr: %s", e)
|
|
| 50 |
+ } |
|
| 51 |
+ |
|
| 52 |
+ part0 := strings.TrimSpace(parts[0]) |
|
| 53 |
+ // validate key |
|
| 54 |
+ matched := alphaNumeric.MatchString(part0) |
|
| 55 |
+ if matched == false {
|
|
| 56 |
+ return nil, fmt.Errorf("key '%s' is invalid", part0)
|
|
| 57 |
+ } |
|
| 58 |
+ |
|
| 59 |
+ part1 := strings.TrimSpace(parts[1]) |
|
| 60 |
+ |
|
| 61 |
+ // validate Value |
|
| 62 |
+ matched = valuePattern.MatchString(part1) |
|
| 63 |
+ if matched == false {
|
|
| 64 |
+ return nil, fmt.Errorf("value '%s' is invalid", part1)
|
|
| 65 |
+ } |
|
| 66 |
+ // TODO(dongluochen): revisit requirements to see if globing or regex are useful |
|
| 67 |
+ exprs = append(exprs, Constraint{key: part0, operator: i, exp: part1})
|
|
| 68 |
+ |
|
| 69 |
+ found = true |
|
| 70 |
+ break // found an op, move to next entry |
|
| 71 |
+ } |
|
| 72 |
+ if !found {
|
|
| 73 |
+ return nil, fmt.Errorf("constraint expected one operator from %s", strings.Join(operators, ", "))
|
|
| 74 |
+ } |
|
| 75 |
+ } |
|
| 76 |
+ return exprs, nil |
|
| 77 |
+} |
|
| 78 |
+ |
|
| 79 |
+// Match checks if the Constraint matches the target strings. |
|
| 80 |
+func (c *Constraint) Match(whats ...string) bool {
|
|
| 81 |
+ var match bool |
|
| 82 |
+ |
|
| 83 |
+ // full string match |
|
| 84 |
+ for _, what := range whats {
|
|
| 85 |
+ // case insensitive compare |
|
| 86 |
+ if strings.EqualFold(c.exp, what) {
|
|
| 87 |
+ match = true |
|
| 88 |
+ break |
|
| 89 |
+ } |
|
| 90 |
+ } |
|
| 91 |
+ |
|
| 92 |
+ switch c.operator {
|
|
| 93 |
+ case eq: |
|
| 94 |
+ return match |
|
| 95 |
+ case noteq: |
|
| 96 |
+ return !match |
|
| 97 |
+ } |
|
| 98 |
+ |
|
| 99 |
+ return false |
|
| 100 |
+} |
|
| 101 |
+ |
|
| 102 |
+// NodeMatches returns true if the node satisfies the given constraints. |
|
| 103 |
+func NodeMatches(constraints []Constraint, n *api.Node) bool {
|
|
| 104 |
+ for _, constraint := range constraints {
|
|
| 105 |
+ switch {
|
|
| 106 |
+ case strings.EqualFold(constraint.key, "node.id"): |
|
| 107 |
+ if !constraint.Match(n.ID) {
|
|
| 108 |
+ return false |
|
| 109 |
+ } |
|
| 110 |
+ case strings.EqualFold(constraint.key, "node.hostname"): |
|
| 111 |
+ // if this node doesn't have hostname |
|
| 112 |
+ // it's equivalent to match an empty hostname |
|
| 113 |
+ // where '==' would fail, '!=' matches |
|
| 114 |
+ if n.Description == nil {
|
|
| 115 |
+ if !constraint.Match("") {
|
|
| 116 |
+ return false |
|
| 117 |
+ } |
|
| 118 |
+ continue |
|
| 119 |
+ } |
|
| 120 |
+ if !constraint.Match(n.Description.Hostname) {
|
|
| 121 |
+ return false |
|
| 122 |
+ } |
|
| 123 |
+ case strings.EqualFold(constraint.key, "node.role"): |
|
| 124 |
+ if !constraint.Match(n.Spec.Role.String()) {
|
|
| 125 |
+ return false |
|
| 126 |
+ } |
|
| 127 |
+ |
|
| 128 |
+ // node labels constraint in form like 'node.labels.key==value' |
|
| 129 |
+ case len(constraint.key) > len(nodeLabelPrefix) && strings.EqualFold(constraint.key[:len(nodeLabelPrefix)], nodeLabelPrefix): |
|
| 130 |
+ if n.Spec.Annotations.Labels == nil {
|
|
| 131 |
+ if !constraint.Match("") {
|
|
| 132 |
+ return false |
|
| 133 |
+ } |
|
| 134 |
+ continue |
|
| 135 |
+ } |
|
| 136 |
+ label := constraint.key[len(nodeLabelPrefix):] |
|
| 137 |
+ // label itself is case sensitive |
|
| 138 |
+ val := n.Spec.Annotations.Labels[label] |
|
| 139 |
+ if !constraint.Match(val) {
|
|
| 140 |
+ return false |
|
| 141 |
+ } |
|
| 142 |
+ |
|
| 143 |
+ // engine labels constraint in form like 'engine.labels.key!=value' |
|
| 144 |
+ case len(constraint.key) > len(engineLabelPrefix) && strings.EqualFold(constraint.key[:len(engineLabelPrefix)], engineLabelPrefix): |
|
| 145 |
+ if n.Description == nil || n.Description.Engine == nil || n.Description.Engine.Labels == nil {
|
|
| 146 |
+ if !constraint.Match("") {
|
|
| 147 |
+ return false |
|
| 148 |
+ } |
|
| 149 |
+ continue |
|
| 150 |
+ } |
|
| 151 |
+ label := constraint.key[len(engineLabelPrefix):] |
|
| 152 |
+ val := n.Description.Engine.Labels[label] |
|
| 153 |
+ if !constraint.Match(val) {
|
|
| 154 |
+ return false |
|
| 155 |
+ } |
|
| 156 |
+ default: |
|
| 157 |
+ // key doesn't match predefined syntax |
|
| 158 |
+ return false |
|
| 159 |
+ } |
|
| 160 |
+ } |
|
| 161 |
+ |
|
| 162 |
+ return true |
|
| 163 |
+} |
| ... | ... |
@@ -4,10 +4,8 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"net" |
| 6 | 6 |
|
| 7 |
- "github.com/docker/libnetwork/ipamapi" |
|
| 8 | 7 |
"github.com/docker/swarmkit/api" |
| 9 | 8 |
"github.com/docker/swarmkit/identity" |
| 10 |
- "github.com/docker/swarmkit/manager/allocator/networkallocator" |
|
| 11 | 9 |
"github.com/docker/swarmkit/manager/state/store" |
| 12 | 10 |
"golang.org/x/net/context" |
| 13 | 11 |
"google.golang.org/grpc" |
| ... | ... |
@@ -60,10 +58,6 @@ func validateIPAM(ipam *api.IPAMOptions) error {
|
| 60 | 60 |
return err |
| 61 | 61 |
} |
| 62 | 62 |
|
| 63 |
- if ipam.Driver != nil && ipam.Driver.Name != ipamapi.DefaultIPAM {
|
|
| 64 |
- return grpc.Errorf(codes.InvalidArgument, "invalid IPAM specified") |
|
| 65 |
- } |
|
| 66 |
- |
|
| 67 | 63 |
for _, ipamConf := range ipam.Configs {
|
| 68 | 64 |
if err := validateIPAMConfiguration(ipamConf); err != nil {
|
| 69 | 65 |
return err |
| ... | ... |
@@ -86,10 +80,6 @@ func validateNetworkSpec(spec *api.NetworkSpec) error {
|
| 86 | 86 |
return err |
| 87 | 87 |
} |
| 88 | 88 |
|
| 89 |
- if spec.DriverConfig != nil && spec.DriverConfig.Name != networkallocator.DefaultDriver {
|
|
| 90 |
- return grpc.Errorf(codes.InvalidArgument, "invalid driver specified") |
|
| 91 |
- } |
|
| 92 |
- |
|
| 93 | 89 |
if err := validateIPAM(spec.IPAM); err != nil {
|
| 94 | 90 |
return err |
| 95 | 91 |
} |
| ... | ... |
@@ -8,7 +8,7 @@ import ( |
| 8 | 8 |
"github.com/docker/distribution/reference" |
| 9 | 9 |
"github.com/docker/swarmkit/api" |
| 10 | 10 |
"github.com/docker/swarmkit/identity" |
| 11 |
- "github.com/docker/swarmkit/manager/scheduler" |
|
| 11 |
+ "github.com/docker/swarmkit/manager/constraint" |
|
| 12 | 12 |
"github.com/docker/swarmkit/manager/state/store" |
| 13 | 13 |
"github.com/docker/swarmkit/protobuf/ptypes" |
| 14 | 14 |
"golang.org/x/net/context" |
| ... | ... |
@@ -81,7 +81,7 @@ func validatePlacement(placement *api.Placement) error {
|
| 81 | 81 |
if placement == nil {
|
| 82 | 82 |
return nil |
| 83 | 83 |
} |
| 84 |
- _, err := scheduler.ParseExprs(placement.Constraints) |
|
| 84 |
+ _, err := constraint.Parse(placement.Constraints) |
|
| 85 | 85 |
return err |
| 86 | 86 |
} |
| 87 | 87 |
|
| ... | ... |
@@ -170,6 +170,24 @@ func validateEndpointSpec(epSpec *api.EndpointSpec) error {
|
| 170 | 170 |
return nil |
| 171 | 171 |
} |
| 172 | 172 |
|
| 173 |
+func (s *Server) validateNetworks(networks []*api.NetworkAttachmentConfig) error {
|
|
| 174 |
+ for _, na := range networks {
|
|
| 175 |
+ var network *api.Network |
|
| 176 |
+ s.store.View(func(tx store.ReadTx) {
|
|
| 177 |
+ network = store.GetNetwork(tx, na.Target) |
|
| 178 |
+ }) |
|
| 179 |
+ if network == nil {
|
|
| 180 |
+ continue |
|
| 181 |
+ } |
|
| 182 |
+ if _, ok := network.Spec.Annotations.Labels["com.docker.swarm.internal"]; ok {
|
|
| 183 |
+ return grpc.Errorf(codes.InvalidArgument, |
|
| 184 |
+ "Service cannot be explicitly attached to %q network which is a swarm internal network", |
|
| 185 |
+ network.Spec.Annotations.Name) |
|
| 186 |
+ } |
|
| 187 |
+ } |
|
| 188 |
+ return nil |
|
| 189 |
+} |
|
| 190 |
+ |
|
| 173 | 191 |
func validateServiceSpec(spec *api.ServiceSpec) error {
|
| 174 | 192 |
if spec == nil {
|
| 175 | 193 |
return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error()) |
| ... | ... |
@@ -259,6 +277,10 @@ func (s *Server) CreateService(ctx context.Context, request *api.CreateServiceRe |
| 259 | 259 |
return nil, err |
| 260 | 260 |
} |
| 261 | 261 |
|
| 262 |
+ if err := s.validateNetworks(request.Spec.Networks); err != nil {
|
|
| 263 |
+ return nil, err |
|
| 264 |
+ } |
|
| 265 |
+ |
|
| 262 | 266 |
if err := s.checkPortConflicts(request.Spec, ""); err != nil {
|
| 263 | 267 |
return nil, err |
| 264 | 268 |
} |
| ... | ... |
@@ -759,6 +759,7 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche |
| 759 | 759 |
initial api.AssignmentsMessage |
| 760 | 760 |
) |
| 761 | 761 |
tasksMap := make(map[string]*api.Task) |
| 762 |
+ tasksUsingSecret := make(map[string]map[string]struct{})
|
|
| 762 | 763 |
|
| 763 | 764 |
sendMessage := func(msg api.AssignmentsMessage, assignmentType api.AssignmentsMessage_Type) error {
|
| 764 | 765 |
sequence++ |
| ... | ... |
@@ -773,6 +774,45 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche |
| 773 | 773 |
return nil |
| 774 | 774 |
} |
| 775 | 775 |
|
| 776 |
+ // returns a slice of new secrets to send down |
|
| 777 |
+ addSecretsForTask := func(readTx store.ReadTx, t *api.Task) []*api.Secret {
|
|
| 778 |
+ container := t.Spec.GetContainer() |
|
| 779 |
+ if container == nil {
|
|
| 780 |
+ return nil |
|
| 781 |
+ } |
|
| 782 |
+ var newSecrets []*api.Secret |
|
| 783 |
+ for _, secretRef := range container.Secrets {
|
|
| 784 |
+ secretID := secretRef.SecretID |
|
| 785 |
+ log := log.WithFields(logrus.Fields{
|
|
| 786 |
+ "secret.id": secretID, |
|
| 787 |
+ "secret.name": secretRef.SecretName, |
|
| 788 |
+ }) |
|
| 789 |
+ |
|
| 790 |
+ if tasksUsingSecret[secretID] == nil {
|
|
| 791 |
+ tasksUsingSecret[secretID] = make(map[string]struct{})
|
|
| 792 |
+ |
|
| 793 |
+ secrets, err := store.FindSecrets(readTx, store.ByIDPrefix(secretID)) |
|
| 794 |
+ if err != nil {
|
|
| 795 |
+ log.WithError(err).Errorf("error retrieving secret")
|
|
| 796 |
+ continue |
|
| 797 |
+ } |
|
| 798 |
+ if len(secrets) != 1 {
|
|
| 799 |
+ log.Debugf("secret not found")
|
|
| 800 |
+ continue |
|
| 801 |
+ } |
|
| 802 |
+ |
|
| 803 |
+ // If the secret was found and there was one result |
|
| 804 |
+ // (there should never be more than one because of the |
|
| 805 |
+ // uniqueness constraint), add this secret to our |
|
| 806 |
+ // initial set that we send down. |
|
| 807 |
+ newSecrets = append(newSecrets, secrets[0]) |
|
| 808 |
+ } |
|
| 809 |
+ tasksUsingSecret[secretID][t.ID] = struct{}{}
|
|
| 810 |
+ } |
|
| 811 |
+ |
|
| 812 |
+ return newSecrets |
|
| 813 |
+ } |
|
| 814 |
+ |
|
| 776 | 815 |
// TODO(aaronl): Also send node secrets that should be exposed to |
| 777 | 816 |
// this node. |
| 778 | 817 |
nodeTasks, cancel, err := store.ViewAndWatch( |
| ... | ... |
@@ -794,7 +834,31 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche |
| 794 | 794 |
} |
| 795 | 795 |
|
| 796 | 796 |
tasksMap[t.ID] = t |
| 797 |
- initial.UpdateTasks = append(initial.UpdateTasks, t) |
|
| 797 |
+ taskChange := &api.AssignmentChange{
|
|
| 798 |
+ Assignment: &api.Assignment{
|
|
| 799 |
+ Item: &api.Assignment_Task{
|
|
| 800 |
+ Task: t, |
|
| 801 |
+ }, |
|
| 802 |
+ }, |
|
| 803 |
+ Action: api.AssignmentChange_AssignmentActionUpdate, |
|
| 804 |
+ } |
|
| 805 |
+ initial.Changes = append(initial.Changes, taskChange) |
|
| 806 |
+ // Only send secrets down if these tasks are in < RUNNING |
|
| 807 |
+ if t.Status.State <= api.TaskStateRunning {
|
|
| 808 |
+ newSecrets := addSecretsForTask(readTx, t) |
|
| 809 |
+ for _, secret := range newSecrets {
|
|
| 810 |
+ secretChange := &api.AssignmentChange{
|
|
| 811 |
+ Assignment: &api.Assignment{
|
|
| 812 |
+ Item: &api.Assignment_Secret{
|
|
| 813 |
+ Secret: secret, |
|
| 814 |
+ }, |
|
| 815 |
+ }, |
|
| 816 |
+ Action: api.AssignmentChange_AssignmentActionUpdate, |
|
| 817 |
+ } |
|
| 818 |
+ |
|
| 819 |
+ initial.Changes = append(initial.Changes, secretChange) |
|
| 820 |
+ } |
|
| 821 |
+ } |
|
| 798 | 822 |
} |
| 799 | 823 |
return nil |
| 800 | 824 |
}, |
| ... | ... |
@@ -802,6 +866,8 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche |
| 802 | 802 |
Checks: []state.TaskCheckFunc{state.TaskCheckNodeID}},
|
| 803 | 803 |
state.EventDeleteTask{Task: &api.Task{NodeID: nodeID},
|
| 804 | 804 |
Checks: []state.TaskCheckFunc{state.TaskCheckNodeID}},
|
| 805 |
+ state.EventUpdateSecret{},
|
|
| 806 |
+ state.EventDeleteSecret{},
|
|
| 805 | 807 |
) |
| 806 | 808 |
if err != nil {
|
| 807 | 809 |
return err |
| ... | ... |
@@ -825,7 +891,9 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche |
| 825 | 825 |
batchingTimer *time.Timer |
| 826 | 826 |
batchingTimeout <-chan time.Time |
| 827 | 827 |
updateTasks = make(map[string]*api.Task) |
| 828 |
+ updateSecrets = make(map[string]*api.Secret) |
|
| 828 | 829 |
removeTasks = make(map[string]struct{})
|
| 830 |
+ removeSecrets = make(map[string]struct{})
|
|
| 829 | 831 |
) |
| 830 | 832 |
|
| 831 | 833 |
oneModification := func() {
|
| ... | ... |
@@ -839,6 +907,28 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche |
| 839 | 839 |
} |
| 840 | 840 |
} |
| 841 | 841 |
|
| 842 |
+ // Release the secrets references from this task |
|
| 843 |
+ releaseSecretsForTask := func(t *api.Task) bool {
|
|
| 844 |
+ var modified bool |
|
| 845 |
+ container := t.Spec.GetContainer() |
|
| 846 |
+ if container == nil {
|
|
| 847 |
+ return modified |
|
| 848 |
+ } |
|
| 849 |
+ |
|
| 850 |
+ for _, secretRef := range container.Secrets {
|
|
| 851 |
+ secretID := secretRef.SecretID |
|
| 852 |
+ delete(tasksUsingSecret[secretID], t.ID) |
|
| 853 |
+ if len(tasksUsingSecret[secretID]) == 0 {
|
|
| 854 |
+ // No tasks are using the secret anymore |
|
| 855 |
+ delete(tasksUsingSecret, secretID) |
|
| 856 |
+ removeSecrets[secretID] = struct{}{}
|
|
| 857 |
+ modified = true |
|
| 858 |
+ } |
|
| 859 |
+ } |
|
| 860 |
+ |
|
| 861 |
+ return modified |
|
| 862 |
+ } |
|
| 863 |
+ |
|
| 842 | 864 |
// The batching loop waits for 50 ms after the most recent |
| 843 | 865 |
// change, or until modificationBatchLimit is reached. The |
| 844 | 866 |
// worst case latency is modificationBatchLimit * batchingWaitTime, |
| ... | ... |
@@ -867,15 +957,35 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche |
| 867 | 867 |
if equality.TasksEqualStable(oldTask, v.Task) && v.Task.Status.State > api.TaskStateAssigned {
|
| 868 | 868 |
// this update should not trigger a task change for the agent |
| 869 | 869 |
tasksMap[v.Task.ID] = v.Task |
| 870 |
+ // If this task got updated to a final state, let's release |
|
| 871 |
+ // the secrets that are being used by the task |
|
| 872 |
+ if v.Task.Status.State > api.TaskStateRunning {
|
|
| 873 |
+ // If releasing the secrets caused a secret to be |
|
| 874 |
+ // removed from an agent, mark one modification |
|
| 875 |
+ if releaseSecretsForTask(v.Task) {
|
|
| 876 |
+ oneModification() |
|
| 877 |
+ } |
|
| 878 |
+ } |
|
| 870 | 879 |
continue |
| 871 | 880 |
} |
| 881 |
+ } else if v.Task.Status.State <= api.TaskStateRunning {
|
|
| 882 |
+ // If this task wasn't part of the assignment set before, and it's <= RUNNING |
|
| 883 |
+ // add the secrets it references to the secrets assignment. |
|
| 884 |
+ // Task states > RUNNING are worker reported only, are never created in |
|
| 885 |
+ // a > RUNNING state. |
|
| 886 |
+ var newSecrets []*api.Secret |
|
| 887 |
+ d.store.View(func(readTx store.ReadTx) {
|
|
| 888 |
+ newSecrets = addSecretsForTask(readTx, v.Task) |
|
| 889 |
+ }) |
|
| 890 |
+ for _, secret := range newSecrets {
|
|
| 891 |
+ updateSecrets[secret.ID] = secret |
|
| 892 |
+ } |
|
| 872 | 893 |
} |
| 873 | 894 |
tasksMap[v.Task.ID] = v.Task |
| 874 | 895 |
updateTasks[v.Task.ID] = v.Task |
| 875 | 896 |
|
| 876 | 897 |
oneModification() |
| 877 | 898 |
case state.EventDeleteTask: |
| 878 |
- |
|
| 879 | 899 |
if _, exists := tasksMap[v.Task.ID]; !exists {
|
| 880 | 900 |
continue |
| 881 | 901 |
} |
| ... | ... |
@@ -884,7 +994,28 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche |
| 884 | 884 |
|
| 885 | 885 |
delete(tasksMap, v.Task.ID) |
| 886 | 886 |
|
| 887 |
+ // Release the secrets being used by this task |
|
| 888 |
+ // Ignoring the return here. We will always mark |
|
| 889 |
+ // this as a modification, since a task is being |
|
| 890 |
+ // removed. |
|
| 891 |
+ releaseSecretsForTask(v.Task) |
|
| 892 |
+ |
|
| 887 | 893 |
oneModification() |
| 894 |
+ // TODO(aaronl): For node secrets, we'll need to handle |
|
| 895 |
+ // EventCreateSecret. |
|
| 896 |
+ case state.EventUpdateSecret: |
|
| 897 |
+ if _, exists := tasksUsingSecret[v.Secret.ID]; !exists {
|
|
| 898 |
+ continue |
|
| 899 |
+ } |
|
| 900 |
+ log.Debugf("Secret %s (ID: %d) was updated though it was still referenced by one or more tasks",
|
|
| 901 |
+ v.Secret.Spec.Annotations.Name, v.Secret.ID) |
|
| 902 |
+ |
|
| 903 |
+ case state.EventDeleteSecret: |
|
| 904 |
+ if _, exists := tasksUsingSecret[v.Secret.ID]; !exists {
|
|
| 905 |
+ continue |
|
| 906 |
+ } |
|
| 907 |
+ log.Debugf("Secret %s (ID: %d) was deleted though it was still referenced by one or more tasks",
|
|
| 908 |
+ v.Secret.Spec.Annotations.Name, v.Secret.ID) |
|
| 888 | 909 |
} |
| 889 | 910 |
case <-batchingTimeout: |
| 890 | 911 |
break batchingLoop |
| ... | ... |
@@ -902,12 +1033,57 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche |
| 902 | 902 |
if modificationCnt > 0 {
|
| 903 | 903 |
for id, task := range updateTasks {
|
| 904 | 904 |
if _, ok := removeTasks[id]; !ok {
|
| 905 |
- update.UpdateTasks = append(update.UpdateTasks, task) |
|
| 905 |
+ taskChange := &api.AssignmentChange{
|
|
| 906 |
+ Assignment: &api.Assignment{
|
|
| 907 |
+ Item: &api.Assignment_Task{
|
|
| 908 |
+ Task: task, |
|
| 909 |
+ }, |
|
| 910 |
+ }, |
|
| 911 |
+ Action: api.AssignmentChange_AssignmentActionUpdate, |
|
| 912 |
+ } |
|
| 913 |
+ |
|
| 914 |
+ update.Changes = append(update.Changes, taskChange) |
|
| 915 |
+ } |
|
| 916 |
+ } |
|
| 917 |
+ for id, secret := range updateSecrets {
|
|
| 918 |
+ if _, ok := removeSecrets[id]; !ok {
|
|
| 919 |
+ secretChange := &api.AssignmentChange{
|
|
| 920 |
+ Assignment: &api.Assignment{
|
|
| 921 |
+ Item: &api.Assignment_Secret{
|
|
| 922 |
+ Secret: secret, |
|
| 923 |
+ }, |
|
| 924 |
+ }, |
|
| 925 |
+ Action: api.AssignmentChange_AssignmentActionUpdate, |
|
| 926 |
+ } |
|
| 927 |
+ |
|
| 928 |
+ update.Changes = append(update.Changes, secretChange) |
|
| 906 | 929 |
} |
| 907 | 930 |
} |
| 908 | 931 |
for id := range removeTasks {
|
| 909 |
- update.RemoveTasks = append(update.RemoveTasks, id) |
|
| 932 |
+ taskChange := &api.AssignmentChange{
|
|
| 933 |
+ Assignment: &api.Assignment{
|
|
| 934 |
+ Item: &api.Assignment_Task{
|
|
| 935 |
+ Task: &api.Task{ID: id},
|
|
| 936 |
+ }, |
|
| 937 |
+ }, |
|
| 938 |
+ Action: api.AssignmentChange_AssignmentActionRemove, |
|
| 939 |
+ } |
|
| 940 |
+ |
|
| 941 |
+ update.Changes = append(update.Changes, taskChange) |
|
| 910 | 942 |
} |
| 943 |
+ for id := range removeSecrets {
|
|
| 944 |
+ secretChange := &api.AssignmentChange{
|
|
| 945 |
+ Assignment: &api.Assignment{
|
|
| 946 |
+ Item: &api.Assignment_Secret{
|
|
| 947 |
+ Secret: &api.Secret{ID: id},
|
|
| 948 |
+ }, |
|
| 949 |
+ }, |
|
| 950 |
+ Action: api.AssignmentChange_AssignmentActionRemove, |
|
| 951 |
+ } |
|
| 952 |
+ |
|
| 953 |
+ update.Changes = append(update.Changes, secretChange) |
|
| 954 |
+ } |
|
| 955 |
+ |
|
| 911 | 956 |
if err := sendMessage(update, api.AssignmentsMessage_INCREMENTAL); err != nil {
|
| 912 | 957 |
return err |
| 913 | 958 |
} |
| ... | ... |
@@ -184,6 +184,10 @@ func New(config *Config) (*Manager, error) {
|
| 184 | 184 |
} else if err != nil {
|
| 185 | 185 |
return nil, err |
| 186 | 186 |
} |
| 187 |
+ if proto == "tcp" {
|
|
| 188 |
+ // in case of 0 port |
|
| 189 |
+ tcpAddr = l.Addr().String() |
|
| 190 |
+ } |
|
| 187 | 191 |
listeners[proto] = l |
| 188 | 192 |
} |
| 189 | 193 |
} |
| ... | ... |
@@ -197,7 +201,7 @@ func New(config *Config) (*Manager, error) {
|
| 197 | 197 |
raftCfg.HeartbeatTick = int(config.HeartbeatTick) |
| 198 | 198 |
} |
| 199 | 199 |
|
| 200 |
- newNodeOpts := raft.NewNodeOptions{
|
|
| 200 |
+ newNodeOpts := raft.NodeOptions{
|
|
| 201 | 201 |
ID: config.SecurityConfig.ClientTLSCreds.NodeID(), |
| 202 | 202 |
Addr: tcpAddr, |
| 203 | 203 |
JoinAddr: config.JoinRaft, |
| ... | ... |
@@ -226,6 +230,14 @@ func New(config *Config) (*Manager, error) {
|
| 226 | 226 |
return m, nil |
| 227 | 227 |
} |
| 228 | 228 |
|
| 229 |
+// Addr returns tcp address on which remote api listens. |
|
| 230 |
+func (m *Manager) Addr() net.Addr {
|
|
| 231 |
+ if l, ok := m.listeners["tcp"]; ok {
|
|
| 232 |
+ return l.Addr() |
|
| 233 |
+ } |
|
| 234 |
+ return nil |
|
| 235 |
+} |
|
| 236 |
+ |
|
| 229 | 237 |
// Run starts all manager sub-systems and the gRPC server at the configured |
| 230 | 238 |
// address. |
| 231 | 239 |
// The call never returns unless an error occurs or `Stop()` is called. |
| ... | ... |
@@ -3,19 +3,27 @@ package orchestrator |
| 3 | 3 |
import ( |
| 4 | 4 |
"github.com/docker/swarmkit/api" |
| 5 | 5 |
"github.com/docker/swarmkit/log" |
| 6 |
+ "github.com/docker/swarmkit/manager/constraint" |
|
| 6 | 7 |
"github.com/docker/swarmkit/manager/state" |
| 7 | 8 |
"github.com/docker/swarmkit/manager/state/store" |
| 8 | 9 |
"golang.org/x/net/context" |
| 9 | 10 |
) |
| 10 | 11 |
|
| 12 |
+type globalService struct {
|
|
| 13 |
+ *api.Service |
|
| 14 |
+ |
|
| 15 |
+ // Compiled constraints |
|
| 16 |
+ constraints []constraint.Constraint |
|
| 17 |
+} |
|
| 18 |
+ |
|
| 11 | 19 |
// GlobalOrchestrator runs a reconciliation loop to create and destroy |
| 12 | 20 |
// tasks as necessary for global services. |
| 13 | 21 |
type GlobalOrchestrator struct {
|
| 14 | 22 |
store *store.MemoryStore |
| 15 |
- // nodes contains nodeID of all valid nodes in the cluster |
|
| 16 |
- nodes map[string]struct{}
|
|
| 17 |
- // globalServices have all the global services in the cluster, indexed by ServiceID |
|
| 18 |
- globalServices map[string]*api.Service |
|
| 23 |
+ // nodes is the set of non-drained nodes in the cluster, indexed by node ID |
|
| 24 |
+ nodes map[string]*api.Node |
|
| 25 |
+ // globalServices has all the global services in the cluster, indexed by ServiceID |
|
| 26 |
+ globalServices map[string]globalService |
|
| 19 | 27 |
|
| 20 | 28 |
// stopChan signals to the state machine to stop running. |
| 21 | 29 |
stopChan chan struct{}
|
| ... | ... |
@@ -34,8 +42,8 @@ func NewGlobalOrchestrator(store *store.MemoryStore) *GlobalOrchestrator {
|
| 34 | 34 |
updater := NewUpdateSupervisor(store, restartSupervisor) |
| 35 | 35 |
return &GlobalOrchestrator{
|
| 36 | 36 |
store: store, |
| 37 |
- nodes: make(map[string]struct{}),
|
|
| 38 |
- globalServices: make(map[string]*api.Service), |
|
| 37 |
+ nodes: make(map[string]*api.Node), |
|
| 38 |
+ globalServices: make(map[string]globalService), |
|
| 39 | 39 |
stopChan: make(chan struct{}),
|
| 40 | 40 |
doneChan: make(chan struct{}),
|
| 41 | 41 |
updater: updater, |
| ... | ... |
@@ -76,10 +84,7 @@ func (g *GlobalOrchestrator) Run(ctx context.Context) error {
|
| 76 | 76 |
return err |
| 77 | 77 |
} |
| 78 | 78 |
for _, n := range nodes {
|
| 79 |
- // if a node is in drain state, do not add it |
|
| 80 |
- if isValidNode(n) {
|
|
| 81 |
- g.nodes[n.ID] = struct{}{}
|
|
| 82 |
- } |
|
| 79 |
+ g.updateNode(n) |
|
| 83 | 80 |
} |
| 84 | 81 |
|
| 85 | 82 |
// Lookup global services |
| ... | ... |
@@ -90,12 +95,15 @@ func (g *GlobalOrchestrator) Run(ctx context.Context) error {
|
| 90 | 90 |
if err != nil {
|
| 91 | 91 |
return err |
| 92 | 92 |
} |
| 93 |
+ |
|
| 94 |
+ var reconcileServiceIDs []string |
|
| 93 | 95 |
for _, s := range existingServices {
|
| 94 | 96 |
if isGlobalService(s) {
|
| 95 |
- g.globalServices[s.ID] = s |
|
| 96 |
- g.reconcileOneService(ctx, s) |
|
| 97 |
+ g.updateService(s) |
|
| 98 |
+ reconcileServiceIDs = append(reconcileServiceIDs, s.ID) |
|
| 97 | 99 |
} |
| 98 | 100 |
} |
| 101 |
+ g.reconcileServices(ctx, reconcileServiceIDs) |
|
| 99 | 102 |
|
| 100 | 103 |
for {
|
| 101 | 104 |
select {
|
| ... | ... |
@@ -108,14 +116,14 @@ func (g *GlobalOrchestrator) Run(ctx context.Context) error {
|
| 108 | 108 |
if !isGlobalService(v.Service) {
|
| 109 | 109 |
continue |
| 110 | 110 |
} |
| 111 |
- g.globalServices[v.Service.ID] = v.Service |
|
| 112 |
- g.reconcileOneService(ctx, v.Service) |
|
| 111 |
+ g.updateService(v.Service) |
|
| 112 |
+ g.reconcileServices(ctx, []string{v.Service.ID})
|
|
| 113 | 113 |
case state.EventUpdateService: |
| 114 | 114 |
if !isGlobalService(v.Service) {
|
| 115 | 115 |
continue |
| 116 | 116 |
} |
| 117 |
- g.globalServices[v.Service.ID] = v.Service |
|
| 118 |
- g.reconcileOneService(ctx, v.Service) |
|
| 117 |
+ g.updateService(v.Service) |
|
| 118 |
+ g.reconcileServices(ctx, []string{v.Service.ID})
|
|
| 119 | 119 |
case state.EventDeleteService: |
| 120 | 120 |
if !isGlobalService(v.Service) {
|
| 121 | 121 |
continue |
| ... | ... |
@@ -125,8 +133,10 @@ func (g *GlobalOrchestrator) Run(ctx context.Context) error {
|
| 125 | 125 |
delete(g.globalServices, v.Service.ID) |
| 126 | 126 |
g.restarts.ClearServiceHistory(v.Service.ID) |
| 127 | 127 |
case state.EventCreateNode: |
| 128 |
+ g.updateNode(v.Node) |
|
| 128 | 129 |
g.reconcileOneNode(ctx, v.Node) |
| 129 | 130 |
case state.EventUpdateNode: |
| 131 |
+ g.updateNode(v.Node) |
|
| 130 | 132 |
switch v.Node.Status.State {
|
| 131 | 133 |
// NodeStatus_DISCONNECTED is a transient state, no need to make any change |
| 132 | 134 |
case api.NodeStatus_DOWN: |
| ... | ... |
@@ -153,7 +163,7 @@ func (g *GlobalOrchestrator) Run(ctx context.Context) error {
|
| 153 | 153 |
if _, exists := g.globalServices[v.Task.ServiceID]; !exists {
|
| 154 | 154 |
continue |
| 155 | 155 |
} |
| 156 |
- g.reconcileServiceOneNode(ctx, v.Task.ServiceID, v.Task.NodeID) |
|
| 156 |
+ g.reconcileServicesOneNode(ctx, []string{v.Task.ServiceID}, v.Task.NodeID)
|
|
| 157 | 157 |
} |
| 158 | 158 |
case <-g.stopChan: |
| 159 | 159 |
return nil |
| ... | ... |
@@ -196,138 +206,225 @@ func (g *GlobalOrchestrator) removeTasksFromNode(ctx context.Context, node *api. |
| 196 | 196 |
} |
| 197 | 197 |
} |
| 198 | 198 |
|
| 199 |
-func (g *GlobalOrchestrator) reconcileOneService(ctx context.Context, service *api.Service) {
|
|
| 200 |
- var ( |
|
| 201 |
- tasks []*api.Task |
|
| 202 |
- err error |
|
| 203 |
- ) |
|
| 199 |
+func (g *GlobalOrchestrator) reconcileServices(ctx context.Context, serviceIDs []string) {
|
|
| 200 |
+ nodeCompleted := make(map[string]map[string]struct{})
|
|
| 201 |
+ nodeTasks := make(map[string]map[string][]*api.Task) |
|
| 202 |
+ |
|
| 204 | 203 |
g.store.View(func(tx store.ReadTx) {
|
| 205 |
- tasks, err = store.FindTasks(tx, store.ByServiceID(service.ID)) |
|
| 206 |
- }) |
|
| 207 |
- if err != nil {
|
|
| 208 |
- log.G(ctx).WithError(err).Errorf("global orchestrator: reconcileOneService failed finding tasks")
|
|
| 209 |
- return |
|
| 210 |
- } |
|
| 211 |
- // a node may have completed this service |
|
| 212 |
- nodeCompleted := make(map[string]struct{})
|
|
| 213 |
- // nodeID -> task list |
|
| 214 |
- nodeTasks := make(map[string][]*api.Task) |
|
| 204 |
+ for _, serviceID := range serviceIDs {
|
|
| 205 |
+ tasks, err := store.FindTasks(tx, store.ByServiceID(serviceID)) |
|
| 206 |
+ if err != nil {
|
|
| 207 |
+ log.G(ctx).WithError(err).Errorf("global orchestrator: reconcileServices failed finding tasks for service %s", serviceID)
|
|
| 208 |
+ continue |
|
| 209 |
+ } |
|
| 215 | 210 |
|
| 216 |
- for _, t := range tasks {
|
|
| 217 |
- if isTaskRunning(t) {
|
|
| 218 |
- // Collect all running instances of this service |
|
| 219 |
- nodeTasks[t.NodeID] = append(nodeTasks[t.NodeID], t) |
|
| 220 |
- } else {
|
|
| 221 |
- // for finished tasks, check restartPolicy |
|
| 222 |
- if isTaskCompleted(t, restartCondition(t)) {
|
|
| 223 |
- nodeCompleted[t.NodeID] = struct{}{}
|
|
| 211 |
+ // a node may have completed this service |
|
| 212 |
+ nodeCompleted[serviceID] = make(map[string]struct{})
|
|
| 213 |
+ // nodeID -> task list |
|
| 214 |
+ nodeTasks[serviceID] = make(map[string][]*api.Task) |
|
| 215 |
+ |
|
| 216 |
+ for _, t := range tasks {
|
|
| 217 |
+ if isTaskRunning(t) {
|
|
| 218 |
+ // Collect all running instances of this service |
|
| 219 |
+ nodeTasks[serviceID][t.NodeID] = append(nodeTasks[serviceID][t.NodeID], t) |
|
| 220 |
+ } else {
|
|
| 221 |
+ // for finished tasks, check restartPolicy |
|
| 222 |
+ if isTaskCompleted(t, restartCondition(t)) {
|
|
| 223 |
+ nodeCompleted[serviceID][t.NodeID] = struct{}{}
|
|
| 224 |
+ } |
|
| 225 |
+ } |
|
| 224 | 226 |
} |
| 225 | 227 |
} |
| 226 |
- } |
|
| 228 |
+ }) |
|
| 227 | 229 |
|
| 228 |
- _, err = g.store.Batch(func(batch *store.Batch) error {
|
|
| 230 |
+ _, err := g.store.Batch(func(batch *store.Batch) error {
|
|
| 229 | 231 |
var updateTasks []slot |
| 230 |
- for nodeID := range g.nodes {
|
|
| 231 |
- ntasks := nodeTasks[nodeID] |
|
| 232 |
- // if restart policy considers this node has finished its task |
|
| 233 |
- // it should remove all running tasks |
|
| 234 |
- if _, exists := nodeCompleted[nodeID]; exists {
|
|
| 235 |
- g.removeTasks(ctx, batch, service, ntasks) |
|
| 236 |
- return nil |
|
| 232 |
+ for _, serviceID := range serviceIDs {
|
|
| 233 |
+ if _, exists := nodeTasks[serviceID]; !exists {
|
|
| 234 |
+ continue |
|
| 237 | 235 |
} |
| 238 |
- // this node needs to run 1 copy of the task |
|
| 239 |
- if len(ntasks) == 0 {
|
|
| 240 |
- g.addTask(ctx, batch, service, nodeID) |
|
| 241 |
- } else {
|
|
| 242 |
- updateTasks = append(updateTasks, ntasks) |
|
| 236 |
+ |
|
| 237 |
+ service := g.globalServices[serviceID] |
|
| 238 |
+ |
|
| 239 |
+ for nodeID, node := range g.nodes {
|
|
| 240 |
+ meetsConstraints := constraint.NodeMatches(service.constraints, node) |
|
| 241 |
+ ntasks := nodeTasks[serviceID][nodeID] |
|
| 242 |
+ delete(nodeTasks[serviceID], nodeID) |
|
| 243 |
+ |
|
| 244 |
+ // if restart policy considers this node has finished its task |
|
| 245 |
+ // it should remove all running tasks |
|
| 246 |
+ if _, exists := nodeCompleted[serviceID][nodeID]; exists || !meetsConstraints {
|
|
| 247 |
+ g.removeTasks(ctx, batch, ntasks) |
|
| 248 |
+ continue |
|
| 249 |
+ } |
|
| 250 |
+ |
|
| 251 |
+ if node.Spec.Availability == api.NodeAvailabilityPause {
|
|
| 252 |
+ // the node is paused, so we won't add or update |
|
| 253 |
+ // any tasks |
|
| 254 |
+ continue |
|
| 255 |
+ } |
|
| 256 |
+ |
|
| 257 |
+ // this node needs to run 1 copy of the task |
|
| 258 |
+ if len(ntasks) == 0 {
|
|
| 259 |
+ g.addTask(ctx, batch, service.Service, nodeID) |
|
| 260 |
+ } else {
|
|
| 261 |
+ updateTasks = append(updateTasks, ntasks) |
|
| 262 |
+ } |
|
| 263 |
+ } |
|
| 264 |
+ if len(updateTasks) > 0 {
|
|
| 265 |
+ g.updater.Update(ctx, g.cluster, service.Service, updateTasks) |
|
| 266 |
+ } |
|
| 267 |
+ |
|
| 268 |
+ // Remove any tasks assigned to nodes not found in g.nodes. |
|
| 269 |
+ // These must be associated with nodes that are drained, or |
|
| 270 |
+ // nodes that no longer exist. |
|
| 271 |
+ for _, ntasks := range nodeTasks[serviceID] {
|
|
| 272 |
+ g.removeTasks(ctx, batch, ntasks) |
|
| 243 | 273 |
} |
| 244 |
- } |
|
| 245 |
- if len(updateTasks) > 0 {
|
|
| 246 |
- g.updater.Update(ctx, g.cluster, service, updateTasks) |
|
| 247 | 274 |
} |
| 248 | 275 |
return nil |
| 249 | 276 |
}) |
| 250 | 277 |
if err != nil {
|
| 251 |
- log.G(ctx).WithError(err).Errorf("global orchestrator: reconcileOneService transaction failed")
|
|
| 278 |
+ log.G(ctx).WithError(err).Errorf("global orchestrator: reconcileServices transaction failed")
|
|
| 279 |
+ } |
|
| 280 |
+} |
|
| 281 |
+ |
|
| 282 |
+// updateNode updates g.nodes based on the current node value |
|
| 283 |
+func (g *GlobalOrchestrator) updateNode(node *api.Node) {
|
|
| 284 |
+ if node.Spec.Availability == api.NodeAvailabilityDrain {
|
|
| 285 |
+ delete(g.nodes, node.ID) |
|
| 286 |
+ } else {
|
|
| 287 |
+ g.nodes[node.ID] = node |
|
| 288 |
+ } |
|
| 289 |
+} |
|
| 290 |
+ |
|
| 291 |
+// updateService updates g.globalServices based on the current service value |
|
| 292 |
+func (g *GlobalOrchestrator) updateService(service *api.Service) {
|
|
| 293 |
+ var constraints []constraint.Constraint |
|
| 294 |
+ |
|
| 295 |
+ if service.Spec.Task.Placement != nil && len(service.Spec.Task.Placement.Constraints) != 0 {
|
|
| 296 |
+ constraints, _ = constraint.Parse(service.Spec.Task.Placement.Constraints) |
|
| 297 |
+ } |
|
| 298 |
+ |
|
| 299 |
+ g.globalServices[service.ID] = globalService{
|
|
| 300 |
+ Service: service, |
|
| 301 |
+ constraints: constraints, |
|
| 252 | 302 |
} |
| 253 | 303 |
} |
| 254 | 304 |
|
| 255 | 305 |
// reconcileOneNode checks all global services on one node |
| 256 | 306 |
func (g *GlobalOrchestrator) reconcileOneNode(ctx context.Context, node *api.Node) {
|
| 257 |
- switch node.Spec.Availability {
|
|
| 258 |
- case api.NodeAvailabilityDrain: |
|
| 307 |
+ if node.Spec.Availability == api.NodeAvailabilityDrain {
|
|
| 259 | 308 |
log.G(ctx).Debugf("global orchestrator: node %s in drain state, removing tasks from it", node.ID)
|
| 260 | 309 |
g.removeTasksFromNode(ctx, node) |
| 261 |
- delete(g.nodes, node.ID) |
|
| 262 |
- return |
|
| 263 |
- case api.NodeAvailabilityActive: |
|
| 264 |
- if _, exists := g.nodes[node.ID]; !exists {
|
|
| 265 |
- log.G(ctx).Debugf("global orchestrator: node %s not in current node list, adding it", node.ID)
|
|
| 266 |
- g.nodes[node.ID] = struct{}{}
|
|
| 267 |
- } |
|
| 268 |
- default: |
|
| 269 |
- log.G(ctx).Debugf("global orchestrator: node %s in %s state, doing nothing", node.ID, node.Spec.Availability.String())
|
|
| 270 | 310 |
return |
| 271 | 311 |
} |
| 272 |
- // typically there are only a few global services on a node |
|
| 273 |
- // iterate through all of them one by one. If raft store visits become a concern, |
|
| 274 |
- // it can be optimized. |
|
| 275 |
- for _, service := range g.globalServices {
|
|
| 276 |
- g.reconcileServiceOneNode(ctx, service.ID, node.ID) |
|
| 312 |
+ |
|
| 313 |
+ var serviceIDs []string |
|
| 314 |
+ for id := range g.globalServices {
|
|
| 315 |
+ serviceIDs = append(serviceIDs, id) |
|
| 277 | 316 |
} |
| 317 |
+ g.reconcileServicesOneNode(ctx, serviceIDs, node.ID) |
|
| 278 | 318 |
} |
| 279 | 319 |
|
| 280 |
-// reconcileServiceOneNode checks one service on one node |
|
| 281 |
-func (g *GlobalOrchestrator) reconcileServiceOneNode(ctx context.Context, serviceID string, nodeID string) {
|
|
| 282 |
- _, exists := g.nodes[nodeID] |
|
| 283 |
- if !exists {
|
|
| 284 |
- return |
|
| 285 |
- } |
|
| 286 |
- service, exists := g.globalServices[serviceID] |
|
| 320 |
+// reconcileServicesOneNode checks the specified services on one node |
|
| 321 |
+func (g *GlobalOrchestrator) reconcileServicesOneNode(ctx context.Context, serviceIDs []string, nodeID string) {
|
|
| 322 |
+ node, exists := g.nodes[nodeID] |
|
| 287 | 323 |
if !exists {
|
| 288 | 324 |
return |
| 289 | 325 |
} |
| 290 |
- // the node has completed this servie |
|
| 291 |
- completed := false |
|
| 292 |
- // tasks for this node and service |
|
| 326 |
+ |
|
| 327 |
+ // whether each service has completed on the node |
|
| 328 |
+ completed := make(map[string]bool) |
|
| 329 |
+ // tasks by service |
|
| 330 |
+ tasks := make(map[string][]*api.Task) |
|
| 331 |
+ |
|
| 293 | 332 |
var ( |
| 294 |
- tasks []*api.Task |
|
| 295 |
- err error |
|
| 333 |
+ tasksOnNode []*api.Task |
|
| 334 |
+ err error |
|
| 296 | 335 |
) |
| 336 |
+ |
|
| 297 | 337 |
g.store.View(func(tx store.ReadTx) {
|
| 298 |
- var tasksOnNode []*api.Task |
|
| 299 | 338 |
tasksOnNode, err = store.FindTasks(tx, store.ByNodeID(nodeID)) |
| 300 |
- if err != nil {
|
|
| 301 |
- return |
|
| 302 |
- } |
|
| 339 |
+ }) |
|
| 340 |
+ if err != nil {
|
|
| 341 |
+ log.G(ctx).WithError(err).Errorf("global orchestrator: reconcile failed finding tasks on node %s", nodeID)
|
|
| 342 |
+ return |
|
| 343 |
+ } |
|
| 344 |
+ |
|
| 345 |
+ for _, serviceID := range serviceIDs {
|
|
| 303 | 346 |
for _, t := range tasksOnNode {
|
| 304 |
- // only interested in one service |
|
| 305 | 347 |
if t.ServiceID != serviceID {
|
| 306 | 348 |
continue |
| 307 | 349 |
} |
| 308 | 350 |
if isTaskRunning(t) {
|
| 309 |
- tasks = append(tasks, t) |
|
| 351 |
+ tasks[serviceID] = append(tasks[serviceID], t) |
|
| 310 | 352 |
} else {
|
| 311 | 353 |
if isTaskCompleted(t, restartCondition(t)) {
|
| 312 |
- completed = true |
|
| 354 |
+ completed[serviceID] = true |
|
| 313 | 355 |
} |
| 314 | 356 |
} |
| 315 | 357 |
} |
| 316 |
- }) |
|
| 317 |
- if err != nil {
|
|
| 318 |
- log.G(ctx).WithError(err).Errorf("global orchestrator: reconcile failed finding tasks")
|
|
| 319 |
- return |
|
| 320 | 358 |
} |
| 321 | 359 |
|
| 322 | 360 |
_, err = g.store.Batch(func(batch *store.Batch) error {
|
| 323 |
- // if restart policy considers this node has finished its task |
|
| 324 |
- // it should remove all running tasks |
|
| 325 |
- if completed {
|
|
| 326 |
- g.removeTasks(ctx, batch, service, tasks) |
|
| 327 |
- return nil |
|
| 328 |
- } |
|
| 329 |
- if len(tasks) == 0 {
|
|
| 330 |
- g.addTask(ctx, batch, service, nodeID) |
|
| 361 |
+ for _, serviceID := range serviceIDs {
|
|
| 362 |
+ service, exists := g.globalServices[serviceID] |
|
| 363 |
+ if !exists {
|
|
| 364 |
+ continue |
|
| 365 |
+ } |
|
| 366 |
+ |
|
| 367 |
+ meetsConstraints := constraint.NodeMatches(service.constraints, node) |
|
| 368 |
+ |
|
| 369 |
+ // if restart policy considers this node has finished its task |
|
| 370 |
+ // it should remove all running tasks |
|
| 371 |
+ if completed[serviceID] || !meetsConstraints {
|
|
| 372 |
+ g.removeTasks(ctx, batch, tasks[serviceID]) |
|
| 373 |
+ continue |
|
| 374 |
+ } |
|
| 375 |
+ |
|
| 376 |
+ if node.Spec.Availability == api.NodeAvailabilityPause {
|
|
| 377 |
+ // the node is paused, so we won't add or update tasks |
|
| 378 |
+ continue |
|
| 379 |
+ } |
|
| 380 |
+ |
|
| 381 |
+ if len(tasks) == 0 {
|
|
| 382 |
+ g.addTask(ctx, batch, service.Service, nodeID) |
|
| 383 |
+ } else {
|
|
| 384 |
+ // If task is out of date, update it. This can happen |
|
| 385 |
+ // on node reconciliation if, for example, we pause a |
|
| 386 |
+ // node, update the service, and then activate the node |
|
| 387 |
+ // later. |
|
| 388 |
+ |
|
| 389 |
+ // We don't use g.updater here for two reasons: |
|
| 390 |
+ // - This is not a rolling update. Since it was not |
|
| 391 |
+ // triggered directly by updating the service, it |
|
| 392 |
+ // should not observe the rolling update parameters |
|
| 393 |
+ // or show status in UpdateStatus. |
|
| 394 |
+ // - Calling Update cancels any current rolling updates |
|
| 395 |
+ // for the service, such as one triggered by service |
|
| 396 |
+ // reconciliation. |
|
| 397 |
+ |
|
| 398 |
+ var ( |
|
| 399 |
+ dirtyTasks []*api.Task |
|
| 400 |
+ cleanTasks []*api.Task |
|
| 401 |
+ ) |
|
| 402 |
+ |
|
| 403 |
+ for _, t := range tasks[serviceID] {
|
|
| 404 |
+ if isTaskDirty(service.Service, t) {
|
|
| 405 |
+ dirtyTasks = append(dirtyTasks, t) |
|
| 406 |
+ } else {
|
|
| 407 |
+ cleanTasks = append(cleanTasks, t) |
|
| 408 |
+ } |
|
| 409 |
+ } |
|
| 410 |
+ |
|
| 411 |
+ if len(cleanTasks) == 0 {
|
|
| 412 |
+ g.addTask(ctx, batch, service.Service, nodeID) |
|
| 413 |
+ } else {
|
|
| 414 |
+ dirtyTasks = append(dirtyTasks, cleanTasks[1:]...) |
|
| 415 |
+ } |
|
| 416 |
+ g.removeTasks(ctx, batch, dirtyTasks) |
|
| 417 |
+ } |
|
| 331 | 418 |
} |
| 332 | 419 |
return nil |
| 333 | 420 |
}) |
| ... | ... |
@@ -383,7 +480,7 @@ func (g *GlobalOrchestrator) addTask(ctx context.Context, batch *store.Batch, se |
| 383 | 383 |
} |
| 384 | 384 |
} |
| 385 | 385 |
|
| 386 |
-func (g *GlobalOrchestrator) removeTasks(ctx context.Context, batch *store.Batch, service *api.Service, tasks []*api.Task) {
|
|
| 386 |
+func (g *GlobalOrchestrator) removeTasks(ctx context.Context, batch *store.Batch, tasks []*api.Task) {
|
|
| 387 | 387 |
for _, t := range tasks {
|
| 388 | 388 |
g.removeTask(ctx, batch, t) |
| 389 | 389 |
} |
| ... | ... |
@@ -393,11 +490,6 @@ func isTaskRunning(t *api.Task) bool {
|
| 393 | 393 |
return t != nil && t.DesiredState <= api.TaskStateRunning && t.Status.State <= api.TaskStateRunning |
| 394 | 394 |
} |
| 395 | 395 |
|
| 396 |
-func isValidNode(n *api.Node) bool {
|
|
| 397 |
- // current simulation spec could be nil |
|
| 398 |
- return n != nil && n.Spec.Availability != api.NodeAvailabilityDrain |
|
| 399 |
-} |
|
| 400 |
- |
|
| 401 | 396 |
func isTaskCompleted(t *api.Task, restartPolicy api.RestartPolicy_RestartCondition) bool {
|
| 402 | 397 |
if t == nil || isTaskRunning(t) {
|
| 403 | 398 |
return false |
| ... | ... |
@@ -489,9 +489,13 @@ func (u *Updater) removeOldTasks(ctx context.Context, batch *store.Batch, remove |
| 489 | 489 |
return removedTask, nil |
| 490 | 490 |
} |
| 491 | 491 |
|
| 492 |
+func isTaskDirty(s *api.Service, t *api.Task) bool {
|
|
| 493 |
+ return !reflect.DeepEqual(s.Spec.Task, t.Spec) || |
|
| 494 |
+ (t.Endpoint != nil && !reflect.DeepEqual(s.Spec.Endpoint, t.Endpoint.Spec)) |
|
| 495 |
+} |
|
| 496 |
+ |
|
| 492 | 497 |
func (u *Updater) isTaskDirty(t *api.Task) bool {
|
| 493 |
- return !reflect.DeepEqual(u.newService.Spec.Task, t.Spec) || |
|
| 494 |
- (t.Endpoint != nil && !reflect.DeepEqual(u.newService.Spec.Endpoint, t.Endpoint.Spec)) |
|
| 498 |
+ return isTaskDirty(u.newService, t) |
|
| 495 | 499 |
} |
| 496 | 500 |
|
| 497 | 501 |
func (u *Updater) isSlotDirty(slot slot) bool {
|
| 498 | 502 |
deleted file mode 100644 |
| ... | ... |
@@ -1,97 +0,0 @@ |
| 1 |
-package scheduler |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "strings" |
|
| 5 |
- |
|
| 6 |
- "github.com/docker/swarmkit/api" |
|
| 7 |
-) |
|
| 8 |
- |
|
| 9 |
-const ( |
|
| 10 |
- nodeLabelPrefix = "node.labels." |
|
| 11 |
- engineLabelPrefix = "engine.labels." |
|
| 12 |
-) |
|
| 13 |
- |
|
| 14 |
-// ConstraintFilter selects only nodes that match certain labels. |
|
| 15 |
-type ConstraintFilter struct {
|
|
| 16 |
- constraints []Expr |
|
| 17 |
-} |
|
| 18 |
- |
|
| 19 |
-// SetTask returns true when the filter is enable for a given task. |
|
| 20 |
-func (f *ConstraintFilter) SetTask(t *api.Task) bool {
|
|
| 21 |
- if t.Spec.Placement == nil || len(t.Spec.Placement.Constraints) == 0 {
|
|
| 22 |
- return false |
|
| 23 |
- } |
|
| 24 |
- |
|
| 25 |
- constraints, err := ParseExprs(t.Spec.Placement.Constraints) |
|
| 26 |
- if err != nil {
|
|
| 27 |
- // constraints have been validated at controlapi |
|
| 28 |
- // if in any case it finds an error here, treat this task |
|
| 29 |
- // as constraint filter disabled. |
|
| 30 |
- return false |
|
| 31 |
- } |
|
| 32 |
- f.constraints = constraints |
|
| 33 |
- return true |
|
| 34 |
-} |
|
| 35 |
- |
|
| 36 |
-// Check returns true if the task's constraint is supported by the given node. |
|
| 37 |
-func (f *ConstraintFilter) Check(n *NodeInfo) bool {
|
|
| 38 |
- for _, constraint := range f.constraints {
|
|
| 39 |
- switch {
|
|
| 40 |
- case strings.EqualFold(constraint.Key, "node.id"): |
|
| 41 |
- if !constraint.Match(n.ID) {
|
|
| 42 |
- return false |
|
| 43 |
- } |
|
| 44 |
- case strings.EqualFold(constraint.Key, "node.hostname"): |
|
| 45 |
- // if this node doesn't have hostname |
|
| 46 |
- // it's equivalent to match an empty hostname |
|
| 47 |
- // where '==' would fail, '!=' matches |
|
| 48 |
- if n.Description == nil {
|
|
| 49 |
- if !constraint.Match("") {
|
|
| 50 |
- return false |
|
| 51 |
- } |
|
| 52 |
- continue |
|
| 53 |
- } |
|
| 54 |
- if !constraint.Match(n.Description.Hostname) {
|
|
| 55 |
- return false |
|
| 56 |
- } |
|
| 57 |
- case strings.EqualFold(constraint.Key, "node.role"): |
|
| 58 |
- if !constraint.Match(n.Spec.Role.String()) {
|
|
| 59 |
- return false |
|
| 60 |
- } |
|
| 61 |
- |
|
| 62 |
- // node labels constraint in form like 'node.labels.key==value' |
|
| 63 |
- case len(constraint.Key) > len(nodeLabelPrefix) && strings.EqualFold(constraint.Key[:len(nodeLabelPrefix)], nodeLabelPrefix): |
|
| 64 |
- if n.Spec.Annotations.Labels == nil {
|
|
| 65 |
- if !constraint.Match("") {
|
|
| 66 |
- return false |
|
| 67 |
- } |
|
| 68 |
- continue |
|
| 69 |
- } |
|
| 70 |
- label := constraint.Key[len(nodeLabelPrefix):] |
|
| 71 |
- // label itself is case sensitive |
|
| 72 |
- val := n.Spec.Annotations.Labels[label] |
|
| 73 |
- if !constraint.Match(val) {
|
|
| 74 |
- return false |
|
| 75 |
- } |
|
| 76 |
- |
|
| 77 |
- // engine labels constraint in form like 'engine.labels.key!=value' |
|
| 78 |
- case len(constraint.Key) > len(engineLabelPrefix) && strings.EqualFold(constraint.Key[:len(engineLabelPrefix)], engineLabelPrefix): |
|
| 79 |
- if n.Description == nil || n.Description.Engine == nil || n.Description.Engine.Labels == nil {
|
|
| 80 |
- if !constraint.Match("") {
|
|
| 81 |
- return false |
|
| 82 |
- } |
|
| 83 |
- continue |
|
| 84 |
- } |
|
| 85 |
- label := constraint.Key[len(engineLabelPrefix):] |
|
| 86 |
- val := n.Description.Engine.Labels[label] |
|
| 87 |
- if !constraint.Match(val) {
|
|
| 88 |
- return false |
|
| 89 |
- } |
|
| 90 |
- default: |
|
| 91 |
- // key doesn't match predefined syntax |
|
| 92 |
- return false |
|
| 93 |
- } |
|
| 94 |
- } |
|
| 95 |
- |
|
| 96 |
- return true |
|
| 97 |
-} |
| 98 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,96 +0,0 @@ |
| 1 |
-package scheduler |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "fmt" |
|
| 5 |
- "regexp" |
|
| 6 |
- "strings" |
|
| 7 |
-) |
|
| 8 |
- |
|
| 9 |
-const ( |
|
| 10 |
- eq = iota |
|
| 11 |
- noteq |
|
| 12 |
-) |
|
| 13 |
- |
|
| 14 |
-var ( |
|
| 15 |
- alphaNumeric = regexp.MustCompile(`^(?i)[a-z_][a-z0-9\-_.]+$`) |
|
| 16 |
- // value can be alphanumeric and some special characters. it shouldn't container |
|
| 17 |
- // current or future operators like '>, <, ~', etc. |
|
| 18 |
- valuePattern = regexp.MustCompile(`^(?i)[a-z0-9:\-_\s\.\*\(\)\?\+\[\]\\\^\$\|\/]+$`) |
|
| 19 |
- |
|
| 20 |
- // operators defines list of accepted operators |
|
| 21 |
- operators = []string{"==", "!="}
|
|
| 22 |
-) |
|
| 23 |
- |
|
| 24 |
-// Expr defines a constraint |
|
| 25 |
-type Expr struct {
|
|
| 26 |
- Key string |
|
| 27 |
- operator int |
|
| 28 |
- exp string |
|
| 29 |
-} |
|
| 30 |
- |
|
| 31 |
-// ParseExprs parses list of constraints into Expr list |
|
| 32 |
-func ParseExprs(env []string) ([]Expr, error) {
|
|
| 33 |
- exprs := []Expr{}
|
|
| 34 |
- for _, e := range env {
|
|
| 35 |
- found := false |
|
| 36 |
- // each expr is in the form of "key op value" |
|
| 37 |
- for i, op := range operators {
|
|
| 38 |
- if !strings.Contains(e, op) {
|
|
| 39 |
- continue |
|
| 40 |
- } |
|
| 41 |
- // split with the op |
|
| 42 |
- parts := strings.SplitN(e, op, 2) |
|
| 43 |
- |
|
| 44 |
- if len(parts) < 2 {
|
|
| 45 |
- return nil, fmt.Errorf("invalid expr: %s", e)
|
|
| 46 |
- } |
|
| 47 |
- |
|
| 48 |
- part0 := strings.TrimSpace(parts[0]) |
|
| 49 |
- // validate Key |
|
| 50 |
- matched := alphaNumeric.MatchString(part0) |
|
| 51 |
- if matched == false {
|
|
| 52 |
- return nil, fmt.Errorf("key '%s' is invalid", part0)
|
|
| 53 |
- } |
|
| 54 |
- |
|
| 55 |
- part1 := strings.TrimSpace(parts[1]) |
|
| 56 |
- |
|
| 57 |
- // validate Value |
|
| 58 |
- matched = valuePattern.MatchString(part1) |
|
| 59 |
- if matched == false {
|
|
| 60 |
- return nil, fmt.Errorf("value '%s' is invalid", part1)
|
|
| 61 |
- } |
|
| 62 |
- // TODO(dongluochen): revisit requirements to see if globing or regex are useful |
|
| 63 |
- exprs = append(exprs, Expr{Key: part0, operator: i, exp: part1})
|
|
| 64 |
- |
|
| 65 |
- found = true |
|
| 66 |
- break // found an op, move to next entry |
|
| 67 |
- } |
|
| 68 |
- if !found {
|
|
| 69 |
- return nil, fmt.Errorf("constraint expected one operator from %s", strings.Join(operators, ", "))
|
|
| 70 |
- } |
|
| 71 |
- } |
|
| 72 |
- return exprs, nil |
|
| 73 |
-} |
|
| 74 |
- |
|
| 75 |
-// Match checks if the Expr matches the target strings. |
|
| 76 |
-func (e *Expr) Match(whats ...string) bool {
|
|
| 77 |
- var match bool |
|
| 78 |
- |
|
| 79 |
- // full string match |
|
| 80 |
- for _, what := range whats {
|
|
| 81 |
- // case insensitive compare |
|
| 82 |
- if strings.EqualFold(e.exp, what) {
|
|
| 83 |
- match = true |
|
| 84 |
- break |
|
| 85 |
- } |
|
| 86 |
- } |
|
| 87 |
- |
|
| 88 |
- switch e.operator {
|
|
| 89 |
- case eq: |
|
| 90 |
- return match |
|
| 91 |
- case noteq: |
|
| 92 |
- return !match |
|
| 93 |
- } |
|
| 94 |
- |
|
| 95 |
- return false |
|
| 96 |
-} |
| ... | ... |
@@ -1,6 +1,9 @@ |
| 1 | 1 |
package scheduler |
| 2 | 2 |
|
| 3 |
-import "github.com/docker/swarmkit/api" |
|
| 3 |
+import ( |
|
| 4 |
+ "github.com/docker/swarmkit/api" |
|
| 5 |
+ "github.com/docker/swarmkit/manager/constraint" |
|
| 6 |
+) |
|
| 4 | 7 |
|
| 5 | 8 |
// Filter checks whether the given task can run on the given node. |
| 6 | 9 |
// A filter may only operate |
| ... | ... |
@@ -129,3 +132,30 @@ func (f *PluginFilter) pluginExistsOnNode(pluginType string, pluginName string, |
| 129 | 129 |
} |
| 130 | 130 |
return false |
| 131 | 131 |
} |
| 132 |
+ |
|
| 133 |
+// ConstraintFilter selects only nodes that match certain labels. |
|
| 134 |
+type ConstraintFilter struct {
|
|
| 135 |
+ constraints []constraint.Constraint |
|
| 136 |
+} |
|
| 137 |
+ |
|
| 138 |
+// SetTask returns true when the filter is enable for a given task. |
|
| 139 |
+func (f *ConstraintFilter) SetTask(t *api.Task) bool {
|
|
| 140 |
+ if t.Spec.Placement == nil || len(t.Spec.Placement.Constraints) == 0 {
|
|
| 141 |
+ return false |
|
| 142 |
+ } |
|
| 143 |
+ |
|
| 144 |
+ constraints, err := constraint.Parse(t.Spec.Placement.Constraints) |
|
| 145 |
+ if err != nil {
|
|
| 146 |
+ // constraints have been validated at controlapi |
|
| 147 |
+ // if in any case it finds an error here, treat this task |
|
| 148 |
+ // as constraint filter disabled. |
|
| 149 |
+ return false |
|
| 150 |
+ } |
|
| 151 |
+ f.constraints = constraints |
|
| 152 |
+ return true |
|
| 153 |
+} |
|
| 154 |
+ |
|
| 155 |
+// Check returns true if the task's constraint is supported by the given node. |
|
| 156 |
+func (f *ConstraintFilter) Check(n *NodeInfo) bool {
|
|
| 157 |
+ return constraint.NodeMatches(f.constraints, n.Node) |
|
| 158 |
+} |
| ... | ... |
@@ -27,11 +27,19 @@ var ( |
| 27 | 27 |
ErrCannotUnmarshalConfig = errors.New("membership: cannot unmarshal configuration change")
|
| 28 | 28 |
) |
| 29 | 29 |
|
| 30 |
+// deferredConn used to store removed members connection for some time. |
|
| 31 |
+// We need this in case if removed node is redirector or endpoint of ControlAPI call. |
|
| 32 |
+type deferredConn struct {
|
|
| 33 |
+ tick int |
|
| 34 |
+ conn *grpc.ClientConn |
|
| 35 |
+} |
|
| 36 |
+ |
|
| 30 | 37 |
// Cluster represents a set of active |
| 31 | 38 |
// raft Members |
| 32 | 39 |
type Cluster struct {
|
| 33 |
- mu sync.RWMutex |
|
| 34 |
- members map[uint64]*Member |
|
| 40 |
+ mu sync.RWMutex |
|
| 41 |
+ members map[uint64]*Member |
|
| 42 |
+ deferedConns map[*deferredConn]struct{}
|
|
| 35 | 43 |
|
| 36 | 44 |
// removed contains the list of removed Members, |
| 37 | 45 |
// those ids cannot be reused |
| ... | ... |
@@ -73,16 +81,13 @@ func NewCluster(heartbeatTicks int) *Cluster {
|
| 73 | 73 |
return &Cluster{
|
| 74 | 74 |
members: make(map[uint64]*Member), |
| 75 | 75 |
removed: make(map[uint64]bool), |
| 76 |
+ deferedConns: make(map[*deferredConn]struct{}),
|
|
| 76 | 77 |
heartbeatTicks: heartbeatTicks, |
| 77 | 78 |
PeersBroadcast: watch.NewQueue(), |
| 78 | 79 |
} |
| 79 | 80 |
} |
| 80 | 81 |
|
| 81 |
-// Tick increases ticks for all members. After heartbeatTicks node marked as |
|
| 82 |
-// inactive. |
|
| 83 |
-func (c *Cluster) Tick() {
|
|
| 84 |
- c.mu.Lock() |
|
| 85 |
- defer c.mu.Unlock() |
|
| 82 |
+func (c *Cluster) handleInactive() {
|
|
| 86 | 83 |
for _, m := range c.members {
|
| 87 | 84 |
if !m.active {
|
| 88 | 85 |
continue |
| ... | ... |
@@ -97,6 +102,25 @@ func (c *Cluster) Tick() {
|
| 97 | 97 |
} |
| 98 | 98 |
} |
| 99 | 99 |
|
| 100 |
+func (c *Cluster) handleDeferredConns() {
|
|
| 101 |
+ for dc := range c.deferedConns {
|
|
| 102 |
+ dc.tick++ |
|
| 103 |
+ if dc.tick > c.heartbeatTicks {
|
|
| 104 |
+ dc.conn.Close() |
|
| 105 |
+ delete(c.deferedConns, dc) |
|
| 106 |
+ } |
|
| 107 |
+ } |
|
| 108 |
+} |
|
| 109 |
+ |
|
| 110 |
+// Tick increases ticks for all members. After heartbeatTicks node marked as |
|
| 111 |
+// inactive. |
|
| 112 |
+func (c *Cluster) Tick() {
|
|
| 113 |
+ c.mu.Lock() |
|
| 114 |
+ defer c.mu.Unlock() |
|
| 115 |
+ c.handleInactive() |
|
| 116 |
+ c.handleDeferredConns() |
|
| 117 |
+} |
|
| 118 |
+ |
|
| 100 | 119 |
// Members returns the list of raft Members in the Cluster. |
| 101 | 120 |
func (c *Cluster) Members() map[uint64]*Member {
|
| 102 | 121 |
members := make(map[uint64]*Member) |
| ... | ... |
@@ -177,7 +201,9 @@ func (c *Cluster) clearMember(id uint64) error {
|
| 177 | 177 |
m, ok := c.members[id] |
| 178 | 178 |
if ok {
|
| 179 | 179 |
if m.Conn != nil {
|
| 180 |
- m.Conn.Close() |
|
| 180 |
+ // defer connection close to after heartbeatTicks |
|
| 181 |
+ dConn := &deferredConn{conn: m.Conn}
|
|
| 182 |
+ c.deferedConns[dConn] = struct{}{}
|
|
| 181 | 183 |
} |
| 182 | 184 |
delete(c.members, id) |
| 183 | 185 |
} |
| ... | ... |
@@ -232,8 +258,13 @@ func (c *Cluster) Clear() {
|
| 232 | 232 |
} |
| 233 | 233 |
} |
| 234 | 234 |
|
| 235 |
+ for dc := range c.deferedConns {
|
|
| 236 |
+ dc.conn.Close() |
|
| 237 |
+ } |
|
| 238 |
+ |
|
| 235 | 239 |
c.members = make(map[uint64]*Member) |
| 236 | 240 |
c.removed = make(map[uint64]bool) |
| 241 |
+ c.deferedConns = make(map[*deferredConn]struct{})
|
|
| 237 | 242 |
c.mu.Unlock() |
| 238 | 243 |
} |
| 239 | 244 |
|
| ... | ... |
@@ -78,29 +78,24 @@ const ( |
| 78 | 78 |
// Node represents the Raft Node useful |
| 79 | 79 |
// configuration. |
| 80 | 80 |
type Node struct {
|
| 81 |
- raft.Node |
|
| 82 |
- cluster *membership.Cluster |
|
| 81 |
+ raftNode raft.Node |
|
| 82 |
+ cluster *membership.Cluster |
|
| 83 | 83 |
|
| 84 |
- Server *grpc.Server |
|
| 85 |
- Ctx context.Context |
|
| 86 |
- cancel func() |
|
| 87 |
- tlsCredentials credentials.TransportCredentials |
|
| 88 |
- |
|
| 89 |
- Address string |
|
| 90 |
- StateDir string |
|
| 84 |
+ Server *grpc.Server |
|
| 85 |
+ Ctx context.Context |
|
| 86 |
+ cancel func() |
|
| 91 | 87 |
|
| 92 | 88 |
raftStore *raft.MemoryStorage |
| 93 | 89 |
memoryStore *store.MemoryStore |
| 94 | 90 |
Config *raft.Config |
| 95 |
- opts NewNodeOptions |
|
| 91 |
+ opts NodeOptions |
|
| 96 | 92 |
reqIDGen *idutil.Generator |
| 97 | 93 |
wait *wait |
| 98 | 94 |
wal *wal.WAL |
| 99 | 95 |
snapshotter *snap.Snapshotter |
| 100 |
- restored bool |
|
| 96 |
+ campaignWhenAble bool |
|
| 101 | 97 |
signalledLeadership uint32 |
| 102 | 98 |
isMember uint32 |
| 103 |
- joinAddr string |
|
| 104 | 99 |
|
| 105 | 100 |
// waitProp waits for all the proposals to be terminated before |
| 106 | 101 |
// shutting down the node. |
| ... | ... |
@@ -110,10 +105,9 @@ type Node struct {
|
| 110 | 110 |
appliedIndex uint64 |
| 111 | 111 |
snapshotIndex uint64 |
| 112 | 112 |
|
| 113 |
- ticker clock.Ticker |
|
| 114 |
- sendTimeout time.Duration |
|
| 115 |
- stopCh chan struct{}
|
|
| 116 |
- doneCh chan struct{}
|
|
| 113 |
+ ticker clock.Ticker |
|
| 114 |
+ stopCh chan struct{}
|
|
| 115 |
+ doneCh chan struct{}
|
|
| 117 | 116 |
// removeRaftCh notifies about node deletion from raft cluster |
| 118 | 117 |
removeRaftCh chan struct{}
|
| 119 | 118 |
removeRaftFunc func() |
| ... | ... |
@@ -129,8 +123,8 @@ type Node struct {
|
| 129 | 129 |
asyncTasks sync.WaitGroup |
| 130 | 130 |
} |
| 131 | 131 |
|
| 132 |
-// NewNodeOptions provides arguments for NewNode |
|
| 133 |
-type NewNodeOptions struct {
|
|
| 132 |
+// NodeOptions provides node-level options. |
|
| 133 |
+type NodeOptions struct {
|
|
| 134 | 134 |
// ID is the node's ID, from its certificate's CN field. |
| 135 | 135 |
ID string |
| 136 | 136 |
// Addr is the address of this node's listener |
| ... | ... |
@@ -161,8 +155,8 @@ func init() {
|
| 161 | 161 |
rand.Seed(time.Now().UnixNano()) |
| 162 | 162 |
} |
| 163 | 163 |
|
| 164 |
-// NewNode generates a new Raft node |
|
| 165 |
-func NewNode(ctx context.Context, opts NewNodeOptions) *Node {
|
|
| 164 |
+// NewNode generates a new Raft node. |
|
| 165 |
+func NewNode(ctx context.Context, opts NodeOptions) *Node {
|
|
| 166 | 166 |
cfg := opts.Config |
| 167 | 167 |
if cfg == nil {
|
| 168 | 168 |
cfg = DefaultNodeConfig() |
| ... | ... |
@@ -170,19 +164,20 @@ func NewNode(ctx context.Context, opts NewNodeOptions) *Node {
|
| 170 | 170 |
if opts.TickInterval == 0 {
|
| 171 | 171 |
opts.TickInterval = time.Second |
| 172 | 172 |
} |
| 173 |
+ if opts.SendTimeout == 0 {
|
|
| 174 |
+ opts.SendTimeout = 2 * time.Second |
|
| 175 |
+ } |
|
| 173 | 176 |
|
| 174 | 177 |
raftStore := raft.NewMemoryStorage() |
| 175 | 178 |
|
| 176 | 179 |
ctx, cancel := context.WithCancel(ctx) |
| 177 | 180 |
|
| 178 | 181 |
n := &Node{
|
| 179 |
- Ctx: ctx, |
|
| 180 |
- cancel: cancel, |
|
| 181 |
- cluster: membership.NewCluster(2 * cfg.ElectionTick), |
|
| 182 |
- tlsCredentials: opts.TLSCredentials, |
|
| 183 |
- raftStore: raftStore, |
|
| 184 |
- Address: opts.Addr, |
|
| 185 |
- opts: opts, |
|
| 182 |
+ Ctx: ctx, |
|
| 183 |
+ cancel: cancel, |
|
| 184 |
+ cluster: membership.NewCluster(2 * cfg.ElectionTick), |
|
| 185 |
+ raftStore: raftStore, |
|
| 186 |
+ opts: opts, |
|
| 186 | 187 |
Config: &raft.Config{
|
| 187 | 188 |
ElectionTick: cfg.ElectionTick, |
| 188 | 189 |
HeartbeatTick: cfg.HeartbeatTick, |
| ... | ... |
@@ -194,9 +189,6 @@ func NewNode(ctx context.Context, opts NewNodeOptions) *Node {
|
| 194 | 194 |
stopCh: make(chan struct{}),
|
| 195 | 195 |
doneCh: make(chan struct{}),
|
| 196 | 196 |
removeRaftCh: make(chan struct{}),
|
| 197 |
- StateDir: opts.StateDir, |
|
| 198 |
- joinAddr: opts.JoinAddr, |
|
| 199 |
- sendTimeout: 2 * time.Second, |
|
| 200 | 197 |
leadershipBroadcast: watch.NewQueue(), |
| 201 | 198 |
} |
| 202 | 199 |
n.memoryStore = store.NewMemoryStore(n) |
| ... | ... |
@@ -206,9 +198,6 @@ func NewNode(ctx context.Context, opts NewNodeOptions) *Node {
|
| 206 | 206 |
} else {
|
| 207 | 207 |
n.ticker = opts.ClockSource.NewTicker(opts.TickInterval) |
| 208 | 208 |
} |
| 209 |
- if opts.SendTimeout != 0 {
|
|
| 210 |
- n.sendTimeout = opts.SendTimeout |
|
| 211 |
- } |
|
| 212 | 209 |
|
| 213 | 210 |
n.reqIDGen = idutil.NewGenerator(uint16(n.Config.ID), time.Now()) |
| 214 | 211 |
n.wait = newWait() |
| ... | ... |
@@ -249,8 +238,8 @@ func (n *Node) JoinAndStart() (err error) {
|
| 249 | 249 |
n.snapshotIndex = snapshot.Metadata.Index |
| 250 | 250 |
|
| 251 | 251 |
if loadAndStartErr == errNoWAL {
|
| 252 |
- if n.joinAddr != "" {
|
|
| 253 |
- c, err := n.ConnectToMember(n.joinAddr, 10*time.Second) |
|
| 252 |
+ if n.opts.JoinAddr != "" {
|
|
| 253 |
+ c, err := n.ConnectToMember(n.opts.JoinAddr, 10*time.Second) |
|
| 254 | 254 |
if err != nil {
|
| 255 | 255 |
return err |
| 256 | 256 |
} |
| ... | ... |
@@ -262,7 +251,7 @@ func (n *Node) JoinAndStart() (err error) {
|
| 262 | 262 |
ctx, cancel := context.WithTimeout(n.Ctx, 10*time.Second) |
| 263 | 263 |
defer cancel() |
| 264 | 264 |
resp, err := client.Join(ctx, &api.JoinRequest{
|
| 265 |
- Addr: n.Address, |
|
| 265 |
+ Addr: n.opts.Addr, |
|
| 266 | 266 |
}) |
| 267 | 267 |
if err != nil {
|
| 268 | 268 |
return err |
| ... | ... |
@@ -274,7 +263,7 @@ func (n *Node) JoinAndStart() (err error) {
|
| 274 | 274 |
return err |
| 275 | 275 |
} |
| 276 | 276 |
|
| 277 |
- n.Node = raft.StartNode(n.Config, []raft.Peer{})
|
|
| 277 |
+ n.raftNode = raft.StartNode(n.Config, []raft.Peer{})
|
|
| 278 | 278 |
|
| 279 | 279 |
if err := n.registerNodes(resp.Members); err != nil {
|
| 280 | 280 |
if walErr := n.wal.Close(); err != nil {
|
| ... | ... |
@@ -289,22 +278,18 @@ func (n *Node) JoinAndStart() (err error) {
|
| 289 | 289 |
if err != nil {
|
| 290 | 290 |
return err |
| 291 | 291 |
} |
| 292 |
- n.Node = raft.StartNode(n.Config, []raft.Peer{peer})
|
|
| 293 |
- if err := n.Campaign(n.Ctx); err != nil {
|
|
| 294 |
- if walErr := n.wal.Close(); err != nil {
|
|
| 295 |
- n.Config.Logger.Errorf("raft: error closing WAL: %v", walErr)
|
|
| 296 |
- } |
|
| 297 |
- return err |
|
| 298 |
- } |
|
| 292 |
+ n.raftNode = raft.StartNode(n.Config, []raft.Peer{peer})
|
|
| 293 |
+ n.campaignWhenAble = true |
|
| 299 | 294 |
} |
| 300 | 295 |
atomic.StoreUint32(&n.isMember, 1) |
| 301 | 296 |
return nil |
| 302 | 297 |
} |
| 303 | 298 |
|
| 304 |
- if n.joinAddr != "" {
|
|
| 299 |
+ if n.opts.JoinAddr != "" {
|
|
| 305 | 300 |
n.Config.Logger.Warning("ignoring request to join cluster, because raft state already exists")
|
| 306 | 301 |
} |
| 307 |
- n.Node = raft.RestartNode(n.Config) |
|
| 302 |
+ n.campaignWhenAble = true |
|
| 303 |
+ n.raftNode = raft.RestartNode(n.Config) |
|
| 308 | 304 |
atomic.StoreUint32(&n.isMember, 1) |
| 309 | 305 |
return nil |
| 310 | 306 |
} |
| ... | ... |
@@ -362,9 +347,9 @@ func (n *Node) Run(ctx context.Context) error {
|
| 362 | 362 |
for {
|
| 363 | 363 |
select {
|
| 364 | 364 |
case <-n.ticker.C(): |
| 365 |
- n.Tick() |
|
| 365 |
+ n.raftNode.Tick() |
|
| 366 | 366 |
n.cluster.Tick() |
| 367 |
- case rd := <-n.Ready(): |
|
| 367 |
+ case rd := <-n.raftNode.Ready(): |
|
| 368 | 368 |
raftConfig := DefaultRaftConfig() |
| 369 | 369 |
n.memoryStore.View(func(readTx store.ReadTx) {
|
| 370 | 370 |
clusters, err := store.FindClusters(readTx, store.ByName(store.DefaultClusterName)) |
| ... | ... |
@@ -457,19 +442,21 @@ func (n *Node) Run(ctx context.Context) error {
|
| 457 | 457 |
} |
| 458 | 458 |
|
| 459 | 459 |
// Advance the state machine |
| 460 |
- n.Advance() |
|
| 461 |
- |
|
| 462 |
- // If we are the only registered member after |
|
| 463 |
- // restoring from the state, campaign to be the |
|
| 464 |
- // leader. |
|
| 465 |
- if !n.restored {
|
|
| 466 |
- // Node ID should be in the progress list to Campaign |
|
| 467 |
- if len(n.cluster.Members()) <= 1 {
|
|
| 468 |
- if err := n.Campaign(n.Ctx); err != nil {
|
|
| 460 |
+ n.raftNode.Advance() |
|
| 461 |
+ |
|
| 462 |
+ // On the first startup, or if we are the only |
|
| 463 |
+ // registered member after restoring from the state, |
|
| 464 |
+ // campaign to be the leader. |
|
| 465 |
+ if n.campaignWhenAble {
|
|
| 466 |
+ members := n.cluster.Members() |
|
| 467 |
+ if len(members) >= 1 {
|
|
| 468 |
+ n.campaignWhenAble = false |
|
| 469 |
+ } |
|
| 470 |
+ if len(members) == 1 && members[n.Config.ID] != nil {
|
|
| 471 |
+ if err := n.raftNode.Campaign(n.Ctx); err != nil {
|
|
| 469 | 472 |
panic("raft: cannot campaign to be the leader on node restore")
|
| 470 | 473 |
} |
| 471 | 474 |
} |
| 472 |
- n.restored = true |
|
| 473 | 475 |
} |
| 474 | 476 |
|
| 475 | 477 |
case snapshotIndex := <-n.snapshotInProgress: |
| ... | ... |
@@ -517,7 +504,7 @@ func (n *Node) stop() {
|
| 517 | 517 |
n.waitProp.Wait() |
| 518 | 518 |
n.asyncTasks.Wait() |
| 519 | 519 |
|
| 520 |
- n.Stop() |
|
| 520 |
+ n.raftNode.Stop() |
|
| 521 | 521 |
n.ticker.Stop() |
| 522 | 522 |
if err := n.wal.Close(); err != nil {
|
| 523 | 523 |
n.Config.Logger.Errorf("raft: error closing WAL: %v", err)
|
| ... | ... |
@@ -532,7 +519,7 @@ func (n *Node) isLeader() bool {
|
| 532 | 532 |
return false |
| 533 | 533 |
} |
| 534 | 534 |
|
| 535 |
- if n.Node.Status().Lead == n.Config.ID {
|
|
| 535 |
+ if n.Status().Lead == n.Config.ID {
|
|
| 536 | 536 |
return true |
| 537 | 537 |
} |
| 538 | 538 |
return false |
| ... | ... |
@@ -549,7 +536,7 @@ func (n *Node) IsLeader() bool {
|
| 549 | 549 |
// leader returns the id of the leader, without the protection of lock and |
| 550 | 550 |
// membership check, so it's caller task. |
| 551 | 551 |
func (n *Node) leader() uint64 {
|
| 552 |
- return n.Node.Status().Lead |
|
| 552 |
+ return n.Status().Lead |
|
| 553 | 553 |
} |
| 554 | 554 |
|
| 555 | 555 |
// Leader returns the id of the leader, with the protection of lock |
| ... | ... |
@@ -859,7 +846,7 @@ func (n *Node) ProcessRaftMessage(ctx context.Context, msg *api.ProcessRaftMessa |
| 859 | 859 |
return nil, ErrNoRaftMember |
| 860 | 860 |
} |
| 861 | 861 |
|
| 862 |
- if err := n.Step(n.Ctx, *msg.Message); err != nil {
|
|
| 862 |
+ if err := n.raftNode.Step(n.Ctx, *msg.Message); err != nil {
|
|
| 863 | 863 |
return nil, err |
| 864 | 864 |
} |
| 865 | 865 |
|
| ... | ... |
@@ -988,6 +975,7 @@ func (n *Node) registerNode(node *api.RaftMember) error {
|
| 988 | 988 |
} |
| 989 | 989 |
return err |
| 990 | 990 |
} |
| 991 |
+ |
|
| 991 | 992 |
return nil |
| 992 | 993 |
} |
| 993 | 994 |
|
| ... | ... |
@@ -1021,7 +1009,7 @@ func (n *Node) GetVersion() *api.Version {
|
| 1021 | 1021 |
return nil |
| 1022 | 1022 |
} |
| 1023 | 1023 |
|
| 1024 |
- status := n.Node.Status() |
|
| 1024 |
+ status := n.Status() |
|
| 1025 | 1025 |
return &api.Version{Index: status.Commit}
|
| 1026 | 1026 |
} |
| 1027 | 1027 |
|
| ... | ... |
@@ -1068,6 +1056,11 @@ func (n *Node) GetMemberlist() map[uint64]*api.RaftMember {
|
| 1068 | 1068 |
return memberlist |
| 1069 | 1069 |
} |
| 1070 | 1070 |
|
| 1071 |
+// Status returns status of underlying etcd.Node. |
|
| 1072 |
+func (n *Node) Status() raft.Status {
|
|
| 1073 |
+ return n.raftNode.Status() |
|
| 1074 |
+} |
|
| 1075 |
+ |
|
| 1071 | 1076 |
// GetMemberByNodeID returns member information based |
| 1072 | 1077 |
// on its generic Node ID. |
| 1073 | 1078 |
func (n *Node) GetMemberByNodeID(nodeID string) *membership.Member {
|
| ... | ... |
@@ -1131,7 +1124,7 @@ func (n *Node) send(messages []raftpb.Message) error {
|
| 1131 | 1131 |
for _, m := range messages {
|
| 1132 | 1132 |
// Process locally |
| 1133 | 1133 |
if m.To == n.Config.ID {
|
| 1134 |
- if err := n.Step(n.Ctx, m); err != nil {
|
|
| 1134 |
+ if err := n.raftNode.Step(n.Ctx, m); err != nil {
|
|
| 1135 | 1135 |
return err |
| 1136 | 1136 |
} |
| 1137 | 1137 |
continue |
| ... | ... |
@@ -1160,7 +1153,7 @@ func (n *Node) sendToMember(members map[uint64]*membership.Member, m raftpb.Mess |
| 1160 | 1160 |
return |
| 1161 | 1161 |
} |
| 1162 | 1162 |
|
| 1163 |
- ctx, cancel := context.WithTimeout(n.Ctx, n.sendTimeout) |
|
| 1163 |
+ ctx, cancel := context.WithTimeout(n.Ctx, n.opts.SendTimeout) |
|
| 1164 | 1164 |
defer cancel() |
| 1165 | 1165 |
|
| 1166 | 1166 |
var ( |
| ... | ... |
@@ -1195,7 +1188,7 @@ func (n *Node) sendToMember(members map[uint64]*membership.Member, m raftpb.Mess |
| 1195 | 1195 |
n.Config.Logger.Errorf("could not resolve address of member ID %x: %v", m.To, err)
|
| 1196 | 1196 |
return |
| 1197 | 1197 |
} |
| 1198 |
- conn, err = n.ConnectToMember(resp.Addr, n.sendTimeout) |
|
| 1198 |
+ conn, err = n.ConnectToMember(resp.Addr, n.opts.SendTimeout) |
|
| 1199 | 1199 |
if err != nil {
|
| 1200 | 1200 |
n.Config.Logger.Errorf("could connect to member ID %x at %s: %v", m.To, resp.Addr, err)
|
| 1201 | 1201 |
return |
| ... | ... |
@@ -1212,13 +1205,13 @@ func (n *Node) sendToMember(members map[uint64]*membership.Member, m raftpb.Mess |
| 1212 | 1212 |
n.removeRaftFunc() |
| 1213 | 1213 |
} |
| 1214 | 1214 |
if m.Type == raftpb.MsgSnap {
|
| 1215 |
- n.ReportSnapshot(m.To, raft.SnapshotFailure) |
|
| 1215 |
+ n.raftNode.ReportSnapshot(m.To, raft.SnapshotFailure) |
|
| 1216 | 1216 |
} |
| 1217 | 1217 |
if !n.IsMember() {
|
| 1218 | 1218 |
// node is removed from cluster or stopped |
| 1219 | 1219 |
return |
| 1220 | 1220 |
} |
| 1221 |
- n.ReportUnreachable(m.To) |
|
| 1221 |
+ n.raftNode.ReportUnreachable(m.To) |
|
| 1222 | 1222 |
|
| 1223 | 1223 |
lastSeenHost := n.cluster.LastSeenHost(m.To) |
| 1224 | 1224 |
if lastSeenHost != "" {
|
| ... | ... |
@@ -1246,7 +1239,7 @@ func (n *Node) sendToMember(members map[uint64]*membership.Member, m raftpb.Mess |
| 1246 | 1246 |
newConn.Conn.Close() |
| 1247 | 1247 |
} |
| 1248 | 1248 |
} else if m.Type == raftpb.MsgSnap {
|
| 1249 |
- n.ReportSnapshot(m.To, raft.SnapshotFinish) |
|
| 1249 |
+ n.raftNode.ReportSnapshot(m.To, raft.SnapshotFinish) |
|
| 1250 | 1250 |
} |
| 1251 | 1251 |
} |
| 1252 | 1252 |
|
| ... | ... |
@@ -1323,7 +1316,7 @@ func (n *Node) processInternalRaftRequest(ctx context.Context, r *api.InternalRa |
| 1323 | 1323 |
return nil, ErrRequestTooLarge |
| 1324 | 1324 |
} |
| 1325 | 1325 |
|
| 1326 |
- err = n.Propose(waitCtx, data) |
|
| 1326 |
+ err = n.raftNode.Propose(waitCtx, data) |
|
| 1327 | 1327 |
if err != nil {
|
| 1328 | 1328 |
n.wait.cancel(r.ID) |
| 1329 | 1329 |
return nil, err |
| ... | ... |
@@ -1351,7 +1344,7 @@ func (n *Node) configure(ctx context.Context, cc raftpb.ConfChange) error {
|
| 1351 | 1351 |
ctx, cancel := context.WithCancel(ctx) |
| 1352 | 1352 |
ch := n.wait.register(cc.ID, nil, cancel) |
| 1353 | 1353 |
|
| 1354 |
- if err := n.ProposeConfChange(ctx, cc); err != nil {
|
|
| 1354 |
+ if err := n.raftNode.ProposeConfChange(ctx, cc); err != nil {
|
|
| 1355 | 1355 |
n.wait.cancel(cc.ID) |
| 1356 | 1356 |
return err |
| 1357 | 1357 |
} |
| ... | ... |
@@ -1449,7 +1442,7 @@ func (n *Node) processConfChange(entry raftpb.Entry) {
|
| 1449 | 1449 |
n.wait.trigger(cc.ID, err) |
| 1450 | 1450 |
} |
| 1451 | 1451 |
|
| 1452 |
- n.confState = *n.ApplyConfChange(cc) |
|
| 1452 |
+ n.confState = *n.raftNode.ApplyConfChange(cc) |
|
| 1453 | 1453 |
n.wait.trigger(cc.ID, nil) |
| 1454 | 1454 |
} |
| 1455 | 1455 |
|
| ... | ... |
@@ -1520,7 +1513,7 @@ func (n *Node) applyRemoveNode(cc raftpb.ConfChange) (err error) {
|
| 1520 | 1520 |
// to be the leader. |
| 1521 | 1521 |
|
| 1522 | 1522 |
if cc.NodeID == n.leader() && !n.isLeader() {
|
| 1523 |
- if err = n.Campaign(n.Ctx); err != nil {
|
|
| 1523 |
+ if err = n.raftNode.Campaign(n.Ctx); err != nil {
|
|
| 1524 | 1524 |
return err |
| 1525 | 1525 |
} |
| 1526 | 1526 |
} |
| ... | ... |
@@ -1548,7 +1541,7 @@ func (n *Node) applyRemoveNode(cc raftpb.ConfChange) (err error) {
|
| 1548 | 1548 |
// ConnectToMember returns a member object with an initialized |
| 1549 | 1549 |
// connection to communicate with other raft members |
| 1550 | 1550 |
func (n *Node) ConnectToMember(addr string, timeout time.Duration) (*membership.Member, error) {
|
| 1551 |
- conn, err := dial(addr, "tcp", n.tlsCredentials, timeout) |
|
| 1551 |
+ conn, err := dial(addr, "tcp", n.opts.TLSCredentials, timeout) |
|
| 1552 | 1552 |
if err != nil {
|
| 1553 | 1553 |
return nil, err |
| 1554 | 1554 |
} |
| ... | ... |
@@ -26,19 +26,19 @@ import ( |
| 26 | 26 |
var errNoWAL = errors.New("no WAL present")
|
| 27 | 27 |
|
| 28 | 28 |
func (n *Node) legacyWALDir() string {
|
| 29 |
- return filepath.Join(n.StateDir, "wal") |
|
| 29 |
+ return filepath.Join(n.opts.StateDir, "wal") |
|
| 30 | 30 |
} |
| 31 | 31 |
|
| 32 | 32 |
func (n *Node) walDir() string {
|
| 33 |
- return filepath.Join(n.StateDir, "wal-v3") |
|
| 33 |
+ return filepath.Join(n.opts.StateDir, "wal-v3") |
|
| 34 | 34 |
} |
| 35 | 35 |
|
| 36 | 36 |
func (n *Node) legacySnapDir() string {
|
| 37 |
- return filepath.Join(n.StateDir, "snap") |
|
| 37 |
+ return filepath.Join(n.opts.StateDir, "snap") |
|
| 38 | 38 |
} |
| 39 | 39 |
|
| 40 | 40 |
func (n *Node) snapDir() string {
|
| 41 |
- return filepath.Join(n.StateDir, "snap-v3") |
|
| 41 |
+ return filepath.Join(n.opts.StateDir, "snap-v3") |
|
| 42 | 42 |
} |
| 43 | 43 |
|
| 44 | 44 |
func (n *Node) loadAndStart(ctx context.Context, forceNewCluster bool) error {
|
| ... | ... |
@@ -189,7 +189,7 @@ func (n *Node) createWAL(nodeID string) (raft.Peer, error) {
|
| 189 | 189 |
raftNode := &api.RaftMember{
|
| 190 | 190 |
RaftID: n.Config.ID, |
| 191 | 191 |
NodeID: nodeID, |
| 192 |
- Addr: n.Address, |
|
| 192 |
+ Addr: n.opts.Addr, |
|
| 193 | 193 |
} |
| 194 | 194 |
metadata, err := raftNode.Marshal() |
| 195 | 195 |
if err != nil {
|
| ... | ... |
@@ -207,7 +207,7 @@ func (n *Node) createWAL(nodeID string) (raft.Peer, error) {
|
| 207 | 207 |
// moveWALAndSnap moves away the WAL and snapshot because we were removed |
| 208 | 208 |
// from the cluster and will need to recreate them if we are readded. |
| 209 | 209 |
func (n *Node) moveWALAndSnap() error {
|
| 210 |
- newWALDir, err := ioutil.TempDir(n.StateDir, "wal.") |
|
| 210 |
+ newWALDir, err := ioutil.TempDir(n.opts.StateDir, "wal.") |
|
| 211 | 211 |
if err != nil {
|
| 212 | 212 |
return err |
| 213 | 213 |
} |
| ... | ... |
@@ -216,7 +216,7 @@ func (n *Node) moveWALAndSnap() error {
|
| 216 | 216 |
return err |
| 217 | 217 |
} |
| 218 | 218 |
|
| 219 |
- newSnapDir, err := ioutil.TempDir(n.StateDir, "snap.") |
|
| 219 |
+ newSnapDir, err := ioutil.TempDir(n.opts.StateDir, "snap.") |
|
| 220 | 220 |
if err != nil {
|
| 221 | 221 |
return err |
| 222 | 222 |
} |