mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-02 11:48:43 -07:00
299 lines
9.7 KiB
Go
299 lines
9.7 KiB
Go
// Copyright 2012-2016 Apcera Inc. All rights reserved.
|
|
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"net"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/nats-io/gnatsd/auth"
|
|
"github.com/nats-io/gnatsd/logger"
|
|
"github.com/nats-io/gnatsd/server"
|
|
)
|
|
|
|
var usageStr = `
|
|
Usage: gnatsd [options]
|
|
|
|
Server Options:
|
|
-a, --addr <host> Bind to host address (default: 0.0.0.0)
|
|
-p, --port <port> Use port for clients (default: 4222)
|
|
-P, --pid <file> File to store PID
|
|
-m, --http_port <port> Use port for http monitoring
|
|
-ms,--https_port <port> Use port for https monitoring
|
|
-c, --config <file> Configuration file
|
|
|
|
Logging Options:
|
|
-l, --log <file> File to redirect log output
|
|
-T, --logtime Timestamp log entries (default: true)
|
|
-s, --syslog Enable syslog as log method
|
|
-r, --remote_syslog <addr> Syslog server addr (udp://localhost:514)
|
|
-D, --debug Enable debugging output
|
|
-V, --trace Trace the raw protocol
|
|
-DV Debug and trace
|
|
|
|
Authorization Options:
|
|
--user <user> User required for connections
|
|
--pass <password> Password required for connections
|
|
--auth <token> Authorization token required for connections
|
|
|
|
TLS Options:
|
|
--tls Enable TLS, do not verify clients (default: false)
|
|
--tlscert <file> Server certificate file
|
|
--tlskey <file> Private key for server certificate
|
|
--tlsverify Enable TLS, very client certificates
|
|
--tlscacert <file> Client certificate CA for verification
|
|
|
|
Cluster Options:
|
|
--routes <rurl-1, rurl-2> Routes to solicit and connect
|
|
--cluster <cluster-url> Cluster URL for solicited routes
|
|
|
|
Common Options:
|
|
-h, --help Show this message
|
|
-v, --version Show version
|
|
--help_tls TLS help
|
|
`
|
|
|
|
// usage will print out the flag options for the server.
|
|
func usage() {
|
|
fmt.Printf("%s\n", usageStr)
|
|
os.Exit(0)
|
|
}
|
|
|
|
func main() {
|
|
// Server Options
|
|
opts := server.Options{}
|
|
|
|
var showVersion bool
|
|
var debugAndTrace bool
|
|
var configFile string
|
|
var showTLSHelp bool
|
|
|
|
// Parse flags
|
|
flag.IntVar(&opts.Port, "port", 0, "Port to listen on.")
|
|
flag.IntVar(&opts.Port, "p", 0, "Port to listen on.")
|
|
flag.StringVar(&opts.Host, "addr", "", "Network host to listen on.")
|
|
flag.StringVar(&opts.Host, "a", "", "Network host to listen on.")
|
|
flag.StringVar(&opts.Host, "net", "", "Network host to listen on.")
|
|
flag.BoolVar(&opts.Debug, "D", false, "Enable Debug logging.")
|
|
flag.BoolVar(&opts.Debug, "debug", false, "Enable Debug logging.")
|
|
flag.BoolVar(&opts.Trace, "V", false, "Enable Trace logging.")
|
|
flag.BoolVar(&opts.Trace, "trace", false, "Enable Trace logging.")
|
|
flag.BoolVar(&debugAndTrace, "DV", false, "Enable Debug and Trace logging.")
|
|
flag.BoolVar(&opts.Logtime, "T", true, "Timestamp log entries.")
|
|
flag.BoolVar(&opts.Logtime, "logtime", true, "Timestamp log entries.")
|
|
flag.StringVar(&opts.Username, "user", "", "Username required for connection.")
|
|
flag.StringVar(&opts.Password, "pass", "", "Password required for connection.")
|
|
flag.StringVar(&opts.Authorization, "auth", "", "Authorization token required for connection.")
|
|
flag.IntVar(&opts.HTTPPort, "m", 0, "HTTP Port for /varz, /connz endpoints.")
|
|
flag.IntVar(&opts.HTTPPort, "http_port", 0, "HTTP Port for /varz, /connz endpoints.")
|
|
flag.IntVar(&opts.HTTPSPort, "ms", 0, "HTTPS Port for /varz, /connz endpoints.")
|
|
flag.IntVar(&opts.HTTPSPort, "https_port", 0, "HTTPS Port for /varz, /connz endpoints.")
|
|
flag.StringVar(&configFile, "c", "", "Configuration file.")
|
|
flag.StringVar(&configFile, "config", "", "Configuration file.")
|
|
flag.StringVar(&opts.PidFile, "P", "", "File to store process pid.")
|
|
flag.StringVar(&opts.PidFile, "pid", "", "File to store process pid.")
|
|
flag.StringVar(&opts.LogFile, "l", "", "File to store logging output.")
|
|
flag.StringVar(&opts.LogFile, "log", "", "File to store logging output.")
|
|
flag.BoolVar(&opts.Syslog, "s", false, "Enable syslog as log method.")
|
|
flag.BoolVar(&opts.Syslog, "syslog", false, "Enable syslog as log method..")
|
|
flag.StringVar(&opts.RemoteSyslog, "r", "", "Syslog server addr (udp://localhost:514).")
|
|
flag.StringVar(&opts.RemoteSyslog, "remote_syslog", "", "Syslog server addr (udp://localhost:514).")
|
|
flag.BoolVar(&showVersion, "version", false, "Print version information.")
|
|
flag.BoolVar(&showVersion, "v", false, "Print version information.")
|
|
flag.IntVar(&opts.ProfPort, "profile", 0, "Profiling HTTP port")
|
|
flag.StringVar(&opts.RoutesStr, "routes", "", "Routes to actively solicit a connection.")
|
|
flag.StringVar(&opts.ClusterListenStr, "cluster", "", "Cluster url from which members can solicit routes.")
|
|
flag.StringVar(&opts.ClusterListenStr, "cluster_listen", "", "Cluster url from which members can solicit routes.")
|
|
flag.BoolVar(&showTLSHelp, "help_tls", false, "TLS help.")
|
|
flag.BoolVar(&opts.TLS, "tls", false, "Enable TLS.")
|
|
flag.BoolVar(&opts.TLSVerify, "tlsverify", false, "Enable TLS with client verification.")
|
|
flag.StringVar(&opts.TLSCert, "tlscert", "", "Server certificate file.")
|
|
flag.StringVar(&opts.TLSKey, "tlskey", "", "Private key for server certificate.")
|
|
flag.StringVar(&opts.TLSCaCert, "tlscacert", "", "Client certificate CA for verification.")
|
|
|
|
flag.Usage = usage
|
|
|
|
flag.Parse()
|
|
|
|
// Show version and exit
|
|
if showVersion {
|
|
server.PrintServerAndExit()
|
|
}
|
|
|
|
if showTLSHelp {
|
|
server.PrintTLSHelpAndDie()
|
|
}
|
|
|
|
// One flag can set multiple options.
|
|
if debugAndTrace {
|
|
opts.Trace, opts.Debug = true, true
|
|
}
|
|
|
|
// Process args looking for non-flag options,
|
|
// 'version' and 'help' only for now
|
|
for _, arg := range flag.Args() {
|
|
switch strings.ToLower(arg) {
|
|
case "version":
|
|
server.PrintServerAndExit()
|
|
case "help":
|
|
usage()
|
|
}
|
|
}
|
|
|
|
// Parse config if given
|
|
if configFile != "" {
|
|
fileOpts, err := server.ProcessConfigFile(configFile)
|
|
if err != nil {
|
|
server.PrintAndDie(err.Error())
|
|
}
|
|
opts = *server.MergeOptions(fileOpts, &opts)
|
|
}
|
|
|
|
// Remove any host/ip that points to itself in Route
|
|
newroutes, err := server.RemoveSelfReference(opts.ClusterPort, opts.Routes)
|
|
if err != nil {
|
|
server.PrintAndDie(err.Error())
|
|
}
|
|
opts.Routes = newroutes
|
|
|
|
// Configure TLS based on any present flags
|
|
configureTLS(&opts)
|
|
|
|
// Configure cluster opts if explicitly set via flags.
|
|
err = configureClusterOpts(&opts)
|
|
if err != nil {
|
|
server.PrintAndDie(err.Error())
|
|
}
|
|
|
|
// Create the server with appropriate options.
|
|
s := server.New(&opts)
|
|
|
|
// Configure the authentication mechanism
|
|
configureAuth(s, &opts)
|
|
|
|
// Configure the logger based on the flags
|
|
configureLogger(s, &opts)
|
|
|
|
// Start things up. Block here until done.
|
|
s.Start()
|
|
}
|
|
|
|
func configureAuth(s *server.Server, opts *server.Options) {
|
|
// Client
|
|
// Check for multiple users first
|
|
if opts.Users != nil {
|
|
auth := auth.NewMultiUser(opts.Users)
|
|
s.SetClientAuthMethod(auth)
|
|
} else if opts.Username != "" {
|
|
auth := &auth.Plain{
|
|
Username: opts.Username,
|
|
Password: opts.Password,
|
|
}
|
|
s.SetClientAuthMethod(auth)
|
|
} else if opts.Authorization != "" {
|
|
auth := &auth.Token{
|
|
Token: opts.Authorization,
|
|
}
|
|
s.SetClientAuthMethod(auth)
|
|
}
|
|
// Routes
|
|
if opts.ClusterUsername != "" {
|
|
auth := &auth.Plain{
|
|
Username: opts.ClusterUsername,
|
|
Password: opts.ClusterPassword,
|
|
}
|
|
s.SetRouteAuthMethod(auth)
|
|
}
|
|
}
|
|
|
|
func configureLogger(s *server.Server, opts *server.Options) {
|
|
var log server.Logger
|
|
|
|
if opts.LogFile != "" {
|
|
log = logger.NewFileLogger(opts.LogFile, opts.Logtime, opts.Debug, opts.Trace, true)
|
|
} else if opts.RemoteSyslog != "" {
|
|
log = logger.NewRemoteSysLogger(opts.RemoteSyslog, opts.Debug, opts.Trace)
|
|
} else if opts.Syslog {
|
|
log = logger.NewSysLogger(opts.Debug, opts.Trace)
|
|
} else {
|
|
colors := true
|
|
// Check to see if stderr is being redirected and if so turn off color
|
|
// Also turn off colors if we're running on Windows where os.Stderr.Stat() returns an invalid handle-error
|
|
stat, err := os.Stderr.Stat()
|
|
if err != nil || (stat.Mode()&os.ModeCharDevice) == 0 {
|
|
colors = false
|
|
}
|
|
log = logger.NewStdLogger(opts.Logtime, opts.Debug, opts.Trace, colors, true)
|
|
}
|
|
|
|
s.SetLogger(log, opts.Debug, opts.Trace)
|
|
}
|
|
|
|
func configureTLS(opts *server.Options) {
|
|
// If no trigger flags, ignore the others
|
|
if !opts.TLS && !opts.TLSVerify {
|
|
return
|
|
}
|
|
if opts.TLSCert == "" {
|
|
server.PrintAndDie("TLS Server certificate must be present and valid.")
|
|
}
|
|
if opts.TLSKey == "" {
|
|
server.PrintAndDie("TLS Server private key must be present and valid.")
|
|
}
|
|
|
|
tc := server.TLSConfigOpts{}
|
|
tc.CertFile = opts.TLSCert
|
|
tc.KeyFile = opts.TLSKey
|
|
tc.CaFile = opts.TLSCaCert
|
|
|
|
if opts.TLSVerify {
|
|
tc.Verify = true
|
|
}
|
|
var err error
|
|
if opts.TLSConfig, err = server.GenTLSConfig(&tc); err != nil {
|
|
server.PrintAndDie(err.Error())
|
|
}
|
|
}
|
|
|
|
func configureClusterOpts(opts *server.Options) error {
|
|
if opts.ClusterListenStr == "" {
|
|
if opts.RoutesStr != "" {
|
|
server.PrintAndDie("Solicited routes require cluster capabilities, e.g. --cluster.")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
clusterURL, err := url.Parse(opts.ClusterListenStr)
|
|
h, p, err := net.SplitHostPort(clusterURL.Host)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
opts.ClusterHost = h
|
|
_, err = fmt.Sscan(p, &opts.ClusterPort)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if clusterURL.User != nil {
|
|
pass, hasPassword := clusterURL.User.Password()
|
|
if !hasPassword {
|
|
return fmt.Errorf("Expected cluster password to be set.")
|
|
}
|
|
opts.ClusterPassword = pass
|
|
|
|
user := clusterURL.User.Username()
|
|
opts.ClusterUsername = user
|
|
}
|
|
|
|
// If we have routes but no config file, fill in here.
|
|
if opts.RoutesStr != "" && opts.Routes == nil {
|
|
opts.Routes = server.RoutesFromStr(opts.RoutesStr)
|
|
}
|
|
|
|
return nil
|
|
}
|