blob: b2fe19fb6f780064de56462049f64ded7b31dc2f [file] [log] [blame]
Madan Jampani08822c42014-11-04 17:17:46 -08001package org.onlab.onos.store.service.impl;
2
3import static org.slf4j.LoggerFactory.getLogger;
4
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -08005import java.io.File;
6import java.io.IOException;
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -08007import java.util.Collection;
8import java.util.Collections;
9import java.util.HashSet;
Madan Jampani08822c42014-11-04 17:17:46 -080010import java.util.List;
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -080011import java.util.Map;
12import java.util.Set;
Yuta HIGUCHI79a1e5e2014-11-05 17:42:01 -080013import java.util.concurrent.CountDownLatch;
14import java.util.concurrent.TimeUnit;
Madan Jampani08822c42014-11-04 17:17:46 -080015
16import net.kuujo.copycat.Copycat;
17import net.kuujo.copycat.StateMachine;
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -080018import net.kuujo.copycat.cluster.ClusterConfig;
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -080019import net.kuujo.copycat.cluster.Member;
Madan Jampani08822c42014-11-04 17:17:46 -080020import net.kuujo.copycat.cluster.TcpCluster;
21import net.kuujo.copycat.cluster.TcpClusterConfig;
22import net.kuujo.copycat.cluster.TcpMember;
Madan Jampani08822c42014-11-04 17:17:46 -080023import net.kuujo.copycat.log.Log;
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -080024
Madan Jampani08822c42014-11-04 17:17:46 -080025import org.apache.felix.scr.annotations.Activate;
Madan Jampanidfbfa182014-11-04 22:06:41 -080026import org.apache.felix.scr.annotations.Component;
Yuta HIGUCHI657626e2014-11-04 20:54:58 -080027import org.apache.felix.scr.annotations.Deactivate;
Madan Jampani08822c42014-11-04 17:17:46 -080028import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
Madan Jampanidfbfa182014-11-04 22:06:41 -080030import org.apache.felix.scr.annotations.Service;
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -080031import org.onlab.onos.cluster.ClusterEvent;
32import org.onlab.onos.cluster.ClusterEventListener;
Madan Jampani08822c42014-11-04 17:17:46 -080033import org.onlab.onos.cluster.ClusterService;
34import org.onlab.onos.cluster.ControllerNode;
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -080035import org.onlab.onos.cluster.DefaultControllerNode;
36import org.onlab.onos.cluster.NodeId;
Madan Jampani12390c12014-11-12 00:35:56 -080037import org.onlab.onos.store.service.BatchReadRequest;
38import org.onlab.onos.store.service.BatchReadResult;
39import org.onlab.onos.store.service.BatchWriteRequest;
40import org.onlab.onos.store.service.BatchWriteResult;
Madan Jampani08822c42014-11-04 17:17:46 -080041import org.onlab.onos.store.service.DatabaseAdminService;
42import org.onlab.onos.store.service.DatabaseException;
43import org.onlab.onos.store.service.DatabaseService;
Madan Jampani08822c42014-11-04 17:17:46 -080044import org.onlab.onos.store.service.ReadResult;
Madan Jampani12390c12014-11-12 00:35:56 -080045import org.onlab.onos.store.service.ReadStatus;
46import org.onlab.onos.store.service.VersionedValue;
Madan Jampani08822c42014-11-04 17:17:46 -080047import org.onlab.onos.store.service.WriteResult;
Madan Jampani12390c12014-11-12 00:35:56 -080048import org.onlab.onos.store.service.WriteStatus;
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -080049import org.onlab.packet.IpAddress;
Madan Jampani08822c42014-11-04 17:17:46 -080050import org.slf4j.Logger;
51
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -080052import com.google.common.collect.ImmutableList;
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -080053
Madan Jampani08822c42014-11-04 17:17:46 -080054/**
55 * Strongly consistent and durable state management service based on
56 * Copycat implementation of Raft consensus protocol.
57 */
Madan Jampanidfbfa182014-11-04 22:06:41 -080058@Component(immediate = true)
59@Service
Madan Jampani08822c42014-11-04 17:17:46 -080060public class DatabaseManager implements DatabaseService, DatabaseAdminService {
61
62 private final Logger log = getLogger(getClass());
63
64 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yuta HIGUCHI5001ba92014-11-04 21:33:54 -080065 protected ClusterService clusterService;
Madan Jampani08822c42014-11-04 17:17:46 -080066
Madan Jampani9b19a822014-11-04 21:37:13 -080067 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yuta HIGUCHI0c1c1002014-11-05 13:47:25 -080068 protected DatabaseProtocolService copycatMessagingProtocol;
Madan Jampani9b19a822014-11-04 21:37:13 -080069
Yuta HIGUCHI13a6f5a2014-11-12 10:07:47 -080070 // FIXME: point to appropriate path
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -080071 public static final String LOG_FILE_PREFIX = "/tmp/onos-copy-cat-log_";
72
73 // Current working dir seems to be /opt/onos/apache-karaf-3.0.2
Pavlin Radoslavov190f8f92014-11-11 15:56:14 -080074 // TODO: Set the path to /opt/onos/config
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -080075 private static final String CONFIG_DIR = "../config";
76
77 private static final String DEFAULT_MEMBER_FILE = "tablets.json";
78
79 private static final String DEFAULT_TABLET = "default";
80
81 // TODO: make this configurable
82 // initial member configuration file path
83 private String initialMemberConfig = DEFAULT_MEMBER_FILE;
Madan Jampani08822c42014-11-04 17:17:46 -080084
85 private Copycat copycat;
86 private DatabaseClient client;
87
Yuta HIGUCHI79a1e5e2014-11-05 17:42:01 -080088 // guarded by synchronized block
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -080089 private ClusterConfig<TcpMember> clusterConfig;
90
Yuta HIGUCHI79a1e5e2014-11-05 17:42:01 -080091 private CountDownLatch clusterEventLatch;
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -080092 private ClusterEventListener clusterEventListener;
93
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -080094 private Map<String, Set<DefaultControllerNode>> tabletMembers;
95
96 private boolean autoAddMember = false;
97
Madan Jampani08822c42014-11-04 17:17:46 -080098 @Activate
99 public void activate() {
Madan Jampanidfbfa182014-11-04 22:06:41 -0800100
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800101 // TODO: Not every node should be part of the consensus ring.
Madan Jampanidfbfa182014-11-04 22:06:41 -0800102
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800103 // load tablet configuration
104 File file = new File(CONFIG_DIR, initialMemberConfig);
105 log.info("Loading config: {}", file.getAbsolutePath());
106 TabletDefinitionStore tabletDef = new TabletDefinitionStore(file);
107 try {
108 tabletMembers = tabletDef.read();
109 } catch (IOException e) {
110 log.error("Failed to load tablet config {}", file);
111 throw new IllegalStateException("Failed to load tablet config", e);
112 }
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800113
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800114 // load default tablet configuration and start copycat
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800115 clusterConfig = new TcpClusterConfig();
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800116 Set<DefaultControllerNode> defaultMember = tabletMembers.get(DEFAULT_TABLET);
117 if (defaultMember == null || defaultMember.isEmpty()) {
118 log.error("No member found in [{}] tablet configuration.",
119 DEFAULT_TABLET);
120 throw new IllegalStateException("No member found in tablet configuration");
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800121
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800122 }
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800123
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800124 final ControllerNode localNode = clusterService.getLocalNode();
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800125 for (ControllerNode member : defaultMember) {
126 final TcpMember tcpMember = new TcpMember(member.ip().toString(),
127 member.tcpPort());
128 if (localNode.equals(member)) {
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800129 clusterConfig.setLocalMember(tcpMember);
130 } else {
131 clusterConfig.addRemoteMember(tcpMember);
132 }
133 }
134
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800135 // note: from this point beyond, clusterConfig requires synchronization
Yuta HIGUCHI79a1e5e2014-11-05 17:42:01 -0800136 clusterEventLatch = new CountDownLatch(1);
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800137 clusterEventListener = new InternalClusterEventListener();
138 clusterService.addListener(clusterEventListener);
Madan Jampani08822c42014-11-04 17:17:46 -0800139
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800140 if (clusterService.getNodes().size() < clusterConfig.getMembers().size()) {
141 // current cluster size smaller then expected
Yuta HIGUCHI79a1e5e2014-11-05 17:42:01 -0800142 try {
143 if (!clusterEventLatch.await(120, TimeUnit.SECONDS)) {
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800144 log.info("Starting with {}/{} nodes cluster",
145 clusterService.getNodes().size(),
146 clusterConfig.getMembers().size());
Yuta HIGUCHI79a1e5e2014-11-05 17:42:01 -0800147 }
148 } catch (InterruptedException e) {
149 log.info("Interrupted waiting for others", e);
150 }
151 }
Madan Jampani08822c42014-11-04 17:17:46 -0800152
Yuta HIGUCHI79a1e5e2014-11-05 17:42:01 -0800153 final TcpCluster cluster;
154 synchronized (clusterConfig) {
Yuta HIGUCHI79a1e5e2014-11-05 17:42:01 -0800155 // Create the cluster.
156 cluster = new TcpCluster(clusterConfig);
157 }
158 log.info("Starting cluster: {}", cluster);
159
Madan Jampani08822c42014-11-04 17:17:46 -0800160
161 StateMachine stateMachine = new DatabaseStateMachine();
Madan Jampani2ee20002014-11-06 20:06:12 -0800162 Log consensusLog = new MapDBLog(LOG_FILE_PREFIX + localNode.id(),
Yuta HIGUCHI361664e2014-11-06 17:28:47 -0800163 ClusterMessagingProtocol.SERIALIZER);
Madan Jampani08822c42014-11-04 17:17:46 -0800164
Madan Jampani9b19a822014-11-04 21:37:13 -0800165 copycat = new Copycat(stateMachine, consensusLog, cluster, copycatMessagingProtocol);
Madan Jampani08822c42014-11-04 17:17:46 -0800166 copycat.start();
167
Yuta HIGUCHIf8468442014-11-11 10:09:20 -0800168 client = new DatabaseClient(copycat);
Madan Jampani08822c42014-11-04 17:17:46 -0800169
170 log.info("Started.");
171 }
172
Yuta HIGUCHI657626e2014-11-04 20:54:58 -0800173 @Deactivate
Madan Jampani08822c42014-11-04 17:17:46 -0800174 public void deactivate() {
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800175 clusterService.removeListener(clusterEventListener);
Madan Jampani08822c42014-11-04 17:17:46 -0800176 copycat.stop();
Yuta HIGUCHI657626e2014-11-04 20:54:58 -0800177 log.info("Stopped.");
Madan Jampani08822c42014-11-04 17:17:46 -0800178 }
179
180 @Override
181 public boolean createTable(String name) {
182 return client.createTable(name);
183 }
184
185 @Override
186 public void dropTable(String name) {
187 client.dropTable(name);
188 }
189
190 @Override
191 public void dropAllTables() {
192 client.dropAllTables();
193 }
194
195 @Override
196 public List<String> listTables() {
197 return client.listTables();
198 }
199
200 @Override
Madan Jampani12390c12014-11-12 00:35:56 -0800201 public VersionedValue get(String tableName, String key) {
202 BatchReadRequest batchRequest = new BatchReadRequest.Builder().get(tableName, key).build();
203 ReadResult readResult = batchRead(batchRequest).getAsList().get(0);
204 if (readResult.status().equals(ReadStatus.OK)) {
205 return readResult.value();
Madan Jampani08822c42014-11-04 17:17:46 -0800206 }
Madan Jampani12390c12014-11-12 00:35:56 -0800207 throw new DatabaseException("get failed due to status: " + readResult.status());
Madan Jampani08822c42014-11-04 17:17:46 -0800208 }
209
210 @Override
Madan Jampani12390c12014-11-12 00:35:56 -0800211 public BatchReadResult batchRead(BatchReadRequest batchRequest) {
212 return new BatchReadResult(client.batchRead(batchRequest));
Yuta HIGUCHI361664e2014-11-06 17:28:47 -0800213 }
214
215 @Override
Madan Jampani12390c12014-11-12 00:35:56 -0800216 public BatchWriteResult batchWrite(BatchWriteRequest batchRequest) {
217 return new BatchWriteResult(client.batchWrite(batchRequest));
Madan Jampani08822c42014-11-04 17:17:46 -0800218 }
219
220 @Override
Madan Jampani12390c12014-11-12 00:35:56 -0800221 public VersionedValue put(String tableName, String key, byte[] value) {
222 BatchWriteRequest batchRequest = new BatchWriteRequest.Builder().put(tableName, key, value).build();
223 WriteResult writeResult = batchWrite(batchRequest).getAsList().get(0);
224 if (writeResult.status().equals(WriteStatus.OK)) {
225 return writeResult.previousValue();
Madan Jampani08822c42014-11-04 17:17:46 -0800226 }
Madan Jampani12390c12014-11-12 00:35:56 -0800227 throw new DatabaseException("put failed due to status: " + writeResult.status());
228 }
Madan Jampani08822c42014-11-04 17:17:46 -0800229
Madan Jampani12390c12014-11-12 00:35:56 -0800230 @Override
231 public boolean putIfAbsent(String tableName, String key, byte[] value) {
Madan Jampani44e6a542014-11-12 01:06:51 -0800232 BatchWriteRequest batchRequest = new BatchWriteRequest.Builder()
233 .putIfAbsent(tableName, key, value).build();
Madan Jampani12390c12014-11-12 00:35:56 -0800234 WriteResult writeResult = batchWrite(batchRequest).getAsList().get(0);
235 if (writeResult.status().equals(WriteStatus.OK)) {
236 return true;
237 } else if (writeResult.status().equals(WriteStatus.PRECONDITION_VIOLATION)) {
238 return false;
239 }
Madan Jampani44e6a542014-11-12 01:06:51 -0800240 throw new DatabaseException("putIfAbsent failed due to status: "
241 + writeResult.status());
Madan Jampani12390c12014-11-12 00:35:56 -0800242 }
243
244 @Override
245 public boolean putIfVersionMatches(String tableName, String key,
246 byte[] value, long version) {
Madan Jampani44e6a542014-11-12 01:06:51 -0800247 BatchWriteRequest batchRequest =
248 new BatchWriteRequest.Builder()
249 .putIfVersionMatches(tableName, key, value, version).build();
Madan Jampani12390c12014-11-12 00:35:56 -0800250 WriteResult writeResult = batchWrite(batchRequest).getAsList().get(0);
251 if (writeResult.status().equals(WriteStatus.OK)) {
252 return true;
253 } else if (writeResult.status().equals(WriteStatus.PRECONDITION_VIOLATION)) {
254 return false;
255 }
Madan Jampani44e6a542014-11-12 01:06:51 -0800256 throw new DatabaseException("putIfVersionMatches failed due to status: "
257 + writeResult.status());
Madan Jampani12390c12014-11-12 00:35:56 -0800258 }
259
260 @Override
261 public boolean putIfValueMatches(String tableName, String key,
262 byte[] oldValue, byte[] newValue) {
Madan Jampani44e6a542014-11-12 01:06:51 -0800263 BatchWriteRequest batchRequest = new BatchWriteRequest.Builder()
264 .putIfValueMatches(tableName, key, oldValue, newValue).build();
Madan Jampani12390c12014-11-12 00:35:56 -0800265 WriteResult writeResult = batchWrite(batchRequest).getAsList().get(0);
266 if (writeResult.status().equals(WriteStatus.OK)) {
267 return true;
268 } else if (writeResult.status().equals(WriteStatus.PRECONDITION_VIOLATION)) {
269 return false;
270 }
Madan Jampani44e6a542014-11-12 01:06:51 -0800271 throw new DatabaseException("putIfValueMatches failed due to status: "
272 + writeResult.status());
Madan Jampani12390c12014-11-12 00:35:56 -0800273 }
274
275 @Override
276 public VersionedValue remove(String tableName, String key) {
Madan Jampani44e6a542014-11-12 01:06:51 -0800277 BatchWriteRequest batchRequest = new BatchWriteRequest.Builder()
278 .remove(tableName, key).build();
Madan Jampani12390c12014-11-12 00:35:56 -0800279 WriteResult writeResult = batchWrite(batchRequest).getAsList().get(0);
280 if (writeResult.status().equals(WriteStatus.OK)) {
281 return writeResult.previousValue();
282 }
Madan Jampani44e6a542014-11-12 01:06:51 -0800283 throw new DatabaseException("remove failed due to status: "
284 + writeResult.status());
Madan Jampani12390c12014-11-12 00:35:56 -0800285 }
286
287 @Override
288 public boolean removeIfVersionMatches(String tableName, String key,
289 long version) {
Madan Jampani44e6a542014-11-12 01:06:51 -0800290 BatchWriteRequest batchRequest = new BatchWriteRequest.Builder()
291 .removeIfVersionMatches(tableName, key, version).build();
Madan Jampani12390c12014-11-12 00:35:56 -0800292 WriteResult writeResult = batchWrite(batchRequest).getAsList().get(0);
293 if (writeResult.status().equals(WriteStatus.OK)) {
294 return true;
295 } else if (writeResult.status().equals(WriteStatus.PRECONDITION_VIOLATION)) {
296 return false;
297 }
Madan Jampani44e6a542014-11-12 01:06:51 -0800298 throw new DatabaseException("removeIfVersionMatches failed due to status: "
299 + writeResult.status());
Madan Jampani12390c12014-11-12 00:35:56 -0800300 }
301
302 @Override
303 public boolean removeIfValueMatches(String tableName, String key,
304 byte[] value) {
Madan Jampani44e6a542014-11-12 01:06:51 -0800305 BatchWriteRequest batchRequest = new BatchWriteRequest.Builder()
306 .removeIfValueMatches(tableName, key, value).build();
Madan Jampani12390c12014-11-12 00:35:56 -0800307 WriteResult writeResult = batchWrite(batchRequest).getAsList().get(0);
308 if (writeResult.status().equals(WriteStatus.OK)) {
309 return true;
310 } else if (writeResult.status().equals(WriteStatus.PRECONDITION_VIOLATION)) {
311 return false;
312 }
Madan Jampani44e6a542014-11-12 01:06:51 -0800313 throw new DatabaseException("removeIfValueMatches failed due to status: "
314 + writeResult.status());
Madan Jampani12390c12014-11-12 00:35:56 -0800315 }
316
317 @Override
318 public void addMember(final ControllerNode node) {
319 final TcpMember tcpMember = new TcpMember(node.ip().toString(),
320 node.tcpPort());
321 log.info("{} was added to the cluster", tcpMember);
322 synchronized (clusterConfig) {
323 clusterConfig.addRemoteMember(tcpMember);
324 }
Madan Jampani08822c42014-11-04 17:17:46 -0800325 }
326
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800327 private final class InternalClusterEventListener
Madan Jampani12390c12014-11-12 00:35:56 -0800328 implements ClusterEventListener {
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800329
330 @Override
331 public void event(ClusterEvent event) {
332 // TODO: Not every node should be part of the consensus ring.
333
334 final ControllerNode node = event.subject();
335 final TcpMember tcpMember = new TcpMember(node.ip().toString(),
Madan Jampani12390c12014-11-12 00:35:56 -0800336 node.tcpPort());
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800337
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800338 switch (event.type()) {
339 case INSTANCE_ACTIVATED:
340 case INSTANCE_ADDED:
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800341 if (autoAddMember) {
342 synchronized (clusterConfig) {
343 if (!clusterConfig.getMembers().contains(tcpMember)) {
344 log.info("{} was automatically added to the cluster", tcpMember);
345 clusterConfig.addRemoteMember(tcpMember);
346 }
347 }
Yuta HIGUCHI79a1e5e2014-11-05 17:42:01 -0800348 }
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800349 break;
350 case INSTANCE_DEACTIVATED:
351 case INSTANCE_REMOVED:
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800352 if (autoAddMember) {
353 Set<DefaultControllerNode> members
Madan Jampani12390c12014-11-12 00:35:56 -0800354 = tabletMembers.getOrDefault(DEFAULT_TABLET,
355 Collections.emptySet());
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800356 // remove only if not the initial members
357 if (!members.contains(node)) {
358 synchronized (clusterConfig) {
359 if (clusterConfig.getMembers().contains(tcpMember)) {
360 log.info("{} was automatically removed from the cluster", tcpMember);
361 clusterConfig.removeRemoteMember(tcpMember);
362 }
363 }
364 }
365 }
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800366 break;
367 default:
368 break;
369 }
Yuta HIGUCHI79a1e5e2014-11-05 17:42:01 -0800370 if (copycat != null) {
371 log.debug("Current cluster: {}", copycat.cluster());
372 }
373 clusterEventLatch.countDown();
Yuta HIGUCHI5027b6b2014-11-05 16:23:26 -0800374 }
375
376 }
377
Yuta HIGUCHI60731cb2014-11-11 01:34:46 -0800378 @Override
379 public void removeMember(final ControllerNode node) {
380 final TcpMember tcpMember = new TcpMember(node.ip().toString(),
381 node.tcpPort());
382 log.info("{} was removed from the cluster", tcpMember);
383 synchronized (clusterConfig) {
384 clusterConfig.removeRemoteMember(tcpMember);
385 }
386 }
387
388 @Override
389 public Collection<ControllerNode> listMembers() {
390 if (copycat == null) {
391 return ImmutableList.of();
392 }
393 Set<ControllerNode> members = new HashSet<>();
394 for (Member member : copycat.cluster().members()) {
395 if (member instanceof TcpMember) {
396 final TcpMember tcpMember = (TcpMember) member;
397 // TODO assuming tcpMember#host to be IP address,
398 // but if not lookup DNS, etc. first
399 IpAddress ip = IpAddress.valueOf(tcpMember.host());
400 int tcpPort = tcpMember.port();
401 NodeId id = getNodeIdFromIp(ip, tcpPort);
402 if (id == null) {
403 log.info("No NodeId found for {}:{}", ip, tcpPort);
404 continue;
405 }
406 members.add(new DefaultControllerNode(id, ip, tcpPort));
407 }
408 }
409 return members;
410 }
411
412 private NodeId getNodeIdFromIp(IpAddress ip, int tcpPort) {
413 for (ControllerNode node : clusterService.getNodes()) {
414 if (node.ip().equals(ip) &&
415 node.tcpPort() == tcpPort) {
416 return node.id();
417 }
418 }
419 return null;
420 }
Madan Jampani44e6a542014-11-12 01:06:51 -0800421}