1package memberlist
2
3import (
4	"io"
5	"log"
6	"os"
7	"time"
8)
9
10type Config struct {
11	// The name of this node. This must be unique in the cluster.
12	Name string
13
14	// Configuration related to what address to bind to and ports to
15	// listen on. The port is used for both UDP and TCP gossip.
16	// It is assumed other nodes are running on this port, but they
17	// do not need to.
18	BindAddr string
19	BindPort int
20
21	// Configuration related to what address to advertise to other
22	// cluster members. Used for nat traversal.
23	AdvertiseAddr string
24	AdvertisePort int
25
26	// ProtocolVersion is the configured protocol version that we
27	// will _speak_. This must be between ProtocolVersionMin and
28	// ProtocolVersionMax.
29	ProtocolVersion uint8
30
31	// TCPTimeout is the timeout for establishing a TCP connection with
32	// a remote node for a full state sync.
33	TCPTimeout time.Duration
34
35	// IndirectChecks is the number of nodes that will be asked to perform
36	// an indirect probe of a node in the case a direct probe fails. Memberlist
37	// waits for an ack from any single indirect node, so increasing this
38	// number will increase the likelihood that an indirect probe will succeed
39	// at the expense of bandwidth.
40	IndirectChecks int
41
42	// RetransmitMult is the multiplier for the number of retransmissions
43	// that are attempted for messages broadcasted over gossip. The actual
44	// count of retransmissions is calculated using the formula:
45	//
46	//   Retransmits = RetransmitMult * log(N+1)
47	//
48	// This allows the retransmits to scale properly with cluster size. The
49	// higher the multiplier, the more likely a failed broadcast is to converge
50	// at the expense of increased bandwidth.
51	RetransmitMult int
52
53	// SuspicionMult is the multiplier for determining the time an
54	// inaccessible node is considered suspect before declaring it dead.
55	// The actual timeout is calculated using the formula:
56	//
57	//   SuspicionTimeout = SuspicionMult * log(N+1) * ProbeInterval
58	//
59	// This allows the timeout to scale properly with expected propagation
60	// delay with a larger cluster size. The higher the multiplier, the longer
61	// an inaccessible node is considered part of the cluster before declaring
62	// it dead, giving that suspect node more time to refute if it is indeed
63	// still alive.
64	SuspicionMult int
65
66	// PushPullInterval is the interval between complete state syncs.
67	// Complete state syncs are done with a single node over TCP and are
68	// quite expensive relative to standard gossiped messages. Setting this
69	// to zero will disable state push/pull syncs completely.
70	//
71	// Setting this interval lower (more frequent) will increase convergence
72	// speeds across larger clusters at the expense of increased bandwidth
73	// usage.
74	PushPullInterval time.Duration
75
76	// ProbeInterval and ProbeTimeout are used to configure probing
77	// behavior for memberlist.
78	//
79	// ProbeInterval is the interval between random node probes. Setting
80	// this lower (more frequent) will cause the memberlist cluster to detect
81	// failed nodes more quickly at the expense of increased bandwidth usage.
82	//
83	// ProbeTimeout is the timeout to wait for an ack from a probed node
84	// before assuming it is unhealthy. This should be set to 99-percentile
85	// of RTT (round-trip time) on your network.
86	ProbeInterval time.Duration
87	ProbeTimeout  time.Duration
88
89	// DisableTcpPings will turn off the fallback TCP pings that are attempted
90	// if the direct UDP ping fails. These get pipelined along with the
91	// indirect UDP pings.
92	DisableTcpPings bool
93
94	// GossipInterval and GossipNodes are used to configure the gossip
95	// behavior of memberlist.
96	//
97	// GossipInterval is the interval between sending messages that need
98	// to be gossiped that haven't been able to piggyback on probing messages.
99	// If this is set to zero, non-piggyback gossip is disabled. By lowering
100	// this value (more frequent) gossip messages are propagated across
101	// the cluster more quickly at the expense of increased bandwidth.
102	//
103	// GossipNodes is the number of random nodes to send gossip messages to
104	// per GossipInterval. Increasing this number causes the gossip messages
105	// to propagate across the cluster more quickly at the expense of
106	// increased bandwidth.
107	GossipInterval time.Duration
108	GossipNodes    int
109
110	// EnableCompression is used to control message compression. This can
111	// be used to reduce bandwidth usage at the cost of slightly more CPU
112	// utilization. This is only available starting at protocol version 1.
113	EnableCompression bool
114
115	// SecretKey is used to initialize the primary encryption key in a keyring.
116	// The primary encryption key is the only key used to encrypt messages and
117	// the first key used while attempting to decrypt messages. Providing a
118	// value for this primary key will enable message-level encryption and
119	// verification, and automatically install the key onto the keyring.
120	// The value should be either 16, 24, or 32 bytes to select AES-128,
121	// AES-192, or AES-256.
122	SecretKey []byte
123
124	// The keyring holds all of the encryption keys used internally. It is
125	// automatically initialized using the SecretKey and SecretKeys values.
126	Keyring *Keyring
127
128	// Delegate and Events are delegates for receiving and providing
129	// data to memberlist via callback mechanisms. For Delegate, see
130	// the Delegate interface. For Events, see the EventDelegate interface.
131	//
132	// The DelegateProtocolMin/Max are used to guarantee protocol-compatibility
133	// for any custom messages that the delegate might do (broadcasts,
134	// local/remote state, etc.). If you don't set these, then the protocol
135	// versions will just be zero, and version compliance won't be done.
136	Delegate                Delegate
137	DelegateProtocolVersion uint8
138	DelegateProtocolMin     uint8
139	DelegateProtocolMax     uint8
140	Events                  EventDelegate
141	Conflict                ConflictDelegate
142	Merge                   MergeDelegate
143	Ping                    PingDelegate
144	Alive                   AliveDelegate
145
146	// DNSConfigPath points to the system's DNS config file, usually located
147	// at /etc/resolv.conf. It can be overridden via config for easier testing.
148	DNSConfigPath string
149
150	// LogOutput is the writer where logs should be sent. If this is not
151	// set, logging will go to stderr by default. You cannot specify both LogOutput
152	// and Logger at the same time.
153	LogOutput io.Writer
154
155	// Logger is a custom logger which you provide. If Logger is set, it will use
156	// this for the internal logger. If Logger is not set, it will fall back to the
157	// behavior for using LogOutput. You cannot specify both LogOutput and Logger
158	// at the same time.
159	Logger *log.Logger
160}
161
162// DefaultLANConfig returns a sane set of configurations for Memberlist.
163// It uses the hostname as the node name, and otherwise sets very conservative
164// values that are sane for most LAN environments. The default configuration
165// errs on the side of caution, choosing values that are optimized
166// for higher convergence at the cost of higher bandwidth usage. Regardless,
167// these values are a good starting point when getting started with memberlist.
168func DefaultLANConfig() *Config {
169	hostname, _ := os.Hostname()
170	return &Config{
171		Name:             hostname,
172		BindAddr:         "0.0.0.0",
173		BindPort:         7946,
174		AdvertiseAddr:    "",
175		AdvertisePort:    7946,
176		ProtocolVersion:  ProtocolVersion2Compatible,
177		TCPTimeout:       10 * time.Second,       // Timeout after 10 seconds
178		IndirectChecks:   3,                      // Use 3 nodes for the indirect ping
179		RetransmitMult:   4,                      // Retransmit a message 4 * log(N+1) nodes
180		SuspicionMult:    5,                      // Suspect a node for 5 * log(N+1) * Interval
181		PushPullInterval: 30 * time.Second,       // Low frequency
182		ProbeTimeout:     500 * time.Millisecond, // Reasonable RTT time for LAN
183		ProbeInterval:    1 * time.Second,        // Failure check every second
184		DisableTcpPings:  false,                  // TCP pings are safe, even with mixed versions
185
186		GossipNodes:    3,                      // Gossip to 3 nodes
187		GossipInterval: 200 * time.Millisecond, // Gossip more rapidly
188
189		EnableCompression: true, // Enable compression by default
190
191		SecretKey: nil,
192		Keyring:   nil,
193
194		DNSConfigPath: "/etc/resolv.conf",
195	}
196}
197
198// DefaultWANConfig works like DefaultConfig, however it returns a configuration
199// that is optimized for most WAN environments. The default configuration is
200// still very conservative and errs on the side of caution.
201func DefaultWANConfig() *Config {
202	conf := DefaultLANConfig()
203	conf.TCPTimeout = 30 * time.Second
204	conf.SuspicionMult = 6
205	conf.PushPullInterval = 60 * time.Second
206	conf.ProbeTimeout = 3 * time.Second
207	conf.ProbeInterval = 5 * time.Second
208	conf.GossipNodes = 4 // Gossip less frequently, but to an additional node
209	conf.GossipInterval = 500 * time.Millisecond
210	return conf
211}
212
213// DefaultLocalConfig works like DefaultConfig, however it returns a configuration
214// that is optimized for a local loopback environments. The default configuration is
215// still very conservative and errs on the side of caution.
216func DefaultLocalConfig() *Config {
217	conf := DefaultLANConfig()
218	conf.TCPTimeout = time.Second
219	conf.IndirectChecks = 1
220	conf.RetransmitMult = 2
221	conf.SuspicionMult = 3
222	conf.PushPullInterval = 15 * time.Second
223	conf.ProbeTimeout = 200 * time.Millisecond
224	conf.ProbeInterval = time.Second
225	conf.GossipInterval = 100 * time.Millisecond
226	return conf
227}
228
229// Returns whether or not encryption is enabled
230func (c *Config) EncryptionEnabled() bool {
231	return c.Keyring != nil && len(c.Keyring.GetKeys()) > 0
232}
233