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