func (c *Config) handleDiscovery() error { p, err := discovery.Do(c.Discovery, c.Name, c.Peer.Addr) // This is fatal, discovery encountered an unexpected error // and we have no peer list. if err != nil && len(c.Peers) == 0 { log.Fatalf("Discovery failed and a backup peer list wasn't provided: %v", err) return err } // Warn about errors coming from discovery, this isn't fatal // since the user might have provided a peer list elsewhere. if err != nil { log.Warnf("Discovery encountered an error but a backup peer list (%v) was provided: %v", c.Peers, err) } for i := range p { // Strip the scheme off of the peer if it has one // TODO(bp): clean this up! purl, err := url.Parse(p[i]) if err == nil { p[i] = purl.Host } } c.Peers = p return nil }
func (s *PeerServer) startAsFollower(cluster []string) { // start as a follower in a existing cluster for i := 0; i < s.Config.RetryTimes; i++ { ok := s.joinCluster(cluster) if ok { return } log.Warnf("Unable to join the cluster using any of the peers %v. Retrying in %.1f seconds", cluster, s.Config.RetryInterval) time.Sleep(time.Second * time.Duration(s.Config.RetryInterval)) } log.Fatalf("Cannot join the cluster via given peers after %x retries", s.Config.RetryTimes) }
func main() { // Load configuration. var config = config.New() if err := config.Load(os.Args[1:]); err != nil { fmt.Println(server.Usage() + "\n") fmt.Println(err.Error() + "\n") os.Exit(1) } else if config.ShowVersion { fmt.Println(server.ReleaseVersion) os.Exit(0) } else if config.ShowHelp { fmt.Println(server.Usage() + "\n") os.Exit(0) } // Enable options. if config.VeryVeryVerbose { log.Verbose = true raft.SetLogLevel(raft.Trace) } else if config.VeryVerbose { log.Verbose = true raft.SetLogLevel(raft.Debug) } else if config.Verbose { log.Verbose = true } if config.CPUProfileFile != "" { profile(config.CPUProfileFile) } if config.DataDir == "" { log.Fatal("The data dir was not set and could not be guessed from machine name") } // Create data directory if it doesn't already exist. if err := os.MkdirAll(config.DataDir, 0744); err != nil { log.Fatalf("Unable to create path: %s", err) } // Warn people if they have an info file info := filepath.Join(config.DataDir, "info") if _, err := os.Stat(info); err == nil { log.Warnf("All cached configuration is now ignored. The file %s can be removed.", info) } var mbName string if config.Trace() { mbName = config.MetricsBucketName() runtime.SetBlockProfileRate(1) } mb := metrics.NewBucket(mbName) if config.GraphiteHost != "" { err := mb.Publish(config.GraphiteHost) if err != nil { panic(err) } } // Retrieve CORS configuration corsInfo, err := ehttp.NewCORSInfo(config.CorsOrigins) if err != nil { log.Fatal("CORS:", err) } // Create etcd key-value store and registry. store := store.New() registry := server.NewRegistry(store) // Create stats objects followersStats := server.NewRaftFollowersStats(config.Name) serverStats := server.NewRaftServerStats(config.Name) // Calculate all of our timeouts heartbeatTimeout := time.Duration(config.Peer.HeartbeatTimeout) * time.Millisecond electionTimeout := time.Duration(config.Peer.ElectionTimeout) * time.Millisecond dialTimeout := (3 * heartbeatTimeout) + electionTimeout responseHeaderTimeout := (3 * heartbeatTimeout) + electionTimeout // Create peer server psConfig := server.PeerServerConfig{ Name: config.Name, Scheme: config.PeerTLSInfo().Scheme(), URL: config.Peer.Addr, SnapshotCount: config.SnapshotCount, MaxClusterSize: config.MaxClusterSize, RetryTimes: config.MaxRetryAttempts, RetryInterval: config.RetryInterval, } ps := server.NewPeerServer(psConfig, registry, store, &mb, followersStats, serverStats) var psListener net.Listener if psConfig.Scheme == "https" { peerServerTLSConfig, err := config.PeerTLSInfo().ServerConfig() if err != nil { log.Fatal("peer server TLS error: ", err) } psListener, err = server.NewTLSListener(config.Peer.BindAddr, peerServerTLSConfig) if err != nil { log.Fatal("Failed to create peer listener: ", err) } } else { psListener, err = server.NewListener(config.Peer.BindAddr) if err != nil { log.Fatal("Failed to create peer listener: ", err) } } // Create raft transporter and server raftTransporter := server.NewTransporter(followersStats, serverStats, registry, heartbeatTimeout, dialTimeout, responseHeaderTimeout) if psConfig.Scheme == "https" { raftClientTLSConfig, err := config.PeerTLSInfo().ClientConfig() if err != nil { log.Fatal("raft client TLS error: ", err) } raftTransporter.SetTLSConfig(*raftClientTLSConfig) } raftServer, err := raft.NewServer(config.Name, config.DataDir, raftTransporter, store, ps, "") if err != nil { log.Fatal(err) } raftServer.SetElectionTimeout(electionTimeout) raftServer.SetHeartbeatInterval(heartbeatTimeout) ps.SetRaftServer(raftServer) // Create etcd server s := server.New(config.Name, config.Addr, ps, registry, store, &mb) if config.Trace() { s.EnableTracing() } var sListener net.Listener if config.EtcdTLSInfo().Scheme() == "https" { etcdServerTLSConfig, err := config.EtcdTLSInfo().ServerConfig() if err != nil { log.Fatal("etcd TLS error: ", err) } sListener, err = server.NewTLSListener(config.BindAddr, etcdServerTLSConfig) if err != nil { log.Fatal("Failed to create TLS etcd listener: ", err) } } else { sListener, err = server.NewListener(config.BindAddr) if err != nil { log.Fatal("Failed to create etcd listener: ", err) } } ps.SetServer(s) ps.Start(config.Snapshot, config.Peers) go func() { log.Infof("peer server [name %s, listen on %s, advertised url %s]", ps.Config.Name, psListener.Addr(), ps.Config.URL) sHTTP := &ehttp.CORSHandler{ps.HTTPHandler(), corsInfo} log.Fatal(http.Serve(psListener, sHTTP)) }() log.Infof("etcd server [name %s, listen on %s, advertised url %s]", s.Name, sListener.Addr(), s.URL()) sHTTP := &ehttp.CORSHandler{s.HTTPHandler(), corsInfo} log.Fatal(http.Serve(sListener, sHTTP)) }