2 * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.netconf.topology.singleton.impl;
10 import static java.util.Objects.requireNonNull;
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 io.netty.util.concurrent.EventExecutor;
19 import java.util.concurrent.Executor;
20 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
21 import org.opendaylight.controller.config.threadpool.ThreadPool;
22 import org.opendaylight.mdsal.binding.api.DataBroker;
23 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
24 import org.opendaylight.netconf.client.NetconfClientDispatcher;
25 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
26 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
27 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
28 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
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.NetconfClientConfigurationBuilderFactory;
34 import org.opendaylight.netconf.topology.spi.NetconfNodeHandler;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.optional.rev221225.NetconfNodeAugmentedOptional;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev221225.NetconfNode;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
40 final class NetconfNodeContext implements AutoCloseable {
41 private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeContext.class);
43 private final NetconfClientDispatcher clientDispatcher;
44 private final EventExecutor eventExecutor;
45 private final DeviceActionFactory deviceActionFactory;
46 private final SchemaResourceManager schemaManager;
47 private final BaseNetconfSchemas baseSchemas;
48 private final NetconfClientConfigurationBuilderFactory builderFactory;
49 private final ScheduledThreadPool keepaliveExecutor;
50 private final Executor processingExecutor;
51 private final DataBroker dataBroker;
52 private final DOMMountPointService mountPointService;
53 private final RemoteDeviceId remoteDeviceId;
54 private final NetconfTopologySetup setup;
55 private final Timeout actorResponseWaitTime;
57 private ActorRef masterActorRef;
58 private MasterSalFacade masterSalFacade;
59 private NetconfNodeManager netconfNodeManager;
60 private NetconfNodeHandler nodeHandler;
62 NetconfNodeContext(final NetconfClientDispatcher clientDispatcher, final EventExecutor eventExecutor,
63 final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor,
64 final SchemaResourceManager schemaManager, final DataBroker dataBroker,
65 final DOMMountPointService mountPointService, final NetconfClientConfigurationBuilderFactory builderFactory,
66 final DeviceActionFactory deviceActionFactory, final BaseNetconfSchemas baseSchemas,
67 final RemoteDeviceId remoteDeviceId, final NetconfTopologySetup setup,
68 final Timeout actorResponseWaitTime) {
69 this.clientDispatcher = requireNonNull(clientDispatcher);
70 this.eventExecutor = requireNonNull(eventExecutor);
71 this.keepaliveExecutor = requireNonNull(keepaliveExecutor);
72 this.processingExecutor = processingExecutor.getExecutor();
73 this.schemaManager = requireNonNull(schemaManager);
74 this.dataBroker = requireNonNull(dataBroker);
75 this.mountPointService = requireNonNull(mountPointService);
76 this.builderFactory = requireNonNull(builderFactory);
77 this.deviceActionFactory = deviceActionFactory;
78 this.baseSchemas = requireNonNull(baseSchemas);
79 this.remoteDeviceId = requireNonNull(remoteDeviceId);
80 this.setup = requireNonNull(setup);
81 this.actorResponseWaitTime = actorResponseWaitTime;
82 registerNodeManager();
85 void becomeTopologyLeader() {
86 // all nodes initially register listener
87 unregisterNodeManager();
89 // create master actor reference
90 final var masterAddress = Cluster.get(setup.getActorSystem()).selfAddress().toString();
91 masterActorRef = setup.getActorSystem().actorOf(NetconfNodeActor.props(setup, remoteDeviceId,
92 actorResponseWaitTime, mountPointService), NetconfTopologyUtils.createMasterActorName(
93 remoteDeviceId.name(), masterAddress));
98 void becomeTopologyFollower() {
99 registerNodeManager();
101 // disconnect device from this node and listen for changes from leader
104 if (masterActorRef != null) {
106 setup.getActorSystem().stop(masterActorRef);
110 void refreshSetupConnection(final NetconfTopologySetup netconfTopologyDeviceSetup, final RemoteDeviceId device) {
113 Patterns.ask(masterActorRef, new RefreshSetupMasterActorData(netconfTopologyDeviceSetup, device),
114 actorResponseWaitTime).onComplete(
117 public void onComplete(final Throwable failure, final Object success) {
118 if (failure != null) {
119 LOG.error("Failed to refresh master actor data", failure);
122 LOG.debug("Succeed to refresh Master Action data. Creating Connector...");
125 }, netconfTopologyDeviceSetup.getActorSystem().dispatcher());
128 void refreshDevice(final NetconfTopologySetup netconfTopologyDeviceSetup, final RemoteDeviceId deviceId) {
129 netconfNodeManager.refreshDevice(netconfTopologyDeviceSetup, deviceId);
132 private void registerNodeManager() {
133 netconfNodeManager = new NetconfNodeManager(setup, remoteDeviceId, actorResponseWaitTime, mountPointService);
134 netconfNodeManager.registerDataTreeChangeListener(setup.getTopologyId(), setup.getNode().key());
137 private void unregisterNodeManager() {
138 netconfNodeManager.close();
142 public void close() {
143 unregisterNodeManager();
145 // we expect that even leader node is going to be follower when data are deleted
146 // thus we do not close connection and actor here
147 // anyway we need to close topology and transaction chain on all nodes that were leaders
148 if (masterSalFacade != null) {
149 // node was at least once leader
150 masterSalFacade.close();
154 private void connectNode() {
155 final var configNode = setup.getNode();
157 final var netconfNode = configNode.augmentation(NetconfNode.class);
158 final var nodeOptional = configNode.augmentation(NetconfNodeAugmentedOptional.class);
160 requireNonNull(netconfNode.getHost());
161 requireNonNull(netconfNode.getPort());
163 // Instantiate the handler ...
164 masterSalFacade = createSalFacade(netconfNode.requireLockDatastore());
166 nodeHandler = new NetconfNodeHandler(clientDispatcher, eventExecutor, keepaliveExecutor.getExecutor(),
167 baseSchemas, schemaManager, processingExecutor, builderFactory, deviceActionFactory, masterSalFacade,
168 remoteDeviceId, configNode.getNodeId(), netconfNode, nodeOptional);
169 nodeHandler.connect();
172 private void dropNode() {
173 if (nodeHandler != null) {
180 MasterSalFacade createSalFacade(final boolean lockDatastore) {
181 return new MasterSalFacade(remoteDeviceId, setup.getActorSystem(), masterActorRef, actorResponseWaitTime,
182 mountPointService, dataBroker, lockDatastore);