예제 #1
0
파일: server.go 프로젝트: kennylixi/etcd
// Adds a server handler to the router.
func (s *Server) handleFunc(r *mux.Router, path string, f func(http.ResponseWriter, *http.Request) error) *mux.Route {

	// Wrap the standard HandleFunc interface to pass in the server reference.
	return r.HandleFunc(path, func(w http.ResponseWriter, req *http.Request) {
		if req.Method == "HEAD" {
			w = &HEADResponseWriter{w}
		}

		// Log request.
		log.Debugf("[recv] %s %s %s [%s]", req.Method, s.URL(), req.URL.Path, req.RemoteAddr)

		// Forward request along if the server is a standby.
		if s.peerServer.Mode() == StandbyMode {
			if s.peerServer.standbyClientURL == "" {
				w.Header().Set("Content-Type", "application/json")
				etcdErr.NewError(402, "", 0).Write(w)
				return
			}
			uhttp.Redirect(s.peerServer.standbyClientURL, w, req)
			return
		}

		// Execute handler function and return error if necessary.
		if err := f(w, req); err != nil {
			if etcdErr, ok := err.(*etcdErr.Error); ok {
				log.Debug("Return error: ", (*etcdErr).Error())
				w.Header().Set("Content-Type", "application/json")
				etcdErr.Write(w)
			} else {
				http.Error(w, err.Error(), http.StatusInternalServerError)
			}
		}
	})
}
예제 #2
0
func (s *StandbyServer) redirectRequests(w http.ResponseWriter, r *http.Request) {
	leader := s.ClusterLeader()
	if leader == nil {
		w.Header().Set("Content-Type", "application/json")
		etcdErr.NewError(etcdErr.EcodeStandbyInternal, "", 0).Write(w)
		return
	}
	uhttp.Redirect(leader.ClientURL, w, r)
}
예제 #3
0
// Retrieves stats on the leader.
func (s *Server) GetLeaderStatsHandler(w http.ResponseWriter, req *http.Request) error {
	if s.peerServer.RaftServer().State() == raft.Leader {
		w.Write(s.peerServer.PeerStats())
		return nil
	}

	leader := s.peerServer.RaftServer().Leader()
	if leader == "" {
		return etcdErr.NewError(300, "", s.Store().Index())
	}
	hostname, _ := s.registry.ClientURL(leader)
	uhttp.Redirect(hostname, w, req)
	return nil
}
예제 #4
0
// Dispatch command to the current leader
func (s *Server) Dispatch(c raft.Command, w http.ResponseWriter, req *http.Request) error {
	ps := s.peerServer
	if ps.raftServer.State() == raft.Leader {
		result, err := ps.raftServer.Do(c)
		if err != nil {
			return err
		}

		if result == nil {
			return etcdErr.NewError(300, "Empty result from raft", s.Store().Index())
		}

		// response for raft related commands[join/remove]
		if b, ok := result.([]byte); ok {
			w.WriteHeader(http.StatusOK)
			w.Write(b)
			return nil
		}

		var b []byte
		if strings.HasPrefix(req.URL.Path, "/v1") {
			b, _ = json.Marshal(result.(*store.Event).Response(0))
			w.WriteHeader(http.StatusOK)
		} else {
			e, _ := result.(*store.Event)
			b, _ = json.Marshal(e)

			w.Header().Set("Content-Type", "application/json")
			// etcd index should be the same as the event index
			// which is also the last modified index of the node
			w.Header().Add("X-Etcd-Index", fmt.Sprint(e.Index()))
			w.Header().Add("X-Raft-Index", fmt.Sprint(s.CommitIndex()))
			w.Header().Add("X-Raft-Term", fmt.Sprint(s.Term()))

			if e.IsCreated() {
				w.WriteHeader(http.StatusCreated)
			} else {
				w.WriteHeader(http.StatusOK)
			}
		}

		w.Write(b)

		return nil

	} else {
		leader := ps.raftServer.Leader()

		// No leader available.
		if leader == "" {
			return etcdErr.NewError(300, "", s.Store().Index())
		}

		var url string
		switch c.(type) {
		case *JoinCommand, *RemoveCommand:
			url, _ = ps.registry.PeerURL(leader)
		default:
			url, _ = ps.registry.ClientURL(leader)
		}
		uhttp.Redirect(url, w, req)

		return nil
	}
}