Bug 6714 - Use singleton service in clustered netconf topology
[netconf.git] / netconf / netconf-topology-singleton / src / main / java / org / opendaylight / netconf / topology / singleton / impl / NetconfTopologyContext.java
1 /*
2  * Copyright (c) 2016 Cisco 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
9 package org.opendaylight.netconf.topology.singleton.impl;
10
11 import static org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY;
12
13 import akka.actor.ActorRef;
14 import akka.cluster.Cluster;
15 import akka.dispatch.OnComplete;
16 import akka.pattern.Patterns;
17 import com.google.common.base.Preconditions;
18 import com.google.common.util.concurrent.Futures;
19 import com.google.common.util.concurrent.ListenableFuture;
20 import javax.annotation.Nonnull;
21 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
22 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
23 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
24 import org.opendaylight.netconf.topology.singleton.api.RemoteDeviceConnector;
25 import org.opendaylight.netconf.topology.singleton.impl.actors.NetconfNodeActor;
26 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
27 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
28 import org.opendaylight.netconf.topology.singleton.messages.RefreshSetupMasterActorData;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32 import scala.concurrent.Future;
33
34 class NetconfTopologyContext implements ClusterSingletonService {
35
36     private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyContext.class);
37
38     private final ServiceGroupIdentifier serviceGroupIdent;
39     private NetconfTopologySetup netconfTopologyDeviceSetup;
40     private RemoteDeviceId remoteDeviceId;
41     private RemoteDeviceConnector remoteDeviceConnector;
42     private NetconfNodeManager netconfNodeManager;
43     private boolean finalClose = false;
44     private boolean isMaster;
45
46     private ActorRef masterActorRef;
47
48     NetconfTopologyContext(final NetconfTopologySetup netconfTopologyDeviceSetup,
49                            final ServiceGroupIdentifier serviceGroupIdent) {
50         this.netconfTopologyDeviceSetup = Preconditions.checkNotNull(netconfTopologyDeviceSetup);
51         this.serviceGroupIdent = serviceGroupIdent;
52
53         remoteDeviceId = NetconfTopologyUtils.createRemoteDeviceId(netconfTopologyDeviceSetup.getNode().getNodeId(),
54                 netconfTopologyDeviceSetup.getNode().getAugmentation(NetconfNode.class));
55
56         remoteDeviceConnector = new RemoteDeviceConnectorImpl(netconfTopologyDeviceSetup, remoteDeviceId);
57
58         netconfNodeManager = createNodeDeviceManager();
59
60     }
61
62     @Override
63     public void instantiateServiceInstance() {
64         LOG.info("Master was selected: {}", remoteDeviceId.getHost().getIpAddress());
65
66         isMaster = true;
67
68         // master should not listen on netconf-node operational datastore
69         if (netconfNodeManager != null) {
70             netconfNodeManager.close();
71             netconfNodeManager = null;
72         }
73
74         if (!finalClose) {
75             final String masterAddress = Cluster.get(netconfTopologyDeviceSetup.getActorSystem()).selfAddress().toString();
76             masterActorRef = netconfTopologyDeviceSetup.getActorSystem().actorOf(NetconfNodeActor.props(
77                     netconfTopologyDeviceSetup, remoteDeviceId, DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY),
78                     NetconfTopologyUtils.createMasterActorName(remoteDeviceId.getName(), masterAddress));
79
80             remoteDeviceConnector.startRemoteDeviceConnection(masterActorRef);
81         }
82
83     }
84
85     // called when master is down/changed to slave
86     @Override
87     public ListenableFuture<Void> closeServiceInstance() {
88
89         if (!finalClose) {
90             // in case that master changes role to slave, new NodeDeviceManager must be created and listener registered
91             netconfNodeManager = createNodeDeviceManager();
92         }
93         if (masterActorRef != null) {
94             netconfTopologyDeviceSetup.getActorSystem().stop(masterActorRef);
95             masterActorRef = null;
96         }
97         if (remoteDeviceConnector != null) {
98             remoteDeviceConnector.stopRemoteDeviceConnection();
99         }
100
101         return Futures.immediateCheckedFuture(null);
102     }
103
104     @Override
105     public ServiceGroupIdentifier getIdentifier() {
106         return serviceGroupIdent;
107     }
108
109     private NetconfNodeManager createNodeDeviceManager() {
110         final NetconfNodeManager ndm =
111                 new NetconfNodeManager(netconfTopologyDeviceSetup, remoteDeviceId, DEFAULT_SCHEMA_REPOSITORY,
112                         DEFAULT_SCHEMA_REPOSITORY);
113         ndm.registerDataTreeChangeListener(netconfTopologyDeviceSetup.getTopologyId(),
114                 netconfTopologyDeviceSetup.getNode().getKey());
115
116         return ndm;
117     }
118
119     void closeFinal() throws Exception {
120         finalClose = true;
121
122         if (netconfNodeManager != null) {
123             netconfNodeManager.close();
124         }
125
126         if (remoteDeviceConnector != null) {
127             remoteDeviceConnector.stopRemoteDeviceConnection();
128         }
129
130         if (masterActorRef != null) {
131             netconfTopologyDeviceSetup.getActorSystem().stop(masterActorRef);
132             masterActorRef = null;
133         }
134     }
135
136     /**
137      * If configuration data was changed
138      * @param setup new setup
139      */
140     void refresh(@Nonnull final NetconfTopologySetup setup) {
141         netconfTopologyDeviceSetup = Preconditions.checkNotNull(setup);
142         remoteDeviceId = NetconfTopologyUtils.createRemoteDeviceId(netconfTopologyDeviceSetup.getNode().getNodeId(),
143                 netconfTopologyDeviceSetup.getNode().getAugmentation(NetconfNode.class));
144
145         if (isMaster) {
146             remoteDeviceConnector.stopRemoteDeviceConnection();
147         }
148         if (!isMaster) {
149             netconfNodeManager.refreshDevice(netconfTopologyDeviceSetup, remoteDeviceId);
150         }
151         remoteDeviceConnector = new RemoteDeviceConnectorImpl(netconfTopologyDeviceSetup, remoteDeviceId);
152
153         if (isMaster) {
154             final Future<Object> future = Patterns.ask(masterActorRef, new RefreshSetupMasterActorData(
155                     netconfTopologyDeviceSetup, remoteDeviceId), NetconfTopologyUtils.TIMEOUT);
156
157             future.onComplete(new OnComplete<Object>() {
158                 @Override
159                 public void onComplete(final Throwable failure, final Object success) throws Throwable {
160                     if (failure != null) {
161                         LOG.error("Failed to refresh master actor data: {}", failure);
162                         return;
163                     }
164                     remoteDeviceConnector.startRemoteDeviceConnection(masterActorRef);
165                 }
166             }, netconfTopologyDeviceSetup.getActorSystem().dispatcher());
167         }
168     }
169 }