}
}
+ container non-module-capabilities {
+ config true;
+ leaf override {
+ type boolean;
+ default false;
+ description "Whether to override or merge this list of non-module based capabilities with non-module
+ based capabilities from device";
+ }
+
+ leaf-list capability {
+ type string;
+ description "Set a list of non-module based capabilities to override or merge non-module capabilities
+ provided in device's hello message. Can be used for devices that do not report or
+ incorrectly report non-module based capabilities in their hello message";
+ }
+ }
+
leaf reconnect-on-changed-schema {
config true;
type boolean;
}
}
}
+ leaf netconf-master-node {
+ config false;
+ type string;
+ }
}
leaf connected-message {
import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.net.URL;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability.CapabilityOrigin;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.Credentials;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
*/
private static final Map<String, NetconfDevice.SchemaResourcesDTO> schemaResourcesDTOs = new HashMap<>();
- private SchemaSourceRegistry schemaRegistry = NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY;
- private SchemaRepository schemaRepository = NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY;
-
- private final NetconfTopologySetup netconfTopologyDeviceSetup;
- private final RemoteDeviceId remoteDeviceId;
-
- private SchemaContextFactory schemaContextFactory = NetconfTopologyUtils.DEFAULT_SCHEMA_CONTEXT_FACTORY;
- private NetconfConnectorDTO deviceCommunicatorDTO;
-
// Initializes default constant instances for the case when the default schema repository
// directory cache/schema is used.
static {
NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY));
}
+ private final NetconfTopologySetup netconfTopologyDeviceSetup;
+ private final RemoteDeviceId remoteDeviceId;
+ private SchemaSourceRegistry schemaRegistry = NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY;
+ private final SchemaRepository schemaRepository = NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY;
+ private SchemaContextFactory schemaContextFactory = NetconfTopologyUtils.DEFAULT_SCHEMA_CONTEXT_FACTORY;
+ private NetconfConnectorDTO deviceCommunicatorDTO;
+
public RemoteDeviceConnectorImpl(final NetconfTopologySetup netconfTopologyDeviceSetup,
final RemoteDeviceId remoteDeviceId) {
Futures.addCallback(future, new FutureCallback<NetconfDeviceCapabilities>() {
@Override
- public void onSuccess(NetconfDeviceCapabilities result) {
+ public void onSuccess(final NetconfDeviceCapabilities result) {
LOG.debug("{}: Connector started successfully", remoteDeviceId);
}
@Override
- public void onFailure(@Nullable Throwable throwable) {
+ public void onFailure(@Nullable final Throwable throwable) {
LOG.error("{}: Connector failed, {}", remoteDeviceId, throwable);
}
});
Preconditions.checkNotNull(deviceCommunicatorDTO, remoteDeviceId + ": Device communicator was not created.");
try {
deviceCommunicatorDTO.close();
- } catch (Exception e) {
+ } catch (final Exception e) {
LOG.error("{}: Error at closing device communicator.", remoteDeviceId, e);
}
}
@VisibleForTesting
NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId, final NetconfNode node,
- final ActorRef deviceContextActorRef) {
+ final ActorRef deviceContextActorRef) {
//setup default values since default value is not supported in mdsal
final Long defaultRequestTimeoutMillis = node.getDefaultRequestTimeoutMillis() == null
? NetconfTopologyUtils.DEFAULT_REQUEST_TIMEOUT_MILLIS : node.getDefaultRequestTimeoutMillis();
final Boolean reconnectOnChangedSchema = node.isReconnectOnChangedSchema() == null
? NetconfTopologyUtils.DEFAULT_RECONNECT_ON_CHANGED_SCHEMA : node.isReconnectOnChangedSchema();
- RemoteDeviceHandler<NetconfSessionPreferences> salFacade = new MasterSalFacade(remoteDeviceId,
+ RemoteDeviceHandler<NetconfSessionPreferences> salFacade = new MasterSalFacade(remoteDeviceId,
netconfTopologyDeviceSetup.getDomBroker(), netconfTopologyDeviceSetup.getBindingAwareBroker(),
netconfTopologyDeviceSetup.getActorSystem(), deviceContextActorRef);
if (keepaliveDelay > 0) {
}
// pre register yang library sources as fallback schemas to schema registry
- List<SchemaSourceRegistration<YangTextSchemaSource>> registeredYangLibSources = Lists.newArrayList();
+ final List<SchemaSourceRegistration<YangTextSchemaSource>> registeredYangLibSources = Lists.newArrayList();
if (node.getYangLibrary() != null) {
final String yangLibURL = node.getYangLibrary().getYangLibraryUrl().getValue();
final String yangLibUsername = node.getYangLibrary().getUsername();
final String yangLigPassword = node.getYangLibrary().getPassword();
- LibraryModulesSchemas libraryModulesSchemas;
+ final LibraryModulesSchemas libraryModulesSchemas;
if (yangLibURL != null) {
if (yangLibUsername != null && yangLigPassword != null) {
libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL, yangLibUsername, yangLigPassword);
libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL);
}
- for (Map.Entry<SourceIdentifier, URL> sourceIdentifierURLEntry :
+ for (final Map.Entry<SourceIdentifier, URL> sourceIdentifierURLEntry :
libraryModulesSchemas.getAvailableModels().entrySet()) {
registeredYangLibSources
.add(schemaRegistry.registerSchemaSource(
return new NetconfConnectorDTO(
userCapabilities.isPresent()
? new NetconfDeviceCommunicator(
- remoteDeviceId, device, new UserPreferences(userCapabilities.get(),
- node.getYangModuleCapabilities().isOverride()), rpcMessageLimit) :
- new NetconfDeviceCommunicator(remoteDeviceId, device, rpcMessageLimit), salFacade);
+ remoteDeviceId, device, new UserPreferences(userCapabilities.get(),
+ node.getYangModuleCapabilities().isOverride(), node.getNonModuleCapabilities().isOverride()),
+ rpcMessageLimit)
+ : new NetconfDeviceCommunicator(remoteDeviceId, device, rpcMessageLimit), salFacade);
}
private Optional<NetconfSessionPreferences> getUserCapabilities(final NetconfNode node) {
- if (node.getYangModuleCapabilities() == null) {
+ if (node.getYangModuleCapabilities() == null && node.getNonModuleCapabilities() == null) {
return Optional.empty();
}
+ final List<String> capabilities = new ArrayList<>();
- final List<String> capabilities = node.getYangModuleCapabilities().getCapability();
- if (capabilities == null || capabilities.isEmpty()) {
- return Optional.empty();
+ if (node.getYangModuleCapabilities() != null) {
+ capabilities.addAll(node.getYangModuleCapabilities().getCapability());
}
- final NetconfSessionPreferences parsedOverrideCapabilities =
- NetconfSessionPreferences.fromStrings(capabilities);
- Preconditions.checkState(parsedOverrideCapabilities.getNonModuleCaps().isEmpty(), remoteDeviceId +
- ": Capabilities to override can only contain module based capabilities, non-module capabilities "
- + "will be retrieved from the device, configured non-module capabilities: "
- + parsedOverrideCapabilities.getNonModuleCaps());
+ //non-module capabilities should not exist in yang module capabilities
+ final NetconfSessionPreferences netconfSessionPreferences = NetconfSessionPreferences.fromStrings(capabilities);
+ Preconditions.checkState(netconfSessionPreferences.getNonModuleCaps().isEmpty(), "List yang-module-capabilities/capability " +
+ "should contain only module based capabilities. Non-module capabilities used: " +
+ netconfSessionPreferences.getNonModuleCaps());
- return Optional.of(parsedOverrideCapabilities);
+ if (node.getNonModuleCapabilities() != null) {
+ capabilities.addAll(node.getNonModuleCapabilities().getCapability());
+ }
+
+ return Optional.of(NetconfSessionPreferences.fromStrings(capabilities, CapabilityOrigin.UserDefined));
}
private NetconfDevice.SchemaResourcesDTO setupSchemaCacheDTO(final NodeId nodeId, final NetconfNode node) {
}
//TODO: duplicate code
- private InetSocketAddress getSocketAddress(final Host host, int port) {
+ private InetSocketAddress getSocketAddress(final Host host, final int port) {
if (host.getDomainName() != null) {
return new InetSocketAddress(host.getDomainName().getValue(), port);
} else {
}
}
- private static final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory {
- private final Long connectionAttempts;
- private final EventExecutor executor;
- private final double sleepFactor;
- private final int minSleep;
-
- TimedReconnectStrategyFactory(final EventExecutor executor, final Long maxConnectionAttempts,
- final int minSleep, final BigDecimal sleepFactor) {
- if (maxConnectionAttempts != null && maxConnectionAttempts > 0) {
- connectionAttempts = maxConnectionAttempts;
- } else {
- connectionAttempts = null;
- }
-
- this.sleepFactor = sleepFactor.doubleValue();
- this.executor = executor;
- this.minSleep = minSleep;
- }
-
- @Override
- public ReconnectStrategy createReconnectStrategy() {
- final Long maxSleep = null;
- final Long deadline = null;
-
- return new TimedReconnectStrategy(executor, minSleep,
- minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
- }
- }
-
@VisibleForTesting
NetconfReconnectingClientConfiguration getClientConfig(final NetconfClientSessionListener listener,
- final NetconfNode node) {
+ final NetconfNode node) {
//setup default values since default value is not supported in mdsal
final long clientConnectionTimeoutMillis = node.getConnectionTimeoutMillis() == null
Map<String, NetconfDevice.SchemaResourcesDTO> getSchemaResourcesDTOs() {
return schemaResourcesDTOs;
}
+
+ private static final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory {
+ private final Long connectionAttempts;
+ private final EventExecutor executor;
+ private final double sleepFactor;
+ private final int minSleep;
+
+ TimedReconnectStrategyFactory(final EventExecutor executor, final Long maxConnectionAttempts,
+ final int minSleep, final BigDecimal sleepFactor) {
+ if (maxConnectionAttempts != null && maxConnectionAttempts > 0) {
+ connectionAttempts = maxConnectionAttempts;
+ } else {
+ connectionAttempts = null;
+ }
+
+ this.sleepFactor = sleepFactor.doubleValue();
+ this.executor = executor;
+ this.minSleep = minSleep;
+ }
+
+ @Override
+ public ReconnectStrategy createReconnectStrategy() {
+ final Long maxSleep = null;
+ final Long deadline = null;
+
+ return new TimedReconnectStrategy(executor, minSleep,
+ minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
+ }
+ }
}
import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.net.URL;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
* Netconf mount. Access to <code>schemaResourcesDTOs</code> should be surrounded by appropriate
* synchronization locks.
*/
- private static volatile Map<String, NetconfDevice.SchemaResourcesDTO> schemaResourcesDTOs = new HashMap<>();
+ private static final Map<String, NetconfDevice.SchemaResourcesDTO> schemaResourcesDTOs = new HashMap<>();
// Initializes default constant instances for the case when the default schema repository
// directory cache/schema is used.
}
@Override
- public ListenableFuture<NetconfDeviceCapabilities> connectNode(NodeId nodeId, Node configNode) {
+ public ListenableFuture<NetconfDeviceCapabilities> connectNode(final NodeId nodeId, final Node configNode) {
LOG.info("Connecting RemoteDevice{{}} , with config {}", nodeId, configNode);
return setupConnection(nodeId, configNode);
}
@Override
- public ListenableFuture<Void> disconnectNode(NodeId nodeId) {
+ public ListenableFuture<Void> disconnectNode(final NodeId nodeId) {
LOG.debug("Disconnecting RemoteDevice{{}}", nodeId.getValue());
if (!activeConnectors.containsKey(nodeId)) {
return Futures.immediateFailedFuture(new IllegalStateException("Unable to disconnect device that is not connected"));
Futures.addCallback(future, new FutureCallback<NetconfDeviceCapabilities>() {
@Override
- public void onSuccess(NetconfDeviceCapabilities result) {
+ public void onSuccess(final NetconfDeviceCapabilities result) {
LOG.debug("Connector for : " + nodeId.getValue() + " started succesfully");
}
@Override
- public void onFailure(Throwable t) {
+ public void onFailure(final Throwable t) {
LOG.error("Connector for : " + nodeId.getValue() + " failed");
// remove this node from active connectors?
}
final Long keepaliveDelay = node.getKeepaliveDelay() == null ? DEFAULT_KEEPALIVE_DELAY : node.getKeepaliveDelay();
final Boolean reconnectOnChangedSchema = node.isReconnectOnChangedSchema() == null ? DEFAULT_RECONNECT_ON_CHANGED_SCHEMA : node.isReconnectOnChangedSchema();
- IpAddress ipAddress = node.getHost().getIpAddress();
- InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null ?
+ final IpAddress ipAddress = node.getHost().getIpAddress();
+ final InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null ?
ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(),
node.getPort().getValue());
- RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address);
+ final RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address);
RemoteDeviceHandler<NetconfSessionPreferences> salFacade =
createSalFacade(remoteDeviceId, domBroker, bindingAwareBroker);
}
// pre register yang library sources as fallback schemas to schema registry
- List<SchemaSourceRegistration<YangTextSchemaSource>> registeredYangLibSources = Lists.newArrayList();
+ final List<SchemaSourceRegistration<YangTextSchemaSource>> registeredYangLibSources = Lists.newArrayList();
if (node.getYangLibrary() != null) {
final String yangLibURL = node.getYangLibrary().getYangLibraryUrl().getValue();
final String yangLibUsername = node.getYangLibrary().getUsername();
final String yangLigPassword = node.getYangLibrary().getPassword();
- LibraryModulesSchemas libraryModulesSchemas;
+ final LibraryModulesSchemas libraryModulesSchemas;
if(yangLibURL != null) {
if(yangLibUsername != null && yangLigPassword != null) {
libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL, yangLibUsername, yangLigPassword);
libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL);
}
- for (Map.Entry<SourceIdentifier, URL> sourceIdentifierURLEntry : libraryModulesSchemas.getAvailableModels().entrySet()) {
+ for (final Map.Entry<SourceIdentifier, URL> sourceIdentifierURLEntry : libraryModulesSchemas.getAvailableModels().entrySet()) {
registeredYangLibSources.
add(schemaRegistry.registerSchemaSource(
new YangLibrarySchemaYangSourceProvider(remoteDeviceId, libraryModulesSchemas.getAvailableModels()),
.build();
}
- final Optional<NetconfSessionPreferences> userCapabilities = getUserCapabilities(node);
+ final Optional<UserPreferences> userCapabilities = getUserCapabilities(node);
final int rpcMessageLimit =
node.getConcurrentRpcLimit() == null ? DEFAULT_CONCURRENT_RPC_LIMIT : node.getConcurrentRpcLimit();
LOG.info("Concurrent rpc limit is smaller than 1, no limit will be enforced for device {}", remoteDeviceId);
}
- return new NetconfConnectorDTO(
- userCapabilities.isPresent() ?
- new NetconfDeviceCommunicator(
- remoteDeviceId, device, new UserPreferences(userCapabilities.get(), node.getYangModuleCapabilities().isOverride()), rpcMessageLimit):
- new NetconfDeviceCommunicator(remoteDeviceId, device, rpcMessageLimit), salFacade);
+ return new NetconfConnectorDTO(userCapabilities.isPresent()
+ ? new NetconfDeviceCommunicator(remoteDeviceId, device, userCapabilities.get(), rpcMessageLimit)
+ : new NetconfDeviceCommunicator(remoteDeviceId, device, rpcMessageLimit), salFacade);
}
protected NetconfDevice.SchemaResourcesDTO setupSchemaCacheDTO(final NodeId nodeId, final NetconfNode node) {
return new FilesystemSchemaSourceCache<>(schemaRegistry, YangTextSchemaSource.class, new File(relativeSchemaCacheDirectory));
}
- public NetconfReconnectingClientConfiguration getClientConfig(final NetconfClientSessionListener listener, NetconfNode node) {
+ public NetconfReconnectingClientConfiguration getClientConfig(final NetconfClientSessionListener listener, final NetconfNode node) {
//setup default values since default value is not supported in mdsal
final long clientConnectionTimeoutMillis = node.getConnectionTimeoutMillis() == null ? DEFAULT_CONNECTION_TIMEOUT_MILLIS : node.getConnectionTimeoutMillis();
protected abstract RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(final RemoteDeviceId id, final Broker domBroker, final BindingAwareBroker bindingBroker);
- private InetSocketAddress getSocketAddress(final Host host, int port) {
+ private InetSocketAddress getSocketAddress(final Host host, final int port) {
if(host.getDomainName() != null) {
return new InetSocketAddress(host.getDomainName().getValue(), port);
} else {
}
}
- private Optional<NetconfSessionPreferences> getUserCapabilities(final NetconfNode node) {
- if(node.getYangModuleCapabilities() == null) {
+ private Optional<UserPreferences> getUserCapabilities(final NetconfNode node) {
+ // if none of yang-module-capabilities or non-module-capabilities is specified
+ // just return absent
+ if (node.getYangModuleCapabilities() == null && node.getNonModuleCapabilities() == null) {
return Optional.absent();
}
- final List<String> capabilities = node.getYangModuleCapabilities().getCapability();
- if(capabilities == null || capabilities.isEmpty()) {
- return Optional.absent();
+ final List<String> capabilities = new ArrayList<>();
+
+ boolean overrideYangModuleCaps = false;
+ if (node.getYangModuleCapabilities() != null) {
+ capabilities.addAll(node.getYangModuleCapabilities().getCapability());
+ overrideYangModuleCaps = node.getYangModuleCapabilities().isOverride();
}
- final NetconfSessionPreferences parsedOverrideCapabilities = NetconfSessionPreferences.fromStrings(capabilities, CapabilityOrigin.UserDefined);
- Preconditions.checkState(parsedOverrideCapabilities.getNonModuleCaps().isEmpty(), "Capabilities to override can " +
- "only contain module based capabilities, non-module capabilities will be retrieved from the device," +
- " configured non-module capabilities: " + parsedOverrideCapabilities.getNonModuleCaps());
+ //non-module capabilities should not exist in yang module capabilities
+ final NetconfSessionPreferences netconfSessionPreferences = NetconfSessionPreferences.fromStrings(capabilities);
+ Preconditions.checkState(netconfSessionPreferences.getNonModuleCaps().isEmpty(), "List yang-module-capabilities/capability " +
+ "should contain only module based capabilities. Non-module capabilities used: " +
+ netconfSessionPreferences.getNonModuleCaps());
- return Optional.of(parsedOverrideCapabilities);
+ boolean overrideNonModuleCaps = false;
+ if (node.getNonModuleCapabilities() != null) {
+ capabilities.addAll(node.getNonModuleCapabilities().getCapability());
+ overrideNonModuleCaps = node.getNonModuleCapabilities().isOverride();
+ }
+
+ return Optional.of(new UserPreferences(NetconfSessionPreferences.fromStrings(capabilities, CapabilityOrigin.UserDefined),
+ overrideYangModuleCaps, overrideNonModuleCaps));
}
private static final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory {
facade.close();
}
}
-
}
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.NonModuleCapabilities;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.NonModuleCapabilitiesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.YangModuleCapabilities;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.YangModuleCapabilitiesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.Credentials;
.setUsername(getUsername())
.setPassword(getPassword())
.build();
- final YangModuleCapabilities capabilities;
+
+ YangModuleCapabilities moduleCapabilities = null;
if (getYangModuleCapabilities() != null) {
- capabilities = new YangModuleCapabilitiesBuilder()
+ moduleCapabilities = new YangModuleCapabilitiesBuilder()
.setOverride(getYangModuleCapabilities().getOverride())
.setCapability(getYangModuleCapabilities().getCapability())
.build();
- } else {
- capabilities = null;
}
+
+ NonModuleCapabilities nonModuleCapabilities = null;
+ if(getNonModuleCapabilities() != null) {
+ nonModuleCapabilities = new NonModuleCapabilitiesBuilder()
+ .setOverride(getNonModuleCapabilities().getOverride())
+ .setCapability(getNonModuleCapabilities().getCapability())
+ .build();
+ }
+
final YangLibrary yangLibrary;
if (getYangLibrary() != null) {
yangLibrary = new YangLibraryBuilder()
.setSchemaCacheDirectory(getSchemaCacheDirectory())
.setSleepFactor(getSleepFactor())
.setTcpOnly(getTcpOnly())
- .setYangModuleCapabilities(capabilities)
+ .setYangModuleCapabilities(moduleCapabilities)
+ .setNonModuleCapabilities(nonModuleCapabilities)
.setYangLibrary(yangLibrary)
.build();
return new NodeBuilder()
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapabilityBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability;
import org.opendaylight.yangtools.yang.common.QName;
.collect(Collectors.toList()));
capabilities.addNonModuleBasedCapabilities(remoteSessionCapabilities.getNonModuleCaps().stream().map(entry -> new AvailableCapabilityBuilder()
- .setCapability(entry).setCapabilityOrigin(AvailableCapability.CapabilityOrigin.DeviceAdvertised).build())
+ .setCapability(entry).setCapabilityOrigin(remoteSessionCapabilities.getNonModuleBasedCapsOrigin().get(entry)).build())
.collect(Collectors.toList()));
handleSalInitializationSuccess(result, remoteSessionCapabilities, getDeviceSpecificRpc(result));
LOG.trace("{}: Session advertised capabilities: {}", id,
netconfSessionPreferences);
- if(overrideNetconfCapabilities.isPresent()) {
- netconfSessionPreferences = overrideNetconfCapabilities.get().isOverride() ?
- netconfSessionPreferences.replaceModuleCaps(overrideNetconfCapabilities.get().getSessionPreferences()) :
- netconfSessionPreferences.addModuleCaps(overrideNetconfCapabilities.get().getSessionPreferences());
- LOG.debug(
- "{}: Session capabilities overridden, capabilities that will be used: {}",
- id, netconfSessionPreferences);
+ if (overrideNetconfCapabilities.isPresent()) {
+ final NetconfSessionPreferences sessionPreferences = overrideNetconfCapabilities
+ .get().getSessionPreferences();
+ netconfSessionPreferences = overrideNetconfCapabilities.get().moduleBasedCapsOverrided()
+ ? netconfSessionPreferences.replaceModuleCaps(sessionPreferences)
+ : netconfSessionPreferences.addModuleCaps(sessionPreferences);
+
+ netconfSessionPreferences = overrideNetconfCapabilities.get().nonModuleBasedCapsOverrided()
+ ? netconfSessionPreferences.replaceNonModuleCaps(sessionPreferences)
+ : netconfSessionPreferences.addNonModuleCaps(sessionPreferences);
+ LOG.debug("{}: Session capabilities overridden, capabilities that will be used: {}", id,
+ netconfSessionPreferences);
}
-
remoteDevice.onRemoteSessionUp(netconfSessionPreferences, this);
if (!firstConnectionFuture.isDone()) {
firstConnectionFuture.set(netconfSessionPreferences.getNetconfDeviceCapabilities());
return Futures.immediateFuture( createSessionDownRpcResult() );
}
- final Request req = new Request( new UncancellableFuture<RpcResult<NetconfMessage>>(true),
- message );
+ final Request req = new Request(new UncancellableFuture<>(true), message);
requests.add(req);
session.sendMessage(req.request).addListener(new FutureListener<Void>() {
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
import java.net.URI;
import java.util.Collection;
import java.util.HashMap;
};
private final Map<QName, CapabilityOrigin> moduleBasedCaps;
- private final Set<String> nonModuleCaps;
+ private final Map<String, CapabilityOrigin> nonModuleCaps;
- NetconfSessionPreferences(final Set<String> nonModuleCaps, final Map<QName, CapabilityOrigin> moduleBasedCaps) {
+ NetconfSessionPreferences(final Map<String, CapabilityOrigin> nonModuleCaps, final Map<QName, CapabilityOrigin> moduleBasedCaps) {
this.nonModuleCaps = Preconditions.checkNotNull(nonModuleCaps);
this.moduleBasedCaps = Preconditions.checkNotNull(moduleBasedCaps);
}
}
public Set<String> getNonModuleCaps() {
+ return nonModuleCaps.keySet();
+ }
+
+ public Map<String, CapabilityOrigin> getNonModuleBasedCapsOrigin() {
return nonModuleCaps;
}
// allows partial matches - assuming parameters are in the same order
public boolean containsPartialNonModuleCapability(final String capability) {
- final Iterator<String> iterator = nonModuleCaps.iterator();
+ final Iterator<String> iterator = getNonModuleCaps().iterator();
while(iterator.hasNext()) {
if (iterator.next().startsWith(capability)) {
LOG.trace("capability {} partially matches {}", capability, nonModuleCaps);
}
public boolean containsNonModuleCapability(final String capability) {
- return nonModuleCaps.contains(capability);
+ return nonModuleCaps.containsKey(capability);
}
public boolean containsModuleCapability(final QName capability) {
final Map<QName, CapabilityOrigin> mergedCaps = Maps.newHashMapWithExpectedSize(moduleBasedCaps.size() + netconfSessionModuleCapabilities.getModuleBasedCaps().size());
mergedCaps.putAll(moduleBasedCaps);
mergedCaps.putAll(netconfSessionModuleCapabilities.getModuleBasedCapsOrigin());
- return new NetconfSessionPreferences(getNonModuleCaps(), mergedCaps);
+ return new NetconfSessionPreferences(getNonModuleBasedCapsOrigin(), mergedCaps);
}
/**
* @return new instance of preferences with replaced module-based capabilities
*/
public NetconfSessionPreferences replaceModuleCaps(final NetconfSessionPreferences netconfSessionPreferences) {
- return new NetconfSessionPreferences(getNonModuleCaps(), netconfSessionPreferences.getModuleBasedCapsOrigin());
+ return new NetconfSessionPreferences(getNonModuleBasedCapsOrigin(), netconfSessionPreferences.getModuleBasedCapsOrigin());
+ }
+
+ public NetconfSessionPreferences replaceModuleCaps(final Map<QName, CapabilityOrigin> newModuleBasedCaps) {
+ return new NetconfSessionPreferences(getNonModuleBasedCapsOrigin(), newModuleBasedCaps);
+ }
+
+
+ /**
+ * Merge list of non-module based capabilities with current list of non-module based capabilities
+ *
+ * @param netconfSessionNonModuleCapabilities capabilities to merge into this
+ *
+ * @return new instance of preferences with merged non-module based capabilities
+ */
+ public NetconfSessionPreferences addNonModuleCaps(
+ final NetconfSessionPreferences netconfSessionNonModuleCapabilities) {
+ final Map<String, CapabilityOrigin> mergedCaps = Maps.newHashMapWithExpectedSize(
+ nonModuleCaps.size() + netconfSessionNonModuleCapabilities.getNonModuleCaps().size());
+ mergedCaps.putAll(getNonModuleBasedCapsOrigin());
+ mergedCaps.putAll(netconfSessionNonModuleCapabilities.getNonModuleBasedCapsOrigin());
+ return new NetconfSessionPreferences(mergedCaps, getModuleBasedCapsOrigin());
}
- public NetconfSessionPreferences replaceModuleCaps(Map<QName, CapabilityOrigin> newModuleBasedCaps) {
- return new NetconfSessionPreferences(getNonModuleCaps(), newModuleBasedCaps);
+ /**
+ * Override current list of non-module based capabilities
+ *
+ * @param netconfSessionPreferences capabilities to override in this
+ *
+ * @return new instance of preferences with replaced non-module based capabilities
+ */
+ public NetconfSessionPreferences replaceNonModuleCaps(final NetconfSessionPreferences netconfSessionPreferences) {
+ return new NetconfSessionPreferences(netconfSessionPreferences.getNonModuleBasedCapsOrigin(), getModuleBasedCapsOrigin());
}
public static NetconfSessionPreferences fromNetconfSession(final NetconfClientSession session) {
return fromStrings(capabilities, CapabilityOrigin.DeviceAdvertised);
}
- public static NetconfSessionPreferences fromStrings(final Collection<String> capabilities, CapabilityOrigin capabilityOrigin) {
+ public static NetconfSessionPreferences fromStrings(final Collection<String> capabilities, final CapabilityOrigin capabilityOrigin) {
final Map<QName, CapabilityOrigin> moduleBasedCaps = new HashMap<>();
- final Set<String> nonModuleCaps = Sets.newHashSet(capabilities);
+ final Map<String, CapabilityOrigin> nonModuleCaps = new HashMap<>();
for (final String capability : capabilities) {
+ nonModuleCaps.put(capability, capabilityOrigin);
final int qmark = capability.indexOf('?');
if (qmark == -1) {
continue;
addModuleQName(moduleBasedCaps, nonModuleCaps, capability, cachedQName(namespace, moduleName), capabilityOrigin);
}
- return new NetconfSessionPreferences(ImmutableSet.copyOf(nonModuleCaps), ImmutableMap.copyOf(moduleBasedCaps));
+ return new NetconfSessionPreferences(ImmutableMap.copyOf(nonModuleCaps), ImmutableMap.copyOf(moduleBasedCaps));
}
- private static void addModuleQName(final Map<QName, CapabilityOrigin> moduleBasedCaps, final Set<String> nonModuleCaps, final String capability, final QName qName, CapabilityOrigin capabilityOrigin) {
+ private static void addModuleQName(final Map<QName, CapabilityOrigin> moduleBasedCaps, final Map<String, CapabilityOrigin> nonModuleCaps, final String capability, final QName qName, final CapabilityOrigin capabilityOrigin) {
moduleBasedCaps.put(qName, capabilityOrigin);
nonModuleCaps.remove(capability);
}
- private NetconfDeviceCapabilities capabilities = new NetconfDeviceCapabilities();
+ private final NetconfDeviceCapabilities capabilities = new NetconfDeviceCapabilities();
public NetconfDeviceCapabilities getNetconfDeviceCapabilities() {
return capabilities;
public class UserPreferences {
private final NetconfSessionPreferences sessionPreferences;
- private final boolean override;
+ private final boolean overrideModuleCapabilities;
+ private final boolean overrideNonModuleCapabilities;
+
+ public UserPreferences(@Nonnull final NetconfSessionPreferences sessionPreferences,
+ boolean overrideModuleCapabilities, boolean overrideNonModuleCapabilities) {
+
+ if (overrideModuleCapabilities && (sessionPreferences.getModuleBasedCaps() == null
+ || sessionPreferences.getModuleBasedCaps().isEmpty())) {
+ throw new IllegalStateException(
+ "Override module based capabilities flag set true but module based capabilities list is empty.");
+ }
+ if (overrideNonModuleCapabilities && (sessionPreferences.getNonModuleCaps() == null
+ || sessionPreferences.getNonModuleCaps().isEmpty())) {
+ throw new IllegalStateException(
+ "Override non-module based capabilities set true but non-module based capabilities list is empty.");
+ }
- public UserPreferences(@Nonnull final NetconfSessionPreferences sessionPreferences, boolean override) {
this.sessionPreferences = sessionPreferences;
- this.override = override;
+ this.overrideModuleCapabilities = overrideModuleCapabilities;
+ this.overrideNonModuleCapabilities = overrideNonModuleCapabilities;
}
public NetconfSessionPreferences getSessionPreferences() {
return sessionPreferences;
}
- public boolean isOverride() {
- return override;
+ public boolean moduleBasedCapsOverrided() {
+ return overrideModuleCapabilities;
+ }
+
+ public boolean nonModuleBasedCapsOverrided() {
+ return overrideNonModuleCapabilities;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("UserPreferences{");
sb.append("sessionPreferences=").append(sessionPreferences);
- sb.append(", override=").append(override);
+ sb.append(", overrideModuleCapabilities=").append(overrideModuleCapabilities);
+ sb.append(", overrideNonModuleCapabilities=").append(overrideNonModuleCapabilities);
sb.append('}');
return sb.toString();
}
}
}
+ container non-module-capabilities {
+ config true;
+ leaf override {
+ type boolean;
+ default false;
+ description "Whether to override or merge this list of non-module based capabilities with non-module
+ based capabilities from device";
+ }
+
+ leaf-list capability {
+ type string;
+ description "Set a list of non-module based capabilities to override or merge non-module capabilities
+ provided in device's hello message. Can be used for devices that do not report or
+ incorrectly report non-module based capabilities in their hello message";
+ }
+ }
+
leaf reconnect-on-changed-schema {
config true;
type boolean;
}
}
+ container non-module-capabilities {
+ leaf override {
+ type boolean;
+ default false;
+ description "Whether to override or merge this list of non-module based capabilities with non-module
+ based capabilities from device";
+ }
+
+ leaf-list capability {
+ type string;
+ description "Set a list of non-module based capabilities to override or merge non-module capabilities
+ provided in device's hello message. Can be used for devices that do not report or
+ incorrectly report non-module based capabilities in their hello message";
+ }
+ }
+
leaf reconnect-on-changed-schema {
type boolean;
default false;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import com.google.common.collect.Lists;
import java.util.List;
assertCaps(replaced, 2, 2);
}
+ @Test
+ public void testNonModuleMerge() throws Exception {
+ final List<String> caps1 = Lists.newArrayList(
+ "namespace:1?module=module1&revision=2012-12-12",
+ "namespace:2?module=module2&revision=2012-12-12",
+ "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04",
+ "urn:ietf:params:netconf:base:1.0",
+ "urn:ietf:params:netconf:capability:rollback-on-error:1.0",
+ "urn:ietf:params:netconf:capability:candidate:1.0"
+ );
+ final NetconfSessionPreferences sessionCaps1 = NetconfSessionPreferences.fromStrings(caps1);
+ assertCaps(sessionCaps1, 3, 3);
+ assertTrue(sessionCaps1.isCandidateSupported());
+
+ final List<String> caps2 = Lists.newArrayList(
+ "namespace:3?module=module3&revision=2012-12-12",
+ "namespace:4?module=module4&revision=2012-12-12",
+ "urn:ietf:params:netconf:capability:writable-running:1.0",
+ "urn:ietf:params:netconf:capability:notification:1.0"
+ );
+ final NetconfSessionPreferences sessionCaps2 = NetconfSessionPreferences.fromStrings(caps2);
+ assertCaps(sessionCaps2, 2, 2);
+ assertTrue(sessionCaps2.isRunningWritable());
+
+ final NetconfSessionPreferences merged = sessionCaps1.addNonModuleCaps(sessionCaps2);
+
+ assertCaps(merged, 3+2, 3);
+ for (final String capability : sessionCaps2.getNonModuleCaps()) {
+ assertThat(merged.getNonModuleCaps(), hasItem(capability));
+ }
+
+ assertThat(merged.getNonModuleCaps(), hasItem("urn:ietf:params:netconf:base:1.0"));
+ assertThat(merged.getNonModuleCaps(), hasItem("urn:ietf:params:netconf:capability:rollback-on-error:1.0"));
+ assertThat(merged.getNonModuleCaps(), hasItem("urn:ietf:params:netconf:capability:writable-running:1.0"));
+ assertThat(merged.getNonModuleCaps(), hasItem("urn:ietf:params:netconf:capability:notification:1.0"));
+
+ assertTrue(merged.isCandidateSupported());
+ assertTrue(merged.isRunningWritable());
+ }
+
+ @Test
+ public void testNonmoduleReplace() throws Exception {
+ final List<String> caps1 = Lists.newArrayList(
+ "namespace:1?module=module1&revision=2012-12-12",
+ "namespace:2?module=module2&revision=2012-12-12",
+ "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04",
+ "urn:ietf:params:netconf:base:1.0",
+ "urn:ietf:params:netconf:capability:rollback-on-error:1.0",
+ "urn:ietf:params:netconf:capability:candidate:1.0"
+ );
+ final NetconfSessionPreferences sessionCaps1 = NetconfSessionPreferences.fromStrings(caps1);
+ assertCaps(sessionCaps1, 3, 3);
+ assertTrue(sessionCaps1.isCandidateSupported());
+
+ final List<String> caps2 = Lists.newArrayList(
+ "namespace:3?module=module3&revision=2012-12-12",
+ "namespace:4?module=module4&revision=2012-12-12",
+ "randomNonModuleCap",
+ "urn:ietf:params:netconf:capability:writable-running:1.0"
+ );
+ final NetconfSessionPreferences sessionCaps2 = NetconfSessionPreferences.fromStrings(caps2);
+ assertCaps(sessionCaps2, 2, 2);
+ assertTrue(sessionCaps2.isRunningWritable());
+
+ final NetconfSessionPreferences replaced = sessionCaps1.replaceNonModuleCaps(sessionCaps2);
+ assertCaps(replaced, 2, 3);
+ assertFalse(replaced.isCandidateSupported());
+ assertTrue(replaced.isRunningWritable());
+ }
+
@Test
public void testCapabilityNoRevision() throws Exception {
final List<String> caps1 = Lists.newArrayList(
}
}
+ container non-module-capabilities {
+ config true;
+ leaf override {
+ type boolean;
+ default false;
+ description "Whether to override or merge this list of non-module based capabilities with non-module
+ based capabilities from device";
+ }
+
+ leaf-list capability {
+ type string;
+ description "Set a list of non-module based capabilities to override or merge non-module capabilities
+ provided in device's hello message. Can be used for devices that do not report or
+ incorrectly report non-module based capabilities in their hello message";
+ }
+ }
+
leaf reconnect-on-changed-schema {
config true;
type boolean;