1
// Copyright 2015 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
7
"github.com/juju/errors"
9
"github.com/juju/juju/worker/uniter/hook"
12
type acceptLeadership struct {
13
DoesNotRequireMachineLock
16
// String is part of the Operation interface.
17
func (al *acceptLeadership) String() string {
18
return "accept leadership"
21
// Prepare is part of the Operation interface.
22
func (al *acceptLeadership) Prepare(state State) (*State, error) {
23
if err := al.checkState(state); err != nil {
26
return nil, ErrSkipExecute
29
// Execute is part of the Operation interface.
30
func (al *acceptLeadership) Execute(state State) (*State, error) {
31
return nil, errors.New("prepare always errors; Execute is never valid")
34
// Commit is part of the Operation interface.
35
func (al *acceptLeadership) Commit(state State) (*State, error) {
36
if err := al.checkState(state); err != nil {
40
// Nothing needs to be done -- leader is only set when queueing a
41
// leader-elected hook. Therefore, if leader is true, the appropriate
42
// hook must be either queued or already run.
45
newState := stateChange{
48
Hook: &hook.Info{Kind: hook.LeaderElected},
50
newState.Leader = true
54
func (al *acceptLeadership) checkState(state State) error {
55
if state.Kind != Continue {
56
// We'll need to queue up a hook, and we can't do that without
57
// stomping on existing state.
58
return ErrCannotAcceptLeadership
63
type resignLeadership struct {
64
DoesNotRequireMachineLock
67
// String is part of the Operation interface.
68
func (rl *resignLeadership) String() string {
69
return "resign leadership"
72
// Prepare is part of the Operation interface.
73
func (rl *resignLeadership) Prepare(state State) (*State, error) {
75
// Nothing needs to be done -- state.Leader should only be set to
76
// false when committing the leader-deposed hook. This code is not
77
// helpful while Execute is a no-op, but it will become so.
78
return nil, ErrSkipExecute
83
// Execute is part of the Operation interface.
84
func (rl *resignLeadership) Execute(state State) (*State, error) {
85
// TODO(fwereade): this hits a lot of interestingly intersecting problems.
87
// 1) we can't yet create a sufficiently dumbed-down hook context for a
88
// leader-deposed hook to run as specced. (This is the proximate issue,
89
// and is sufficient to prevent us from implementing this op right.)
90
// 2) we want to write a state-file change, so this has to be an operation
91
// (or, at least, it has to be serialized with all other operations).
92
// * note that the change we write must *not* include the RunHook
93
// operation for leader-deposed -- we want to run this at high
94
// priority, in any possible state, and not to disturn what's
95
// there other than to note that we no longer think we're leader.
96
// 3) the hook execution itself *might* not need to be serialized with
97
// other operations, which is moot until we consider that:
98
// 4) we want to invoke this behaviour from elsewhere (ie when we don't
99
// have an api connection available), but:
100
// 5) we can't get around the serialization requirement in (2).
102
// So. I *think* that the right approach is to implement a no-api uniter
103
// variant, that we run *instead of* the normal uniter when the API is
104
// unavailable, and replace with a real uniter when appropriate; this
105
// implies that we need to take care not to allow the implementations to
106
// diverge, but implementing them both as "uniters" is probably the best
107
// way to encourage logic-sharing and prevent that problem.
109
// In the short term, though, we can just run leader-deposed as soon as we
110
// can build the right environment. Not sure whether this particular type
111
// will still be justified, or whether it'll just be a plain old RunHook --
112
// I *think* it will stay, because the state-writing behaviour will stay
113
// very different (ie just write `.Leader = false` and don't step on pre-
115
logger.Warningf("we should run a leader-deposed hook here, but we can't yet")
119
// Commit is part of the Operation interface.
120
func (rl *resignLeadership) Commit(state State) (*State, error) {