199cfa931e382ae29bab490e6228c43a5c3ab89b
[netconf.git] / apps / netconf-topology-singleton / src / main / java / org / opendaylight / netconf / topology / singleton / impl / NetconfTopologySingletonImpl.java
1 /*
2  * Copyright (c) 2023 PANTHEON.tech, s.r.o. 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 akka.actor.ActorRef;
11 import akka.cluster.Cluster;
12 import akka.dispatch.OnComplete;
13 import akka.pattern.Patterns;
14 import akka.util.Timeout;
15 import io.netty.util.concurrent.EventExecutor;
16 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
17 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
18 import org.opendaylight.controller.config.threadpool.ThreadPool;
19 import org.opendaylight.mdsal.binding.api.DataBroker;
20 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
21 import org.opendaylight.netconf.client.NetconfClientDispatcher;
22 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
23 import org.opendaylight.netconf.client.mdsal.api.CredentialProvider;
24 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
25 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceHandler;
26 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
27 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
28 import org.opendaylight.netconf.client.mdsal.api.SslHandlerFactoryProvider;
29 import org.opendaylight.netconf.topology.singleton.impl.actors.NetconfNodeActor;
30 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
31 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
32 import org.opendaylight.netconf.topology.singleton.messages.RefreshSetupMasterActorData;
33 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 final class NetconfTopologySingletonImpl extends AbstractNetconfTopology implements AutoCloseable {
39     private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologySingletonImpl.class);
40
41     private final RemoteDeviceId remoteDeviceId;
42     private final NetconfTopologySetup setup;
43     private final Timeout actorResponseWaitTime;
44
45     private ActorRef masterActorRef;
46     private MasterSalFacade masterSalFacade;
47     private NetconfNodeManager netconfNodeManager;
48
49     NetconfTopologySingletonImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
50             final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
51             final ThreadPool processingExecutor, final SchemaResourceManager schemaManager,
52             final DataBroker dataBroker, final DOMMountPointService mountPointService,
53             final AAAEncryptionService encryptionService, final DeviceActionFactory deviceActionFactory,
54             final BaseNetconfSchemas baseSchemas, final RemoteDeviceId remoteDeviceId,
55             final NetconfTopologySetup setup, final Timeout actorResponseWaitTime,
56             final CredentialProvider credentialProvider, final SslHandlerFactoryProvider sslHandlerFactoryProvider) {
57         super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor, schemaManager,
58                 dataBroker, mountPointService, encryptionService, deviceActionFactory, baseSchemas, credentialProvider,
59                 sslHandlerFactoryProvider);
60         this.remoteDeviceId = remoteDeviceId;
61         this.setup = setup;
62         this.actorResponseWaitTime = actorResponseWaitTime;
63         registerNodeManager();
64     }
65
66     void becomeTopologyLeader() {
67         // all nodes initially register listener
68         unregisterNodeManager();
69
70         // create master actor reference
71         final var masterAddress = Cluster.get(setup.getActorSystem()).selfAddress().toString();
72         masterActorRef = setup.getActorSystem().actorOf(NetconfNodeActor.props(setup, remoteDeviceId,
73                 actorResponseWaitTime, mountPointService), NetconfTopologyUtils.createMasterActorName(
74                 remoteDeviceId.name(), masterAddress));
75
76         // setup connection to device
77         ensureNode(setup.getNode());
78     }
79
80     void becomeTopologyFollower() {
81         registerNodeManager();
82         // disconnect device from this node and listen for changes from leader
83         deleteNode(setup.getNode().getNodeId());
84         if (masterActorRef != null) {
85             // was leader before
86             setup.getActorSystem().stop(masterActorRef);
87         }
88     }
89
90     void refreshSetupConnection(final NetconfTopologySetup netconfTopologyDeviceSetup, final RemoteDeviceId device) {
91         Patterns.ask(masterActorRef, new RefreshSetupMasterActorData(netconfTopologyDeviceSetup, device),
92             actorResponseWaitTime).onComplete(
93                 new OnComplete<>() {
94                     @Override
95                     public void onComplete(final Throwable failure, final Object success) {
96                         if (failure != null) {
97                             LOG.error("Failed to refresh master actor data", failure);
98                             return;
99                         }
100                         LOG.debug("Succeed to refresh Master Action data. Creating Connector...");
101                         setupConnection(setup.getNode().getNodeId(), setup.getNode());
102                     }
103                 }, netconfTopologyDeviceSetup.getActorSystem().dispatcher());
104     }
105
106     void refreshDevice(final NetconfTopologySetup netconfTopologyDeviceSetup, final RemoteDeviceId deviceId) {
107         netconfNodeManager.refreshDevice(netconfTopologyDeviceSetup, deviceId);
108     }
109
110     private void registerNodeManager() {
111         netconfNodeManager = new NetconfNodeManager(setup, remoteDeviceId, actorResponseWaitTime, mountPointService);
112         netconfNodeManager.registerDataTreeChangeListener(setup.getTopologyId(), setup.getNode().key());
113     }
114
115     private void unregisterNodeManager() {
116         netconfNodeManager.close();
117     }
118
119     void dropNode(final NodeId nodeId) {
120         deleteNode(nodeId);
121     }
122
123     @Override
124     public void close() {
125         unregisterNodeManager();
126
127         // we expect that even leader node is going to be follower when data are deleted
128         // thus we do not close connection and actor here
129         // anyway we need to close topology and transaction chain on all nodes that were leaders
130         if (masterSalFacade != null) {
131             // node was at least once leader
132             masterSalFacade.close();
133         }
134     }
135
136     @Override
137     public RemoteDeviceHandler createSalFacade(final RemoteDeviceId deviceId, final boolean lockDatastore) {
138         masterSalFacade = new MasterSalFacade(deviceId, setup.getActorSystem(), masterActorRef,
139                 actorResponseWaitTime, mountPointService, dataBroker, lockDatastore);
140         return masterSalFacade;
141     }
142 }