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