673e8a82988f0ad47a574afc4e78b6a1b264b9cd
[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 package org.opendaylight.netconf.topology.singleton.impl;
9
10 import static java.util.Objects.requireNonNull;
11
12 import akka.actor.ActorRef;
13 import akka.cluster.Cluster;
14 import akka.dispatch.OnComplete;
15 import akka.pattern.Patterns;
16 import akka.util.Timeout;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import java.util.concurrent.atomic.AtomicBoolean;
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
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.opendaylight.yangtools.util.concurrent.FluentFutures;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import scala.concurrent.Future;
34
35 class NetconfTopologyContext implements ClusterSingletonService, AutoCloseable {
36
37     private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyContext.class);
38
39     private final ServiceGroupIdentifier serviceGroupIdent;
40     private final Timeout actorResponseWaitTime;
41     private final DOMMountPointService mountService;
42
43     private NetconfTopologySetup netconfTopologyDeviceSetup;
44     private RemoteDeviceId remoteDeviceId;
45     private RemoteDeviceConnector remoteDeviceConnector;
46     private NetconfNodeManager netconfNodeManager;
47     private ActorRef masterActorRef;
48     private final AtomicBoolean closed = new AtomicBoolean(false);
49     private final AtomicBoolean stopped = new AtomicBoolean(false);
50     private volatile boolean isMaster;
51
52     NetconfTopologyContext(final NetconfTopologySetup netconfTopologyDeviceSetup,
53                            final ServiceGroupIdentifier serviceGroupIdent,
54                            final Timeout actorResponseWaitTime, final DOMMountPointService mountService) {
55         this.netconfTopologyDeviceSetup = requireNonNull(netconfTopologyDeviceSetup);
56         this.serviceGroupIdent = serviceGroupIdent;
57         this.actorResponseWaitTime = actorResponseWaitTime;
58         this.mountService = mountService;
59
60         remoteDeviceId = NetconfTopologyUtils.createRemoteDeviceId(netconfTopologyDeviceSetup.getNode().getNodeId(),
61                 netconfTopologyDeviceSetup.getNode().augmentation(NetconfNode.class));
62
63         remoteDeviceConnector = new RemoteDeviceConnectorImpl(netconfTopologyDeviceSetup, remoteDeviceId);
64
65         netconfNodeManager = createNodeDeviceManager();
66     }
67
68     @Override
69     public void instantiateServiceInstance() {
70         LOG.info("Master was selected: {}", remoteDeviceId.getHost().getIpAddress());
71
72         isMaster = true;
73
74         // master should not listen on netconf-node operational datastore
75         if (netconfNodeManager != null) {
76             netconfNodeManager.close();
77             netconfNodeManager = null;
78         }
79
80         if (!closed.get()) {
81             final String masterAddress =
82                     Cluster.get(netconfTopologyDeviceSetup.getActorSystem()).selfAddress().toString();
83             masterActorRef = netconfTopologyDeviceSetup.getActorSystem().actorOf(NetconfNodeActor.props(
84                     netconfTopologyDeviceSetup, remoteDeviceId, actorResponseWaitTime, mountService),
85                     NetconfTopologyUtils.createMasterActorName(remoteDeviceId.getName(), masterAddress));
86
87             remoteDeviceConnector.startRemoteDeviceConnection(newMasterSalFacade());
88         }
89
90     }
91
92     // called when master is down/changed to slave
93     @Override
94     public ListenableFuture<?> closeServiceInstance() {
95
96         if (!closed.get()) {
97             // in case that master changes role to slave, new NodeDeviceManager must be created and listener registered
98             netconfNodeManager = createNodeDeviceManager();
99         }
100         stopDeviceConnectorAndActor();
101
102         return FluentFutures.immediateNullFluentFuture();
103     }
104
105     @Override
106     public ServiceGroupIdentifier getIdentifier() {
107         return serviceGroupIdent;
108     }
109
110     private NetconfNodeManager createNodeDeviceManager() {
111         final NetconfNodeManager ndm =
112                 new NetconfNodeManager(netconfTopologyDeviceSetup, remoteDeviceId, actorResponseWaitTime, mountService);
113         ndm.registerDataTreeChangeListener(netconfTopologyDeviceSetup.getTopologyId(),
114                 netconfTopologyDeviceSetup.getNode().key());
115
116         return ndm;
117     }
118
119     @Override
120     public void close() {
121         if (!closed.compareAndSet(false, true)) {
122             return;
123         }
124
125         if (netconfNodeManager != null) {
126             netconfNodeManager.close();
127         }
128         stopDeviceConnectorAndActor();
129
130     }
131
132     /**
133      * Refresh, if configuration data was changed.
134      * @param setup new setup
135      */
136     void refresh(final @NonNull NetconfTopologySetup setup) {
137         netconfTopologyDeviceSetup = requireNonNull(setup);
138         remoteDeviceId = NetconfTopologyUtils.createRemoteDeviceId(netconfTopologyDeviceSetup.getNode().getNodeId(),
139                 netconfTopologyDeviceSetup.getNode().augmentation(NetconfNode.class));
140
141         if (isMaster) {
142             remoteDeviceConnector.stopRemoteDeviceConnection();
143         }
144         if (!isMaster) {
145             netconfNodeManager.refreshDevice(netconfTopologyDeviceSetup, remoteDeviceId);
146         }
147         remoteDeviceConnector = new RemoteDeviceConnectorImpl(netconfTopologyDeviceSetup, remoteDeviceId);
148
149         if (isMaster) {
150             final Future<Object> future = Patterns.ask(masterActorRef, new RefreshSetupMasterActorData(
151                     netconfTopologyDeviceSetup, remoteDeviceId), actorResponseWaitTime);
152
153             future.onComplete(new OnComplete<Object>() {
154                 @Override
155                 public void onComplete(final Throwable failure, final Object success) {
156                     if (failure != null) {
157                         LOG.error("Failed to refresh master actor data", failure);
158                         return;
159                     }
160                     remoteDeviceConnector.startRemoteDeviceConnection(newMasterSalFacade());
161                 }
162             }, netconfTopologyDeviceSetup.getActorSystem().dispatcher());
163         }
164     }
165
166     private void stopDeviceConnectorAndActor() {
167         if (!stopped.compareAndSet(false, true)) {
168             return;
169         }
170         if (remoteDeviceConnector != null) {
171             remoteDeviceConnector.stopRemoteDeviceConnection();
172         }
173
174         if (masterActorRef != null) {
175             netconfTopologyDeviceSetup.getActorSystem().stop(masterActorRef);
176             masterActorRef = null;
177         }
178     }
179
180     protected MasterSalFacade newMasterSalFacade() {
181         return new MasterSalFacade(remoteDeviceId, netconfTopologyDeviceSetup.getActorSystem(), masterActorRef,
182                 actorResponseWaitTime, mountService, netconfTopologyDeviceSetup.getDataBroker());
183     }
184 }