@@ -3,15 +3,16 @@ package ballot
33import (
44 "encoding/json"
55 "fmt"
6+ "os/exec"
7+ "sync/atomic"
8+ "time"
9+
610 "github.com/google/shlex"
711 "github.com/hashicorp/consul/api"
812 "github.com/hashicorp/consul/api/watch"
913 log "github.com/sirupsen/logrus"
1014 "golang.org/x/exp/slices"
1115 "golang.org/x/net/context"
12- "os/exec"
13- "sync/atomic"
14- "time"
1516)
1617
1718type ElectionPayload struct {
@@ -86,6 +87,31 @@ func (b *Ballot) copyServiceToRegistration(service *api.AgentService) *api.Agent
8687 }
8788}
8889
90+ func (b * Ballot ) copyCatalogServiceToRegistration (service * api.CatalogService ) * api.CatalogRegistration {
91+ return & api.CatalogRegistration {
92+ ID : service .ID ,
93+ Node : service .Node ,
94+ Address : service .ServiceAddress ,
95+ TaggedAddresses : service .TaggedAddresses ,
96+ NodeMeta : service .NodeMeta ,
97+ Datacenter : service .Datacenter ,
98+ Service : & api.AgentService {
99+ ID : service .ServiceID ,
100+ Service : service .ServiceName ,
101+ Tags : service .ServiceTags ,
102+ Meta : service .ServiceMeta ,
103+ Port : service .ServicePort ,
104+ Address : service .ServiceAddress ,
105+ TaggedAddresses : service .ServiceTaggedAddresses ,
106+ Weights : api.AgentWeights {
107+ Passing : service .ServiceWeights .Passing ,
108+ Warning : service .ServiceWeights .Warning ,
109+ },
110+ EnableTagOverride : service .ServiceEnableTagOverride ,
111+ },
112+ }
113+ }
114+
89115// Run starts the leader election.
90116func (b * Ballot ) Run () (err error ) {
91117 b .ctx = context .Background ()
@@ -102,22 +128,26 @@ func (b *Ballot) Run() (err error) {
102128}
103129
104130// getService returns the registered service.
105- func (b * Ballot ) getService () (service * api.AgentService , err error ) {
131+ func (b * Ballot ) getService () (service * api.AgentService , catalogServices [] * api. CatalogService , err error ) {
106132 agent := b .client .Agent ()
107- services , err : = agent .Services ( )
133+ service , _ , err = agent .Service ( b . ID , & api. QueryOptions {} )
108134 if err != nil {
109- return service , err
135+ return service , nil , err
110136 }
111- service , ok := services [b .ID ]
112- if ! ok {
113- return service , fmt .Errorf ("service %s not found" , b .ID )
137+ if service == nil {
138+ return service , nil , fmt .Errorf ("service %s not found" , b .ID )
114139 }
115- return service , err
140+ catalog := b .client .Catalog ()
141+ catalogServices , _ , err = catalog .Service (b .ID , b .PrimaryTag , & api.QueryOptions {})
142+ if err != nil {
143+ return service , nil , err
144+ }
145+ return service , catalogServices , err
116146}
117147
118148// updateServiceTags updates the service tags.
119149func (b * Ballot ) updateServiceTags () error {
120- service , err := b .getService ()
150+ service , _ , err := b .getService ()
121151 if err != nil {
122152 return err
123153 }
@@ -156,6 +186,42 @@ func (b *Ballot) updateServiceTags() error {
156186 return err
157187}
158188
189+ // cleanup is called on promote, it cleans up tags on the instances of the service, useful if an other ballot stopped unexpectedly
190+ func (b * Ballot ) cleanup () error {
191+ service , catalogServices , err := b .getService ()
192+ if err != nil {
193+ return err
194+ }
195+ for _ , catcatalogService := range catalogServices {
196+ if catcatalogService .Address != service .Address {
197+ p := slices .Index (catcatalogService .ServiceTags , b .PrimaryTag )
198+ if p == - 1 {
199+ return nil
200+ }
201+ log .WithFields (log.Fields {
202+ "caller" : "cleanupCatalogServiceTags" ,
203+ "service" : b .ID ,
204+ "node" : catcatalogService .Node ,
205+ "tags" : catcatalogService .ServiceTags ,
206+ }).Debug ("current service tags" )
207+ catcatalogService .ServiceTags = slices .Delete (catcatalogService .ServiceTags , p , p + 1 )
208+ catalog := b .client .Catalog ()
209+ reg := b .copyCatalogServiceToRegistration (catcatalogService )
210+ _ , err := catalog .Register (reg , & api.WriteOptions {})
211+ if err != nil {
212+ return err
213+ }
214+ log .WithFields (log.Fields {
215+ "caller" : "cleanupCatalogServiceTags" ,
216+ "service" : b .ID ,
217+ "node" : catcatalogService .Node ,
218+ "tags" : catcatalogService .ServiceTags ,
219+ }).Debug ("new service tags" )
220+ }
221+ }
222+ return nil
223+ }
224+
159225// onPromote is called when the node is promoted to leader.
160226func (b * Ballot ) onPromote () (err error ) {
161227 b .leader .Store (true )
@@ -164,6 +230,11 @@ func (b *Ballot) onPromote() (err error) {
164230 b .releaseSession ()
165231 return fmt .Errorf ("failed to update service tags: %s" , err )
166232 }
233+ err = b .cleanup ()
234+ if err != nil {
235+ b .releaseSession ()
236+ return fmt .Errorf ("failed to cleanup old service tags: %s" , err )
237+ }
167238 return err
168239}
169240
@@ -182,7 +253,7 @@ func (b *Ballot) election() (err error) {
182253
183254 if ! b .leader .Load () {
184255 if b .sessionID .Load () != nil {
185- service , err := b .getService ()
256+ service , _ , err := b .getService ()
186257 if err != nil {
187258 return fmt .Errorf ("failed to get service: %s" , err )
188259 }
0 commit comments