influxdb/cmd/influxd/join_cluster.go

118 lines
3.4 KiB
Go

package main
import (
"flag"
"log"
"net/url"
"os"
"path/filepath"
"strings"
"github.com/influxdb/influxdb/messaging"
)
// execJoinCluster runs the "join-cluster" command.
func execJoinCluster(args []string) {
// Parse command flags.
fs := flag.NewFlagSet("", flag.ExitOnError)
var (
configPath = fs.String("config", configDefaultPath, "")
role = fs.String("role", "combined", "")
seedServers = fs.String("seed-servers", "", "")
)
fs.Usage = printJoinClusterUsage
fs.Parse(args)
// Parse configuration.
config, err := ParseConfigFile(*configPath)
if err != nil {
log.Fatalf("config: %s", err)
}
// Validate command line arguments.
if *seedServers == "" {
log.Fatalf("at least one seed server must be supplied")
} else if *role != "combined" && *role != "broker" && *role != "data" {
log.Fatalf("node must join as 'combined', 'broker', or 'data'")
}
var seedURLs []*url.URL
for _, s := range strings.Split(*seedServers, ",") {
u, err := url.Parse(s)
if err != nil {
log.Fatalf("seed server: %s", err)
}
seedURLs = append(seedURLs, u)
}
// If joining as broker then create broker.
if *role == "combined" || *role == "broker" {
// Broker required -- but don't initialize it.
// Joining a cluster will do that.
b := messaging.NewBroker()
if err := b.Open(config.Broker.Dir, config.BrokerConnectionString()); err != nil {
log.Fatalf("join: %s", err)
}
// Loop through each, connecting to one must succeed.
joined := false
for _, s := range seedURLs {
err := b.Join(s)
if err != nil {
log.Println("error: join failed to connect to", s, err)
} else {
log.Println("join: connected successfully to", s)
joined = true
break
}
}
if !joined {
log.Fatalf("join: failed to connect to any seed server")
}
}
// If joining as a data node then create a data directory.
if *role == "combined" || *role == "data" {
if _, err := os.Stat(config.Data.Dir); err == nil {
log.Fatalf("join-cluster: data directory already exists")
}
if err := os.MkdirAll(config.Data.Dir, 0744); err != nil {
log.Fatalf("join-cluster data dir: %s", err.Error())
}
// Configure the Messaging Client.
c := messaging.NewClient(0) // TODO: Set replica id.
if err := c.Open(filepath.Join(config.Data.Dir, messagingClientFile), seedURLs); err != nil {
log.Fatalf("join-cluster open client: %s", err.Error())
}
if err := c.Close(); err != nil {
log.Fatalf("join-cluster close client: %s", err.Error())
}
}
log.Printf("joined cluster as '%s' at %s", *role, *seedServers)
}
func printJoinClusterUsage() {
log.Printf(`usage: join-cluster [flags]
join-cluster creates a completely new node that will attempt to join an existing cluster.
-config <path>
Set the path to the configuration file. Defaults to %s.
-role <role>
Set the role to be 'combined', 'broker' or 'data'. broker' means it will take
part in Raft Distributed Consensus. 'data' means it will store time-series data.
'combined' means it will do both. The default is 'combined'. In role other than
these three is invalid.
-seed-servers <servers>
Set the list of servers the node should contact, to join the cluster. This
should be comma-delimited list of servers, in the form host:port. This option
is REQUIRED.
\n`, configDefaultPath)
}