func main() { flag.Parse() // Set up profiling, if requested. if cpuprofile != "" { log.Info("Profiling enabled") f, err := os.Create(cpuprofile) if err != nil { log.Errorf("Unable to create path: %s", err.Error()) } defer closeFile(f) err = pprof.StartCPUProfile(f) if err != nil { log.Errorf("Unable to start CPU Profile: %s", err.Error()) } defer pprof.StopCPUProfile() } // Set logging log.SetLevel(logLevel) if logFile != "stdout" { f := createFile(logFile) defer closeFile(f) log.Infof("Redirecting logging to %s", logFile) log.SetOutput(f) } // Set the data directory. if flag.NArg() == 0 { flag.Usage() println("Data path argument required") log.Error("No data path supplied -- aborting") os.Exit(1) } dataPath := flag.Arg(0) createDir(dataPath) s := server.NewServer(dataPath, dbfile, snapAfter, host, port) go func() { log.Error(s.ListenAndServe(join).Error()) }() if !disableReporting { reportLaunch() } terminate := make(chan os.Signal, 1) signal.Notify(terminate, os.Interrupt) <-terminate log.Info("rqlite server stopped") }
// Open an existing database, creating it if it does not exist. func Open(dbPath string) *DB { log.Tracef("Opening SQLite database path at %s", dbPath) dbc, err := sql.Open("sqlite3", dbPath) if err != nil { log.Error(err.Error()) return nil } return &DB{ dbConn: dbc, } }
// serveStatistics returns the statistics for the program func (s *Server) serveStatistics(w http.ResponseWriter, req *http.Request) { statistics := make(map[string]interface{}) resources := map[string]interfaces.Statistics{"server": s} for k, v := range resources { s, err := v.GetStatistics() if err != nil { log.Error("failed to get " + k + " stats") http.Error(w, "failed to get "+k+" stats", http.StatusInternalServerError) return } statistics[k] = s } _, err := w.Write(ensurePrettyPrint(req, statistics)) if err != nil { log.Error("failed to serve stats") http.Error(w, "failed to serve stats", http.StatusInternalServerError) return } }
// serveRaftInfo returns information about the underlying Raft server func (s *Server) serveRaftInfo(w http.ResponseWriter, req *http.Request) { var peers []interface{} for _, v := range s.raftServer.Peers() { peers = append(peers, v) } info := make(map[string]interface{}) info["name"] = s.raftServer.Name() info["state"] = s.raftServer.State() info["leader"] = s.raftServer.Leader() info["peers"] = peers _, err := w.Write(ensurePrettyPrint(req, info)) if err != nil { log.Error("failed to serve raft info") http.Error(w, "failed to serve raft info", http.StatusInternalServerError) return } }
// serveDiagnostics returns basic server diagnostics func (s *Server) serveDiagnostics(w http.ResponseWriter, req *http.Request) { diagnostics := make(map[string]interface{}) diagnostics["started"] = s.diagnostics.startTime.String() diagnostics["uptime"] = time.Since(s.diagnostics.startTime).String() diagnostics["host"] = s.host diagnostics["port"] = s.port diagnostics["data"] = s.path diagnostics["database"] = s.dbPath diagnostics["connection"] = s.connectionString() diagnostics["snapafter"] = s.snapConf.snapshotAfter diagnostics["snapindex"] = s.snapConf.lastIndex _, err := w.Write(ensurePrettyPrint(req, diagnostics)) if err != nil { log.Error("failed to serve diagnostics") http.Error(w, "failed to serve diagnostics", http.StatusInternalServerError) return } }
// leaderRedirect returns a 307 Temporary Redirect, with the full path // to the leader. func (s *Server) leaderRedirect(w http.ResponseWriter, r *http.Request) { peers := s.raftServer.Peers() leader := peers[s.raftServer.Leader()] if leader == nil { // No leader available, give up. log.Error("attempted leader redirection, but no leader available") w.WriteHeader(http.StatusServiceUnavailable) w.Write([]byte("no leader available")) return } var u string for _, p := range peers { if p.Name == leader.Name { u = p.ConnectionString break } } http.Redirect(w, r, u+r.URL.Path, http.StatusTemporaryRedirect) }
// ListenAndServe starts the server. func (s *Server) ListenAndServe(leader string) error { var err error log.Infof("Initializing Raft Server: %s", s.path) // Initialize and start Raft server. transporter := raft.NewHTTPTransporter("/raft", 200*time.Millisecond) stateMachine := NewDbStateMachine(s.dbPath) s.raftServer, err = raft.NewServer(s.name, s.path, transporter, stateMachine, s.db, "") if err != nil { log.Errorf("Failed to create new Raft server: %s", err.Error()) return err } log.Info("Loading latest snapshot, if any, from disk") if err := s.raftServer.LoadSnapshot(); err != nil && os.IsNotExist(err) { log.Info("no snapshot found") } else if err != nil { log.Errorf("Error loading snapshot: %s", err.Error()) } transporter.Install(s.raftServer, s) if err := s.raftServer.Start(); err != nil { log.Errorf("Error starting raft server: %s", err.Error()) } if leader != "" { // Join to leader if specified. log.Infof("Attempting to join leader at %s", leader) if !s.raftServer.IsLogEmpty() { log.Error("Cannot join with an existing log") return errors.New("Cannot join with an existing log") } if err := s.Join(leader); err != nil { log.Errorf("Failed to join leader: %s", err.Error()) return err } } else if s.raftServer.IsLogEmpty() { // Initialize the server by joining itself. log.Info("Initializing new cluster") _, err := s.raftServer.Do(&raft.DefaultJoinCommand{ Name: s.raftServer.Name(), ConnectionString: s.connectionString(), }) if err != nil { log.Errorf("Failed to join to self: %s", err.Error()) } } else { log.Info("Recovered from log") } log.Info("Initializing HTTP server") // Initialize and start HTTP server. s.httpServer = &http.Server{ Addr: fmt.Sprintf(":%d", s.port), Handler: s.router, } s.router.HandleFunc("/statistics", s.serveStatistics).Methods("GET") s.router.HandleFunc("/diagnostics", s.serveDiagnostics).Methods("GET") s.router.HandleFunc("/raft", s.serveRaftInfo).Methods("GET") s.router.HandleFunc("/db", s.readHandler).Methods("GET") s.router.HandleFunc("/db", s.writeHandler).Methods("POST") s.router.HandleFunc("/join", s.joinHandler).Methods("POST") log.Infof("Listening at %s", s.connectionString()) return s.httpServer.ListenAndServe() }