Skip to content

Commit

Permalink
Fix hostname/bind addresses
Browse files Browse the repository at this point in the history
This fixes several issues related to the bind address and hostname:
* Allows bind addresses where a hostname or IP is not specified to
work correct and bind to all interfaces by default.
* Fixes the top-level "hostname" config option to allow overridding
all bind address hostnames.  This allows a node to advertise a different
hostname than what is defined in the bind address setting.
* Adds the -hostname command-line option back to allow specifing
both -join and -hostname as command-line flags.
* Enforces a configuration precedence and overriding ability defined
as config file is overridden by env vars which are overriden by command-line
flags.

Fixes #5670 #5671
  • Loading branch information
jwilder committed Feb 17, 2016
1 parent 0891f6d commit 07d8f38
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 41 deletions.
18 changes: 17 additions & 1 deletion cmd/influxd/run/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,19 @@ func (cmd *Command) Run(args ...string) error {
return fmt.Errorf("apply env config: %v", err)
}

// Command-line flags for -join and -hostname override the config
// and env variable
if options.Join != "" {
config.Meta.JoinPeers = strings.Split(options.Join, ",")
}

if options.Hostname != "" {
config.Hostname = options.Hostname
}

// Propogate the top-level hostname down to dependendent configs
config.Meta.RemoteHostname = config.Hostname

// Validate the configuration.
if err := config.Validate(); err != nil {
return fmt.Errorf("%s. To generate a valid configuration file run `influxd config > influxdb.generated.conf`", err)
Expand Down Expand Up @@ -156,6 +165,7 @@ func (cmd *Command) ParseFlags(args ...string) (Options, error) {
fs.StringVar(&options.ConfigPath, "config", "", "")
fs.StringVar(&options.PIDFile, "pidfile", "", "")
fs.StringVar(&options.Join, "join", "", "")
fs.StringVar(&options.Hostname, "hostname", "", "")
fs.StringVar(&options.CPUProfile, "cpuprofile", "", "")
fs.StringVar(&options.MemProfile, "memprofile", "", "")
fs.Usage = func() { fmt.Fprintln(cmd.Stderr, usage) }
Expand Down Expand Up @@ -215,7 +225,12 @@ then a new cluster will be initialized unless the -join argument is used.
Set the path to the configuration file.
-join <host:port>
Joins the server to an existing cluster. Should be the HTTP bind address of an existing meta server
Joins the server to an existing cluster. Should be
the HTTP bind address of an existing meta server
-hostname <name>
Override the hostname, the 'hostname' configuration
option will be overridden.
-pidfile <path>
Write process ID to a file.
Expand All @@ -232,6 +247,7 @@ type Options struct {
ConfigPath string
PIDFile string
Join string
Hostname string
CPUProfile string
MemProfile string
}
4 changes: 4 additions & 0 deletions cmd/influxd/run/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ type Config struct {

// BindAddress is the address that all TCP services use (Raft, Snapshot, Cluster, etc.)
BindAddress string `toml:"bind-address"`

// Hostname is the hostname portion to use when registering local
// addresses. This hostname must be resolvable from other nodes.
Hostname string `toml:"hostname"`
}

// NewConfig returns an instance of Config with reasonable defaults.
Expand Down
39 changes: 26 additions & 13 deletions cmd/influxd/run/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,6 @@ func NewServer(c *Config, buildInfo *BuildInfo) (*Server, error) {
return nil, fmt.Errorf("must run as either meta node or data node or both")
}

httpBindAddress, err := meta.DefaultHost(DefaultHostname, c.HTTPD.BindAddress)
if err != nil {
return nil, err
}
tcpBindAddress, err := meta.DefaultHost(DefaultHostname, bind)
if err != nil {
return nil, err
}

s := &Server{
buildInfo: *buildInfo,
err: make(chan error),
Expand All @@ -184,9 +175,9 @@ func NewServer(c *Config, buildInfo *BuildInfo) (*Server, error) {
joinPeers: c.Meta.JoinPeers,
metaUseTLS: c.Meta.HTTPSEnabled,

httpAPIAddr: httpBindAddress,
httpAPIAddr: c.HTTPD.BindAddress,
httpUseTLS: c.HTTPD.HTTPSEnabled,
tcpAddr: tcpBindAddress,
tcpAddr: bind,

config: c,
}
Expand Down Expand Up @@ -646,11 +637,11 @@ func (s *Server) initializeMetaClient() error {
return nil
}

n, err := s.MetaClient.CreateDataNode(s.httpAPIAddr, s.tcpAddr)
n, err := s.MetaClient.CreateDataNode(s.HTTPAddr(), s.TCPAddr())
for err != nil {
log.Printf("Unable to create data node. retry in 1s: %s", err.Error())
time.Sleep(time.Second)
n, err = s.MetaClient.CreateDataNode(s.httpAPIAddr, s.tcpAddr)
n, err = s.MetaClient.CreateDataNode(s.HTTPAddr(), s.TCPAddr())
}
s.Node.ID = n.ID

Expand All @@ -661,6 +652,28 @@ func (s *Server) initializeMetaClient() error {
return nil
}

// HTTPAddr returns the HTTP address used by other nodes for HTTP queries and writes.
func (s *Server) HTTPAddr() string {
return s.remoteAddr(s.httpAPIAddr)
}

// TCPAddr returns the TCP address used by other nodes for cluster communication.
func (s *Server) TCPAddr() string {
return s.remoteAddr(s.tcpAddr)
}

func (s *Server) remoteAddr(addr string) string {
hostname := s.config.Hostname
if hostname == "" {
hostname = meta.DefaultHostname
}
remote, err := meta.DefaultHost(hostname, addr)
if err != nil {
return addr
}
return remote
}

// MetaServers returns the meta node HTTP addresses used by this server.
func (s *Server) MetaServers() []string {
return s.MetaClient.MetaServers()
Expand Down
18 changes: 4 additions & 14 deletions services/meta/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ type Config struct {
Enabled bool `toml:"enabled"`
Dir string `toml:"dir"`

// RemoteHostname is the hostname portion to use when registering meta node
// addresses. This hostname must be resolvable from other nodes.
RemoteHostname string

// this is deprecated. Should use the address from run/config.go
BindAddress string `toml:"bind-address"`

Expand Down Expand Up @@ -103,20 +107,6 @@ func (c *Config) defaultHost(addr string) string {
return address
}

// DefaultedBindAddress returns the BindAddress normalized with the
// hosts name or "localhost" if that could not be determined. If
// the BindAddress already has a hostname, BindAddress is returned.
func (c *Config) DefaultedBindAddress() string {
return c.defaultHost(c.BindAddress)
}

// DefaultedHTTPBindAddress returns the HTTPBindAddress normalized with the
// hosts name or "localhost" if that could not be determined. If
// the HTTPBindAddress already has a hostname, HTTPBindAddress is returned.
func (c *Config) DefaultedHTTPBindAddress() string {
return c.defaultHost(c.HTTPBindAddress)
}

func DefaultHost(hostname, addr string) (string, error) {
host, port, err := net.SplitHostPort(addr)
if err != nil {
Expand Down
9 changes: 0 additions & 9 deletions services/meta/raft_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,6 @@ func (r *raftState) open(s *store, ln net.Listener, initializePeers []string) er
peers = []string{r.addr}
}

// If we have multiple nodes in the cluster, make sure our address is in the raft peers or
// we won't be able to boot into the cluster because the other peers will reject our new hostname. This
// is difficult to resolve automatically because we need to have all the raft peers agree on the current members
// of the cluster before we can change them.
if len(peers) > 0 && !raft.PeerContained(peers, r.addr) {
r.logger.Printf("%s is not in the list of raft peers. Please ensure all nodes have the same meta nodes configured", r.addr)
return fmt.Errorf("peers out of sync: %v not in %v", r.addr, peers)
}

// Create the log store and stable store.
store, err := raftboltdb.NewBoltStore(filepath.Join(r.path, "raft.db"))
if err != nil {
Expand Down
20 changes: 16 additions & 4 deletions services/meta/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ type Service struct {
func NewService(c *Config) *Service {
s := &Service{
config: c,
httpAddr: c.DefaultedHTTPBindAddress(),
raftAddr: c.DefaultedBindAddress(),
httpAddr: c.HTTPBindAddress,
raftAddr: c.BindAddress,
https: c.HTTPSEnabled,
cert: c.HTTPSCertificate,
err: make(chan error),
Expand Down Expand Up @@ -108,8 +108,8 @@ func (s *Service) Open() error {
return err
}

// Open the store
s.store = newStore(s.config, s.httpAddr, s.raftAddr)
// Open the store. The addresses passed in are remotely accessible.
s.store = newStore(s.config, s.remoteAddr(s.httpAddr), s.remoteAddr(s.raftAddr))

handler := newHandler(s.config, s)
handler.logger = s.Logger
Expand All @@ -126,6 +126,18 @@ func (s *Service) Open() error {
return nil
}

func (s *Service) remoteAddr(addr string) string {
hostname := s.config.RemoteHostname
if hostname == "" {
hostname = DefaultHostname
}
remote, err := DefaultHost(hostname, addr)
if err != nil {
return addr
}
return remote
}

// serve serves the handler from the listener.
func (s *Service) serve() {
// The listener was closed so exit
Expand Down

0 comments on commit 07d8f38

Please sign in to comment.