diff --git a/command/agent/agent.go b/command/agent/agent.go index fc4104e544..ed92061029 100644 --- a/command/agent/agent.go +++ b/command/agent/agent.go @@ -38,6 +38,9 @@ const ( "but no reason was provided. This is a default message." defaultServiceMaintReason = "Maintenance mode is enabled for this " + "service, but no reason was provided. This is a default message." + + // An interval used to send network coordinates to servers + syncCoordinateStaggerIntv = 15 * time.Second ) var ( @@ -557,19 +560,38 @@ func (a *Agent) ResumeSync() { a.state.Resume() } -// SendCoordinates starts a goroutine that periodically sends the local coordinate +// SendCoordinates starts a loop that periodically sends the local coordinate // to a server -func (a *Agent) SendCoordinates() { - var c coordinate.Coordinate - if a.config.Server { - c = a.server - } - req := structs.CoordinateUpdateRequest{ - NodeSpecificRequest: NodeSpecificRequest{ - Datacenter: a.config.Datacenter, - Node: a.config.NodeName, - }, - QueryOptions: structs.QueryOptions{Token: a.config.ACLToken}, +func (a *Agent) SendCoordinates(shutdownCh chan struct{}) { + for { + intv := aeScale(a.config.SyncCoordinateInterval, len(a.LANMembers())) + intv = intv + randomStagger(intv) + timer := time.After(intv) + select { + case <-timer: + var c coordinate.Coordinate + if a.config.Server { + c = a.server.GetLANCoordinate() + } else { + c = a.client.GetCoordinate() + } + req := structs.CoordinateUpdateRequest{ + NodeSpecificRequest: NodeSpecificRequest{ + Datacenter: a.config.Datacenter, + Node: a.config.NodeName, + }, + Op: structs.CoordinateSet, + Coord: c, + QueryOptions: structs.QueryOptions{Token: a.config.ACLToken}, + } + + var reply struct{} + if err := a.RPC("Coordinate.Update", &arg, &reply); err != nil { + a.logger.Printf("[ERR] coordinate update error: %s", err.Error()) + } + case <-shutdownCh: + return + } } } diff --git a/command/agent/command.go b/command/agent/command.go index 2d642b20e3..69bc9233dd 100644 --- a/command/agent/command.go +++ b/command/agent/command.go @@ -709,6 +709,9 @@ func (c *Command) Run(args []string) int { errWanCh := make(chan struct{}) go c.retryJoinWan(config, errWanCh) + // Start sending network coordinates to servers + go c.agent.SendCoordinates(c.agent.shutdownCh) + // Wait for exit return c.handleSignals(config, errCh, errWanCh) } diff --git a/command/agent/config.go b/command/agent/config.go index 7941b2997e..7e19b0ff1a 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -372,6 +372,10 @@ type Config struct { // representation of our state. Defaults to every 60s. AEInterval time.Duration `mapstructure:"-" json:"-"` + // SyncCoordinateInterval controls the interval for sending network coordinates + // to servers. + SyncCoordinateInterval time.Duration `mapstructure:"-" json:"-"` + // Checks holds the provided check definitions Checks []*CheckDefinition `mapstructure:"-" json:"-"` @@ -466,6 +470,7 @@ func DefaultConfig() *Config { Protocol: consul.ProtocolVersionMax, CheckUpdateInterval: 5 * time.Minute, AEInterval: time.Minute, + SyncCoordinateInterval: 15 * time.Second, ACLTTL: 30 * time.Second, ACLDownPolicy: "extend-cache", ACLDefaultPolicy: "allow", diff --git a/consul/client.go b/consul/client.go index abd27cd2da..9c1b12fdb4 100644 --- a/consul/client.go +++ b/consul/client.go @@ -12,6 +12,7 @@ import ( "time" "github.com/hashicorp/consul/consul/structs" + "github.com/hashicorp/serf/coordinate" "github.com/hashicorp/serf/serf" ) @@ -376,3 +377,8 @@ func (c *Client) Stats() map[string]map[string]string { } return stats } + +// GetCoordinate returns the network coordinate of the receiver +func (c *Client) GetCoordinate() *coordinate.Coordinate { + return c.serf.GetCoordinate() +} diff --git a/consul/server.go b/consul/server.go index d992e0cfc1..b355b90763 100644 --- a/consul/server.go +++ b/consul/server.go @@ -19,6 +19,7 @@ import ( "github.com/hashicorp/consul/tlsutil" "github.com/hashicorp/raft" "github.com/hashicorp/raft-boltdb" + "github.com/hashicorp/serf/coordinate" "github.com/hashicorp/serf/serf" ) @@ -693,3 +694,8 @@ func (s *Server) Stats() map[string]map[string]string { } return stats } + +// GetLANCoordinate returns the network coordinate of the receiver +func (s *Server) GetLANCoordinate() *coordinate.Coordinate { + return s.serfLAN.GetCoordinate() +}