diff --git a/config.go b/config.go index fe93be19e..60c49932b 100644 --- a/config.go +++ b/config.go @@ -60,11 +60,19 @@ type TLSConfig struct { // Config represents the configuration for the command. type Config struct { - DataDir string `toml:"data-dir"` - Bind string `toml:"bind"` + DataDir string `toml:"data-dir"` + Bind string `toml:"bind"` + // GossipPort DEPRECATED GossipPort string `toml:"gossip-port"` + // GossipSeed DEPRECATED GossipSeed string `toml:"gossip-seed"` + Gossip struct { + Port string `toml:"port"` + Seed string `toml:"seed"` + Key string `toml:"key"` + } `toml:"gossip"` + Cluster struct { ReplicaN int `toml:"replicas"` Type string `toml:"type"` diff --git a/ctl/server.go b/ctl/server.go index a0c080729..77361f7db 100644 --- a/ctl/server.go +++ b/ctl/server.go @@ -26,8 +26,11 @@ func BuildServerFlags(cmd *cobra.Command, srv *server.Command) { flags := cmd.Flags() flags.StringVarP(&srv.Config.DataDir, "data-dir", "d", "~/.pilosa", "Directory to store pilosa data files.") flags.StringVarP(&srv.Config.Bind, "bind", "b", ":10101", "Default URI on which pilosa should listen.") - flags.StringVarP(&srv.Config.GossipPort, "gossip-port", "", "", "Port to which pilosa should bind for internal state sharing.") - flags.StringVarP(&srv.Config.GossipSeed, "gossip-seed", "", "", "Host with which to seed the gossip membership.") + flags.StringVarP(&srv.Config.GossipPort, "gossip-port", "", "", "(DEPRECATED) Port to which pilosa should bind for internal state sharing.") + flags.StringVarP(&srv.Config.GossipSeed, "gossip-seed", "", "", "(DEPRECATED) Host with which to seed the gossip membership.") + flags.StringVarP(&srv.Config.Gossip.Port, "gossip.port", "", "", "Port to which pilosa should bind for internal state sharing.") + flags.StringVarP(&srv.Config.Gossip.Seed, "gossip.seed", "", "", "Host with which to seed the gossip membership.") + flags.StringVarP(&srv.Config.Gossip.Key, "gossip.key", "", "", "The path to file of the encryption key for gossip. The contents of the file should be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.") flags.IntVarP(&srv.Config.MaxWritesPerRequest, "max-writes-per-request", "", srv.Config.MaxWritesPerRequest, "Number of write commands per request.") flags.IntVarP(&srv.Config.Cluster.ReplicaN, "cluster.replicas", "", 1, "Number of hosts each piece of data should be stored on.") flags.StringSliceVarP(&srv.Config.Cluster.Hosts, "cluster.hosts", "", []string{}, "Comma separated list of hosts in cluster.") diff --git a/docs/configuration.md b/docs/configuration.md index 6741bc74b..10325b09f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -79,23 +79,36 @@ Any flag that has a value that is a comma separated list on the command line bec #### Gossip Port * Description: Port to which Pilosa should bind for internal communication. -* Flag: `--gossip-port=11101` +* Flag: `--gossip.port=11101` * Env: `PILOSA_GOSSIP_PORT=11101` * Config: ```toml - gossip-port = 11101 + [gossip] + port = 11101 ``` #### Gossip Seed * Description: When using the gossip [Cluster Type]({{< ref "#cluster-type" >}}), this specifies which internal host should be used to initialize membership in the cluster. Typcially this can be the address of any available host in the cluster. For example, when starting a three-node cluster made up of `node0`, `node1`, and `node2`, the `gossip-seed` for all three nodes can be configured to be the address of `node0`. -* Flag: `--gossip-seed="localhost:11101"` +* Flag: `--gossip.seed="localhost:11101"` * Env: `PILOSA_GOSSIP_SEED="localhost:11101"` * Config: ```toml - gossip-seed = "localhost:11101" + [gossip] + seed = "localhost:11101" + ``` + +#### Gossip Key + +* Description: Path to the file which contains the key to encrypt gossip communication. The contents of the file should be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256 encryption. You can read from `/dev/random` device on UNIX-like systems to create the key file; e.g., `head -c 32 /dev/random > gossip.key32` creates a key file to use AES-256. +* Flag: `--gossip.key="/var/secret/gossip.key32"` +* Env: `PILOSA_GOSSIP_KEY="/var/secret/gossip.key32"` +* Config: + ```toml + [gossip] + key = "/var/secret/gossip.key32" ``` #### Cluster Hosts @@ -250,8 +263,10 @@ A three node cluster could be minimally configured as follows: data-dir = "/home/pilosa/data" bind = "node0.pilosa.com:10101" - gossip-port = 12000 - gossip-seed = "node0.pilosa.com:12000" + + [gossip] + port = 12000 + seed = "node0.pilosa.com:12000" [cluster] replicas = 1 @@ -262,8 +277,10 @@ A three node cluster could be minimally configured as follows: data-dir = "/home/pilosa/data" bind = "node1.pilosa.com:10101" - gossip-port = 12000 - gossip-seed = "node0.pilosa.com:12000" + + [gossip] + port = 12000 + seed = "node0.pilosa.com:12000" [cluster] replicas = 1 @@ -274,8 +291,10 @@ A three node cluster could be minimally configured as follows: data-dir = "/home/pilosa/data" bind = "node2.pilosa.com:10101" - gossip-port = 12000 - gossip-seed = "node0.pilosa.com:12000" + + [gossip] + port = 12000 + seed = "node0.pilosa.com:12000" [cluster] replicas = 1 @@ -285,14 +304,17 @@ A three node cluster could be minimally configured as follows: ### Example Cluster Configuration (HTTPS) -The same cluster which uses HTTPS instead of HTTP can be configured as follows. Note that we explicitly specify `https` as the protocol in `bind` and `cluster.hosts` configuration: +The same cluster which uses HTTPS instead of HTTP can be configured as follows. Note that we explicitly specify `https` as the protocol in `bind` and `cluster.hosts` configuration. It is not required to use a gossip key but it is highly recommended: #### Node 0 data-dir = "/home/pilosa/data" bind = "https://node0.pilosa.com:10101" - gossip-port = 12000 - gossip-seed = "node0.pilosa.com:12000" + + [gossip] + port = 12000 + seed = "node0.pilosa.com:12000" + key = "/home/pilosa/private/gossip.key32" [cluster] replicas = 1 @@ -307,8 +329,11 @@ The same cluster which uses HTTPS instead of HTTP can be configured as follows. data-dir = "/home/pilosa/data" bind = "https://node1.pilosa.com:10101" - gossip-port = 12000 - gossip-seed = "node0.pilosa.com:12000" + + [gossip] + port = 12000 + seed = "node0.pilosa.com:12000" + key = "/home/pilosa/private/gossip.key32" [cluster] replicas = 1 @@ -323,8 +348,11 @@ The same cluster which uses HTTPS instead of HTTP can be configured as follows. data-dir = "/home/pilosa/data" bind = "https://node2.pilosa.com:10101" - gossip-port = 12000 - gossip-seed = "node0.pilosa.com:12000" + + [gossip] + port = 12000 + seed = "node0.pilosa.com:12000" + key = "/home/pilosa/private/gossip.key32" [cluster] replicas = 1 diff --git a/gossip/gossip.go b/gossip/gossip.go index eade109a7..7085710b3 100644 --- a/gossip/gossip.go +++ b/gossip/gossip.go @@ -123,7 +123,7 @@ type gossipConfig struct { } // NewGossipNodeSet returns a new instance of GossipNodeSet. -func NewGossipNodeSet(name string, gossipHost string, gossipPort int, gossipSeed string, server *pilosa.Server) *GossipNodeSet { +func NewGossipNodeSet(name string, gossipHost string, gossipPort int, gossipSeed string, server *pilosa.Server, secretKey []byte) *GossipNodeSet { g := &GossipNodeSet{ LogOutput: server.LogOutput, } @@ -139,6 +139,7 @@ func NewGossipNodeSet(name string, gossipHost string, gossipPort int, gossipSeed g.config.memberlistConfig.AdvertiseAddr = pilosa.HostToIP(gossipHost) g.config.memberlistConfig.AdvertisePort = gossipPort g.config.memberlistConfig.Delegate = g + g.config.memberlistConfig.SecretKey = secretKey g.statusHandler = server diff --git a/server/server.go b/server/server.go index d1063f306..22e965b55 100644 --- a/server/server.go +++ b/server/server.go @@ -33,6 +33,7 @@ import ( "github.com/pilosa/pilosa" "github.com/pilosa/pilosa/gossip" "github.com/pilosa/pilosa/statsd" + "io/ioutil" ) func init() { @@ -173,7 +174,10 @@ func (m *Command) SetupServer() error { // Set internal port (string). gossipPortStr := pilosa.DefaultGossipPort - if m.Config.GossipPort != "" { + // Config.GossipPort is deprecated, so Config.Gossip.Port has priority + if m.Config.Gossip.Port != "" { + gossipPortStr = m.Config.Gossip.Port + } else if m.Config.GossipPort != "" { gossipPortStr = m.Config.GossipPort } @@ -184,13 +188,24 @@ func (m *Command) SetupServer() error { return err } gossipSeed := pilosa.DefaultHost + ":" + pilosa.DefaultGossipPort - if m.Config.GossipSeed != "" { + // Config.GossipSeed is deprecated, so Config.Gossip.Seed has priority + if m.Config.Gossip.Seed != "" { + gossipSeed = m.Config.Gossip.Seed + } else if m.Config.GossipSeed != "" { gossipSeed = m.Config.GossipSeed } + var gossipKey []byte + if m.Config.Gossip.Key != "" { + gossipKey, err = ioutil.ReadFile(m.Config.Gossip.Key) + if err != nil { + return err + } + } + // get the host portion of addr to use for binding gossipHost := uri.Host() - gossipNodeSet := gossip.NewGossipNodeSet(uri.HostPort(), gossipHost, gossipPort, gossipSeed, m.Server) + gossipNodeSet := gossip.NewGossipNodeSet(uri.HostPort(), gossipHost, gossipPort, gossipSeed, m.Server, gossipKey) m.Server.Cluster.NodeSet = gossipNodeSet m.Server.Broadcaster = gossipNodeSet m.Server.BroadcastReceiver = gossipNodeSet