github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/uniter/leadership/resolver.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package leadership 5 6 import ( 7 "github.com/juju/charm/v12/hooks" 8 9 "github.com/juju/juju/core/life" 10 "github.com/juju/juju/worker/uniter/hook" 11 "github.com/juju/juju/worker/uniter/operation" 12 "github.com/juju/juju/worker/uniter/remotestate" 13 "github.com/juju/juju/worker/uniter/resolver" 14 ) 15 16 // Logger is here to stop the desire of creating a package level Logger. 17 // Don't do this, instead use the one passed into the NewResolver as needed. 18 type logger interface{} 19 20 var _ logger = struct{}{} 21 22 // Logger defines the logging methods used by the leadership package. 23 type Logger interface { 24 Tracef(string, ...interface{}) 25 } 26 27 type leadershipResolver struct { 28 logger Logger 29 } 30 31 // NewResolver returns a new leadership resolver. 32 func NewResolver(logger Logger) resolver.Resolver { 33 return &leadershipResolver{logger: logger} 34 } 35 36 // NextOp is defined on the Resolver interface. 37 func (l *leadershipResolver) NextOp( 38 localState resolver.LocalState, 39 remoteState remotestate.Snapshot, 40 opFactory operation.Factory, 41 ) (operation.Operation, error) { 42 43 // TODO(wallyworld) - maybe this can occur before install 44 if !localState.Installed { 45 return nil, resolver.ErrNoOperation 46 } 47 48 // Check for any leadership change, and enact it if possible. 49 l.logger.Tracef("checking leadership status") 50 51 // If we've already accepted leadership, we don't need to do it again. 52 canAcceptLeader := !localState.Leader 53 if remoteState.Life == life.Dying { 54 canAcceptLeader = false 55 } else { 56 // If we're in an unexpected mode (eg pending hook) we shouldn't try either. 57 if localState.Kind != operation.Continue { 58 canAcceptLeader = false 59 } 60 } 61 62 switch { 63 case remoteState.Leader && canAcceptLeader: 64 return opFactory.NewAcceptLeadership() 65 66 // If we're the leader but should not be any longer, or 67 // if the unit is dying, we should resign leadership. 68 case localState.Leader && (!remoteState.Leader || remoteState.Life == life.Dying): 69 return opFactory.NewResignLeadership() 70 } 71 72 if localState.Kind == operation.Continue { 73 // We want to run the leader settings hook if we're 74 // not the leader and the settings have changed. 75 // Note though that if we are dying, we may have already executed "resign leadership". 76 // In this case, as far as the unit agent is concerned, we are not the leader any more 77 // but we don't want to run the leader settings hook as the transition away from leadership 78 // has only been recorded locally, and the Juju model still has us as a leader that is dying. 79 if !localState.Leader && remoteState.Life != life.Dying && localState.LeaderSettingsVersion != remoteState.LeaderSettingsVersion { 80 return opFactory.NewRunHook(hook.Info{Kind: hooks.LeaderSettingsChanged}) 81 } 82 } 83 84 l.logger.Tracef("leadership status is up-to-date") 85 return nil, resolver.ErrNoOperation 86 }