2014-12-06 01:02:30 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2015-03-25 16:49:05 +00:00
|
|
|
"flag"
|
2015-02-12 00:10:18 +00:00
|
|
|
"fmt"
|
2014-12-06 01:02:30 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
2015-02-03 16:51:05 +00:00
|
|
|
"net"
|
2014-12-06 01:02:30 +00:00
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2015-03-25 16:49:05 +00:00
|
|
|
"runtime"
|
2014-12-06 01:02:30 +00:00
|
|
|
"strconv"
|
2014-12-16 07:03:09 +00:00
|
|
|
"strings"
|
2015-02-10 21:41:55 +00:00
|
|
|
"time"
|
2014-12-06 01:02:30 +00:00
|
|
|
|
|
|
|
"github.com/influxdb/influxdb"
|
2015-02-11 07:03:23 +00:00
|
|
|
"github.com/influxdb/influxdb/admin"
|
2015-01-09 00:09:28 +00:00
|
|
|
"github.com/influxdb/influxdb/collectd"
|
2014-12-31 21:37:58 +00:00
|
|
|
"github.com/influxdb/influxdb/graphite"
|
2014-12-06 01:02:30 +00:00
|
|
|
"github.com/influxdb/influxdb/messaging"
|
2015-03-29 16:26:03 +00:00
|
|
|
"github.com/influxdb/influxdb/opentsdb"
|
2015-03-10 20:53:45 +00:00
|
|
|
"github.com/influxdb/influxdb/raft"
|
2015-03-04 20:31:39 +00:00
|
|
|
"github.com/influxdb/influxdb/udp"
|
2014-12-06 01:02:30 +00:00
|
|
|
)
|
|
|
|
|
2015-03-25 16:49:05 +00:00
|
|
|
type RunCommand struct {
|
2015-03-25 16:59:15 +00:00
|
|
|
// The logger passed to the ticker during execution.
|
2015-03-25 20:27:20 +00:00
|
|
|
logWriter *os.File
|
|
|
|
config *Config
|
|
|
|
hostname string
|
2015-04-06 21:18:40 +00:00
|
|
|
node *Node
|
2015-03-25 16:49:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewRunCommand() *RunCommand {
|
2015-03-26 21:54:10 +00:00
|
|
|
return &RunCommand{
|
2015-04-06 21:18:40 +00:00
|
|
|
node: &Node{},
|
2015-03-26 21:54:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-06 21:18:40 +00:00
|
|
|
type Node struct {
|
2015-04-07 18:08:27 +00:00
|
|
|
Broker *influxdb.Broker
|
|
|
|
DataNode *influxdb.Server
|
2015-03-26 21:54:10 +00:00
|
|
|
raftLog *raft.Log
|
2015-04-07 20:36:18 +00:00
|
|
|
|
2015-04-13 20:00:41 +00:00
|
|
|
adminServer *admin.Server
|
|
|
|
clusterListener net.Listener // The cluster TCP listener
|
2015-04-13 21:21:56 +00:00
|
|
|
apiListener net.Listener // The API TCP listener
|
2015-03-25 16:49:05 +00:00
|
|
|
}
|
|
|
|
|
2015-04-10 02:41:06 +00:00
|
|
|
func (s *Node) Close() error {
|
2015-04-07 20:36:18 +00:00
|
|
|
if err := s.closeClusterListener(); err != nil {
|
2015-04-10 02:41:06 +00:00
|
|
|
return err
|
2015-04-07 20:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-04-13 21:21:56 +00:00
|
|
|
if err := s.closeAPIListener(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-04-09 16:53:51 +00:00
|
|
|
if err := s.closeAdminServer(); err != nil {
|
2015-04-10 02:41:06 +00:00
|
|
|
return err
|
2015-04-09 16:53:51 +00:00
|
|
|
}
|
|
|
|
|
2015-04-07 20:36:18 +00:00
|
|
|
if s.DataNode != nil {
|
|
|
|
if err := s.DataNode.Close(); err != nil {
|
2015-04-10 02:41:06 +00:00
|
|
|
return err
|
2015-04-07 20:36:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-07 18:08:27 +00:00
|
|
|
if s.Broker != nil {
|
|
|
|
if err := s.Broker.Close(); err != nil {
|
2015-04-10 02:41:06 +00:00
|
|
|
return err
|
2015-03-26 23:04:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.raftLog != nil {
|
|
|
|
if err := s.raftLog.Close(); err != nil {
|
2015-04-10 02:41:06 +00:00
|
|
|
return err
|
2015-03-26 23:04:12 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-10 02:41:06 +00:00
|
|
|
return nil
|
2015-04-07 20:36:18 +00:00
|
|
|
}
|
2015-03-26 23:04:12 +00:00
|
|
|
|
2015-04-09 16:53:51 +00:00
|
|
|
func (s *Node) openAdminServer(port int) error {
|
|
|
|
// Start the admin interface on the default port
|
|
|
|
addr := net.JoinHostPort("", strconv.Itoa(port))
|
|
|
|
s.adminServer = admin.NewServer(addr)
|
|
|
|
return s.adminServer.ListenAndServe()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Node) closeAdminServer() error {
|
|
|
|
if s.adminServer != nil {
|
|
|
|
return s.adminServer.Close()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-04-13 21:21:56 +00:00
|
|
|
func (s *Node) openListener(desc, addr string, h http.Handler) (net.Listener, error) {
|
2015-04-07 20:36:18 +00:00
|
|
|
var err error
|
|
|
|
listener, err := net.Listen("tcp", addr)
|
|
|
|
if err != nil {
|
2015-04-13 21:21:56 +00:00
|
|
|
return nil, err
|
2015-03-26 23:04:12 +00:00
|
|
|
}
|
2015-04-07 20:36:18 +00:00
|
|
|
go func() {
|
2015-04-13 21:21:56 +00:00
|
|
|
err := http.Serve(listener, h)
|
2015-04-07 20:36:18 +00:00
|
|
|
|
|
|
|
// The listener was closed so exit
|
|
|
|
// See https://github.com/golang/go/issues/4373
|
|
|
|
if operr, ok := err.(*net.OpError); ok && strings.Contains(operr.Err.Error(), "closed network connection") {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if err != nil {
|
2015-04-13 21:21:56 +00:00
|
|
|
log.Fatalf("%s server failed to serve on %s: %s", desc, addr, err)
|
2015-04-07 20:36:18 +00:00
|
|
|
}
|
|
|
|
}()
|
2015-04-13 21:21:56 +00:00
|
|
|
return listener, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Node) openAPIListener(addr string, h http.Handler) error {
|
|
|
|
var err error
|
|
|
|
s.apiListener, err = s.openListener("API", addr, h)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Node) closeAPIListener() error {
|
|
|
|
var err error
|
|
|
|
if s.apiListener != nil {
|
|
|
|
err = s.apiListener.Close()
|
|
|
|
s.apiListener = nil
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Node) openClusterListener(addr string, h http.Handler) error {
|
|
|
|
var err error
|
|
|
|
s.clusterListener, err = s.openListener("Cluster", addr, h)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-04-07 20:36:18 +00:00
|
|
|
return nil
|
|
|
|
}
|
2015-03-26 23:04:12 +00:00
|
|
|
|
2015-04-07 20:36:18 +00:00
|
|
|
func (s *Node) closeClusterListener() error {
|
|
|
|
var err error
|
|
|
|
if s.clusterListener != nil {
|
|
|
|
err = s.clusterListener.Close()
|
|
|
|
s.clusterListener = nil
|
|
|
|
}
|
|
|
|
return err
|
2015-03-26 23:04:12 +00:00
|
|
|
}
|
|
|
|
|
2015-04-13 16:45:39 +00:00
|
|
|
func (cmd *RunCommand) ParseConfig(path, hostname string) error {
|
|
|
|
var err error
|
2015-03-25 16:59:15 +00:00
|
|
|
|
2015-04-13 16:45:39 +00:00
|
|
|
// Parse configuration file from disk.
|
|
|
|
if path != "" {
|
|
|
|
cmd.config, err = ParseConfigFile(path)
|
|
|
|
|
|
|
|
if err != nil {
|
2015-04-13 22:27:43 +00:00
|
|
|
return fmt.Errorf("error parsing configuration %s - %s\n", path, err)
|
2015-04-13 16:45:39 +00:00
|
|
|
}
|
|
|
|
// Override config properties.
|
|
|
|
if hostname != "" {
|
|
|
|
cmd.config.Hostname = hostname
|
|
|
|
}
|
|
|
|
|
2015-04-13 22:27:43 +00:00
|
|
|
log.Printf("using configuration at: %s\n", path)
|
2015-04-13 16:45:39 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.config, err = NewTestConfig()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error parsing default config: %s\n", err)
|
|
|
|
}
|
2015-04-15 15:52:23 +00:00
|
|
|
// Override config properties.
|
|
|
|
if hostname != "" {
|
|
|
|
cmd.config.Hostname = hostname
|
|
|
|
}
|
2015-04-13 22:27:43 +00:00
|
|
|
log.Println("no configuration provided, using default settings")
|
2015-04-13 16:45:39 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *RunCommand) Run(args ...string) error {
|
2015-03-25 16:49:05 +00:00
|
|
|
// Parse command flags.
|
|
|
|
fs := flag.NewFlagSet("", flag.ExitOnError)
|
2015-03-25 20:31:25 +00:00
|
|
|
var configPath, pidfile, hostname, join, cpuprofile, memprofile string
|
|
|
|
|
|
|
|
fs.StringVar(&configPath, "config", "", "")
|
|
|
|
fs.StringVar(&pidfile, "pidfile", "", "")
|
|
|
|
fs.StringVar(&hostname, "hostname", "", "")
|
|
|
|
fs.StringVar(&join, "join", "", "")
|
|
|
|
fs.StringVar(&cpuprofile, "cpuprofile", "", "")
|
|
|
|
fs.StringVar(&memprofile, "memprofile", "", "")
|
|
|
|
|
2015-03-25 16:49:05 +00:00
|
|
|
fs.Usage = printRunUsage
|
|
|
|
fs.Parse(args)
|
2015-03-25 20:31:25 +00:00
|
|
|
cmd.hostname = hostname
|
2015-03-25 16:49:05 +00:00
|
|
|
|
|
|
|
// Start profiling, if set.
|
2015-03-25 20:31:25 +00:00
|
|
|
startProfiling(cpuprofile, memprofile)
|
2015-03-25 16:49:05 +00:00
|
|
|
defer stopProfiling()
|
|
|
|
|
|
|
|
// Print sweet InfluxDB logo and write the process id to file.
|
|
|
|
fmt.Print(logo)
|
2015-03-25 20:31:25 +00:00
|
|
|
writePIDFile(pidfile)
|
2015-03-25 16:49:05 +00:00
|
|
|
|
|
|
|
// Set parallelism.
|
|
|
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
|
|
|
log.Printf("GOMAXPROCS set to %d", runtime.GOMAXPROCS(0))
|
|
|
|
|
2015-04-13 16:45:39 +00:00
|
|
|
// Parse config
|
|
|
|
if err := cmd.ParseConfig(configPath, hostname); err != nil {
|
|
|
|
log.Fatal(err)
|
2015-03-25 16:49:05 +00:00
|
|
|
}
|
|
|
|
|
2015-04-08 17:09:48 +00:00
|
|
|
// Use the config JoinURLs by default
|
|
|
|
joinURLs := cmd.config.Initialization.JoinURLs
|
|
|
|
|
|
|
|
// If a -join flag was passed, these should override the config
|
|
|
|
if join != "" {
|
|
|
|
joinURLs = join
|
|
|
|
}
|
2015-04-07 15:51:17 +00:00
|
|
|
cmd.CheckConfig()
|
2015-04-08 17:09:48 +00:00
|
|
|
cmd.Open(cmd.config, joinURLs)
|
2015-03-25 16:49:05 +00:00
|
|
|
|
|
|
|
// Wait indefinitely.
|
|
|
|
<-(chan struct{})(nil)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-04-07 15:51:17 +00:00
|
|
|
// CheckConfig validates the configuration
|
|
|
|
func (cmd *RunCommand) CheckConfig() {
|
|
|
|
if !(cmd.config.Data.Enabled || cmd.config.Broker.Enabled) {
|
2015-04-13 16:45:39 +00:00
|
|
|
log.Fatal("Node must be configured as a broker node, data node, or as both. Run `influxd config` to generate a valid configuration.")
|
2015-04-07 15:51:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if cmd.config.Broker.Enabled && cmd.config.Broker.Dir == "" {
|
2015-04-13 16:45:39 +00:00
|
|
|
log.Fatal("Broker.Dir must be specified. Run `influxd config` to generate a valid configuration.")
|
2015-04-07 15:51:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if cmd.config.Data.Enabled && cmd.config.Data.Dir == "" {
|
2015-04-13 16:45:39 +00:00
|
|
|
log.Fatal("Data.Dir must be specified. Run `influxd config` to generate a valid configuration.")
|
2015-04-07 15:51:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-07 18:08:27 +00:00
|
|
|
func (cmd *RunCommand) Open(config *Config, join string) *Node {
|
2015-03-25 20:27:20 +00:00
|
|
|
if config != nil {
|
|
|
|
cmd.config = config
|
|
|
|
}
|
|
|
|
|
2015-02-24 17:47:07 +00:00
|
|
|
log.Printf("influxdb started, version %s, commit %s", version, commit)
|
|
|
|
|
2015-01-27 01:29:30 +00:00
|
|
|
// Parse join urls from the --join flag.
|
2015-04-03 19:49:54 +00:00
|
|
|
joinURLs := parseURLs(join)
|
2015-03-27 20:12:09 +00:00
|
|
|
|
2015-04-15 17:18:44 +00:00
|
|
|
// Start the broker handler.
|
|
|
|
h := &Handler{Config: config}
|
|
|
|
if err := cmd.node.openClusterListener(cmd.config.ClusterAddr(), h); err != nil {
|
|
|
|
log.Fatalf("Cluster server failed to listen on %s. %s ", cmd.config.ClusterAddr(), err)
|
|
|
|
}
|
|
|
|
log.Printf("Cluster server listening on %s", cmd.config.ClusterAddr())
|
|
|
|
|
2015-03-10 20:53:45 +00:00
|
|
|
// Open broker & raft log, initialize or join as necessary.
|
2015-03-26 23:04:12 +00:00
|
|
|
if cmd.config.Broker.Enabled {
|
2015-04-15 17:18:44 +00:00
|
|
|
cmd.openBroker(joinURLs, h)
|
2015-04-08 20:35:25 +00:00
|
|
|
// If were running as a broker locally, always connect to it since it must
|
|
|
|
// be ready before we can start the data node.
|
2015-04-07 18:08:27 +00:00
|
|
|
joinURLs = []url.URL{cmd.node.Broker.URL()}
|
2015-03-26 23:04:12 +00:00
|
|
|
}
|
2014-12-30 22:46:50 +00:00
|
|
|
|
2015-03-26 23:04:12 +00:00
|
|
|
var s *influxdb.Server
|
2015-01-07 00:21:32 +00:00
|
|
|
// Open server, initialize or join as necessary.
|
2015-03-26 23:04:12 +00:00
|
|
|
if cmd.config.Data.Enabled {
|
2015-03-27 20:12:09 +00:00
|
|
|
|
2015-03-26 23:04:12 +00:00
|
|
|
//FIXME: Need to also pass in dataURLs to bootstrap a data node
|
2015-04-03 19:49:54 +00:00
|
|
|
s = cmd.openServer(joinURLs)
|
Don't set data node until after it has joined or initialized
By setting it, data node requests can be served by the http handler
before the data node is actually ready.
Possible fix for:
2015/04/14 11:33:54 http: panic serving 10.0.1.8:62661: runtime error: invalid memory address or nil pointer dereference
goroutine 11467 [running]:
net/http.func·011()
/usr/local/go/src/net/http/server.go:1130 +0xcc
github.com/influxdb/influxdb.(*Server).broadcast(0xc20805cc00, 0xc208220000, 0x5d25e0, 0xc208869e80, 0x0, 0x0, 0x0)
/Users/jason/go/src/github.com/influxdb/influxdb/server.go:568 +0x227
github.com/influxdb/influxdb.(*Server).CreateDataNode(0xc20805cc00, 0xc2081c6e70, 0x0, 0x0)
/Users/jason/go/src/github.com/influxdb/influxdb/server.go:859 +0xe6
github.com/influxdb/influxdb/httpd.(*Handler).serveCreateDataNode(0xc20842ea00, 0x19378c0, 0xc2082207e0, 0xc2083191e0)
2015-04-14 18:03:55 +00:00
|
|
|
cmd.node.DataNode = s
|
2015-03-26 23:04:12 +00:00
|
|
|
s.SetAuthenticationEnabled(cmd.config.Authentication.Enabled)
|
2015-04-13 16:45:39 +00:00
|
|
|
log.Printf("authentication enabled: %v\n", cmd.config.Authentication.Enabled)
|
2015-03-26 23:04:12 +00:00
|
|
|
|
|
|
|
// Enable retention policy enforcement if requested.
|
|
|
|
if cmd.config.Data.RetentionCheckEnabled {
|
|
|
|
interval := time.Duration(cmd.config.Data.RetentionCheckPeriod)
|
|
|
|
if err := s.StartRetentionPolicyEnforcement(interval); err != nil {
|
|
|
|
log.Fatalf("retention policy enforcement failed: %s", err.Error())
|
|
|
|
}
|
|
|
|
log.Printf("broker enforcing retention policies with check interval of %s", interval)
|
2015-02-10 21:41:55 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 23:04:12 +00:00
|
|
|
// Start shard group pre-create
|
|
|
|
interval := cmd.config.ShardGroupPreCreateCheckPeriod()
|
|
|
|
if err := s.StartShardGroupsPreCreate(interval); err != nil {
|
|
|
|
log.Fatalf("shard group pre-create failed: %s", err.Error())
|
|
|
|
}
|
|
|
|
log.Printf("shard group pre-create with check interval of %s", interval)
|
2015-03-09 23:27:15 +00:00
|
|
|
}
|
|
|
|
|
2015-01-10 16:08:00 +00:00
|
|
|
// Start the server handler. Attach to broker if listening on the same port.
|
2015-01-07 00:21:32 +00:00
|
|
|
if s != nil {
|
2015-03-31 22:45:33 +00:00
|
|
|
h.Server = s
|
2015-03-26 23:09:48 +00:00
|
|
|
if config.Snapshot.Enabled {
|
2015-04-13 20:00:41 +00:00
|
|
|
log.Printf("snapshot server listening on %s", cmd.config.ClusterAddr())
|
2015-03-26 23:09:48 +00:00
|
|
|
} else {
|
2015-04-13 20:00:41 +00:00
|
|
|
log.Printf("snapshot server disabled")
|
2015-03-26 23:09:48 +00:00
|
|
|
}
|
2015-03-22 16:28:04 +00:00
|
|
|
|
2015-03-25 20:27:20 +00:00
|
|
|
if cmd.config.Admin.Enabled {
|
2015-04-09 16:53:51 +00:00
|
|
|
if err := cmd.node.openAdminServer(cmd.config.Admin.Port); err != nil {
|
|
|
|
log.Fatalf("admin server failed to listen on :%d: %s", cmd.config.Admin.Port, err)
|
|
|
|
}
|
|
|
|
log.Printf("admin server listening on :%d", cmd.config.Admin.Port)
|
2015-02-11 07:34:17 +00:00
|
|
|
}
|
2015-02-11 07:03:23 +00:00
|
|
|
|
2015-01-09 00:09:28 +00:00
|
|
|
// Spin up the collectd server
|
2015-03-25 20:27:20 +00:00
|
|
|
if cmd.config.Collectd.Enabled {
|
|
|
|
c := cmd.config.Collectd
|
2015-01-10 03:12:18 +00:00
|
|
|
cs := collectd.NewServer(s, c.TypesDB)
|
|
|
|
cs.Database = c.Database
|
2015-03-25 20:27:20 +00:00
|
|
|
err := collectd.ListenAndServe(cs, c.ConnectionString(cmd.config.BindAddress))
|
2015-01-09 00:09:28 +00:00
|
|
|
if err != nil {
|
2015-01-11 14:44:52 +00:00
|
|
|
log.Printf("failed to start collectd Server: %v\n", err.Error())
|
2015-01-09 00:09:28 +00:00
|
|
|
}
|
|
|
|
}
|
2015-02-11 07:03:23 +00:00
|
|
|
|
2015-03-04 20:31:39 +00:00
|
|
|
// Start the server bound to a UDP listener
|
2015-03-25 20:27:20 +00:00
|
|
|
if cmd.config.UDP.Enabled {
|
2015-04-03 17:04:19 +00:00
|
|
|
log.Printf("Starting UDP listener on %s", cmd.config.APIAddrUDP())
|
2015-03-04 20:31:39 +00:00
|
|
|
u := udp.NewUDPServer(s)
|
2015-04-03 17:04:19 +00:00
|
|
|
if err := u.ListenAndServe(cmd.config.APIAddrUDP()); err != nil {
|
|
|
|
log.Printf("Failed to start UDP listener on %s: %s", cmd.config.APIAddrUDP(), err)
|
2015-03-04 20:31:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-01-06 22:26:31 +00:00
|
|
|
// Spin up any Graphite servers
|
2015-03-25 20:27:20 +00:00
|
|
|
for _, c := range cmd.config.Graphites {
|
2015-01-06 22:26:31 +00:00
|
|
|
if !c.Enabled {
|
|
|
|
continue
|
|
|
|
}
|
2015-01-02 16:09:11 +00:00
|
|
|
|
2015-01-07 07:18:14 +00:00
|
|
|
// Configure Graphite parsing.
|
|
|
|
parser := graphite.NewParser()
|
2015-01-08 00:15:39 +00:00
|
|
|
parser.Separator = c.NameSeparatorString()
|
2015-01-08 20:23:48 +00:00
|
|
|
parser.LastEnabled = c.LastEnabled()
|
2015-01-07 07:18:14 +00:00
|
|
|
|
2015-03-12 20:29:51 +00:00
|
|
|
if err := s.CreateDatabaseIfNotExists(c.DatabaseString()); err != nil {
|
|
|
|
log.Fatalf("failed to create database for %s Graphite server: %s", c.Protocol, err.Error())
|
|
|
|
}
|
|
|
|
|
2015-03-12 19:12:23 +00:00
|
|
|
// Spin up the server.
|
|
|
|
var g graphite.Server
|
2015-03-12 20:29:51 +00:00
|
|
|
g, err := graphite.NewServer(c.Protocol, parser, s, c.DatabaseString())
|
2015-03-12 19:12:23 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("failed to initialize %s Graphite server: %s", c.Protocol, err.Error())
|
|
|
|
}
|
2015-03-12 20:29:51 +00:00
|
|
|
|
2015-03-25 20:27:20 +00:00
|
|
|
err = g.ListenAndServe(c.ConnectionString(cmd.config.BindAddress))
|
2015-03-12 19:12:23 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("failed to start %s Graphite server: %s", c.Protocol, err.Error())
|
2015-01-06 03:14:43 +00:00
|
|
|
}
|
2015-01-02 16:09:11 +00:00
|
|
|
}
|
2015-03-12 23:23:33 +00:00
|
|
|
|
2015-03-29 16:26:03 +00:00
|
|
|
// Spin up any OpenTSDB servers
|
|
|
|
if config.OpenTSDB.Enabled {
|
|
|
|
o := config.OpenTSDB
|
|
|
|
db := o.DatabaseString()
|
|
|
|
laddr := o.ListenAddress(config.BindAddress)
|
|
|
|
policy := o.RetentionPolicy
|
|
|
|
|
|
|
|
if err := s.CreateDatabaseIfNotExists(db); err != nil {
|
|
|
|
log.Fatalf("failed to create database for OpenTSDB server: %s", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
if policy != "" {
|
|
|
|
// Ensure retention policy exists.
|
|
|
|
rp := influxdb.NewRetentionPolicy(policy)
|
|
|
|
if err := s.CreateRetentionPolicyIfNotExists(db, rp); err != nil {
|
|
|
|
log.Fatalf("failed to create retention policy for OpenTSDB: %s", err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
os := opentsdb.NewServer(s, policy, db)
|
|
|
|
|
2015-04-06 18:07:31 +00:00
|
|
|
log.Println("Starting OpenTSDB service on", laddr)
|
2015-03-29 16:26:03 +00:00
|
|
|
go os.ListenAndServe(laddr)
|
|
|
|
}
|
|
|
|
|
2015-03-12 23:23:33 +00:00
|
|
|
// Start up self-monitoring if enabled.
|
2015-03-25 20:27:20 +00:00
|
|
|
if cmd.config.Monitoring.Enabled {
|
2015-04-03 21:35:44 +00:00
|
|
|
database := monitoringDatabase
|
|
|
|
policy := monitoringRetentionPolicy
|
2015-03-25 20:27:20 +00:00
|
|
|
interval := time.Duration(cmd.config.Monitoring.WriteInterval)
|
2015-03-13 22:26:04 +00:00
|
|
|
|
2015-03-13 23:42:06 +00:00
|
|
|
// Ensure database exists.
|
2015-03-13 22:26:04 +00:00
|
|
|
if err := s.CreateDatabaseIfNotExists(database); err != nil {
|
2015-04-03 21:24:28 +00:00
|
|
|
log.Fatalf("failed to create database %s for internal monitoring: %s", database, err.Error())
|
2015-03-13 22:26:04 +00:00
|
|
|
}
|
2015-03-13 23:42:06 +00:00
|
|
|
|
|
|
|
// Ensure retention policy exists.
|
|
|
|
rp := influxdb.NewRetentionPolicy(policy)
|
|
|
|
if err := s.CreateRetentionPolicyIfNotExists(database, rp); err != nil {
|
2015-04-03 21:24:28 +00:00
|
|
|
log.Fatalf("failed to create retention policy for internal monitoring: %s", err.Error())
|
2015-03-13 23:42:06 +00:00
|
|
|
}
|
|
|
|
|
2015-03-13 23:10:40 +00:00
|
|
|
s.StartSelfMonitoring(database, policy, interval)
|
2015-03-13 22:58:55 +00:00
|
|
|
log.Printf("started self-monitoring at interval of %s", interval)
|
2015-03-12 23:23:33 +00:00
|
|
|
}
|
2014-12-31 19:42:53 +00:00
|
|
|
}
|
2015-02-12 16:59:32 +00:00
|
|
|
|
2015-02-12 19:23:10 +00:00
|
|
|
// unless disabled, start the loop to report anonymous usage stats every 24h
|
2015-03-25 20:27:20 +00:00
|
|
|
if !cmd.config.ReportingDisabled {
|
2015-03-26 23:04:12 +00:00
|
|
|
if cmd.config.Broker.Enabled && cmd.config.Data.Enabled {
|
|
|
|
// Make sure we have a config object b4 we try to use it.
|
2015-04-07 18:08:27 +00:00
|
|
|
if clusterID := cmd.node.Broker.Broker.ClusterID(); clusterID != 0 {
|
2015-03-26 23:04:12 +00:00
|
|
|
go s.StartReportingLoop(clusterID)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Fatalln("failed to start reporting because not running as a broker and a data node")
|
2015-03-06 18:24:56 +00:00
|
|
|
}
|
2015-02-12 19:23:10 +00:00
|
|
|
}
|
2015-02-12 16:59:32 +00:00
|
|
|
|
2015-04-07 18:08:27 +00:00
|
|
|
if cmd.node.Broker != nil {
|
2015-04-08 21:43:09 +00:00
|
|
|
// have it occasionally tell a data node in the cluster to run continuous queries
|
|
|
|
if cmd.config.ContinuousQuery.Disabled {
|
|
|
|
log.Printf("Not running continuous queries. [continuous_queries].disabled is set to true.")
|
|
|
|
} else {
|
2015-04-07 18:08:27 +00:00
|
|
|
cmd.node.Broker.RunContinuousQueryLoop()
|
2015-04-08 21:43:09 +00:00
|
|
|
}
|
2015-03-26 23:04:12 +00:00
|
|
|
}
|
2015-04-08 21:43:09 +00:00
|
|
|
|
2015-04-13 21:21:56 +00:00
|
|
|
if cmd.config.APIAddr() != cmd.config.ClusterAddr() {
|
|
|
|
err := cmd.node.openAPIListener(cmd.config.APIAddr(), h)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("API server failed to listen on %s. %s ", cmd.config.APIAddr(), err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
log.Printf("API server listening on %s", cmd.config.APIAddr())
|
|
|
|
|
2015-04-07 18:08:27 +00:00
|
|
|
return cmd.node
|
2015-03-26 23:04:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *RunCommand) Close() {
|
2015-04-06 21:18:40 +00:00
|
|
|
cmd.node.Close()
|
2014-12-30 22:46:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// write the current process id to a file specified by path.
|
|
|
|
func writePIDFile(path string) {
|
|
|
|
if path == "" {
|
|
|
|
return
|
2014-12-06 01:02:30 +00:00
|
|
|
}
|
|
|
|
|
2015-01-27 02:33:06 +00:00
|
|
|
// Ensure the required directory structure exists.
|
2015-03-06 18:24:56 +00:00
|
|
|
err := os.MkdirAll(filepath.Dir(path), 0755)
|
2015-01-27 02:33:06 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2014-12-30 22:46:50 +00:00
|
|
|
// Retrieve the PID and write it.
|
|
|
|
pid := strconv.Itoa(os.Getpid())
|
|
|
|
if err := ioutil.WriteFile(path, []byte(pid), 0644); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-07 00:21:32 +00:00
|
|
|
// creates and initializes a broker.
|
2015-04-15 17:18:44 +00:00
|
|
|
func (cmd *RunCommand) openBroker(brokerURLs []url.URL, h *Handler) {
|
2015-03-26 20:30:03 +00:00
|
|
|
path := cmd.config.BrokerDir()
|
2015-04-03 17:01:21 +00:00
|
|
|
u := cmd.config.ClusterURL()
|
2015-03-26 20:30:03 +00:00
|
|
|
raftTracing := cmd.config.Logging.RaftTracing
|
|
|
|
|
2015-03-26 21:54:10 +00:00
|
|
|
// Create broker
|
|
|
|
b := influxdb.NewBroker()
|
2015-04-14 02:40:51 +00:00
|
|
|
b.TruncationInterval = time.Duration(cmd.config.Broker.TruncationInterval)
|
2015-04-14 01:59:50 +00:00
|
|
|
b.MaxTopicSize = cmd.config.Broker.MaxTopicSize
|
|
|
|
b.MaxSegmentSize = cmd.config.Broker.MaxSegmentSize
|
2015-04-07 18:08:27 +00:00
|
|
|
cmd.node.Broker = b
|
2015-03-26 21:54:10 +00:00
|
|
|
|
2015-03-10 20:53:45 +00:00
|
|
|
// Create raft log.
|
|
|
|
l := raft.NewLog()
|
|
|
|
l.SetURL(u)
|
2015-03-10 22:27:37 +00:00
|
|
|
l.DebugEnabled = raftTracing
|
2015-03-10 20:53:45 +00:00
|
|
|
b.Log = l
|
2015-04-06 21:18:40 +00:00
|
|
|
cmd.node.raftLog = l
|
2015-01-20 02:44:47 +00:00
|
|
|
|
2015-03-10 20:53:45 +00:00
|
|
|
// Open broker so it can feed last index data to the log.
|
|
|
|
if err := b.Open(path); err != nil {
|
2015-03-18 15:58:56 +00:00
|
|
|
log.Fatalf("failed to open broker at %s : %s", path, err)
|
2014-12-16 03:35:26 +00:00
|
|
|
}
|
2015-03-20 22:14:42 +00:00
|
|
|
log.Printf("broker opened at %s", path)
|
2015-01-07 00:21:32 +00:00
|
|
|
|
2015-04-07 03:39:18 +00:00
|
|
|
// Attach the broker as the finite state machine of the raft log.
|
2015-03-10 20:53:45 +00:00
|
|
|
l.FSM = &messaging.RaftFSM{Broker: b}
|
|
|
|
|
|
|
|
// Open raft log inside broker directory.
|
|
|
|
if err := l.Open(filepath.Join(path, "raft")); err != nil {
|
|
|
|
log.Fatalf("raft: %s", err)
|
|
|
|
}
|
|
|
|
|
2015-04-15 17:43:58 +00:00
|
|
|
// Attach broker and log to handler.
|
2015-04-15 17:18:44 +00:00
|
|
|
h.Broker = b
|
|
|
|
h.Log = l
|
|
|
|
|
2015-04-08 21:47:24 +00:00
|
|
|
// Checks to see if the raft index is 0. If it's 0, it might be the first
|
|
|
|
// node in the cluster and must initialize or join
|
2015-04-14 19:43:25 +00:00
|
|
|
index, _ := l.LastLogIndexTerm()
|
2015-04-08 21:47:24 +00:00
|
|
|
if index == 0 {
|
|
|
|
// If we have join URLs, then attemp to join the cluster
|
|
|
|
if len(brokerURLs) > 0 {
|
2015-04-06 16:47:33 +00:00
|
|
|
joinLog(l, brokerURLs)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-03-26 20:30:03 +00:00
|
|
|
if err := l.Initialize(); err != nil {
|
|
|
|
log.Fatalf("initialize raft log: %s", err)
|
2015-01-07 00:21:32 +00:00
|
|
|
}
|
2015-04-08 21:47:24 +00:00
|
|
|
|
2015-03-26 21:54:10 +00:00
|
|
|
u := b.Broker.URL()
|
|
|
|
log.Printf("initialized broker: %s\n", (&u).String())
|
2015-04-08 21:47:24 +00:00
|
|
|
} else {
|
|
|
|
log.Printf("broker already member of cluster. Using existing state and ignoring join URLs")
|
2015-03-26 20:30:03 +00:00
|
|
|
}
|
2015-01-07 00:21:32 +00:00
|
|
|
}
|
|
|
|
|
2015-03-10 20:53:45 +00:00
|
|
|
// joins a raft log to an existing cluster.
|
2015-03-26 23:04:12 +00:00
|
|
|
func joinLog(l *raft.Log, brokerURLs []url.URL) {
|
2015-01-07 00:21:32 +00:00
|
|
|
// Attempts to join each server until successful.
|
2015-03-26 23:04:12 +00:00
|
|
|
for _, u := range brokerURLs {
|
2015-04-14 19:43:25 +00:00
|
|
|
if err := l.Join(u); err == raft.ErrInitialized {
|
|
|
|
return
|
|
|
|
} else if err != nil {
|
2015-04-08 21:47:24 +00:00
|
|
|
log.Printf("join: failed to connect to raft cluster: %s: %s", (&u).String(), err)
|
2015-01-07 00:21:32 +00:00
|
|
|
} else {
|
2015-04-08 21:47:24 +00:00
|
|
|
log.Printf("join: connected raft log to %s", (&u).String())
|
2015-01-07 00:21:32 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2015-03-10 20:53:45 +00:00
|
|
|
log.Fatalf("join: failed to connect raft log to any specified server")
|
2015-01-07 00:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// creates and initializes a server.
|
2015-04-03 19:49:54 +00:00
|
|
|
func (cmd *RunCommand) openServer(joinURLs []url.URL) *influxdb.Server {
|
2015-03-11 18:00:45 +00:00
|
|
|
|
|
|
|
// Create messaging client to the brokers.
|
2015-04-03 16:58:51 +00:00
|
|
|
c := influxdb.NewMessagingClient(cmd.config.ClusterURL())
|
2015-04-08 20:35:25 +00:00
|
|
|
c.SetURLs(joinURLs)
|
2015-04-01 18:01:17 +00:00
|
|
|
|
2015-03-25 20:27:20 +00:00
|
|
|
if err := c.Open(filepath.Join(cmd.config.Data.Dir, messagingClientFile)); err != nil {
|
2015-03-11 18:00:45 +00:00
|
|
|
log.Fatalf("messaging client error: %s", err)
|
|
|
|
}
|
|
|
|
|
2015-03-14 19:36:06 +00:00
|
|
|
// If no URLs exist on the client the return an error since we cannot reach a broker.
|
|
|
|
if len(c.URLs()) == 0 {
|
|
|
|
log.Fatal("messaging client has no broker URLs")
|
|
|
|
}
|
|
|
|
|
2015-01-07 00:21:32 +00:00
|
|
|
// Create and open the server.
|
2015-02-05 22:54:32 +00:00
|
|
|
s := influxdb.NewServer()
|
2015-03-25 20:27:20 +00:00
|
|
|
|
|
|
|
s.WriteTrace = cmd.config.Logging.WriteTracing
|
|
|
|
s.RetentionAutoCreate = cmd.config.Data.RetentionAutoCreate
|
|
|
|
s.RecomputePreviousN = cmd.config.ContinuousQuery.RecomputePreviousN
|
|
|
|
s.RecomputeNoOlderThan = time.Duration(cmd.config.ContinuousQuery.RecomputeNoOlderThan)
|
|
|
|
s.ComputeRunsPerInterval = cmd.config.ContinuousQuery.ComputeRunsPerInterval
|
|
|
|
s.ComputeNoMoreThan = time.Duration(cmd.config.ContinuousQuery.ComputeNoMoreThan)
|
2015-03-24 03:13:11 +00:00
|
|
|
s.Version = version
|
|
|
|
s.CommitHash = commit
|
2015-01-25 21:41:39 +00:00
|
|
|
|
2015-03-11 18:00:45 +00:00
|
|
|
// Open server with data directory and broker client.
|
2015-03-25 20:27:20 +00:00
|
|
|
if err := s.Open(cmd.config.Data.Dir, c); err != nil {
|
2015-04-08 21:47:24 +00:00
|
|
|
log.Fatalf("failed to open data node: %v", err.Error())
|
2014-12-16 03:35:26 +00:00
|
|
|
}
|
2015-04-14 19:43:25 +00:00
|
|
|
log.Printf("data node(%d) opened at %s", s.ID(), cmd.config.Data.Dir)
|
2015-01-07 00:21:32 +00:00
|
|
|
|
2015-04-14 19:43:25 +00:00
|
|
|
// Give brokers time to elect a leader if entire cluster is being restarted.
|
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
|
|
|
|
if s.ID() == 0 && s.Index() == 0 {
|
2015-04-06 16:47:33 +00:00
|
|
|
if len(joinURLs) > 0 {
|
|
|
|
joinServer(s, cmd.config.ClusterURL(), joinURLs)
|
|
|
|
return s
|
|
|
|
}
|
2015-03-27 20:12:09 +00:00
|
|
|
|
2015-04-03 16:58:51 +00:00
|
|
|
if err := s.Initialize(cmd.config.ClusterURL()); err != nil {
|
2015-04-14 19:43:25 +00:00
|
|
|
log.Fatalf("server initialization error(0): %s", err)
|
2015-01-07 00:21:32 +00:00
|
|
|
}
|
2015-04-08 21:47:24 +00:00
|
|
|
|
2015-04-03 16:58:51 +00:00
|
|
|
u := cmd.config.ClusterURL()
|
2015-03-26 21:54:10 +00:00
|
|
|
log.Printf("initialized data node: %s\n", (&u).String())
|
|
|
|
return s
|
2015-04-08 21:47:24 +00:00
|
|
|
} else {
|
|
|
|
log.Printf("data node already member of cluster. Using existing state and ignoring join URLs")
|
2015-03-26 21:54:10 +00:00
|
|
|
}
|
|
|
|
|
2014-12-31 19:42:53 +00:00
|
|
|
return s
|
|
|
|
}
|
2014-12-16 03:35:26 +00:00
|
|
|
|
2015-01-07 00:21:32 +00:00
|
|
|
// joins a server to an existing cluster.
|
2015-03-10 20:53:45 +00:00
|
|
|
func joinServer(s *influxdb.Server, u url.URL, joinURLs []url.URL) {
|
2015-01-07 00:21:32 +00:00
|
|
|
// TODO: Use separate broker and data join urls.
|
|
|
|
|
|
|
|
// Create data node on an existing data node.
|
|
|
|
for _, joinURL := range joinURLs {
|
2015-04-14 19:43:25 +00:00
|
|
|
if err := s.Join(&u, &joinURL); err == influxdb.ErrDataNodeNotFound {
|
2015-04-03 19:49:54 +00:00
|
|
|
// No data nodes could be found to join. We're the first.
|
2015-04-14 19:43:25 +00:00
|
|
|
if err := s.Initialize(u); err != nil {
|
|
|
|
log.Fatalf("server initialization error(1): %s", err)
|
2015-04-03 19:49:54 +00:00
|
|
|
}
|
2015-04-14 19:43:25 +00:00
|
|
|
log.Printf("initialized data node: %s\n", (&u).String())
|
|
|
|
return
|
|
|
|
} else if err != nil {
|
2015-04-08 21:47:24 +00:00
|
|
|
log.Printf("join: failed to connect data node: %s: %s", (&u).String(), err)
|
2015-01-07 00:21:32 +00:00
|
|
|
} else {
|
|
|
|
log.Printf("join: connected data node to %s", u)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
log.Fatalf("join: failed to connect data node to any specified server")
|
|
|
|
}
|
|
|
|
|
2014-12-31 19:42:53 +00:00
|
|
|
// parses a comma-delimited list of URLs.
|
2015-03-10 20:53:45 +00:00
|
|
|
func parseURLs(s string) (a []url.URL) {
|
2015-01-07 00:21:32 +00:00
|
|
|
if s == "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-12-31 19:42:53 +00:00
|
|
|
for _, s := range strings.Split(s, ",") {
|
|
|
|
u, err := url.Parse(s)
|
|
|
|
if err != nil {
|
2015-01-07 00:21:32 +00:00
|
|
|
log.Fatalf("cannot parse urls: %s", err)
|
2014-12-31 19:42:53 +00:00
|
|
|
}
|
2015-03-10 20:53:45 +00:00
|
|
|
a = append(a, *u)
|
2014-12-16 06:05:01 +00:00
|
|
|
}
|
2014-12-31 19:42:53 +00:00
|
|
|
return
|
|
|
|
}
|
2014-12-06 01:02:30 +00:00
|
|
|
|
2014-12-31 19:42:53 +00:00
|
|
|
// returns true if the file exists.
|
|
|
|
func fileExists(path string) bool {
|
|
|
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
2014-12-06 01:02:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func printRunUsage() {
|
2014-12-11 21:49:42 +00:00
|
|
|
log.Printf(`usage: run [flags]
|
2014-12-06 01:02:30 +00:00
|
|
|
|
2015-01-10 16:08:00 +00:00
|
|
|
run starts the broker and data node server. If this is the first time running
|
|
|
|
the command then a new cluster will be initialized unless the -join argument
|
|
|
|
is used.
|
2014-12-06 01:02:30 +00:00
|
|
|
|
|
|
|
-config <path>
|
2015-01-07 00:21:32 +00:00
|
|
|
Set the path to the configuration file.
|
2014-12-06 01:02:30 +00:00
|
|
|
|
|
|
|
-hostname <name>
|
2015-01-07 00:21:32 +00:00
|
|
|
Override the hostname, the 'hostname' configuration
|
|
|
|
option will be overridden.
|
2014-12-06 01:02:30 +00:00
|
|
|
|
2015-01-10 16:08:00 +00:00
|
|
|
-join <url>
|
2015-01-07 00:21:32 +00:00
|
|
|
Joins the server to an existing cluster.
|
2014-12-16 07:03:09 +00:00
|
|
|
|
2014-12-06 01:02:30 +00:00
|
|
|
-pidfile <path>
|
2015-01-07 00:21:32 +00:00
|
|
|
Write process ID to a file.
|
2015-01-16 23:45:31 +00:00
|
|
|
`)
|
2014-12-06 01:02:30 +00:00
|
|
|
}
|