// 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(timeout time.Duration) { b, err := json.Marshal(s.attributes) if err != nil { plog.Panicf("json marshal error: %v", err) return } req := pb.Request{ Method: "PUT", Path: membership.MemberAttributesStorePath(s.id), Val: string(b), } for { ctx, cancel := context.WithTimeout(context.Background(), timeout) _, err := s.Do(ctx, req) cancel() switch err { case nil: close(s.readych) plog.Infof("published %+v to cluster %s", s.attributes, s.cluster.ID()) return case ErrStopped: plog.Infof("aborting publish because server is stopped") return default: plog.Errorf("publish error: %v", err) } } }
func TestPublish(t *testing.T) { n := newNodeRecorder() ch := make(chan interface{}, 1) // simulate that request has gone through consensus ch <- Response{} w := wait.NewWithResponse(ch) srv := &EtcdServer{ readych: make(chan struct{}), cfg: &ServerConfig{TickMs: 1}, id: 1, r: raftNode{Node: n}, attributes: membership.Attributes{Name: "node1", ClientURLs: []string{"http://a", "http://b"}}, cluster: &membership.RaftCluster{}, w: w, reqIDGen: idutil.NewGenerator(0, time.Time{}), } srv.publish(time.Hour) action := n.Action() if len(action) != 1 { t.Fatalf("len(action) = %d, want 1", len(action)) } if action[0].Name != "Propose" { t.Fatalf("action = %s, want Propose", action[0].Name) } data := action[0].Params[0].([]byte) var r pb.Request if err := r.Unmarshal(data); err != nil { t.Fatalf("unmarshal request error: %v", err) } if r.Method != "PUT" { t.Errorf("method = %s, want PUT", r.Method) } wm := membership.Member{ID: 1, Attributes: membership.Attributes{Name: "node1", ClientURLs: []string{"http://a", "http://b"}}} if wpath := membership.MemberAttributesStorePath(wm.ID); r.Path != wpath { t.Errorf("path = %s, want %s", r.Path, wpath) } var gattr membership.Attributes if err := json.Unmarshal([]byte(r.Val), &gattr); err != nil { t.Fatalf("unmarshal val error: %v", err) } if !reflect.DeepEqual(gattr, wm.Attributes) { t.Errorf("member = %v, want %v", gattr, wm.Attributes) } }
func TestApplyRequestOnAdminMemberAttributes(t *testing.T) { cl := newTestCluster([]*membership.Member{{ID: 1}}) srv := &EtcdServer{ store: mockstore.NewRecorder(), cluster: cl, } req := pb.Request{ Method: "PUT", ID: 1, Path: membership.MemberAttributesStorePath(1), Val: `{"Name":"abc","ClientURLs":["http://127.0.0.1:2379"]}`, } srv.applyRequest(req) w := membership.Attributes{Name: "abc", ClientURLs: []string{"http://127.0.0.1:2379"}} if g := cl.Member(1).Attributes; !reflect.DeepEqual(g, w) { t.Errorf("attributes = %v, want %v", g, w) } }