示例#1
0
// publish registers server information into the cluster. The information
// is the JSON representation of this server's member struct, updated with the
// static clientURLs of the server.
// The function keeps attempting to register until it succeeds,
// or its server is stopped.
func (s *EtcdServer) publish(retryInterval time.Duration) {
	b, err := json.Marshal(s.attributes)
	if err != nil {
		log.Printf("etcdserver: json marshal error: %v", err)
		return
	}
	req := pb.Request{
		ID:     GenID(),
		Method: "PUT",
		Path:   path.Join(memberStoreKey(s.id), attributesSuffix),
		Val:    string(b),
	}

	for {
		ctx, cancel := context.WithTimeout(context.Background(), retryInterval)
		_, err := s.Do(ctx, req)
		cancel()
		switch err {
		case nil:
			log.Printf("etcdserver: published %+v to cluster %x", s.attributes, s.Cluster.ID())
			return
		case ErrStopped:
			log.Printf("etcdserver: aborting publish because server is stopped")
			return
		default:
			log.Printf("etcdserver: publish error: %v", err)
		}
	}
}
示例#2
0
func ExampleWithTimeout() {
	// Pass a context with a timeout to tell a blocking function that it
	// should abandon its work after the timeout elapses.
	ctx, _ := context.WithTimeout(context.Background(), 100*time.Millisecond)
	select {
	case <-time.After(200 * time.Millisecond):
		fmt.Println("overslept")
	case <-ctx.Done():
		fmt.Println(ctx.Err()) // prints "context deadline exceeded"
	}
	// Output:
	// context deadline exceeded
}
示例#3
0
func (h *keysHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if !allowMethod(w, r.Method, "GET", "PUT", "POST", "DELETE") {
		return
	}
	cid := strconv.FormatUint(h.clusterInfo.ID(), 16)
	w.Header().Set("X-Etcd-Cluster-ID", cid)

	ctx, cancel := context.WithTimeout(context.Background(), h.timeout)
	defer cancel()

	rr, err := parseKeyRequest(r, etcdserver.GenID(), clockwork.NewRealClock())
	if err != nil {
		writeError(w, err)
		return
	}

	resp, err := h.server.Do(ctx, rr)
	if err != nil {
		err = trimErrorPrefix(err, etcdserver.StoreKeysPrefix)
		writeError(w, err)
		return
	}

	switch {
	case resp.Event != nil:
		if err := writeKeyEvent(w, resp.Event, h.timer); err != nil {
			// Should never be reached
			log.Printf("error writing event: %v", err)
		}
	case resp.Watcher != nil:
		ctx, cancel := context.WithTimeout(context.Background(), defaultWatchTimeout)
		defer cancel()
		handleKeyWatch(ctx, w, resp.Watcher, rr.Stream, h.timer)
	default:
		writeError(w, errors.New("received response with no Event/Watcher!"))
	}
}
示例#4
0
// sync proposes a SYNC request and is non-blocking.
// This makes no guarantee that the request will be proposed or performed.
// The request will be cancelled after the given timeout.
func (s *EtcdServer) sync(timeout time.Duration) {
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	req := pb.Request{
		Method: "SYNC",
		ID:     GenID(),
		Time:   time.Now().UnixNano(),
	}
	data := pbutil.MustMarshal(&req)
	// There is no promise that node has leader when do SYNC request,
	// so it uses goroutine to propose.
	go func() {
		s.node.Propose(ctx, data)
		cancel()
	}()
}
示例#5
0
func (c *httpClient) doWithTimeout(act httpAction) (*http.Response, []byte, error) {
	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
	defer cancel()
	return c.do(ctx, act)
}
示例#6
0
func (h *adminMembersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if !allowMethod(w, r.Method, "GET", "POST", "DELETE") {
		return
	}
	cid := strconv.FormatUint(h.clusterInfo.ID(), 16)
	w.Header().Set("X-Etcd-Cluster-ID", cid)

	ctx, cancel := context.WithTimeout(context.Background(), defaultServerTimeout)
	defer cancel()

	switch r.Method {
	case "GET":
		if trimPrefix(r.URL.Path, adminMembersPrefix) != "" {
			writeError(w, httptypes.NewHTTPError(http.StatusNotFound, "Not found"))
			return
		}
		mc := newMemberCollection(h.clusterInfo.Members())
		w.Header().Set("Content-Type", "application/json")
		if err := json.NewEncoder(w).Encode(mc); err != nil {
			log.Printf("etcdhttp: %v", err)
		}
	case "POST":
		ctype := r.Header.Get("Content-Type")
		if ctype != "application/json" {
			writeError(w, httptypes.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Bad Content-Type %s, accept application/json", ctype)))
			return
		}
		b, err := ioutil.ReadAll(r.Body)
		if err != nil {
			writeError(w, httptypes.NewHTTPError(http.StatusBadRequest, err.Error()))
			return
		}
		raftAttr := etcdserver.RaftAttributes{}
		if err := json.Unmarshal(b, &raftAttr); err != nil {
			writeError(w, httptypes.NewHTTPError(http.StatusBadRequest, err.Error()))
			return
		}
		validURLs, err := types.NewURLs(raftAttr.PeerURLs)
		if err != nil {
			writeError(w, httptypes.NewHTTPError(http.StatusBadRequest, "Bad peer urls"))
			return
		}
		now := h.clock.Now()
		m := etcdserver.NewMember("", validURLs, "", &now)
		if err := h.server.AddMember(ctx, *m); err != nil {
			log.Printf("etcdhttp: error adding node %x: %v", m.ID, err)
			writeError(w, err)
			return
		}
		log.Printf("etcdhttp: added node %x with peer urls %v", m.ID, raftAttr.PeerURLs)
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusCreated)
		if err := json.NewEncoder(w).Encode(m); err != nil {
			log.Printf("etcdhttp: %v", err)
		}
	case "DELETE":
		idStr := trimPrefix(r.URL.Path, adminMembersPrefix)
		if idStr == "" {
			http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
			return
		}
		id, err := strconv.ParseUint(idStr, 16, 64)
		if err != nil {
			writeError(w, httptypes.NewHTTPError(http.StatusBadRequest, err.Error()))
			return
		}
		log.Printf("etcdhttp: remove node %x", id)
		if err := h.server.RemoveMember(ctx, id); err != nil {
			log.Printf("etcdhttp: error removing node %x: %v", id, err)
			writeError(w, err)
			return
		}
		w.WriteHeader(http.StatusNoContent)
	}
}