Initial code for RaftActorServerConfigurationSupport
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / main / java / org / opendaylight / controller / cluster / raft / RaftActorServerConfigurationSupport.java
1 /*
2  * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.cluster.raft;
9
10 import akka.actor.ActorRef;
11 import akka.actor.ActorSelection;
12 import org.opendaylight.controller.cluster.raft.FollowerLogInformation.FollowerState;
13 import org.opendaylight.controller.cluster.raft.behaviors.AbstractLeader;
14 import org.opendaylight.controller.cluster.raft.messages.AddServer;
15 import org.opendaylight.controller.cluster.raft.messages.AddServerReply;
16 import org.opendaylight.controller.cluster.raft.messages.ServerChangeStatus;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
19
20 /**
21  * Handles server configuration related messages for a RaftActor.
22  *
23  * @author Thomas Pantelis
24  */
25 class RaftActorServerConfigurationSupport {
26     private static final Logger LOG = LoggerFactory.getLogger(RaftActorServerConfigurationSupport.class);
27
28     private final RaftActorContext context;
29
30     RaftActorServerConfigurationSupport(RaftActorContext context) {
31         this.context = context;
32     }
33
34     boolean handleMessage(Object message, RaftActor raftActor, ActorRef sender) {
35         if(message instanceof AddServer) {
36             onAddServer((AddServer)message, raftActor, sender);
37             return true;
38         } else {
39             return false;
40         }
41     }
42
43     private void onAddServer(AddServer addServer, RaftActor raftActor, ActorRef sender) {
44         LOG.debug("onAddServer: {}", addServer);
45
46         if(noLeaderOrForwardedToLeader(addServer, raftActor, sender)) {
47             return;
48         }
49
50         // TODO - check if a server config is in progress. If so, cache this AddServer request to be processed
51         // after the current one is done.
52
53         context.addToPeers(addServer.getNewServerId(), addServer.getNewServerAddress());
54
55         AbstractLeader leader = (AbstractLeader) raftActor.getCurrentBehavior();
56         FollowerState initialState = addServer.isVotingMember() ? FollowerState.VOTING_NOT_INITIALIZED :
57             FollowerState.NON_VOTING;
58         leader.addFollower(addServer.getNewServerId(), initialState);
59
60         // TODO
61         // if initialState == FollowerState.VOTING_NOT_INITIALIZED
62         //     Initiate snapshot via leader.initiateCaptureSnapshot(addServer.getNewServerId())
63         //     Start a timer to abort the operation after a period of time (maybe 2 times election timeout)
64         //     Set local instance state and wait for message from the AbstractLeader when install snapshot is done and return now
65         //     When install snapshot message is received, go to step 1
66         // else
67         //     go to step 2
68         //
69         // 1) tell AbstractLeader mark the follower as VOTING and recalculate minReplicationCount and
70         //        minIsolatedLeaderPeerCount
71         // 2) persist and replicate ServerConfigurationPayload via
72         //           raftActor.persistData(sender, uuid, newServerConfigurationPayload)
73         // 3) Wait for commit complete via ApplyState message in RaftActor or time it out. In RaftActor,
74         //       on ApplyState, check if ReplicatedLogEntry payload is ServerConfigurationPayload and call
75         //       this class.
76         //
77
78         // TODO - temporary
79         sender.tell(new AddServerReply(ServerChangeStatus.OK, raftActor.getLeaderId()), raftActor.self());
80     }
81
82     private boolean noLeaderOrForwardedToLeader(Object message, RaftActor raftActor, ActorRef sender) {
83         if (raftActor.isLeader()) {
84             return false;
85         }
86
87         ActorSelection leader = raftActor.getLeader();
88         if (leader != null) {
89             LOG.debug("Not leader - forwarding to leader {}", leader);
90             leader.forward(message, raftActor.getContext());
91         } else {
92             LOG.debug("No leader - returning NO_LEADER AddServerReply");
93             sender.tell(new AddServerReply(ServerChangeStatus.NO_LEADER, null), raftActor.self());
94         }
95
96         return true;
97     }
98 }