2013-12-19 22:48:14 +00:00
|
|
|
package consul
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2016-10-26 02:20:24 +00:00
|
|
|
"io"
|
2013-12-19 22:48:14 +00:00
|
|
|
"os"
|
2014-02-24 00:37:33 +00:00
|
|
|
"strconv"
|
2013-12-19 22:48:14 +00:00
|
|
|
"sync"
|
2018-06-11 19:51:17 +00:00
|
|
|
"sync/atomic"
|
2013-12-19 23:42:17 +00:00
|
|
|
"time"
|
2015-01-06 23:48:46 +00:00
|
|
|
|
2017-09-01 22:02:50 +00:00
|
|
|
"github.com/armon/go-metrics"
|
2017-06-15 13:16:16 +00:00
|
|
|
"github.com/hashicorp/consul/agent/pool"
|
2017-07-06 10:40:54 +00:00
|
|
|
"github.com/hashicorp/consul/agent/router"
|
2017-07-06 10:34:00 +00:00
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
2017-01-18 06:20:11 +00:00
|
|
|
"github.com/hashicorp/consul/lib"
|
2020-01-28 23:50:41 +00:00
|
|
|
"github.com/hashicorp/consul/logging"
|
2019-02-26 15:52:07 +00:00
|
|
|
"github.com/hashicorp/consul/tlsutil"
|
2020-01-28 23:50:41 +00:00
|
|
|
"github.com/hashicorp/go-hclog"
|
2015-01-06 23:48:46 +00:00
|
|
|
"github.com/hashicorp/serf/serf"
|
2017-09-01 22:02:50 +00:00
|
|
|
"golang.org/x/time/rate"
|
2013-12-19 22:48:14 +00:00
|
|
|
)
|
|
|
|
|
2014-05-27 21:33:09 +00:00
|
|
|
const (
|
2016-02-20 01:32:16 +00:00
|
|
|
// clientRPCConnMaxIdle controls how long we keep an idle connection
|
|
|
|
// open to a server. 127s was chosen as the first prime above 120s
|
|
|
|
// (arbitrarily chose to use a prime) with the intent of reusing
|
|
|
|
// connections who are used by once-a-minute cron(8) jobs *and* who
|
|
|
|
// use a 60s jitter window (e.g. in vixie cron job execution can
|
|
|
|
// drift by up to 59s per job, or 119s for a once-a-minute cron job).
|
|
|
|
clientRPCConnMaxIdle = 127 * time.Second
|
2014-05-27 21:33:09 +00:00
|
|
|
|
2015-09-15 12:22:08 +00:00
|
|
|
// clientMaxStreams controls how many idle streams we keep
|
2014-05-27 21:33:09 +00:00
|
|
|
// open to a server
|
|
|
|
clientMaxStreams = 32
|
2016-02-19 01:46:02 +00:00
|
|
|
|
|
|
|
// serfEventBacklog is the maximum number of unprocessed Serf Events
|
|
|
|
// that will be held in queue before new serf events block. A
|
|
|
|
// blocking serf event queue is a bad thing.
|
|
|
|
serfEventBacklog = 256
|
|
|
|
|
|
|
|
// serfEventBacklogWarning is the threshold at which point log
|
|
|
|
// warnings will be emitted indicating a problem when processing serf
|
|
|
|
// events.
|
|
|
|
serfEventBacklogWarning = 200
|
2014-02-03 19:53:04 +00:00
|
|
|
)
|
|
|
|
|
2013-12-19 22:48:14 +00:00
|
|
|
// Client is Consul client which uses RPC to communicate with the
|
|
|
|
// services for service discovery, health checking, and DC forwarding.
|
|
|
|
type Client struct {
|
|
|
|
config *Config
|
|
|
|
|
2018-10-19 16:04:07 +00:00
|
|
|
// acls is used to resolve tokens to effective policies
|
|
|
|
acls *ACLResolver
|
|
|
|
|
|
|
|
// DEPRECATED (ACL-Legacy-Compat) - Only needed while we support both
|
|
|
|
// useNewACLs is a flag to indicate whether we are using the new ACL system
|
|
|
|
useNewACLs int32
|
|
|
|
|
2013-12-19 22:48:14 +00:00
|
|
|
// Connection pool to consul servers
|
2017-06-15 13:16:16 +00:00
|
|
|
connPool *pool.ConnPool
|
2013-12-19 22:48:14 +00:00
|
|
|
|
2017-07-06 10:40:54 +00:00
|
|
|
// routers is responsible for the selection and maintenance of
|
2016-03-25 18:57:54 +00:00
|
|
|
// Consul servers this agent uses for RPC requests
|
2017-07-06 10:40:54 +00:00
|
|
|
routers *router.Manager
|
2013-12-19 22:48:14 +00:00
|
|
|
|
2017-09-01 22:02:50 +00:00
|
|
|
// rpcLimiter is used to rate limit the total number of RPCs initiated
|
|
|
|
// from an agent.
|
2018-06-11 19:51:17 +00:00
|
|
|
rpcLimiter atomic.Value
|
2017-09-01 22:02:50 +00:00
|
|
|
|
2013-12-19 22:48:14 +00:00
|
|
|
// eventCh is used to receive events from the
|
|
|
|
// serf cluster in the datacenter
|
|
|
|
eventCh chan serf.Event
|
|
|
|
|
|
|
|
// Logger uses the provided LogOutput
|
2020-01-28 23:50:41 +00:00
|
|
|
logger hclog.InterceptLogger
|
2013-12-19 22:48:14 +00:00
|
|
|
|
|
|
|
// serf is the Serf cluster maintained inside the DC
|
|
|
|
// which contains all the DC nodes
|
|
|
|
serf *serf.Serf
|
|
|
|
|
|
|
|
shutdown bool
|
|
|
|
shutdownCh chan struct{}
|
|
|
|
shutdownLock sync.Mutex
|
2018-05-24 14:36:42 +00:00
|
|
|
|
|
|
|
// embedded struct to hold all the enterprise specific data
|
|
|
|
EnterpriseClient
|
2019-06-27 20:22:07 +00:00
|
|
|
|
|
|
|
tlsConfigurator *tlsutil.Configurator
|
2013-12-19 22:48:14 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 09:29:06 +00:00
|
|
|
// NewClient is used to construct a new Consul client from the configuration,
|
|
|
|
// potentially returning an error.
|
|
|
|
// NewClient only used to help setting up a client for testing. Normal code
|
|
|
|
// exercises NewClientLogger.
|
2013-12-19 22:48:14 +00:00
|
|
|
func NewClient(config *Config) (*Client, error) {
|
2019-03-13 09:29:06 +00:00
|
|
|
c, err := tlsutil.NewConfigurator(config.ToTLSUtilConfig(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return NewClientLogger(config, nil, c)
|
2017-05-31 09:05:02 +00:00
|
|
|
}
|
|
|
|
|
2020-06-10 20:15:32 +00:00
|
|
|
func NewClientWithOptions(config *Config, options ...ConsulOption) (*Client, error) {
|
|
|
|
flat := flattenConsulOptions(options)
|
|
|
|
|
|
|
|
logger := flat.logger
|
|
|
|
tlsConfigurator := flat.tlsConfigurator
|
|
|
|
connPool := flat.connPool
|
|
|
|
|
2014-03-09 22:18:36 +00:00
|
|
|
// Check the protocol version
|
2017-05-03 19:02:01 +00:00
|
|
|
if err := config.CheckProtocolVersion(); err != nil {
|
2014-03-09 22:18:36 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2013-12-19 22:48:14 +00:00
|
|
|
// Check for a data directory!
|
|
|
|
if config.DataDir == "" {
|
|
|
|
return nil, fmt.Errorf("Config must provide a DataDir")
|
|
|
|
}
|
|
|
|
|
2014-08-05 22:20:35 +00:00
|
|
|
// Sanity check the ACLs
|
|
|
|
if err := config.CheckACL(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2013-12-19 22:48:14 +00:00
|
|
|
// Ensure we have a log output
|
|
|
|
if config.LogOutput == nil {
|
|
|
|
config.LogOutput = os.Stderr
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a logger
|
2017-05-31 09:05:02 +00:00
|
|
|
if logger == nil {
|
2020-01-28 23:50:41 +00:00
|
|
|
logger = hclog.NewInterceptLogger(&hclog.LoggerOptions{
|
|
|
|
Level: hclog.Debug,
|
|
|
|
Output: config.LogOutput,
|
|
|
|
})
|
2017-05-31 09:05:02 +00:00
|
|
|
}
|
2013-12-19 22:48:14 +00:00
|
|
|
|
2020-06-10 20:15:32 +00:00
|
|
|
if connPool == nil {
|
|
|
|
connPool = &pool.ConnPool{
|
|
|
|
Server: false,
|
|
|
|
SrcAddr: config.RPCSrcAddr,
|
|
|
|
LogOutput: config.LogOutput,
|
|
|
|
MaxTime: clientRPCConnMaxIdle,
|
|
|
|
MaxStreams: clientMaxStreams,
|
|
|
|
TLSConfigurator: tlsConfigurator,
|
|
|
|
Datacenter: config.Datacenter,
|
|
|
|
}
|
2017-06-15 13:16:16 +00:00
|
|
|
}
|
|
|
|
|
2017-09-01 22:02:50 +00:00
|
|
|
// Create client
|
2013-12-19 22:48:14 +00:00
|
|
|
c := &Client{
|
2019-06-27 20:22:07 +00:00
|
|
|
config: config,
|
|
|
|
connPool: connPool,
|
|
|
|
eventCh: make(chan serf.Event, serfEventBacklog),
|
2020-01-28 23:50:41 +00:00
|
|
|
logger: logger.NamedIntercept(logging.ConsulClient),
|
2019-06-27 20:22:07 +00:00
|
|
|
shutdownCh: make(chan struct{}),
|
|
|
|
tlsConfigurator: tlsConfigurator,
|
2013-12-19 22:48:14 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 13:07:22 +00:00
|
|
|
c.rpcLimiter.Store(rate.NewLimiter(config.RPCRate, config.RPCMaxBurst))
|
2018-06-11 20:11:36 +00:00
|
|
|
|
2018-05-24 14:36:42 +00:00
|
|
|
if err := c.initEnterprise(); err != nil {
|
|
|
|
c.Shutdown()
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-10-19 16:04:07 +00:00
|
|
|
c.useNewACLs = 0
|
|
|
|
aclConfig := ACLResolverConfig{
|
2020-01-13 20:51:40 +00:00
|
|
|
Config: config,
|
|
|
|
Delegate: c,
|
2020-01-28 23:50:41 +00:00
|
|
|
Logger: c.logger,
|
2020-01-13 20:51:40 +00:00
|
|
|
AutoDisable: true,
|
|
|
|
CacheConfig: clientACLCacheConfig,
|
2020-01-28 23:50:41 +00:00
|
|
|
ACLConfig: newACLConfig(c.logger),
|
2018-10-19 16:04:07 +00:00
|
|
|
}
|
2019-03-13 09:29:06 +00:00
|
|
|
var err error
|
2018-10-19 16:04:07 +00:00
|
|
|
if c.acls, err = NewACLResolver(&aclConfig); err != nil {
|
|
|
|
c.Shutdown()
|
|
|
|
return nil, fmt.Errorf("Failed to create ACL resolver: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-11-10 20:26:48 +00:00
|
|
|
// Initialize the LAN Serf
|
2013-12-19 22:48:14 +00:00
|
|
|
c.serf, err = c.setupSerf(config.SerfLANConfig,
|
|
|
|
c.eventCh, serfLANSnapshot)
|
|
|
|
if err != nil {
|
|
|
|
c.Shutdown()
|
|
|
|
return nil, fmt.Errorf("Failed to start lan serf: %v", err)
|
|
|
|
}
|
2016-03-27 04:59:45 +00:00
|
|
|
|
2016-03-29 22:58:15 +00:00
|
|
|
// Start maintenance task for servers
|
2020-04-30 20:12:17 +00:00
|
|
|
c.routers = router.New(c.logger, c.shutdownCh, c.serf, c.connPool, "")
|
2017-07-06 10:40:54 +00:00
|
|
|
go c.routers.Start()
|
2016-03-27 04:59:45 +00:00
|
|
|
|
2017-11-10 20:26:48 +00:00
|
|
|
// Start LAN event handlers after the router is complete since the event
|
|
|
|
// handlers depend on the router and the router depends on Serf.
|
|
|
|
go c.lanEventHandler()
|
|
|
|
|
2020-06-03 14:36:32 +00:00
|
|
|
// This needs to happen after initializing c.routers to prevent a race
|
|
|
|
// condition where the router manager is used when the pointer is nil
|
|
|
|
if c.acls.ACLsEnabled() {
|
|
|
|
go c.monitorACLMode()
|
|
|
|
}
|
|
|
|
|
2018-05-24 14:36:42 +00:00
|
|
|
if err := c.startEnterprise(); err != nil {
|
|
|
|
c.Shutdown()
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2013-12-19 22:48:14 +00:00
|
|
|
return c, nil
|
|
|
|
}
|
|
|
|
|
2020-06-10 20:15:32 +00:00
|
|
|
func NewClientLogger(config *Config, logger hclog.InterceptLogger, tlsConfigurator *tlsutil.Configurator) (*Client, error) {
|
|
|
|
return NewClientWithOptions(config, WithLogger(logger), WithTLSConfigurator(tlsConfigurator))
|
|
|
|
}
|
|
|
|
|
2013-12-19 22:48:14 +00:00
|
|
|
// Shutdown is used to shutdown the client
|
|
|
|
func (c *Client) Shutdown() error {
|
2020-01-28 23:50:41 +00:00
|
|
|
c.logger.Info("shutting down client")
|
2013-12-19 22:48:14 +00:00
|
|
|
c.shutdownLock.Lock()
|
|
|
|
defer c.shutdownLock.Unlock()
|
|
|
|
|
|
|
|
if c.shutdown {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
c.shutdown = true
|
|
|
|
close(c.shutdownCh)
|
|
|
|
|
|
|
|
if c.serf != nil {
|
|
|
|
c.serf.Shutdown()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close the connection pool
|
|
|
|
c.connPool.Shutdown()
|
2019-12-06 19:01:34 +00:00
|
|
|
|
|
|
|
c.acls.Close()
|
|
|
|
|
2013-12-19 22:48:14 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Leave is used to prepare for a graceful shutdown
|
|
|
|
func (c *Client) Leave() error {
|
2020-01-28 23:50:41 +00:00
|
|
|
c.logger.Info("client starting leave")
|
2013-12-19 22:48:14 +00:00
|
|
|
|
|
|
|
// Leave the LAN pool
|
|
|
|
if c.serf != nil {
|
|
|
|
if err := c.serf.Leave(); err != nil {
|
2020-01-28 23:50:41 +00:00
|
|
|
c.logger.Error("Failed to leave LAN Serf cluster", "error", err)
|
2013-12-19 22:48:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// JoinLAN is used to have Consul client join the inner-DC pool
|
|
|
|
// The target address should be another node inside the DC
|
|
|
|
// listening on the Serf LAN address
|
2013-12-30 20:20:17 +00:00
|
|
|
func (c *Client) JoinLAN(addrs []string) (int, error) {
|
2014-02-21 00:27:03 +00:00
|
|
|
return c.serf.Join(addrs, true)
|
2013-12-19 22:48:14 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 18:21:56 +00:00
|
|
|
// LocalMember is used to return the local node
|
|
|
|
func (c *Client) LocalMember() serf.Member {
|
|
|
|
return c.serf.LocalMember()
|
|
|
|
}
|
|
|
|
|
2013-12-19 22:48:14 +00:00
|
|
|
// LANMembers is used to return the members of the LAN cluster
|
|
|
|
func (c *Client) LANMembers() []serf.Member {
|
|
|
|
return c.serf.Members()
|
|
|
|
}
|
|
|
|
|
2017-09-05 19:22:20 +00:00
|
|
|
// LANMembersAllSegments returns members from all segments.
|
|
|
|
func (c *Client) LANMembersAllSegments() ([]serf.Member, error) {
|
|
|
|
return c.serf.Members(), nil
|
|
|
|
}
|
|
|
|
|
2017-08-14 14:36:07 +00:00
|
|
|
// LANSegmentMembers only returns our own segment's members, because clients
|
|
|
|
// can't be in multiple segments.
|
2017-08-30 23:44:04 +00:00
|
|
|
func (c *Client) LANSegmentMembers(segment string) ([]serf.Member, error) {
|
|
|
|
if segment == c.config.Segment {
|
2017-08-14 14:36:07 +00:00
|
|
|
return c.LANMembers(), nil
|
|
|
|
}
|
|
|
|
|
2017-08-30 23:44:04 +00:00
|
|
|
return nil, fmt.Errorf("segment %q not found", segment)
|
2017-08-14 14:36:07 +00:00
|
|
|
}
|
|
|
|
|
2013-12-30 22:42:23 +00:00
|
|
|
// RemoveFailedNode is used to remove a failed node from the cluster
|
2019-10-04 21:10:02 +00:00
|
|
|
func (c *Client) RemoveFailedNode(node string, prune bool) error {
|
|
|
|
if prune {
|
2019-10-07 21:15:23 +00:00
|
|
|
return c.serf.RemoveFailedNodePrune(node)
|
2019-10-04 21:10:02 +00:00
|
|
|
}
|
2013-12-30 22:42:23 +00:00
|
|
|
return c.serf.RemoveFailedNode(node)
|
|
|
|
}
|
|
|
|
|
2014-11-20 00:45:49 +00:00
|
|
|
// KeyManagerLAN returns the LAN Serf keyring manager
|
|
|
|
func (c *Client) KeyManagerLAN() *serf.KeyManager {
|
|
|
|
return c.serf.KeyManager()
|
|
|
|
}
|
|
|
|
|
2013-12-19 23:08:55 +00:00
|
|
|
// RPC is used to forward an RPC call to a consul server, or fail if no servers
|
|
|
|
func (c *Client) RPC(method string, args interface{}, reply interface{}) error {
|
2017-10-10 22:19:50 +00:00
|
|
|
// This is subtle but we start measuring the time on the client side
|
|
|
|
// right at the time of the first request, vs. on the first retry as
|
|
|
|
// is done on the server side inside forward(). This is because the
|
|
|
|
// servers may already be applying the RPCHoldTimeout up there, so by
|
|
|
|
// starting the timer here we won't potentially double up the delay.
|
|
|
|
// TODO (slackpad) Plumb a deadline here with a context.
|
|
|
|
firstCheck := time.Now()
|
|
|
|
|
|
|
|
TRY:
|
2017-07-06 10:40:54 +00:00
|
|
|
server := c.routers.FindServer()
|
2016-02-19 21:17:52 +00:00
|
|
|
if server == nil {
|
|
|
|
return structs.ErrNoServers
|
|
|
|
}
|
|
|
|
|
2017-09-01 22:02:50 +00:00
|
|
|
// Enforce the RPC limit.
|
2017-10-04 23:43:27 +00:00
|
|
|
metrics.IncrCounter([]string{"client", "rpc"}, 1)
|
2018-06-11 19:51:17 +00:00
|
|
|
if !c.rpcLimiter.Load().(*rate.Limiter).Allow() {
|
2017-10-04 23:43:27 +00:00
|
|
|
metrics.IncrCounter([]string{"client", "rpc", "exceeded"}, 1)
|
2017-09-01 22:02:50 +00:00
|
|
|
return structs.ErrRPCRateExceeded
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make the request.
|
2020-05-28 07:48:34 +00:00
|
|
|
rpcErr := c.connPool.RPC(c.config.Datacenter, server.ShortName, server.Addr, method, args, reply)
|
2017-10-10 22:19:50 +00:00
|
|
|
if rpcErr == nil {
|
|
|
|
return nil
|
2014-02-03 19:53:04 +00:00
|
|
|
}
|
|
|
|
|
2017-10-10 22:19:50 +00:00
|
|
|
// Move off to another server, and see if we can retry.
|
2020-01-28 23:50:41 +00:00
|
|
|
c.logger.Error("RPC failed to server",
|
|
|
|
"method", method,
|
|
|
|
"server", server.Addr,
|
|
|
|
"error", rpcErr,
|
|
|
|
)
|
2018-06-13 13:56:14 +00:00
|
|
|
metrics.IncrCounterWithLabels([]string{"client", "rpc", "failed"}, 1, []metrics.Label{{Name: "server", Value: server.Name}})
|
2017-10-10 22:19:50 +00:00
|
|
|
c.routers.NotifyFailedServer(server)
|
|
|
|
if retry := canRetry(args, rpcErr); !retry {
|
|
|
|
return rpcErr
|
|
|
|
}
|
|
|
|
|
|
|
|
// We can wait a bit and retry!
|
2017-10-17 18:38:24 +00:00
|
|
|
if time.Since(firstCheck) < c.config.RPCHoldTimeout {
|
2017-10-10 22:19:50 +00:00
|
|
|
jitter := lib.RandomStagger(c.config.RPCHoldTimeout / jitterFraction)
|
|
|
|
select {
|
|
|
|
case <-time.After(jitter):
|
|
|
|
goto TRY
|
|
|
|
case <-c.shutdownCh:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rpcErr
|
2013-12-19 23:08:55 +00:00
|
|
|
}
|
2014-02-24 00:37:33 +00:00
|
|
|
|
2016-10-26 02:20:24 +00:00
|
|
|
// SnapshotRPC sends the snapshot request to one of the servers, reading from
|
|
|
|
// the streaming input and writing to the streaming output depending on the
|
|
|
|
// operation.
|
|
|
|
func (c *Client) SnapshotRPC(args *structs.SnapshotRequest, in io.Reader, out io.Writer,
|
2017-06-15 09:50:28 +00:00
|
|
|
replyFn structs.SnapshotReplyFn) error {
|
2017-07-06 10:40:54 +00:00
|
|
|
server := c.routers.FindServer()
|
2016-10-26 02:20:24 +00:00
|
|
|
if server == nil {
|
|
|
|
return structs.ErrNoServers
|
|
|
|
}
|
|
|
|
|
2017-09-01 22:02:50 +00:00
|
|
|
// Enforce the RPC limit.
|
2017-10-04 23:43:27 +00:00
|
|
|
metrics.IncrCounter([]string{"client", "rpc"}, 1)
|
2018-06-11 19:51:17 +00:00
|
|
|
if !c.rpcLimiter.Load().(*rate.Limiter).Allow() {
|
2017-10-04 23:43:27 +00:00
|
|
|
metrics.IncrCounter([]string{"client", "rpc", "exceeded"}, 1)
|
2017-09-01 22:02:50 +00:00
|
|
|
return structs.ErrRPCRateExceeded
|
|
|
|
}
|
|
|
|
|
2016-10-26 02:20:24 +00:00
|
|
|
// Request the operation.
|
|
|
|
var reply structs.SnapshotResponse
|
2020-05-28 08:18:30 +00:00
|
|
|
snap, err := SnapshotRPC(c.connPool, c.config.Datacenter, server.ShortName, server.Addr, args, in, &reply)
|
2016-10-26 02:20:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
if err := snap.Close(); err != nil {
|
2020-01-28 23:50:41 +00:00
|
|
|
c.logger.Error("Failed closing snapshot stream", "error", err)
|
2016-10-26 02:20:24 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Let the caller peek at the reply.
|
|
|
|
if replyFn != nil {
|
|
|
|
if err := replyFn(&reply); err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stream the snapshot.
|
|
|
|
if out != nil {
|
|
|
|
if _, err := io.Copy(out, snap); err != nil {
|
|
|
|
return fmt.Errorf("failed to stream snapshot: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-02-24 00:37:33 +00:00
|
|
|
// Stats is used to return statistics for debugging and insight
|
|
|
|
// for various sub-systems
|
|
|
|
func (c *Client) Stats() map[string]map[string]string {
|
2017-07-06 10:40:54 +00:00
|
|
|
numServers := c.routers.NumServers()
|
2016-02-19 20:13:17 +00:00
|
|
|
|
2014-02-24 00:37:33 +00:00
|
|
|
toString := func(v uint64) string {
|
|
|
|
return strconv.FormatUint(v, 10)
|
|
|
|
}
|
|
|
|
stats := map[string]map[string]string{
|
2020-06-16 17:19:31 +00:00
|
|
|
"consul": {
|
2014-02-24 02:08:58 +00:00
|
|
|
"server": "false",
|
2016-02-20 01:32:16 +00:00
|
|
|
"known_servers": toString(uint64(numServers)),
|
2014-02-24 00:37:33 +00:00
|
|
|
},
|
2014-03-09 22:46:03 +00:00
|
|
|
"serf_lan": c.serf.Stats(),
|
2014-04-29 17:55:42 +00:00
|
|
|
"runtime": runtimeStats(),
|
2014-02-24 00:37:33 +00:00
|
|
|
}
|
2018-05-24 14:36:42 +00:00
|
|
|
|
2020-07-03 20:52:08 +00:00
|
|
|
if c.config.ACLsEnabled {
|
2018-10-31 20:00:46 +00:00
|
|
|
if c.UseLegacyACLs() {
|
|
|
|
stats["consul"]["acl"] = "legacy"
|
|
|
|
} else {
|
|
|
|
stats["consul"]["acl"] = "enabled"
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
stats["consul"]["acl"] = "disabled"
|
|
|
|
}
|
|
|
|
|
2018-05-24 14:36:42 +00:00
|
|
|
for outerKey, outerValue := range c.enterpriseStats() {
|
|
|
|
if _, ok := stats[outerKey]; ok {
|
|
|
|
for innerKey, innerValue := range outerValue {
|
|
|
|
stats[outerKey][innerKey] = innerValue
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
stats[outerKey] = outerValue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-24 00:37:33 +00:00
|
|
|
return stats
|
|
|
|
}
|
2015-04-15 23:12:45 +00:00
|
|
|
|
2017-05-15 14:05:17 +00:00
|
|
|
// GetLANCoordinate returns the network coordinate of the current node, as
|
2015-06-06 03:31:33 +00:00
|
|
|
// maintained by Serf.
|
2017-08-14 14:36:07 +00:00
|
|
|
func (c *Client) GetLANCoordinate() (lib.CoordinateSet, error) {
|
|
|
|
lan, err := c.serf.GetCoordinate()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cs := lib.CoordinateSet{c.config.Segment: lan}
|
|
|
|
return cs, nil
|
2015-04-15 23:12:45 +00:00
|
|
|
}
|
2018-06-11 19:51:17 +00:00
|
|
|
|
|
|
|
// ReloadConfig is used to have the Client do an online reload of
|
|
|
|
// relevant configuration information
|
|
|
|
func (c *Client) ReloadConfig(config *Config) error {
|
|
|
|
c.rpcLimiter.Store(rate.NewLimiter(config.RPCRate, config.RPCMaxBurst))
|
|
|
|
return nil
|
|
|
|
}
|