import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalProvider;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.opendaylight.netconf.topology.singleton.messages.CreateInitialMasterActorData;
+import org.opendaylight.netconf.topology.spi.NetconfDeviceTopologyAdapter;
import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
private final NetconfDeviceSalProvider salProvider;
private final ActorRef masterActorRef;
private final ActorSystem actorSystem;
+ private final NetconfDeviceTopologyAdapter datastoreAdapter;
private final boolean lockDatastore;
private NetconfDeviceSchema currentSchema = null;
final DataBroker dataBroker,
final boolean lockDatastore) {
this.id = id;
- salProvider = new NetconfDeviceSalProvider(id, mountService, dataBroker);
+ salProvider = new NetconfDeviceSalProvider(id, mountService);
this.actorSystem = actorSystem;
this.masterActorRef = masterActorRef;
this.actorResponseWaitTime = actorResponseWaitTime;
this.lockDatastore = lockDatastore;
+
+ datastoreAdapter = new NetconfDeviceTopologyAdapter(dataBroker, id);
}
@Override
@Override
public void onDeviceDisconnected() {
LOG.info("Device {} disconnected - unregistering master mount point", id);
- salProvider.getTopologyDatastoreAdapter().updateDeviceData(false, NetconfDeviceCapabilities.empty());
+ datastoreAdapter.updateDeviceData(false, NetconfDeviceCapabilities.empty());
unregisterMasterMountPoint();
}
@Override
public void onDeviceFailed(final Throwable throwable) {
- salProvider.getTopologyDatastoreAdapter().setDeviceAsFailed(throwable);
+ datastoreAdapter.setDeviceAsFailed(throwable);
unregisterMasterMountPoint();
}
@Override
public void close() {
+ datastoreAdapter.close();
unregisterMasterMountPoint();
closeGracefully(salProvider);
}
private void updateDeviceData() {
final String masterAddress = Cluster.get(actorSystem).selfAddress().toString();
LOG.debug("{}: updateDeviceData with master address {}", id, masterAddress);
- salProvider.getTopologyDatastoreAdapter().updateClusteredDeviceData(true, masterAddress,
- currentSchema.capabilities());
+ datastoreAdapter.updateClusteredDeviceData(true, masterAddress, currentSchema.capabilities());
}
private void unregisterMasterMountPoint() {
<groupId>org.opendaylight.netconf</groupId>
<artifactId>sal-netconf-connector</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>org.awaitility</groupId>
+ <artifactId>awaitility</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-test-utils</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-test-models</artifactId>
+ </dependency>
</dependencies>
</project>
import org.opendaylight.netconf.sal.connect.netconf.auth.DatastoreBackedPublicKeyAuth;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
import org.opendaylight.netconf.sal.connect.netconf.sal.KeepaliveSalFacade;
-import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalFacade;
import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfKeystoreAdapter;
import org.opendaylight.netconf.sal.connect.netconf.schema.YangLibrarySchemaYangSourceProvider;
import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseNetconfSchemas;
final var deviceId = NetconfNodeUtils.toRemoteDeviceId(nodeId, node);
final long keepaliveDelay = node.requireKeepaliveDelay().toJava();
- final var deviceSalFacade = new NetconfDeviceSalFacade(deviceId, mountPointService, dataBroker,
- node.requireLockDatastore());
+ final var deviceSalFacade = new NetconfTopologyDeviceSalFacade(deviceId, mountPointService,
+ node.requireLockDatastore(), dataBroker);
// The facade we are going it present to NetconfDevice
RemoteDeviceHandler salFacade;
final KeepaliveSalFacade keepAliveFacade;
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.netconf.sal.connect.netconf.sal;
+package org.opendaylight.netconf.topology.spi;
import static java.util.Objects.requireNonNull;
private TransactionChain txChain;
- NetconfDeviceTopologyAdapter(final DataBroker dataBroker, final RemoteDeviceId id) {
+ public NetconfDeviceTopologyAdapter(final DataBroker dataBroker, final RemoteDeviceId id) {
this.dataBroker = requireNonNull(dataBroker);
this.id = requireNonNull(id);
txChain = dataBroker.createMergingTransactionChain(this);
--- /dev/null
+/*
+ * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.topology.spi;
+
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.dom.api.DOMMountPointService;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalFacade;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+
+/**
+ * {@link NetconfDeviceSalFacade} specialization for netconf topology.
+ */
+public class NetconfTopologyDeviceSalFacade extends NetconfDeviceSalFacade {
+ private final NetconfDeviceTopologyAdapter datastoreAdapter;
+
+ public NetconfTopologyDeviceSalFacade(final RemoteDeviceId id, final DOMMountPointService mountPointService,
+ final boolean lockDatastore, final DataBroker dataBroker) {
+ super(id, mountPointService, lockDatastore);
+ datastoreAdapter = new NetconfDeviceTopologyAdapter(dataBroker, id);
+ }
+
+ @Override
+ public synchronized void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
+ final NetconfSessionPreferences sessionPreferences, final RemoteDeviceServices services) {
+ super.onDeviceConnected(deviceSchema, sessionPreferences, services);
+ datastoreAdapter.updateDeviceData(true, deviceSchema.capabilities());
+
+ }
+
+ @Override
+ public synchronized void onDeviceDisconnected() {
+ datastoreAdapter.updateDeviceData(false, NetconfDeviceCapabilities.empty());
+ super.onDeviceDisconnected();
+ }
+
+ @Override
+ public synchronized void onDeviceFailed(final Throwable throwable) {
+ datastoreAdapter.setDeviceAsFailed(throwable);
+ super.onDeviceFailed(throwable);
+ }
+
+ @Override
+ public void close() {
+ datastoreAdapter.close();
+ super.close();
+ }
+}
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.netconf.sal.connect.netconf.sal;
+package org.opendaylight.netconf.topology.spi;
import static org.junit.Assert.assertEquals;
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.netconf.sal.connect.netconf.sal;
+package org.opendaylight.netconf.topology.spi;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
<type>test-jar</type>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>org.opendaylight.mdsal</groupId>
- <artifactId>mdsal-binding-test-utils</artifactId>
- </dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
- <dependency>
- <groupId>org.awaitility</groupId>
- <artifactId>awaitility</artifactId>
- </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-test-util</artifactId>
</dependency>
- <dependency>
- <groupId>org.opendaylight.netconf</groupId>
- <artifactId>netconf-test-models</artifactId>
- </dependency>
</dependencies>
<scm>
*/
package org.opendaylight.netconf.sal.connect.netconf.sal;
+import static java.util.Objects.requireNonNull;
+
import com.google.common.annotations.VisibleForTesting;
-import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.dom.api.DOMMountPointService;
import org.opendaylight.mdsal.dom.api.DOMNotification;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public final class NetconfDeviceSalFacade implements RemoteDeviceHandler, AutoCloseable {
+public class NetconfDeviceSalFacade implements RemoteDeviceHandler, AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceSalFacade.class);
private final RemoteDeviceId id;
private final boolean lockDatastore;
public NetconfDeviceSalFacade(final RemoteDeviceId id, final DOMMountPointService mountPointService,
- final DataBroker dataBroker, final boolean lockDatastore) {
- this(id, new NetconfDeviceSalProvider(id, mountPointService, dataBroker), lockDatastore);
+ final boolean lockDatastore) {
+ this(id, new NetconfDeviceSalProvider(id, mountPointService), lockDatastore);
}
@VisibleForTesting
NetconfDeviceSalFacade(final RemoteDeviceId id, final NetconfDeviceSalProvider salProvider,
final boolean lockDatastore) {
- this.id = id;
- this.salProvider = salProvider;
+ this.id = requireNonNull(id);
+ this.salProvider = requireNonNull(salProvider);
this.lockDatastore = lockDatastore;
}
salProvider.getMountInstance().onTopologyDeviceConnected(modelContext, services, netconfDataBroker,
netconfDataTree);
- salProvider.getTopologyDatastoreAdapter().updateDeviceData(true, deviceSchema.capabilities());
}
@Override
public synchronized void onDeviceDisconnected() {
- salProvider.getTopologyDatastoreAdapter().updateDeviceData(false, NetconfDeviceCapabilities.empty());
salProvider.getMountInstance().onTopologyDeviceDisconnected();
}
@Override
public synchronized void onDeviceFailed(final Throwable throwable) {
- salProvider.getTopologyDatastoreAdapter().setDeviceAsFailed(throwable);
salProvider.getMountInstance().onTopologyDeviceDisconnected();
}
import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
-import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.dom.api.DOMActionService;
import org.opendaylight.mdsal.dom.api.DOMDataBroker;
import org.opendaylight.mdsal.dom.api.DOMMountPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+// FIXME: remove this class and promote MountInstance to a top-level construct
+// Non-final for mocking
public class NetconfDeviceSalProvider implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceSalProvider.class);
private final RemoteDeviceId id;
private final MountInstance mountInstance;
- private volatile NetconfDeviceTopologyAdapter topologyDatastoreAdapter;
-
public NetconfDeviceSalProvider(final RemoteDeviceId deviceId, final DOMMountPointService mountService) {
- this(deviceId, mountService, null);
- }
-
- // FIXME: NETCONF-918: remove this method
- public NetconfDeviceSalProvider(final RemoteDeviceId deviceId, final DOMMountPointService mountService,
- final DataBroker dataBroker) {
- id = deviceId;
+ id = requireNonNull(deviceId);
mountInstance = new MountInstance(mountService, id);
- if (dataBroker != null) {
- topologyDatastoreAdapter = new NetconfDeviceTopologyAdapter(dataBroker, id);
- }
}
public MountInstance getMountInstance() {
return mountInstance;
}
- public NetconfDeviceTopologyAdapter getTopologyDatastoreAdapter() {
- final NetconfDeviceTopologyAdapter local = topologyDatastoreAdapter;
- checkState(local != null,
- "%s: Sal provider %s was not initialized by sal. Cannot get topology datastore adapter", id, this);
- return local;
- }
-
@Override
public void close() {
mountInstance.close();
- if (topologyDatastoreAdapter != null) {
- topologyDatastoreAdapter.close();
- topologyDatastoreAdapter = null;
- }
}
public static class MountInstance implements AutoCloseable {
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-
package org.opendaylight.netconf.sal.connect.netconf.sal;
-import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
-import org.opendaylight.mdsal.binding.api.DataBroker;
-import org.opendaylight.mdsal.binding.api.TransactionChain;
-import org.opendaylight.mdsal.binding.api.WriteTransaction;
-import org.opendaylight.mdsal.common.api.CommitInfo;
-import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.dom.api.DOMDataBroker;
import org.opendaylight.mdsal.dom.api.DOMNotification;
import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev221225.ConnectionOper.ConnectionStatus;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev221225.NetconfNode;
import org.opendaylight.yangtools.rfc8528.data.util.EmptyMountPointContext;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
private NetconfDeviceSalProvider.MountInstance mountInstance;
@Mock
private NetconfDeviceSalProvider salProvider;
- @Mock
- private DataBroker dataBroker;
- @Mock
- private TransactionChain txChain;
- @Mock
- private WriteTransaction tx;
- @Captor
- private ArgumentCaptor<NetconfNode> nodeCaptor;
private NetconfDeviceSalFacade deviceFacade;
@Before
public void setUp() throws Exception {
- doReturn(txChain).when(dataBroker).createMergingTransactionChain(any());
- doReturn(tx).when(txChain).newWriteOnlyTransaction();
- doNothing().when(tx).mergeParentStructurePut(eq(LogicalDatastoreType.OPERATIONAL),
- eq(remoteDeviceId.getTopologyBindingPath().augmentation(NetconfNode.class)), nodeCaptor.capture());
- doReturn(CommitInfo.emptyFluentFuture()).when(tx).commit();
-
- final NetconfDeviceTopologyAdapter adapter = new NetconfDeviceTopologyAdapter(dataBroker, remoteDeviceId);
-
deviceFacade = new NetconfDeviceSalFacade(remoteDeviceId, salProvider, true);
- doReturn(adapter).when(salProvider).getTopologyDatastoreAdapter();
-
doReturn(mountInstance).when(salProvider).getMountInstance();
doNothing().when(mountInstance).onTopologyDeviceDisconnected();
}
public void testOnDeviceDisconnected() {
deviceFacade.onDeviceDisconnected();
- verifyConnectionStatusUpdate(ConnectionStatus.Connecting);
verify(mountInstance, times(1)).onTopologyDeviceDisconnected();
}
final Throwable throwable = new Throwable();
deviceFacade.onDeviceFailed(throwable);
- verifyConnectionStatusUpdate(ConnectionStatus.UnableToConnect);
verify(mountInstance, times(1)).onTopologyDeviceDisconnected();
}
new NetconfDeviceSchema(NetconfDeviceCapabilities.empty(), new EmptyMountPointContext(schemaContext)),
netconfSessionPreferences, deviceServices);
- verifyConnectionStatusUpdate(ConnectionStatus.Connected);
verify(mountInstance, times(1)).onTopologyDeviceConnected(eq(schemaContext), eq(deviceServices),
any(DOMDataBroker.class), any(NetconfDataTreeService.class));
}
deviceFacade.onNotification(domNotification);
verify(mountInstance).publish(domNotification);
}
-
- private void verifyConnectionStatusUpdate(final ConnectionStatus expectedStatus) {
- verify(tx).mergeParentStructurePut(eq(LogicalDatastoreType.OPERATIONAL),
- eq(remoteDeviceId.getTopologyBindingPath().augmentation(NetconfNode.class)), any());
- assertEquals(expectedStatus, nodeCaptor.getValue().getConnectionStatus());
- }
}
*/
package org.opendaylight.netconf.sal.connect.netconf.sal;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.verify;
-
import java.net.InetSocketAddress;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
-import org.opendaylight.mdsal.binding.api.DataBroker;
-import org.opendaylight.mdsal.binding.api.TransactionChain;
-import org.opendaylight.mdsal.binding.api.TransactionChainListener;
-import org.opendaylight.mdsal.binding.api.WriteTransaction;
-import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.mdsal.dom.api.DOMMountPointService;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class NetconfDeviceSalProviderTest {
- @Mock
- private WriteTransaction tx;
- @Mock
- private DataBroker dataBroker;
- @Mock
- private TransactionChain chain;
@Mock
private DOMMountPointService mountPointService;
- @Mock
- private WriteTransaction writeTx;
- @Captor
- private ArgumentCaptor<TransactionChainListener> listeners;
private NetconfDeviceSalProvider provider;
@Before
public void setUp() {
- doReturn(chain).when(dataBroker).createMergingTransactionChain(listeners.capture());
- doReturn(writeTx).when(chain).newWriteOnlyTransaction();
- doReturn("Some object").when(writeTx).getIdentifier();
- doReturn(CommitInfo.emptyFluentFuture()).when(writeTx).commit();
provider = new NetconfDeviceSalProvider(new RemoteDeviceId("device1",
- InetSocketAddress.createUnresolved("localhost", 17830)), mountPointService, dataBroker);
- doReturn(tx).when(chain).newWriteOnlyTransaction();
- doReturn(CommitInfo.emptyFluentFuture()).when(tx).commit();
- doReturn(tx).when(tx).getIdentifier();
+ InetSocketAddress.createUnresolved("localhost", 17830)), mountPointService);
}
@Test
public void close() {
- listeners.getValue().onTransactionChainSuccessful(chain);
provider.close();
- verify(chain).close();
}
@Test