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