go.etcd.io/etcd@v3.3.27+incompatible/etcdserver/api/v3election/election.go (about) 1 // Copyright 2017 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package v3election 16 17 import ( 18 "context" 19 "errors" 20 21 "github.com/coreos/etcd/clientv3" 22 "github.com/coreos/etcd/clientv3/concurrency" 23 epb "github.com/coreos/etcd/etcdserver/api/v3election/v3electionpb" 24 ) 25 26 // ErrMissingLeaderKey is returned when election API request 27 // is missing the "leader" field. 28 var ErrMissingLeaderKey = errors.New(`"leader" field must be provided`) 29 30 type electionServer struct { 31 c *clientv3.Client 32 } 33 34 func NewElectionServer(c *clientv3.Client) epb.ElectionServer { 35 return &electionServer{c} 36 } 37 38 func (es *electionServer) Campaign(ctx context.Context, req *epb.CampaignRequest) (*epb.CampaignResponse, error) { 39 s, err := es.session(ctx, req.Lease) 40 if err != nil { 41 return nil, err 42 } 43 e := concurrency.NewElection(s, string(req.Name)) 44 if err = e.Campaign(ctx, string(req.Value)); err != nil { 45 return nil, err 46 } 47 return &epb.CampaignResponse{ 48 Header: e.Header(), 49 Leader: &epb.LeaderKey{ 50 Name: req.Name, 51 Key: []byte(e.Key()), 52 Rev: e.Rev(), 53 Lease: int64(s.Lease()), 54 }, 55 }, nil 56 } 57 58 func (es *electionServer) Proclaim(ctx context.Context, req *epb.ProclaimRequest) (*epb.ProclaimResponse, error) { 59 if req.Leader == nil { 60 return nil, ErrMissingLeaderKey 61 } 62 s, err := es.session(ctx, req.Leader.Lease) 63 if err != nil { 64 return nil, err 65 } 66 e := concurrency.ResumeElection(s, string(req.Leader.Name), string(req.Leader.Key), req.Leader.Rev) 67 if err := e.Proclaim(ctx, string(req.Value)); err != nil { 68 return nil, err 69 } 70 return &epb.ProclaimResponse{Header: e.Header()}, nil 71 } 72 73 func (es *electionServer) Observe(req *epb.LeaderRequest, stream epb.Election_ObserveServer) error { 74 s, err := es.session(stream.Context(), -1) 75 if err != nil { 76 return err 77 } 78 e := concurrency.NewElection(s, string(req.Name)) 79 ch := e.Observe(stream.Context()) 80 for stream.Context().Err() == nil { 81 select { 82 case <-stream.Context().Done(): 83 case resp, ok := <-ch: 84 if !ok { 85 return nil 86 } 87 lresp := &epb.LeaderResponse{Header: resp.Header, Kv: resp.Kvs[0]} 88 if err := stream.Send(lresp); err != nil { 89 return err 90 } 91 } 92 } 93 return stream.Context().Err() 94 } 95 96 func (es *electionServer) Leader(ctx context.Context, req *epb.LeaderRequest) (*epb.LeaderResponse, error) { 97 s, err := es.session(ctx, -1) 98 if err != nil { 99 return nil, err 100 } 101 l, lerr := concurrency.NewElection(s, string(req.Name)).Leader(ctx) 102 if lerr != nil { 103 return nil, lerr 104 } 105 return &epb.LeaderResponse{Header: l.Header, Kv: l.Kvs[0]}, nil 106 } 107 108 func (es *electionServer) Resign(ctx context.Context, req *epb.ResignRequest) (*epb.ResignResponse, error) { 109 if req.Leader == nil { 110 return nil, ErrMissingLeaderKey 111 } 112 s, err := es.session(ctx, req.Leader.Lease) 113 if err != nil { 114 return nil, err 115 } 116 e := concurrency.ResumeElection(s, string(req.Leader.Name), string(req.Leader.Key), req.Leader.Rev) 117 if err := e.Resign(ctx); err != nil { 118 return nil, err 119 } 120 return &epb.ResignResponse{Header: e.Header()}, nil 121 } 122 123 func (es *electionServer) session(ctx context.Context, lease int64) (*concurrency.Session, error) { 124 s, err := concurrency.NewSession( 125 es.c, 126 concurrency.WithLease(clientv3.LeaseID(lease)), 127 concurrency.WithContext(ctx), 128 ) 129 if err != nil { 130 return nil, err 131 } 132 s.Orphan() 133 return s, nil 134 }