github.com/macb/etcd@v0.3.1-0.20140227003422-a60481c6b1a0/server/server.go (about)

     1  package server
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"net/http/pprof"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/coreos/etcd/third_party/github.com/coreos/raft"
    12  	"github.com/coreos/etcd/third_party/github.com/gorilla/mux"
    13  
    14  	etcdErr "github.com/coreos/etcd/error"
    15  	"github.com/coreos/etcd/log"
    16  	"github.com/coreos/etcd/metrics"
    17  	"github.com/coreos/etcd/mod"
    18  	ehttp "github.com/coreos/etcd/http"
    19  	uhttp "github.com/coreos/etcd/pkg/http"
    20  	"github.com/coreos/etcd/server/v1"
    21  	"github.com/coreos/etcd/server/v2"
    22  	"github.com/coreos/etcd/store"
    23  	_ "github.com/coreos/etcd/store/v2"
    24  )
    25  
    26  // This is the default implementation of the Server interface.
    27  type Server struct {
    28  	Name		string
    29  	url		string
    30  	handler		http.Handler
    31  	peerServer	*PeerServer
    32  	registry	*Registry
    33  	store		store.Store
    34  	metrics		*metrics.Bucket
    35  
    36  	trace	bool
    37  }
    38  
    39  // Creates a new Server.
    40  func New(name, url string, peerServer *PeerServer, registry *Registry, store store.Store, mb *metrics.Bucket) *Server {
    41  	s := &Server{
    42  		Name:		name,
    43  		url:		url,
    44  		store:		store,
    45  		registry:	registry,
    46  		peerServer:	peerServer,
    47  		metrics:	mb,
    48  	}
    49  
    50  	return s
    51  }
    52  
    53  func (s *Server) EnableTracing() {
    54  	s.trace = true
    55  }
    56  
    57  // The current state of the server in the cluster.
    58  func (s *Server) State() string {
    59  	return s.peerServer.RaftServer().State()
    60  }
    61  
    62  // The node name of the leader in the cluster.
    63  func (s *Server) Leader() string {
    64  	return s.peerServer.RaftServer().Leader()
    65  }
    66  
    67  // The current Raft committed index.
    68  func (s *Server) CommitIndex() uint64 {
    69  	return s.peerServer.RaftServer().CommitIndex()
    70  }
    71  
    72  // The current Raft term.
    73  func (s *Server) Term() uint64 {
    74  	return s.peerServer.RaftServer().Term()
    75  }
    76  
    77  // The server URL.
    78  func (s *Server) URL() string {
    79  	return s.url
    80  }
    81  
    82  // PeerHost retrieves the host part of Peer URL for a given node name.
    83  func (s *Server) PeerHost(name string) (string, bool) {
    84  	return s.registry.PeerHost(name)
    85  }
    86  
    87  // Retrives the Peer URL for a given node name.
    88  func (s *Server) PeerURL(name string) (string, bool) {
    89  	return s.registry.PeerURL(name)
    90  }
    91  
    92  // ClientURL retrieves the Client URL for a given node name.
    93  func (s *Server) ClientURL(name string) (string, bool) {
    94  	return s.registry.ClientURL(name)
    95  }
    96  
    97  // Returns a reference to the Store.
    98  func (s *Server) Store() store.Store {
    99  	return s.store
   100  }
   101  
   102  func (s *Server) installV1(r *mux.Router) {
   103  	s.handleFuncV1(r, "/v1/keys/{key:.*}", v1.GetKeyHandler).Methods("GET")
   104  	s.handleFuncV1(r, "/v1/keys/{key:.*}", v1.SetKeyHandler).Methods("POST", "PUT")
   105  	s.handleFuncV1(r, "/v1/keys/{key:.*}", v1.DeleteKeyHandler).Methods("DELETE")
   106  	s.handleFuncV1(r, "/v1/watch/{key:.*}", v1.WatchKeyHandler).Methods("GET", "POST")
   107  	s.handleFunc(r, "/v1/leader", s.GetLeaderHandler).Methods("GET")
   108  	s.handleFunc(r, "/v1/machines", s.GetPeersHandler).Methods("GET")
   109  	s.handleFunc(r, "/v1/peers", s.GetPeersHandler).Methods("GET")
   110  	s.handleFunc(r, "/v1/stats/self", s.GetStatsHandler).Methods("GET")
   111  	s.handleFunc(r, "/v1/stats/leader", s.GetLeaderStatsHandler).Methods("GET")
   112  	s.handleFunc(r, "/v1/stats/store", s.GetStoreStatsHandler).Methods("GET")
   113  }
   114  
   115  func (s *Server) installV2(r *mux.Router) {
   116  	r2 := mux.NewRouter()
   117  	r.PathPrefix("/v2").Handler(ehttp.NewLowerQueryParamsHandler(r2))
   118  
   119  	s.handleFuncV2(r2, "/v2/keys/{key:.*}", v2.GetHandler).Methods("GET")
   120  	s.handleFuncV2(r2, "/v2/keys/{key:.*}", v2.PostHandler).Methods("POST")
   121  	s.handleFuncV2(r2, "/v2/keys/{key:.*}", v2.PutHandler).Methods("PUT")
   122  	s.handleFuncV2(r2, "/v2/keys/{key:.*}", v2.DeleteHandler).Methods("DELETE")
   123  	s.handleFunc(r2, "/v2/leader", s.GetLeaderHandler).Methods("GET")
   124  	s.handleFunc(r2, "/v2/machines", s.GetPeersHandler).Methods("GET")
   125  	s.handleFunc(r2, "/v2/peers", s.GetPeersHandler).Methods("GET")
   126  	s.handleFunc(r2, "/v2/stats/self", s.GetStatsHandler).Methods("GET")
   127  	s.handleFunc(r2, "/v2/stats/leader", s.GetLeaderStatsHandler).Methods("GET")
   128  	s.handleFunc(r2, "/v2/stats/store", s.GetStoreStatsHandler).Methods("GET")
   129  	s.handleFunc(r2, "/v2/speedTest", s.SpeedTestHandler).Methods("GET")
   130  }
   131  
   132  func (s *Server) installMod(r *mux.Router) {
   133  	r.PathPrefix("/mod").Handler(http.StripPrefix("/mod", mod.HttpHandler(s.URL())))
   134  }
   135  
   136  func (s *Server) installDebug(r *mux.Router) {
   137  	s.handleFunc(r, "/debug/metrics", s.GetMetricsHandler).Methods("GET")
   138  	r.HandleFunc("/debug/pprof", pprof.Index)
   139  	r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
   140  	r.HandleFunc("/debug/pprof/profile", pprof.Profile)
   141  	r.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
   142  	r.HandleFunc("/debug/pprof/{name}", pprof.Index)
   143  }
   144  
   145  // Adds a v1 server handler to the router.
   146  func (s *Server) handleFuncV1(r *mux.Router, path string, f func(http.ResponseWriter, *http.Request, v1.Server) error) *mux.Route {
   147  	return s.handleFunc(r, path, func(w http.ResponseWriter, req *http.Request) error {
   148  		return f(w, req, s)
   149  	})
   150  }
   151  
   152  // Adds a v2 server handler to the router.
   153  func (s *Server) handleFuncV2(r *mux.Router, path string, f func(http.ResponseWriter, *http.Request, v2.Server) error) *mux.Route {
   154  	return s.handleFunc(r, path, func(w http.ResponseWriter, req *http.Request) error {
   155  		return f(w, req, s)
   156  	})
   157  }
   158  
   159  // Adds a server handler to the router.
   160  func (s *Server) handleFunc(r *mux.Router, path string, f func(http.ResponseWriter, *http.Request) error) *mux.Route {
   161  
   162  	// Wrap the standard HandleFunc interface to pass in the server reference.
   163  	return r.HandleFunc(path, func(w http.ResponseWriter, req *http.Request) {
   164  		// Log request.
   165  		log.Debugf("[recv] %s %s %s [%s]", req.Method, s.URL(), req.URL.Path, req.RemoteAddr)
   166  
   167  		// Execute handler function and return error if necessary.
   168  		if err := f(w, req); err != nil {
   169  			if etcdErr, ok := err.(*etcdErr.Error); ok {
   170  				log.Debug("Return error: ", (*etcdErr).Error())
   171  				w.Header().Set("Content-Type", "application/json")
   172  				etcdErr.Write(w)
   173  			} else {
   174  				http.Error(w, err.Error(), http.StatusInternalServerError)
   175  			}
   176  		}
   177  	})
   178  }
   179  
   180  func (s *Server) HTTPHandler() http.Handler {
   181  	router := mux.NewRouter()
   182  
   183  	// Install the routes.
   184  	s.handleFunc(router, "/version", s.GetVersionHandler).Methods("GET")
   185  	s.installV1(router)
   186  	s.installV2(router)
   187  	s.installMod(router)
   188  
   189  	if s.trace {
   190  		s.installDebug(router)
   191  	}
   192  
   193  	return router
   194  }
   195  
   196  // Dispatch command to the current leader
   197  func (s *Server) Dispatch(c raft.Command, w http.ResponseWriter, req *http.Request) error {
   198  	ps := s.peerServer
   199  	if ps.raftServer.State() == raft.Leader {
   200  		result, err := ps.raftServer.Do(c)
   201  		if err != nil {
   202  			return err
   203  		}
   204  
   205  		if result == nil {
   206  			return etcdErr.NewError(300, "Empty result from raft", s.Store().Index())
   207  		}
   208  
   209  		// response for raft related commands[join/remove]
   210  		if b, ok := result.([]byte); ok {
   211  			w.WriteHeader(http.StatusOK)
   212  			w.Write(b)
   213  			return nil
   214  		}
   215  
   216  		var b []byte
   217  		if strings.HasPrefix(req.URL.Path, "/v1") {
   218  			b, _ = json.Marshal(result.(*store.Event).Response(0))
   219  			w.WriteHeader(http.StatusOK)
   220  		} else {
   221  			e, _ := result.(*store.Event)
   222  			b, _ = json.Marshal(e)
   223  
   224  			w.Header().Set("Content-Type", "application/json")
   225  			// etcd index should be the same as the event index
   226  			// which is also the last modified index of the node
   227  			w.Header().Add("X-Etcd-Index", fmt.Sprint(e.Index()))
   228  			w.Header().Add("X-Raft-Index", fmt.Sprint(s.CommitIndex()))
   229  			w.Header().Add("X-Raft-Term", fmt.Sprint(s.Term()))
   230  
   231  			if e.IsCreated() {
   232  				w.WriteHeader(http.StatusCreated)
   233  			} else {
   234  				w.WriteHeader(http.StatusOK)
   235  			}
   236  		}
   237  
   238  		w.Write(b)
   239  
   240  		return nil
   241  
   242  	} else {
   243  		leader := ps.raftServer.Leader()
   244  
   245  		// No leader available.
   246  		if leader == "" {
   247  			return etcdErr.NewError(300, "", s.Store().Index())
   248  		}
   249  
   250  		var url string
   251  		switch c.(type) {
   252  		case *JoinCommand, *RemoveCommand:
   253  			url, _ = ps.registry.PeerURL(leader)
   254  		default:
   255  			url, _ = ps.registry.ClientURL(leader)
   256  		}
   257  		uhttp.Redirect(url, w, req)
   258  
   259  		return nil
   260  	}
   261  }
   262  
   263  // Handler to return the current version of etcd.
   264  func (s *Server) GetVersionHandler(w http.ResponseWriter, req *http.Request) error {
   265  	w.WriteHeader(http.StatusOK)
   266  	fmt.Fprintf(w, "etcd %s", ReleaseVersion)
   267  	return nil
   268  }
   269  
   270  // Handler to return the current leader's raft address
   271  func (s *Server) GetLeaderHandler(w http.ResponseWriter, req *http.Request) error {
   272  	leader := s.peerServer.RaftServer().Leader()
   273  	if leader == "" {
   274  		return etcdErr.NewError(etcdErr.EcodeLeaderElect, "", s.Store().Index())
   275  	}
   276  	w.WriteHeader(http.StatusOK)
   277  	url, _ := s.registry.PeerURL(leader)
   278  	w.Write([]byte(url))
   279  	return nil
   280  }
   281  
   282  // Handler to return all the known peers in the current cluster.
   283  func (s *Server) GetPeersHandler(w http.ResponseWriter, req *http.Request) error {
   284  	peers := s.registry.ClientURLs(s.peerServer.RaftServer().Leader(), s.Name)
   285  	w.WriteHeader(http.StatusOK)
   286  	w.Write([]byte(strings.Join(peers, ", ")))
   287  	return nil
   288  }
   289  
   290  // Retrieves stats on the Raft server.
   291  func (s *Server) GetStatsHandler(w http.ResponseWriter, req *http.Request) error {
   292  	w.Write(s.peerServer.Stats())
   293  	return nil
   294  }
   295  
   296  // Retrieves stats on the leader.
   297  func (s *Server) GetLeaderStatsHandler(w http.ResponseWriter, req *http.Request) error {
   298  	if s.peerServer.RaftServer().State() == raft.Leader {
   299  		w.Write(s.peerServer.PeerStats())
   300  		return nil
   301  	}
   302  
   303  	leader := s.peerServer.RaftServer().Leader()
   304  	if leader == "" {
   305  		return etcdErr.NewError(300, "", s.Store().Index())
   306  	}
   307  	hostname, _ := s.registry.ClientURL(leader)
   308  	uhttp.Redirect(hostname, w, req)
   309  	return nil
   310  }
   311  
   312  // Retrieves stats on the leader.
   313  func (s *Server) GetStoreStatsHandler(w http.ResponseWriter, req *http.Request) error {
   314  	w.Write(s.store.JsonStats())
   315  	return nil
   316  }
   317  
   318  // Executes a speed test to evaluate the performance of update replication.
   319  func (s *Server) SpeedTestHandler(w http.ResponseWriter, req *http.Request) error {
   320  	count := 1000
   321  	c := make(chan bool, count)
   322  	for i := 0; i < count; i++ {
   323  		go func() {
   324  			for j := 0; j < 10; j++ {
   325  				c := s.Store().CommandFactory().CreateSetCommand("foo", false, "bar", time.Unix(0, 0))
   326  				s.peerServer.RaftServer().Do(c)
   327  			}
   328  			c <- true
   329  		}()
   330  	}
   331  
   332  	for i := 0; i < count; i++ {
   333  		<-c
   334  	}
   335  
   336  	w.WriteHeader(http.StatusOK)
   337  	w.Write([]byte("speed test success"))
   338  	return nil
   339  }
   340  
   341  // Retrieves metrics from bucket
   342  func (s *Server) GetMetricsHandler(w http.ResponseWriter, req *http.Request) error {
   343  	(*s.metrics).Dump(w)
   344  	return nil
   345  }