212d3a61b9105ca25e9fe6d9f16b51174af23ff5
[netconf.git] / apps / netconf-topology-singleton / src / main / java / org / opendaylight / netconf / topology / singleton / impl / NetconfNodeContext.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 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.annotations.VisibleForTesting;
18 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
19 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
20 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
21 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
22 import org.opendaylight.netconf.topology.singleton.impl.actors.NetconfNodeActor;
23 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
24 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
25 import org.opendaylight.netconf.topology.singleton.messages.RefreshSetupMasterActorData;
26 import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFactory;
27 import org.opendaylight.netconf.topology.spi.NetconfNodeHandler;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.optional.rev221225.NetconfNodeAugmentedOptional;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev231121.NetconfNode;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 final class NetconfNodeContext implements AutoCloseable {
34     private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeContext.class);
35
36     private final DeviceActionFactory deviceActionFactory;
37     private final SchemaResourceManager schemaManager;
38     private final NetconfClientConfigurationBuilderFactory builderFactory;
39     private final DOMMountPointService mountPointService;
40     private final RemoteDeviceId remoteDeviceId;
41     private final NetconfTopologySetup setup;
42     private final Timeout actorResponseWaitTime;
43
44     private ActorRef masterActorRef;
45     private MasterSalFacade masterSalFacade;
46     private NetconfNodeManager netconfNodeManager;
47     private NetconfNodeHandler nodeHandler;
48
49     NetconfNodeContext(final NetconfTopologySetup setup, final SchemaResourceManager schemaManager,
50             final DOMMountPointService mountPointService, final NetconfClientConfigurationBuilderFactory builderFactory,
51             final DeviceActionFactory deviceActionFactory, final RemoteDeviceId remoteDeviceId,
52             final Timeout actorResponseWaitTime) {
53         this.setup = requireNonNull(setup);
54         this.schemaManager = requireNonNull(schemaManager);
55         this.mountPointService = requireNonNull(mountPointService);
56         this.builderFactory = requireNonNull(builderFactory);
57         this.deviceActionFactory = deviceActionFactory;
58         this.remoteDeviceId = requireNonNull(remoteDeviceId);
59         this.actorResponseWaitTime = actorResponseWaitTime;
60         registerNodeManager();
61     }
62
63     void becomeTopologyLeader() {
64         // all nodes initially register listener
65         unregisterNodeManager();
66
67         // create master actor reference
68         final var masterAddress = Cluster.get(setup.getActorSystem()).selfAddress().toString();
69         masterActorRef = setup.getActorSystem().actorOf(NetconfNodeActor.props(setup, remoteDeviceId,
70                 actorResponseWaitTime, mountPointService), NetconfTopologyUtils.createMasterActorName(
71                 remoteDeviceId.name(), masterAddress));
72
73         connectNode();
74     }
75
76     void becomeTopologyFollower() {
77         registerNodeManager();
78
79         // disconnect device from this node and listen for changes from leader
80         dropNode();
81
82         if (masterActorRef != null) {
83             // was leader before
84             setup.getActorSystem().stop(masterActorRef);
85         }
86     }
87
88     void refreshSetupConnection(final NetconfTopologySetup netconfTopologyDeviceSetup, final RemoteDeviceId device) {
89         dropNode();
90
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                         connectNode();
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     @Override
120     public void close() {
121         unregisterNodeManager();
122
123         // we expect that even leader node is going to be follower when data are deleted
124         // thus we do not close connection and actor here
125         // anyway we need to close topology and transaction chain on all nodes that were leaders
126         if (masterSalFacade != null) {
127             // node was at least once leader
128             masterSalFacade.close();
129         }
130     }
131
132     private void connectNode() {
133         final var configNode = setup.getNode();
134
135         final var netconfNode = configNode.augmentation(NetconfNode.class);
136         final var nodeOptional = configNode.augmentation(NetconfNodeAugmentedOptional.class);
137
138         requireNonNull(netconfNode.getHost());
139         requireNonNull(netconfNode.getPort());
140
141         // Instantiate the handler ...
142         masterSalFacade = createSalFacade(netconfNode.requireLockDatastore());
143
144         nodeHandler = new NetconfNodeHandler(setup.getNetconfClientFactory(), setup.getTimer(), setup.getBaseSchemas(),
145             schemaManager, setup.getSchemaAssembler(), builderFactory, deviceActionFactory, masterSalFacade,
146             remoteDeviceId, configNode.getNodeId(), netconfNode, nodeOptional);
147         nodeHandler.connect();
148     }
149
150     private void dropNode() {
151         if (nodeHandler != null) {
152             nodeHandler.close();
153             nodeHandler = null;
154         }
155     }
156
157     @VisibleForTesting
158     MasterSalFacade createSalFacade(final boolean lockDatastore) {
159         return new MasterSalFacade(remoteDeviceId, setup.getActorSystem(), masterActorRef, actorResponseWaitTime,
160             mountPointService, setup.getDataBroker(), lockDatastore);
161     }
162 }