func (s *RaftServer) joinHandler(w http.ResponseWriter, req *http.Request) { if s.raftServer.State() == raft.Leader { command := &InfluxJoinCommand{} if err := json.NewDecoder(req.Body).Decode(&command); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } log.Debug("ON RAFT LEADER - JOIN: %v", command) // during the test suite the join command will sometimes time out.. just retry a few times if _, err := s.raftServer.Do(command); err != nil { log.Error("Can't process %v: %s", command, err) http.Error(w, err.Error(), http.StatusInternalServerError) return } server := s.clusterConfig.GetServerByRaftName(command.Name) // it's a new server the cluster has never seen, make it a potential if server == nil { log.Info("Adding new server to the cluster config %s", command.Name) clusterServer := cluster.NewClusterServer(command.Name, command.ConnectionString, command.ProtobufConnectionString, nil, s.config.ProtobufHeartbeatInterval.Duration) addServer := NewAddPotentialServerCommand(clusterServer) if _, err := s.raftServer.Do(addServer); err != nil { log.Error("Error joining raft server: ", err, command) http.Error(w, err.Error(), http.StatusInternalServerError) return } } log.Info("Server %s already exist in the cluster config", command.Name) } else { leader, ok := s.leaderConnectString() log.Debug("Non-leader redirecting to: (%v, %v)", leader, ok) if ok { log.Debug("redirecting to leader to join...") http.Redirect(w, req, leader+"/join", http.StatusTemporaryRedirect) } else { http.Error(w, errors.New("Couldn't find leader of the cluster to join").Error(), http.StatusInternalServerError) } } }
func (c *InfluxJoinCommand) Apply(server raft.Server) (interface{}, error) { err := server.AddPeer(c.Name, c.ConnectionString) if err != nil { return nil, err } clusterConfig := server.Context().(*cluster.ClusterConfiguration) newServer := clusterConfig.GetServerByRaftName(c.Name) // it's a new server the cluster has never seen, make it a potential if newServer != nil { return nil, fmt.Errorf("Server %s already exist", c.Name) } log.Info("Adding new server to the cluster config %s", c.Name) clusterServer := cluster.NewClusterServer(c.Name, c.ConnectionString, c.ProtobufConnectionString, nil, clusterConfig.GetLocalConfiguration()) clusterConfig.AddPotentialServer(clusterServer) return nil, nil }
func (s *RaftServer) startRaft() error { log.Info("Initializing Raft Server: %s %d", s.path, s.port) // Initialize and start Raft server. transporter := raft.NewHTTPTransporter("/raft") var err error s.raftServer, err = raft.NewServer(s.name, s.path, transporter, s.clusterConfig, s.clusterConfig, "") if err != nil { return err } s.raftServer.LoadSnapshot() // ignore errors s.raftServer.AddEventListener(raft.StateChangeEventType, s.raftEventHandler) transporter.Install(s.raftServer, s) s.raftServer.Start() go s.CompactLog() if !s.raftServer.IsLogEmpty() { log.Info("Recovered from log") return nil } potentialLeaders := s.config.SeedServers if len(potentialLeaders) == 0 { log.Info("Starting as new Raft leader...") name := s.raftServer.Name() connectionString := s.connectionString() _, err := s.raftServer.Do(&InfluxJoinCommand{ Name: name, ConnectionString: connectionString, ProtobufConnectionString: s.config.ProtobufConnectionString(), }) if err != nil { log.Error(err) } protobufConnectString := s.config.ProtobufConnectionString() clusterServer := cluster.NewClusterServer(name, connectionString, protobufConnectString, nil, s.config.ProtobufHeartbeatInterval.Duration) command := NewAddPotentialServerCommand(clusterServer) _, err = s.doOrProxyCommand(command, "add_server") if err != nil { return err } err = s.CreateRootUser() return err } for { for _, leader := range potentialLeaders { log.Info("(raft:%s) Attempting to join leader: %s", s.raftServer.Name(), leader) if err := s.Join(leader); err == nil { log.Info("Joined: %s", leader) return nil } } log.Warn("Couldn't join any of the seeds, sleeping and retrying...") time.Sleep(100 * time.Millisecond) } return nil }