Merge pull request #273 from nats-io/listen

Enable listen address parsing
This commit is contained in:
Derek Collison
2016-05-13 06:28:14 -07:00
32 changed files with 255 additions and 98 deletions

View File

@@ -94,10 +94,9 @@ Common Options:
```
port: 4242 # port to listen for client connections
net: apcera.me # net interface to listen
listen: localhost:4242 # host/port to listen for client connections
http_port: 8222 # HTTP monitoring port
http: localhost:8222 # HTTP monitoring port
# Authorization for client connections
authorization {
@@ -111,8 +110,7 @@ authorization {
cluster {
host: '127.0.0.1' # host/net interface
port: 4244 # port for inbound route connections
listen: localhost:4244 # host/port for inbound route connections
# Authorization for route connections
authorization {
@@ -179,14 +177,11 @@ Alternatively, you could use a configuration file, let's call it `seed.conf`, wi
```
# Cluster Seed Node
port: 4222
net: 127.0.0.1
http_port: 8222
listen: 127.0.0.1:4222
http: 8222
cluster {
host: 127.0.0.1
port: 4248
listen: 127.0.0.1:4248
}
```
and start the server like this:
@@ -196,8 +191,8 @@ gnatsd -config ./seed.conf -D
This will produce an output similar to:
```
[75653] 2016/04/26 15:14:47.339321 [INF] Listening for route connections on localhost:4248
[75653] 2016/04/26 15:14:47.340787 [INF] Listening for client connections on 0.0.0.0:4222
[75653] 2016/04/26 15:14:47.339321 [INF] Listening for route connections on 127.0.0.1:4248
[75653] 2016/04/26 15:14:47.340787 [INF] Listening for client connections on 127.0.0.1:4222
[75653] 2016/04/26 15:14:47.340822 [DBG] server id is xZfu3u7usAPWkuThomoGzM
[75653] 2016/04/26 15:14:47.340825 [INF] server is ready
```
@@ -307,8 +302,7 @@ with a CA authority to verify the client certificates.
```
# Simple TLS config file
net: 127.0.0.1
port: 4443
listen: 127.0.0.1:4443
tls {
cert_file: "./configs/certs/server-cert.pem"
@@ -339,8 +333,7 @@ both directions. Certificates can be configured only for the server's cluster id
```
cluster {
host: '127.0.0.1'
port: 4244
listen: 127.0.0.1:4244
tls {
# Route cert

View File

@@ -0,0 +1,12 @@
# Copyright 2016 Apcera Inc. All rights reserved.
# Test all permutations of listen address parsing, client, cluster and http.
listen: 10.0.1.22:4422
http: 127.0.0.1:8422
https: 127.0.0.1:9443
cluster {
listen: 127.0.0.1:4244
}

View File

@@ -0,0 +1,3 @@
# Copyright 2016 Apcera Inc. All rights reserved.
listen: 8922

View File

@@ -0,0 +1,3 @@
# Copyright 2016 Apcera Inc. All rights reserved.
listen: :8922

View File

@@ -2,12 +2,10 @@
# Cluster Seed Node
port: 7222
net: 127.0.0.1
listen: 127.0.0.1:7222
http_port: 9222
http: 127.0.0.1:9222
cluster {
host: 127.0.0.1
port: 7248
listen: 127.0.0.1:7248
}

View File

@@ -2,14 +2,12 @@
# Cluster Seed Node
port: 7222
net: 127.0.0.1
listen: 127.0.0.1:7222
http_port: 9222
http: 127.0.0.1:9222
cluster {
host: 127.0.0.1
port: 7248
listen: 127.0.0.1:7248
tls {
# Route cert

View File

@@ -2,12 +2,10 @@
# Cluster Server A
port: 7222
net: 127.0.0.1
listen: 127.0.0.1:7222
cluster {
host: 127.0.0.1
port: 7244
listen: 127.0.0.1:7244
authorization {
user: ruser

View File

@@ -2,8 +2,7 @@
# Cluster Server A
host: 127.0.0.1
port: 7222
listen: 127.0.0.1:7222
authorization {
user: user
@@ -12,8 +11,7 @@ authorization {
}
cluster {
host: 127.0.0.1
port: 7244
listen: 127.0.0.1:7244
authorization {
user: ruser

View File

@@ -2,12 +2,10 @@
# Cluster Server B
port: 7224
net: 127.0.0.1
listen: 127.0.0.1:7224
cluster {
host: 127.0.0.1
port: 7246
listen: 127.0.0.1:7246
authorization {
user: ruser

View File

@@ -2,8 +2,7 @@
# Cluster Server B
host: 127.0.0.1
port: 7224
listen: 127.0.0.1:7224
authorization {
user: user
@@ -12,8 +11,7 @@ authorization {
}
cluster {
host: 127.0.0.1
port: 7246
listen: 127.0.0.1:7246
authorization {
user: ruser

View File

@@ -1,10 +1,9 @@
# Simple config file
port: 4242
net: localhost
listen: localhost:4242
http_port: 8222
http: 8222
authorization {
user: derek

View File

@@ -1,8 +1,7 @@
# Simple TLS config file
port: 4443
net: localhost
listen: localhost:4443
tls {
cert_file: "./configs/certs/server.pem"

View File

@@ -1,8 +1,7 @@
# Simple TLS config file
port: 4443
net: localhost
listen: localhost:4443
tls {
cert_file: "./configs/certs/server.pem"

View File

@@ -1,8 +1,7 @@
# Simple TLS config file
port: 4443
net: localhost
listen: localhost:4443
tls {
cert_file: "./configs/certs/server.pem"

View File

@@ -1,8 +1,7 @@
# Simple TLS config file
port: 4443
net: localhost
listen: localhost:4443
tls {
cert_file: "./configs/certs/server.pem"

View File

@@ -0,0 +1,9 @@
# Simple TLS config file
listen: localhost:4443
tls {
cert_file: "./configs/certs/server.pem"
key_file: "./configs/certs/key.pem"
}

View File

@@ -23,6 +23,7 @@ const CLUSTER_PORT = 12444
var DefaultMonitorOptions = Options{
Host: "localhost",
Port: CLIENT_PORT,
HTTPHost: "127.0.0.1",
HTTPPort: MONITOR_PORT,
ClusterHost: "localhost",
ClusterPort: CLUSTER_PORT,

View File

@@ -32,6 +32,7 @@ type Options struct {
Authorization string `json:"-"`
PingInterval time.Duration `json:"ping_interval"`
MaxPingsOut int `json:"ping_max"`
HTTPHost string `json:"http_host"`
HTTPPort int `json:"http_port"`
HTTPSPort int `json:"https_port"`
AuthTimeout float64 `json:"auth_timeout"`
@@ -120,6 +121,13 @@ func ProcessConfigFile(configFile string) (*Options, error) {
for k, v := range m {
switch strings.ToLower(k) {
case "listen":
hp, err := parseListen(v)
if err != nil {
return nil, err
}
opts.Host = hp.host
opts.Port = hp.port
case "port":
opts.Port = int(v.(int64))
case "host", "net":
@@ -136,6 +144,20 @@ func ProcessConfigFile(configFile string) (*Options, error) {
opts.Username = auth.user
opts.Password = auth.pass
opts.AuthTimeout = auth.timeout
case "http":
hp, err := parseListen(v)
if err != nil {
return nil, err
}
opts.HTTPHost = hp.host
opts.HTTPPort = hp.port
case "https":
hp, err := parseListen(v)
if err != nil {
return nil, err
}
opts.HTTPHost = hp.host
opts.HTTPSPort = hp.port
case "http_port", "monitor_port":
opts.HTTPPort = int(v.(int64))
case "https_port":
@@ -178,10 +200,44 @@ func ProcessConfigFile(configFile string) (*Options, error) {
return opts, nil
}
// hostPort is simple struct to hold parsed listen/addr strings.
type hostPort struct {
host string
port int
}
// parseListen will parse listen option which is replacing host/net and port
func parseListen(v interface{}) (*hostPort, error) {
hp := &hostPort{}
switch v.(type) {
// Only a port
case int64:
hp.port = int(v.(int64))
case string:
host, port, err := net.SplitHostPort(v.(string))
if err != nil {
return nil, fmt.Errorf("Could not parse address string %q", v)
}
hp.port, err = strconv.Atoi(port)
if err != nil {
return nil, fmt.Errorf("Could not parse port %q", port)
}
hp.host = host
}
return hp, nil
}
// parseCluster will parse the cluster config.
func parseCluster(cm map[string]interface{}, opts *Options) error {
for mk, mv := range cm {
switch strings.ToLower(mk) {
case "listen":
hp, err := parseListen(mv)
if err != nil {
return err
}
opts.ClusterHost = hp.host
opts.ClusterPort = hp.port
case "port":
opts.ClusterPort = int(mv.(int64))
case "host", "net":

View File

@@ -1,4 +1,4 @@
// Copyright 2013-2015 Apcera Inc. All rights reserved.
// Copyright 2013-2016 Apcera Inc. All rights reserved.
package server
@@ -308,3 +308,84 @@ func TestRouteFlagOverrideWithMultiple(t *testing.T) {
golden, merged)
}
}
func TestListenConfig(t *testing.T) {
opts, err := ProcessConfigFile("./configs/listen.conf")
if err != nil {
t.Fatalf("Received an error reading config file: %v\n", err)
}
processOptions(opts)
// Normal clients
host := "10.0.1.22"
port := 4422
if opts.Host != host {
t.Fatalf("Received incorrect host %q, expected %q\n", opts.Host, host)
}
if opts.Port != port {
t.Fatalf("Received incorrect port %v, expected %v\n", opts.Port, port)
}
// Clustering
clusterHost := "127.0.0.1"
clusterPort := 4244
if opts.ClusterHost != clusterHost {
t.Fatalf("Received incorrect cluster host %q, expected %q\n", opts.ClusterHost, clusterHost)
}
if opts.ClusterPort != clusterPort {
t.Fatalf("Received incorrect cluster port %v, expected %v\n", opts.ClusterPort, clusterPort)
}
// HTTP
httpHost := "127.0.0.1"
httpPort := 8422
if opts.HTTPHost != httpHost {
t.Fatalf("Received incorrect http host %q, expected %q\n", opts.HTTPHost, httpHost)
}
if opts.HTTPPort != httpPort {
t.Fatalf("Received incorrect http port %v, expected %v\n", opts.HTTPPort, httpPort)
}
// HTTPS
httpsPort := 9443
if opts.HTTPSPort != httpsPort {
t.Fatalf("Received incorrect https port %v, expected %v\n", opts.HTTPSPort, httpsPort)
}
}
func TestListenPortOnlyConfig(t *testing.T) {
opts, err := ProcessConfigFile("./configs/listen_port.conf")
if err != nil {
t.Fatalf("Received an error reading config file: %v\n", err)
}
processOptions(opts)
port := 8922
if opts.Host != DEFAULT_HOST {
t.Fatalf("Received incorrect host %q, expected %q\n", opts.Host, DEFAULT_HOST)
}
if opts.Port != port {
t.Fatalf("Received incorrect port %v, expected %v\n", opts.Port, port)
}
}
func TestListenPortWithColonConfig(t *testing.T) {
opts, err := ProcessConfigFile("./configs/listen_port_with_colon.conf")
if err != nil {
t.Fatalf("Received an error reading config file: %v\n", err)
}
processOptions(opts)
port := 8922
if opts.Host != DEFAULT_HOST {
t.Fatalf("Received incorrect host %q, expected %q\n", opts.Host, DEFAULT_HOST)
}
if opts.Port != port {
t.Fatalf("Received incorrect port %v, expected %v\n", opts.Port, port)
}
}

View File

@@ -445,14 +445,14 @@ func (s *Server) startMonitoring(secure bool) {
var err error
if secure {
hp = net.JoinHostPort(s.opts.Host, strconv.Itoa(s.opts.HTTPSPort))
hp = net.JoinHostPort(s.opts.HTTPHost, strconv.Itoa(s.opts.HTTPSPort))
Noticef("Starting https monitor on %s", hp)
config := *s.opts.TLSConfig
config.ClientAuth = tls.NoClientCert
s.http, err = tls.Listen("tcp", hp, &config)
} else {
hp = net.JoinHostPort(s.opts.Host, strconv.Itoa(s.opts.HTTPPort))
hp = net.JoinHostPort(s.opts.HTTPHost, strconv.Itoa(s.opts.HTTPPort))
Noticef("Starting http monitor on %s", hp)
s.http, err = net.Listen("tcp", hp)
}

View File

@@ -2,14 +2,12 @@
# Cluster Seed Node
port: 4222
net: 127.0.0.1
listen: 127.0.0.1:4222
http_port: 8222
http: 8222
cluster {
host: '127.0.0.1'
port: 4248
listen: 127.0.0.1:4248
authorization {
user: ruser

View File

@@ -2,12 +2,10 @@
# Cluster config file
host: 127.0.0.1
port: 4242
listen: 127.0.0.1:4242
cluster {
host: '127.0.0.1'
port: 4244
listen: 127.0.0.1:4244
authorization {
user: route_user

View File

@@ -2,8 +2,7 @@
# Config file to test overrides to client
host: 127.0.0.1
port: 4224
listen: 127.0.0.1:4224
# maximum payload
max_payload: 2222

View File

@@ -2,12 +2,10 @@
# Cluster Seed Node
port: 4222
net: 127.0.0.1
listen: 127.0.0.1:4222
http_port: 8222
http: 8222
cluster {
host: 127.0.0.1
port: 4248
listen: 127.0.0.1:4248
}

View File

@@ -2,12 +2,10 @@
# Cluster Server A
port: 4222
net: 127.0.0.1
listen: 127.0.0.1:4222
cluster {
host: '127.0.0.1'
port: 4244
listen: 127.0.0.1:4244
authorization {
user: ruser

View File

@@ -2,12 +2,10 @@
# Cluster Server A
host: 127.0.0.1
port: 4222
listen: 127.0.0.1:4222
cluster {
host: 127.0.0.1
port: 4244
listen: 127.0.0.1:4244
tls {
# Route cert

View File

@@ -2,12 +2,10 @@
# Cluster Server B
port: 4224
net: 127.0.0.1
listen: 127.0.0.1:4224
cluster {
host: 127.0.0.1
port: 4246
listen: 127.0.0.1:4246
authorization {
user: ruser

View File

@@ -2,12 +2,10 @@
# Cluster Server B
host: 127.0.0.1
port: 4224
listen: 127.0.0.1:4224
cluster {
host: 127.0.0.1
port: 4246
listen: 127.0.0.1:4246
tls {
# Route cert

View File

@@ -1,10 +1,9 @@
# Simple TLS config file
port: 4443
net: localhost
listen: localhost:4443
https_port: 11522
https: 11522
tls {
# Server cert

View File

@@ -1,8 +1,7 @@
# Simple TLS config file
port: 4443
net: localhost
listen: localhost:4443
tls {
# Server cert

View File

@@ -25,6 +25,7 @@ func runMonitorServer() *server.Server {
opts := DefaultTestOptions
opts.Port = CLIENT_PORT
opts.HTTPPort = MONITOR_PORT
opts.HTTPHost = "localhost"
return RunServer(&opts)
}
@@ -450,6 +451,40 @@ func TestSubsz(t *testing.T) {
}
}
func TestHTTPHost(t *testing.T) {
s := runMonitorServer()
defer s.Shutdown()
// Grab non-localhost address and try to use that to connect.
// Should fail.
var ip net.IP
ifaces, _ := net.Interfaces()
for _, i := range ifaces {
addrs, _ := i.Addrs()
for _, addr := range addrs {
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
// Skip loopback/localhost or any ipv6 for now.
if ip.IsLoopback() || ip.To4() == nil {
ip = nil
continue
}
break
}
}
if ip == nil {
t.Fatalf("Could not find non-loopback IPV4 address")
}
url := fmt.Sprintf("http://%v:%d/", ip, MONITOR_PORT)
if resp, err := http.Get(url + "varz"); err == nil {
t.Fatalf("Expected error: Got %+v\n", resp)
}
}
// Create a connection to test ConnInfo
func createClientConnSubscribeAndPublish(t *testing.T) net.Conn {
cl := createClientConn(t, "localhost", CLIENT_PORT)

View File

@@ -1,10 +1,8 @@
// Copyright 2015 Apcera Inc. All rights reserved.
// Copyright 2015-2016 Apcera Inc. All rights reserved.
package test
import (
"testing"
)
import "testing"
func TestServerConfig(t *testing.T) {
srv, opts := RunServerWithConfig("./configs/override.conf")