<classifier>config</classifier>
<type>xml</type>
</dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>abstract-topology</artifactId>
- </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-topology</artifactId>
<classifier>config</classifier>
<type>xml</type>
</dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>netconf-topology-config</artifactId>
- <classifier>clustered-config</classifier>
- <type>xml</type>
- </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-tcp</artifactId>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-topology-singleton</artifactId>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<bundle>mvn:org.opendaylight.netconf/sal-netconf-connector/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.controller.model/model-inventory/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.netconf/netconf-topology/{{VERSION}}</bundle>
- <bundle>mvn:org.opendaylight.netconf/abstract-topology/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.netconf/sal-netconf-connector/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.netconf/netconf-config-dispatcher/{{VERSION}}</bundle>
<configfile finalname='${config.configfile.directory}/${config.netconf.client.configfile}'>mvn:org.opendaylight.netconf/netconf-config/{{VERSION}}/xml/config</configfile>
<configfile finalname='${config.configfile.directory}/${config.netconf.topology.configfile}'>mvn:org.opendaylight.netconf/netconf-topology-config/{{VERSION}}/xml/config</configfile>
</feature>
- <feature name='odl-netconf-clustered-topology' version='${project.version}' description="OpenDaylight :: Clustered Netconf Topology :: Netconf Connector + Netconf SSH Server + Clustered Netconf configuration via config topology datastore">
- <feature version='${netconf.version}'>odl-netconf-ssh</feature>
+ <feature name='odl-netconf-clustered-topology' version='${project.version}' description="OpenDaylight :: Clustered Netconf Topology :: Netconf Connector + Netconf SSH Server">
+ <feature version='${project.version}'>odl-netconf-ssh</feature>
<feature version='${project.version}'>odl-netconf-connector</feature>
- <configfile finalname='${config.configfile.directory}/${config.netconf.topology.configfile}'>mvn:org.opendaylight.netconf/netconf-topology-config/{{VERSION}}/xml/clustered-config</configfile>
+ <bundle>mvn:org.opendaylight.netconf/netconf-topology-singleton/{{VERSION}}</bundle>
</feature>
<feature name='odl-netconf-console' version='${project.version}' description="OpenDaylight :: Netconf Console + Karaf CLI for netconf CRUD operations">
<groupId>${project.groupId}</groupId>
<artifactId>netconf-util</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-util</artifactId>
+ <type>cfg</type>
+ <classifier>config</classifier>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-impl</artifactId>
<feature version='${project.version}'>odl-netconf-mapping-api</feature>
<feature version='${yangtools.version}'>odl-yangtools-yang-data</feature>
<bundle>mvn:org.opendaylight.netconf/netconf-util/{{VERSION}}</bundle>
+ <configfile finalname="etc/netconf.cfg">mvn:org.opendaylight.netconf/netconf-util/{{VERSION}}/cfg/config</configfile>
</feature>
<feature name='odl-netconf-impl' version='${project.version}' description="OpenDaylight :: Netconf :: Impl">
</feature>
<feature name='odl-netconf-ssh' version='${project.version}' description="OpenDaylight :: Netconf Connector :: SSH">
+ <feature version='${project.version}'>odl-netconf-util</feature>
<feature version='${project.version}'>odl-netconf-tcp</feature>
<feature version='${project.version}'>odl-aaa-netconf-plugin</feature>
<bundle>mvn:org.opendaylight.netconf/netconf-ssh/{{VERSION}}</bundle>
</feature>
<feature name='odl-netconf-tcp' version='${project.version}' description="OpenDaylight :: Netconf Connector :: TCP">
+ <feature version='${project.version}'>odl-netconf-util</feature>
<feature version='${project.version}'>odl-netconf-impl</feature>
<feature version='${config.version}'>odl-config-netty</feature>
<bundle>mvn:org.opendaylight.netconf/netconf-tcp/{{VERSION}}</bundle>
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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;
-
-import com.google.common.annotations.Beta;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-
-/**
- * Provides initial and failed state for NodeManagers
- */
-@Beta
-public interface InitialStateProvider {
- @Nonnull
- Node getInitialState(@Nonnull final NodeId nodeId, @Nonnull final Node configNode);
-
- @Nonnull
- Node getFailedState(@Nonnull final NodeId nodeId, @Nullable final Node configNode);
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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;
-
-import com.google.common.annotations.Beta;
-import com.google.common.util.concurrent.ListenableFuture;
-import javax.annotation.Nonnull;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-
-/**
- * Node events that happen on a single node on cluster, for a method to notify remote nodes of these events look into RemoteNodeListener
- */
-@Beta
-public interface NodeListener extends RoleChangeListener {
-
- @Nonnull ListenableFuture<Node> onNodeCreated(@Nonnull NodeId nodeId, @Nonnull Node configNode);
-
- @Nonnull ListenableFuture<Node> onNodeUpdated(@Nonnull NodeId nodeId, @Nonnull Node configNode);
-
- @Nonnull ListenableFuture<Void> onNodeDeleted(@Nonnull NodeId nodeId);
-
- @Nonnull ListenableFuture<Node> getCurrentStatusForNode(@Nonnull NodeId nodeId);
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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;
-
-import akka.actor.TypedActor.Receiver;
-import com.google.common.annotations.Beta;
-import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-
-/**
- * Node manager that handles communication between node managers and delegates calls to the customizable NodeManagerCallback
- */
-@Beta
-public interface NodeManager extends InitialStateProvider, NodeListener, Receiver, RemoteNodeListener, RemoteDeviceHandler<NetconfSessionPreferences> {
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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;
-
-import akka.actor.ActorSystem;
-import akka.actor.TypedActor.Receiver;
-import com.google.common.annotations.Beta;
-import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-
-/**
- * Customizable layer that handles communication with your application.
- */
-@Beta
-public interface NodeManagerCallback extends InitialStateProvider, NodeListener, Receiver, RemoteDeviceHandler<NetconfSessionPreferences> {
-
- interface NodeManagerCallbackFactory<M> {
- NodeManagerCallback create(String nodeId, String topologyId, ActorSystem actorSystem);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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;
-
-import com.google.common.annotations.Beta;
-import org.opendaylight.netconf.topology.util.messages.NormalizedNodeMessage;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import scala.concurrent.Future;
-
-/**
- * Interface that provides methods of calling node events on a remote actor.
- * Use these when you want to call node events asynchronously similar to akka ask()
- */
-@Beta
-public interface RemoteNodeListener {
-
- /**
- * This is called when a remote node is informing you that a new configuration was recieved.
- * @param message - serializable message to send
- * @return response from the remote node
- */
- Future<NormalizedNodeMessage> onRemoteNodeCreated(NormalizedNodeMessage message);
-
- /**
- * This is called when a remote node is informing you that a configuration was updated.
- * @param message - serializable message to send
- * @return response from the remote node
- */
- Future<NormalizedNodeMessage> onRemoteNodeUpdated(NormalizedNodeMessage message);
-
- /**
- * This is called when a remote node is informing you that a new configuration was deleted.
- * @param nodeId - id of the node which was deleted
- * @return void future success if delete succeed, failure otherwise
- */
- Future<Void> onRemoteNodeDeleted(NodeId nodeId);
-
- /**
- * Called when a remote node is requesting a node's status, after a status change notification(f.ex sessionUp, sessionDown)
- * on lower level
- * @param nodeId - id of the node which status we want to retrieve
- * @return status for the node requested
- */
- Future<NormalizedNodeMessage> remoteGetCurrentStatusForNode(NodeId nodeId);
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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;
-
-import com.google.common.annotations.Beta;
-
-/**
- * A listener that recieves {@link #onRoleChanged(RoleChangeDTO)} callbacks when a role change occurs
- */
-@Beta
-public interface RoleChangeListener {
-
- /**
- * Called when a role change occurs
- * @param roleChangeDTO a DTO that wraps the current ownership status
- */
- void onRoleChanged(RoleChangeDTO roleChangeDTO);
-
- /**
- * A DTO that wraps an ownership change status
- */
- class RoleChangeDTO {
-
- private final boolean wasOwner;
- private final boolean isOwner;
- private final boolean hasOwner;
-
- public RoleChangeDTO(boolean wasOwner, boolean isOwner, boolean hasOwner) {
- this.wasOwner = wasOwner;
- this.isOwner = isOwner;
- this.hasOwner = hasOwner;
- }
-
- public boolean wasOwner() {
- return wasOwner;
- }
-
- public boolean isOwner() {
- return isOwner;
- }
-
- public boolean hasOwner() {
- return hasOwner;
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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;
-
-import com.google.common.annotations.Beta;
-
-/**
- * A customizable strategy that gets executed when a BaseTopologyManager|BaseNodeManager is created.
- * If the election should be executed at another moment, you need to pass the NoopRoleChangeStrategy into the Manager
- * and the role candidate registration needs to happen in your implemented Node/Topology callback
- */
-@Beta
-public interface RoleChangeStrategy extends RoleChangeListener {
-
- /**
- * Your pre-election and election logic goes here, e.g you should register your candidate into the ElectionService
- * @param electionCandidate NodeListener that should receive the subsequent onRoleChanged callback
- * when a role change occurs.
- */
- void registerRoleCandidate(NodeListener electionCandidate);
-
- /**
- * Invoke whenever you want to stop candidate from partaking in election.
- */
- void unregisterRoleCandidate();
-
- /**
- *
- * @return True/False based on if this candidate is already registered into ownership service
- */
- boolean isCandidateRegistered();
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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;
-
-import com.google.common.annotations.Beta;
-import com.google.common.util.concurrent.ListenableFuture;
-import java.util.List;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-
-/**
- * Aggregate different node states into a single state
- */
-@Beta
-public interface StateAggregator {
-
- ListenableFuture<Node> combineCreateAttempts(final List<ListenableFuture<Node>> stateFutures);
-
- ListenableFuture<Node> combineUpdateAttempts(final List<ListenableFuture<Node>> stateFutures);
-
- ListenableFuture<Void> combineDeleteAttempts(final List<ListenableFuture<Void>> stateFutures);
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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;
-
-import akka.actor.TypedActor.PostStop;
-import akka.actor.TypedActor.PreStart;
-import akka.actor.TypedActor.Receiver;
-import com.google.common.annotations.Beta;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import scala.concurrent.Future;
-
-/**
- * Top level topology manager that handles comunication between nodes, aggregates results, and handles writes into the datastore
- */
-@Beta
-public interface TopologyManager extends NodeListener, Receiver, RemoteNodeListener, PreStart, PostStop{
-
- /**
- * ask if this manager is master
- * @return true/false based on ownership status
- */
- Future<Boolean> isMaster();
-
- /**
- *
- * @param nodeId - id of the node that sessionUp/Down happened on
- */
- void notifyNodeStatusChange(NodeId nodeId);
-
- boolean hasAllPeersUp();
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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;
-
-import akka.actor.ActorSystem;
-import akka.actor.TypedActor.Receiver;
-import com.google.common.annotations.Beta;
-
-/**
- * Customizable extension layer between the top level TopologyManager and NodeManager
- */
-@Beta
-public interface TopologyManagerCallback extends InitialStateProvider, NodeListener, Receiver, RoleChangeListener {
-
- interface TopologyManagerCallbackFactory {
- TopologyManagerCallback create(ActorSystem actorSystem, String topologyId);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.example;
-
-import akka.actor.ActorRef;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.topology.NodeManagerCallback;
-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.NetconfNodeFields;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-
-public class ExampleNodeManagerCallback implements NodeManagerCallback {
-
- public ExampleNodeManagerCallback() {
- }
-
- @Nonnull
- @Override public Node getInitialState(@Nonnull final NodeId nodeId,
- @Nonnull final Node configNode) {
- return new NodeBuilder().addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder().setConnectionStatus(NetconfNodeFields.ConnectionStatus.Connecting).build()).build();
- }
-
- @Nonnull @Override public Node getFailedState(@Nonnull final NodeId nodeId,
- @Nonnull final Node configNode) {
- return new NodeBuilder().addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder().setConnectionStatus(NetconfNodeFields.ConnectionStatus.UnableToConnect).build()).build();
- }
-
- @Nonnull @Override public ListenableFuture<Node> onNodeCreated(@Nonnull final NodeId nodeId,
- @Nonnull final Node configNode) {
- return Futures.immediateFuture(new NodeBuilder().addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder().setConnectionStatus(NetconfNodeFields.ConnectionStatus.Connected).build()).build());
- }
-
- @Nonnull @Override public ListenableFuture<Node> onNodeUpdated(@Nonnull final NodeId nodeId,
- @Nonnull final Node configNode) {
- // update magic
- return Futures.immediateFuture(new NodeBuilder().addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder().setConnectionStatus(NetconfNodeFields.ConnectionStatus.Connected).build()).build());
- }
-
- @Nonnull @Override public ListenableFuture<Void> onNodeDeleted(@Nonnull final NodeId nodeId) {
- return Futures.immediateFuture(null);
- }
-
- @Nonnull
- @Override
- public ListenableFuture<Node> getCurrentStatusForNode(@Nonnull NodeId nodeId) {
- return null;
- }
-
- @Override
- public void onReceive(Object message, ActorRef sender) {
-
- }
-
- @Override
- public void onRoleChanged(RoleChangeDTO roleChangeDTO) {
-
- }
-
- @Override
- public void onDeviceConnected(SchemaContext remoteSchemaContext, NetconfSessionPreferences netconfSessionPreferences, DOMRpcService deviceRpc) {
-
- }
-
- @Override
- public void onDeviceDisconnected() {
-
- }
-
- @Override
- public void onDeviceFailed(Throwable throwable) {
-
- }
-
- @Override
- public void onNotification(DOMNotification domNotification) {
-
- }
-
- @Override
- public void close() {
-
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.example;
-
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.ListenableFuture;
-import java.util.List;
-import org.opendaylight.netconf.topology.StateAggregator;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-
-/**
- * Aggregator implementation expecting just a single state
- */
-public final class ExampleSingleStateAggregator implements StateAggregator {
-
- @Override public ListenableFuture<Node> combineCreateAttempts(final List<ListenableFuture<Node>> stateFutures) {
- return getSingleFuture(stateFutures);
- }
-
- private <T> ListenableFuture<T> getSingleFuture(final List<ListenableFuture<T>> stateFutures) {
- Preconditions.checkArgument(stateFutures.size() == 1, "Recieved multiple results, Single result is enforced here");
- return stateFutures.get(0);
- }
-
- @Override public ListenableFuture<Node> combineUpdateAttempts(final List<ListenableFuture<Node>> stateFutures) {
- return getSingleFuture(stateFutures);
- }
-
- @Override public ListenableFuture<Void> combineDeleteAttempts(final List<ListenableFuture<Void>> stateFutures) {
- return getSingleFuture(stateFutures);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.example;
-
-import akka.actor.ActorSystem;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.netconf.topology.NodeManagerCallback;
-import org.opendaylight.netconf.topology.NodeManagerCallback.NodeManagerCallbackFactory;
-import org.opendaylight.netconf.topology.TopologyManagerCallback;
-import org.opendaylight.netconf.topology.TopologyManagerCallback.TopologyManagerCallbackFactory;
-import org.opendaylight.netconf.topology.util.BaseTopologyManager;
-
-public class ExampleTopology {
-
- private static final String TOPOLOGY_NETCONF = "topology-netconf";
- private BaseTopologyManager netconfNodeBaseTopologyManager;
- private final DataBroker dataBroker;
-
- public ExampleTopology(final EntityOwnershipService entityOwnershipService, final DataBroker dataBroker) {
- final ActorSystem actorSystem = ActorSystem.create("netconf-cluster");
-
- this.dataBroker = dataBroker;
-
- final NodeManagerCallbackFactory nodeManagerCallbackFactory = new NodeManagerCallbackFactory() {
- @Override
- public NodeManagerCallback create(String nodeId, String topologyId, ActorSystem actorSystem) {
- return new ExampleNodeManagerCallback();
- }
- };
-
- final TopologyManagerCallbackFactory topologyManagerCallbackFactory = new TopologyManagerCallbackFactory() {
- @Override
- public TopologyManagerCallback create(ActorSystem actorSystem, String topologyId) {
- return new ExampleTopologyManagerCallback(actorSystem, dataBroker, topologyId, nodeManagerCallbackFactory);
- }
- };
-
-// netconfNodeBaseTopologyManager = new BaseTopologyManager<>(dataBroker, TOPOLOGY_NETCONF,
-// topologyManagerCallbackFactory,
-// new SingleStateAggregator(),
-// new SalNodeWriter(dataBroker, TOPOLOGY_NETCONF),
-// new TopologyRoleChangeStrategy(dataBroker, entityOwnershipService, "netconf", TOPOLOGY_NETCONF));
-
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.example;
-
-import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
-import akka.actor.TypedActor;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.netconf.topology.NodeManager;
-import org.opendaylight.netconf.topology.NodeManagerCallback.NodeManagerCallbackFactory;
-import org.opendaylight.netconf.topology.TopologyManagerCallback;
-import org.opendaylight.netconf.topology.util.BaseNodeManager.BaseNodeManagerBuilder;
-import org.opendaylight.netconf.topology.util.NodeWriter;
-import org.opendaylight.netconf.topology.util.NoopRoleChangeStrategy;
-import org.opendaylight.netconf.topology.util.SalNodeWriter;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ExampleTopologyManagerCallback implements TopologyManagerCallback {
-
- private static final Logger LOG = LoggerFactory.getLogger(ExampleTopologyManagerCallback.class);
-
- private final DataBroker dataBroker;
- private final ActorSystem actorSystem;
- private boolean isMaster;
-
- private final String topologyId;
- private final NodeWriter naSalNodeWriter;
- private final Map<NodeId, NodeManager> nodes = new HashMap<>();
- private final NodeManagerCallbackFactory nodeHandlerFactory;
-
- public ExampleTopologyManagerCallback(final ActorSystem actorSystem,
- final DataBroker dataBroker,
- final String topologyId,
- final NodeManagerCallbackFactory nodeHandlerFactory) {
- this(actorSystem, dataBroker, topologyId, nodeHandlerFactory, new SalNodeWriter(dataBroker, topologyId));
- }
-
- public ExampleTopologyManagerCallback(final ActorSystem actorSystem,
- final DataBroker dataBroker,
- final String topologyId,
- final NodeManagerCallbackFactory nodeHandlerFactory,
- final NodeWriter naSalNodeWriter) {
- this(actorSystem, dataBroker, topologyId, nodeHandlerFactory, naSalNodeWriter, false);
-
- }
-
- public ExampleTopologyManagerCallback(final ActorSystem actorSystem,
- final DataBroker dataBroker,
- final String topologyId,
- final NodeManagerCallbackFactory nodeHandlerFactory,
- final NodeWriter naSalNodeWriter,
- boolean isMaster) {
- this.dataBroker = dataBroker;
- this.actorSystem = actorSystem;
- this.topologyId = topologyId;
- this.nodeHandlerFactory = nodeHandlerFactory;
- this.naSalNodeWriter = naSalNodeWriter;
-
- this.isMaster = isMaster;
- }
-
- @Override
- public ListenableFuture<Node> onNodeCreated(NodeId nodeId, Node node) {
- // Init node admin and a writer for it
-
- // TODO let end user code notify the baseNodeManager about state changes and handle them here on topology level
- final NodeManager naBaseNodeManager =
- createNodeManager(nodeId);
-
- nodes.put(nodeId, naBaseNodeManager);
-
- // Set initial state ? in every peer or just master ? TODO
- if (isMaster) {
- naSalNodeWriter.init(nodeId, naBaseNodeManager.getInitialState(nodeId, node));
- }
-
- // trigger connect on this node
- return naBaseNodeManager.onNodeCreated(nodeId, node);
- }
-
- @Override
- public ListenableFuture<Node> onNodeUpdated(final NodeId nodeId, final Node node) {
- // Set initial state
- naSalNodeWriter.init(nodeId, nodes.get(nodeId).getInitialState(nodeId, node));
-
- // Trigger onNodeUpdated only on this node
- return nodes.get(nodeId).onNodeUpdated(nodeId, node);
- }
-
- @Override
- public ListenableFuture<Void> onNodeDeleted(final NodeId nodeId) {
- // Trigger delete only on this node
- final ListenableFuture<Void> future = nodes.get(nodeId).onNodeDeleted(nodeId);
- Futures.addCallback(future, new FutureCallback<Void>() {
- @Override
- public void onSuccess(Void result) {
- // remove proxy from node list and stop the actor
- final NodeManager remove = nodes.remove(nodeId);
- TypedActor.get(actorSystem).stop(remove);
- }
-
- @Override
- public void onFailure(Throwable t) {
- // NOOP will be handled on higher level
- }
- });
- return future;
- }
-
- @Nonnull
- @Override
- public ListenableFuture<Node> getCurrentStatusForNode(@Nonnull NodeId nodeId) {
- return nodes.get(nodeId).getCurrentStatusForNode(nodeId);
- }
-
- @Override
- public void onRoleChanged(RoleChangeDTO roleChangeDTO) {
- isMaster = roleChangeDTO.isOwner();
- // our post-election logic
- }
-
- private NodeManager createNodeManager(NodeId nodeId) {
- return new BaseNodeManagerBuilder().setNodeId(nodeId.getValue())
- .setActorContext(TypedActor.context())
- .setDelegateFactory(nodeHandlerFactory)
- .setRoleChangeStrategy(new NoopRoleChangeStrategy())
- .setTopologyId(topologyId)
- .build();
- }
-
- @Override
- public void onReceive(Object o, ActorRef actorRef) {
-
- }
-
- @Nonnull
- @Override
- public Node getInitialState(@Nonnull NodeId nodeId, @Nonnull Node configNode) {
- return nodes.get(nodeId).getInitialState(nodeId, configNode);
- }
-
- @Nonnull
- @Override
- public Node getFailedState(@Nonnull NodeId nodeId, @Nullable Node configNode) {
- return nodes.get(nodeId).getFailedState(nodeId, configNode);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.example;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import javax.annotation.Nonnull;
-import org.opendaylight.netconf.topology.util.NodeWriter;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class LoggingSalNodeWriter implements NodeWriter{
-
- private static final Logger LOG = LoggerFactory.getLogger(LoggingSalNodeWriter.class);
-
- private final ArrayList<NodeWriter> delegates;
-
- public LoggingSalNodeWriter(final NodeWriter... delegates) {
- this.delegates = new ArrayList<>(Arrays.asList(delegates));
- }
-
- @Override
- public void init(@Nonnull NodeId id, @Nonnull Node operationalDataNode) {
- LOG.warn("Init recieved");
- LOG.warn("NodeId: {}", id.getValue());
- LOG.warn("Node: {}", operationalDataNode);
- for (final NodeWriter delegate : delegates) {
- delegate.init(id, operationalDataNode);
- }
- }
-
- @Override
- public void update(@Nonnull NodeId id, @Nonnull Node operationalDataNode) {
- LOG.warn("Update recieved");
- LOG.warn("NodeId: {}", id.getValue());
- LOG.warn("Node: {}", operationalDataNode);
- for (final NodeWriter delegate : delegates) {
- delegate.update(id, operationalDataNode);
- }
- }
-
- @Override
- public void delete(@Nonnull NodeId id) {
- LOG.warn("Delete recieved");
- LOG.warn("NodeId: {}", id.getValue());
- for (final NodeWriter delegate : delegates) {
- delegate.delete(id);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.util;
-
-import akka.actor.ActorContext;
-import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
-import akka.actor.TypedActor;
-import akka.actor.TypedProps;
-import akka.japi.Creator;
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.ListenableFuture;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.topology.NodeManager;
-import org.opendaylight.netconf.topology.NodeManagerCallback;
-import org.opendaylight.netconf.topology.NodeManagerCallback.NodeManagerCallbackFactory;
-import org.opendaylight.netconf.topology.RoleChangeStrategy;
-import org.opendaylight.netconf.topology.util.messages.NormalizedNodeMessage;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import scala.concurrent.Future;
-
-public final class BaseNodeManager implements NodeManager {
-
- private static final Logger LOG = LoggerFactory.getLogger(BaseNodeManager.class);
-
- private final String nodeId;
- private final NodeManagerCallback delegate;
-
- private BaseNodeManager(final String nodeId,
- final String topologyId,
- final ActorSystem actorSystem,
- final NodeManagerCallbackFactory delegateFactory,
- final RoleChangeStrategy roleChangeStrategy) {
- LOG.debug("Creating BaseNodeManager, id: {}, {}", topologyId, nodeId );
- this.nodeId = nodeId;
- this.delegate = delegateFactory.create(nodeId, topologyId, actorSystem);
- // if we want to override the place election happens,
- // we need to override this with noop election strategy and implement election in callback
- // cannot leak "this" here! have to use TypedActor.self()
- roleChangeStrategy.registerRoleCandidate((NodeManager) TypedActor.self());
- }
-
- @Nonnull @Override public Node getInitialState(@Nonnull final NodeId nodeId, @Nonnull final Node configNode) {
- LOG.trace("Retrieving Node {} initial state", nodeId);
- return delegate.getInitialState(nodeId, configNode);
- }
-
- @Nonnull @Override public Node getFailedState(@Nonnull final NodeId nodeId, @Nonnull final Node configNode) {
- LOG.trace("Retrieving Node {} failed state", nodeId);
- return delegate.getFailedState(nodeId, configNode);
- }
-
- @Nonnull @Override public ListenableFuture<Node> onNodeCreated(@Nonnull final NodeId nodeId, @Nonnull final Node configNode) {
- LOG.debug("Creating Node {}, with configuration: {}", nodeId.getValue(), configNode);
- return delegate.onNodeCreated(nodeId, configNode);
- }
-
- @Nonnull @Override public ListenableFuture<Node> onNodeUpdated(@Nonnull final NodeId nodeId, @Nonnull final Node configNode) {
- LOG.debug("Updating Node {}, with configuration: {}", nodeId.getValue(), configNode);
- return delegate.onNodeUpdated(nodeId, configNode);
- }
-
- @Nonnull @Override public ListenableFuture<Void> onNodeDeleted(@Nonnull final NodeId nodeId) {
- LOG.debug("Deleting Node {}", nodeId.getValue());
- return delegate.onNodeDeleted(nodeId);
- }
-
- @Nonnull
- @Override
- public ListenableFuture<Node> getCurrentStatusForNode(@Nonnull NodeId nodeId) {
- LOG.debug("Getting current status for node: {}", nodeId.getValue());
- return delegate.getCurrentStatusForNode(nodeId);
- }
-
- @Override
- public void onRoleChanged(RoleChangeDTO roleChangeDTO) {
- LOG.debug("Node {} role has changed from: {} to {}", nodeId,
- (roleChangeDTO.wasOwner() ? "master" : "slave"),
- (roleChangeDTO.isOwner() ? "master" : "slave"));
-
- delegate.onRoleChanged(roleChangeDTO);
- }
-
- @Override
- public void onReceive(Object o, ActorRef actorRef) {
- delegate.onReceive(o, actorRef);
- }
-
- @Override
- public Future<NormalizedNodeMessage> onRemoteNodeCreated(final NormalizedNodeMessage message) {
- return null;
- }
-
- @Override
- public Future<NormalizedNodeMessage> onRemoteNodeUpdated(final NormalizedNodeMessage message) {
- return null;
- }
-
- @Override
- public Future<Void> onRemoteNodeDeleted(final NodeId nodeId) {
- return null;
- }
-
- @Override
- public Future<NormalizedNodeMessage> remoteGetCurrentStatusForNode(final NodeId nodeId) {
- return null;
- }
-
- @Override
- public void onDeviceConnected(SchemaContext remoteSchemaContext, NetconfSessionPreferences netconfSessionPreferences, DOMRpcService deviceRpc) {
- delegate.onDeviceConnected(remoteSchemaContext, netconfSessionPreferences, deviceRpc);
- }
-
- @Override
- public void onDeviceDisconnected() {
- delegate.onDeviceDisconnected();
- }
-
- @Override
- public void onDeviceFailed(Throwable throwable) {
- delegate.onDeviceFailed(throwable);
- }
-
- @Override
- public void onNotification(DOMNotification domNotification) {
- delegate.onNotification(domNotification);
- }
-
- @Override
- public void close() {
- // NOOP
- }
-
- /**
- * Builder of BaseNodeManager instances that are proxied as TypedActors
- */
- public static class BaseNodeManagerBuilder {
- private String nodeId;
- private String topologyId;
- private NodeManagerCallbackFactory delegateFactory;
- private RoleChangeStrategy roleChangeStrategy;
- private ActorContext actorContext;
-
-
- public BaseNodeManagerBuilder setNodeId(final String nodeId) {
- this.nodeId = nodeId;
- return this;
- }
-
- public BaseNodeManagerBuilder setTopologyId(final String topologyId) {
- this.topologyId = topologyId;
- return this;
- }
-
- public BaseNodeManagerBuilder setDelegateFactory(final NodeManagerCallbackFactory delegateFactory) {
- this.delegateFactory = delegateFactory;
- return this;
- }
-
- public BaseNodeManagerBuilder setRoleChangeStrategy(final RoleChangeStrategy roleChangeStrategy) {
- this.roleChangeStrategy = roleChangeStrategy;
- return this;
- }
-
- public BaseNodeManagerBuilder setActorContext(final ActorContext actorContext) {
- this.actorContext = actorContext;
- return this;
- }
-
- public NodeManager build() {
- Preconditions.checkNotNull(nodeId);
- Preconditions.checkNotNull(topologyId);
- Preconditions.checkNotNull(delegateFactory);
- Preconditions.checkNotNull(roleChangeStrategy);
- Preconditions.checkNotNull(actorContext);
- LOG.debug("Creating typed actor with id: {}", nodeId);
-
- return TypedActor.get(actorContext).typedActorOf(new TypedProps<>(NodeManager.class, new Creator<BaseNodeManager>() {
- @Override
- public BaseNodeManager create() throws Exception {
- return new BaseNodeManager(nodeId, topologyId, actorContext.system(), delegateFactory, roleChangeStrategy);
- }
- }), nodeId);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.util;
-
-import akka.actor.ActorContext;
-import akka.actor.ActorIdentity;
-import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
-import akka.actor.Address;
-import akka.actor.Identify;
-import akka.actor.TypedActor;
-import akka.actor.TypedActorExtension;
-import akka.actor.TypedProps;
-import akka.cluster.Cluster;
-import akka.cluster.ClusterEvent;
-import akka.cluster.ClusterEvent.MemberEvent;
-import akka.cluster.ClusterEvent.MemberExited;
-import akka.cluster.ClusterEvent.MemberRemoved;
-import akka.cluster.ClusterEvent.MemberUp;
-import akka.cluster.ClusterEvent.ReachableMember;
-import akka.cluster.ClusterEvent.UnreachableMember;
-import akka.cluster.Member;
-import akka.dispatch.OnComplete;
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Random;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
-import org.opendaylight.netconf.topology.RoleChangeStrategy;
-import org.opendaylight.netconf.topology.StateAggregator;
-import org.opendaylight.netconf.topology.TopologyManager;
-import org.opendaylight.netconf.topology.TopologyManagerCallback;
-import org.opendaylight.netconf.topology.TopologyManagerCallback.TopologyManagerCallbackFactory;
-import org.opendaylight.netconf.topology.util.messages.CustomIdentifyMessage;
-import org.opendaylight.netconf.topology.util.messages.CustomIdentifyMessageReply;
-import org.opendaylight.netconf.topology.util.messages.NormalizedNodeMessage;
-import org.opendaylight.netconf.util.NetconfTopologyPathCreator;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import scala.concurrent.Future;
-import scala.concurrent.duration.FiniteDuration;
-import scala.concurrent.impl.Promise.DefaultPromise;
-
-public final class BaseTopologyManager
- implements TopologyManager {
-
- private static final Logger LOG = LoggerFactory.getLogger(BaseTopologyManager.class);
-
- private final KeyedInstanceIdentifier<Topology, TopologyKey> topologyListPath;
-
- private final ActorSystem system;
- private final TypedActorExtension typedExtension;
- private final Cluster clusterExtension;
-
- private final BindingNormalizedNodeCodecRegistry codecRegistry;
-
- private static final String PATH = "/user/";
-
- private final DataBroker dataBroker;
- private final RoleChangeStrategy roleChangeStrategy;
- private final StateAggregator aggregator;
-
- private final NodeWriter naSalNodeWriter;
- private final String topologyId;
- private final TopologyManagerCallback delegateTopologyHandler;
- private final Set<NodeId> created = new HashSet<>();
-
- private final Map<Address, TopologyManager> peers = new HashMap<>();
- private final int id = new Random().nextInt();
-
- private boolean isMaster;
-
- public BaseTopologyManager(final ActorSystem system,
- final BindingNormalizedNodeCodecRegistry codecRegistry,
- final DataBroker dataBroker,
- final String topologyId,
- final TopologyManagerCallbackFactory topologyManagerCallbackFactory,
- final StateAggregator aggregator,
- final NodeWriter naSalNodeWriter,
- final RoleChangeStrategy roleChangeStrategy) {
- this(system, codecRegistry, dataBroker, topologyId, topologyManagerCallbackFactory, aggregator, naSalNodeWriter, roleChangeStrategy, false);
- }
-
- public BaseTopologyManager(final ActorSystem system,
- final BindingNormalizedNodeCodecRegistry codecRegistry,
- final DataBroker dataBroker,
- final String topologyId,
- final TopologyManagerCallbackFactory topologyManagerCallbackFactory,
- final StateAggregator aggregator,
- final NodeWriter naSalNodeWriter,
- final RoleChangeStrategy roleChangeStrategy,
- final boolean isMaster) {
-
- this.system = system;
- this.typedExtension = TypedActor.get(system);
- this.clusterExtension = Cluster.get(system);
- this.dataBroker = dataBroker;
- this.topologyId = topologyId;
- this.delegateTopologyHandler = topologyManagerCallbackFactory.create(system, topologyId);
- this.aggregator = aggregator;
- this.naSalNodeWriter = naSalNodeWriter;
- this.roleChangeStrategy = roleChangeStrategy;
- this.codecRegistry = codecRegistry;
-
- // election has not yet happened
- this.isMaster = isMaster;
-
- this.topologyListPath = TopologyUtil.createTopologyListPath(topologyId);
-
- LOG.debug("Base manager started ", +id);
- }
-
- @Override
- public void preStart() {
- LOG.debug("preStart called");
- // TODO change to enum, master/slave active/standby
- roleChangeStrategy.registerRoleCandidate(TypedActor.<BaseTopologyManager>self());
- LOG.debug("candidate registered");
- clusterExtension.subscribe(TypedActor.context().self(), ClusterEvent.initialStateAsEvents(), MemberEvent.class, UnreachableMember.class);
- }
-
- @Override
- public void postStop() {
- LOG.debug("postStop called");
- clusterExtension.leave(clusterExtension.selfAddress());
- clusterExtension.unsubscribe(TypedActor.context().self());
- }
-
- @Override
- public ListenableFuture<Node> onNodeCreated(final NodeId nodeId, final Node node) {
- LOG.debug("TopologyManager({}) onNodeCreated received, nodeid: {} , isMaster: {}", id, nodeId.getValue(), isMaster);
-
- if (created.contains(nodeId)) {
- LOG.warn("Node{} already exists, triggering update..", nodeId);
- return onNodeUpdated(nodeId, node);
- }
- created.add(nodeId);
- final ArrayList<ListenableFuture<Node>> futures = new ArrayList<>();
-
- if (isMaster) {
-
- futures.add(delegateTopologyHandler.onNodeCreated(nodeId, node));
- // only master should call connect on peers and aggregate futures
- for (TopologyManager topologyManager : peers.values()) {
- // convert binding into NormalizedNode for transfer
- final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNodeEntry = codecRegistry.toNormalizedNode(TopologyUtil.createTopologyNodePath(topologyId), node);
-
- LOG.debug("YangInstanceIdentifier {}", normalizedNodeEntry.getKey());
- LOG.debug("Value {}", normalizedNodeEntry.getValue());
-
- // add a future into our futures that gets its completion status from the converted scala future
- final SettableFuture<Node> settableFuture = SettableFuture.create();
- futures.add(settableFuture);
- final Future<NormalizedNodeMessage> scalaFuture = topologyManager.onRemoteNodeCreated(new NormalizedNodeMessage(normalizedNodeEntry.getKey(), normalizedNodeEntry.getValue()));
- scalaFuture.onComplete(new OnComplete<NormalizedNodeMessage>() {
- @Override
- public void onComplete(Throwable failure, NormalizedNodeMessage success) throws Throwable {
- if (failure != null) {
- settableFuture.setException(failure);
- return;
- }
- final Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode =
- codecRegistry.fromNormalizedNode(success.getIdentifier(), success.getNode());
- final Node value = (Node) fromNormalizedNode.getValue();
-
- settableFuture.set(value);
- }
- }, TypedActor.context().dispatcher());
- }
-
- final ListenableFuture<Node> aggregatedFuture = aggregator.combineCreateAttempts(futures);
- Futures.addCallback(aggregatedFuture, new FutureCallback<Node>() {
- @Override
- public void onSuccess(final Node result) {
- LOG.debug("Futures aggregated succesfully");
- naSalNodeWriter.init(nodeId, result);
- }
-
- @Override
- public void onFailure(final Throwable t) {
- // If the combined connection attempt failed, set the node to connection failed
- LOG.debug("Futures aggregation failed");
- naSalNodeWriter.update(nodeId, delegateTopologyHandler.getFailedState(nodeId, node));
- }
- }, TypedActor.context().dispatcher());
-
- //combine peer futures
- return aggregatedFuture;
- }
-
- // trigger create on this slave
- return delegateTopologyHandler.onNodeCreated(nodeId, node);
- }
-
- @Override
- public ListenableFuture<Node> onNodeUpdated(final NodeId nodeId, final Node node) {
- LOG.debug("TopologyManager({}) onNodeUpdated received, nodeid: {}", id, nodeId.getValue());
-
- // Master needs to trigger onNodeUpdated on peers and combine results
- if (isMaster) {
- // first cleanup old node
- final ListenableFuture<Void> deleteFuture = onNodeDeleted(nodeId);
- final SettableFuture<Node> createFuture = SettableFuture.create();
- final TopologyManager selfProxy = TypedActor.self();
- final ActorContext context = TypedActor.context();
- Futures.addCallback(deleteFuture, new FutureCallback<Void>() {
- @Override
- public void onSuccess(Void result) {
- LOG.warn("Delete part of update succesfull, triggering create");
- // trigger create on all nodes
- Futures.addCallback(selfProxy.onNodeCreated(nodeId, node), new FutureCallback<Node>() {
- @Override
- public void onSuccess(Node result) {
- createFuture.set(result);
- }
-
- @Override
- public void onFailure(Throwable t) {
- createFuture.setException(t);
- }
- }, context.dispatcher());
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.warn("Delete part of update failed, {}", t);
- }
- }, context.dispatcher());
- return createFuture;
- }
-
- // Trigger update on this slave
- return delegateTopologyHandler.onNodeUpdated(nodeId, node);
- }
-
- @Override
- public ListenableFuture<Void> onNodeDeleted(final NodeId nodeId) {
- final ArrayList<ListenableFuture<Void>> futures = new ArrayList<>();
- created.remove(nodeId);
-
- // Master needs to trigger delete on peers and combine results
- if (isMaster) {
- futures.add(delegateTopologyHandler.onNodeDeleted(nodeId));
- for (TopologyManager topologyManager : peers.values()) {
- // add a future into our futures that gets its completion status from the converted scala future
- final SettableFuture<Void> settableFuture = SettableFuture.create();
- futures.add(settableFuture);
- final Future<Void> scalaFuture = topologyManager.onRemoteNodeDeleted(nodeId);
- scalaFuture.onComplete(new OnComplete<Void>() {
- @Override
- public void onComplete(Throwable failure, Void success) throws Throwable {
- if (failure != null) {
- settableFuture.setException(failure);
- return;
- }
-
- settableFuture.set(success);
- }
- }, TypedActor.context().dispatcher());
- }
-
- final ListenableFuture<Void> aggregatedFuture = aggregator.combineDeleteAttempts(futures);
- Futures.addCallback(aggregatedFuture, new FutureCallback<Void>() {
- @Override
- public void onSuccess(final Void result) {
- naSalNodeWriter.delete(nodeId);
- }
-
- @Override
- public void onFailure(final Throwable t) {
-
- }
- });
-
- return aggregatedFuture;
- }
-
- // Trigger delete
- return delegateTopologyHandler.onNodeDeleted(nodeId);
- }
-
- @Nonnull
- @Override
- public ListenableFuture<Node> getCurrentStatusForNode(@Nonnull final NodeId nodeId) {
- return delegateTopologyHandler.getCurrentStatusForNode(nodeId);
- }
-
- @Override
- public void onRoleChanged(final RoleChangeDTO roleChangeDTO) {
- isMaster = roleChangeDTO.isOwner();
- delegateTopologyHandler.onRoleChanged(roleChangeDTO);
- if (isMaster) {
- LOG.debug("Node {} is master now", clusterExtension.selfAddress());
- clusterExtension.join(clusterExtension.selfAddress());
- }
- }
-
- @Override
- public Future<Boolean> isMaster() {
- return new DefaultPromise<Boolean>().success(isMaster).future();
- }
-
- @Override
- public void notifyNodeStatusChange(final NodeId nodeId) {
- LOG.debug("Connection status has changed on node {}", nodeId.getValue());
- if (isMaster) {
- // grab status from all peers and aggregate
- final ArrayList<ListenableFuture<Node>> futures = new ArrayList<>();
- futures.add(delegateTopologyHandler.getCurrentStatusForNode(nodeId));
- // only master should call connect on peers and aggregate futures
- for (TopologyManager topologyManager : peers.values()) {
- // add a future into our futures that gets its completion status from the converted scala future
- final SettableFuture<Node> settableFuture = SettableFuture.create();
- futures.add(settableFuture);
- final Future<NormalizedNodeMessage> scalaFuture = topologyManager.remoteGetCurrentStatusForNode(nodeId);
- scalaFuture.onComplete(new OnComplete<NormalizedNodeMessage>() {
- @Override
- public void onComplete(Throwable failure, NormalizedNodeMessage success) throws Throwable {
- if (failure != null) {
- settableFuture.setException(failure);
- return;
- }
- final Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode =
- codecRegistry.fromNormalizedNode(success.getIdentifier(), success.getNode());
- final Node value = (Node) fromNormalizedNode.getValue();
-
- settableFuture.set(value);
- }
- }, TypedActor.context().dispatcher());
- }
-
- final ListenableFuture<Node> aggregatedFuture = aggregator.combineUpdateAttempts(futures);
- Futures.addCallback(aggregatedFuture, new FutureCallback<Node>() {
- @Override
- public void onSuccess(final Node result) {
- LOG.debug("Futures aggregated succesfully");
- naSalNodeWriter.update(nodeId, result);
- }
-
- @Override
- public void onFailure(final Throwable t) {
- // If the combined connection attempt failed, set the node to connection failed
- LOG.debug("Futures aggregation failed");
- naSalNodeWriter.update(nodeId, delegateTopologyHandler.getFailedState(nodeId, null));
- }
- });
- return;
- }
- LOG.debug("Not master, forwarding..");
- for (final TopologyManager manager : peers.values()) {
- // asynchronously find out which peer is master
- final Future<Boolean> future = manager.isMaster();
- future.onComplete(new OnComplete<Boolean>() {
- @Override
- public void onComplete(Throwable failure, Boolean success) throws Throwable {
- if (failure == null && success) {
- LOG.debug("Found master peer");
- // forward to master
- manager.notifyNodeStatusChange(nodeId);
- return;
- }
- if (failure != null) {
- LOG.debug("Retrieving master peer failed, {}", failure);
- }
- }
- }, TypedActor.context().dispatcher());
- }
- }
-
- @Override
- public boolean hasAllPeersUp() {
- LOG.debug("Peers needed: {} Peers up: {}", 2, peers.size());
- LOG.warn(clusterExtension.state().toString());
- LOG.warn(peers.toString());
- return peers.size() == 2;
- }
-
- @Override
- public Future<NormalizedNodeMessage> onRemoteNodeCreated(final NormalizedNodeMessage message) {
- final Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode =
- codecRegistry.fromNormalizedNode(message.getIdentifier(), message.getNode());
- final InstanceIdentifier<Node> iid = (InstanceIdentifier<Node>) fromNormalizedNode.getKey();
- final Node value = (Node) fromNormalizedNode.getValue();
-
- LOG.debug("TopologyManager({}) onRemoteNodeCreated received, nodeid: {}", value.getNodeId(), value);
- final ListenableFuture<Node> nodeListenableFuture = onNodeCreated(value.getNodeId(), value);
- final DefaultPromise<NormalizedNodeMessage> promise = new DefaultPromise<>();
- Futures.addCallback(nodeListenableFuture, new FutureCallback<Node>() {
- @Override
- public void onSuccess(Node result) {
- final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry = codecRegistry.toNormalizedNode(iid, result);
- promise.success(new NormalizedNodeMessage(entry.getKey(), entry.getValue()));
- }
-
- @Override
- public void onFailure(Throwable t) {
- promise.failure(t);
- }
- });
-
- return promise.future();
- }
-
- @Override
- public Future<NormalizedNodeMessage> onRemoteNodeUpdated(final NormalizedNodeMessage message) {
- final Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode =
- codecRegistry.fromNormalizedNode(message.getIdentifier(), message.getNode());
- final InstanceIdentifier<Node> iid = (InstanceIdentifier<Node>) fromNormalizedNode.getKey();
- final Node value = (Node) fromNormalizedNode.getValue();
-
- LOG.debug("TopologyManager({}) onRemoteNodeUpdated received, nodeid: {}", id, value.getNodeId());
-
- final ListenableFuture<Node> nodeListenableFuture = onNodeUpdated(value.getNodeId(), value);
- final DefaultPromise<NormalizedNodeMessage> promise = new DefaultPromise<>();
- Futures.addCallback(nodeListenableFuture, new FutureCallback<Node>() {
- @Override
- public void onSuccess(Node result) {
- final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry = codecRegistry.toNormalizedNode(iid, result);
- promise.success(new NormalizedNodeMessage(entry.getKey(), entry.getValue()));
- }
-
- @Override
- public void onFailure(Throwable t) {
- promise.failure(t);
- }
- });
- return promise.future();
- }
-
- @Override
- public Future<Void> onRemoteNodeDeleted(final NodeId nodeId) {
- LOG.debug("TopologyManager({}) onRemoteNodeDeleted received, nodeid: {}", id, nodeId.getValue());
-
- final ListenableFuture<Void> listenableFuture = onNodeDeleted(nodeId);
- final DefaultPromise<Void> promise = new DefaultPromise<>();
- Futures.addCallback(listenableFuture, new FutureCallback<Void>() {
- @Override
- public void onSuccess(Void result) {
- promise.success(null);
- }
-
- @Override
- public void onFailure(Throwable t) {
- promise.failure(t);
- }
- });
-
- return promise.future();
- }
-
- public Future<NormalizedNodeMessage> remoteGetCurrentStatusForNode(final NodeId nodeId) {
- LOG.debug("TopologyManager({}) remoteGetCurrentStatusForNode received, nodeid: {}", id, nodeId.getValue());
-
- final ListenableFuture<Node> listenableFuture = getCurrentStatusForNode(nodeId);
- final DefaultPromise<NormalizedNodeMessage> promise = new DefaultPromise<>();
- Futures.addCallback(listenableFuture, new FutureCallback<Node>() {
- @Override
- public void onSuccess(Node result) {
- final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry = codecRegistry.toNormalizedNode(TopologyUtil.createTopologyNodePath(topologyId), result);
- promise.success(new NormalizedNodeMessage(entry.getKey(), entry.getValue()));
- }
-
- @Override
- public void onFailure(Throwable t) {
- promise.failure(t);
- }
- });
- return promise.future();
- }
-
- @Override
- public void onReceive(final Object message, final ActorRef actorRef) {
- LOG.debug("message received {}", message);
- if (message instanceof MemberUp) {
- final Member member = ((MemberUp) message).member();
- LOG.info("Member is Up: {}", member);
- if (member.address().equals(clusterExtension.selfAddress())) {
- return;
- }
-
- final NetconfTopologyPathCreator pathCreator = new NetconfTopologyPathCreator(member.address().toString(), topologyId);
- final String path = pathCreator.build();
- LOG.debug("Actor at :{} is resolving topology actor for path {}", clusterExtension.selfAddress(), path);
-
- // first send basic identify message in case our messages have not been loaded through osgi yet to prevent crashing akka.
- clusterExtension.system().actorSelection(path).tell(new Identify(member.address()), TypedActor.context().self());
- } else if (message instanceof MemberExited) {
- // remove peer
- final Member member = ((MemberExited) message).member();
- LOG.info("Member exited cluster: {}", member);
- peers.remove(member.address());
- } else if (message instanceof MemberRemoved) {
- // remove peer
- final Member member = ((MemberRemoved) message).member();
- LOG.info("Member was removed from cluster: {}", member);
- peers.remove(member.address());
- } else if (message instanceof UnreachableMember) {
- // remove peer
- final Member member = ((UnreachableMember) message).member();
- LOG.info("Member is unreachable: {}", member);
- peers.remove(member.address());
- } else if (message instanceof ReachableMember) {
- // resync peer
- final Member member = ((ReachableMember) message).member();
- LOG.info("Member is reachable again: {}", member);
-
- if (member.address().equals(clusterExtension.selfAddress())) {
- return;
- }
- final NetconfTopologyPathCreator pathCreator = new NetconfTopologyPathCreator(member.address().toString(), topologyId);
- final String path = pathCreator.build();
- LOG.debug("Actor at :{} is resolving topology actor for path {}", clusterExtension.selfAddress(), path);
-
- clusterExtension.system().actorSelection(path).tell(new Identify(member.address()), TypedActor.context().self());
- } else if (message instanceof ActorIdentity) {
- LOG.debug("Received ActorIdentity message", message);
- final NetconfTopologyPathCreator pathCreator = new NetconfTopologyPathCreator(((ActorIdentity) message).correlationId().toString(), topologyId);
- final String path = pathCreator.build();
- if (((ActorIdentity) message).getRef() == null) {
- LOG.debug("ActorIdentity has null actor ref, retrying..", message);
- final ActorRef self = TypedActor.context().self();
- final ActorContext context = TypedActor.context();
- system.scheduler().scheduleOnce(new FiniteDuration(5, TimeUnit.SECONDS), new Runnable() {
- @Override
- public void run() {
- LOG.debug("Retrying identify message from master to node {} , full path {}", ((ActorIdentity) message).correlationId(), path);
- context.system().actorSelection(path).tell(new Identify(((ActorIdentity) message).correlationId()), self);
-
- }
- }, system.dispatcher());
- return;
- }
- LOG.debug("Actor at :{} is resolving topology actor for path {}, with a custom message", clusterExtension.selfAddress(), path);
-
- clusterExtension.system().actorSelection(path).tell(new CustomIdentifyMessage(clusterExtension.selfAddress()), TypedActor.context().self());
- } else if (message instanceof CustomIdentifyMessageReply) {
-
- LOG.warn("Received a custom identify reply message from: {}", ((CustomIdentifyMessageReply) message).getAddress());
- if (!peers.containsKey(((CustomIdentifyMessage) message).getAddress())) {
- final TopologyManager peer = typedExtension.typedActorOf(new TypedProps<>(TopologyManager.class, BaseTopologyManager.class), actorRef);
- peers.put(((CustomIdentifyMessageReply) message).getAddress(), peer);
- if (isMaster) {
- resyncPeer(peer);
- }
- }
- } else if (message instanceof CustomIdentifyMessage) {
- LOG.warn("Received a custom identify message from: {}", ((CustomIdentifyMessage) message).getAddress());
- if (!peers.containsKey(((CustomIdentifyMessage) message).getAddress())) {
- final TopologyManager peer = typedExtension.typedActorOf(new TypedProps<>(TopologyManager.class, BaseTopologyManager.class), actorRef);
- peers.put(((CustomIdentifyMessage) message).getAddress(), peer);
- if (isMaster) {
- resyncPeer(peer);
- }
- }
- actorRef.tell(new CustomIdentifyMessageReply(clusterExtension.selfAddress()), TypedActor.context().self());
- }
- }
-
- private void resyncPeer(final TopologyManager peer) {
- final ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
- final CheckedFuture<Optional<Topology>, ReadFailedException> read = rTx.read(LogicalDatastoreType.CONFIGURATION, topologyListPath);
-
- Futures.addCallback(read, new FutureCallback<Optional<Topology>>() {
- @Override
- public void onSuccess(Optional<Topology> result) {
- if (result.isPresent() && result.get().getNode() != null) {
- for (final Node node : result.get().getNode()) {
- final Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry = codecRegistry.toNormalizedNode(TopologyUtil.createTopologyNodePath(topologyId), node);
- peer.onRemoteNodeCreated(new NormalizedNodeMessage(entry.getKey(), entry.getValue()));
- // we dont care about the future from now on since we will be notified by the onConnected event
- }
- }
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.error("Unable to read from datastore");
- }
- });
-
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.util;
-
-import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
-import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.netconf.topology.RoleChangeStrategy;
-import org.opendaylight.netconf.topology.NodeListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class NodeRoleChangeStrategy implements RoleChangeStrategy, EntityOwnershipListener {
-
- private static final Logger LOG = LoggerFactory.getLogger(NodeRoleChangeStrategy.class);
-
- private final EntityOwnershipService entityOwnershipService;
- private final String entityType;
- private final String entityName;
- private final Entity entity;
- private NodeListener ownershipCandidate;
-
- private EntityOwnershipCandidateRegistration candidateRegistration = null;
- private EntityOwnershipListenerRegistration ownershipListenerRegistration = null;
-
- public NodeRoleChangeStrategy(final EntityOwnershipService entityOwnershipService,
- final String entityType,
- final String entityName) {
- this.entityOwnershipService = entityOwnershipService;
- this.entityType = entityType + "/" + entityName;
- this.entityName = entityName;
- this.entity = new Entity(this.entityType, entityName);
- }
-
- @Override
- public void registerRoleCandidate(NodeListener electionCandidate) {
- LOG.debug("Registering role candidate type: {} , name: {}", entityType, entityName);
- this.ownershipCandidate = electionCandidate;
- try {
- if (candidateRegistration != null) {
- unregisterRoleCandidate();
- }
- candidateRegistration = entityOwnershipService.registerCandidate(entity);
- ownershipListenerRegistration = entityOwnershipService.registerListener(entityType, this);
- } catch (CandidateAlreadyRegisteredException e) {
- LOG.error("Candidate already registered for election", e);
- throw new IllegalStateException("Candidate already registered for election", e);
- }
- }
-
- @Override
- public void unregisterRoleCandidate() {
- LOG.debug("Unregistering role candidate");
- if (candidateRegistration != null) {
- candidateRegistration.close();
- candidateRegistration = null;
- }
- if (ownershipListenerRegistration != null) {
- ownershipListenerRegistration.close();
- ownershipListenerRegistration = null;
- }
- }
-
- @Override
- public boolean isCandidateRegistered() {
- return entityOwnershipService.isCandidateRegistered(entity);
- }
-
- @Override
- public void onRoleChanged(RoleChangeDTO roleChangeDTO) {
- LOG.debug("Role was changed {}", roleChangeDTO);
- ownershipCandidate.onRoleChanged(roleChangeDTO);
- }
-
- @Override
- public void ownershipChanged(EntityOwnershipChange ownershipChange) {
- LOG.debug("Ownership has changed {}", ownershipChange);
- ownershipCandidate.onRoleChanged(new RoleChangeDTO(ownershipChange.wasOwner(), ownershipChange.isOwner(), ownershipChange.hasOwner()));
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.util;
-
-import com.google.common.annotations.Beta;
-import javax.annotation.Nonnull;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-
-/**
- * Customizable code that gets executed after result aggregation, meant for custom writes
- * into the datastore, but any user code can be run here if desired.
- */
-@Beta
-public interface NodeWriter {
-
- void init(@Nonnull final NodeId id, @Nonnull final Node operationalDataNode);
-
- void update(@Nonnull final NodeId id, @Nonnull final Node operationalDataNode);
-
- void delete(@Nonnull final NodeId id);
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.util;
-
-import org.opendaylight.netconf.topology.NodeListener;
-import org.opendaylight.netconf.topology.RoleChangeStrategy;
-
-/**
- * Use this strategy to override the default roleChange registration's in BaseTopologyManager|BaseNodeManager
- * If you use this, you will need to execute your own election in your implemented callbacks.
- */
-public class NoopRoleChangeStrategy implements RoleChangeStrategy {
-
- @Override
- public void registerRoleCandidate(NodeListener electionCandidate) {
-
- }
-
- @Override
- public void unregisterRoleCandidate() {
-
- }
-
- @Override
- public boolean isCandidateRegistered() {
- return false;
- }
-
- @Override
- public void onRoleChanged(RoleChangeDTO roleChangeDTO) {
-
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.util;
-
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public final class SalNodeWriter implements NodeWriter {
-
- private static final Logger LOG = LoggerFactory.getLogger(SalNodeWriter.class);
-
- private final String topologyId;
-
- private final BindingTransactionChain transactionChain;
- public SalNodeWriter(final DataBroker dataBroker, final String topologyId) {
- this.topologyId = topologyId;
- this.transactionChain = Preconditions.checkNotNull(dataBroker).createTransactionChain(new TransactionChainListener() {
- @Override
- public void onTransactionChainFailed(TransactionChain<?, ?> transactionChain, AsyncTransaction<?, ?> transaction, Throwable cause) {
- LOG.error("{}: TransactionChain({}) {} FAILED!", transactionChain,
- transaction.getIdentifier(), cause);
- throw new IllegalStateException("Abstract topology writer TransactionChain(" + transactionChain + ") not committed correctly", cause);
- }
-
- @Override
- public void onTransactionChainSuccessful(TransactionChain<?, ?> transactionChain) {
- LOG.trace("Abstract topology writer TransactionChain({}) SUCCESSFUL", transactionChain);
- }
- });
- }
-
- @Override public void init(@Nonnull final NodeId id, @Nonnull final Node operationalDataNode) {
- // put into Datastore
- final WriteTransaction wTx = transactionChain.newWriteOnlyTransaction();
- wTx.put(LogicalDatastoreType.OPERATIONAL, TopologyUtil.createTopologyNodeListPath(new NodeKey(id), topologyId), operationalDataNode);
- commitTransaction(wTx, id, "init");
- }
-
- @Override public void update(@Nonnull final NodeId id, @Nonnull final Node operationalDataNode) {
- // merge
- final WriteTransaction wTx = transactionChain.newWriteOnlyTransaction();
- wTx.put(LogicalDatastoreType.OPERATIONAL, TopologyUtil.createTopologyNodeListPath(new NodeKey(id), topologyId), operationalDataNode);
- commitTransaction(wTx, id, "update");
- }
-
- @Override public void delete(@Nonnull final NodeId id) {
- // delete
- final WriteTransaction wTx = transactionChain.newWriteOnlyTransaction();
- wTx.delete(LogicalDatastoreType.OPERATIONAL, TopologyUtil.createTopologyNodeListPath(new NodeKey(id), topologyId));
- commitTransaction(wTx, id, "delete");
- }
-
- private void commitTransaction(final WriteTransaction transaction, final NodeId id, final String txType) {
- LOG.debug("{}: Committing Transaction {}:{}", id.getValue(), txType,
- transaction.getIdentifier());
- final CheckedFuture<Void, TransactionCommitFailedException> result = transaction.submit();
-
- Futures.addCallback(result, new FutureCallback<Void>() {
- @Override
- public void onSuccess(final Void result) {
- LOG.debug("{}: Transaction({}) {} SUCCESSFUL", id.getValue(), txType,
- transaction.getIdentifier());
- }
-
- @Override
- public void onFailure(final Throwable t) {
- LOG.error("{}: Transaction({}) {} FAILED!", id.getValue(), txType,
- transaction.getIdentifier(), t);
- throw new IllegalStateException(id + " Transaction(" + txType + ") not committed correctly", t);
- }
- });
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.util;
-
-import java.util.Collection;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
-import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
-import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
-import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
-import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.netconf.topology.NodeListener;
-import org.opendaylight.netconf.topology.RoleChangeStrategy;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class TopologyRoleChangeStrategy implements RoleChangeStrategy, ClusteredDataTreeChangeListener<Node>, EntityOwnershipListener {
-
- private static final Logger LOG = LoggerFactory.getLogger(TopologyRoleChangeStrategy.class);
-
- private final DataBroker dataBroker;
-
- private final EntityOwnershipService entityOwnershipService;
- private NodeListener ownershipCandidate;
- private final String entityType;
- // use topologyId as entityName
- private final Entity entity;
-
- private EntityOwnershipCandidateRegistration candidateRegistration = null;
- private EntityOwnershipListenerRegistration ownershipListenerRegistration = null;
-
- private ListenerRegistration<TopologyRoleChangeStrategy> datastoreListenerRegistration;
-
- public TopologyRoleChangeStrategy(final DataBroker dataBroker,
- final EntityOwnershipService entityOwnershipService,
- final String entityType,
- final String entityName) {
- this.dataBroker = dataBroker;
- this.entityOwnershipService = entityOwnershipService;
- this.entityType = entityType;
- this.entity = new Entity(entityType, entityName);
-
- datastoreListenerRegistration = null;
- }
-
- @Override
- public void registerRoleCandidate(NodeListener electionCandidate) {
- LOG.warn("Registering candidate");
- ownershipCandidate = electionCandidate;
- try {
- if (candidateRegistration != null) {
- unregisterRoleCandidate();
- }
- candidateRegistration = entityOwnershipService.registerCandidate(entity);
- ownershipListenerRegistration = entityOwnershipService.registerListener(entityType, this);
- } catch (CandidateAlreadyRegisteredException e) {
- LOG.error("Candidate already registered for election", e);
- throw new IllegalStateException("Candidate already registered for election", e);
- }
- }
-
- @Override
- public void unregisterRoleCandidate() {
- candidateRegistration.close();
- candidateRegistration = null;
- ownershipListenerRegistration.close();
- ownershipListenerRegistration = null;
- }
-
- @Override
- public boolean isCandidateRegistered() {
- return entityOwnershipService.isCandidateRegistered(entity);
- }
-
- @Override
- public void onRoleChanged(RoleChangeDTO roleChangeDTO) {
- if (roleChangeDTO.isOwner()) {
- LOG.warn("Gained ownership of entity, registering datastore listener");
-
- if (datastoreListenerRegistration == null) {
- LOG.debug("Listener on path {}", TopologyUtil.createTopologyListPath(entityType).child(Node.class).getPathArguments());
- datastoreListenerRegistration = dataBroker.registerDataTreeChangeListener(
- new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, TopologyUtil.createTopologyListPath(entityType).child(Node.class)), this);
- }
- } else if (datastoreListenerRegistration != null) {
- LOG.warn("No longer owner of entity, unregistering datastore listener");
- datastoreListenerRegistration.close();
- datastoreListenerRegistration = null;
- }
- ownershipCandidate.onRoleChanged(roleChangeDTO);
- }
-
- @Override
- public void ownershipChanged(final EntityOwnershipChange ownershipChange) {
- onRoleChanged(new RoleChangeDTO(ownershipChange.wasOwner(), ownershipChange.isOwner(), ownershipChange.hasOwner()));
- }
-
- @Override
- public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<Node>> changes) {
- for (DataTreeModification<Node> change : changes) {
- final DataObjectModification<Node> rootNode = change.getRootNode();
- switch (rootNode.getModificationType()) {
- case WRITE:
- LOG.debug("Data was Created {}, {}", rootNode.getIdentifier(), rootNode.getDataAfter());
- ownershipCandidate.onNodeCreated(TopologyUtil.getNodeId(rootNode.getIdentifier()), rootNode.getDataAfter());
- break;
- case SUBTREE_MODIFIED:
- LOG.debug("Data was Updated {}, {}", rootNode.getIdentifier(), rootNode.getDataAfter());
- ownershipCandidate.onNodeUpdated(TopologyUtil.getNodeId(rootNode.getIdentifier()), rootNode.getDataAfter());
- break;
- case DELETE:
- LOG.debug("Data was Deleted {}", rootNode.getIdentifier());
- ownershipCandidate.onNodeDeleted(TopologyUtil.getNodeId(rootNode.getIdentifier()));
- }
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.util.messages;
-
-import akka.actor.Address;
-import java.io.Serializable;
-
-public class CustomIdentifyMessage implements Serializable {
- private static final long serialVersionUID = 1L;
-
- private final Address address;
-
- public CustomIdentifyMessage(final Address addressFrom) {
- address = addressFrom;
- }
-
- public Address getAddress() {
- return address;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.util.messages;
-
-import akka.actor.Address;
-
-// Marker message, that signals that actor should not reply to this one
-public class CustomIdentifyMessageReply extends CustomIdentifyMessage {
- private static final long serialVersionUID = 1L;
-
- public CustomIdentifyMessageReply(final Address addressFrom) {
- super(addressFrom);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.util.messages;
-
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeDataInput;
-import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeDataOutput;
-import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeInputOutput;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
-import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
-
-public class NormalizedNodeMessage implements Externalizable{
- private static final long serialVersionUID = 1L;
-
- private YangInstanceIdentifier identifier = null;
- private NormalizedNode<?, ?> node = null;
-
- public NormalizedNodeMessage() {
-
- }
-
- public NormalizedNodeMessage(YangInstanceIdentifier identifier, NormalizedNode<?, ?> node) {
- this.identifier = identifier;
- this.node = node;
- }
-
- public YangInstanceIdentifier getIdentifier() {
- return identifier;
- }
-
- public NormalizedNode<?, ?> getNode() {
- return node;
- }
-
- @Override
- public void writeExternal(final ObjectOutput out) throws IOException {
- final NormalizedNodeDataOutput dataOutput = NormalizedNodeInputOutput.newDataOutput(out);
- final NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter((NormalizedNodeStreamWriter) dataOutput);
-
- dataOutput.writeYangInstanceIdentifier(identifier);
- normalizedNodeWriter.write(node);
- }
-
- @Override
- public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
- final NormalizedNodeDataInput dataInput = NormalizedNodeInputOutput.newDataInput(in);
-
- identifier = dataInput.readYangInstanceIdentifier();
- node = dataInput.readNormalizedNode();
- }
-}
<artifactId>aaa-authn-odl-plugin</artifactId>
<version>${project.version}</version>
</dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>abstract-topology</artifactId>
- <version>${project.version}</version>
- </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-config-dispatcher</artifactId>
<artifactId>netconf-util</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-util</artifactId>
+ <version>${project.version}</version>
+ <classifier>config</classifier>
+ <type>cfg</type>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-mdsal-config</artifactId>
<classifier>config</classifier>
<type>xml</type>
</dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>netconf-topology-config</artifactId>
- <version>${project.version}</version>
- <classifier>clustered-config</classifier>
- <type>xml</type>
- </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>yanglib-config</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-topology-singleton</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-client</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
</dependencies>
<build>
</execution>
</executions>
</plugin>
- <plugin>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-maven-plugin</artifactId>
- </plugin>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ </plugin>
</plugins>
</build>
*/
package org.opendaylight.netconf.ssh.osgi;
-import com.google.common.base.Optional;
import io.netty.channel.local.LocalAddress;
import io.netty.channel.nio.NioEventLoopGroup;
import java.io.IOException;
import org.opendaylight.netconf.ssh.SshProxyServer;
import org.opendaylight.netconf.ssh.SshProxyServerConfigurationBuilder;
import org.opendaylight.netconf.util.osgi.NetconfConfigUtil;
-import org.opendaylight.netconf.util.osgi.NetconfConfigUtil.InfixProp;
+import org.opendaylight.netconf.util.osgi.NetconfConfiguration;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
}
private SshProxyServer startSSHServer(final BundleContext bundleContext) throws IOException {
- final Optional<InetSocketAddress> maybeSshSocketAddress = NetconfConfigUtil.extractNetconfServerAddress(bundleContext, InfixProp.ssh);
- if (!maybeSshSocketAddress.isPresent()) {
- LOG.warn("SSH bridge not configured. Using default value {}", NetconfConfigUtil.DEFAULT_SSH_SERVER_ADRESS);
- }
- final InetSocketAddress sshSocketAddress = maybeSshSocketAddress
- .or(NetconfConfigUtil.DEFAULT_SSH_SERVER_ADRESS);
- LOG.info("Starting netconf SSH bridge at {}", sshSocketAddress);
+ final NetconfConfiguration netconfConfiguration = NetconfConfigUtil.getNetconfConfigurationService(bundleContext).
+ orElseThrow(() -> new IllegalStateException("Configuration for SSH not found."));
- final LocalAddress localAddress = NetconfConfigUtil.getNetconfLocalAddress();
+ final InetSocketAddress sshSocketAddress = netconfConfiguration.getSshServerAddress();
+ LOG.info("Starting netconf SSH server at {}", sshSocketAddress);
+ final LocalAddress localAddress = NetconfConfigUtil.getNetconfLocalAddress();
authProviderTracker = new AuthProviderTracker(bundleContext);
- final Optional<String> maybePath = NetconfConfigUtil.getPrivateKeyPath(bundleContext);
- if(!maybePath.isPresent()) {
- LOG.warn("Private key path not configured. Using default value {}",
- NetconfConfigUtil.DEFAULT_PRIVATE_KEY_PATH);
- }
- final String path = maybePath.or(NetconfConfigUtil.DEFAULT_PRIVATE_KEY_PATH);
- LOG.trace("Starting netconf SSH bridge with path to ssh private key {}", path);
+ final String path = netconfConfiguration.getPrivateKeyPath();
+ LOG.trace("Starting netconf SSH server with path to ssh private key {}", path);
final SshProxyServer sshProxyServer = new SshProxyServer(minaTimerExecutor, clientGroup, nioExecutor);
sshProxyServer.bind(
.createSshProxyServerConfiguration());
return sshProxyServer;
}
-
}
<artifactId>mockito-configuration</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
</dependencies>
<build>
package org.opendaylight.netconf.tcp.osgi;
-import com.google.common.base.Optional;
import java.net.InetSocketAddress;
import org.opendaylight.netconf.tcp.netty.ProxyServer;
import org.opendaylight.netconf.util.osgi.NetconfConfigUtil;
import org.opendaylight.netconf.util.osgi.NetconfConfigUtil.InfixProp;
+import org.opendaylight.netconf.util.osgi.NetconfConfiguration;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
@Override
public void start(BundleContext context) {
- final Optional<InetSocketAddress> maybeAddress = NetconfConfigUtil.extractNetconfServerAddress(context, InfixProp.tcp);
- if (maybeAddress.isPresent() == false) {
- LOG.warn("Netconf tcp server is not configured. Using default value {}",
- NetconfConfigUtil.DEFAULT_TCP_SERVER_ADRESS);
- }
+ final NetconfConfiguration netconfConfiguration = NetconfConfigUtil.getNetconfConfigurationService(context).
+ orElseThrow(() -> new IllegalStateException("Configuration for TCP not found."));
- InetSocketAddress address = maybeAddress.or(NetconfConfigUtil.DEFAULT_TCP_SERVER_ADRESS);
+ final InetSocketAddress address = netconfConfiguration.getTcpServerAddress();
if (address.getAddress().isAnyLocalAddress()) {
LOG.warn("Unprotected netconf TCP address is configured to ANY local address. This is a security risk. Consider changing {} to 127.0.0.1",
<type>xml</type>
<classifier>config</classifier>
</artifact>
- <artifact>
- <file>${project.build.directory}/classes/initial/02-clustered-netconf-topology.xml</file>
- <type>xml</type>
- <classifier>clustered-config</classifier>
- </artifact>
</artifacts>
</configuration>
</execution>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<!--
- Copyright (c) 2015 Cisco Systems, Inc. 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
--->
-<snapshot>
- <configuration>
- <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
- <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology">prefix:clustered-netconf-topology-impl</type>
- <name>clustered-netconf-topology</name>
- <topology-id xmlns="urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology">topology-netconf</topology-id>
- <event-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology">
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-event-executor</type>
- <name>global-event-executor</name>
- </event-executor>
- <binding-registry xmlns="urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology">
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-broker-osgi-registry</type>
- <name>binding-osgi-broker</name>
- </binding-registry>
- <dom-registry xmlns="urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology">
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
- <name>dom-broker</name>
- </dom-registry>
- <client-dispatcher xmlns="urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology">
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf">prefix:netconf-client-dispatcher</type>
- <name>global-netconf-dispatcher</name>
- </client-dispatcher>
- <processing-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology">
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:threadpool">prefix:threadpool</type>
- <name>global-netconf-processing-executor</name>
- </processing-executor>
- <keepalive-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology">
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:threadpool">prefix:scheduled-threadpool</type>
- <name>global-netconf-ssh-scheduled-executor</name>
- </keepalive-executor>
- <shared-schema-repository xmlns="urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology">
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:topology:shared:schema:repository">prefix:shared-schema-repository</type>
- <name>default-shared-schema-repository</name>
- </shared-schema-repository>
- <entity-ownership-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology">
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">prefix:entity-ownership-service</type>
- <name>entity-ownership-service</name>
- </entity-ownership-service>
- <actor-system-provider-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology">
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:actor-system-provider:service">prefix:actor-system-provider-service</type>
- <name>actor-system-provider</name>
- </actor-system-provider-service>
- </module>
- </modules>
-
- <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <service>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:topology">prefix:netconf-topology</type>
- <instance>
- <name>clustered-netconf-topology</name>
- <provider>/modules/module[type='clustered-netconf-topology-impl'][name='clustered-netconf-topology']</provider>
- </instance>
- </service>
- </services>
- </data>
- </configuration>
- <required-capabilities>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:topology?module=netconf-topology&revision=2015-07-27</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology?module=clustered-netconf-topology&revision=2015-11-04</capability>
- <capability>
- urn:opendaylight:params:xml:ns:yang:controller:config:legacy-entity-ownership-service-provider?module=opendaylight-legacy-entity-ownership-service-provider&revision=2016-02-26
- </capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:actor-system-provider:service?module=actor-system-provider-service&revision=2015-10-05</capability>
- </required-capabilities>
-</snapshot>
\ No newline at end of file
<modelVersion>4.0.0</modelVersion>
<parent>
- <groupId>org.opendaylight.odlparent</groupId>
- <artifactId>bundle-parent</artifactId>
- <version>1.8.0-SNAPSHOT</version>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-parent</artifactId>
+ <version>0.6.0-SNAPSHOT</version>
<relativePath/>
</parent>
<groupId>org.opendaylight.netconf</groupId>
- <artifactId>abstract-topology</artifactId>
+ <artifactId>netconf-topology-singleton</artifactId>
<version>1.2.0-SNAPSHOT</version>
+ <name>${project.artifactId}</name>
<packaging>bundle</packaging>
<dependencyManagement>
<type>pom</type>
<scope>import</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>mdsal-artifacts</artifactId>
+ <version>1.5.0-SNAPSHOT</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
- <properties>
- </properties>
-
<dependencies>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>mdsal-netconf-notification</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.mdsal.model</groupId>
<artifactId>ietf-topology</artifactId>
</dependency>
<dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-common-api</artifactId>
+ <groupId>com.typesafe.akka</groupId>
+ <artifactId>akka-actor_2.11</artifactId>
</dependency>
<dependency>
- <groupId>${project.groupId}</groupId>
+ <groupId>org.opendaylight.netconf</groupId>
<artifactId>sal-netconf-connector</artifactId>
</dependency>
<dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-api</artifactId>
+ <groupId>com.typesafe.akka</groupId>
+ <artifactId>akka-cluster_2.11</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-clustering-commons</artifactId>
</dependency>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-library</artifactId>
- </dependency>
- <dependency>
- <groupId>com.typesafe.akka</groupId>
- <artifactId>akka-actor_${scala.version}</artifactId>
- </dependency>
- <dependency>
- <groupId>com.typesafe.akka</groupId>
- <artifactId>akka-remote_${scala.version}</artifactId>
- </dependency>
- <dependency>
- <groupId>com.typesafe.akka</groupId>
- <artifactId>akka-cluster_${scala.version}</artifactId>
- </dependency>
- <dependency>
- <groupId>com.typesafe.akka</groupId>
- <artifactId>akka-osgi_${scala.version}</artifactId>
- </dependency>
- <dependency>
- <groupId>com.typesafe</groupId>
- <artifactId>config</artifactId>
- </dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
- <groupId>com.jayway.awaitility</groupId>
- <artifactId>awaitility</artifactId>
- <version>1.6.5</version>
+ <groupId>com.typesafe.akka</groupId>
+ <artifactId>akka-testkit_2.11</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-distributed-datastore</artifactId>
+ </dependency>
</dependencies>
-</project>
+
+</project>
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.api;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netconf.topology.singleton.messages.NormalizedNodeMessage;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import scala.concurrent.Future;
+
+/**
+ * Provides API for all operations of read and write transactions
+ */
+public interface NetconfDOMTransaction {
+
+ /**
+ * Read data from particular data-store
+ * @param store data-store type
+ * @param path unique identifier of a particular node instance in the data tree
+ * @return result as future
+ */
+ Future<Optional<NormalizedNodeMessage>> read(LogicalDatastoreType store, YangInstanceIdentifier path);
+
+ /**
+ * Test existence of node in certain data-store
+ * @param store data-store type
+ * @param path unique identifier of a particular node instance in the data tree
+ * @return result as future
+ */
+ Future<Boolean> exists(LogicalDatastoreType store, YangInstanceIdentifier path);
+
+ /**
+ * Put data to particular data-store
+ * @param store data-store type
+ * @param data data for inserting included in NormalizedNodeMessage object
+ */
+ void put(LogicalDatastoreType store, NormalizedNodeMessage data);
+
+ /**
+ * Merge data with existing node in particular data-store
+ * @param store data-store type
+ * @param data data for merging included in NormalizedNodeMessage object
+ */
+ void merge(LogicalDatastoreType store, NormalizedNodeMessage data);
+
+ /**
+ * Delete node in particular data-store in path
+ * @param store data-store type
+ * @param path unique identifier of a particular node instance in the data tree
+ */
+ void delete(LogicalDatastoreType store, YangInstanceIdentifier path);
+
+ /**
+ * Cancel operation
+ * @return success or not
+ */
+ boolean cancel();
+
+ /**
+ * Commit opened transaction.
+ * @return void or raised exception
+ */
+ Future<Void> submit();
+}
/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.pipeline.tx;
+package org.opendaylight.netconf.topology.singleton.api;
-public interface NetconfDeviceDataBrokerProxy {
+/**
+ * Provides API for advertising services for blue print service
+ */
+public interface NetconfTopologySingletonService {
}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.api;
+
+import akka.actor.ActorRef;
+
+/**
+ * Provides API for connection odl (master) with device
+ */
+public interface RemoteDeviceConnector {
+
+ /**
+ * Create device communicator and open device connection
+ * @param masterActorRef master actor reference
+ */
+ void startRemoteDeviceConnection(ActorRef masterActorRef);
+
+ /**
+ * Stop device communicator
+ */
+ void stopRemoteDeviceConnection();
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.api;
+
+import akka.actor.ActorRef;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netconf.topology.singleton.messages.NormalizedNodeMessage;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+/**
+ * Provides API for remote calling operations of transactions. Slave sends message of particular
+ * operation to master and master performs it.
+ */
+public interface RemoteOperationTxProcessor {
+
+ /**
+ * Delete node in particular data-store in path
+ * @param store data-store type
+ * @param path unique identifier of a particular node instance in the data tree
+ */
+ void doDelete(LogicalDatastoreType store, YangInstanceIdentifier path);
+
+ /**
+ * Commit opened transaction.
+ * @param recipient recipient of submit result
+ * @param sender sender of submit result
+ */
+ void doSubmit(ActorRef recipient, ActorRef sender);
+
+ /**
+ * Cancel operation
+ * @param recipient recipient of cancel result
+ * @param sender sender of cancel result
+ */
+ void doCancel(ActorRef recipient, ActorRef sender);
+
+ /**
+ * Put data to particular data-store
+ * @param store data-store type
+ * @param data data for inserting included in NormalizedNodeMessage object
+ */
+ void doPut(LogicalDatastoreType store, NormalizedNodeMessage data);
+
+ /**
+ * Merge data with existing node in particular data-store
+ * @param store data-store type
+ * @param data data for merging included in NormalizedNodeMessage object
+ */
+ void doMerge(LogicalDatastoreType store, NormalizedNodeMessage data);
+
+ /**
+ * Read data from particular data-store
+ * @param store data-store type
+ * @param path unique identifier of a particular node instance in the data tree
+ * @param recipient recipient of read result
+ * @param sender sender of read result
+ */
+ void doRead(LogicalDatastoreType store, YangInstanceIdentifier path, ActorRef recipient, ActorRef sender);
+
+ /**
+ * Test existence of node in certain data-store
+ * @param store data-store type
+ * @param path unique identifier of a particular node instance in the data tree
+ * @param recipient recipient of exists result
+ * @param sender sender of exists result
+ */
+ void doExists(LogicalDatastoreType store, YangInstanceIdentifier path, ActorRef recipient, ActorRef sender);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.cluster.Cluster;
+import akka.dispatch.OnComplete;
+import akka.pattern.Patterns;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+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.NetconfDeviceNotificationService;
+import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalProvider;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.api.NetconfDOMTransaction;
+import org.opendaylight.netconf.topology.singleton.impl.tx.NetconfMasterDOMTransaction;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
+import org.opendaylight.netconf.topology.singleton.messages.CreateInitialMasterActorData;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.concurrent.Future;
+
+class MasterSalFacade implements AutoCloseable, RemoteDeviceHandler<NetconfSessionPreferences> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MasterSalFacade.class);
+
+ private final RemoteDeviceId id;
+
+ private SchemaContext remoteSchemaContext = null;
+ private NetconfSessionPreferences netconfSessionPreferences = null;
+ private DOMRpcService deviceRpc = null;
+ private final NetconfDeviceSalProvider salProvider;
+
+ private final ActorRef masterActorRef;
+ private final ActorSystem actorSystem;
+ private DOMDataBroker deviceDataBroker = null;
+
+ MasterSalFacade(final RemoteDeviceId id,
+ final Broker domBroker,
+ final BindingAwareBroker bindingBroker,
+ final ActorSystem actorSystem,
+ final ActorRef masterActorRef) {
+ this.id = id;
+ this.salProvider = new NetconfDeviceSalProvider(id);
+ this.actorSystem = actorSystem;
+ this.masterActorRef = masterActorRef;
+
+ registerToSal(domBroker, bindingBroker);
+ }
+
+ private void registerToSal(final Broker domRegistryDependency, final BindingAwareBroker bindingBroker) {
+ // TODO: remove use of provider, there is possible directly create mount instance and
+ // TODO: NetconfDeviceTopologyAdapter in constructor = less complexity
+
+ domRegistryDependency.registerProvider(salProvider);
+ bindingBroker.registerProvider(salProvider);
+ }
+
+ @Override
+ public void onDeviceConnected(final SchemaContext remoteSchemaContext,
+ final NetconfSessionPreferences netconfSessionPreferences,
+ final DOMRpcService deviceRpc) {
+ this.remoteSchemaContext = remoteSchemaContext;
+ this.netconfSessionPreferences = netconfSessionPreferences;
+ this.deviceRpc = deviceRpc;
+
+ registerMasterMountPoint();
+
+ sendInitialDataToActor().onComplete(new OnComplete<Object>() {
+ @Override
+ public void onComplete(final Throwable failure, final Object success) throws Throwable {
+ if (failure == null) {
+ updateDeviceData();
+ return;
+ }
+ throw failure;
+ }
+ }, actorSystem.dispatcher());
+
+ }
+
+ @Override
+ public void onDeviceDisconnected() {
+ salProvider.getTopologyDatastoreAdapter().updateDeviceData(false, new NetconfDeviceCapabilities());
+ unregisterMasterMountPoint();
+ }
+
+ @Override
+ public void onDeviceFailed(final Throwable throwable) {
+ salProvider.getTopologyDatastoreAdapter().setDeviceAsFailed(throwable);
+ unregisterMasterMountPoint();
+ }
+
+ @Override
+ public void onNotification(final DOMNotification domNotification) {
+ salProvider.getMountInstance().publish(domNotification);
+ }
+
+ @Override
+ public void close() {
+ unregisterMasterMountPoint();
+ closeGracefully(salProvider);
+ }
+
+ private void registerMasterMountPoint() {
+ Preconditions.checkNotNull(id);
+ Preconditions.checkNotNull(remoteSchemaContext,
+ "Device has no remote schema context yet. Probably not fully connected.");
+ Preconditions.checkNotNull(netconfSessionPreferences,
+ "Device has no capabilities yet. Probably not fully connected.");
+
+ final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
+
+ LOG.info("{}: Creating master data broker for device", id);
+
+ final NetconfDOMTransaction masterDOMTransactions =
+ new NetconfMasterDOMTransaction(id, remoteSchemaContext, deviceRpc, netconfSessionPreferences);
+ deviceDataBroker =
+ new NetconfDOMDataBroker(actorSystem, id, masterDOMTransactions);
+ salProvider.getMountInstance()
+ .onTopologyDeviceConnected(remoteSchemaContext, deviceDataBroker, deviceRpc, notificationService);
+ }
+
+ private Future<Object> sendInitialDataToActor() {
+ final List<SourceIdentifier> sourceIdentifiers =
+ remoteSchemaContext.getAllModuleIdentifiers().stream().map(mi ->
+ RevisionSourceIdentifier.create(mi.getName(),
+ (SimpleDateFormatUtil.DEFAULT_DATE_REV == mi.getRevision() ? Optional.<String>absent() :
+ Optional.of(SimpleDateFormatUtil.getRevisionFormat().format(mi.getRevision())))))
+ .collect(Collectors.toList());
+
+ // send initial data to master actor and create actor for providing it
+ return Patterns.ask(masterActorRef, new CreateInitialMasterActorData(deviceDataBroker, sourceIdentifiers),
+ NetconfTopologyUtils.TIMEOUT);
+ }
+
+ private void updateDeviceData() {
+ Cluster cluster = Cluster.get(actorSystem);
+ salProvider.getTopologyDatastoreAdapter().updateClusteredDeviceData(true, cluster.selfAddress().toString(),
+ netconfSessionPreferences.getNetconfDeviceCapabilities());
+ }
+
+ private void unregisterMasterMountPoint() {
+ salProvider.getMountInstance().onTopologyDeviceDisconnected();
+ }
+
+ private void closeGracefully(final AutoCloseable resource) {
+ if (resource != null) {
+ try {
+ resource.close();
+ } catch (final Exception e) {
+ LOG.error("{}: Ignoring exception while closing {}", id, resource, e);
+ }
+ }
+ }
+
+}
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.netconf.topology.pipeline;
+package org.opendaylight.netconf.topology.singleton.impl;
import akka.actor.ActorSystem;
import java.util.Collections;
import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
import org.opendaylight.netconf.sal.connect.netconf.sal.tx.ReadWriteTx;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.netconf.topology.pipeline.tx.ProxyReadOnlyTransaction;
-import org.opendaylight.netconf.topology.pipeline.tx.ProxyWriteOnlyTransaction;
+import org.opendaylight.netconf.topology.singleton.api.NetconfDOMTransaction;
+import org.opendaylight.netconf.topology.singleton.impl.tx.NetconfReadOnlyTransaction;
+import org.opendaylight.netconf.topology.singleton.impl.tx.NetconfWriteOnlyTransaction;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-public class NetconfDeviceSlaveDataBroker implements DOMDataBroker{
+public class NetconfDOMDataBroker implements DOMDataBroker {
private final RemoteDeviceId id;
- private final ProxyNetconfDeviceDataBroker masterDataBroker;
+ private final NetconfDOMTransaction masterDataBroker;
private final ActorSystem actorSystem;
- public NetconfDeviceSlaveDataBroker(final ActorSystem actorSystem, final RemoteDeviceId id, final ProxyNetconfDeviceDataBroker masterDataBroker) {
+ public NetconfDOMDataBroker(final ActorSystem actorSystem, final RemoteDeviceId id,
+ final NetconfDOMTransaction masterDataBroker) {
this.id = id;
this.masterDataBroker = masterDataBroker;
this.actorSystem = actorSystem;
@Override
public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
- return new ProxyReadOnlyTransaction(actorSystem, id, masterDataBroker);
+ return new NetconfReadOnlyTransaction(id, actorSystem, masterDataBroker);
}
@Override
public DOMDataReadWriteTransaction newReadWriteTransaction() {
- return new ReadWriteTx(new ProxyReadOnlyTransaction(actorSystem, id, masterDataBroker), new ProxyWriteOnlyTransaction(actorSystem, masterDataBroker));
+ return new ReadWriteTx(new NetconfReadOnlyTransaction(id, actorSystem, masterDataBroker),
+ new NetconfWriteOnlyTransaction(id, actorSystem, masterDataBroker));
}
@Override
public DOMDataWriteTransaction newWriteOnlyTransaction() {
- return new ProxyWriteOnlyTransaction(actorSystem, masterDataBroker);
+ return new NetconfWriteOnlyTransaction(id, actorSystem, masterDataBroker);
}
@Override
- public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(LogicalDatastoreType store, YangInstanceIdentifier path, DOMDataChangeListener listener, DataChangeScope triggeringScope) {
+ public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(
+ LogicalDatastoreType store, YangInstanceIdentifier path, DOMDataChangeListener listener,
+ DataChangeScope triggeringScope) {
throw new UnsupportedOperationException(id + ": Data change listeners not supported for netconf mount point");
}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl;
+
+import akka.actor.ActorRef;
+import akka.actor.PoisonPill;
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.api.NetconfTopologySingletonService;
+import org.opendaylight.netconf.topology.singleton.impl.actors.NetconfNodeActor;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
+import org.opendaylight.netconf.topology.singleton.messages.AskForMasterMountPoint;
+import org.opendaylight.netconf.topology.singleton.messages.UnregisterSlaveMountPoint;
+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.NetconfNodeConnectionStatus;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Managing and reacting on data tree changes in specific netconf node when master writes status to the operational
+ * data store (e.g. handling lifecycle of slave mount point).
+ */
+class NetconfNodeManager
+ implements ClusteredDataTreeChangeListener<Node>, NetconfTopologySingletonService, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeManager.class);
+
+ private NetconfTopologySetup setup;
+ private ListenerRegistration<NetconfNodeManager> dataChangeListenerRegistration;
+ private RemoteDeviceId id;
+ private final SchemaSourceRegistry schemaRegistry;
+ private final SchemaRepository schemaRepository;
+ private ActorRef slaveActorRef;
+
+ NetconfNodeManager(final NetconfTopologySetup setup,
+ final RemoteDeviceId id, final SchemaSourceRegistry schemaRegistry,
+ final SchemaRepository schemaRepository) {
+ this.setup = setup;
+ this.id = id;
+ this.schemaRegistry = schemaRegistry;
+ this.schemaRepository = schemaRepository;
+ }
+
+ @Override
+ public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<Node>> changes) {
+ for (final DataTreeModification<Node> change : changes) {
+ final DataObjectModification<Node> rootNode = change.getRootNode();
+ final NodeId nodeId = NetconfTopologyUtils.getNodeId(rootNode.getIdentifier());
+ switch (rootNode.getModificationType()) {
+ case SUBTREE_MODIFIED:
+ LOG.debug("{}: Operational for node {} updated. Trying to register slave mount point", id, nodeId);
+ handleSlaveMountPoint(rootNode);
+ break;
+ case WRITE:
+ if (rootNode.getDataBefore() != null) {
+ LOG.debug("{}: Operational for node {} rewrited. Trying to register slave mount point", id, nodeId);
+ } else {
+ LOG.debug("{}: Operational for node {} created. Trying to register slave mount point", id, nodeId);
+ }
+ handleSlaveMountPoint(rootNode);
+ break;
+ case DELETE:
+ LOG.debug("{}: Operational for node {} deleted. Trying to remove slave mount point", id, nodeId);
+ closeActor();
+ break;
+ default:
+ LOG.debug("{}: Uknown operation for node: {}", id, nodeId);
+ }
+ }
+ }
+
+ @Override
+ public void close() {
+ closeActor();
+
+ if (dataChangeListenerRegistration != null) {
+ dataChangeListenerRegistration.close();
+ dataChangeListenerRegistration = null;
+ }
+ }
+
+ private void closeActor() {
+ if (slaveActorRef != null) {
+ slaveActorRef.tell(new UnregisterSlaveMountPoint(), ActorRef.noSender());
+ slaveActorRef.tell(PoisonPill.getInstance(), ActorRef.noSender());
+ slaveActorRef = null;
+ }
+ }
+
+ void registerDataTreeChangeListener(final String topologyId, final NodeKey key) {
+ LOG.debug("{}: Registering data tree change listener on node {}", id, key);
+ dataChangeListenerRegistration = setup.getDataBroker().registerDataTreeChangeListener(
+ new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
+ NetconfTopologyUtils.createTopologyNodeListPath(key, topologyId)), this);
+ }
+
+ private void handleSlaveMountPoint(final DataObjectModification<Node> rootNode) {
+ @SuppressWarnings("ConstantConditions")
+ final NetconfNode netconfNodeAfter = rootNode.getDataAfter().getAugmentation(NetconfNode.class);
+
+ if (NetconfNodeConnectionStatus.ConnectionStatus.Connected.equals(netconfNodeAfter.getConnectionStatus())) {
+ createActorRef();
+ final String masterAddress = netconfNodeAfter.getClusteredConnectionStatus().getNetconfMasterNode();
+ final String path = NetconfTopologyUtils.createActorPath(masterAddress,
+ NetconfTopologyUtils.createMasterActorName(id.getName(),
+ netconfNodeAfter.getClusteredConnectionStatus().getNetconfMasterNode()));
+ setup.getActorSystem().actorSelection(path).tell(new AskForMasterMountPoint(), slaveActorRef);
+ } else { ;
+ closeActor();
+ }
+ }
+
+ private void createActorRef() {
+ if (slaveActorRef == null) {
+ slaveActorRef = setup.getActorSystem().actorOf(NetconfNodeActor.props(setup, id, schemaRegistry,
+ schemaRepository), id.getName());
+ }
+ }
+
+ void refreshDevice(final NetconfTopologySetup netconfTopologyDeviceSetup, final RemoteDeviceId remoteDeviceId) {
+ setup = netconfTopologyDeviceSetup;
+ id = remoteDeviceId;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl;
+
+import static org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY;
+
+import akka.actor.ActorRef;
+import akka.cluster.Cluster;
+import akka.dispatch.OnComplete;
+import akka.pattern.Patterns;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.api.RemoteDeviceConnector;
+import org.opendaylight.netconf.topology.singleton.impl.actors.NetconfNodeActor;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
+import org.opendaylight.netconf.topology.singleton.messages.RefreshSetupMasterActorData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.concurrent.Future;
+
+class NetconfTopologyContext implements ClusterSingletonService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyContext.class);
+
+ private final ServiceGroupIdentifier serviceGroupIdent;
+ private NetconfTopologySetup netconfTopologyDeviceSetup;
+ private RemoteDeviceId remoteDeviceId;
+ private RemoteDeviceConnector remoteDeviceConnector;
+ private NetconfNodeManager netconfNodeManager;
+ private boolean finalClose = false;
+ private boolean isMaster;
+
+ private ActorRef masterActorRef;
+
+ NetconfTopologyContext(final NetconfTopologySetup netconfTopologyDeviceSetup,
+ final ServiceGroupIdentifier serviceGroupIdent) {
+ this.netconfTopologyDeviceSetup = Preconditions.checkNotNull(netconfTopologyDeviceSetup);
+ this.serviceGroupIdent = serviceGroupIdent;
+
+ remoteDeviceId = NetconfTopologyUtils.createRemoteDeviceId(netconfTopologyDeviceSetup.getNode().getNodeId(),
+ netconfTopologyDeviceSetup.getNode().getAugmentation(NetconfNode.class));
+
+ remoteDeviceConnector = new RemoteDeviceConnectorImpl(netconfTopologyDeviceSetup, remoteDeviceId);
+
+ netconfNodeManager = createNodeDeviceManager();
+
+ }
+
+ @Override
+ public void instantiateServiceInstance() {
+ LOG.info("Master was selected: {}", remoteDeviceId.getHost().getIpAddress());
+
+ isMaster = true;
+
+ // master should not listen on netconf-node operational datastore
+ if (netconfNodeManager != null) {
+ netconfNodeManager.close();
+ netconfNodeManager = null;
+ }
+
+ if (!finalClose) {
+ final String masterAddress = Cluster.get(netconfTopologyDeviceSetup.getActorSystem()).selfAddress().toString();
+ masterActorRef = netconfTopologyDeviceSetup.getActorSystem().actorOf(NetconfNodeActor.props(
+ netconfTopologyDeviceSetup, remoteDeviceId, DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY),
+ NetconfTopologyUtils.createMasterActorName(remoteDeviceId.getName(), masterAddress));
+
+ remoteDeviceConnector.startRemoteDeviceConnection(masterActorRef);
+ }
+
+ }
+
+ // called when master is down/changed to slave
+ @Override
+ public ListenableFuture<Void> closeServiceInstance() {
+
+ if (!finalClose) {
+ // in case that master changes role to slave, new NodeDeviceManager must be created and listener registered
+ netconfNodeManager = createNodeDeviceManager();
+ }
+ if (masterActorRef != null) {
+ netconfTopologyDeviceSetup.getActorSystem().stop(masterActorRef);
+ masterActorRef = null;
+ }
+ if (remoteDeviceConnector != null) {
+ remoteDeviceConnector.stopRemoteDeviceConnection();
+ }
+
+ return Futures.immediateCheckedFuture(null);
+ }
+
+ @Override
+ public ServiceGroupIdentifier getIdentifier() {
+ return serviceGroupIdent;
+ }
+
+ private NetconfNodeManager createNodeDeviceManager() {
+ final NetconfNodeManager ndm =
+ new NetconfNodeManager(netconfTopologyDeviceSetup, remoteDeviceId, DEFAULT_SCHEMA_REPOSITORY,
+ DEFAULT_SCHEMA_REPOSITORY);
+ ndm.registerDataTreeChangeListener(netconfTopologyDeviceSetup.getTopologyId(),
+ netconfTopologyDeviceSetup.getNode().getKey());
+
+ return ndm;
+ }
+
+ void closeFinal() throws Exception {
+ finalClose = true;
+
+ if (netconfNodeManager != null) {
+ netconfNodeManager.close();
+ }
+
+ if (remoteDeviceConnector != null) {
+ remoteDeviceConnector.stopRemoteDeviceConnection();
+ }
+
+ if (masterActorRef != null) {
+ netconfTopologyDeviceSetup.getActorSystem().stop(masterActorRef);
+ masterActorRef = null;
+ }
+ }
+
+ /**
+ * If configuration data was changed
+ * @param setup new setup
+ */
+ void refresh(@Nonnull final NetconfTopologySetup setup) {
+ netconfTopologyDeviceSetup = Preconditions.checkNotNull(setup);
+ remoteDeviceId = NetconfTopologyUtils.createRemoteDeviceId(netconfTopologyDeviceSetup.getNode().getNodeId(),
+ netconfTopologyDeviceSetup.getNode().getAugmentation(NetconfNode.class));
+
+ if (isMaster) {
+ remoteDeviceConnector.stopRemoteDeviceConnection();
+ }
+ if (!isMaster) {
+ netconfNodeManager.refreshDevice(netconfTopologyDeviceSetup, remoteDeviceId);
+ }
+ remoteDeviceConnector = new RemoteDeviceConnectorImpl(netconfTopologyDeviceSetup, remoteDeviceId);
+
+ if (isMaster) {
+ final Future<Object> future = Patterns.ask(masterActorRef, new RefreshSetupMasterActorData(
+ netconfTopologyDeviceSetup, remoteDeviceId), NetconfTopologyUtils.TIMEOUT);
+
+ future.onComplete(new OnComplete<Object>() {
+ @Override
+ public void onComplete(final Throwable failure, final Object success) throws Throwable {
+ if (failure != null) {
+ LOG.error("Failed to refresh master actor data: {}", failure);
+ return;
+ }
+ remoteDeviceConnector.startRemoteDeviceConnection(masterActorRef);
+ }
+ }, netconfTopologyDeviceSetup.getActorSystem().dispatcher());
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl;
+
+import akka.actor.ActorSystem;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import io.netty.util.concurrent.EventExecutor;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.cluster.ActorSystemProvider;
+import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
+import org.opendaylight.controller.config.threadpool.ThreadPool;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
+import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.topology.singleton.api.NetconfTopologySingletonService;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup.NetconfTopologySetupBuilder;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfTopologyManager
+ implements ClusteredDataTreeChangeListener<Node>, NetconfTopologySingletonService, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyManager.class);
+
+ private final Map<InstanceIdentifier<Node>, NetconfTopologyContext> contexts = new HashMap<>();
+ private final Map<InstanceIdentifier<Node>, ClusterSingletonServiceRegistration>
+ clusterRegistrations = new HashMap<>();
+
+ private ListenerRegistration<NetconfTopologyManager> dataChangeListenerRegistration;
+
+ private final DataBroker dataBroker;
+ private final RpcProviderRegistry rpcProviderRegistry;
+ private final ClusterSingletonServiceProvider clusterSingletonServiceProvider;
+ private final BindingAwareBroker bindingAwareBroker;
+ private final ScheduledThreadPool keepaliveExecutor;
+ private final ThreadPool processingExecutor;
+ private final Broker domBroker;
+ private final ActorSystem actorSystem;
+ private final EventExecutor eventExecutor;
+ private final NetconfClientDispatcher clientDispatcher;
+ private final String topologyId;
+
+ public NetconfTopologyManager(final DataBroker dataBroker, final RpcProviderRegistry rpcProviderRegistry,
+ final ClusterSingletonServiceProvider clusterSingletonServiceProvider,
+ final BindingAwareBroker bindingAwareBroker,
+ final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor,
+ final Broker domBroker, final ActorSystemProvider actorSystemProvider, final EventExecutor eventExecutor,
+ final NetconfClientDispatcher clientDispatcher, final String topologyId) {
+ this.dataBroker = Preconditions.checkNotNull(dataBroker);
+ this.rpcProviderRegistry = Preconditions.checkNotNull(rpcProviderRegistry);
+ this.clusterSingletonServiceProvider = Preconditions.checkNotNull(clusterSingletonServiceProvider);
+ this.bindingAwareBroker = Preconditions.checkNotNull(bindingAwareBroker);
+ this.keepaliveExecutor = Preconditions.checkNotNull(keepaliveExecutor);
+ this.processingExecutor = Preconditions.checkNotNull(processingExecutor);
+ this.domBroker = Preconditions.checkNotNull(domBroker);
+ this.actorSystem = Preconditions.checkNotNull(actorSystemProvider).getActorSystem();
+ this.eventExecutor = Preconditions.checkNotNull(eventExecutor);
+ this.clientDispatcher = Preconditions.checkNotNull(clientDispatcher);
+ this.topologyId = Preconditions.checkNotNull(topologyId);
+ }
+
+ // Blueprint init method
+ public void init() {
+ dataChangeListenerRegistration = registerDataTreeChangeListener(topologyId);
+ }
+
+ @Override
+ public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<Node>> changes) {
+ for (DataTreeModification<Node> change : changes) {
+ final DataObjectModification<Node> rootNode = change.getRootNode();
+ final InstanceIdentifier<Node> dataModifIdent = change.getRootPath().getRootIdentifier();
+ final NodeId nodeId = NetconfTopologyUtils.getNodeId(rootNode.getIdentifier());
+ switch (rootNode.getModificationType()) {
+ case SUBTREE_MODIFIED:
+ LOG.debug("Config for node {} updated", nodeId);
+ refreshNetconfDeviceContext(dataModifIdent, rootNode.getDataAfter());
+ break;
+ case WRITE:
+ if (contexts.containsKey(dataModifIdent)) {
+ LOG.debug("RemoteDevice{{}} was already configured, reconfiguring node...", nodeId);
+ refreshNetconfDeviceContext(dataModifIdent, rootNode.getDataAfter());
+ } else {
+ LOG.debug("Config for node {} created", nodeId);
+ startNetconfDeviceContext(dataModifIdent, rootNode.getDataAfter());
+ }
+ break;
+ case DELETE:
+ LOG.debug("Config for node {} deleted", nodeId);
+ stopNetconfDeviceContext(dataModifIdent);
+ break;
+ default:
+ LOG.warn("Unknown operation for {}.", nodeId);
+ }
+ }
+ }
+
+ private void refreshNetconfDeviceContext(InstanceIdentifier<Node> instanceIdentifier, Node node) {
+ final NetconfTopologyContext context = contexts.get(instanceIdentifier);
+ context.refresh(createSetup(instanceIdentifier, node));
+ }
+
+ private void startNetconfDeviceContext(final InstanceIdentifier<Node> instanceIdentifier, final Node node) {
+ final NetconfNode netconfNode = node.getAugmentation(NetconfNode.class);
+ Preconditions.checkNotNull(netconfNode);
+ Preconditions.checkNotNull(netconfNode.getHost());
+ Preconditions.checkNotNull(netconfNode.getHost().getIpAddress());
+
+ final ServiceGroupIdentifier serviceGroupIdent =
+ ServiceGroupIdentifier.create(instanceIdentifier.toString());
+
+ final NetconfTopologyContext newNetconfTopologyContext =
+ new NetconfTopologyContext(createSetup(instanceIdentifier, node), serviceGroupIdent);
+
+ final ClusterSingletonServiceRegistration clusterSingletonServiceRegistration =
+ clusterSingletonServiceProvider.registerClusterSingletonService(newNetconfTopologyContext);
+
+ clusterRegistrations.put(instanceIdentifier, clusterSingletonServiceRegistration);
+ contexts.put(instanceIdentifier, newNetconfTopologyContext);
+ }
+
+ private void stopNetconfDeviceContext(final InstanceIdentifier<Node> instanceIdentifier) {
+ if (contexts.containsKey(instanceIdentifier)) {
+ try {
+ clusterRegistrations.get(instanceIdentifier).close();
+ contexts.get(instanceIdentifier).closeFinal();
+ } catch (Exception e) {
+ LOG.warn("Error at closing topology context. InstanceIdentifier: " + instanceIdentifier);
+ }
+ contexts.remove(instanceIdentifier);
+ clusterRegistrations.remove(instanceIdentifier);
+ }
+ }
+
+ @Override
+ public void close() {
+ if (dataChangeListenerRegistration != null) {
+ dataChangeListenerRegistration.close();
+ dataChangeListenerRegistration = null;
+ }
+ contexts.forEach((instanceIdentifier, netconfTopologyContext) -> {
+ try {
+ netconfTopologyContext.closeFinal();
+ } catch (Exception e) {
+ LOG.error("Error at closing topology context. InstanceIdentifier: " + instanceIdentifier, e);
+ }
+ });
+ clusterRegistrations.forEach((instanceIdentifier, clusterSingletonServiceRegistration) -> {
+ try {
+ clusterSingletonServiceRegistration.close();
+ } catch (Exception e) {
+ LOG.error("Error at unregistering from cluster. InstanceIdentifier: " + instanceIdentifier, e);
+ }
+ });
+ contexts.clear();
+ clusterRegistrations.clear();
+ }
+
+ private ListenerRegistration<NetconfTopologyManager> registerDataTreeChangeListener(String topologyId) {
+ final WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+ initTopology(wtx, LogicalDatastoreType.CONFIGURATION, topologyId);
+ initTopology(wtx, LogicalDatastoreType.OPERATIONAL, topologyId);
+ Futures.addCallback(wtx.submit(), new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void result) {
+ LOG.debug("topology initialization successful");
+ }
+
+ @Override
+ public void onFailure(@Nonnull Throwable throwable) {
+ LOG.error("Unable to initialize netconf-topology, {}", throwable);
+ }
+ });
+
+ LOG.debug("Registering datastore listener");
+ return dataBroker.registerDataTreeChangeListener(
+ new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+ NetconfTopologyUtils.createTopologyListPath(topologyId).child(Node.class)), this);
+ }
+
+ private void initTopology(final WriteTransaction wtx, final LogicalDatastoreType datastoreType, String topologyId) {
+ final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
+ final InstanceIdentifier<NetworkTopology> networkTopologyId =
+ InstanceIdentifier.builder(NetworkTopology.class).build();
+ wtx.merge(datastoreType, networkTopologyId, networkTopology);
+ final Topology topology = new TopologyBuilder().setTopologyId(new TopologyId(topologyId)).build();
+ wtx.merge(datastoreType, networkTopologyId.child(Topology.class,
+ new TopologyKey(new TopologyId(topologyId))), topology);
+ }
+
+ private NetconfTopologySetup createSetup(final InstanceIdentifier<Node> instanceIdentifier, final Node node) {
+ final NetconfTopologySetupBuilder builder = NetconfTopologySetupBuilder.create()
+ .setClusterSingletonServiceProvider(clusterSingletonServiceProvider)
+ .setDataBroker(dataBroker)
+ .setInstanceIdentifier(instanceIdentifier)
+ .setRpcProviderRegistry(rpcProviderRegistry)
+ .setNode(node)
+ .setBindingAwareBroker(bindingAwareBroker)
+ .setActorSystem(actorSystem)
+ .setEventExecutor(eventExecutor)
+ .setDomBroker(domBroker)
+ .setKeepaliveExecutor(keepaliveExecutor)
+ .setProcessingExecutor(processingExecutor)
+ .setTopologyId(topologyId)
+ .setNetconfClientDispatcher(clientDispatcher);
+
+ return builder.build();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.singleton.impl;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public class ProxyDOMRpcService implements DOMRpcService {
+
+ @Nonnull
+ @Override
+ public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(@Nonnull final SchemaPath type,
+ @Nullable final NormalizedNode<?, ?> input) {
+ throw new UnsupportedOperationException("InvokeRpc: DOMRpc service not working in cluster.");
+ }
+
+ @Nonnull
+ @Override
+ public <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(
+ @Nonnull final T listener) {
+ throw new UnsupportedOperationException("RegisterRpcListener: DOMRpc service not working in cluster.");
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl;
+
+import akka.actor.ActorContext;
+import akka.actor.ActorRef;
+import akka.dispatch.Futures;
+import akka.dispatch.OnComplete;
+import akka.pattern.Patterns;
+import com.google.common.collect.Sets;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.cluster.schema.provider.RemoteYangTextSourceProvider;
+import org.opendaylight.controller.cluster.schema.provider.impl.YangTextSchemaSourceSerializationProxy;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
+import org.opendaylight.netconf.topology.singleton.messages.YangTextSchemaSourceRequest;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import scala.concurrent.Future;
+import scala.concurrent.impl.Promise;
+
+public class ProxyYangTextSourceProvider implements RemoteYangTextSourceProvider {
+
+ private final ActorRef masterRef;
+ private final ActorContext actorContext;
+
+ public ProxyYangTextSourceProvider(final ActorRef masterRef, final ActorContext actorContext) {
+ this.masterRef = masterRef;
+ this.actorContext = actorContext;
+ }
+
+ @Override
+ public Future<Set<SourceIdentifier>> getProvidedSources() {
+ // NOOP
+ return Futures.successful(Sets.newHashSet());
+ }
+
+ @Override
+ public Future<YangTextSchemaSourceSerializationProxy> getYangTextSchemaSource(
+ @Nonnull final SourceIdentifier sourceIdentifier) {
+
+ final Future<Object> scalaFuture = Patterns.ask(masterRef,
+ new YangTextSchemaSourceRequest(sourceIdentifier), NetconfTopologyUtils.TIMEOUT);
+
+ final Promise.DefaultPromise<YangTextSchemaSourceSerializationProxy> promise = new Promise.DefaultPromise<>();
+
+ scalaFuture.onComplete(new OnComplete<Object>() {
+ @Override
+ public void onComplete(final Throwable failure, final Object success) throws Throwable {
+ if (failure != null) {
+ promise.failure(failure);
+ return;
+ }
+ if (success instanceof Throwable) {
+ promise.failure((Throwable) success);
+ return;
+ }
+ promise.success((YangTextSchemaSourceSerializationProxy) success);
+ }
+ }, actorContext.dispatcher());
+
+ return promise.future();
+
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl;
+
+import akka.actor.ActorRef;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import io.netty.util.concurrent.EventExecutor;
+import java.io.File;
+import java.math.BigDecimal;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import javax.annotation.Nullable;
+import org.opendaylight.netconf.api.NetconfMessage;
+import org.opendaylight.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
+import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
+import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
+import org.opendaylight.netconf.sal.connect.api.RemoteDevice;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.netconf.LibraryModulesSchemas;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceBuilder;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfStateSchemasResolverImpl;
+import org.opendaylight.netconf.sal.connect.netconf.SchemalessNetconfDevice;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.netconf.sal.connect.netconf.listener.UserPreferences;
+import org.opendaylight.netconf.sal.connect.netconf.sal.KeepaliveSalFacade;
+import org.opendaylight.netconf.sal.connect.netconf.schema.YangLibrarySchemaYangSourceProvider;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.api.RemoteDeviceConnector;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfConnectorDTO;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
+import org.opendaylight.protocol.framework.TimedReconnectStrategy;
+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.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;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache;
+import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
+import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RemoteDeviceConnectorImpl.class);
+
+ /**
+ * Keeps track of initialized Schema resources. A Map is maintained in which the key represents the name
+ * of the schema cache directory, and the value is a corresponding <code>SchemaResourcesDTO</code>. The
+ * <code>SchemaResourcesDTO</code> is essentially a container that allows for the extraction of the
+ * <code>SchemaRegistry</code> and <code>SchemaContextFactory</code> which should be used for a particular
+ * Netconf mount. Access to <code>schemaResourcesDTOs</code> should be surrounded by appropriate
+ * synchronization locks.
+ */
+ 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 {
+ schemaResourcesDTOs.put(NetconfTopologyUtils.DEFAULT_CACHE_DIRECTORY,
+ new NetconfDevice.SchemaResourcesDTO(NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY,
+ NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY,
+ NetconfTopologyUtils.DEFAULT_SCHEMA_CONTEXT_FACTORY,
+ new NetconfStateSchemasResolverImpl()));
+ NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(NetconfTopologyUtils.DEFAULT_CACHE);
+ NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(
+ TextToASTTransformer.create(NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY,
+ NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY));
+ }
+
+ public RemoteDeviceConnectorImpl(final NetconfTopologySetup netconfTopologyDeviceSetup,
+ final RemoteDeviceId remoteDeviceId) {
+
+ this.netconfTopologyDeviceSetup = Preconditions.checkNotNull(netconfTopologyDeviceSetup);
+ this.remoteDeviceId = remoteDeviceId;
+ }
+
+ @Override
+ public void startRemoteDeviceConnection(final ActorRef deviceContextActorRef) {
+
+ final NetconfNode netconfNode = netconfTopologyDeviceSetup.getNode().getAugmentation(NetconfNode.class);
+ final NodeId nodeId = netconfTopologyDeviceSetup.getNode().getNodeId();
+ Preconditions.checkNotNull(netconfNode.getHost());
+ Preconditions.checkNotNull(netconfNode.getPort());
+ Preconditions.checkNotNull(netconfNode.isTcpOnly());
+
+ this.deviceCommunicatorDTO = createDeviceCommunicator(nodeId, netconfNode, deviceContextActorRef);
+ final NetconfDeviceCommunicator deviceCommunicator = deviceCommunicatorDTO.getCommunicator();
+ final NetconfClientSessionListener netconfClientSessionListener = deviceCommunicatorDTO.getSessionListener();
+ final NetconfReconnectingClientConfiguration clientConfig =
+ getClientConfig(netconfClientSessionListener, netconfNode);
+ final ListenableFuture<NetconfDeviceCapabilities> future = deviceCommunicator
+ .initializeRemoteConnection(netconfTopologyDeviceSetup.getNetconfClientDispatcher(), clientConfig);
+
+ Futures.addCallback(future, new FutureCallback<NetconfDeviceCapabilities>() {
+ @Override
+ public void onSuccess(NetconfDeviceCapabilities result) {
+ LOG.debug("{}: Connector started successfully", remoteDeviceId);
+ }
+
+ @Override
+ public void onFailure(@Nullable Throwable throwable) {
+ LOG.error("{}: Connector failed, {}", remoteDeviceId, throwable);
+ }
+ });
+ }
+
+ @Override
+ public void stopRemoteDeviceConnection() {
+ Preconditions.checkNotNull(deviceCommunicatorDTO, remoteDeviceId + ": Device communicator was not created.");
+ try {
+ deviceCommunicatorDTO.close();
+ } catch (Exception e) {
+ LOG.error("{}: Error at closing device communicator.", remoteDeviceId, e);
+ }
+ }
+
+ @VisibleForTesting
+ NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId, final NetconfNode node,
+ 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 Long keepaliveDelay = node.getKeepaliveDelay() == null
+ ? NetconfTopologyUtils.DEFAULT_KEEPALIVE_DELAY : node.getKeepaliveDelay();
+ final Boolean reconnectOnChangedSchema = node.isReconnectOnChangedSchema() == null
+ ? NetconfTopologyUtils.DEFAULT_RECONNECT_ON_CHANGED_SCHEMA : node.isReconnectOnChangedSchema();
+
+ RemoteDeviceHandler<NetconfSessionPreferences> salFacade = new MasterSalFacade(remoteDeviceId,
+ netconfTopologyDeviceSetup.getDomBroker(), netconfTopologyDeviceSetup.getBindingAwareBroker(),
+ netconfTopologyDeviceSetup.getActorSystem(), deviceContextActorRef);
+ if (keepaliveDelay > 0) {
+ LOG.info("{}: Adding keepalive facade.", remoteDeviceId);
+ salFacade = new KeepaliveSalFacade(remoteDeviceId, salFacade,
+ netconfTopologyDeviceSetup.getKeepaliveExecutor().getExecutor(), keepaliveDelay,
+ defaultRequestTimeoutMillis);
+ }
+
+ // pre register yang library sources as fallback schemas to schema registry
+ 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;
+ if (yangLibURL != null) {
+ if (yangLibUsername != null && yangLigPassword != null) {
+ libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL, yangLibUsername, yangLigPassword);
+ } else {
+ libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL);
+ }
+
+ for (Map.Entry<SourceIdentifier, URL> sourceIdentifierURLEntry :
+ libraryModulesSchemas.getAvailableModels().entrySet()) {
+ registeredYangLibSources
+ .add(schemaRegistry.registerSchemaSource(
+ new YangLibrarySchemaYangSourceProvider(remoteDeviceId,
+ libraryModulesSchemas.getAvailableModels()),
+ PotentialSchemaSource
+ .create(sourceIdentifierURLEntry.getKey(), YangTextSchemaSource.class,
+ PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
+ }
+ }
+ }
+
+ final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = setupSchemaCacheDTO(nodeId, node);
+ final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> device;
+ if (node.isSchemaless()) {
+ device = new SchemalessNetconfDevice(remoteDeviceId, salFacade);
+ } else {
+ device = new NetconfDeviceBuilder()
+ .setReconnectOnSchemasChange(reconnectOnChangedSchema)
+ .setSchemaResourcesDTO(schemaResourcesDTO)
+ .setGlobalProcessingExecutor(netconfTopologyDeviceSetup.getProcessingExecutor().getExecutor())
+ .setId(remoteDeviceId)
+ .setSalFacade(salFacade)
+ .build();
+ }
+
+ final Optional<NetconfSessionPreferences> userCapabilities = getUserCapabilities(node);
+ final int rpcMessageLimit =
+ node.getConcurrentRpcLimit() == null
+ ? NetconfTopologyUtils.DEFAULT_CONCURRENT_RPC_LIMIT : node.getConcurrentRpcLimit();
+
+ if (rpcMessageLimit < 1) {
+ LOG.info("{}: Concurrent rpc limit is smaller than 1, no limit will be enforced.", remoteDeviceId);
+ }
+
+ return new NetconfConnectorDTO(
+ userCapabilities.isPresent()
+ ? new NetconfDeviceCommunicator(
+ remoteDeviceId, device, new UserPreferences(userCapabilities.get(),
+ node.getYangModuleCapabilities().isOverride()), rpcMessageLimit) :
+ new NetconfDeviceCommunicator(remoteDeviceId, device, rpcMessageLimit), salFacade);
+ }
+
+ private Optional<NetconfSessionPreferences> getUserCapabilities(final NetconfNode node) {
+ if (node.getYangModuleCapabilities() == null) {
+ return Optional.empty();
+ }
+
+ final List<String> capabilities = node.getYangModuleCapabilities().getCapability();
+ if (capabilities == null || capabilities.isEmpty()) {
+ return Optional.empty();
+ }
+
+ 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());
+
+ return Optional.of(parsedOverrideCapabilities);
+ }
+
+ private NetconfDevice.SchemaResourcesDTO setupSchemaCacheDTO(final NodeId nodeId, final NetconfNode node) {
+ // Setup information related to the SchemaRegistry, SchemaResourceFactory, etc.
+ NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = null;
+ final String moduleSchemaCacheDirectory = node.getSchemaCacheDirectory();
+ // Only checks to ensure the String is not empty or null; further checks related to directory accessibility
+ // and file permissions are handled during the FilesystemSchemaSourceCache initialization.
+ if (!Strings.isNullOrEmpty(moduleSchemaCacheDirectory)) {
+ // If a custom schema cache directory is specified, create the backing DTO; otherwise, the SchemaRegistry
+ // and SchemaContextFactory remain the default values.
+ if (!moduleSchemaCacheDirectory.equals(NetconfTopologyUtils.DEFAULT_CACHE_DIRECTORY)) {
+ // Multiple modules may be created at once; synchronize to avoid issues with data consistency among
+ // threads.
+ synchronized (schemaResourcesDTOs) {
+ // Look for the cached DTO to reuse SchemaRegistry and SchemaContextFactory variables if
+ // they already exist
+ schemaResourcesDTO = schemaResourcesDTOs.get(moduleSchemaCacheDirectory);
+ if (schemaResourcesDTO == null) {
+ schemaResourcesDTO = createSchemaResourcesDTO(moduleSchemaCacheDirectory);
+ schemaResourcesDTO.getSchemaRegistry().registerSchemaSourceListener(
+ TextToASTTransformer.create((SchemaRepository) schemaResourcesDTO.getSchemaRegistry(),
+ schemaResourcesDTO.getSchemaRegistry())
+ );
+ schemaResourcesDTOs.put(moduleSchemaCacheDirectory, schemaResourcesDTO);
+ }
+ }
+ LOG.info("{} : netconf connector will use schema cache directory {} instead of {}",
+ remoteDeviceId, moduleSchemaCacheDirectory, NetconfTopologyUtils.DEFAULT_CACHE_DIRECTORY);
+ }
+ } else {
+ LOG.info("{} : using the default directory {}",
+ remoteDeviceId, NetconfTopologyUtils.QUALIFIED_DEFAULT_CACHE_DIRECTORY);
+ }
+
+ if (schemaResourcesDTO == null) {
+ schemaResourcesDTO =
+ new NetconfDevice.SchemaResourcesDTO(schemaRegistry, schemaRepository, schemaContextFactory,
+ new NetconfStateSchemasResolverImpl());
+ }
+
+ return schemaResourcesDTO;
+ }
+
+ /**
+ * Creates the backing Schema classes for a particular directory.
+ *
+ * @param moduleSchemaCacheDirectory The string directory relative to "cache"
+ * @return A DTO containing the Schema classes for the Netconf mount.
+ */
+ private NetconfDevice.SchemaResourcesDTO createSchemaResourcesDTO(final String moduleSchemaCacheDirectory) {
+ final SharedSchemaRepository repository = new SharedSchemaRepository(moduleSchemaCacheDirectory);
+ final SchemaContextFactory schemaContextFactory
+ = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+ this.schemaRegistry = repository;
+ this.schemaContextFactory = schemaContextFactory;
+
+ final FilesystemSchemaSourceCache<YangTextSchemaSource> deviceCache =
+ createDeviceFilesystemCache(moduleSchemaCacheDirectory);
+ repository.registerSchemaSourceListener(deviceCache);
+ return new NetconfDevice.SchemaResourcesDTO(repository, repository, schemaContextFactory,
+ new NetconfStateSchemasResolverImpl());
+ }
+
+ /**
+ * Creates a <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory.
+ *
+ * @param schemaCacheDirectory The custom cache directory relative to "cache"
+ * @return A <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory
+ */
+ private FilesystemSchemaSourceCache<YangTextSchemaSource> createDeviceFilesystemCache(
+ final String schemaCacheDirectory) {
+ final String relativeSchemaCacheDirectory =
+ NetconfTopologyUtils.CACHE_DIRECTORY + File.separator + schemaCacheDirectory;
+ return new FilesystemSchemaSourceCache<>(schemaRegistry, YangTextSchemaSource.class,
+ new File(relativeSchemaCacheDirectory));
+ }
+
+ //TODO: duplicate code
+ private InetSocketAddress getSocketAddress(final Host host, int port) {
+ if (host.getDomainName() != null) {
+ return new InetSocketAddress(host.getDomainName().getValue(), port);
+ } else {
+ final IpAddress ipAddress = host.getIpAddress();
+ final String ip = ipAddress.getIpv4Address() != null ? ipAddress.getIpv4Address().getValue() :
+ ipAddress.getIpv6Address().getValue();
+ return new InetSocketAddress(ip, port);
+ }
+ }
+
+ 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) {
+
+ //setup default values since default value is not supported in mdsal
+ final long clientConnectionTimeoutMillis = node.getConnectionTimeoutMillis() == null
+ ? NetconfTopologyUtils.DEFAULT_CONNECTION_TIMEOUT_MILLIS : node.getConnectionTimeoutMillis();
+ final long maxConnectionAttempts = node.getMaxConnectionAttempts() == null
+ ? NetconfTopologyUtils.DEFAULT_MAX_CONNECTION_ATTEMPTS : node.getMaxConnectionAttempts();
+ final int betweenAttemptsTimeoutMillis = node.getBetweenAttemptsTimeoutMillis() == null
+ ? NetconfTopologyUtils.DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS : node.getBetweenAttemptsTimeoutMillis();
+ final BigDecimal sleepFactor = node.getSleepFactor() == null
+ ? NetconfTopologyUtils.DEFAULT_SLEEP_FACTOR : node.getSleepFactor();
+
+ final InetSocketAddress socketAddress = getSocketAddress(node.getHost(), node.getPort().getValue());
+
+ final ReconnectStrategyFactory sf =
+ new TimedReconnectStrategyFactory(netconfTopologyDeviceSetup.getEventExecutor(), maxConnectionAttempts,
+ betweenAttemptsTimeoutMillis, sleepFactor);
+ final ReconnectStrategy strategy = sf.createReconnectStrategy();
+
+ final AuthenticationHandler authHandler;
+ final Credentials credentials = node.getCredentials();
+ if (credentials instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPassword) {
+ authHandler = new LoginPassword(
+ ((org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPassword) credentials).getUsername(),
+ ((org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPassword) credentials).getPassword());
+ } else {
+ throw new IllegalStateException(remoteDeviceId + ": Only login/password authentication is supported");
+ }
+
+ return NetconfReconnectingClientConfigurationBuilder.create()
+ .withAddress(socketAddress)
+ .withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
+ .withReconnectStrategy(strategy)
+ .withAuthHandler(authHandler)
+ .withProtocol(node.isTcpOnly()
+ ? NetconfClientConfiguration.NetconfClientProtocol.TCP
+ : NetconfClientConfiguration.NetconfClientProtocol.SSH)
+ .withConnectStrategyFactory(sf)
+ .withSessionListener(listener)
+ .build();
+ }
+
+ @VisibleForTesting
+ Map<String, NetconfDevice.SchemaResourcesDTO> getSchemaResourcesDTOs() {
+ return schemaResourcesDTOs;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl;
+
+import akka.actor.ActorRef;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.api.RemoteOperationTxProcessor;
+import org.opendaylight.netconf.topology.singleton.messages.NormalizedNodeMessage;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.SubmitFailedReply;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.EmptyReadResponse;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.SubmitReply;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RemoteOperationTxProcessorImpl implements RemoteOperationTxProcessor, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RemoteOperationTxProcessorImpl.class);
+
+ private final DOMDataBroker dataBroker;
+ private final RemoteDeviceId id;
+ private DOMDataWriteTransaction writeTx;
+ private DOMDataReadOnlyTransaction readTx;
+
+ public RemoteOperationTxProcessorImpl(final DOMDataBroker dataBroker, final RemoteDeviceId id) {
+ this.dataBroker = dataBroker;
+ this.id = id;
+ this.readTx = dataBroker.newReadOnlyTransaction();
+ }
+
+ @Override
+ public void doDelete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ if (writeTx == null) {
+ writeTx = dataBroker.newWriteOnlyTransaction();
+ }
+ writeTx.delete(store, path);
+ }
+
+ @Override
+ public void doSubmit(final ActorRef recipient, final ActorRef sender) {
+ if (writeTx != null) {
+ CheckedFuture<Void, TransactionCommitFailedException> submitFuture = writeTx.submit();
+ Futures.addCallback(submitFuture, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void result) {
+ recipient.tell(new SubmitReply(), sender);
+ }
+
+ @Override
+ public void onFailure(@Nonnull Throwable throwable) {
+ recipient.tell(throwable, sender);
+ }
+ });
+ } else {
+ recipient.tell(new SubmitFailedReply(), sender);
+ LOG.warn("{}: Couldn't submit transaction because it was already closed.", id);
+ }
+ }
+
+ @Override
+ public void doCancel(final ActorRef recipient, final ActorRef sender) {
+ boolean cancel = false;
+ if (writeTx != null) {
+ cancel = writeTx.cancel();
+ }
+ recipient.tell(cancel, sender);
+ }
+
+ @Override
+ public void doPut(final LogicalDatastoreType store, final NormalizedNodeMessage data) {
+ if (writeTx == null) {
+ writeTx = dataBroker.newWriteOnlyTransaction();
+ }
+ writeTx.put(store, data.getIdentifier(), data.getNode());
+ }
+
+ @Override
+ public void doMerge(final LogicalDatastoreType store, final NormalizedNodeMessage data) {
+ if (writeTx == null) {
+ writeTx = dataBroker.newWriteOnlyTransaction();
+ }
+ writeTx.merge(store, data.getIdentifier(), data.getNode());
+ }
+
+ @Override
+ public void doRead(final LogicalDatastoreType store, final YangInstanceIdentifier path, final ActorRef recipient,
+ final ActorRef sender) {
+ final CheckedFuture<Optional<NormalizedNode<?,?>>, ReadFailedException> readFuture =
+ readTx.read(store, path);
+
+ Futures.addCallback(readFuture, new FutureCallback<Optional<NormalizedNode<?, ?>>>() {
+
+ @Override
+ public void onSuccess(final Optional<NormalizedNode<?, ?>> result) {
+ if (!result.isPresent()) {
+ recipient.tell(new EmptyReadResponse(), sender);
+ return;
+ }
+ recipient.tell(new NormalizedNodeMessage(path, result.get()), sender);
+ }
+
+ @Override
+ public void onFailure(@Nonnull final Throwable throwable) {
+ recipient.tell(throwable, sender);
+ }
+ });
+ }
+
+ @Override
+ public void doExists(final LogicalDatastoreType store, final YangInstanceIdentifier path, final ActorRef recipient,
+ final ActorRef sender) {
+ final CheckedFuture<Boolean, ReadFailedException> readFuture =
+ readTx.exists(store, path);
+ Futures.addCallback(readFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(final Boolean result) {
+ if (result == null) {
+ recipient.tell(false, sender);
+ } else {
+ recipient.tell(result, sender);
+ }
+ }
+
+ @Override
+ public void onFailure(@Nonnull final Throwable throwable) {
+ recipient.tell(throwable, sender);
+ }
+ });
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (readTx != null) {
+ readTx.close();
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceNotificationService;
+import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalProvider;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.api.NetconfDOMTransaction;
+import org.opendaylight.netconf.topology.singleton.impl.tx.NetconfProxyDOMTransaction;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SlaveSalFacade {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SlaveSalFacade.class);
+
+ private final RemoteDeviceId id;
+ private final NetconfDeviceSalProvider salProvider;
+
+ private final ActorSystem actorSystem;
+
+ public SlaveSalFacade(final RemoteDeviceId id,
+ final Broker domBroker,
+ final ActorSystem actorSystem) {
+ this.id = id;
+ this.salProvider = new NetconfDeviceSalProvider(id);
+ this.actorSystem = actorSystem;
+
+ registerToSal(domBroker);
+ }
+
+ private void registerToSal(final Broker domRegistryDependency) {
+ domRegistryDependency.registerProvider(salProvider);
+
+ }
+
+ public void registerSlaveMountPoint(final SchemaContext remoteSchemaContext, final DOMRpcService deviceRpc,
+ final ActorRef masterActorRef) {
+ final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
+
+ final NetconfDOMTransaction proxyDOMTransactions =
+ new NetconfProxyDOMTransaction(id, actorSystem, masterActorRef);
+
+ final NetconfDOMDataBroker netconfDeviceDataBroker =
+ new NetconfDOMDataBroker(actorSystem, id, proxyDOMTransactions);
+
+ salProvider.getMountInstance().onTopologyDeviceConnected(remoteSchemaContext, netconfDeviceDataBroker,
+ deviceRpc, notificationService);
+
+ LOG.info("{}: Slave mount point registered.", id);
+ }
+
+ public void unregisterSlaveMountPoint() {
+ salProvider.getMountInstance().onTopologyDeviceDisconnected();
+ }
+
+ public void close() {
+ unregisterSlaveMountPoint();
+ try {
+ salProvider.getMountInstance().close();
+ } catch (Exception exception) {
+ LOG.warn("{}: Exception in closing slave sal facade: {}", id, exception);
+ }
+
+ }
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl.actors;
+
+import akka.actor.ActorRef;
+import akka.actor.Props;
+import akka.actor.UntypedActor;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import java.io.IOException;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.cluster.schema.provider.RemoteYangTextSourceProvider;
+import org.opendaylight.controller.cluster.schema.provider.impl.RemoteSchemaProvider;
+import org.opendaylight.controller.cluster.schema.provider.impl.YangTextSchemaSourceSerializationProxy;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.api.RemoteOperationTxProcessor;
+import org.opendaylight.netconf.topology.singleton.impl.ProxyDOMRpcService;
+import org.opendaylight.netconf.topology.singleton.impl.ProxyYangTextSourceProvider;
+import org.opendaylight.netconf.topology.singleton.impl.RemoteOperationTxProcessorImpl;
+import org.opendaylight.netconf.topology.singleton.impl.SlaveSalFacade;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
+import org.opendaylight.netconf.topology.singleton.messages.AskForMasterMountPoint;
+import org.opendaylight.netconf.topology.singleton.messages.CreateInitialMasterActorData;
+import org.opendaylight.netconf.topology.singleton.messages.MasterActorDataInitialized;
+import org.opendaylight.netconf.topology.singleton.messages.RefreshSetupMasterActorData;
+import org.opendaylight.netconf.topology.singleton.messages.RegisterMountPoint;
+import org.opendaylight.netconf.topology.singleton.messages.UnregisterSlaveMountPoint;
+import org.opendaylight.netconf.topology.singleton.messages.YangTextSchemaSourceRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.CancelRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.DeleteRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.ExistsRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.MergeRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.PutRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.ReadRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.SubmitRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.TransactionRequest;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfNodeActor extends UntypedActor {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeActor.class);
+
+ private NetconfTopologySetup setup;
+ private RemoteDeviceId id;
+ private final SchemaSourceRegistry schemaRegistry;
+ private final SchemaRepository schemaRepository;
+
+ private RemoteOperationTxProcessor operationsProcessor;
+ private List<SourceIdentifier> sourceIdentifiers;
+ private SlaveSalFacade slaveSalManager;
+
+ public static Props props(final NetconfTopologySetup setup,
+ final RemoteDeviceId id, final SchemaSourceRegistry schemaRegistry,
+ final SchemaRepository schemaRepository) {
+ return Props.create(NetconfNodeActor.class, () ->
+ new NetconfNodeActor(setup, id, schemaRegistry, schemaRepository));
+ }
+
+ private NetconfNodeActor(final NetconfTopologySetup setup,
+ final RemoteDeviceId id, SchemaSourceRegistry schemaRegistry,
+ final SchemaRepository schemaRepository) {
+ this.setup = setup;
+ this.id = id;
+ this.schemaRegistry = schemaRegistry;
+ this.schemaRepository = schemaRepository;
+ }
+
+ @Override
+ public void onReceive(final Object message) throws Exception {
+ if (message instanceof CreateInitialMasterActorData) { // master
+
+ sourceIdentifiers = ((CreateInitialMasterActorData) message).getSourceIndentifiers();
+ operationsProcessor =
+ new RemoteOperationTxProcessorImpl(((CreateInitialMasterActorData) message).getDeviceDataBroker(),
+ id);
+ sender().tell(new MasterActorDataInitialized(), self());
+
+ LOG.debug("{}: Master is ready.", id);
+
+ } else if (message instanceof RefreshSetupMasterActorData) {
+ setup = ((RefreshSetupMasterActorData) message).getNetconfTopologyDeviceSetup();
+ id = ((RefreshSetupMasterActorData) message).getRemoteDeviceId();
+ sender().tell(new MasterActorDataInitialized(), self());
+ } else if (message instanceof AskForMasterMountPoint) { // master
+ // only master contains reference to operations processor
+ if (operationsProcessor != null) {
+ getSender().tell(new RegisterMountPoint(sourceIdentifiers), getSelf());
+ }
+
+ } else if (message instanceof TransactionRequest) { // master
+
+ resolveProxyCalls(message, sender(), getSelf());
+
+ } else if (message instanceof YangTextSchemaSourceRequest) { // master
+
+ final YangTextSchemaSourceRequest yangTextSchemaSourceRequest = (YangTextSchemaSourceRequest) message;
+ sendYangTextSchemaSourceProxy(yangTextSchemaSourceRequest.getSourceIdentifier(), sender());
+
+ } else if (message instanceof RegisterMountPoint) { //slaves
+
+ sourceIdentifiers = ((RegisterMountPoint) message).getSourceIndentifiers();
+ registerSlaveMountPoint(getSender());
+
+ } else if (message instanceof UnregisterSlaveMountPoint) { //slaves
+ if (slaveSalManager != null) {
+ slaveSalManager.close();
+ slaveSalManager = null;
+ }
+
+ }
+ }
+
+ private void resolveProxyCalls(final Object message, final ActorRef recipient, final ActorRef futureSender) {
+ if (message instanceof ReadRequest) {
+
+ final ReadRequest readRequest = (ReadRequest) message;
+ operationsProcessor.doRead(readRequest.getStore(), readRequest.getPath(), recipient, futureSender);
+
+ } else if (message instanceof ExistsRequest) {
+
+ final ExistsRequest readRequest = (ExistsRequest) message;
+ operationsProcessor.doExists(readRequest.getStore(), readRequest.getPath(), recipient, futureSender);
+
+ } else if (message instanceof MergeRequest) {
+
+ final MergeRequest mergeRequest = (MergeRequest) message;
+ operationsProcessor.doMerge(mergeRequest.getStore(), mergeRequest.getNormalizedNodeMessage());
+
+ } else if (message instanceof PutRequest) {
+
+ final PutRequest putRequest = (PutRequest) message;
+ operationsProcessor.doPut(putRequest.getStore(), putRequest.getNormalizedNodeMessage());
+
+ } else if (message instanceof DeleteRequest) {
+
+ final DeleteRequest deleteRequest = (DeleteRequest) message;
+ operationsProcessor.doDelete(deleteRequest.getStore(), deleteRequest.getPath());
+
+ } else if (message instanceof CancelRequest) {
+
+ operationsProcessor.doCancel(recipient, futureSender);
+
+ } else if (message instanceof SubmitRequest) {
+
+ operationsProcessor.doSubmit(recipient, futureSender);
+ }
+ }
+
+ private void sendYangTextSchemaSourceProxy(final SourceIdentifier sourceIdentifier, final ActorRef sender) {
+ final CheckedFuture<YangTextSchemaSource, SchemaSourceException> yangTextSchemaSource =
+ schemaRepository.getSchemaSource(sourceIdentifier, YangTextSchemaSource.class);
+
+ Futures.addCallback(yangTextSchemaSource, new FutureCallback<YangTextSchemaSource>() {
+ @Override
+ public void onSuccess(final YangTextSchemaSource yangTextSchemaSource) {
+ try {
+ sender.tell(new YangTextSchemaSourceSerializationProxy(yangTextSchemaSource), getSelf());
+ } catch (IOException exception) {
+ sender.tell(exception.getCause(), getSelf());
+ }
+ }
+
+ @Override
+ public void onFailure(@Nonnull final Throwable throwable) {
+ sender.tell(throwable, getSelf());
+ }
+ });
+ }
+
+ private void registerSlaveMountPoint(final ActorRef masterReference) {
+ if (this.slaveSalManager != null) {
+ slaveSalManager.close();
+ }
+ slaveSalManager = new SlaveSalFacade(id, setup.getDomBroker(), setup.getActorSystem());
+
+ final CheckedFuture<SchemaContext, SchemaResolutionException> remoteSchemaContext =
+ getSchemaContext(masterReference);
+ final DOMRpcService deviceRpc = getDOMRpcService();
+
+ Futures.addCallback(remoteSchemaContext, new FutureCallback<SchemaContext>() {
+ @Override
+ public void onSuccess(final SchemaContext result) {
+ LOG.info("{}: Schema context resolved: {}", id, result.getModules());
+ slaveSalManager.registerSlaveMountPoint(result, deviceRpc, masterReference);
+ }
+
+ @Override
+ public void onFailure(@Nonnull final Throwable throwable) {
+ LOG.error("{}: Failed to register mount point: {}", id, throwable);
+ }
+ });
+ }
+
+ private DOMRpcService getDOMRpcService() {
+ return new ProxyDOMRpcService();
+ }
+
+ private CheckedFuture<SchemaContext, SchemaResolutionException> getSchemaContext(ActorRef masterReference) {
+
+ final RemoteYangTextSourceProvider remoteYangTextSourceProvider =
+ new ProxyYangTextSourceProvider(masterReference, getContext());
+ final RemoteSchemaProvider remoteProvider = new RemoteSchemaProvider(remoteYangTextSourceProvider,
+ getContext().dispatcher());
+
+ sourceIdentifiers.forEach(sourceId ->
+ schemaRegistry.registerSchemaSource(remoteProvider, PotentialSchemaSource.create(sourceId,
+ YangTextSchemaSource.class, PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
+
+ final SchemaContextFactory schemaContextFactory
+ = schemaRepository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+
+ return schemaContextFactory.createSchemaContext(sourceIdentifiers);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl.tx;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
+import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceDataBroker;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.api.NetconfDOMTransaction;
+import org.opendaylight.netconf.topology.singleton.messages.NormalizedNodeMessage;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.concurrent.Future;
+import scala.concurrent.impl.Promise.DefaultPromise;
+
+public class NetconfMasterDOMTransaction implements NetconfDOMTransaction {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfMasterDOMTransaction.class);
+
+ private final RemoteDeviceId id;
+ private final DOMDataBroker delegateBroker;
+
+ private DOMDataReadOnlyTransaction readTx;
+ private DOMDataWriteTransaction writeTx;
+
+ public NetconfMasterDOMTransaction(final RemoteDeviceId id,
+ final SchemaContext schemaContext,
+ final DOMRpcService rpc,
+ final NetconfSessionPreferences netconfSessionPreferences) {
+ this(id, new NetconfDeviceDataBroker(id, schemaContext, rpc, netconfSessionPreferences));
+ }
+
+ public NetconfMasterDOMTransaction(final RemoteDeviceId id, final DOMDataBroker delegateBroker) {
+ this.id = id;
+ this.delegateBroker = delegateBroker;
+
+ // only ever need 1 readTx since it doesnt need to be closed
+ readTx = delegateBroker.newReadOnlyTransaction();
+ }
+
+ @Override
+ public Future<Optional<NormalizedNodeMessage>> read(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+ LOG.trace("{}: Read[{}] {} via NETCONF: {}", id, readTx.getIdentifier(), store, path);
+
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readFuture = readTx.read(store, path);
+
+ final DefaultPromise<Optional<NormalizedNodeMessage>> promise = new DefaultPromise<>();
+ Futures.addCallback(readFuture, new FutureCallback<Optional<NormalizedNode<?, ?>>>() {
+ @Override
+ public void onSuccess(final Optional<NormalizedNode<?, ?>> result) {
+ if (!result.isPresent()) {
+ promise.success(Optional.absent());
+ } else {
+ promise.success(Optional.of(new NormalizedNodeMessage(path, result.get())));
+ }
+ }
+
+ @Override
+ public void onFailure(@Nonnull final Throwable throwable) {
+ promise.failure(throwable);
+ }
+ });
+ return promise.future();
+ }
+
+ @Override
+ public Future<Boolean> exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ LOG.trace("{}: Exists[{}] {} via NETCONF: {}", id, readTx.getIdentifier(), store, path);
+
+ final CheckedFuture<Boolean, ReadFailedException> existsFuture = readTx.exists(store, path);
+
+ final DefaultPromise<Boolean> promise = new DefaultPromise<>();
+ Futures.addCallback(existsFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(final Boolean result) {
+ promise.success(result);
+ }
+
+ @Override
+ public void onFailure(@Nonnull final Throwable throwable) {
+ promise.failure(throwable);
+ }
+ });
+ return promise.future();
+ }
+
+ @Override
+ public void put(final LogicalDatastoreType store, final NormalizedNodeMessage data) {
+ if (writeTx == null) {
+ writeTx = delegateBroker.newWriteOnlyTransaction();
+ }
+
+ LOG.trace("{}: Write[{}] {} via NETCONF: {} with payload {}", id, writeTx.getIdentifier(), store,
+ data.getIdentifier(), data.getNode());
+
+ writeTx.put(store, data.getIdentifier(), data.getNode());
+ }
+
+ @Override
+ public void merge(final LogicalDatastoreType store, final NormalizedNodeMessage data) {
+ if (writeTx == null) {
+ writeTx = delegateBroker.newWriteOnlyTransaction();
+ }
+
+ LOG.trace("{}: Merge[{}] {} via NETCONF: {} with payload {}", id, writeTx.getIdentifier(),store,
+ data.getIdentifier(), data.getNode());
+
+ writeTx.merge(store, data.getIdentifier(), data.getNode());
+ }
+
+ @Override
+ public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ if (writeTx == null) {
+ writeTx = delegateBroker.newWriteOnlyTransaction();
+ }
+
+ LOG.trace("{}: Delete[{}} {} via NETCONF: {}", id, writeTx.getIdentifier(), store, path);
+
+ writeTx.delete(store, path);
+ }
+
+ @Override
+ public boolean cancel() {
+ LOG.trace("{}: Cancel[{}} via NETCONF", id, writeTx.getIdentifier());
+
+ return writeTx.cancel();
+ }
+
+ @Override
+ public Future<Void> submit() {
+ LOG.trace("{}: Submit[{}} via NETCONF", id, writeTx.getIdentifier());
+
+ final CheckedFuture<Void, TransactionCommitFailedException> submitFuture = writeTx.submit();
+ final DefaultPromise<Void> promise = new DefaultPromise<>();
+ Futures.addCallback(submitFuture, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(final Void result) {
+ promise.success(result);
+ writeTx = null;
+ }
+
+ @Override
+ public void onFailure(@Nonnull final Throwable throwable) {
+ promise.failure(throwable);
+ writeTx = null;
+ }
+ });
+ return promise.future();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl.tx;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.dispatch.OnComplete;
+import akka.pattern.Patterns;
+import com.google.common.base.Optional;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.api.NetconfDOMTransaction;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
+import org.opendaylight.netconf.topology.singleton.messages.NormalizedNodeMessage;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.SubmitFailedReply;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.CancelRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.DeleteRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.EmptyReadResponse;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.ExistsRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.MergeRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.PutRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.ReadRequest;
+import org.opendaylight.netconf.topology.singleton.messages.transactions.SubmitRequest;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.concurrent.Await;
+import scala.concurrent.Future;
+import scala.concurrent.impl.Promise.DefaultPromise;
+
+
+public class NetconfProxyDOMTransaction implements NetconfDOMTransaction {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfProxyDOMTransaction.class);
+
+ private final RemoteDeviceId id;
+ private final ActorSystem actorSystem;
+ private final ActorRef masterContextRef;
+
+ public NetconfProxyDOMTransaction(final RemoteDeviceId id,
+ final ActorSystem actorSystem,
+ final ActorRef masterContextRef) {
+ this.id = id;
+ this.actorSystem = actorSystem;
+ this.masterContextRef = masterContextRef;
+ }
+
+ @Override
+ public Future<Optional<NormalizedNodeMessage>> read(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+
+ final Future<Object> readScalaFuture =
+ Patterns.ask(masterContextRef, new ReadRequest(store, path), NetconfTopologyUtils.TIMEOUT);
+
+ LOG.trace("{}: Read {} via NETCONF: {}", id, store, path);
+
+ final DefaultPromise<Optional<NormalizedNodeMessage>> promise = new DefaultPromise<>();
+
+ readScalaFuture.onComplete(new OnComplete<Object>() {
+ @Override
+ public void onComplete(final Throwable failure, final Object success) throws Throwable {
+ if (failure != null) { // ask timeout
+ Exception exception = new DocumentedException(id + ":Master is down. Please try again.",
+ DocumentedException.ErrorType.APPLICATION, DocumentedException.ErrorTag.OPERATION_FAILED,
+ DocumentedException.ErrorSeverity.WARNING);
+ promise.failure(exception);
+ return;
+ }
+ if (success instanceof Throwable) { // Error sended by master
+ promise.failure((Throwable) success);
+ return;
+ }
+ if (success instanceof EmptyReadResponse) {
+ promise.success(Optional.absent());
+ return;
+ }
+
+ promise.success(Optional.of((NormalizedNodeMessage) success));
+ }
+ }, actorSystem.dispatcher());
+
+ return promise.future();
+ }
+
+ @Override
+ public Future<Boolean> exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ final Future<Object> existsScalaFuture =
+ Patterns.ask(masterContextRef, new ExistsRequest(store, path), NetconfTopologyUtils.TIMEOUT);
+
+ LOG.trace("{}: Exists {} via NETCONF: {}", id, store, path);
+
+ final DefaultPromise<Boolean> promise = new DefaultPromise<>();
+ existsScalaFuture.onComplete(new OnComplete<Object>() {
+ @Override
+ public void onComplete(final Throwable failure, final Object success) throws Throwable {
+ if (failure != null) { // ask timeout
+ Exception exception = new DocumentedException(id + ":Master is down. Please try again.",
+ DocumentedException.ErrorType.APPLICATION, DocumentedException.ErrorTag.OPERATION_FAILED,
+ DocumentedException.ErrorSeverity.WARNING);
+ promise.failure(exception);
+ return;
+ }
+ if (success instanceof Throwable) {
+ promise.failure((Throwable) success);
+ return;
+ }
+ promise.success((Boolean) success);
+ }
+ }, actorSystem.dispatcher());
+ return promise.future();
+ }
+
+ @Override
+ public void put(final LogicalDatastoreType store, final NormalizedNodeMessage data) {
+ LOG.trace("{}: Write {} via NETCONF: {} with payload {}", id, store, data.getIdentifier(), data.getNode());
+
+ masterContextRef.tell(new PutRequest(store, data), ActorRef.noSender());
+
+ }
+
+ @Override
+ public void merge(final LogicalDatastoreType store, final NormalizedNodeMessage data) {
+ LOG.trace("{}: Merge {} via NETCONF: {} with payload {}", id, store, data.getIdentifier(), data.getNode());
+
+ masterContextRef.tell(new MergeRequest(store, data), ActorRef.noSender());
+ }
+
+ @Override
+ public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ LOG.trace("{}: Delete {} via NETCONF: {}", id, store, path);
+
+ masterContextRef.tell(new DeleteRequest(store, path), ActorRef.noSender());
+ }
+
+ @Override
+ public boolean cancel() {
+ final Future<Object> cancelScalaFuture =
+ Patterns.ask(masterContextRef, new CancelRequest(), NetconfTopologyUtils.TIMEOUT);
+
+ LOG.trace("{}: Cancel {} via NETCONF", id);
+
+ try {
+ // here must be Await because AsyncWriteTransaction do not return future
+ return (boolean) Await.result(cancelScalaFuture, NetconfTopologyUtils.TIMEOUT.duration());
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ @Override
+ public Future<Void> submit() {
+ final Future<Object> submitScalaFuture =
+ Patterns.ask(masterContextRef, new SubmitRequest(), NetconfTopologyUtils.TIMEOUT);
+
+ LOG.trace("{}: Submit {} via NETCONF", id);
+
+ final DefaultPromise<Void> promise = new DefaultPromise<>();
+
+ submitScalaFuture.onComplete(new OnComplete<Object>() {
+ @Override
+ public void onComplete(final Throwable failure, final Object success) throws Throwable {
+ if (failure != null) { // ask timeout
+ Exception exception = new DocumentedException(id + ":Master is down. Please try again.",
+ DocumentedException.ErrorType.APPLICATION, DocumentedException.ErrorTag.OPERATION_FAILED,
+ DocumentedException.ErrorSeverity.WARNING);
+ promise.failure(exception);
+ return;
+ }
+ if (success instanceof Throwable) {
+ promise.failure((Throwable) success);
+ } else {
+ if (success instanceof SubmitFailedReply) {
+ LOG.error("{}: Transaction was not submitted because already closed.", id);
+ }
+ promise.success(null);
+ }
+ }
+ }, actorSystem.dispatcher());
+
+ return promise.future();
+ }
+
+}
/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.pipeline.tx;
+package org.opendaylight.netconf.topology.singleton.impl.tx;
import akka.actor.ActorSystem;
import akka.dispatch.OnComplete;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.netconf.topology.pipeline.ProxyNetconfDeviceDataBroker;
-import org.opendaylight.netconf.topology.util.messages.NormalizedNodeMessage;
+import org.opendaylight.netconf.topology.singleton.api.NetconfDOMTransaction;
+import org.opendaylight.netconf.topology.singleton.messages.NormalizedNodeMessage;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import scala.concurrent.Future;
-public class ProxyReadOnlyTransaction implements DOMDataReadOnlyTransaction{
+public class NetconfReadOnlyTransaction implements DOMDataReadOnlyTransaction {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfReadOnlyTransaction.class);
private final RemoteDeviceId id;
- private final ProxyNetconfDeviceDataBroker delegate;
+ private final NetconfDOMTransaction delegate;
private final ActorSystem actorSystem;
- public ProxyReadOnlyTransaction(final ActorSystem actorSystem, final RemoteDeviceId id, final ProxyNetconfDeviceDataBroker delegate) {
+ public NetconfReadOnlyTransaction(final RemoteDeviceId id,
+ final ActorSystem actorSystem,
+ final NetconfDOMTransaction delegate) {
this.id = id;
this.delegate = delegate;
this.actorSystem = actorSystem;
}
@Override
- public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+
+ LOG.trace("{}: Read {} via NETCONF: {}", id, store, path);
+
final Future<Optional<NormalizedNodeMessage>> future = delegate.read(store, path);
final SettableFuture<Optional<NormalizedNode<?, ?>>> settableFuture = SettableFuture.create();
- final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> checkedFuture = Futures.makeChecked(settableFuture, new Function<Exception, ReadFailedException>() {
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> checkedFuture;
+ checkedFuture = Futures.makeChecked(settableFuture, new Function<Exception, ReadFailedException>() {
@Nullable
@Override
public ReadFailedException apply(Exception cause) {
});
future.onComplete(new OnComplete<Optional<NormalizedNodeMessage>>() {
@Override
- public void onComplete(Throwable throwable, Optional<NormalizedNodeMessage> normalizedNodeMessage) throws Throwable {
+ public void onComplete(final Throwable throwable,
+ final Optional<NormalizedNodeMessage> normalizedNodeMessage) throws Throwable {
if (throwable == null) {
if (normalizedNodeMessage.isPresent()) {
- settableFuture.set(normalizedNodeMessage.transform(new Function<NormalizedNodeMessage, NormalizedNode<?, ?>>() {
+ settableFuture.set(normalizedNodeMessage.transform(new Function<NormalizedNodeMessage,
+ NormalizedNode<?, ?>>() {
+
@Nullable
@Override
- public NormalizedNode<?, ?> apply(NormalizedNodeMessage input) {
+ public NormalizedNode<?, ?> apply(final NormalizedNodeMessage input) {
return input.getNode();
}
}));
}
@Override
- public CheckedFuture<Boolean, ReadFailedException> exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ public CheckedFuture<Boolean, ReadFailedException> exists(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+
+ LOG.trace("{}: Exists {} via NETCONF: {}", id, store, path);
+
final Future<Boolean> existsFuture = delegate.exists(store, path);
final SettableFuture<Boolean> settableFuture = SettableFuture.create();
- final CheckedFuture<Boolean, ReadFailedException> checkedFuture = Futures.makeChecked(settableFuture, new Function<Exception, ReadFailedException>() {
+ final CheckedFuture<Boolean, ReadFailedException> checkedFuture;
+ checkedFuture = Futures.makeChecked(settableFuture, new Function<Exception, ReadFailedException>() {
@Nullable
@Override
public ReadFailedException apply(Exception cause) {
});
existsFuture.onComplete(new OnComplete<Boolean>() {
@Override
- public void onComplete(Throwable throwable, Boolean result) throws Throwable {
+ public void onComplete(final Throwable throwable, final Boolean result) throws Throwable {
if (throwable == null) {
settableFuture.set(result);
} else {
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl.tx;
+
+import akka.actor.ActorSystem;
+import akka.dispatch.OnComplete;
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.api.NetconfDOMTransaction;
+import org.opendaylight.netconf.topology.singleton.messages.NormalizedNodeMessage;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.concurrent.Future;
+
+public class NetconfWriteOnlyTransaction implements DOMDataWriteTransaction {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfWriteOnlyTransaction.class);
+
+ private final RemoteDeviceId id;
+ private final NetconfDOMTransaction delegate;
+ private final ActorSystem actorSystem;
+
+ public NetconfWriteOnlyTransaction(final RemoteDeviceId id,
+ final ActorSystem actorSystem,
+ final NetconfDOMTransaction delegate) {
+ this.id = id;
+ this.delegate = delegate;
+ this.actorSystem = actorSystem;
+ }
+
+ @Override
+ public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ final NormalizedNode<?,?> data) {
+ LOG.trace("{}: Write {} via NETCONF: {} with payload {}", id, store, path, data);
+
+ delegate.put(store, new NormalizedNodeMessage(path, data));
+ }
+
+ @Override
+ public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ final NormalizedNode<?,?> data) {
+ LOG.trace("{}: Merge {} via NETCONF: {} with payload {}", id, store, path, data);
+
+ delegate.merge(store, new NormalizedNodeMessage(path, data));
+ }
+
+ @Override
+ public boolean cancel() {
+ LOG.trace("{}: Cancel", id);
+
+ return delegate.cancel();
+ }
+
+ @Override
+ public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ LOG.trace("{}: Delete {} via NETCONF: {}", id, store, path);
+
+ delegate.delete(store, path);
+ }
+
+ @Override
+ public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+ LOG.trace("{}: Submit", id);
+
+ final Future<Void> submit = delegate.submit();
+ final SettableFuture<Void> settFuture = SettableFuture.create();
+ final CheckedFuture<Void, TransactionCommitFailedException> checkedFuture;
+ checkedFuture = Futures.makeChecked(settFuture, new Function<Exception, TransactionCommitFailedException>() {
+ @Nullable
+ @Override
+ public TransactionCommitFailedException apply(Exception input) {
+ return new TransactionCommitFailedException("Transaction commit failed", input);
+ }
+ });
+ submit.onComplete(new OnComplete<Void>() {
+ @Override
+ public void onComplete(Throwable throwable, Void object) throws Throwable {
+ if (throwable == null) {
+ settFuture.set(object);
+ } else {
+ settFuture.setException(throwable);
+ }
+ }
+ }, actorSystem.dispatcher());
+ return checkedFuture;
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+ LOG.trace("{}: Commit", id);
+
+ final Future<Void> commit = delegate.submit();
+ final SettableFuture<RpcResult<TransactionStatus>> settFuture = SettableFuture.create();
+ commit.onComplete(new OnComplete<Void>() {
+ @Override
+ public void onComplete(final Throwable throwable, final Void result) throws Throwable {
+ if (throwable == null) {
+ TransactionStatus status = TransactionStatus.SUBMITED;
+ RpcResult<TransactionStatus> rpcResult = RpcResultBuilder.success(status).build();
+ settFuture.set(rpcResult);
+ } else {
+ settFuture.setException(throwable);
+ }
+ }
+ }, actorSystem.dispatcher());
+ return settFuture;
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return this;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl.utils;
+
+import org.opendaylight.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
+
+public class NetconfConnectorDTO implements AutoCloseable {
+
+ private final NetconfDeviceCommunicator communicator;
+ private final RemoteDeviceHandler<NetconfSessionPreferences> facade;
+
+ public NetconfConnectorDTO(final NetconfDeviceCommunicator communicator,
+ final RemoteDeviceHandler<NetconfSessionPreferences> facade) {
+ this.communicator = communicator;
+ this.facade = facade;
+ }
+
+ public NetconfDeviceCommunicator getCommunicator() {
+ return communicator;
+ }
+
+ public RemoteDeviceHandler<NetconfSessionPreferences> getFacade() {
+ return facade;
+ }
+
+ public NetconfClientSessionListener getSessionListener() {
+ return communicator;
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (communicator != null) {
+ communicator.close();
+ }
+ if (facade != null) {
+ facade.close();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl.utils;
+
+import akka.actor.ActorSystem;
+import io.netty.util.concurrent.EventExecutor;
+import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
+import org.opendaylight.controller.config.threadpool.ThreadPool;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class NetconfTopologySetup {
+
+ private final ClusterSingletonServiceProvider clusterSingletonServiceProvider;
+ private final RpcProviderRegistry rpcProviderRegistry;
+ private final DataBroker dataBroker;
+ private final InstanceIdentifier<Node> instanceIdentifier;
+ private final Node node;
+ private final BindingAwareBroker bindingAwareBroker;
+ private final ScheduledThreadPool keepaliveExecutor;
+ private final ThreadPool processingExecutor;
+ private final Broker domBroker;
+ private final ActorSystem actorSystem;
+ private final EventExecutor eventExecutor;
+ private final NetconfClientDispatcher netconfClientDispatcher;
+ private final String topologyId;
+ private NetconfTopologySetup(final NetconfTopologySetupBuilder builder) {
+ this.clusterSingletonServiceProvider = builder.getClusterSingletonServiceProvider();
+ this.rpcProviderRegistry = builder.getRpcProviderRegistry();
+ this.dataBroker = builder.getDataBroker();
+ this.instanceIdentifier = builder.getInstanceIdentifier();
+ this.node = builder.getNode();
+ this.bindingAwareBroker = builder.getBindingAwareBroker();
+ this.keepaliveExecutor = builder.getKeepaliveExecutor();
+ this.processingExecutor = builder.getProcessingExecutor();
+ this.domBroker = builder.getDomBroker();
+ this.actorSystem = builder.getActorSystem();
+ this.eventExecutor = builder.getEventExecutor();
+ this.netconfClientDispatcher = builder.getNetconfClientDispatcher();
+ this.topologyId = builder.getTopologyId();
+ }
+
+ public ClusterSingletonServiceProvider getClusterSingletonServiceProvider() {
+ return clusterSingletonServiceProvider;
+ }
+
+ public RpcProviderRegistry getRpcProviderRegistry() {
+ return rpcProviderRegistry;
+ }
+
+ public DataBroker getDataBroker() {
+ return dataBroker;
+ }
+
+ public InstanceIdentifier<Node> getInstanceIdentifier() {
+ return instanceIdentifier;
+ }
+
+ public Node getNode() {
+ return node;
+ }
+
+ public BindingAwareBroker getBindingAwareBroker() {
+ return bindingAwareBroker;
+ }
+
+ public ThreadPool getProcessingExecutor() {
+ return processingExecutor;
+ }
+
+ public ScheduledThreadPool getKeepaliveExecutor() {
+ return keepaliveExecutor;
+ }
+
+ public Broker getDomBroker() {
+ return domBroker;
+ }
+
+ public ActorSystem getActorSystem() {
+ return actorSystem;
+ }
+
+ public EventExecutor getEventExecutor() {
+ return eventExecutor;
+ }
+
+ public String getTopologyId() {
+ return topologyId;
+ }
+
+ public NetconfClientDispatcher getNetconfClientDispatcher() {
+ return netconfClientDispatcher;
+ }
+
+ public static class NetconfTopologySetupBuilder {
+
+ private ClusterSingletonServiceProvider clusterSingletonServiceProvider;
+ private RpcProviderRegistry rpcProviderRegistry;
+ private DataBroker dataBroker;
+ private InstanceIdentifier<Node> instanceIdentifier;
+ private Node node;
+ private BindingAwareBroker bindingAwareBroker;
+ private ScheduledThreadPool keepaliveExecutor;
+ private ThreadPool processingExecutor;
+ private Broker domBroker;
+ private ActorSystem actorSystem;
+ private EventExecutor eventExecutor;
+ private String topologyId;
+ private NetconfClientDispatcher netconfClientDispatcher;
+
+ public NetconfTopologySetupBuilder(){
+ }
+
+ private ClusterSingletonServiceProvider getClusterSingletonServiceProvider() {
+ return clusterSingletonServiceProvider;
+ }
+
+ public NetconfTopologySetupBuilder setClusterSingletonServiceProvider(
+ final ClusterSingletonServiceProvider clusterSingletonServiceProvider) {
+ this.clusterSingletonServiceProvider = clusterSingletonServiceProvider;
+ return this;
+ }
+
+ private RpcProviderRegistry getRpcProviderRegistry() {
+ return rpcProviderRegistry;
+ }
+
+ public NetconfTopologySetupBuilder setRpcProviderRegistry(final RpcProviderRegistry rpcProviderRegistry) {
+ this.rpcProviderRegistry = rpcProviderRegistry;
+ return this;
+ }
+
+ private DataBroker getDataBroker() {
+ return dataBroker;
+ }
+
+ public NetconfTopologySetupBuilder setDataBroker(final DataBroker dataBroker) {
+ this.dataBroker = dataBroker;
+ return this;
+ }
+
+ private InstanceIdentifier<Node> getInstanceIdentifier() {
+ return instanceIdentifier;
+ }
+
+ public NetconfTopologySetupBuilder setInstanceIdentifier(final InstanceIdentifier<Node> instanceIdentifier) {
+ this.instanceIdentifier = instanceIdentifier;
+ return this;
+ }
+
+ public Node getNode() {
+ return node;
+ }
+
+ public NetconfTopologySetupBuilder setNode(final Node node) {
+ this.node = node;
+ return this;
+ }
+
+ public NetconfTopologySetup build() {
+ return new NetconfTopologySetup(this);
+ }
+
+ private BindingAwareBroker getBindingAwareBroker() {
+ return bindingAwareBroker;
+ }
+
+ public NetconfTopologySetupBuilder setBindingAwareBroker(BindingAwareBroker bindingAwareBroker) {
+ this.bindingAwareBroker = bindingAwareBroker;
+ return this;
+ }
+
+ private ScheduledThreadPool getKeepaliveExecutor() {
+ return keepaliveExecutor;
+ }
+
+ public NetconfTopologySetupBuilder setKeepaliveExecutor(ScheduledThreadPool keepaliveExecutor) {
+ this.keepaliveExecutor = keepaliveExecutor;
+ return this;
+ }
+
+ private ThreadPool getProcessingExecutor() {
+ return processingExecutor;
+ }
+
+ public NetconfTopologySetupBuilder setProcessingExecutor(ThreadPool processingExecutor) {
+ this.processingExecutor = processingExecutor;
+ return this;
+ }
+
+ private Broker getDomBroker() {
+ return domBroker;
+ }
+
+ public NetconfTopologySetupBuilder setDomBroker(Broker domBroker) {
+ this.domBroker = domBroker;
+ return this;
+ }
+
+ private ActorSystem getActorSystem() {
+ return actorSystem;
+ }
+
+ public NetconfTopologySetupBuilder setActorSystem(ActorSystem actorSystem) {
+ this.actorSystem = actorSystem;
+ return this;
+ }
+
+ private EventExecutor getEventExecutor() {
+ return eventExecutor;
+ }
+
+ public NetconfTopologySetupBuilder setEventExecutor(EventExecutor eventExecutor) {
+ this.eventExecutor = eventExecutor;
+ return this;
+ }
+
+ private String getTopologyId() {
+ return topologyId;
+ }
+
+ public NetconfTopologySetupBuilder setTopologyId(String topologyId) {
+ this.topologyId = topologyId;
+ return this;
+ }
+
+ private NetconfClientDispatcher getNetconfClientDispatcher() {
+ return netconfClientDispatcher;
+ }
+
+ public NetconfTopologySetupBuilder setNetconfClientDispatcher(NetconfClientDispatcher clientDispatcher) {
+ this.netconfClientDispatcher = clientDispatcher;
+ return this;
+ }
+
+ public static NetconfTopologySetupBuilder create() {
+ return new NetconfTopologySetupBuilder();
+ }
+ }
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl.utils;
+
+import akka.cluster.Member;
+import akka.util.Timeout;
+import java.io.File;
+import java.math.BigDecimal;
+import java.net.InetSocketAddress;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+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.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache;
+import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
+import scala.concurrent.duration.Duration;
+
+public class NetconfTopologyUtils {
+
+ private static final String DEFAULT_SCHEMA_REPOSITORY_NAME = "sal-netconf-connector";
+
+ public static final Timeout TIMEOUT = new Timeout(Duration.create(10, "seconds"));
+
+ public static final long DEFAULT_REQUEST_TIMEOUT_MILLIS = 60000L;
+ public static final int DEFAULT_KEEPALIVE_DELAY = 0;
+ public static final boolean DEFAULT_RECONNECT_ON_CHANGED_SCHEMA = false;
+ public static final int DEFAULT_CONCURRENT_RPC_LIMIT = 0;
+ public static final int DEFAULT_MAX_CONNECTION_ATTEMPTS = 0;
+ public static final int DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS = 2000;
+ public static final long DEFAULT_CONNECTION_TIMEOUT_MILLIS = 20000L;
+ public static final BigDecimal DEFAULT_SLEEP_FACTOR = new BigDecimal(1.5);
+
+
+ // The default cache directory relative to <code>CACHE_DIRECTORY</code>
+
+ public static final String DEFAULT_CACHE_DIRECTORY = "schema";
+
+ // Filesystem based caches are stored relative to the cache directory.
+ public static final String CACHE_DIRECTORY = "cache";
+
+ // The qualified schema cache directory <code>cache/schema</code>
+ public static final String QUALIFIED_DEFAULT_CACHE_DIRECTORY =
+ CACHE_DIRECTORY + File.separator + DEFAULT_CACHE_DIRECTORY;
+
+ // The default schema repository in the case that one is not specified.
+ public static final SharedSchemaRepository DEFAULT_SCHEMA_REPOSITORY =
+ new SharedSchemaRepository(DEFAULT_SCHEMA_REPOSITORY_NAME);
+
+
+ // The default <code>FilesystemSchemaSourceCache</code>, which stores cached files in <code>cache/schema</code>.
+ public static final FilesystemSchemaSourceCache<YangTextSchemaSource> DEFAULT_CACHE =
+ new FilesystemSchemaSourceCache<>(DEFAULT_SCHEMA_REPOSITORY, YangTextSchemaSource.class,
+ new File(QUALIFIED_DEFAULT_CACHE_DIRECTORY));
+
+ // The default factory for creating <code>SchemaContext</code> instances.
+ public static final SchemaContextFactory DEFAULT_SCHEMA_CONTEXT_FACTORY =
+ DEFAULT_SCHEMA_REPOSITORY.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+
+ public static RemoteDeviceId createRemoteDeviceId(final NodeId nodeId, final NetconfNode node) {
+ IpAddress ipAddress = node.getHost().getIpAddress();
+ InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null
+ ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(),
+ node.getPort().getValue());
+ return new RemoteDeviceId(nodeId.getValue(), address);
+ }
+
+ public static String createActorPath(String masterMember, String name) {
+ return masterMember + "/user/" + name;
+ }
+
+ public static String createMasterActorName(String name, String masterAddress) {
+ return masterAddress.replaceAll("//", "") + "_" + name;
+ }
+
+ public static NodeId getNodeId(final InstanceIdentifier.PathArgument pathArgument) {
+ if (pathArgument instanceof InstanceIdentifier.IdentifiableItem<?, ?>) {
+
+ final Identifier key = ((InstanceIdentifier.IdentifiableItem) pathArgument).getKey();
+ if (key instanceof NodeKey) {
+ return ((NodeKey) key).getNodeId();
+ }
+ }
+ throw new IllegalStateException("Unable to create NodeId from: " + pathArgument);
+ }
+
+ public static KeyedInstanceIdentifier<Topology, TopologyKey> createTopologyListPath(final String topologyId) {
+ final InstanceIdentifier<NetworkTopology> networkTopology = InstanceIdentifier.create(NetworkTopology.class);
+ return networkTopology.child(Topology.class, new TopologyKey(new TopologyId(topologyId)));
+ }
+
+ public static InstanceIdentifier<Node> createTopologyNodeListPath(final NodeKey key, final String topologyId) {
+ return createTopologyListPath(topologyId)
+ .child(Node.class, new NodeKey(new NodeId(key.getNodeId().getValue())));
+ }
+
+ public static InstanceIdentifier<Node> createTopologyNodePath(final String topologyId) {
+ return createTopologyListPath(topologyId).child(Node.class);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages;
+
+import java.io.Serializable;
+
+/**
+ * After master is connected, slaves send the message to master and master triggers registering slave mount point
+ * with reply 'RegisterMountPoint' which includes needed parameters.
+ */
+public class AskForMasterMountPoint implements Serializable {
+ private static final long serialVersionUID = 1L;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages;
+
+import java.io.Serializable;
+import java.util.List;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+
+/**
+ * Master sends this message to the own actor to set necessary parameters.
+ */
+public class CreateInitialMasterActorData implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final DOMDataBroker deviceDataBroker;
+ private final List<SourceIdentifier> allSourceIdentifiers;
+
+ public CreateInitialMasterActorData(final DOMDataBroker deviceDataBroker,
+ final List<SourceIdentifier> allSourceIdentifiers) {
+ this.deviceDataBroker = deviceDataBroker;
+ this.allSourceIdentifiers = allSourceIdentifiers;
+ }
+
+ public DOMDataBroker getDeviceDataBroker() {
+ return deviceDataBroker;
+ }
+
+ public List<SourceIdentifier> getSourceIndentifiers() {
+ return allSourceIdentifiers;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages;
+
+import java.io.Serializable;
+
+/**
+ * Due to possibility of race condition (when data-store is updated before data are initialized in master actor), only
+ * when this message is received by master, operational data-store is changed.
+ */
+public class MasterActorDataInitialized implements Serializable {
+ private static final long serialVersionUID = 1L;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import org.opendaylight.controller.cluster.datastore.utils.SerializationUtils;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Message which holds node data, prepared to sending between remote hosts with serialization.
+ */
+public class NormalizedNodeMessage implements Externalizable {
+ private static final long serialVersionUID = 1L;
+
+ private YangInstanceIdentifier identifier = null;
+ private NormalizedNode<?, ?> node = null;
+
+ public NormalizedNodeMessage() {
+ // empty constructor needed for Externalizable
+ }
+
+ public NormalizedNodeMessage(final YangInstanceIdentifier identifier, final NormalizedNode<?, ?> node) {
+ this.identifier = identifier;
+ this.node = node;
+ }
+
+ public YangInstanceIdentifier getIdentifier() {
+ return identifier;
+ }
+
+ public NormalizedNode<?, ?> getNode() {
+ return node;
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ SerializationUtils.serializePathAndNode(getIdentifier(), node, out);
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+ SerializationUtils.deserializePathAndNode(in, this, APPLIER);
+ }
+
+ private static final SerializationUtils.Applier<NormalizedNodeMessage> APPLIER = (instance, path, node) -> {
+ instance.identifier = path;
+ instance.node = node;
+ };
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages;
+
+import java.io.Serializable;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
+
+/**
+ * Master sends this message to the own actor to refresh setup data
+ */
+public class RefreshSetupMasterActorData implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final NetconfTopologySetup netconfTopologyDeviceSetup;
+ private final RemoteDeviceId remoteDeviceId;
+
+ public RefreshSetupMasterActorData(final NetconfTopologySetup netconfTopologyDeviceSetup,
+ final RemoteDeviceId remoteDeviceId) {
+ this.netconfTopologyDeviceSetup = netconfTopologyDeviceSetup;
+ this.remoteDeviceId = remoteDeviceId;
+ }
+
+ public NetconfTopologySetup getNetconfTopologyDeviceSetup() {
+ return netconfTopologyDeviceSetup;
+ }
+
+ public RemoteDeviceId getRemoteDeviceId() {
+ return remoteDeviceId;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages;
+
+import java.io.Serializable;
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+
+/**
+ * Master sends the message to slave with necessary parameters for creating slave mount point.
+ */
+public class RegisterMountPoint implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final List<SourceIdentifier> allSourceIdentifiers;
+
+ public RegisterMountPoint(final List<SourceIdentifier> allSourceIdentifiers) {
+ this.allSourceIdentifiers = allSourceIdentifiers;
+ }
+
+ public List<SourceIdentifier> getSourceIndentifiers() {
+ return allSourceIdentifiers;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages;
+
+import java.io.Serializable;
+
+/**
+ * Slave sends the message when unregisters slave mount point (in NetconfNodeManager
+ * close method). Message must be sended before slave actor is poisoned.
+ */
+public class UnregisterSlaveMountPoint implements Serializable {
+ private static final long serialVersionUID = 1L;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages;
+
+import java.io.Serializable;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+
+/**
+ * Slave sends message to master when tries to resolve schema with particular sourceIdentifier (proxy call).
+ * Master responds with resolved schema source.
+ */
+public class YangTextSchemaSourceRequest implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final SourceIdentifier sourceIdentifier;
+
+ public YangTextSchemaSourceRequest(final SourceIdentifier sourceIdentifier) {
+ this.sourceIdentifier = sourceIdentifier;
+ }
+
+ public SourceIdentifier getSourceIdentifier() {
+ return sourceIdentifier;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages.transactions;
+
+public class CancelRequest implements TransactionRequest {
+ private static final long serialVersionUID = 1L;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages.transactions;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+public class DeleteRequest implements TransactionRequest {
+ private static final long serialVersionUID = 1L;
+
+ private final LogicalDatastoreType store;
+ private final YangInstanceIdentifier path;
+
+ public DeleteRequest(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ this.store = store;
+ this.path = path;
+ }
+
+ public LogicalDatastoreType getStore() {
+ return store;
+ }
+
+ public YangInstanceIdentifier getPath() {
+ return path;
+ }
+}
/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.util.messages;
+package org.opendaylight.netconf.topology.singleton.messages.transactions;
import java.io.Serializable;
-public class AnnounceMasterMountPoint implements Serializable {
+/**
+ * Message is sended when read result do not present any value.
+ */
+public class EmptyReadResponse implements Serializable {
private static final long serialVersionUID = 1L;
-
- public AnnounceMasterMountPoint() {}
}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages.transactions;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+public class ExistsRequest implements TransactionRequest {
+ private static final long serialVersionUID = 1L;
+
+ private final LogicalDatastoreType store;
+ private final YangInstanceIdentifier path;
+
+ public ExistsRequest(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ this.store = store;
+ this.path = path;
+ }
+
+ public LogicalDatastoreType getStore() {
+ return store;
+ }
+
+ public YangInstanceIdentifier getPath() {
+ return path;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages.transactions;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netconf.topology.singleton.messages.NormalizedNodeMessage;
+
+public class MergeRequest implements TransactionRequest {
+ private static final long serialVersionUID = 1L;
+
+ private final NormalizedNodeMessage data;
+ private final LogicalDatastoreType store;
+
+ public MergeRequest(final LogicalDatastoreType store, final NormalizedNodeMessage data) {
+ this.store = store;
+ this.data = data;
+ }
+
+ public NormalizedNodeMessage getNormalizedNodeMessage() {
+ return data;
+ }
+
+ public LogicalDatastoreType getStore() {
+ return store;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages.transactions;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.netconf.topology.singleton.messages.NormalizedNodeMessage;
+
+public class PutRequest implements TransactionRequest {
+ private static final long serialVersionUID = 1L;
+
+ private final LogicalDatastoreType store;
+ private final NormalizedNodeMessage data;
+
+ public PutRequest(final LogicalDatastoreType store, final NormalizedNodeMessage data) {
+ this.store = store;
+ this.data = data;
+ }
+
+ public NormalizedNodeMessage getNormalizedNodeMessage() {
+ return data;
+ }
+
+ public LogicalDatastoreType getStore() {
+ return store;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages.transactions;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+public class ReadRequest implements TransactionRequest {
+ private static final long serialVersionUID = 1L;
+
+ private final LogicalDatastoreType store;
+ private final YangInstanceIdentifier path;
+
+ public ReadRequest(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ this.store = store;
+ this.path = path;
+ }
+
+ public LogicalDatastoreType getStore() {
+ return store;
+ }
+
+ public YangInstanceIdentifier getPath() {
+ return path;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages.transactions;
+
+import java.io.Serializable;
+
+/**
+ * Message sent from master back to the slave when submit is not performed, tx is closed
+ */
+public class SubmitFailedReply implements Serializable {
+ private static final long serialVersionUID = 1L;
+}
/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.util.messages;
+package org.opendaylight.netconf.topology.singleton.messages.transactions;
import java.io.Serializable;
-public class AnnounceMasterMountPointDown implements Serializable {
+/**
+ * Message sent from master back to the slave when submit is successfully performed.
+ */
+public class SubmitReply implements Serializable {
private static final long serialVersionUID = 1L;
-
- public AnnounceMasterMountPointDown() {
-
- }
}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages.transactions;
+
+public class SubmitRequest implements TransactionRequest {
+ private static final long serialVersionUID = 1L;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.messages.transactions;
+
+import java.io.Serializable;
+
+/**
+ * API for transaction request messages, slave sends these message types to master for performing required operation.
+ * This interface helps better handle request messages in actor. All messages are send with operations defined in
+ * NetconfProxyDOMTransaction. Messages requiring response are send by ask otherwise with tell.
+ */
+public interface TransactionRequest extends Serializable {
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+Copyright © 2016 Cisco Systems, Inc. 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
+-->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+ odl:use-default-for-reference-types="true">
+
+ <reference id="dataBroker"
+ interface="org.opendaylight.controller.md.sal.binding.api.DataBroker"/>
+ <reference id="rpcRegistry"
+ interface="org.opendaylight.controller.sal.binding.api.RpcProviderRegistry"/>
+ <reference id="clusterSingletonService"
+ interface="org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider"/>
+ <reference id="bindingAwareBroker"
+ interface="org.opendaylight.controller.sal.binding.api.BindingAwareBroker"/>
+ <reference id="keepAliveExecutor"
+ interface="org.opendaylight.controller.config.threadpool.ScheduledThreadPool"/>
+ <reference id="processingExecutor"
+ interface="org.opendaylight.controller.config.threadpool.ThreadPool"/>
+ <reference id="domBroker"
+ interface="org.opendaylight.controller.sal.core.api.Broker"/>
+ <reference id="actorSystemProvider"
+ interface="org.opendaylight.controller.cluster.ActorSystemProvider"/>
+ <reference id="eventExecutor"
+ interface="io.netty.util.concurrent.EventExecutor"
+ odl:type="global-event-executor"/>
+ <reference id="clientDispatcherDependency"
+ interface="org.opendaylight.netconf.client.NetconfClientDispatcher"/>
+
+ <bean id="netconfTopologyManager"
+ class="org.opendaylight.netconf.topology.singleton.impl.NetconfTopologyManager"
+ init-method="init" destroy-method="close">
+ <argument ref="dataBroker"/>
+ <argument ref="rpcRegistry"/>
+ <argument ref="clusterSingletonService"/>
+ <argument ref="bindingAwareBroker"/>
+ <argument ref="keepAliveExecutor"/>
+ <argument ref="processingExecutor"/>
+ <argument ref="domBroker"/>
+ <argument ref="actorSystemProvider"/>
+ <argument ref="eventExecutor"/>
+ <argument ref="clientDispatcherDependency"/>
+ <argument value="topology-netconf"/>
+ </bean>
+ <service ref="netconfTopologyManager"
+ interface="org.opendaylight.netconf.topology.singleton.api.NetconfTopologySingletonService"/>
+
+</blueprint>
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY;
+
+import akka.actor.ActorContext;
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Props;
+import akka.pattern.Patterns;
+import akka.testkit.JavaTestKit;
+import akka.testkit.TestActorRef;
+import akka.util.Timeout;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.opendaylight.controller.cluster.schema.provider.impl.YangTextSchemaSourceSerializationProxy;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.impl.actors.NetconfNodeActor;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
+import org.opendaylight.netconf.topology.singleton.messages.AskForMasterMountPoint;
+import org.opendaylight.netconf.topology.singleton.messages.CreateInitialMasterActorData;
+import org.opendaylight.netconf.topology.singleton.messages.MasterActorDataInitialized;
+import org.opendaylight.netconf.topology.singleton.messages.RefreshSetupMasterActorData;
+import org.opendaylight.netconf.topology.singleton.messages.RegisterMountPoint;
+import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import scala.concurrent.Await;
+import scala.concurrent.Future;
+import scala.concurrent.duration.Duration;
+
+public class NetconfNodeActorTest {
+
+ private static final Timeout TIMEOUT = new Timeout(Duration.create(5, "seconds"));
+ private static ActorSystem system;
+
+ @Rule
+ public final ExpectedException exception = ExpectedException.none();
+
+ private ActorRef masterRef;
+ private RemoteDeviceId remoteDeviceId;
+
+ @Before
+ public void setup() throws UnknownHostException {
+
+ remoteDeviceId = new RemoteDeviceId("netconf-topology",
+ new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 9999));
+
+ final NetconfTopologySetup setup = mock(NetconfTopologySetup.class);
+
+ final Props props = NetconfNodeActor.props(setup, remoteDeviceId, DEFAULT_SCHEMA_REPOSITORY,
+ DEFAULT_SCHEMA_REPOSITORY);
+
+ system = ActorSystem.create();
+
+ masterRef = TestActorRef.create(system, props, "master_messages");
+ }
+
+ @After
+ public void teardown() {
+ JavaTestKit.shutdownActorSystem(system);
+ system = null;
+ }
+
+ @Test
+ public void testInitDataMessages() throws Exception {
+
+ final DOMDataBroker domDataBroker = mock(DOMDataBroker.class);
+ final List<SourceIdentifier> sourceIdentifiers = Lists.newArrayList();
+
+ /* Test init master data */
+
+ final Future<Object> initialDataToActor =
+ Patterns.ask(masterRef, new CreateInitialMasterActorData(domDataBroker, sourceIdentifiers),
+ TIMEOUT);
+
+ final Object success = Await.result(initialDataToActor, TIMEOUT.duration());
+ assertTrue(success instanceof MasterActorDataInitialized);
+
+
+ /* Test refresh master data */
+
+ final RemoteDeviceId remoteDeviceId2 = new RemoteDeviceId("netconf-topology2",
+ new InetSocketAddress(InetAddress.getByName("127.0.0.2"), 9999));
+
+ final NetconfTopologySetup setup2 = mock(NetconfTopologySetup.class);
+
+ final Future<Object> refreshDataToActor =
+ Patterns.ask(masterRef, new RefreshSetupMasterActorData(setup2, remoteDeviceId2),
+ TIMEOUT);
+
+ final Object success2 = Await.result(refreshDataToActor, TIMEOUT.duration());
+ assertTrue(success2 instanceof MasterActorDataInitialized);
+
+ }
+
+ @Test
+ public void testRegisterMountPointMessage() throws Exception {
+
+ final DOMDataBroker domDataBroker = mock(DOMDataBroker.class);
+ final List<SourceIdentifier> sourceIdentifiers =
+ Lists.newArrayList(SourceIdentifier.create("testID", Optional.absent()));
+
+ // init master data
+
+ final Future<Object> initialDataToActor =
+ Patterns.ask(masterRef, new CreateInitialMasterActorData(domDataBroker, sourceIdentifiers),
+ TIMEOUT);
+
+ final Object successInit = Await.result(initialDataToActor, TIMEOUT.duration());
+
+ assertTrue(successInit instanceof MasterActorDataInitialized);
+
+ // test if slave get right identifiers from master
+
+ final Future<Object> registerMountPointFuture =
+ Patterns.ask(masterRef, new AskForMasterMountPoint(),
+ TIMEOUT);
+
+ final RegisterMountPoint success =
+ (RegisterMountPoint) Await.result(registerMountPointFuture, TIMEOUT.duration());
+
+ assertEquals(sourceIdentifiers, success.getSourceIndentifiers());
+
+ }
+
+ @Test
+ public void testYangTextSchemaSourceRequestMessage() throws Exception {
+ final SchemaRepository schemaRepository = mock(SchemaRepository.class);
+ final SourceIdentifier sourceIdentifier = SourceIdentifier.create("testID", Optional.absent());
+ final Props props = NetconfNodeActor.props(mock(NetconfTopologySetup.class), remoteDeviceId,
+ DEFAULT_SCHEMA_REPOSITORY, schemaRepository);
+
+ final ActorRef actorRefSchemaRepo = TestActorRef.create(system, props, "master_mocked_schema_repository");
+ final ActorContext actorContext = mock(ActorContext.class);
+ doReturn(system.dispatcher()).when(actorContext).dispatcher();
+
+ final ProxyYangTextSourceProvider proxyYang =
+ new ProxyYangTextSourceProvider(actorRefSchemaRepo, actorContext);
+ // test if asking for source is resolved and sended back
+
+ final YangTextSchemaSource yangTextSchemaSource = new YangTextSchemaSource(sourceIdentifier) {
+ @Override
+ protected MoreObjects.ToStringHelper addToStringAttributes(MoreObjects.ToStringHelper toStringHelper) {
+ return null;
+ }
+
+ @Override
+ public InputStream openStream() throws IOException {
+ return new ByteArrayInputStream("YANG".getBytes());
+ }
+ };
+
+
+ final CheckedFuture<YangTextSchemaSource, SchemaSourceException> result =
+ Futures.immediateCheckedFuture(yangTextSchemaSource);
+
+ doReturn(result).when(schemaRepository).getSchemaSource(sourceIdentifier, YangTextSchemaSource.class);
+
+ final Future<YangTextSchemaSourceSerializationProxy> resolvedSchema =
+ proxyYang.getYangTextSchemaSource(sourceIdentifier);
+
+ final YangTextSchemaSourceSerializationProxy success = Await.result(resolvedSchema, TIMEOUT.duration());
+
+ assertEquals(sourceIdentifier, success.getRepresentation().getIdentifier());
+ assertEquals("YANG", convertStreamToString(success.getRepresentation().openStream()));
+
+
+ // test if asking for source is missing
+ exception.expect(MissingSchemaSourceException.class);
+
+ final SchemaSourceException schemaSourceException =
+ new MissingSchemaSourceException("Fail", sourceIdentifier);
+
+ final CheckedFuture<YangTextSchemaSource, SchemaSourceException> resultFail =
+ Futures.immediateFailedCheckedFuture(schemaSourceException);
+
+ doReturn(resultFail).when(schemaRepository).getSchemaSource(sourceIdentifier, YangTextSchemaSource.class);
+
+ final Future<YangTextSchemaSourceSerializationProxy> failedSchema =
+ proxyYang.getYangTextSchemaSource(sourceIdentifier);
+
+ Await.result(failedSchema, TIMEOUT.duration());
+
+ }
+
+ private String convertStreamToString(java.io.InputStream is) {
+ java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
+ return s.hasNext() ? s.next() : "";
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl;
+
+import static junit.framework.TestCase.assertFalse;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.DELETE;
+import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.WRITE;
+
+import com.google.common.util.concurrent.Futures;
+import io.netty.util.concurrent.EventExecutor;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.controller.cluster.ActorSystemProvider;
+import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
+import org.opendaylight.controller.config.threadpool.ThreadPool;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
+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.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
+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.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class NetconfTopologyManagerTest {
+
+ private final String topologyId = "topologyID";
+ private NetconfTopologyManager netconfTopologyManager;
+
+ @Mock
+ private DataBroker dataBroker;
+
+ @Mock
+ private ClusterSingletonServiceProvider clusterSingletonServiceProvider;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+
+ final RpcProviderRegistry rpcProviderRegistry = mock(RpcProviderRegistry.class);
+ final BindingAwareBroker bindingAwareBroker = mock(BindingAwareBroker.class);
+ final ScheduledThreadPool keepaliveExecutor = mock(ScheduledThreadPool.class);
+ final ThreadPool processingExecutor = mock(ThreadPool.class);
+ final Broker domBroker = mock(Broker.class);
+ final ActorSystemProvider actorSystemProvider = mock(ActorSystemProvider.class);
+ final EventExecutor eventExecutor = mock(EventExecutor.class);
+ final NetconfClientDispatcher clientDispatcher = mock(NetconfClientDispatcher.class);
+
+ netconfTopologyManager = new NetconfTopologyManager(dataBroker, rpcProviderRegistry,
+ clusterSingletonServiceProvider, bindingAwareBroker, keepaliveExecutor, processingExecutor, domBroker,
+ actorSystemProvider, eventExecutor, clientDispatcher, topologyId);
+ }
+ @Test
+ public void testWriteConfiguration() throws Exception {
+
+ final ClusterSingletonServiceRegistration clusterRegistration = mock(ClusterSingletonServiceRegistration.class);
+
+ final Field fieldContexts = NetconfTopologyManager.class.getDeclaredField("contexts");
+ fieldContexts.setAccessible(true);
+ @SuppressWarnings("unchecked")
+ final Map<InstanceIdentifier<Node>, NetconfTopologyContext> contexts =
+ (Map<InstanceIdentifier<Node>, NetconfTopologyContext>) fieldContexts.get(netconfTopologyManager);
+
+ final Field fieldClusterRegistrations = NetconfTopologyManager.class.getDeclaredField("clusterRegistrations");
+ fieldClusterRegistrations.setAccessible(true);
+ @SuppressWarnings("unchecked")
+ final Map<InstanceIdentifier<Node>, ClusterSingletonServiceRegistration> clusterRegistrations =
+ (Map<InstanceIdentifier<Node>, ClusterSingletonServiceRegistration>)
+ fieldClusterRegistrations.get(netconfTopologyManager);
+
+ final Collection<DataTreeModification<Node>> changes = new ArrayList<>();
+
+ final InstanceIdentifier<Node> instanceIdentifier = NetconfTopologyUtils.createTopologyNodeListPath(
+ new NodeKey(new NodeId("node-id-1")),"topology-1");
+
+ final InstanceIdentifier<Node> instanceIdentifierDiferent = NetconfTopologyUtils.createTopologyNodeListPath(
+ new NodeKey(new NodeId("node-id-2")),"topology-2");
+
+ final DataTreeIdentifier<Node> rootIdentifier =
+ new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
+
+ final DataTreeIdentifier<Node> rootIdentifierDifferent =
+ new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, instanceIdentifierDiferent);
+
+ @SuppressWarnings("unchecked")
+ final DataObjectModification<Node> objectModification = mock(DataObjectModification.class);
+
+ final NetconfNode netconfNode = new NetconfNodeBuilder()
+ .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
+ .setPort(new PortNumber(9999))
+ .setReconnectOnChangedSchema(true)
+ .setDefaultRequestTimeoutMillis(1000L)
+ .setBetweenAttemptsTimeoutMillis(100)
+ .setSchemaless(false)
+ .setTcpOnly(false)
+ .build();
+ final Node node = new NodeBuilder().setNodeId(new NodeId("node-id"))
+ .addAugmentation(NetconfNode.class, netconfNode).build();
+
+ final Identifier key = new NodeKey(new NodeId("node-id"));
+
+ @SuppressWarnings("unchecked")
+ final InstanceIdentifier.IdentifiableItem<Node, NodeKey> pathArgument =
+ new InstanceIdentifier.IdentifiableItem(Node.class, key);
+
+
+ // testing WRITE on two identical rootIdentifiers and one different
+
+ changes.add(new CustomTreeModification(rootIdentifier, objectModification));
+ changes.add(new CustomTreeModification(rootIdentifier, objectModification));
+ changes.add(new CustomTreeModification(rootIdentifierDifferent, objectModification));
+
+ doReturn(WRITE).when(objectModification).getModificationType();
+ doReturn(node).when(objectModification).getDataAfter();
+ doReturn(pathArgument).when(objectModification).getIdentifier();
+ doReturn(clusterRegistration).when(clusterSingletonServiceProvider).registerClusterSingletonService(any());
+
+ netconfTopologyManager.onDataTreeChanged(changes);
+
+ verify(clusterSingletonServiceProvider, times(2)).registerClusterSingletonService(any());
+
+ // only two created contexts
+ assertEquals(2, contexts.size());
+ assertTrue(contexts.containsKey(rootIdentifier.getRootIdentifier()));
+ assertTrue(contexts.containsKey(rootIdentifierDifferent.getRootIdentifier()));
+
+ // only two created cluster registrations
+ assertEquals(2, contexts.size());
+ assertTrue(clusterRegistrations.containsKey(rootIdentifier.getRootIdentifier()));
+ assertTrue(clusterRegistrations.containsKey(rootIdentifierDifferent.getRootIdentifier()));
+
+ // after delete there should be no context and clustered registrations
+ doReturn(DELETE).when(objectModification).getModificationType();
+
+ doNothing().when(clusterRegistration).close();
+
+ netconfTopologyManager.onDataTreeChanged(changes);
+
+ verify(clusterRegistration, times(2)).close();
+
+ // empty map of contexts
+ assertTrue(contexts.isEmpty());
+ assertFalse(contexts.containsKey(rootIdentifier.getRootIdentifier()));
+ assertFalse(contexts.containsKey(rootIdentifierDifferent.getRootIdentifier()));
+
+ // empty map of clustered registrations
+ assertTrue(clusterRegistrations.isEmpty());
+ assertFalse(clusterRegistrations.containsKey(rootIdentifier.getRootIdentifier()));
+ assertFalse(clusterRegistrations.containsKey(rootIdentifierDifferent.getRootIdentifier()));
+
+ }
+
+ @Test
+ public void testRegisterDataTreeChangeListener() {
+
+ final WriteTransaction wtx = mock(WriteTransaction.class);
+
+ doReturn(wtx).when(dataBroker).newWriteOnlyTransaction();
+ doNothing().when(wtx).merge(any(), any(), any());
+ doReturn(Futures.immediateCheckedFuture(null)).when(wtx).submit();
+ doReturn(null).when(dataBroker).registerDataChangeListener(any(), any(), any(), any());
+
+ netconfTopologyManager.init();
+
+ // verify if listener is called with right parameters = registered on right path
+
+ verify(dataBroker, times(1)).registerDataTreeChangeListener(
+ new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, NetconfTopologyUtils
+ .createTopologyListPath(topologyId).child(Node.class)), netconfTopologyManager);
+
+ }
+
+ @Test
+ public void testClose() throws Exception {
+
+ final Field fieldContexts = NetconfTopologyManager.class.getDeclaredField("contexts");
+ fieldContexts.setAccessible(true);
+ @SuppressWarnings("unchecked")
+ final Map<InstanceIdentifier<Node>, NetconfTopologyContext> contexts =
+ (Map<InstanceIdentifier<Node>, NetconfTopologyContext>) fieldContexts.get(netconfTopologyManager);
+
+ final Field fieldClusterRegistrations = NetconfTopologyManager.class.getDeclaredField("clusterRegistrations");
+ fieldClusterRegistrations.setAccessible(true);
+ @SuppressWarnings("unchecked")
+ final Map<InstanceIdentifier<Node>, ClusterSingletonServiceRegistration> clusterRegistrations =
+ (Map<InstanceIdentifier<Node>, ClusterSingletonServiceRegistration>)
+ fieldClusterRegistrations.get(netconfTopologyManager);
+
+ final InstanceIdentifier<Node> instanceIdentifier = NetconfTopologyUtils.createTopologyNodeListPath(
+ new NodeKey(new NodeId("node-id-1")),"topology-1");
+
+
+ final NetconfTopologyContext context = mock(NetconfTopologyContext.class);
+ final ClusterSingletonServiceRegistration clusterRegistration =
+ mock(ClusterSingletonServiceRegistration.class);
+ contexts.put(instanceIdentifier, context);
+ clusterRegistrations.put(instanceIdentifier, clusterRegistration);
+
+ doNothing().when(context).closeFinal();
+ doNothing().when(clusterRegistration).close();
+
+ netconfTopologyManager.close();
+ verify(context, times(1)).closeFinal();
+ verify(clusterRegistration, times(1)).close();
+
+ assertTrue(contexts.isEmpty());
+ assertTrue(clusterRegistrations.isEmpty());
+
+ }
+
+ private class CustomTreeModification implements DataTreeModification<Node> {
+
+ private final DataTreeIdentifier<Node> rootPath;
+ private final DataObjectModification<Node> rootNode;
+
+ CustomTreeModification(DataTreeIdentifier<Node> rootPath, DataObjectModification<Node> rootNode) {
+ this.rootPath = rootPath;
+ this.rootNode = rootNode;
+ }
+
+ @Nonnull
+ @Override
+ public DataTreeIdentifier<Node> getRootPath() {
+ return rootPath;
+ }
+
+ @Nonnull
+ @Override
+ public DataObjectModification<Node> getRootNode() {
+ return rootNode;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import io.netty.util.concurrent.EventExecutor;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.concurrent.ExecutorService;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
+import org.opendaylight.controller.config.threadpool.ThreadPool;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
+import org.opendaylight.netconf.sal.connect.netconf.sal.KeepaliveSalFacade;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfConnectorDTO;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
+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.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
+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.credentials.Credentials;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPasswordBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+
+public class RemoteDeviceConnectorImplTest {
+
+ private static final NodeId NODE_ID = new NodeId("testing-node");
+ private static final String TOPOLOGY_ID = "testing-topology";
+
+ @Mock
+ private DataBroker dataBroker;
+
+ @Mock
+ private RpcProviderRegistry rpcProviderRegistry;
+
+ @Mock
+ private ClusterSingletonServiceProvider clusterSingletonServiceProvider;
+
+ @Mock
+ private BindingAwareBroker bindingAwareBroker;
+
+ @Mock
+ private ScheduledThreadPool keepaliveExecutor;
+
+ @Mock
+ private ThreadPool processingExecutor;
+
+ @Mock
+ private Broker domBroker;
+
+ @Mock
+ private ActorSystem actorSystem;
+
+ @Mock
+ private EventExecutor eventExecutor;
+
+ @Mock
+ private NetconfClientDispatcher clientDispatcher;
+
+ private NetconfTopologySetup.NetconfTopologySetupBuilder builder;
+ private RemoteDeviceId remoteDeviceId;
+
+ @Before
+ public void setUp() throws UnknownHostException {
+ initMocks(this);
+
+ remoteDeviceId = new RemoteDeviceId(TOPOLOGY_ID,
+ new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 9999));
+
+ builder = new NetconfTopologySetup.NetconfTopologySetupBuilder();
+ builder.setDataBroker(dataBroker);
+ builder.setRpcProviderRegistry(rpcProviderRegistry);
+ builder.setClusterSingletonServiceProvider(clusterSingletonServiceProvider);
+ builder.setBindingAwareBroker(bindingAwareBroker);
+ builder.setKeepaliveExecutor(keepaliveExecutor);
+ builder.setProcessingExecutor(processingExecutor);
+ builder.setDomBroker(domBroker);
+ builder.setActorSystem(actorSystem);
+ builder.setEventExecutor(eventExecutor);
+ builder.setNetconfClientDispatcher(clientDispatcher);
+ builder.setTopologyId(TOPOLOGY_ID);
+
+ }
+
+ @Test
+ public void testStopRemoteDeviceConnection() {
+ final Credentials credentials = new LoginPasswordBuilder().setPassword("admin").setUsername("admin").build();
+ final NetconfNode netconfNode = new NetconfNodeBuilder()
+ .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
+ .setPort(new PortNumber(9999))
+ .setReconnectOnChangedSchema(true)
+ .setDefaultRequestTimeoutMillis(1000L)
+ .setBetweenAttemptsTimeoutMillis(100)
+ .setSchemaless(false)
+ .setTcpOnly(false)
+ .setCredentials(credentials)
+ .build();
+ final Node node = new NodeBuilder().setNodeId(NODE_ID).addAugmentation(NetconfNode.class, netconfNode).build();
+
+ builder.setNode(node);
+
+
+ final NetconfDeviceCommunicator communicator = mock (NetconfDeviceCommunicator.class);
+ final RemoteDeviceHandler salFacade = mock(RemoteDeviceHandler.class);
+
+ final TestingRemoteDeviceConnectorImpl remoteDeviceConnection =
+ new TestingRemoteDeviceConnectorImpl(builder.build(), remoteDeviceId, communicator, salFacade);
+
+ final ActorRef masterRef = mock(ActorRef.class);
+
+ remoteDeviceConnection.startRemoteDeviceConnection(masterRef);
+
+ remoteDeviceConnection.stopRemoteDeviceConnection();
+
+ verify(communicator, times(1)).close();
+ verify(salFacade, times(1)).close();
+
+ }
+
+ @Test
+ public void testMasterSalFacade() throws UnknownHostException {
+ final ExecutorService executorService = mock(ExecutorService.class);
+ doReturn(executorService).when(processingExecutor).getExecutor();
+
+ final Credentials credentials = new LoginPasswordBuilder().setPassword("admin").setUsername("admin").build();
+ final NetconfNode netconfNode = new NetconfNodeBuilder()
+ .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
+ .setPort(new PortNumber(9999))
+ .setReconnectOnChangedSchema(true)
+ .setDefaultRequestTimeoutMillis(1000L)
+ .setBetweenAttemptsTimeoutMillis(100)
+ .setSchemaless(false)
+ .setTcpOnly(false)
+ .setCredentials(credentials)
+ .build();
+
+ final RemoteDeviceConnectorImpl remoteDeviceConnection =
+ new RemoteDeviceConnectorImpl(builder.build(), remoteDeviceId);
+
+ final ActorRef masterRef = mock(ActorRef.class);
+
+ final NetconfConnectorDTO connectorDTO =
+ remoteDeviceConnection.createDeviceCommunicator(NODE_ID, netconfNode, masterRef);
+
+ assertTrue(connectorDTO.getFacade() instanceof MasterSalFacade);
+ }
+
+ @Test
+ public void testKeapAliveFacade() throws UnknownHostException {
+ final ExecutorService executorService = mock(ExecutorService.class);
+ doReturn(executorService).when(processingExecutor).getExecutor();
+
+ final Credentials credentials = new LoginPasswordBuilder().setPassword("admin").setUsername("admin").build();
+ final NetconfNode netconfNode = new NetconfNodeBuilder()
+ .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
+ .setPort(new PortNumber(9999))
+ .setReconnectOnChangedSchema(true)
+ .setDefaultRequestTimeoutMillis(1000L)
+ .setBetweenAttemptsTimeoutMillis(100)
+ .setSchemaless(false)
+ .setTcpOnly(false)
+ .setCredentials(credentials)
+ .setKeepaliveDelay(1L)
+ .build();
+
+ final RemoteDeviceId remoteDeviceId = new RemoteDeviceId(TOPOLOGY_ID,
+ new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 9999));
+
+ final RemoteDeviceConnectorImpl remoteDeviceConnection =
+ new RemoteDeviceConnectorImpl(builder.build(), remoteDeviceId);
+
+ final ActorRef masterRef = mock(ActorRef.class);
+
+ final NetconfConnectorDTO connectorDTO =
+ remoteDeviceConnection.createDeviceCommunicator(NODE_ID, netconfNode, masterRef);
+
+ assertTrue(connectorDTO.getFacade() instanceof KeepaliveSalFacade);
+ }
+
+ @Test
+ public void testGetClientConfig() throws UnknownHostException {
+ final NetconfClientSessionListener listener = mock(NetconfClientSessionListener.class);
+ final Host host = new Host(new IpAddress(new Ipv4Address("127.0.0.1")));
+ final PortNumber portNumber = new PortNumber(9999);
+ final NetconfNode testingNode = new NetconfNodeBuilder()
+ .setConnectionTimeoutMillis(1000L)
+ .setDefaultRequestTimeoutMillis(2000L)
+ .setHost(host)
+ .setPort(portNumber)
+ .setCredentials(new LoginPasswordBuilder()
+ .setUsername("testuser")
+ .setPassword("testpassword").build())
+ .setTcpOnly(true)
+ .build();
+
+ final RemoteDeviceConnectorImpl remoteDeviceConnection =
+ new RemoteDeviceConnectorImpl(builder.build(), remoteDeviceId);
+
+ final NetconfReconnectingClientConfiguration defaultClientConfig =
+ remoteDeviceConnection.getClientConfig(listener, testingNode);
+
+ assertEquals(defaultClientConfig.getConnectionTimeoutMillis().longValue(), 1000L);
+ assertEquals(defaultClientConfig.getAddress(), new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 9999));
+ assertSame(defaultClientConfig.getSessionListener(), listener);
+ assertEquals(defaultClientConfig.getAuthHandler().getUsername(), "testuser");
+ assertEquals(defaultClientConfig.getProtocol(), NetconfClientConfiguration.NetconfClientProtocol.TCP);
+ }
+
+ @Test
+ public void testSchemaResourceDTO() throws UnknownHostException {
+ final ExecutorService executorService = mock(ExecutorService.class);
+ doReturn(executorService).when(processingExecutor).getExecutor();
+
+ final Credentials credentials = new LoginPasswordBuilder().setPassword("admin").setUsername("admin").build();
+ final NetconfNode netconfNode = new NetconfNodeBuilder()
+ .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
+ .setPort(new PortNumber(9999))
+ .setReconnectOnChangedSchema(true)
+ .setDefaultRequestTimeoutMillis(1000L)
+ .setBetweenAttemptsTimeoutMillis(100)
+ .setSchemaless(false)
+ .setTcpOnly(false)
+ .setCredentials(credentials)
+ .setSchemaCacheDirectory("schemas-test")
+ .build();
+
+ final RemoteDeviceConnectorImpl remoteDeviceConnection =
+ new RemoteDeviceConnectorImpl(builder.build(), remoteDeviceId);
+
+ final ActorRef masterRef = mock(ActorRef.class);
+
+ remoteDeviceConnection.createDeviceCommunicator(NODE_ID, netconfNode, masterRef);
+
+ assertTrue(remoteDeviceConnection.getSchemaResourcesDTOs().containsKey("schemas-test"));
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+
+import akka.actor.ActorRef;
+import com.google.common.util.concurrent.Futures;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfConnectorDTO;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+
+class TestingRemoteDeviceConnectorImpl extends RemoteDeviceConnectorImpl {
+
+ private final NetconfDeviceCommunicator communicator;
+ private final RemoteDeviceHandler salFacade;
+
+ TestingRemoteDeviceConnectorImpl(final NetconfTopologySetup netconfTopologyDeviceSetup,
+ final RemoteDeviceId remoteDeviceId,
+ final NetconfDeviceCommunicator communicator,
+ final RemoteDeviceHandler salFacade) {
+ super(netconfTopologyDeviceSetup, remoteDeviceId);
+ this.communicator = communicator;
+ this.salFacade = salFacade;
+ }
+
+ @Override
+ public NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId, final NetconfNode node,
+ final ActorRef deviceContextActorRef) {
+ final NetconfConnectorDTO connectorDTO = new NetconfConnectorDTO(communicator, salFacade);
+ doReturn(Futures.immediateCheckedFuture(null)).when(communicator).initializeRemoteConnection(any(), any());
+
+ return connectorDTO;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl.tx;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.MockitoAnnotations.initMocks;
+import static org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Props;
+import akka.pattern.Patterns;
+import akka.testkit.JavaTestKit;
+import akka.testkit.TestActorRef;
+import akka.util.Timeout;
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mock;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.api.NetconfDOMTransaction;
+import org.opendaylight.netconf.topology.singleton.impl.NetconfDOMDataBroker;
+import org.opendaylight.netconf.topology.singleton.impl.actors.NetconfNodeActor;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
+import org.opendaylight.netconf.topology.singleton.messages.CreateInitialMasterActorData;
+import org.opendaylight.netconf.topology.singleton.messages.MasterActorDataInitialized;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import scala.concurrent.Await;
+import scala.concurrent.Future;
+import scala.concurrent.duration.Duration;
+
+public class ReadOnlyTransactionTest {
+ private static final Timeout TIMEOUT = new Timeout(Duration.create(5, "seconds"));
+ private static final int TIMEOUT_SEC = 5;
+ private static ActorSystem system;
+
+ @Rule
+ public final ExpectedException exception = ExpectedException.none();
+
+ private ActorRef masterRef;
+ private NetconfDOMDataBroker slaveDataBroker;
+ private DOMDataBroker masterDataBroker;
+ private List<SourceIdentifier> sourceIdentifiers;
+
+ @Mock
+ private DOMDataReadOnlyTransaction readTx;
+
+ @Before
+ public void setup() throws UnknownHostException {
+ initMocks(this);
+
+ system = ActorSystem.create();
+
+ final RemoteDeviceId remoteDeviceId = new RemoteDeviceId("netconf-topology",
+ new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 9999));
+
+ final NetconfTopologySetup setup = mock(NetconfTopologySetup.class);
+ final Props props = NetconfNodeActor.props(setup, remoteDeviceId, DEFAULT_SCHEMA_REPOSITORY,
+ DEFAULT_SCHEMA_REPOSITORY);
+
+ masterRef = TestActorRef.create(system, props, "master_read");
+
+ sourceIdentifiers = Lists.newArrayList();
+
+ // Create master data broker
+
+ final DOMDataBroker delegateDataBroker = mock(DOMDataBroker.class);
+ readTx = mock(DOMDataReadOnlyTransaction.class);
+
+ doReturn(readTx).when(delegateDataBroker).newReadOnlyTransaction();
+
+ final NetconfDOMTransaction masterDOMTransactions =
+ new NetconfMasterDOMTransaction(remoteDeviceId, delegateDataBroker);
+
+ masterDataBroker =
+ new NetconfDOMDataBroker(system, remoteDeviceId, masterDOMTransactions);
+
+ // Create slave data broker for testing proxy
+
+ final NetconfDOMTransaction proxyDOMTransactions =
+ new NetconfProxyDOMTransaction(remoteDeviceId, system, masterRef);
+
+ slaveDataBroker = new NetconfDOMDataBroker(system, remoteDeviceId, proxyDOMTransactions);
+
+
+ }
+
+ @After
+ public void teardown() {
+ JavaTestKit.shutdownActorSystem(system);
+ system = null;
+ }
+
+ @Test
+ public void testRead() throws Exception {
+
+ /* Initialize data on master */
+
+ initializeDataTest();
+
+ final YangInstanceIdentifier instanceIdentifier = YangInstanceIdentifier.EMPTY;
+ final LogicalDatastoreType storeType = LogicalDatastoreType.CONFIGURATION;
+
+ // Message: EmptyReadResponse
+
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> resultEmpty =
+ Futures.immediateCheckedFuture(Optional.absent());
+
+ doReturn(resultEmpty).when(readTx).read(storeType, instanceIdentifier);
+
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> resultEmptyResponse =
+ slaveDataBroker.newReadOnlyTransaction().read(storeType,
+ instanceIdentifier);
+
+ final Optional<NormalizedNode<?, ?>> resultEmptyMessage =
+ resultEmptyResponse.checkedGet(TIMEOUT_SEC, TimeUnit.SECONDS);
+
+ assertEquals(resultEmptyMessage, Optional.absent());
+
+ // Message: NormalizedNodeMessage
+
+ final NormalizedNode<?, ?> outputNode = ImmutableContainerNodeBuilder.create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create("TestQname")))
+ .withChild(ImmutableNodes.leafNode(QName.create("NodeQname"), "foo")).build();
+
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> resultNormalizedNodeMessage =
+ Futures.immediateCheckedFuture(Optional.of(outputNode));
+
+ doReturn(resultNormalizedNodeMessage).when(readTx).read(storeType, instanceIdentifier);
+
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> resultNodeMessageResponse =
+ slaveDataBroker.newReadOnlyTransaction().read(storeType, instanceIdentifier);
+
+ final Optional<NormalizedNode<?, ?>> resultNodeMessage =
+ resultNodeMessageResponse.checkedGet(TIMEOUT_SEC, TimeUnit.SECONDS);
+
+ assertTrue(resultNodeMessage.isPresent());
+ assertEquals(resultNodeMessage.get(), outputNode);
+
+ // Message: Throwable
+
+ final ReadFailedException readFailedException = new ReadFailedException("Fail", null);
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> resultThrowable =
+ Futures.immediateFailedCheckedFuture(readFailedException);
+
+ doReturn(resultThrowable).when(readTx).read(storeType, instanceIdentifier);
+
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> resultThrowableResponse =
+ slaveDataBroker.newReadOnlyTransaction().read(storeType, instanceIdentifier);
+
+ exception.expect(ReadFailedException.class);
+ resultThrowableResponse.checkedGet(TIMEOUT_SEC, TimeUnit.SECONDS);
+
+ }
+
+ @Test
+ public void testExist() throws Exception {
+
+ /* Initialize data on master */
+
+ initializeDataTest();
+
+ final YangInstanceIdentifier instanceIdentifier = YangInstanceIdentifier.EMPTY;
+ final LogicalDatastoreType storeType = LogicalDatastoreType.CONFIGURATION;
+
+ // Message: True
+
+ final CheckedFuture<Boolean, ReadFailedException> resultTrue =
+ Futures.immediateCheckedFuture(true);
+
+ doReturn(resultTrue).when(readTx).exists(storeType, instanceIdentifier);
+
+ final CheckedFuture<Boolean, ReadFailedException> trueResponse =
+ slaveDataBroker.newReadOnlyTransaction().exists(storeType, instanceIdentifier);
+
+ final Boolean trueMessage = trueResponse.checkedGet(TIMEOUT_SEC, TimeUnit.SECONDS);
+
+ assertEquals(true, trueMessage);
+
+ // Message: False
+
+ final CheckedFuture<Boolean, ReadFailedException> resultFalse = Futures.immediateCheckedFuture(false);
+
+ doReturn(resultFalse).when(readTx).exists(storeType, instanceIdentifier);
+
+ final CheckedFuture<Boolean, ReadFailedException> falseResponse =
+ slaveDataBroker.newReadOnlyTransaction().exists(storeType,
+ instanceIdentifier);
+
+ final Boolean falseMessage = falseResponse.checkedGet(TIMEOUT_SEC, TimeUnit.SECONDS);
+
+ assertEquals(false, falseMessage);
+
+ // Message: False, result null
+
+ final CheckedFuture<Boolean, ReadFailedException> resultNull = Futures.immediateCheckedFuture(null);
+
+ doReturn(resultNull).when(readTx).exists(storeType, instanceIdentifier);
+
+ final CheckedFuture<Boolean, ReadFailedException> nullResponse =
+ slaveDataBroker.newReadOnlyTransaction().exists(storeType,
+ instanceIdentifier);
+
+ final Boolean nullFalseMessage = nullResponse.checkedGet(TIMEOUT_SEC, TimeUnit.SECONDS);
+
+ assertEquals(false, nullFalseMessage);
+
+ // Message: Throwable
+
+ final ReadFailedException readFailedException = new ReadFailedException("Fail", null);
+ final CheckedFuture<Boolean, ReadFailedException> resultThrowable =
+ Futures.immediateFailedCheckedFuture(readFailedException);
+
+ doReturn(resultThrowable).when(readTx).exists(storeType, instanceIdentifier);
+
+ final CheckedFuture<Boolean, ReadFailedException> resultThrowableResponse =
+ slaveDataBroker.newReadOnlyTransaction().exists(storeType, instanceIdentifier);
+
+ exception.expect(ReadFailedException.class);
+ resultThrowableResponse.checkedGet(TIMEOUT_SEC, TimeUnit.SECONDS);
+
+ }
+
+ private void initializeDataTest() throws Exception {
+ final Future<Object> initialDataToActor =
+ Patterns.ask(masterRef, new CreateInitialMasterActorData(masterDataBroker, sourceIdentifiers),
+ TIMEOUT);
+
+ final Object success = Await.result(initialDataToActor, TIMEOUT.duration());
+
+ assertTrue(success instanceof MasterActorDataInitialized);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl.tx;
+
+import static junit.framework.TestCase.assertNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+import static org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Props;
+import akka.pattern.Patterns;
+import akka.testkit.JavaTestKit;
+import akka.testkit.TestActorRef;
+import akka.util.Timeout;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.netconf.topology.singleton.api.NetconfDOMTransaction;
+import org.opendaylight.netconf.topology.singleton.impl.NetconfDOMDataBroker;
+import org.opendaylight.netconf.topology.singleton.impl.actors.NetconfNodeActor;
+import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
+import org.opendaylight.netconf.topology.singleton.messages.CreateInitialMasterActorData;
+import org.opendaylight.netconf.topology.singleton.messages.MasterActorDataInitialized;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import scala.concurrent.Await;
+import scala.concurrent.Future;
+import scala.concurrent.duration.Duration;
+
+public class WriteOnlyTransactionTest {
+ private static final Timeout TIMEOUT = new Timeout(Duration.create(5, "seconds"));
+ private static final int TIMEOUT_SEC = 5;
+ private static ActorSystem system;
+
+ @Rule
+ public final ExpectedException exception = ExpectedException.none();
+
+ private ActorRef masterRef;
+ private NetconfDOMDataBroker slaveDataBroker;
+ private DOMDataBroker masterDataBroker;
+ private List<SourceIdentifier> sourceIdentifiers;
+
+ @Mock
+ private DOMDataWriteTransaction writeTx;
+
+ @Before
+ public void setup() throws UnknownHostException {
+ initMocks(this);
+
+ system = ActorSystem.create();
+
+ final RemoteDeviceId remoteDeviceId = new RemoteDeviceId("netconf-topology",
+ new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 9999));
+
+ final NetconfTopologySetup setup = mock(NetconfTopologySetup.class);
+ final Props props = NetconfNodeActor.props(setup, remoteDeviceId, DEFAULT_SCHEMA_REPOSITORY,
+ DEFAULT_SCHEMA_REPOSITORY);
+
+ masterRef = TestActorRef.create(system, props, "master_read");
+
+ sourceIdentifiers = Lists.newArrayList();
+
+ // Create master data broker
+
+ final DOMDataBroker delegateDataBroker = mock(DOMDataBroker.class);
+ writeTx = mock(DOMDataWriteTransaction.class);
+ final DOMDataReadOnlyTransaction readTx = mock(DOMDataReadOnlyTransaction.class);
+
+ doReturn(writeTx).when(delegateDataBroker).newWriteOnlyTransaction();
+ doReturn(readTx).when(delegateDataBroker).newReadOnlyTransaction();
+
+ final NetconfDOMTransaction masterDOMTransactions =
+ new NetconfMasterDOMTransaction(remoteDeviceId, delegateDataBroker);
+
+ masterDataBroker =
+ new NetconfDOMDataBroker(system, remoteDeviceId, masterDOMTransactions);
+
+ // Create slave data broker for testing proxy
+
+ final NetconfDOMTransaction proxyDOMTransactions =
+ new NetconfProxyDOMTransaction(remoteDeviceId, system, masterRef);
+
+ slaveDataBroker = new NetconfDOMDataBroker(system, remoteDeviceId, proxyDOMTransactions);
+
+
+ }
+
+ @After
+ public void teardown() {
+ JavaTestKit.shutdownActorSystem(system);
+ system = null;
+ }
+
+ @Test
+ public void testPutMergeDeleteCalls() throws Exception {
+
+ /* Initialize data on master */
+
+ initializeDataTest();
+
+ final YangInstanceIdentifier instanceIdentifier = YangInstanceIdentifier.EMPTY;
+ final LogicalDatastoreType storeType = LogicalDatastoreType.CONFIGURATION;
+ final NormalizedNode<?, ?> testNode = ImmutableContainerNodeBuilder.create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create("TestQname")))
+ .withChild(ImmutableNodes.leafNode(QName.create("NodeQname"), "foo")).build();
+
+ // Test of invoking put on master through slave proxy
+
+ doNothing().when(writeTx).put(storeType, instanceIdentifier, testNode);
+ slaveDataBroker.newWriteOnlyTransaction().put(storeType, instanceIdentifier, testNode);
+
+ verify(writeTx, times(1)).put(storeType, instanceIdentifier, testNode);
+
+ // Test of invoking merge on master through slave proxy
+
+ doNothing().when(writeTx).merge(storeType, instanceIdentifier, testNode);
+ slaveDataBroker.newWriteOnlyTransaction().merge(storeType, instanceIdentifier, testNode);
+
+ verify(writeTx, times(1)).merge(storeType, instanceIdentifier, testNode);
+
+ // Test of invoking delete on master through slave proxy
+
+ doNothing().when(writeTx).delete(storeType, instanceIdentifier);
+ slaveDataBroker.newWriteOnlyTransaction().delete(storeType, instanceIdentifier);
+
+ verify(writeTx, times(1)).delete(storeType, instanceIdentifier);
+
+ }
+
+ @Test
+ public void testSubmit() throws Exception {
+
+ /* Initialize data on master */
+
+ initializeDataTest();
+
+ // Without Tx
+
+ final CheckedFuture<Void,TransactionCommitFailedException> resultSubmit = Futures.immediateCheckedFuture(null);
+ doReturn(resultSubmit).when(writeTx).submit();
+
+ final CheckedFuture<Void, TransactionCommitFailedException> resultSubmitResponse =
+ slaveDataBroker.newWriteOnlyTransaction().submit();
+
+ final Object result= resultSubmitResponse.checkedGet(TIMEOUT_SEC, TimeUnit.SECONDS);
+
+ assertNull(result);
+
+ // With Tx
+
+ doNothing().when(writeTx).delete(any(), any());
+ slaveDataBroker.newWriteOnlyTransaction().delete(LogicalDatastoreType.CONFIGURATION,
+ YangInstanceIdentifier.EMPTY);
+
+ final CheckedFuture<Void,TransactionCommitFailedException> resultSubmitTx = Futures.immediateCheckedFuture(null);
+ doReturn(resultSubmitTx).when(writeTx).submit();
+
+ final CheckedFuture<Void, TransactionCommitFailedException> resultSubmitTxResponse =
+ slaveDataBroker.newWriteOnlyTransaction().submit();
+
+ final Object resultTx = resultSubmitTxResponse.checkedGet(TIMEOUT_SEC, TimeUnit.SECONDS);
+
+ assertNull(resultTx);
+
+ slaveDataBroker.newWriteOnlyTransaction().delete(LogicalDatastoreType.CONFIGURATION,
+ YangInstanceIdentifier.EMPTY);
+
+ final TransactionCommitFailedException throwable = new TransactionCommitFailedException("Fail", null);
+ final CheckedFuture<Void,TransactionCommitFailedException> resultThrowable =
+ Futures.immediateFailedCheckedFuture(throwable);
+
+ doReturn(resultThrowable).when(writeTx).submit();
+
+ final CheckedFuture<Void, TransactionCommitFailedException> resultThrowableResponse =
+ slaveDataBroker.newWriteOnlyTransaction().submit();
+
+ exception.expect(TransactionCommitFailedException.class);
+ resultThrowableResponse.checkedGet(TIMEOUT_SEC, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void testCancel() throws Exception {
+
+ /* Initialize data on master */
+
+ initializeDataTest();
+
+ // Without Tx
+
+ final Boolean resultFalseNoTx = slaveDataBroker.newWriteOnlyTransaction().cancel();
+ assertEquals(false, resultFalseNoTx);
+
+ // With Tx, readWriteTx test
+
+ doNothing().when(writeTx).delete(any(), any());
+ slaveDataBroker.newReadWriteTransaction().delete(LogicalDatastoreType.CONFIGURATION,
+ YangInstanceIdentifier.EMPTY);
+
+ doReturn(true).when(writeTx).cancel();
+
+ final Boolean resultTrue = slaveDataBroker.newWriteOnlyTransaction().cancel();
+ assertEquals(true, resultTrue);
+
+ doReturn(false).when(writeTx).cancel();
+
+ final Boolean resultFalse = slaveDataBroker.newWriteOnlyTransaction().cancel();
+ assertEquals(false, resultFalse);
+
+ }
+
+ private void initializeDataTest() throws Exception {
+ final Future<Object> initialDataToActor =
+ Patterns.ask(masterRef, new CreateInitialMasterActorData(masterDataBroker, sourceIdentifiers),
+ TIMEOUT);
+
+ final Object success = Await.result(initialDataToActor, TIMEOUT.duration());
+
+ assertTrue(success instanceof MasterActorDataInitialized);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.singleton.impl.utils;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+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.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
+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.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class NetconfTopologyUtilTest {
+
+ @Test
+ public void testCreateRemoteDeviceId() {
+ final Host host = new Host(new IpAddress(new Ipv4Address("127.0.0.1")));
+ final NetconfNode netconfNode = new NetconfNodeBuilder().setHost(host).setPort(new PortNumber(9999)).build();
+ final NodeId nodeId = new NodeId("testing-node");
+ final RemoteDeviceId id = NetconfTopologyUtils.createRemoteDeviceId(nodeId, netconfNode);
+
+ assertEquals("testing-node", id.getName());
+ assertEquals(host, id.getHost());
+ assertEquals(9999, id.getAddress().getPort());
+ }
+
+ @Test
+ public void testCreateActorPath() {
+ final String actorPath = NetconfTopologyUtils.createActorPath("member", "name");
+ assertEquals("member/user/name", actorPath);
+ }
+
+ @Test
+ public void testCreateListPath() {
+ final InstanceIdentifier<Node> listPath =
+ NetconfTopologyUtils.createTopologyNodeListPath(new NodeKey(new NodeId("nodeId")), "topologyId");
+
+ assertEquals("nodeId", listPath.firstKeyOf(Node.class).getNodeId().getValue());
+ assertEquals("topologyId", listPath.firstKeyOf(Topology.class).getTopologyId().getValue());
+
+ assertEquals("topologyId", NetconfTopologyUtils.createTopologyNodePath("topologyId").
+ firstKeyOf(Topology.class).getTopologyId().getValue());
+ }
+
+}
<groupId>org.opendaylight.netconf</groupId>
<artifactId>sal-netconf-connector</artifactId>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-clustering-commons</artifactId>
- </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</artifactId>
</dependency>
- <dependency>
- <groupId>org.opendaylight.netconf</groupId>
- <artifactId>abstract-topology</artifactId>
- </dependency>
- <dependency>
- <groupId>com.typesafe</groupId>
- <artifactId>config</artifactId>
- </dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
- <version>1.9.5</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.jayway.awaitility</groupId>
- <artifactId>awaitility</artifactId>
- <version>1.6.5</version>
<scope>test</scope>
</dependency>
<dependency>
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.controller.config.yang.clustered.netconf.topology;
-
-import org.opendaylight.netconf.topology.impl.ClusteredNetconfTopology;
-
-public class ClusteredNetconfTopologyModule extends org.opendaylight.controller.config.yang.clustered.netconf.topology.AbstractClusteredNetconfTopologyModule {
- public ClusteredNetconfTopologyModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
- super(identifier, dependencyResolver);
- }
-
- public ClusteredNetconfTopologyModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.clustered.netconf.topology.ClusteredNetconfTopologyModule oldModule, java.lang.AutoCloseable oldInstance) {
- super(identifier, dependencyResolver, oldModule, oldInstance);
- }
-
- @Override
- public void customValidation() {
- // add custom validation form module attributes here.
- }
-
- @Override
- public java.lang.AutoCloseable createInstance() {
- return new ClusteredNetconfTopology(getTopologyId(),
- getClientDispatcherDependency(),
- getBindingRegistryDependency(),
- getDomRegistryDependency(),
- getEventExecutorDependency(),
- getKeepaliveExecutorDependency(),
- getProcessingExecutorDependency(),
- getSharedSchemaRepositoryDependency(),
- getActorSystemProviderServiceDependency().getActorSystem(),
- getEntityOwnershipServiceDependency());
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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
- */
-
-/*
-* Generated file
-*
-* Generated from: yang module name: clustered-netconf-topology yang module local name: clustered-netconf-topology-impl
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Wed Nov 04 10:59:45 CET 2015
-*
-* Do not modify this file unless it is present under src/main directory
-*/
-package org.opendaylight.controller.config.yang.clustered.netconf.topology;
-public class ClusteredNetconfTopologyModuleFactory extends org.opendaylight.controller.config.yang.clustered.netconf.topology.AbstractClusteredNetconfTopologyModuleFactory {
-
-}
import org.opendaylight.netconf.sal.connect.netconf.sal.KeepaliveSalFacade;
import org.opendaylight.netconf.sal.connect.netconf.schema.YangLibrarySchemaYangSourceProvider;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.netconf.topology.pipeline.TopologyMountPointFacade.ConnectionStatusListenerRegistration;
import org.opendaylight.protocol.framework.ReconnectStrategy;
import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
import org.opendaylight.protocol.framework.TimedReconnectStrategy;
@Override
public abstract void onSessionInitiated(ProviderContext session);
- @Override
- public String getTopologyId() {
- return topologyId;
- }
-
- @Override
- public DataBroker getDataBroker() {
- return dataBroker;
- }
-
@Override
public ListenableFuture<NetconfDeviceCapabilities> connectNode(NodeId nodeId, Node configNode) {
LOG.info("Connecting RemoteDevice{{}} , with config {}", nodeId, configNode);
protected abstract RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(final RemoteDeviceId id, final Broker domBroker, final BindingAwareBroker bindingBroker);
- @Override
- public abstract ConnectionStatusListenerRegistration registerConnectionStatusListener(NodeId node, RemoteDeviceHandler<NetconfSessionPreferences> listener);
-
@Override
public void onSessionInitiated(ProviderSession session) {
mountPointService = session.getService(DOMMountPointService.class);
package org.opendaylight.netconf.topology;
-import akka.actor.ActorContext;
-import akka.actor.ActorRef;
import com.google.common.util.concurrent.ListenableFuture;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.topology.pipeline.TopologyMountPointFacade.ConnectionStatusListenerRegistration;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
public interface NetconfTopology {
- String getTopologyId();
-
- DataBroker getDataBroker();
-
ListenableFuture<NetconfDeviceCapabilities> connectNode(NodeId nodeId, Node configNode);
ListenableFuture<Void> disconnectNode(NodeId nodeId);
- /**
- * register master mount point
- * @param context
- * @param nodeId
- */
- void registerMountPoint(ActorContext context, NodeId nodeId);
-
- /**
- * register slave mountpoint with the provided ActorRef
- * @param context
- * @param nodeId
- * @param masterRef
- */
- void registerMountPoint(ActorContext context, NodeId nodeId, ActorRef masterRef);
-
- void unregisterMountPoint(NodeId nodeId);
-
- ConnectionStatusListenerRegistration registerConnectionStatusListener(NodeId node, RemoteDeviceHandler<NetconfSessionPreferences> listener);
}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.impl;
-
-import akka.actor.ActorContext;
-import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
-import akka.actor.TypedActor;
-import akka.actor.TypedActorExtension;
-import akka.actor.TypedProps;
-import akka.japi.Creator;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import io.netty.util.concurrent.EventExecutor;
-import java.net.InetSocketAddress;
-import java.util.Collection;
-import java.util.Collections;
-import javassist.ClassPool;
-import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
-import org.opendaylight.controller.config.threadpool.ThreadPool;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.controller.sal.core.api.Broker;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
-import org.opendaylight.netconf.client.NetconfClientSessionListener;
-import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
-import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.sal.connect.netconf.sal.KeepaliveSalFacade;
-import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.netconf.topology.AbstractNetconfTopology;
-import org.opendaylight.netconf.topology.NetconfTopology;
-import org.opendaylight.netconf.topology.NodeManagerCallback;
-import org.opendaylight.netconf.topology.NodeManagerCallback.NodeManagerCallbackFactory;
-import org.opendaylight.netconf.topology.SchemaRepositoryProvider;
-import org.opendaylight.netconf.topology.TopologyManager;
-import org.opendaylight.netconf.topology.TopologyManagerCallback;
-import org.opendaylight.netconf.topology.TopologyManagerCallback.TopologyManagerCallbackFactory;
-import org.opendaylight.netconf.topology.example.LoggingSalNodeWriter;
-import org.opendaylight.netconf.topology.pipeline.ClusteredNetconfDevice;
-import org.opendaylight.netconf.topology.pipeline.ClusteredNetconfDeviceCommunicator;
-import org.opendaylight.netconf.topology.pipeline.ClusteredNetconfDeviceCommunicator.NetconfClientSessionListenerRegistration;
-import org.opendaylight.netconf.topology.pipeline.TopologyMountPointFacade;
-import org.opendaylight.netconf.topology.pipeline.TopologyMountPointFacade.ConnectionStatusListenerRegistration;
-import org.opendaylight.netconf.topology.util.BaseTopologyManager;
-import org.opendaylight.netconf.topology.util.NodeRoleChangeStrategy;
-import org.opendaylight.netconf.topology.util.NodeWriter;
-import org.opendaylight.netconf.topology.util.TopologyRoleChangeStrategy;
-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.$YangModuleInfoImpl;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
-import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
-import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
-import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
-import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ClusteredNetconfTopology extends AbstractNetconfTopology implements AutoCloseable {
-
- private static final Logger LOG = LoggerFactory.getLogger(ClusteredNetconfTopology.class);
-
- private final BindingNormalizedNodeCodecRegistry codecRegistry;
-
- private final ActorSystem actorSystem;
- private final EntityOwnershipService entityOwnershipService;
- private TopologyManager topologyManager;
-
- public ClusteredNetconfTopology(final String topologyId, final NetconfClientDispatcher clientDispatcher,
- final BindingAwareBroker bindingAwareBroker, final Broker domBroker,
- final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
- final ThreadPool processingExecutor, final SchemaRepositoryProvider schemaRepositoryProvider,
- final ActorSystem actorSystem, final EntityOwnershipService entityOwnershipService) {
- super(topologyId, clientDispatcher,
- bindingAwareBroker, domBroker, eventExecutor,
- keepaliveExecutor, processingExecutor, schemaRepositoryProvider);
-
- final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
- moduleInfoBackedContext.addModuleInfos(Collections.singletonList($YangModuleInfoImpl.getInstance()));
- final Optional<SchemaContext> schemaContextOptional = moduleInfoBackedContext.tryToCreateSchemaContext();
- Preconditions.checkState(schemaContextOptional.isPresent());
- final SchemaContext topologySchemaCtx = schemaContextOptional.get();
-
- final JavassistUtils javassist = JavassistUtils.forClassPool(ClassPool.getDefault());
- codecRegistry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(javassist));
- codecRegistry.onBindingRuntimeContextUpdated(BindingRuntimeContext.create(moduleInfoBackedContext, topologySchemaCtx));
-
- this.actorSystem = actorSystem;
- this.entityOwnershipService = entityOwnershipService;
- registerToSal(this, this);
- LOG.warn("Clustered netconf topo started");
- }
-
-
-
- @Override
- public void onSessionInitiated(final ProviderContext session) {
- dataBroker = session.getSALService(DataBroker.class);
- final NodeWriter writer = new TopologyNodeWriter(topologyId, dataBroker);
- TypedActorExtension typedActorExtension = TypedActor.get(this.actorSystem);
- LOG.warn("Registering actor on path {}", actorSystem.name() + "/user/" + topologyId);
- topologyManager = typedActorExtension.typedActorOf(new TypedProps<>(TopologyManager.class, new Creator<BaseTopologyManager>() {
- @Override
- public BaseTopologyManager create() throws Exception {
- return new BaseTopologyManager(actorSystem,
- codecRegistry,
- dataBroker,
- topologyId,
- new TopologyCallbackFactory(ClusteredNetconfTopology.this, entityOwnershipService, writer),
- new NetconfNodeOperationalDataAggregator(),
- new LoggingSalNodeWriter(writer),
- new TopologyRoleChangeStrategy(dataBroker, entityOwnershipService, "topology-netconf", "topology-manager"));
- }
- }), topologyId);
- }
-
- @Override
- public void close() throws Exception {
- // close all existing connectors, delete whole topology in datastore?
- for (NetconfConnectorDTO connectorDTO : activeConnectors.values()) {
- connectorDTO.getCommunicator().close();
- }
- activeConnectors.clear();
- }
-
- @Override
- protected NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId,
- final NetconfNode node) {
- //setup default values since default value is not supported in mdsal
- final Long defaultRequestTimeoutMillis = node.getDefaultRequestTimeoutMillis() == null ? DEFAULT_REQUEST_TIMEOUT_MILLIS : node.getDefaultRequestTimeoutMillis();
- 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 ?
- ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(),
- node.getPort().getValue());
- RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address);
-
- RemoteDeviceHandler<NetconfSessionPreferences> salFacade =
- createSalFacade(remoteDeviceId, domBroker, bindingAwareBroker);
-
- if (keepaliveDelay > 0) {
- LOG.warn("Adding keepalive facade, for device {}", nodeId);
- salFacade = new KeepaliveSalFacade(remoteDeviceId, salFacade, keepaliveExecutor.getExecutor(), keepaliveDelay, defaultRequestTimeoutMillis);
- }
-
- final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = setupSchemaCacheDTO(nodeId, node);
-
- final NetconfDevice device = new ClusteredNetconfDevice(schemaResourcesDTO, remoteDeviceId, salFacade,
- processingExecutor.getExecutor(), actorSystem, topologyId, nodeId.getValue(), TypedActor.context(),
- reconnectOnChangedSchema);
-
- final int rpcMessageLimit =
- node.getConcurrentRpcLimit() == null ? DEFAULT_CONCURRENT_RPC_LIMIT : node.getConcurrentRpcLimit();
-
- if (rpcMessageLimit < 1) {
- LOG.info("Concurrent rpc limit is smaller than 1, no limit will be enforced for device {}", remoteDeviceId);
- }
-
- return new NetconfConnectorDTO(new ClusteredNetconfDeviceCommunicator(remoteDeviceId, device, entityOwnershipService, rpcMessageLimit), salFacade);
- }
-
- @Override
- protected RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(final RemoteDeviceId id, final Broker domBroker, final BindingAwareBroker bindingBroker) {
- return new TopologyMountPointFacade(topologyId, id, domBroker, bindingBroker);
- }
-
- @Override
- public void registerMountPoint(final ActorContext context, final NodeId nodeId) {
- ((TopologyMountPointFacade) activeConnectors.get(nodeId).getFacade()).registerMountPoint(actorSystem, context);
- }
-
- @Override
- public void registerMountPoint(final ActorContext context, final NodeId nodeId, final ActorRef masterRef) {
- ((TopologyMountPointFacade) activeConnectors.get(nodeId).getFacade()).registerMountPoint(actorSystem, context, masterRef);
- }
-
- @Override
- public void unregisterMountPoint(final NodeId nodeId) {
- Preconditions.checkState(activeConnectors.containsKey(nodeId), "Cannot unregister nonexistent mountpoint");
- ((TopologyMountPointFacade) activeConnectors.get(nodeId).getFacade()).unregisterMountPoint();
- }
-
- @Override
- public ConnectionStatusListenerRegistration registerConnectionStatusListener(final NodeId node, final RemoteDeviceHandler<NetconfSessionPreferences> listener) {
- Preconditions.checkState(activeConnectors.containsKey(node), "Need to connect a node before a connection listener can be registered");
- return ((TopologyMountPointFacade) activeConnectors.get(node).getFacade()).registerConnectionStatusListener(listener);
- }
-
- public Collection<ProviderFunctionality> getProviderFunctionality() {
- return Collections.emptySet();
- }
-
- public NetconfClientSessionListenerRegistration registerNetconfClientSessionListener(final NodeId node, final NetconfClientSessionListener listener) {
- Preconditions.checkState(activeConnectors.containsKey(node), "Need to connect a node before a session listener can be registered");
- return ((ClusteredNetconfDeviceCommunicator) activeConnectors.get(node).getCommunicator()).registerNetconfClientSessionListener(listener);
- }
-
- static class TopologyCallbackFactory implements TopologyManagerCallbackFactory {
-
- private final NetconfTopology netconfTopology;
- private final EntityOwnershipService entityOwnershipService;
- private final NodeWriter writer;
-
- TopologyCallbackFactory(final NetconfTopology netconfTopology, final EntityOwnershipService entityOwnershipService, final NodeWriter writer) {
- this.netconfTopology = netconfTopology;
- this.entityOwnershipService = entityOwnershipService;
- this.writer = writer;
- }
-
- @Override
- public TopologyManagerCallback create(final ActorSystem actorSystem, final String topologyId) {
- return new NetconfTopologyManagerCallback(actorSystem, topologyId, new NodeCallbackFactory(netconfTopology, entityOwnershipService), new LoggingSalNodeWriter(writer));
- }
- }
-
- private static class NodeCallbackFactory implements NodeManagerCallbackFactory {
-
- private final NetconfTopology netconfTopology;
- private final EntityOwnershipService entityOwnershipService;
-
- NodeCallbackFactory(final NetconfTopology netconfTopology, final EntityOwnershipService entityOwnershipService) {
- this.netconfTopology = netconfTopology;
- this.entityOwnershipService = entityOwnershipService;
- }
-
- @Override
- public NodeManagerCallback create(final String nodeId, final String topologyId, final ActorSystem actorSystem) {
- return new NetconfNodeManagerCallback(nodeId, topologyId, actorSystem, netconfTopology, new NodeRoleChangeStrategy(entityOwnershipService, "netconf-node", nodeId));
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.impl;
-
-import akka.actor.ActorContext;
-import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
-import akka.actor.TypedActor;
-import akka.actor.TypedProps;
-import akka.cluster.Cluster;
-import akka.dispatch.OnComplete;
-import com.google.common.base.Function;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.concurrent.TimeUnit;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
-import org.opendaylight.netconf.api.NetconfMessage;
-import org.opendaylight.netconf.api.NetconfTerminationReason;
-import org.opendaylight.netconf.client.NetconfClientSession;
-import org.opendaylight.netconf.client.NetconfClientSessionListener;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.topology.NetconfTopology;
-import org.opendaylight.netconf.topology.NodeManager;
-import org.opendaylight.netconf.topology.NodeManagerCallback;
-import org.opendaylight.netconf.topology.RoleChangeStrategy;
-import org.opendaylight.netconf.topology.TopologyManager;
-import org.opendaylight.netconf.topology.pipeline.ClusteredNetconfDeviceCommunicator.NetconfClientSessionListenerRegistration;
-import org.opendaylight.netconf.topology.pipeline.TopologyMountPointFacade.ConnectionStatusListenerRegistration;
-import org.opendaylight.netconf.topology.util.BaseNodeManager;
-import org.opendaylight.netconf.topology.util.BaseTopologyManager;
-import org.opendaylight.netconf.topology.util.messages.AnnounceMasterMountPoint;
-import org.opendaylight.netconf.topology.util.messages.AnnounceMasterMountPointDown;
-import org.opendaylight.netconf.util.NetconfTopologyPathCreator;
-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.NetconfNodeConnectionStatus.ConnectionStatus;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.AvailableCapabilitiesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.ClusteredConnectionStatusBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.UnavailableCapabilities;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.UnavailableCapabilitiesBuilder;
-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.clustered.connection.status.NodeStatus.Status;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.clustered.connection.status.NodeStatusBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability.FailureReason;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapabilityBuilder;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import scala.concurrent.Future;
-import scala.concurrent.duration.FiniteDuration;
-
-public class NetconfNodeManagerCallback implements NodeManagerCallback, NetconfClientSessionListener{
-
- private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeManagerCallback.class);
-
- public static final Function<Entry<QName, FailureReason>, UnavailableCapability> UNAVAILABLE_CAPABILITY_TRANSFORMER = new Function<Entry<QName, FailureReason>, UnavailableCapability>() {
- @Override
- public UnavailableCapability apply(final Entry<QName, FailureReason> input) {
- return new UnavailableCapabilityBuilder()
- .setCapability(input.getKey().toString())
- .setFailureReason(input.getValue()).build();
- }
- };
-
- private static final String UNKNOWN_REASON = "Unknown reason";
-
- private boolean isMaster = false;
- private ClusteredNetconfTopology topologyDispatcher;
- private final ActorSystem actorSystem;
- private final Cluster clusterExtension;
-
- private final RoleChangeStrategy roleChangeStrategy;
-
- private String nodeId;
- private String topologyId;
- private TopologyManager topologyManager;
- private NodeManager nodeManager;
- // cached context so that we can use it in callbacks from topology
- private ActorContext cachedContext;
-
- private Node currentConfig;
- private Node currentOperationalNode;
-
- private ConnectionStatusListenerRegistration connectionStatusregistration = null;
- private NetconfClientSessionListenerRegistration sessionListener = null;
-
- private ActorRef masterDataBrokerRef = null;
- private boolean connected = false;
-
- public NetconfNodeManagerCallback(final String nodeId,
- final String topologyId,
- final ActorSystem actorSystem,
- final NetconfTopology topologyDispatcher,
- final RoleChangeStrategy roleChangeStrategy) {
- this.nodeId = nodeId;
- this.topologyId = topologyId;
- this.actorSystem = actorSystem;
- this.clusterExtension = Cluster.get(actorSystem);
- this.topologyDispatcher = (ClusteredNetconfTopology) topologyDispatcher;
- this.roleChangeStrategy = roleChangeStrategy;
-
- final NetconfTopologyPathCreator pathCreator = new NetconfTopologyPathCreator(topologyId);
- final Future<ActorRef> topologyRefFuture = actorSystem.actorSelection(pathCreator.build()).resolveOne(FiniteDuration.create(10L, TimeUnit.SECONDS));
- topologyRefFuture.onComplete(new OnComplete<ActorRef>() {
- @Override
- public void onComplete(Throwable throwable, ActorRef actorRef) throws Throwable {
- if (throwable != null) {
- LOG.warn("Unable to resolve actor for path: {} ", "/user/" + topologyId, throwable);
-
- }
-
- LOG.debug("Actor ref for path {} resolved", "/user/" + topologyId);
- topologyManager = TypedActor.get(actorSystem).typedActorOf(new TypedProps<>(TopologyManager.class, BaseTopologyManager.class), actorRef);
- }
- }, actorSystem.dispatcher());
-
- final Future<ActorRef> nodeRefFuture = actorSystem.actorSelection(pathCreator.withSuffix(nodeId).build()).resolveOne(FiniteDuration.create(10L, TimeUnit.SECONDS));
- nodeRefFuture.onComplete(new OnComplete<ActorRef>() {
- @Override
- public void onComplete(Throwable throwable, ActorRef actorRef) throws Throwable {
- if (throwable != null) {
- LOG.warn("Unable to resolve actor for path: {} ", "/user/" + topologyId + "/" + nodeId, throwable);
- }
- LOG.debug("Actor ref for path {} resolved", "/user/" + topologyId);
- nodeManager = TypedActor.get(actorSystem).typedActorOf(new TypedProps<>(NodeManager.class, BaseNodeManager.class), actorRef);
- }
- }, actorSystem.dispatcher());
- }
-
-
- @Nonnull
- @Override public Node getInitialState(@Nonnull final NodeId nodeId,
- @Nonnull final Node configNode) {
- final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class);
-
- final Node initialNode = new NodeBuilder()
- .setNodeId(nodeId)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setHost(netconfNode.getHost())
- .setPort(netconfNode.getPort())
- .setConnectionStatus(ConnectionStatus.Connecting)
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(
- Lists.newArrayList(
- new NodeStatusBuilder()
- .setNode(clusterExtension.selfAddress().toString())
- .setStatus(Status.Unavailable)
- .build()))
- .build())
- .build())
- .build();
-
- if (currentOperationalNode == null) {
- currentOperationalNode = initialNode;
- }
-
- return initialNode;
- }
-
- @Nonnull @Override public Node getFailedState(@Nonnull final NodeId nodeId,
- @Nullable final Node configNode) {
- final NetconfNode netconfNode = configNode == null ? currentOperationalNode.getAugmentation(NetconfNode.class) : configNode.getAugmentation(NetconfNode.class);
-
- final Node failedNode = new NodeBuilder()
- .setNodeId(nodeId)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setHost(netconfNode.getHost())
- .setPort(netconfNode.getPort())
- .setConnectionStatus(ConnectionStatus.UnableToConnect)
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(
- Collections.singletonList(
- new NodeStatusBuilder()
- .setNode(clusterExtension.selfAddress().toString())
- .setStatus(Status.Failed)
- .build()))
- .build())
- .build())
- .build();
-
- if (currentOperationalNode == null) {
- currentOperationalNode = failedNode;
- }
-
- return failedNode;
- }
-
- @Nonnull @Override public ListenableFuture<Node> onNodeCreated(@Nonnull final NodeId nodeId,
- @Nonnull final Node configNode) {
- cachedContext = TypedActor.context();
- this.nodeId = nodeId.getValue();
- this.currentConfig = configNode;
- // set initial state before anything happens
- this.currentOperationalNode = getInitialState(nodeId, configNode);
-
- // connect magic, send config into the netconf pipeline through topo dispatcher
- final ListenableFuture<NetconfDeviceCapabilities> connectionFuture = topologyDispatcher.connectNode(nodeId, configNode);
-
- Futures.addCallback(connectionFuture, new FutureCallback<NetconfDeviceCapabilities>() {
- @Override
- public void onSuccess(@Nullable NetconfDeviceCapabilities result) {
- connectionStatusregistration = topologyDispatcher.registerConnectionStatusListener(nodeId, nodeManager);
- sessionListener = topologyDispatcher.registerNetconfClientSessionListener(nodeId, NetconfNodeManagerCallback.this);
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.error("Connection to device failed", t);
- }
- });
-
- final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class);
-
- // transform future result into state that gets written into datastore
- return Futures.transform(connectionFuture, new Function<NetconfDeviceCapabilities, Node>() {
- @Nullable
- @Override
- public Node apply(NetconfDeviceCapabilities input) {
- // build state data
- currentOperationalNode = new NodeBuilder().setNodeId(nodeId)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setConnectionStatus(ConnectionStatus.Connected)
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(
- Collections.singletonList(
- new NodeStatusBuilder()
- .setNode(clusterExtension.selfAddress().toString())
- .setStatus(Status.Connected)
- .build()))
- .build())
- .setHost(netconfNode.getHost())
- .setPort(netconfNode.getPort())
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .build()).build();
- return currentOperationalNode;
- }
- });
- }
-
- @Nonnull
- @Override
- public ListenableFuture<Node> onNodeUpdated(@Nonnull final NodeId nodeId,
- @Nonnull final Node configNode) {
- // first disconnect this node
- topologyDispatcher.unregisterMountPoint(nodeId);
-
- if (connectionStatusregistration != null) {
- connectionStatusregistration.close();
- }
- topologyDispatcher.disconnectNode(nodeId);
-
- // now reinit this connection with new settings
- final ListenableFuture<NetconfDeviceCapabilities> connectionFuture = topologyDispatcher.connectNode(nodeId, configNode);
-
- Futures.addCallback(connectionFuture, new FutureCallback<NetconfDeviceCapabilities>() {
- @Override
- public void onSuccess(@Nullable NetconfDeviceCapabilities result) {
- connectionStatusregistration = topologyDispatcher.registerConnectionStatusListener(nodeId, NetconfNodeManagerCallback.this);
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.error("Connection to device failed", t);
- }
- });
-
- final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class);
-
- return Futures.transform(connectionFuture, new Function<NetconfDeviceCapabilities, Node>() {
- @Nullable
- @Override
- public Node apply(NetconfDeviceCapabilities input) {
- // build state data
- return new NodeBuilder()
- .setNodeId(nodeId)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setConnectionStatus(ConnectionStatus.Connected)
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(
- Collections.singletonList(
- new NodeStatusBuilder()
- .setNode(clusterExtension.selfAddress().toString())
- .setStatus(Status.Connected)
- .build()))
- .build())
- .setHost(netconfNode.getHost())
- .setPort(netconfNode.getPort())
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .build())
- .build();
- }
- });
- }
-
- @Nonnull @Override public ListenableFuture<Void> onNodeDeleted(@Nonnull final NodeId nodeId) {
- // cleanup and disconnect
- topologyDispatcher.unregisterMountPoint(nodeId);
-
- if(connectionStatusregistration != null) {
- connectionStatusregistration.close();
- }
- roleChangeStrategy.unregisterRoleCandidate();
- return topologyDispatcher.disconnectNode(nodeId);
- }
-
- @Nonnull
- @Override
- public ListenableFuture<Node> getCurrentStatusForNode(@Nonnull NodeId nodeId) {
- LOG.debug("Getting current status for node: {} status: {}", nodeId, currentOperationalNode);
- return Futures.immediateFuture(currentOperationalNode);
- }
-
- @Override
- public void onRoleChanged(final RoleChangeDTO roleChangeDTO) {
- topologyDispatcher.unregisterMountPoint(new NodeId(nodeId));
-
- isMaster = roleChangeDTO.isOwner();
- }
-
- @Override
- public void onDeviceConnected(final SchemaContext remoteSchemaContext, final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService deviceRpc) {
- // we need to notify the higher level that something happened, get a current status from all other nodes, and aggregate a new result
- connected = true;
- if (isMaster) {
- LOG.debug("Master is done with schema resolution, registering mount point");
- topologyDispatcher.registerMountPoint(TypedActor.context(), new NodeId(nodeId));
- } else if (masterDataBrokerRef != null) {
- LOG.warn("Device connected, master already present in topology, registering mount point");
- topologyDispatcher.registerMountPoint(cachedContext, new NodeId(nodeId), masterDataBrokerRef);
- }
-
- List<AvailableCapability> capabilityList = new ArrayList<>();
- capabilityList.addAll(netconfSessionPreferences.getNetconfDeviceCapabilities().getNonModuleBasedCapabilities());
- capabilityList.addAll(netconfSessionPreferences.getNetconfDeviceCapabilities().getResolvedCapabilities());
- final AvailableCapabilitiesBuilder avCapabalitiesBuilder = new AvailableCapabilitiesBuilder();
- avCapabalitiesBuilder.setAvailableCapability(capabilityList);
-
- final UnavailableCapabilities unavailableCapabilities =
- new UnavailableCapabilitiesBuilder().setUnavailableCapability(FluentIterable.from(netconfSessionPreferences.getNetconfDeviceCapabilities().getUnresolvedCapabilites().entrySet())
- .transform(UNAVAILABLE_CAPABILITY_TRANSFORMER).toList()).build();
-
- final NetconfNode netconfNode = currentConfig.getAugmentation(NetconfNode.class);
- currentOperationalNode = new NodeBuilder().setNodeId(new NodeId(nodeId))
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setConnectionStatus(ConnectionStatus.Connected)
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(
- Collections.singletonList(
- new NodeStatusBuilder()
- .setNode(clusterExtension.selfAddress().toString())
- .setStatus(Status.Connected)
- .build()))
- .build())
- .setHost(netconfNode.getHost())
- .setPort(netconfNode.getPort())
- .setAvailableCapabilities(avCapabalitiesBuilder.build())
- .setUnavailableCapabilities(unavailableCapabilities)
- .build())
- .build();
- topologyManager.notifyNodeStatusChange(new NodeId(nodeId));
- }
-
- @Override
- public void onDeviceDisconnected() {
- // we need to notify the higher level that something happened, get a current status from all other nodes, and aggregate a new result
- LOG.debug("onDeviceDisconnected received, unregistered role candidate");
- connected = false;
- if (isMaster) {
- // set master to false since we are unregistering, the ownershipChanged callback can sometimes lag behind causing multiple nodes behaving as masters
- isMaster = false;
- // onRoleChanged() callback can sometimes lag behind, so unregister the mount right when it disconnects
- topologyDispatcher.unregisterMountPoint(new NodeId(nodeId));
- }
-
- final NetconfNode netconfNode = currentConfig.getAugmentation(NetconfNode.class);
- currentOperationalNode = new NodeBuilder().setNodeId(new NodeId(nodeId))
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setConnectionStatus(ConnectionStatus.Connecting)
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(
- Collections.singletonList(
- new NodeStatusBuilder()
- .setNode(clusterExtension.selfAddress().toString())
- .setStatus(Status.Unavailable)
- .build()))
- .build())
- .setHost(netconfNode.getHost())
- .setPort(netconfNode.getPort())
- .build()).build();
- topologyManager.notifyNodeStatusChange(new NodeId(nodeId));
- }
-
- @Override
- public void onDeviceFailed(Throwable throwable) {
- // we need to notify the higher level that something happened, get a current status from all other nodes, and aggregate a new result
- // no need to remove mountpoint, we should receive onRoleChanged callback after unregistering from election that unregisters the mountpoint
- LOG.warn("Netconf node {} failed with {}", nodeId, throwable);
- connected = false;
- String reason = (throwable != null && throwable.getMessage() != null) ? throwable.getMessage() : UNKNOWN_REASON;
-
- currentOperationalNode = new NodeBuilder().setNodeId(new NodeId(nodeId))
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setConnectionStatus(ConnectionStatus.UnableToConnect)
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(
- Collections.singletonList(
- new NodeStatusBuilder()
- .setNode(clusterExtension.selfAddress().toString())
- .setStatus(Status.Failed)
- .build()))
- .build())
- .setConnectedMessage(reason)
- .build()).build();
- topologyManager.notifyNodeStatusChange(new NodeId(nodeId));
- }
-
- @Override
- public void onNotification(DOMNotification domNotification) {
- //NOOP
- }
-
- @Override
- public void close() {
- //NOOP
- }
-
- @Override
- public void onReceive(Object message, ActorRef actorRef) {
- LOG.debug("Netconf node callback received message {}", message);
- if (message instanceof AnnounceMasterMountPoint) {
- masterDataBrokerRef = actorRef;
- // candidate gets registered when mount point is already prepared so we can go ahead a register it
- if (connected) {
- topologyDispatcher.registerMountPoint(TypedActor.context(), new NodeId(nodeId), masterDataBrokerRef);
- } else {
- LOG.debug("Announce master mount point msg received but mount point is not ready yet");
- }
- } else if (message instanceof AnnounceMasterMountPointDown) {
- LOG.debug("Master mountpoint went down");
- masterDataBrokerRef = null;
- topologyDispatcher.unregisterMountPoint(new NodeId(nodeId));
- }
- }
-
- @Override
- public void onSessionUp(NetconfClientSession netconfClientSession) {
- //NetconfClientSession is up, we can register role candidate
- LOG.debug("Netconf client session is up, registering role candidate");
- roleChangeStrategy.registerRoleCandidate(nodeManager);
- }
-
- @Override
- public void onSessionDown(NetconfClientSession netconfClientSession, Exception e) {
- LOG.debug("Netconf client session is down, unregistering role candidate");
- roleChangeStrategy.unregisterRoleCandidate();
- }
-
- @Override
- public void onSessionTerminated(NetconfClientSession netconfClientSession, NetconfTerminationReason netconfTerminationReason) {
- LOG.debug("Netconf client session is down, unregistering role candidate");
- roleChangeStrategy.unregisterRoleCandidate();
- }
-
- @Override
- public void onMessage(NetconfClientSession netconfClientSession, NetconfMessage netconfMessage) {
- //NOOP
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.impl;
-
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
-import java.util.ArrayList;
-import java.util.List;
-import org.opendaylight.netconf.topology.StateAggregator;
-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.NetconfNodeConnectionStatus.ConnectionStatus;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.AvailableCapabilities;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.ClusteredConnectionStatusBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.UnavailableCapabilities;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.clustered.connection.status.NodeStatus;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class NetconfNodeOperationalDataAggregator implements StateAggregator{
-
- private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeOperationalDataAggregator.class);
-
- @Override
- public ListenableFuture<Node> combineCreateAttempts(final List<ListenableFuture<Node>> stateFutures) {
- final SettableFuture<Node> future = SettableFuture.create();
- final ListenableFuture<List<Node>> allAsList = Futures.allAsList(stateFutures);
- Futures.addCallback(allAsList, new FutureCallback<List<Node>>() {
- @Override
- public void onSuccess(final List<Node> result) {
- Node base = null;
- NetconfNode baseAugmentation = null;
- AvailableCapabilities masterCaps = null;
- UnavailableCapabilities unavailableMasterCaps = null;
- final ArrayList<NodeStatus> statusList = new ArrayList<>();
- for (final Node node : result) {
- final NetconfNode netconfNode = node.getAugmentation(NetconfNode.class);
- if (base == null && netconfNode.getConnectionStatus().equals(ConnectionStatus.Connected)) {
- base = node;
- baseAugmentation = netconfNode;
- }
- // we need to pull out caps from master, since slave does not go through resolution
- if (masterCaps == null) {
- masterCaps = netconfNode.getAvailableCapabilities();
- unavailableMasterCaps = netconfNode.getUnavailableCapabilities();
- }
- if (netconfNode.getAvailableCapabilities().getAvailableCapability().size() > masterCaps.getAvailableCapability().size()) {
- masterCaps = netconfNode.getAvailableCapabilities();
- unavailableMasterCaps = netconfNode.getUnavailableCapabilities();
- }
- LOG.debug(netconfNode.toString());
- statusList.addAll(netconfNode.getClusteredConnectionStatus().getNodeStatus());
- }
-
- if (base == null) {
- base = result.get(0);
- baseAugmentation = result.get(0).getAugmentation(NetconfNode.class);
- LOG.debug("All results {}", result.toString());
- }
-
- final Node aggregatedNode =
- new NodeBuilder(base)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder(baseAugmentation)
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(statusList)
- .build())
- .setAvailableCapabilities(masterCaps)
- .setUnavailableCapabilities(unavailableMasterCaps)
- .build())
- .build();
-
- future.set(aggregatedNode);
- }
-
- @Override
- public void onFailure(final Throwable t) {
- LOG.error("One of the combined create attempts failed {}", t);
- future.setException(t);
- }
- });
- return future;
- }
-
- @Override
- public ListenableFuture<Node> combineUpdateAttempts(final List<ListenableFuture<Node>> stateFutures) {
- final SettableFuture<Node> future = SettableFuture.create();
- final ListenableFuture<List<Node>> allAsList = Futures.allAsList(stateFutures);
- Futures.addCallback(allAsList, new FutureCallback<List<Node>>() {
- @Override
- public void onSuccess(final List<Node> result) {
- Node base = null;
- NetconfNode baseAugmentation = null;
- AvailableCapabilities masterCaps = null;
- UnavailableCapabilities unavailableMasterCaps = null;
- final ArrayList<NodeStatus> statusList = new ArrayList<>();
- for (final Node node : result) {
- final NetconfNode netconfNode = node.getAugmentation(NetconfNode.class);
- if (base == null && netconfNode.getConnectionStatus().equals(ConnectionStatus.Connected)) {
- base = node;
- baseAugmentation = netconfNode;
- }
- // we need to pull out caps from master, since slave does not go through resolution
- if (masterCaps == null) {
- masterCaps = netconfNode.getAvailableCapabilities();
- unavailableMasterCaps = netconfNode.getUnavailableCapabilities();
- }
- if (netconfNode.getAvailableCapabilities().getAvailableCapability().size() > masterCaps.getAvailableCapability().size()) {
- masterCaps = netconfNode.getAvailableCapabilities();
- unavailableMasterCaps = netconfNode.getUnavailableCapabilities();
- }
- LOG.debug(netconfNode.toString());
- statusList.addAll(netconfNode.getClusteredConnectionStatus().getNodeStatus());
- }
-
- if (base == null) {
- base = result.get(0);
- baseAugmentation = result.get(0).getAugmentation(NetconfNode.class);
- LOG.debug("All results {}", result.toString());
- }
-
- final Node aggregatedNode =
- new NodeBuilder(base)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder(baseAugmentation)
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(statusList)
- .build())
- .setAvailableCapabilities(masterCaps)
- .setUnavailableCapabilities(unavailableMasterCaps)
- .build())
- .build();
- future.set(aggregatedNode);
- }
-
- @Override
- public void onFailure(final Throwable t) {
- LOG.error("One of the combined update attempts failed {}", t);
- future.setException(t);
- }
- });
- return future;
- }
-
- @Override
- public ListenableFuture<Void> combineDeleteAttempts(final List<ListenableFuture<Void>> stateFutures) {
- final SettableFuture<Void> future = SettableFuture.create();
- final ListenableFuture<List<Void>> allAsList = Futures.allAsList(stateFutures);
- Futures.addCallback(allAsList, new FutureCallback<List<Void>>() {
- @Override
- public void onSuccess(final List<Void> result) {
- future.set(null);
- }
-
- @Override
- public void onFailure(final Throwable t) {
- LOG.error("One of the combined delete attempts failed {}", t);
- future.setException(t);
- }
- });
- return future;
- }
-}
package org.opendaylight.netconf.topology.impl;
-import akka.actor.ActorContext;
-import akka.actor.ActorRef;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import io.netty.util.concurrent.EventExecutor;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.opendaylight.netconf.topology.AbstractNetconfTopology;
import org.opendaylight.netconf.topology.SchemaRepositoryProvider;
-import org.opendaylight.netconf.topology.pipeline.TopologyMountPointFacade.ConnectionStatusListenerRegistration;
-import org.opendaylight.netconf.topology.util.TopologyUtil;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
return new NetconfDeviceSalFacade(id, domBroker, bindingAwareBroker);
}
- @Override
- public void registerMountPoint(ActorContext context, NodeId nodeId) {
- throw new UnsupportedOperationException("MountPoint registration is not supported in regular topology, this happens automaticaly in the netconf pipeline");
- }
-
- @Override
- public void registerMountPoint(ActorContext context, NodeId nodeId, ActorRef masterRef) {
- throw new UnsupportedOperationException("MountPoint registration is not supported in regular topology, this happens automaticaly in the netconf pipeline");
- }
-
- @Override
- public void unregisterMountPoint(NodeId nodeId) {
- throw new UnsupportedOperationException("MountPoint registration is not supported in regular topology, this happens automaticaly in the netconf pipeline");
- }
-
- @Override
- public ConnectionStatusListenerRegistration registerConnectionStatusListener(NodeId node, RemoteDeviceHandler<NetconfSessionPreferences> listener) {
- throw new UnsupportedOperationException("Registering a listener on a regular netconf device is not supported(supported only in clustered netconf topology)");
- }
-
@Override
public void onSessionInitiated(ProviderContext session) {
dataBroker = session.getSALService(DataBroker.class);
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.impl;
-
-import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
-import akka.actor.TypedActor;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.netconf.topology.NodeManager;
-import org.opendaylight.netconf.topology.NodeManagerCallback.NodeManagerCallbackFactory;
-import org.opendaylight.netconf.topology.TopologyManagerCallback;
-import org.opendaylight.netconf.topology.util.BaseNodeManager.BaseNodeManagerBuilder;
-import org.opendaylight.netconf.topology.util.NodeWriter;
-import org.opendaylight.netconf.topology.util.NoopRoleChangeStrategy;
-import org.opendaylight.netconf.topology.util.SalNodeWriter;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class NetconfTopologyManagerCallback implements TopologyManagerCallback {
-
- private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyManagerCallback.class);
-
- private final ActorSystem actorSystem;
- private boolean isMaster;
-
- private final String topologyId;
- private final NodeWriter naSalNodeWriter;
- private final Map<NodeId, NodeManager> nodes = new HashMap<>();
- private final NodeManagerCallbackFactory nodeHandlerFactory;
-
- public NetconfTopologyManagerCallback(final ActorSystem actorSystem,
- final DataBroker dataBroker,
- final String topologyId,
- final NodeManagerCallbackFactory nodeHandlerFactory) {
- this(actorSystem, topologyId, nodeHandlerFactory, new SalNodeWriter(dataBroker, topologyId));
- }
-
- public NetconfTopologyManagerCallback(final ActorSystem actorSystem,
- final String topologyId,
- final NodeManagerCallbackFactory nodeHandlerFactory,
- final NodeWriter naSalNodeWriter) {
- this(actorSystem, topologyId, nodeHandlerFactory, naSalNodeWriter, false);
-
- }
-
- public NetconfTopologyManagerCallback(final ActorSystem actorSystem,
- final String topologyId,
- final NodeManagerCallbackFactory nodeHandlerFactory,
- final NodeWriter naSalNodeWriter,
- boolean isMaster) {
- this.actorSystem = actorSystem;
- this.topologyId = topologyId;
- this.nodeHandlerFactory = nodeHandlerFactory;
- this.naSalNodeWriter = naSalNodeWriter;
-
- this.isMaster = isMaster;
- }
-
- @Override
- public ListenableFuture<Node> onNodeCreated(final NodeId nodeId, final Node node) {
-
- // if this node was already configured, and whole config was pushed again, reinit with update
- if (nodes.containsKey(nodeId)) {
- return onNodeUpdated(nodeId, node);
- }
-
- // Init node admin
- final NodeManager naBaseNodeManager =
- createNodeManager(nodeId);
- nodes.put(nodeId, naBaseNodeManager);
-
- // only master should put initial state into datastore
- if (isMaster) {
- naSalNodeWriter.init(nodeId, naBaseNodeManager.getInitialState(nodeId, node));
- }
-
- // trigger connect on this node
- return naBaseNodeManager.onNodeCreated(nodeId, node);
- }
-
- @Override
- public ListenableFuture<Node> onNodeUpdated(final NodeId nodeId, final Node node) {
- // only master should put initial state into datastore
- if (isMaster) {
- naSalNodeWriter.init(nodeId, nodes.get(nodeId).getInitialState(nodeId, node));
- }
-
- // Trigger onNodeUpdated only on this node
- return nodes.get(nodeId).onNodeUpdated(nodeId, node);
- }
-
- @Override
- public ListenableFuture<Void> onNodeDeleted(final NodeId nodeId) {
- // Trigger delete only on this node
- final ListenableFuture<Void> future = nodes.get(nodeId).onNodeDeleted(nodeId);
- Futures.addCallback(future, new FutureCallback<Void>() {
- @Override
- public void onSuccess(Void result) {
- // remove proxy from node list and stop the actor
- LOG.debug("Stopping node actor for node : {}", nodeId.getValue());
- final NodeManager remove = nodes.remove(nodeId);
- TypedActor.get(actorSystem).stop(remove);
- }
-
- @Override
- public void onFailure(Throwable t) {
- // NOOP will be handled on higher level
- }
- });
- return future;
- }
-
- @Nonnull
- @Override
- public ListenableFuture<Node> getCurrentStatusForNode(@Nonnull NodeId nodeId) {
- if (!nodes.containsKey(nodeId)) {
- nodes.put(nodeId, createNodeManager(nodeId));
- }
- return nodes.get(nodeId).getCurrentStatusForNode(nodeId);
- }
-
- @Override
- public void onRoleChanged(RoleChangeDTO roleChangeDTO) {
- isMaster = roleChangeDTO.isOwner();
- // our post-election logic
- }
-
- private NodeManager createNodeManager(NodeId nodeId) {
- return new BaseNodeManagerBuilder().setNodeId(nodeId.getValue())
- .setActorContext(TypedActor.context())
- .setDelegateFactory(nodeHandlerFactory)
- .setRoleChangeStrategy(new NoopRoleChangeStrategy())
- .setTopologyId(topologyId)
- .build();
- }
-
- @Override
- public void onReceive(Object o, ActorRef actorRef) {
-
- }
-
- @Nonnull
- @Override
- public Node getInitialState(@Nonnull NodeId nodeId, @Nonnull Node configNode) {
- return nodes.get(nodeId).getInitialState(nodeId, configNode);
- }
-
- @Nonnull
- @Override
- public Node getFailedState(@Nonnull NodeId nodeId, @Nonnull Node configNode) {
- return nodes.get(nodeId).getFailedState(nodeId, configNode);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.impl;
-
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import java.util.concurrent.locks.ReentrantLock;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.netconf.topology.util.NodeWriter;
-import org.opendaylight.netconf.topology.util.TopologyUtil;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class TopologyNodeWriter implements NodeWriter{
-
- private static final Logger LOG = LoggerFactory.getLogger(TopologyNodeWriter.class);
-
- private final String topologyId;
- private final BindingTransactionChain txChain;
-
- private final InstanceIdentifier<NetworkTopology> networkTopologyPath;
- private final KeyedInstanceIdentifier<Topology, TopologyKey> topologyListPath;
-
- private final ReentrantLock lock = new ReentrantLock(true);
-
- public TopologyNodeWriter(final String topologyId, final DataBroker dataBroker) {
- this.topologyId = topologyId;
- this.txChain = Preconditions.checkNotNull(dataBroker).createTransactionChain(new TransactionChainListener() {
- @Override
- public void onTransactionChainFailed(TransactionChain<?, ?> chain, AsyncTransaction<?, ?> transaction, Throwable cause) {
- LOG.error("{}: TransactionChain({}) {} FAILED!", chain,
- transaction.getIdentifier(), cause);
- throw new IllegalStateException("Clustered topology writer TransactionChain(" + chain + ") not committed correctly", cause);
- }
-
- @Override
- public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
- LOG.trace("Clustered topology writer TransactionChain({}) SUCCESSFUL", chain);
- }
- });
-
- this.networkTopologyPath = InstanceIdentifier.builder(NetworkTopology.class).build();
- this.topologyListPath = networkTopologyPath.child(Topology.class, new TopologyKey(new TopologyId(topologyId)));
-
- // write an empty topology container at the start
- final WriteTransaction wTx = txChain.newWriteOnlyTransaction();
- createNetworkTopologyIfNotPresent(wTx, LogicalDatastoreType.OPERATIONAL);
- createNetworkTopologyIfNotPresent(wTx, LogicalDatastoreType.CONFIGURATION);
- commitTransaction(wTx, "init topology container", new NodeId("topology-netconf"));
- }
-
- @Override
- public void init(@Nonnull NodeId id, @Nonnull Node operationalDataNode) {
- lock.lock();
- try {
- final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
-
- createNetworkTopologyIfNotPresent(writeTx, LogicalDatastoreType.OPERATIONAL);
- final InstanceIdentifier<Node> path = TopologyUtil.createTopologyNodeListPath(new NodeKey(id), topologyId);
-
- LOG.trace("{}: Init device state transaction {} putting if absent operational data started. Putting data on path {}",
- id.getValue(), writeTx.getIdentifier(), path);
- writeTx.put(LogicalDatastoreType.OPERATIONAL, path, operationalDataNode);
- LOG.trace("{}: Init device state transaction {} putting operational data ended.",
- id.getValue(), writeTx.getIdentifier());
-
- commitTransaction(writeTx, "init", id);
- } finally {
- lock.unlock();
- }
- }
-
- @Override
- public void update(@Nonnull NodeId id, @Nonnull Node operationalDataNode) {
- lock.lock();
- try {
- final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
-
- final InstanceIdentifier<Node> path = TopologyUtil.createTopologyNodeListPath(new NodeKey(id), topologyId);
- LOG.trace("{}: Update device state transaction {} merging operational data started. Putting data on path {}",
- id, writeTx.getIdentifier(), operationalDataNode);
- writeTx.put(LogicalDatastoreType.OPERATIONAL, path, operationalDataNode);
- LOG.trace("{}: Update device state transaction {} merging operational data ended.",
- id, writeTx.getIdentifier());
-
- commitTransaction(writeTx, "update", id);
- } finally {
- lock.unlock();
- }
-
- }
-
- @Override
- public void delete(@Nonnull NodeId id) {
- lock.lock();
- try {
- final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
-
- final InstanceIdentifier<Node> path = TopologyUtil.createTopologyNodeListPath(new NodeKey(id), topologyId);
-
- LOG.trace(
- "{}: Close device state transaction {} removing all data started. Path: {}",
- id, writeTx.getIdentifier(), path);
- writeTx.delete(LogicalDatastoreType.OPERATIONAL, path);
- LOG.trace(
- "{}: Close device state transaction {} removing all data ended.",
- id, writeTx.getIdentifier());
-
- commitTransaction(writeTx, "close", id);
- } finally {
- lock.unlock();
- }
- }
-
- private void commitTransaction(final WriteTransaction transaction, final String txType, final NodeId id) {
- LOG.trace("{}: Committing Transaction {}:{}", id.getValue(), txType,
- transaction.getIdentifier());
- final CheckedFuture<Void, TransactionCommitFailedException> result = transaction.submit();
-
- Futures.addCallback(result, new FutureCallback<Void>() {
- @Override
- public void onSuccess(final Void result) {
- LOG.trace("{}: Transaction({}) {} SUCCESSFUL", id.getValue(), txType,
- transaction.getIdentifier());
- }
-
- @Override
- public void onFailure(final Throwable t) {
- LOG.error("{}: Transaction({}) {} FAILED!", id.getValue(), txType,
- transaction.getIdentifier(), t);
- throw new IllegalStateException(id.getValue() + " Transaction(" + txType + ") not committed correctly", t);
- }
- });
- }
-
- private void createNetworkTopologyIfNotPresent(final WriteTransaction writeTx, final LogicalDatastoreType datastoreType) {
-
- final NetworkTopology networkTopology = new NetworkTopologyBuilder().build();
- LOG.trace("{}: Merging {} container to ensure its presence", topologyId,
- NetworkTopology.QNAME, writeTx.getIdentifier());
- writeTx.merge(datastoreType, networkTopologyPath, networkTopology);
-
- final Topology topology = new TopologyBuilder().setTopologyId(new TopologyId(topologyId)).build();
- LOG.trace("{}: Merging {} container to ensure its presence", topologyId,
- Topology.QNAME, writeTx.getIdentifier());
- writeTx.merge(datastoreType, topologyListPath, topology);
- }
-}
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.netconf.topology.util;
+package org.opendaylight.netconf.topology.impl;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
final InstanceIdentifier<NetworkTopology> networkTopology = InstanceIdentifier.create(NetworkTopology.class);
return networkTopology.child(Topology.class, new TopologyKey(new TopologyId(topologyId)));
}
-
- public static InstanceIdentifier<Node> createTopologyNodeListPath(final NodeKey key, final String topologyId) {
- return createTopologyListPath(topologyId).child(Node.class, new NodeKey(new NodeId(key.getNodeId().getValue())));
- }
-
- public static InstanceIdentifier<Node> createTopologyNodePath(final String topologyId) {
- return createTopologyListPath(topologyId).child(Node.class);
- }
}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline;
-
-import akka.actor.TypedActor;
-import java.util.Set;
-import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
-import scala.concurrent.Future;
-
-public interface ClusteredDeviceSourcesResolver extends TypedActor.Receiver, TypedActor.PreStart {
-
- Future<Set<SourceIdentifier>> getResolvedSources();
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline;
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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
- */
-
-import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
-import akka.actor.TypedActor;
-import akka.actor.TypedProps;
-import akka.cluster.Cluster;
-import akka.cluster.Member;
-import akka.dispatch.Futures;
-import akka.dispatch.OnComplete;
-import java.util.List;
-import java.util.Set;
-import org.opendaylight.controller.cluster.schema.provider.impl.RemoteSchemaProvider;
-import org.opendaylight.netconf.topology.pipeline.messages.AnnounceClusteredDeviceSourcesResolverUp;
-import org.opendaylight.netconf.topology.pipeline.messages.AnnounceMasterOnSameNodeUp;
-import org.opendaylight.netconf.topology.pipeline.messages.AnnounceMasterSourceProviderUp;
-import org.opendaylight.netconf.util.NetconfTopologyPathCreator;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
-import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
-import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
-import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import scala.concurrent.Future;
-import scala.concurrent.Promise;
-
-
-public class ClusteredDeviceSourcesResolverImpl implements ClusteredDeviceSourcesResolver {
-
- private static Logger LOG = LoggerFactory.getLogger(ClusteredDeviceSourcesResolver.class);
-
- private final String topologyId;
- private final String nodeId;
- private final ActorSystem actorSystem;
- private final SchemaSourceRegistry schemaRegistry;
- private final List<SchemaSourceRegistration<? extends SchemaSourceRepresentation>> sourceRegistrations;
-
- private final Promise<Set<SourceIdentifier>> resolvedSourcesPromise;
- private MasterSourceProvider remoteYangTextSourceProvider;
-
- public ClusteredDeviceSourcesResolverImpl(String topologyId, String nodeId, ActorSystem actorSystem,
- SchemaSourceRegistry schemaRegistry,
- List<SchemaSourceRegistration<? extends SchemaSourceRepresentation>> sourceRegistrations) {
- this.topologyId = topologyId;
- this.nodeId = nodeId;
- this.actorSystem = actorSystem;
- this.schemaRegistry = schemaRegistry;
- this.sourceRegistrations = sourceRegistrations;
- resolvedSourcesPromise = Futures.promise();
- }
-
- @Override
- public void preStart(){
- Cluster cluster = Cluster.get(actorSystem);
- for(Member node : cluster.state().getMembers()) {
- if(!node.address().equals(cluster.selfAddress())) {
- final NetconfTopologyPathCreator pathCreator = new NetconfTopologyPathCreator(node.address().toString(), topologyId);
- final String path = pathCreator.withSuffix(nodeId).withSuffix(NetconfTopologyPathCreator.MASTER_SOURCE_PROVIDER).build();
- actorSystem.actorSelection(path).tell(new AnnounceClusteredDeviceSourcesResolverUp(), TypedActor.context().self());
- }
- }
- }
-
- @Override
- public void onReceive(Object o, ActorRef actorRef) {
- if(o instanceof AnnounceMasterSourceProviderUp) {
- if(remoteYangTextSourceProvider == null) {
- remoteYangTextSourceProvider = TypedActor.get(actorSystem).typedActorOf(
- new TypedProps<>(MasterSourceProvider.class,
- MasterSourceProviderImpl.class), actorRef);
- registerProvidedSourcesToSchemaRegistry();
- }
- } else if(o instanceof AnnounceMasterOnSameNodeUp) {
- resolvedSourcesPromise.failure(new MasterSourceProviderOnSameNodeException());
- }
- }
-
- private void registerProvidedSourcesToSchemaRegistry() {
- Future<Set<SourceIdentifier>> sourcesFuture = remoteYangTextSourceProvider.getProvidedSources();
- resolvedSourcesPromise.completeWith(sourcesFuture);
- final RemoteSchemaProvider remoteProvider = new RemoteSchemaProvider(remoteYangTextSourceProvider, actorSystem.dispatcher());
-
- sourcesFuture.onComplete(new OnComplete<Set<SourceIdentifier>>() {
- @Override
- public void onComplete(Throwable throwable, Set<SourceIdentifier> sourceIdentifiers) throws Throwable {
- for (SourceIdentifier sourceId : sourceIdentifiers) {
- sourceRegistrations.add(schemaRegistry.registerSchemaSource(remoteProvider,
- PotentialSchemaSource.create(sourceId, YangTextSchemaSource.class, PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
- }
- }
- }, actorSystem.dispatcher());
- }
-
- @Override
- public Future<Set<SourceIdentifier>> getResolvedSources() {
- return resolvedSourcesPromise.future();
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline;
-
-import akka.actor.ActorContext;
-import akka.actor.ActorSystem;
-import akka.actor.TypedActor;
-import akka.actor.TypedProps;
-import akka.dispatch.OnComplete;
-import akka.japi.Creator;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
-import org.opendaylight.netconf.api.NetconfMessage;
-import org.opendaylight.netconf.sal.connect.api.RemoteDeviceCommunicator;
-import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
-import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
-import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceBuilder;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc;
-import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer;
-import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.netconf.util.NetconfTopologyPathCreator;
-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.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
-import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
-import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ClusteredNetconfDevice extends NetconfDevice implements EntityOwnershipListener {
-
- private static final Logger LOG = LoggerFactory.getLogger(ClusteredNetconfDevice.class);
-
- private NetconfDeviceCommunicator listener;
- private NetconfSessionPreferences sessionPreferences;
- private SchemaRepository schemaRepo;
- private final ActorSystem actorSystem;
- private final String topologyId;
- private final String nodeId;
- private final ActorContext cachedContext;
-
- private MasterSourceProvider masterSourceProvider = null;
- private ClusteredDeviceSourcesResolver resolver = null;
-
- public ClusteredNetconfDevice(final SchemaResourcesDTO schemaResourcesDTO, final RemoteDeviceId id, final RemoteDeviceHandler<NetconfSessionPreferences> salFacade,
- final ExecutorService globalProcessingExecutor, final ActorSystem actorSystem, final String topologyId, final String nodeId,
- final ActorContext cachedContext, final boolean reconnectOnSchemaChanged) {
- super(schemaResourcesDTO, id, salFacade, globalProcessingExecutor, reconnectOnSchemaChanged);
- this.schemaRepo = (SchemaRepository) schemaResourcesDTO.getSchemaRegistry();
- this.actorSystem = actorSystem;
- this.topologyId = topologyId;
- this.nodeId = nodeId;
- this.cachedContext = cachedContext;
- }
-
- @Override
- public void onRemoteSessionUp(NetconfSessionPreferences remoteSessionCapabilities, NetconfDeviceCommunicator listener) {
- LOG.warn("Node {} SessionUp, with capabilities {}", nodeId, remoteSessionCapabilities);
- this.listener = listener;
- this.sessionPreferences = remoteSessionCapabilities;
- slaveSetupSchema();
- }
-
-
- @Override
- protected void handleSalInitializationSuccess(SchemaContext result, NetconfSessionPreferences remoteSessionCapabilities, DOMRpcService deviceRpc) {
- super.handleSalInitializationSuccess(result, remoteSessionCapabilities, deviceRpc);
-
- final Set<SourceIdentifier> sourceIds = Sets.newHashSet();
- for(ModuleIdentifier id : result.getAllModuleIdentifiers()) {
- sourceIds.add(SourceIdentifier.create(id.getName(), (SimpleDateFormatUtil.DEFAULT_DATE_REV == id.getRevision() ? Optional.<String>absent() :
- Optional.of(SimpleDateFormatUtil.getRevisionFormat().format(id.getRevision())))));
- }
-
- //TODO extract string constant to util class
- LOG.debug("Creating master source provider");
- masterSourceProvider = TypedActor.get(cachedContext).typedActorOf(
- new TypedProps<>(MasterSourceProvider.class,
- new Creator<MasterSourceProviderImpl>() {
- @Override
- public MasterSourceProviderImpl create() throws Exception {
- return new MasterSourceProviderImpl(schemaRepo, sourceIds, actorSystem, topologyId, nodeId);
- }
- }), NetconfTopologyPathCreator.MASTER_SOURCE_PROVIDER);
- }
-
- @Override
- public void onRemoteSessionDown() {
- super.onRemoteSessionDown();
- listener = null;
- sessionPreferences = null;
- if (masterSourceProvider != null) {
- // if we have master the slave that started on this node should be already killed via PoisonPill, so stop master only now
- LOG.debug("Stopping master source provider for node {}", nodeId);
- TypedActor.get(actorSystem).stop(masterSourceProvider);
- masterSourceProvider = null;
- } else {
- LOG.debug("Stopping slave source resolver for node {}", nodeId);
- TypedActor.get(actorSystem).stop(resolver);
- resolver = null;
- }
- }
-
- private void slaveSetupSchema() {
- //TODO extract string constant to util class
- resolver = TypedActor.get(cachedContext).typedActorOf(
- new TypedProps<>(ClusteredDeviceSourcesResolver.class,
- new Creator<ClusteredDeviceSourcesResolverImpl>() {
- @Override
- public ClusteredDeviceSourcesResolverImpl create() throws Exception {
- return new ClusteredDeviceSourcesResolverImpl(topologyId, nodeId, actorSystem, schemaRegistry, sourceRegistrations);
- }
- }), NetconfTopologyPathCreator.CLUSTERED_DEVICE_SOURCES_RESOLVER);
-
- final FutureCallback<SchemaContext> schemaContextFuture = new FutureCallback<SchemaContext>() {
- @Override
- public void onSuccess(SchemaContext schemaContext) {
- LOG.debug("{}: Schema context built successfully.", id);
-
- final NetconfDeviceCapabilities deviceCap = sessionPreferences.getNetconfDeviceCapabilities();
- final Set<AvailableCapability> providedSourcesQnames = Sets.newHashSet();
- final Set<AvailableCapability> providedSourcesNonModuleCaps = Sets.newHashSet();
- for(ModuleIdentifier id : schemaContext.getAllModuleIdentifiers()) {
- providedSourcesQnames.add(new AvailableCapabilityBuilder()
- .setCapability(QName.create(id.getQNameModule(), id.getName()).toString()).build());
- }
- sessionPreferences.getNonModuleCaps().forEach(e -> providedSourcesNonModuleCaps.add(new AvailableCapabilityBuilder()
- .setCapability(e).build()));
- deviceCap.addNonModuleBasedCapabilities(providedSourcesNonModuleCaps);
- deviceCap.addCapabilities(providedSourcesQnames);
-
- ClusteredNetconfDevice.super.handleSalInitializationSuccess(
- schemaContext, sessionPreferences, getDeviceSpecificRpc(schemaContext, listener));
- }
-
- @Override
- public void onFailure(Throwable throwable) {
- LOG.warn("{}: Unexpected error resolving device sources: {}", id, throwable);
- handleSalInitializationFailure(throwable, listener);
- }
- };
-
- resolver.getResolvedSources().onComplete(
- new OnComplete<Set<SourceIdentifier>>() {
- @Override
- public void onComplete(Throwable throwable, Set<SourceIdentifier> sourceIdentifiers) throws Throwable {
- if(throwable != null) {
- if(throwable instanceof MasterSourceProviderOnSameNodeException) {
- //do nothing
- } else {
- LOG.warn("{}: Unexpected error resolving device sources: {}", id, throwable);
- handleSalInitializationFailure(throwable, listener);
- }
- } else {
- LOG.trace("{}: Trying to build schema context from {}", id, sourceIdentifiers);
- Futures.addCallback(schemaContextFactory.createSchemaContext(sourceIdentifiers), schemaContextFuture);
- }
- }
- }, actorSystem.dispatcher());
- }
-
- private NetconfDeviceRpc getDeviceSpecificRpc(SchemaContext result, RemoteDeviceCommunicator<NetconfMessage> listener) {
- return new NetconfDeviceRpc(result, listener, new NetconfMessageTransformer(result, true));
- }
-
- @Override
- public void ownershipChanged(EntityOwnershipChange ownershipChange) {
- LOG.debug("Entity ownership change received {}", ownershipChange);
- if(ownershipChange.isOwner()) {
- super.onRemoteSessionUp(sessionPreferences, listener);
- } else if (ownershipChange.wasOwner()) {
- slaveSetupSchema();
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline;
-
-import java.util.ArrayList;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.netconf.api.NetconfMessage;
-import org.opendaylight.netconf.api.NetconfTerminationReason;
-import org.opendaylight.netconf.client.NetconfClientSession;
-import org.opendaylight.netconf.client.NetconfClientSessionListener;
-import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
-import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-
-public class ClusteredNetconfDeviceCommunicator extends NetconfDeviceCommunicator {
-
- private final EntityOwnershipService ownershipService;
-
- private final ArrayList<NetconfClientSessionListener> netconfClientSessionListeners = new ArrayList<>();
- private EntityOwnershipListenerRegistration ownershipListenerRegistration = null;
-
- public ClusteredNetconfDeviceCommunicator(RemoteDeviceId id, NetconfDevice remoteDevice, EntityOwnershipService ownershipService, final int rpcMessageLimit) {
- super(id, remoteDevice, rpcMessageLimit);
- this.ownershipService = ownershipService;
- }
-
- @Override
- public void onMessage(NetconfClientSession session, NetconfMessage message) {
- super.onMessage(session, message);
- for(NetconfClientSessionListener listener : netconfClientSessionListeners) {
- listener.onMessage(session, message);
- }
- }
-
- @Override
- public void onSessionDown(NetconfClientSession session, Exception e) {
- super.onSessionDown(session, e);
- ownershipListenerRegistration.close();
- for(NetconfClientSessionListener listener : netconfClientSessionListeners) {
- listener.onSessionDown(session, e);
- }
- }
-
- @Override
- public void onSessionUp(NetconfClientSession session) {
- super.onSessionUp(session);
- ownershipListenerRegistration = ownershipService.registerListener("netconf-node/" + id.getName(), (ClusteredNetconfDevice) remoteDevice);
- for(NetconfClientSessionListener listener : netconfClientSessionListeners) {
- listener.onSessionUp(session);
- }
- }
-
- @Override
- public void onSessionTerminated(NetconfClientSession session, NetconfTerminationReason reason) {
- super.onSessionTerminated(session, reason);
- ownershipListenerRegistration.close();
- for(NetconfClientSessionListener listener : netconfClientSessionListeners) {
- listener.onSessionTerminated(session, reason);
- }
- }
-
- public NetconfClientSessionListenerRegistration registerNetconfClientSessionListener(NetconfClientSessionListener listener) {
- netconfClientSessionListeners.add(listener);
- return new NetconfClientSessionListenerRegistration(listener);
- }
-
- public class NetconfClientSessionListenerRegistration {
-
- private final NetconfClientSessionListener listener;
-
- public NetconfClientSessionListenerRegistration(NetconfClientSessionListener listener) {
- this.listener = listener;
- }
-
- public void close() {
- netconfClientSessionListeners.remove(listener);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline;
-
-import com.google.common.base.Preconditions;
-import java.util.Collection;
-import java.util.Collections;
-import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
-import org.opendaylight.controller.sal.core.api.Broker;
-import org.opendaylight.controller.sal.core.api.Provider;
-import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalProvider.MountInstance;
-import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ClusteredNetconfDeviceMountInstanceProxy implements Provider, AutoCloseable{
-
- private static final Logger LOG = LoggerFactory.getLogger(ClusteredNetconfDeviceMountInstanceProxy.class);
-
- private final RemoteDeviceId id;
- private MountInstance mountInstance;
-
- public ClusteredNetconfDeviceMountInstanceProxy(final RemoteDeviceId deviceId) {
- this.id = deviceId;
- }
-
- public MountInstance getMountInstance() {
- Preconditions.checkState(mountInstance != null,
- "%s: Mount instance was not initialized by sal. Cannot get mount instance", id);
- return mountInstance;
- }
-
- @Override
- public void close() throws Exception {
- mountInstance.close();
- }
-
- @Override
- public void onSessionInitiated(final Broker.ProviderSession session) {
- LOG.debug("{}: (BI)Session with sal established {}", id, session);
-
- final DOMMountPointService mountService = session.getService(DOMMountPointService.class);
- if (mountService != null) {
- mountInstance = new MountInstance(mountService, id);
- }
- }
-
- @Override
- public Collection<ProviderFunctionality> getProviderFunctionality() {
- return Collections.emptySet();
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline;
-
-import akka.actor.TypedActor;
-import org.opendaylight.controller.cluster.schema.provider.RemoteYangTextSourceProvider;
-
-public interface MasterSourceProvider
- extends TypedActor.PreStart, TypedActor.Receiver, RemoteYangTextSourceProvider {
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline;
-
-import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
-import akka.actor.PoisonPill;
-import akka.actor.TypedActor;
-import akka.cluster.Cluster;
-import akka.cluster.Member;
-import java.util.Set;
-import org.opendaylight.controller.cluster.schema.provider.impl.RemoteYangTextSourceProviderImpl;
-import org.opendaylight.netconf.topology.pipeline.messages.AnnounceClusteredDeviceSourcesResolverUp;
-import org.opendaylight.netconf.topology.pipeline.messages.AnnounceMasterOnSameNodeUp;
-import org.opendaylight.netconf.topology.pipeline.messages.AnnounceMasterSourceProviderUp;
-import org.opendaylight.netconf.util.NetconfTopologyPathCreator;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
-import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class MasterSourceProviderImpl extends RemoteYangTextSourceProviderImpl
- implements MasterSourceProvider {
-
- private static Logger LOG = LoggerFactory.getLogger(MasterSourceProviderImpl.class);
-
- private final ActorSystem actorSystem;
- private final String topologyId;
- private final String nodeId;
-
- public MasterSourceProviderImpl(SchemaRepository schemaRepo, Set<SourceIdentifier> providedSources, ActorSystem actorSystem, String topologyId, String nodeId) {
- super(schemaRepo, providedSources);
- this.actorSystem = actorSystem;
- this.topologyId = topologyId;
- this.nodeId = nodeId;
- }
-
- @Override
- public void onReceive(Object o, ActorRef actorRef) {
- if(o instanceof AnnounceClusteredDeviceSourcesResolverUp) {
- LOG.debug("Received source resolver up");
- actorRef.tell(new AnnounceMasterSourceProviderUp(), TypedActor.context().self());
- }
- }
-
- @Override
- public void preStart() {
- Cluster cluster = Cluster.get(actorSystem);
- cluster.join(cluster.selfAddress());
- LOG.debug("Notifying members master schema source provider is up.");
- for(Member node : cluster.state().getMembers()) {
- final NetconfTopologyPathCreator pathCreator = new NetconfTopologyPathCreator(node.address().toString(),topologyId);
- final String path = pathCreator.withSuffix(nodeId).withSuffix(NetconfTopologyPathCreator.CLUSTERED_DEVICE_SOURCES_RESOLVER).build();
- if(node.address().equals(cluster.selfAddress())) {
- actorSystem.actorSelection(path).tell(new AnnounceMasterOnSameNodeUp(), TypedActor.context().self());
- actorSystem.actorSelection(path).tell(PoisonPill.getInstance(), TypedActor.context().self());
- } else {
- //TODO extract string constant to util class
- actorSystem.actorSelection(path).tell(new AnnounceMasterSourceProviderUp(), TypedActor.context().self());
- }
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline;
-
-public class MasterSourceProviderOnSameNodeException extends Exception {
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline;
-
-import akka.actor.ActorSystem;
-import akka.actor.TypedActor;
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import java.util.Collections;
-import java.util.Map;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
-import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceDataBroker;
-import org.opendaylight.netconf.sal.connect.netconf.sal.tx.ReadWriteTx;
-import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.netconf.topology.pipeline.tx.ProxyReadOnlyTransaction;
-import org.opendaylight.netconf.topology.pipeline.tx.ProxyWriteOnlyTransaction;
-import org.opendaylight.netconf.topology.util.messages.NormalizedNodeMessage;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import scala.concurrent.Future;
-import scala.concurrent.impl.Promise.DefaultPromise;
-
-public class NetconfDeviceMasterDataBroker implements ProxyNetconfDeviceDataBroker {
-
- private final RemoteDeviceId id;
-
- private final NetconfDeviceDataBroker delegateBroker;
- private final ActorSystem actorSystem;
-
- private DOMDataReadOnlyTransaction readTx;
- private DOMDataWriteTransaction writeTx;
-
- public NetconfDeviceMasterDataBroker(final ActorSystem actorSystem, final RemoteDeviceId id,
- final SchemaContext schemaContext, final DOMRpcService rpc,
- final NetconfSessionPreferences netconfSessionPreferences) {
- this.id = id;
- delegateBroker = new NetconfDeviceDataBroker(id, schemaContext, rpc, netconfSessionPreferences);
- this.actorSystem = actorSystem;
-
- // only ever need 1 readTx since it doesnt need to be closed
- readTx = delegateBroker.newReadOnlyTransaction();
- }
-
- @Override
- public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
- return new ProxyReadOnlyTransaction(actorSystem, id, TypedActor.<NetconfDeviceMasterDataBroker>self());
- }
-
- @Override
- public DOMDataReadWriteTransaction newReadWriteTransaction() {
- return new ReadWriteTx(new ProxyReadOnlyTransaction(actorSystem, id, TypedActor.<NetconfDeviceMasterDataBroker>self()),
- newWriteOnlyTransaction());
- }
-
- @Override
- public DOMDataWriteTransaction newWriteOnlyTransaction() {
- writeTx = delegateBroker.newWriteOnlyTransaction();
- return new ProxyWriteOnlyTransaction(actorSystem, TypedActor.<NetconfDeviceMasterDataBroker>self());
- }
-
- @Override
- public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(LogicalDatastoreType store, YangInstanceIdentifier path, DOMDataChangeListener listener, DataChangeScope triggeringScope) {
- throw new UnsupportedOperationException(id + ": Data change listeners not supported for netconf mount point");
- }
-
- @Override
- public DOMTransactionChain createTransactionChain(TransactionChainListener listener) {
- throw new UnsupportedOperationException(id + ": Transaction chains not supported for netconf mount point");
- }
-
- @Nonnull
- @Override
- public Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> getSupportedExtensions() {
- return Collections.emptyMap();
- }
-
- @Override
- public Future<Optional<NormalizedNodeMessage>> read(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
- final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readFuture = readTx.read(store, path);
-
- final DefaultPromise<Optional<NormalizedNodeMessage>> promise = new DefaultPromise<>();
- Futures.addCallback(readFuture, new FutureCallback<Optional<NormalizedNode<?, ?>>>() {
- @Override
- public void onSuccess(Optional<NormalizedNode<?, ?>> result) {
- if (!result.isPresent()) {
- promise.success(Optional.<NormalizedNodeMessage>absent());
- } else {
- promise.success(Optional.of(new NormalizedNodeMessage(path, result.get())));
- }
- }
-
- @Override
- public void onFailure(Throwable t) {
- promise.failure(t);
- }
- });
- return promise.future();
- }
-
- @Override
- public Future<Boolean> exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
- final CheckedFuture<Boolean, ReadFailedException> existsFuture = readTx.exists(store, path);
-
- final DefaultPromise<Boolean> promise = new DefaultPromise<>();
- Futures.addCallback(existsFuture, new FutureCallback<Boolean>() {
- @Override
- public void onSuccess(Boolean result) {
- promise.success(result);
- }
-
- @Override
- public void onFailure(Throwable t) {
- promise.failure(t);
- }
- });
- return promise.future();
- }
-
- @Override
- public void put(final LogicalDatastoreType store, final NormalizedNodeMessage data) {
- if (writeTx == null) {
- writeTx = delegateBroker.newWriteOnlyTransaction();
- }
- writeTx.put(store, data.getIdentifier(), data.getNode());
- }
-
- @Override
- public void merge(final LogicalDatastoreType store, final NormalizedNodeMessage data) {
- if (writeTx == null) {
- writeTx = delegateBroker.newWriteOnlyTransaction();
- }
- writeTx.merge(store, data.getIdentifier(), data.getNode());
- }
-
- @Override
- public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
- if (writeTx == null) {
- writeTx = delegateBroker.newWriteOnlyTransaction();
- }
- writeTx.delete(store, path);
- }
-
- @Override
- public boolean cancel() {
- return writeTx.cancel();
- }
-
- @Override
- public Future<Void> submit() {
- final CheckedFuture<Void, TransactionCommitFailedException> submitFuture = writeTx.submit();
- final DefaultPromise<Void> promise = new DefaultPromise<>();
- Futures.addCallback(submitFuture, new FutureCallback<Void>() {
- @Override
- public void onSuccess(Void result) {
- promise.success(result);
- writeTx = null;
- }
-
- @Override
- public void onFailure(Throwable t) {
- promise.failure(t);
- writeTx = null;
- }
- });
- return promise.future();
- }
-
- @Override
- @Deprecated
- public Future<RpcResult<TransactionStatus>> commit() {
- final ListenableFuture<RpcResult<TransactionStatus>> commitFuture = writeTx.commit();
- final DefaultPromise<RpcResult<TransactionStatus>> promise = new DefaultPromise<>();
- Futures.addCallback(commitFuture, new FutureCallback<RpcResult<TransactionStatus>>() {
- @Override
- public void onSuccess(RpcResult<TransactionStatus> result) {
- promise.success(result);
- writeTx = null;
- }
-
- @Override
- public void onFailure(Throwable t) {
- promise.failure(t);
- writeTx = null;
- }
- });
- return promise.future();
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline;
-
-import com.google.common.base.Optional;
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
-import org.opendaylight.netconf.topology.util.messages.NormalizedNodeMessage;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import scala.concurrent.Future;
-
-public interface ProxyNetconfDeviceDataBroker extends DOMDataBroker{
- Future<Optional<NormalizedNodeMessage>> read(LogicalDatastoreType store, YangInstanceIdentifier path);
-
- Future<Boolean> exists(LogicalDatastoreType store, YangInstanceIdentifier path);
-
- void put(LogicalDatastoreType store, NormalizedNodeMessage data);
-
- void merge(LogicalDatastoreType store, NormalizedNodeMessage data);
-
- void delete(LogicalDatastoreType store, YangInstanceIdentifier path);
-
- boolean cancel();
-
- Future<Void> submit();
-
- @Deprecated
- Future<RpcResult<TransactionStatus>> commit();
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline;
-
-import akka.actor.ActorContext;
-import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
-import akka.actor.TypedActor;
-import akka.actor.TypedProps;
-import akka.cluster.Cluster;
-import akka.cluster.Member;
-import akka.japi.Creator;
-import com.google.common.base.Preconditions;
-import java.util.ArrayList;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
-import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.controller.sal.core.api.Broker;
-import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceNotificationService;
-import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.netconf.topology.util.messages.AnnounceMasterMountPoint;
-import org.opendaylight.netconf.topology.util.messages.AnnounceMasterMountPointDown;
-import org.opendaylight.netconf.util.NetconfTopologyPathCreator;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class TopologyMountPointFacade implements AutoCloseable, RemoteDeviceHandler<NetconfSessionPreferences> {
-
- private static final Logger LOG = LoggerFactory.getLogger(TopologyMountPointFacade.class);
-
- private static final String MOUNT_POINT = "mountpoint";
-
- private final String topologyId;
- private final RemoteDeviceId id;
- private final Broker domBroker;
- private final BindingAwareBroker bindingBroker;
-
- private SchemaContext remoteSchemaContext = null;
- private NetconfSessionPreferences netconfSessionPreferences = null;
- private DOMRpcService deviceRpc = null;
- private final ClusteredNetconfDeviceMountInstanceProxy salProvider;
-
- private ActorSystem actorSystem;
- private DOMDataBroker deviceDataBroker = null;
-
- private final ArrayList<RemoteDeviceHandler<NetconfSessionPreferences>> connectionStatusListeners = new ArrayList<>();
-
- public TopologyMountPointFacade(final String topologyId,
- final RemoteDeviceId id,
- final Broker domBroker,
- final BindingAwareBroker bindingBroker) {
- this.topologyId = topologyId;
- this.id = id;
- this.domBroker = domBroker;
- this.bindingBroker = bindingBroker;
- this.salProvider = new ClusteredNetconfDeviceMountInstanceProxy(id);
- registerToSal(domBroker);
- }
-
- public void registerToSal(final Broker domRegistryDependency) {
- domRegistryDependency.registerProvider(salProvider);
- }
-
- @Override
- public void onDeviceConnected(final SchemaContext remoteSchemaContext,
- final NetconfSessionPreferences netconfSessionPreferences,
- final DOMRpcService deviceRpc) {
- // prepare our prerequisites for mountpoint
- LOG.debug("Mount point facade onConnected capabilities {}", netconfSessionPreferences);
- this.remoteSchemaContext = remoteSchemaContext;
- this.netconfSessionPreferences = netconfSessionPreferences;
- this.deviceRpc = deviceRpc;
- for (RemoteDeviceHandler<NetconfSessionPreferences> listener : connectionStatusListeners) {
- listener.onDeviceConnected(remoteSchemaContext, netconfSessionPreferences, deviceRpc);
- }
- }
-
- @Override
- public void onDeviceDisconnected() {
- // do not unregister mount point here, this gets handle by the underlying call from role change callback
- for (RemoteDeviceHandler<NetconfSessionPreferences> listener : connectionStatusListeners) {
- listener.onDeviceDisconnected();
- }
- }
-
- @Override
- public void onDeviceFailed(Throwable throwable) {
- // do not unregister mount point here, this gets handle by the underlying call from role change callback
- for (RemoteDeviceHandler<NetconfSessionPreferences> listener : connectionStatusListeners) {
- listener.onDeviceFailed(throwable);
- }
- }
-
- @Override
- public void onNotification(DOMNotification domNotification) {
- salProvider.getMountInstance().publish(domNotification);
- }
-
- public void registerMountPoint(final ActorSystem actorSystem, final ActorContext context) {
- if (remoteSchemaContext == null || netconfSessionPreferences == null) {
- LOG.debug("Master mount point does not have schemas ready yet, delaying registration");
- return;
- }
-
- Preconditions.checkNotNull(id);
- Preconditions.checkNotNull(remoteSchemaContext, "Device has no remote schema context yet. Probably not fully connected.");
- Preconditions.checkNotNull(netconfSessionPreferences, "Device has no capabilities yet. Probably not fully connected.");
- this.actorSystem = actorSystem;
- final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
-
- LOG.warn("Creating master data broker for device {}", id);
- deviceDataBroker = TypedActor.get(context).typedActorOf(new TypedProps<>(ProxyNetconfDeviceDataBroker.class, new Creator<NetconfDeviceMasterDataBroker>() {
- @Override
- public NetconfDeviceMasterDataBroker create() throws Exception {
- return new NetconfDeviceMasterDataBroker(actorSystem, id, remoteSchemaContext, deviceRpc, netconfSessionPreferences);
- }
- }), MOUNT_POINT);
- LOG.debug("Master data broker registered on path {}", TypedActor.get(actorSystem).getActorRefFor(deviceDataBroker).path());
- salProvider.getMountInstance().onTopologyDeviceConnected(remoteSchemaContext, deviceDataBroker, deviceRpc, notificationService);
- final Cluster cluster = Cluster.get(actorSystem);
- final Iterable<Member> members = cluster.state().getMembers();
- final ActorRef deviceDataBrokerRef = TypedActor.get(actorSystem).getActorRefFor(deviceDataBroker);
- for (final Member member : members) {
- if (!member.address().equals(cluster.selfAddress())) {
- final NetconfTopologyPathCreator pathCreator = new NetconfTopologyPathCreator(member.address().toString(),topologyId);
- final String path = pathCreator.withSuffix(id.getName()).build();
- actorSystem.actorSelection(path).tell(new AnnounceMasterMountPoint(), deviceDataBrokerRef);
- }
- }
- }
-
- public void registerMountPoint(final ActorSystem actorSystem, final ActorContext context, final ActorRef masterRef) {
- if (remoteSchemaContext == null || netconfSessionPreferences == null) {
- LOG.debug("Slave mount point does not have schemas ready yet, delaying registration");
- return;
- }
-
- Preconditions.checkNotNull(id);
- Preconditions.checkNotNull(remoteSchemaContext, "Device has no remote schema context yet. Probably not fully connected.");
- Preconditions.checkNotNull(netconfSessionPreferences, "Device has no capabilities yet. Probably not fully connected.");
- this.actorSystem = actorSystem;
- final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
-
- final ProxyNetconfDeviceDataBroker masterDataBroker = TypedActor.get(actorSystem).typedActorOf(new TypedProps<>(ProxyNetconfDeviceDataBroker.class, NetconfDeviceMasterDataBroker.class), masterRef);
- LOG.warn("Creating slave data broker for device {}", id);
- final DOMDataBroker deviceDataBroker = new NetconfDeviceSlaveDataBroker(actorSystem, id, masterDataBroker);
- salProvider.getMountInstance().onTopologyDeviceConnected(remoteSchemaContext, deviceDataBroker, deviceRpc, notificationService);
- }
-
- public void unregisterMountPoint() {
- salProvider.getMountInstance().onTopologyDeviceDisconnected();
- if (deviceDataBroker != null) {
- LOG.debug("Stopping master data broker for device {}", id.getName());
- for (final Member member : Cluster.get(actorSystem).state().getMembers()) {
- if (member.address().equals(Cluster.get(actorSystem).selfAddress())) {
- continue;
- }
- final NetconfTopologyPathCreator pathCreator = new NetconfTopologyPathCreator(member.address().toString(), topologyId);
- final String path = pathCreator.withSuffix(id.getName()).build();
- actorSystem.actorSelection(path).tell(new AnnounceMasterMountPointDown(), null);
- }
- TypedActor.get(actorSystem).stop(deviceDataBroker);
- deviceDataBroker = null;
- }
- }
-
- public ConnectionStatusListenerRegistration registerConnectionStatusListener(final RemoteDeviceHandler<NetconfSessionPreferences> listener) {
- connectionStatusListeners.add(listener);
- return new ConnectionStatusListenerRegistration(listener);
- }
-
- @Override
- public void close() {
- closeGracefully(salProvider);
- }
-
- private void closeGracefully(final AutoCloseable resource) {
- if (resource != null) {
- try {
- resource.close();
- } catch (final Exception e) {
- LOG.warn("{}: Ignoring exception while closing {}", id, resource, e);
- }
- }
- }
-
- public class ConnectionStatusListenerRegistration{
-
- private final RemoteDeviceHandler<NetconfSessionPreferences> listener;
-
- public ConnectionStatusListenerRegistration(final RemoteDeviceHandler<NetconfSessionPreferences> listener) {
- this.listener = listener;
- }
-
- public void close() {
- connectionStatusListeners.remove(listener);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline.messages;
-
-import java.io.Serializable;
-
-public class AnnounceClusteredDeviceSourcesResolverUp implements Serializable {
- public static final long serialVersionUID = 1L;
-
- public AnnounceClusteredDeviceSourcesResolverUp() {}
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline.messages;
-
-import java.io.Serializable;
-
-public class AnnounceMasterOnSameNodeUp implements Serializable {
- public static long serialVersionUID = 1L;
-
- public AnnounceMasterOnSameNodeUp() {
-
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline.messages;
-
-import java.io.Serializable;
-
-public class AnnounceMasterSourceProviderUp implements Serializable {
- public static final long serialVersionUID = 1L;
-
- public AnnounceMasterSourceProviderUp() {
-
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.pipeline.tx;
-
-import akka.actor.ActorSystem;
-import akka.dispatch.OnComplete;
-import com.google.common.base.Function;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
-import javax.annotation.Nullable;
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
-import org.opendaylight.netconf.topology.pipeline.ProxyNetconfDeviceDataBroker;
-import org.opendaylight.netconf.topology.util.messages.NormalizedNodeMessage;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import scala.concurrent.Future;
-
-public class ProxyWriteOnlyTransaction implements DOMDataWriteTransaction {
-
- private final ProxyNetconfDeviceDataBroker delegate;
- private final ActorSystem actorSystem;
-
- public ProxyWriteOnlyTransaction(ActorSystem actorSystem, final ProxyNetconfDeviceDataBroker delegate) {
- this.delegate = delegate;
- this.actorSystem = actorSystem;
- }
-
- @Override
- public void put (final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode < ?,?>data){
- delegate.put(store, new NormalizedNodeMessage(path, data));
- }
-
- @Override
- public void merge (final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode < ?,?>data){
- delegate.merge(store, new NormalizedNodeMessage(path, data));
- }
-
- @Override
- public boolean cancel () {
- return delegate.cancel();
- }
-
- @Override
- public void delete (final LogicalDatastoreType store, final YangInstanceIdentifier path){
- delegate.delete(store, path);
- }
-
- @Override
- public CheckedFuture<Void, TransactionCommitFailedException> submit() {
- final Future<Void> submit = delegate.submit();
- final SettableFuture<Void> settableFuture = SettableFuture.create();
- final CheckedFuture<Void, TransactionCommitFailedException> checkedFuture = Futures.makeChecked(settableFuture, new Function<Exception, TransactionCommitFailedException>() {
- @Nullable
- @Override
- public TransactionCommitFailedException apply(Exception input) {
- return new TransactionCommitFailedException("Transaction commit failed", input);
- }
- });
- submit.onComplete(new OnComplete<Void>() {
- @Override
- public void onComplete(Throwable throwable, Void aVoid) throws Throwable {
- if (throwable == null) {
- settableFuture.set(aVoid);
- } else {
- settableFuture.setException(throwable);
- }
- }
- }, actorSystem.dispatcher());
- return checkedFuture;
- }
-
- @Override
- public ListenableFuture<RpcResult<TransactionStatus>> commit () {
- final Future<RpcResult<TransactionStatus>> commit = delegate.commit();
- final SettableFuture<RpcResult<TransactionStatus>> settableFuture = SettableFuture.create();
- commit.onComplete(new OnComplete<RpcResult<TransactionStatus>>() {
- @Override
- public void onComplete(Throwable throwable, RpcResult<TransactionStatus> transactionStatusRpcResult) throws Throwable {
- if (throwable == null) {
- settableFuture.set(transactionStatusRpcResult);
- } else {
- settableFuture.setException(throwable);
- }
- }
- }, actorSystem.dispatcher());
- return settableFuture;
- }
-
- @Override
- public Object getIdentifier () {
- return this;
- }
-}
+++ /dev/null
-module clustered-netconf-topology {
-
- yang-version 1;
- namespace "urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology";
- prefix "nt";
-
- import config { prefix config; revision-date 2013-04-05; }
- import threadpool {prefix th;}
- import netty {prefix netty;}
- import opendaylight-md-sal-dom {prefix dom;}
- import opendaylight-md-sal-binding {prefix md-sal-binding; revision-date 2013-10-28;}
- import odl-netconf-cfg { prefix cfg-net; revision-date 2014-04-08; }
- import shared-schema-repository { prefix sh; revision-date 2015-07-27; }
- import netconf-topology { prefix topo; revision-date 2015-07-27; }
- import opendaylight-entity-ownership-service { prefix eos; revision-date 2015-08-10; }
- import actor-system-provider-service { prefix asp; revision-date 2015-10-05; }
-
- description
- "Module definition for Netconf topolgy. Netconf topology provides a set of common configuration ";
-
- revision "2015-11-04" {
- description
- "Initial revision";
- }
-
- identity clustered-netconf-topology-impl {
- base config:module-type;
- config:java-name-prefix ClusteredNetconfTopology;
- config:provided-service topo:netconf-topology;
- }
-
- augment "/config:modules/config:module/config:configuration" {
- case clustered-netconf-topology-impl {
- when "/config:modules/config:module/config:type = 'clustered-netconf-topology-impl'";
-
- leaf topology-id {
- mandatory true;
- type string;
- }
-
- container dom-registry {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity dom:dom-broker-osgi-registry;
- }
- }
- }
-
- container binding-registry {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity md-sal-binding:binding-broker-osgi-registry;
- }
- }
- }
-
- container event-executor {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity netty:netty-event-executor;
- }
- }
- }
-
- container processing-executor {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity th:threadpool;
- }
- }
-
- description "Makes up for flaws in netty threading design";
- }
-
- container client-dispatcher {
- uses config:service-ref {
- refine type {
- mandatory false;
- config:required-identity cfg-net:netconf-client-dispatcher;
- }
- }
- }
-
- container keepalive-executor {
- uses config:service-ref {
- refine type {
- mandatory false;
- config:required-identity th:scheduled-threadpool;
- }
- }
-
- description "Dedicated solely to keepalive execution";
- }
-
- container shared-schema-repository {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity sh:shared-schema-repository;
- }
- }
- }
-
- container entity-ownership-service {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity eos:entity-ownership-service;
- }
- }
- }
-
- container actor-system-provider-service {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity asp:actor-system-provider-service;
- }
- }
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2016 Cisco Systems, Inc. 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;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import akka.actor.ActorContext;
-import akka.actor.ActorRef;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.ImmediateEventExecutor;
-import io.netty.util.concurrent.SucceededFuture;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
-import java.util.concurrent.ExecutionException;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
-import org.opendaylight.controller.config.threadpool.ThreadPool;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.controller.sal.core.api.Broker;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
-import org.opendaylight.netconf.client.NetconfClientSessionListener;
-import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
-import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
-import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
-import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
-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.KeepaliveSalFacade;
-import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.netconf.topology.pipeline.TopologyMountPointFacade;
-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.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
-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.credentials.Credentials;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPasswordBuilder;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
-import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
-
-public class AbstractNetconfTopologyTest {
-
- private static final NodeId NODE_ID = new NodeId("testing-node");
- private static final String TOPOLOGY_ID = "testing-topology";
-
- @Mock
- private Broker mockedDataBroker;
-
- @Mock
- private NetconfClientDispatcher mockedClientDispatcher;
-
- @Mock
- private BindingAwareBroker mockedBindingAwareBroker;
-
- @Mock
- private EventExecutor mockedEventExecutor;
-
- @Mock
- private ScheduledThreadPool mockedKeepaliveExecutor;
-
- @Mock
- private ThreadPool mockedProcessingExecutor;
-
- @Mock
- private SchemaRepositoryProvider mockedSchemaRepositoryProvider;
-
-
- private TestingAbstractNetconfTopology topology;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- when(mockedSchemaRepositoryProvider.getSharedSchemaRepository()).thenReturn(new SharedSchemaRepository("testingSharedSchemaRepo"));
- when(mockedProcessingExecutor.getExecutor()).thenReturn(MoreExecutors.newDirectExecutorService());
- Future<Void> future = new SucceededFuture<>(ImmediateEventExecutor.INSTANCE, null);
- when(mockedClientDispatcher.createReconnectingClient(any(NetconfReconnectingClientConfiguration.class))).thenReturn(future);
-
- topology = new TestingAbstractNetconfTopology(TOPOLOGY_ID, mockedClientDispatcher, mockedBindingAwareBroker,
- mockedDataBroker, mockedEventExecutor, mockedKeepaliveExecutor, mockedProcessingExecutor, mockedSchemaRepositoryProvider);
- }
-
- @Test
- public void testCreateSalFacade() {
- NetconfNode testingNode = new NetconfNodeBuilder()
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(9999))
- .setReconnectOnChangedSchema(true)
- .setDefaultRequestTimeoutMillis(1000L)
- .setBetweenAttemptsTimeoutMillis(100)
- .setSchemaless(false)
- .build();
-
- AbstractNetconfTopology.NetconfConnectorDTO connectorDTO = topology.createDeviceCommunicator(NODE_ID, testingNode);
- assertSame(connectorDTO.getFacade(), topology.getFacade());
- }
-
- @Test
- public void testCreateKeepAliveSalFacade() {
- NetconfNode testingNode = new NetconfNodeBuilder()
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(9999))
- .setReconnectOnChangedSchema(true)
- .setDefaultRequestTimeoutMillis(1000L)
- .setBetweenAttemptsTimeoutMillis(100)
- .setKeepaliveDelay(1L)
- .setSchemaless(false)
- .build();
-
- AbstractNetconfTopology.NetconfConnectorDTO connectorDTO = topology.createDeviceCommunicator(NODE_ID, testingNode);
- assertTrue(connectorDTO.getFacade() instanceof KeepaliveSalFacade);
- }
-
- @Test
- public void testSetupSchemaResourceDTO() {
- NetconfNode testingNode = new NetconfNodeBuilder()
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(9999))
- .setReconnectOnChangedSchema(true)
- .setDefaultRequestTimeoutMillis(1000L)
- .setBetweenAttemptsTimeoutMillis(100)
- .setKeepaliveDelay(1000L).build();
-
- NetconfDevice.SchemaResourcesDTO resultDTO = topology.setupSchemaCacheDTO(NODE_ID, testingNode);
- SharedSchemaRepository repo = (SharedSchemaRepository) resultDTO.getSchemaRegistry();
- assertEquals(repo.getIdentifier(), "sal-netconf-connector");
-
- testingNode = new NetconfNodeBuilder()
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(9999))
- .setReconnectOnChangedSchema(true)
- .setDefaultRequestTimeoutMillis(1000L)
- .setBetweenAttemptsTimeoutMillis(100)
- .setKeepaliveDelay(1000L)
- .setSchemaCacheDirectory("test-directory")
- .build();
-
- resultDTO = topology.setupSchemaCacheDTO(NODE_ID, testingNode);
- repo = (SharedSchemaRepository) resultDTO.getSchemaRegistry();
- assertEquals(repo.getIdentifier(), "test-directory");
- }
-
- @Test
- public void testGetClientConfig() throws UnknownHostException {
- NetconfClientSessionListener listener = mock(NetconfClientSessionListener.class);
- Host host = new Host(new IpAddress(new Ipv4Address("127.0.0.1")));
- PortNumber portNumber = new PortNumber(9999);
- NetconfNode testingNode = new NetconfNodeBuilder()
- .setConnectionTimeoutMillis(1000L)
- .setDefaultRequestTimeoutMillis(2000L)
- .setHost(host)
- .setPort(portNumber)
- .setCredentials(new LoginPasswordBuilder().setUsername("testuser").setPassword("testpassword").build())
- .setTcpOnly(true)
- .build();
- NetconfReconnectingClientConfiguration defaultClientConfig = topology.getClientConfig(listener, testingNode);
-
- assertEquals(defaultClientConfig.getConnectionTimeoutMillis().longValue(), 1000L);
- assertEquals(defaultClientConfig.getAddress(), new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 9999));
- assertSame(defaultClientConfig.getSessionListener(), listener);
- assertEquals(defaultClientConfig.getAuthHandler().getUsername(), "testuser");
- assertEquals(defaultClientConfig.getProtocol(), NetconfClientConfiguration.NetconfClientProtocol.TCP);
- }
-
- @Test
- public void testGetClientConfigNotSupportedCredentialsFail() {
- NetconfClientSessionListener listener = mock(NetconfClientSessionListener.class);
- Host host = new Host(new IpAddress(new Ipv4Address("127.0.0.1")));
- PortNumber portNumber = new PortNumber(9999);
-
- Credentials notSupportedCredentials = new Credentials() {
- @Override
- public Class<? extends DataContainer> getImplementedInterface() {
- return Credentials.class;
- }
- };
-
- NetconfNode testingNode = new NetconfNodeBuilder()
- .setConnectionTimeoutMillis(1000L)
- .setDefaultRequestTimeoutMillis(2000L)
- .setHost(host)
- .setPort(portNumber)
- .setCredentials(notSupportedCredentials)
- .setTcpOnly(true)
- .build();
- try {
- topology.getClientConfig(listener, testingNode);
- fail("Exception expected here.");
- } catch(Exception e) {
- assertTrue(e instanceof IllegalStateException);
- }
- }
-
- @Test
- public void testConnectNode() {
- NetconfNode testingNode = new NetconfNodeBuilder()
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(9999))
- .setReconnectOnChangedSchema(true)
- .setDefaultRequestTimeoutMillis(1000L)
- .setBetweenAttemptsTimeoutMillis(100)
- .setKeepaliveDelay(1000L)
- .setTcpOnly(true)
- .setSchemaless(false)
- .setCredentials(new LoginPasswordBuilder().setUsername("testuser").setPassword("testpassword").build())
- .build();
- Node nd = mock(Node.class);
- when(nd.getAugmentation(NetconfNode.class)).thenReturn(testingNode);
- topology.connectNode(NODE_ID, nd);
- assertTrue(topology.activeConnectors.containsKey(NODE_ID));
- }
-
- @Test
- public void testDisconnectNode() {
- NetconfNode testingNode = new NetconfNodeBuilder()
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(9999))
- .setReconnectOnChangedSchema(true)
- .setDefaultRequestTimeoutMillis(1000L)
- .setBetweenAttemptsTimeoutMillis(100)
- .setKeepaliveDelay(1000L)
- .setTcpOnly(true)
- .setSchemaless(false)
- .setCredentials(new LoginPasswordBuilder().setUsername("testuser").setPassword("testpassword").build())
- .build();
- Node nd = mock(Node.class);
- when(nd.getAugmentation(NetconfNode.class)).thenReturn(testingNode);
- topology.connectNode(NODE_ID, nd);
- assertTrue(topology.activeConnectors.containsKey(NODE_ID));
- assertTrue(topology.disconnectNode(NODE_ID).isDone());
- assertTrue(!topology.activeConnectors.containsKey(NODE_ID));
- verify(topology.getFacade()).close();
- }
-
- @Test
- public void testDisconnectNotConnectedNode() throws ExecutionException, InterruptedException {
- ListenableFuture disconnectFuture = topology.disconnectNode(NODE_ID);
- assertTrue(disconnectFuture.isDone());
- try {
- disconnectFuture.get();
- fail("Exception expected!");
- } catch(Exception e) {
- assertTrue(e instanceof ExecutionException);
- assertTrue(e.getCause() instanceof IllegalStateException);
- }
- }
-
- public static class TestingAbstractNetconfTopology extends AbstractNetconfTopology {
-
- private RemoteDeviceHandler salFacade;
-
- protected TestingAbstractNetconfTopology(String topologyId, NetconfClientDispatcher clientDispatcher,
- BindingAwareBroker bindingAwareBroker, Broker domBroker,
- EventExecutor eventExecutor, ScheduledThreadPool keepaliveExecutor,
- ThreadPool processingExecutor,
- SchemaRepositoryProvider schemaRepositoryProvider) {
- super(topologyId, clientDispatcher, bindingAwareBroker, domBroker, eventExecutor, keepaliveExecutor, processingExecutor, schemaRepositoryProvider);
- salFacade = mock(RemoteDeviceHandler.class);
- }
-
- public RemoteDeviceHandler<NetconfSessionPreferences> getFacade() {
- return salFacade;
- }
-
- @Override
- public void onSessionInitiated(BindingAwareBroker.ProviderContext session) {
-
- }
-
- @Override
- protected RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(RemoteDeviceId id, Broker domBroker, BindingAwareBroker bindingBroker) {
- return salFacade;
- }
-
- @Override
- public TopologyMountPointFacade.ConnectionStatusListenerRegistration registerConnectionStatusListener(NodeId node, RemoteDeviceHandler<NetconfSessionPreferences> listener) {
- return null;
- }
-
- @Override
- public void registerMountPoint(ActorContext context, NodeId nodeId) {
-
- }
-
- @Override
- public void registerMountPoint(ActorContext context, NodeId nodeId, ActorRef masterRef) {
-
- }
-
- @Override
- public void unregisterMountPoint(NodeId nodeId) {
-
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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;
-
-import static com.jayway.awaitility.Awaitility.await;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.when;
-
-import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
-import akka.actor.TypedActor;
-import akka.actor.TypedActorExtension;
-import akka.actor.TypedProps;
-import akka.japi.Creator;
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
-import com.typesafe.config.ConfigFactory;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import javassist.ClassPool;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
-import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
-import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.topology.NodeManagerCallback.NodeManagerCallbackFactory;
-import org.opendaylight.netconf.topology.TopologyManagerCallback.TopologyManagerCallbackFactory;
-import org.opendaylight.netconf.topology.example.ExampleNodeManagerCallback;
-import org.opendaylight.netconf.topology.example.ExampleTopologyManagerCallback;
-import org.opendaylight.netconf.topology.example.LoggingSalNodeWriter;
-import org.opendaylight.netconf.topology.impl.NetconfNodeOperationalDataAggregator;
-import org.opendaylight.netconf.topology.util.BaseTopologyManager;
-import org.opendaylight.netconf.topology.util.NoopRoleChangeStrategy;
-import org.opendaylight.netconf.topology.util.TopologyRoleChangeStrategy;
-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.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.$YangModuleInfoImpl;
-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.NetconfNodeConnectionStatus.ConnectionStatus;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.AvailableCapabilitiesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.ClusteredConnectionStatusBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.UnavailableCapabilitiesBuilder;
-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.clustered.connection.status.NodeStatus.Status;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.clustered.connection.status.NodeStatusBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
-import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
-import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
-import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
-import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
-import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ActorTest {
-
- private static final Logger LOG = LoggerFactory.getLogger(ActorTest.class);
-
- private static final String TOPOLOGY_NETCONF = "TopologyNetconf";
-
- @Mock
- private EntityOwnershipService entityOwnershipService;
-
- @Mock
- private DataBroker dataBroker;
-
- @Mock
- private ReadOnlyTransaction mockedReadOnlyTx;
-
- private static final BindingNormalizedNodeCodecRegistry CODEC_REGISTRY;
-
- static {
- final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
- moduleInfoBackedContext.addModuleInfos(Collections.singletonList($YangModuleInfoImpl.getInstance()));
- final Optional<SchemaContext> schemaContextOptional = moduleInfoBackedContext.tryToCreateSchemaContext();
- Preconditions.checkState(schemaContextOptional.isPresent());
- final SchemaContext topologySchemaCtx = schemaContextOptional.get();
-
- final JavassistUtils javassist = JavassistUtils.forClassPool(ClassPool.getDefault());
- CODEC_REGISTRY = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(javassist));
- CODEC_REGISTRY.onBindingRuntimeContextUpdated(BindingRuntimeContext.create(moduleInfoBackedContext, topologySchemaCtx));
- }
-
- private static final String PATH_MASTER = "akka.tcp://NetconfNode@127.0.0.1:2552/user/TopologyNetconf";
- private static final String PATH_SLAVE1 = "akka.tcp://NetconfNode@127.0.0.1:2553/user/TopologyNetconf";
- private static final String PATH_SLAVE2 = "akka.tcp://NetconfNode@127.0.0.1:2554/user/TopologyNetconf";
-
- private static final List<String> PATHS_MASTER = Lists.newArrayList(PATH_SLAVE1, PATH_SLAVE2);
- private static final List<String> PATHS_SLAVE1 = Lists.newArrayList(PATH_MASTER, PATH_SLAVE2);
- private static final List<String> PATHS_SLAVE2 = Lists.newArrayList(PATH_MASTER, PATH_SLAVE1);
-
- private static final ActorSystem ACTOR_SYSTEM = ActorSystem.create("NetconfNode", ConfigFactory.load("netconf-node1"));
- private static final ActorSystem ACTOR_SYSTEM_SLAVE1 = ActorSystem.create("NetconfNode", ConfigFactory.load("netconf-node2"));
- private static final ActorSystem ACTOR_SYSTEM_SLAVE2 = ActorSystem.create("NetconfNode", ConfigFactory.load("netconf-node3"));
-
- private static final ExecutorService callbackExecutor = Executors.newFixedThreadPool(8);
-
- private TopologyManager master = null;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- final SettableFuture<Optional<Topology>> settableFuture = SettableFuture.create();
- final CheckedFuture<Optional<Topology>, ReadFailedException> checkedFuture = Futures.makeChecked(settableFuture, new Function<Exception, ReadFailedException>() {
- @Nullable
- @Override
- public ReadFailedException apply(Exception input) {
- return new ReadFailedException("Dummy future should never return this");
- }
- });
- settableFuture.set(Optional.<Topology>absent());
- when(mockedReadOnlyTx.read(any(LogicalDatastoreType.class), any(InstanceIdentifier.class))).thenReturn(checkedFuture);
- when(dataBroker.registerDataChangeListener(
- any(LogicalDatastoreType.class),
- any(InstanceIdentifier.class),
- any(DataChangeListener.class),
- any(DataChangeScope.class))).thenReturn(null);
- when(dataBroker.newReadOnlyTransaction()).thenReturn(mockedReadOnlyTx);
- }
-
- private void setMaster(final TopologyManager manager) {
-
- }
-
- @Test
- public void testRealActors() throws Exception {
-
- EntityOwnershipService topoOwnership = new TestingEntityOwnershipService();
- // load from config
- final TopologyManager master = createManagerWithOwnership(ACTOR_SYSTEM, TOPOLOGY_NETCONF, true, createRealTopoTestingNodeCallbackFactory(), new TopologyRoleChangeStrategy(dataBroker, topoOwnership, TOPOLOGY_NETCONF, "topology-manager"));
- Thread.sleep(1000);
- final TopologyManager slave1 = createManagerWithOwnership(ACTOR_SYSTEM_SLAVE1, TOPOLOGY_NETCONF, false, createRealTopoTestingNodeCallbackFactory(), new TopologyRoleChangeStrategy(dataBroker, topoOwnership, TOPOLOGY_NETCONF, "topology-manager"));
- final TopologyManager slave2 = createManagerWithOwnership(ACTOR_SYSTEM_SLAVE2, TOPOLOGY_NETCONF, false, createRealTopoTestingNodeCallbackFactory(), new TopologyRoleChangeStrategy(dataBroker, topoOwnership, TOPOLOGY_NETCONF, "topology-manager"));
-
- await().atMost(30L, TimeUnit.SECONDS).until(new Callable<Boolean>() {
- @Override
- public Boolean call() throws Exception {
- return master.hasAllPeersUp();
- }
- });
-
- final List<ListenableFuture<Node>> futures = new ArrayList<>();
- for (int i = 0; i <= 1; i++) {
- final String nodeid = "testing-node" + i;
- final Node testingNode = new NodeBuilder()
- .setNodeId(new NodeId(nodeid))
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(10000 + i))
- .build())
- .build();
- final ListenableFuture<Node> nodeListenableFuture = master.onNodeCreated(new NodeId(nodeid), testingNode);
- futures.add(nodeListenableFuture);
- Futures.addCallback(nodeListenableFuture, new FutureCallback<Node>() {
- @Override
- public void onSuccess(Node result) {
- LOG.warn("Node {} created succesfully on all nodes", result.getNodeId().getValue());
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.warn("Node creation failed. ", t);
- }
- });
- }
-
- for (int i = 0; i <= 1; i++) {
- final String nodeid = "testing-node" + i;
- final Node testingNode = new NodeBuilder()
- .setNodeId(new NodeId(nodeid))
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(10000 + i))
- .build())
- .build();
- final ListenableFuture<Node> nodeListenableFuture = master.onNodeUpdated(new NodeId(nodeid), testingNode);
- futures.add(nodeListenableFuture);
- Futures.addCallback(nodeListenableFuture, new FutureCallback<Node>() {
- @Override
- public void onSuccess(Node result) {
- LOG.warn("Node {} updated succesfully on all nodes", result.getNodeId().getValue());
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.warn("Node update failed. ", t);
- }
- });
- }
- LOG.debug("Waiting for updates to finish");
- Futures.allAsList(futures).get();
-
-
- final List<ListenableFuture<Void>> deleteFutures = new ArrayList<>();
- for (int i = 0; i <= 1; i++) {
- final String nodeid = "testing-node" + i;
- final ListenableFuture<Void> nodeListenableFuture = master.onNodeDeleted(new NodeId(nodeid));
- deleteFutures.add(nodeListenableFuture);
- Futures.addCallback(nodeListenableFuture, new FutureCallback<Void>() {
- @Override
- public void onSuccess(Void result) {
- LOG.warn("Node {} succesfully deleted on all nodes", nodeid);
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.warn("Node delete failed. ", t);
- }
- });
-
- }
- LOG.warn("All tasks submitted");
- Futures.allAsList(futures).get();
- Futures.allAsList(deleteFutures).get();
-
- TypedActor.get(ACTOR_SYSTEM).stop(master);
- TypedActor.get(ACTOR_SYSTEM_SLAVE1).stop(slave1);
- TypedActor.get(ACTOR_SYSTEM_SLAVE2).stop(slave2);
-
- }
-
- // TODO seems like stopping actors is not enough to create an actor with same name, split this into multiple classes?
- @Ignore
- @Test
- public void testWithDummyOwnershipService() throws Exception {
-
- final TestingEntityOwnershipService ownershipService = new TestingEntityOwnershipService();
- // load from config
- final TopologyManager master = createNoopRoleChangeNode(ACTOR_SYSTEM, TOPOLOGY_NETCONF, true, createRealTopoCallbackFactory(ownershipService));
- final TopologyManager slave1 = createNoopRoleChangeNode(ACTOR_SYSTEM_SLAVE1, TOPOLOGY_NETCONF, false, createRealTopoCallbackFactory(ownershipService));
- final TopologyManager slave2 = createNoopRoleChangeNode(ACTOR_SYSTEM_SLAVE2, TOPOLOGY_NETCONF, false, createRealTopoCallbackFactory(ownershipService));
-
- await().atMost(10L, TimeUnit.SECONDS).until(new Callable<Boolean>() {
- @Override
- public Boolean call() throws Exception {
- return master.hasAllPeersUp();
- }
- });
-
- final List<ListenableFuture<Node>> futures = new ArrayList<>();
- for (int i = 0; i <= 0; i++) {
- final String nodeid = "testing-node" + i;
- final Node testingNode = new NodeBuilder()
- .setNodeId(new NodeId(nodeid))
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(10000 + i))
- .build())
- .build();
- final ListenableFuture<Node> nodeListenableFuture = master.onNodeCreated(new NodeId(nodeid), testingNode);
- futures.add(nodeListenableFuture);
- Futures.addCallback(nodeListenableFuture, new FutureCallback<Node>() {
- @Override
- public void onSuccess(Node result) {
- LOG.warn("Node {} created succesfully on all nodes", result.getNodeId().getValue());
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.warn("Node creation failed. ", t);
- }
- });
- }
-
- Futures.allAsList(futures).get();
- ownershipService.distributeOwnership();
-
- Thread.sleep(30000);
- TypedActor.get(ACTOR_SYSTEM).stop(master);
- TypedActor.get(ACTOR_SYSTEM_SLAVE1).stop(slave1);
- TypedActor.get(ACTOR_SYSTEM_SLAVE2).stop(slave2);
- }
-
- private TopologyManager createNoopRoleChangeNode(final ActorSystem actorSystem, final String topologyId, final boolean isMaster,
- final TopologyManagerCallbackFactory topologyManagerCallbackFactory) {
-
- final TypedActorExtension typedActorExtension = TypedActor.get(actorSystem);
- return typedActorExtension.typedActorOf(new TypedProps<>(TopologyManager.class, new Creator<BaseTopologyManager>() {
- @Override
- public BaseTopologyManager create() throws Exception {
- return new BaseTopologyManager(actorSystem,
- CODEC_REGISTRY,
- dataBroker,
- topologyId,
- topologyManagerCallbackFactory,
- new TestingSuccesfulStateAggregator(),
- new LoggingSalNodeWriter(),
- new NoopRoleChangeStrategy(),
- isMaster);
- }
- }), TOPOLOGY_NETCONF);
- }
-
- private TopologyManager createManagerWithOwnership(final ActorSystem actorSystem, final String topologyId, final boolean isMaster,
- final TopologyManagerCallbackFactory topologyManagerCallbackFactory, final RoleChangeStrategy roleChangeStrategy) {
- final TypedActorExtension typedActorExtension = TypedActor.get(actorSystem);
- return typedActorExtension.typedActorOf(new TypedProps<>(TopologyManager.class, new Creator<BaseTopologyManager>() {
- @Override
- public BaseTopologyManager create() throws Exception {
- return new BaseTopologyManager(actorSystem,
- CODEC_REGISTRY,
- dataBroker,
- topologyId,
- topologyManagerCallbackFactory,
- new NetconfNodeOperationalDataAggregator(),
- new LoggingSalNodeWriter(),
- roleChangeStrategy,
- isMaster);
- }
- }), TOPOLOGY_NETCONF);
- }
-
- private TopologyManagerCallbackFactory createRealTopoTestingNodeCallbackFactory() {
- final NodeManagerCallbackFactory nodeManagerCallbackFactory = new NodeManagerCallbackFactory() {
- @Override
- public NodeManagerCallback create(String nodeId, String topologyId, ActorSystem actorSystem) {
- return new LoggingNodeManagerCallback();
- }
- };
-
- return new TopologyManagerCallbackFactory() {
- @Override
- public TopologyManagerCallback create(ActorSystem actorSystem, String topologyId) {
- return new ExampleTopologyManagerCallback(actorSystem, dataBroker, topologyId, nodeManagerCallbackFactory, new LoggingSalNodeWriter());
- }
- };
- }
-
- private TopologyManagerCallbackFactory createRealTopoCallbackFactory(final EntityOwnershipService entityOwnershipService) {
- final NodeManagerCallbackFactory nodeManagerCallbackFactory = new NodeManagerCallbackFactory() {
- @Override
- public NodeManagerCallback create(String nodeId, String topologyId, ActorSystem actorSystem) {
- return new ExampleNodeManagerCallback();
- }
- };
-
- return new TopologyManagerCallbackFactory() {
- @Override
- public TopologyManagerCallback create(ActorSystem actorSystem, String topologyId) {
- return new ExampleTopologyManagerCallback(actorSystem, dataBroker, topologyId, nodeManagerCallbackFactory);
- }
- };
- }
-
- private TopologyManagerCallbackFactory createTestingTopoCallbackFactory() {
- return new TopologyManagerCallbackFactory() {
- @Override
- public TopologyManagerCallback create(ActorSystem actorSystem, String topologyId) {
- return new TestingTopologyManagerCallback();
- }
- };
- }
-
- public static class LoggingNodeManagerCallback implements NodeManagerCallback {
-
- @Nonnull
- @Override
- public Node getInitialState(@Nonnull NodeId nodeId, @Nonnull Node configNode) {
- final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class);
- return new NodeBuilder()
- .setNodeId(nodeId)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setHost(netconfNode.getHost())
- .setPort(netconfNode.getPort())
- .setConnectionStatus(ConnectionStatus.Connecting)
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(
- Lists.newArrayList(
- new NodeStatusBuilder()
- .setNode("testing-node")
- .setStatus(Status.Unavailable)
- .build()))
- .build())
- .build())
- .build();
- }
-
- @Nonnull
- @Override
- public Node getFailedState(@Nonnull NodeId nodeId, @Nonnull Node configNode) {
- final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class);
- return new NodeBuilder()
- .setNodeId(nodeId)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setHost(netconfNode.getHost())
- .setPort(netconfNode.getPort())
- .setConnectionStatus(ConnectionStatus.UnableToConnect)
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(
- Collections.singletonList(
- new NodeStatusBuilder()
- .setNode("testing-node")
- .setStatus(Status.Failed)
- .build()))
- .build())
- .build())
- .build();
- }
-
- @Nonnull
- @Override
- public ListenableFuture<Node> onNodeCreated(@Nonnull NodeId nodeId, @Nonnull Node configNode) {
- LOG.debug("Creating node {} with config {}", nodeId, configNode);
- final NetconfNode augmentation = configNode.getAugmentation(NetconfNode.class);
- return Futures.immediateFuture(new NodeBuilder()
- .setNodeId(nodeId)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setConnectionStatus(ConnectionStatus.Connected)
- .setHost(augmentation.getHost())
- .setPort(augmentation.getPort())
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(
- Collections.singletonList(
- new NodeStatusBuilder()
- .setNode("testing-node")
- .setStatus(Status.Connected)
- .build()))
- .build())
- .build())
- .build());
- }
-
- @Nonnull
- @Override
- public ListenableFuture<Node> onNodeUpdated(@Nonnull NodeId nodeId, @Nonnull Node configNode) {
- LOG.debug("Updating node {} with config {}", nodeId, configNode);
- final NetconfNode augmentation = configNode.getAugmentation(NetconfNode.class);
- return Futures.immediateFuture(new NodeBuilder()
- .setNodeId(nodeId)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setConnectionStatus(ConnectionStatus.Connected)
- .setHost(augmentation.getHost())
- .setPort(augmentation.getPort())
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(
- Collections.singletonList(
- new NodeStatusBuilder()
- .setNode("testing-node")
- .setStatus(Status.Connected)
- .build()))
- .build())
- .build())
- .build());
- }
-
- @Nonnull
- @Override
- public ListenableFuture<Void> onNodeDeleted(@Nonnull NodeId nodeId) {
- LOG.debug("Deleting node {}", nodeId);
- return Futures.immediateFuture(null);
- }
-
- @Nonnull
- @Override
- public ListenableFuture<Node> getCurrentStatusForNode(@Nonnull NodeId nodeId) {
- return null;
- }
-
- @Override
- public void onRoleChanged(RoleChangeDTO roleChangeDTO) {
-
- }
-
- @Override
- public void onReceive(Object o, ActorRef actorRef) {
-
- }
-
- @Override
- public void onDeviceConnected(SchemaContext remoteSchemaContext, NetconfSessionPreferences netconfSessionPreferences, DOMRpcService deviceRpc) {
-
- }
-
- @Override
- public void onDeviceDisconnected() {
-
- }
-
- @Override
- public void onDeviceFailed(Throwable throwable) {
-
- }
-
- @Override
- public void onNotification(DOMNotification domNotification) {
-
- }
-
- @Override
- public void close() {
-
- }
- }
-
- public static class TestingTopologyManagerCallback implements TopologyManagerCallback {
-
- public TestingTopologyManagerCallback() {
-
- }
-
- @Override
- public ListenableFuture<Node> onNodeCreated(NodeId nodeId, Node node) {
- LOG.warn("Actor system that called this: {}", TypedActor.context().system().settings().toString());
- return Futures.immediateFuture(new NodeBuilder()
- .setNodeId(nodeId)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setConnectionStatus(ConnectionStatus.Connected)
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(2555))
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .build())
- .build());
- }
-
- @Override
- public ListenableFuture<Node> onNodeUpdated(NodeId nodeId, Node node) {
- LOG.warn("Actor system that called this: {}", TypedActor.context().system().settings().toString());
- LOG.debug("Update called on node {}, with config {}", nodeId.getValue(), node);
- return Futures.immediateFuture(new NodeBuilder()
- .setNodeId(nodeId)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setConnectionStatus(ConnectionStatus.Connected)
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(65535))
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .build())
- .build());
- }
-
- @Override
- public ListenableFuture<Void> onNodeDeleted(NodeId nodeId) {
- LOG.debug("Delete called on node {}", nodeId.getValue());
- return Futures.immediateFuture(null);
- }
-
- @Nonnull
- @Override
- public ListenableFuture<Node> getCurrentStatusForNode(@Nonnull NodeId nodeId) {
- return null;
- }
-
- @Override
- public void onRoleChanged(RoleChangeDTO roleChangeDTO) {
-
- }
-
- @Override
- public void onReceive(Object o, ActorRef actorRef) {
-
- }
-
- @Nonnull
- @Override
- public Node getInitialState(@Nonnull NodeId nodeId, @Nonnull Node configNode) {
- return new NodeBuilder()
- .setNodeId(nodeId)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setConnectionStatus(ConnectionStatus.Connecting)
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(65535))
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .build())
- .build();
- }
-
- @Nonnull
- @Override
- public Node getFailedState(@Nonnull NodeId nodeId, @Nonnull Node configNode) {
- return new NodeBuilder()
- .setNodeId(nodeId)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setConnectionStatus(ConnectionStatus.UnableToConnect)
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(65535))
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .build())
- .build();
- }
- }
-
- public class TestingSuccesfulStateAggregator implements StateAggregator {
-
- @Override
- public ListenableFuture<Node> combineCreateAttempts(List<ListenableFuture<Node>> stateFutures) {
- final SettableFuture<Node> future = SettableFuture.create();
- final ListenableFuture<List<Node>> allAsList = Futures.allAsList(stateFutures);
- Futures.addCallback(allAsList, new FutureCallback<List<Node>>() {
- @Override
- public void onSuccess(List<Node> result) {
- for (int i = 0; i < result.size() - 1; i++) {
- if (!result.get(i).equals(result.get(i + 1))) {
- LOG.warn("Node 1 {}: {}", result.get(i).getClass(), result.get(i));
- LOG.warn("Node 2 {}: {}", result.get(i + 1).getClass(), result.get(i + 1));
- future.setException(new IllegalStateException("Create futures have different result"));
- LOG.warn("Future1 : {} Future2 : {}", result.get(i), result.get(i+1));
- }
- }
- future.set(result.get(0));
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.error("One of the combined create attempts failed {}", t);
- future.setException(t);
- }
- }, TypedActor.context().dispatcher());
-
- return future;
- }
-
- @Override
- public ListenableFuture<Node> combineUpdateAttempts(List<ListenableFuture<Node>> stateFutures) {
- final SettableFuture<Node> future = SettableFuture.create();
- final ListenableFuture<List<Node>> allAsList = Futures.allAsList(stateFutures);
- Futures.addCallback(allAsList, new FutureCallback<List<Node>>() {
- @Override
- public void onSuccess(List<Node> result) {
- for (int i = 0; i < result.size() - 1; i++) {
- if (!result.get(i).equals(result.get(i + 1))) {
- future.setException(new IllegalStateException("Update futures have different result"));
- }
- }
- future.set(result.get(0));
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.error("One of the combined update attempts failed {}", t);
- future.setException(t);
- }
- });
- return future;
- }
-
- @Override
- public ListenableFuture<Void> combineDeleteAttempts(List<ListenableFuture<Void>> stateFutures) {
- final SettableFuture<Void> future = SettableFuture.create();
- final ListenableFuture<List<Void>> allAsList = Futures.allAsList(stateFutures);
- Futures.addCallback(allAsList, new FutureCallback<List<Void>>() {
- @Override
- public void onSuccess(List<Void> result) {
- future.set(null);
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.error("One of the combined delete attempts failed {}", t);
- future.setException(t);
- }
- });
- return future;
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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;
-
-import com.google.common.base.Optional;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import javax.annotation.Nonnull;
-import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
-import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class TestingEntityOwnershipService implements EntityOwnershipService{
-
- private static final Logger LOG = LoggerFactory.getLogger(TestingEntityOwnershipService.class);
-
- private final List<EntityOwnershipListener> listeners = new ArrayList<>();
- private final ExecutorService executorService = Executors.newFixedThreadPool(1);
-
- private Entity entity;
- private boolean masterSet = false;
-
- @Override
- public EntityOwnershipCandidateRegistration registerCandidate(final Entity entity) throws CandidateAlreadyRegisteredException {
- LOG.warn("Registering Candidate");
- this.entity = entity;
- return new EntityOwnershipCandidateRegistration() {
- @Override
- public void close() {
- LOG.debug("Closing candidate registration");
- }
-
- @Override
- public Entity getInstance() {
- return entity;
- }
- };
- }
-
- @Override
- public EntityOwnershipListenerRegistration registerListener(final String entityType, final EntityOwnershipListener listener) {
- listeners.add(listener);
- if (listeners.size() == 3) {
- distributeOwnership();
- }
- return new EntityOwnershipListenerRegistration() {
- @Nonnull
- @Override
- public String getEntityType() {
- return entityType;
- }
-
- @Override
- public void close() {
- listeners.remove(listener);
- }
-
- @Override
- public EntityOwnershipListener getInstance() {
- return listener;
- }
- };
- }
-
- @Override
- public Optional<EntityOwnershipState> getOwnershipState(final Entity forEntity) {
- return null;
- }
-
- @Override
- public boolean isCandidateRegistered(@Nonnull Entity entity) {
- return true;
- }
-
- public void distributeOwnership() {
- LOG.debug("Distributing ownership");
- executorService.submit(new Runnable() {
- @Override
- public void run() {
- masterSet = false;
- LOG.debug("Distributing ownership for {} listeners", listeners.size());
- for (final EntityOwnershipListener listener : listeners) {
- if (!masterSet) {
- listener.ownershipChanged(new EntityOwnershipChange(entity, false, true, true));
- masterSet = true;
- } else {
- listener.ownershipChanged(new EntityOwnershipChange(entity, false, false, true));
- }
- }
-
- }
- });
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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;
-
-import akka.actor.ActorContext;
-import akka.actor.ActorRef;
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.topology.pipeline.TopologyMountPointFacade.ConnectionStatusListenerRegistration;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class TestingTopologyDispatcher implements NetconfTopology{
-
- private static final Logger LOG = LoggerFactory.getLogger(TestingTopologyDispatcher.class);
-
- private final String topologyId;
-
- private final ExecutorService executorService = Executors.newSingleThreadExecutor();
- private final Set<NodeId> connected = new HashSet<>();
- private final Map<NodeId, RemoteDeviceHandler<NetconfSessionPreferences>> listeners = new HashMap<>();
-
-
- public TestingTopologyDispatcher(final String topologyId) {
-
- this.topologyId = topologyId;
- }
-
- @Override
- public String getTopologyId() {
- return topologyId;
- }
-
- @Override
- public DataBroker getDataBroker() {
- return null;
- }
-
- // log the current connection attempt and return a successful future asynchronously
- @Override
- public ListenableFuture<NetconfDeviceCapabilities> connectNode(final NodeId nodeId, final Node configNode) {
- final NetconfNode augmentation = configNode.getAugmentation(NetconfNode.class);
- LOG.debug("Connecting node {}, with config: {} ", nodeId.getValue(),
- augmentation.getHost().getIpAddress().toString() + ":" + augmentation.getPort());
- connected.add(nodeId);
- final SettableFuture<NetconfDeviceCapabilities> future = SettableFuture.create();
- executorService.submit(new Runnable() {
- @Override
- public void run() {
- try {
- Thread.sleep(4000);
- executorService.submit(new Runnable() {
- @Override
- public void run() {
- future.set(new NetconfDeviceCapabilities());
- }
- });
- } catch (InterruptedException e) {
- LOG.error("Cannot sleep thread", e);
- }
- }
- });
- return future;
- }
-
- @Override
- public ListenableFuture<Void> disconnectNode(final NodeId nodeId) {
- Preconditions.checkState(connected.contains(nodeId), "Node is not connected yet");
- LOG.debug("Disconnecting node {}", nodeId.getValue());
- final SettableFuture<Void> future = SettableFuture.create();
- executorService.submit(new Runnable() {
- @Override
- public void run() {
- try {
- Thread.sleep(4000);
- executorService.submit(new Runnable() {
- @Override
- public void run() {
- connected.remove(nodeId);
- future.set(null);
- }
- });
- } catch (InterruptedException e) {
- LOG.error("Cannot sleep thread", e);
- }
-
- }
- });
- return future;
- }
-
- @Override
- public void registerMountPoint(ActorContext context, NodeId nodeId) {
- LOG.debug("Registering mount point for node {}", nodeId.getValue());
- }
-
- @Override
- public void registerMountPoint(ActorContext context, NodeId nodeId, ActorRef masterRef) {
- LOG.debug("Registering mount point for node {}", nodeId.getValue());
- }
-
- @Override
- public void unregisterMountPoint(NodeId nodeId) {
- LOG.debug("Unregistering mount point for node {}", nodeId.getValue());
- }
-
- @Override
- public ConnectionStatusListenerRegistration registerConnectionStatusListener(final NodeId node, final RemoteDeviceHandler<NetconfSessionPreferences> listener) {
- Preconditions.checkState(connected.contains(node), "Node is not connected yet");
-
- LOG.debug("Registering a connection status listener for node {}", node.getValue());
- listeners.put(node, listener);
- executorService.submit(new Runnable() {
- @Override
- public void run() {
- try {
- Thread.sleep(10000);
-
- boolean up = false;
- for (int i = 0; i < 20; i++) {
- if (up) {
- LOG.debug("Device has connected {}", node.getValue());
- listener.onDeviceConnected(null, null, null);
- up = false;
- } else {
- LOG.debug("Device has diconnected {}", node.getValue());
- listener.onDeviceDisconnected();
- up = true;
- }
- try {
- Thread.sleep(5000);
- } catch (InterruptedException e) {
- LOG.error("Cannot sleep thread", e);
- }
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- }
- });
-
- return null;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2016 Cisco Systems, Inc. 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.impl;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import org.junit.Before;
-import org.junit.Test;
-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.NetconfNodeConnectionStatus;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.AvailableCapabilitiesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.ClusteredConnectionStatusBuilder;
-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.clustered.connection.status.NodeStatus;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.clustered.connection.status.NodeStatusBuilder;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
-
-public class NetconfNodeOperationalDataAggregatorTest {
-
- private List<ListenableFuture<Node>> stateFutures;
-
- private NetconfNodeOperationalDataAggregator aggregator;
-
- @Before
- public void setUp() {
- aggregator = new NetconfNodeOperationalDataAggregator();
- stateFutures = Lists.newArrayList();
- }
-
- @Test
- public void testCombineCreateAttempts() throws ExecutionException, InterruptedException {
- NetconfNode testingNode = new NetconfNodeBuilder().setAvailableCapabilities(
- new AvailableCapabilitiesBuilder().setAvailableCapability(Lists.<AvailableCapability>newArrayList()).build())
- .setClusteredConnectionStatus(new ClusteredConnectionStatusBuilder().setNodeStatus(Lists.newArrayList(
- new NodeStatusBuilder().setStatus(NodeStatus.Status.Connected).build())).build())
- .setConnectionStatus(NetconfNodeConnectionStatus.ConnectionStatus.Connected).build();
- stateFutures.add(Futures.immediateFuture(new NodeBuilder().addAugmentation(NetconfNode.class, testingNode).build()));
-
- ListenableFuture<Node> aggregatedCreateFuture = aggregator.combineCreateAttempts(stateFutures);
- assertTrue(aggregatedCreateFuture.isDone());
-
- NetconfNode aggregatedNode = aggregatedCreateFuture.get().getAugmentation(NetconfNode.class);
- assertEquals(aggregatedNode.getClusteredConnectionStatus().getNodeStatus().get(0).getStatus(),
- NodeStatus.Status.Connected);
- }
-
- @Test
- public void testSuccessfulCombineUpdateAttempts() throws ExecutionException, InterruptedException {
- NetconfNode testingNode = new NetconfNodeBuilder().setAvailableCapabilities(
- new AvailableCapabilitiesBuilder().setAvailableCapability(Lists.<AvailableCapability>newArrayList()).build())
- .setClusteredConnectionStatus(new ClusteredConnectionStatusBuilder().setNodeStatus(Lists.newArrayList(
- new NodeStatusBuilder().setStatus(NodeStatus.Status.Connected).build())).build())
- .setConnectionStatus(NetconfNodeConnectionStatus.ConnectionStatus.Connected).build();
- stateFutures.add(Futures.immediateFuture(new NodeBuilder().addAugmentation(NetconfNode.class, testingNode).build()));
-
- ListenableFuture<Node> aggregatedUpdateFuture = aggregator.combineUpdateAttempts(stateFutures);
- assertTrue(aggregatedUpdateFuture.isDone());
-
- NetconfNode aggregatedNode = aggregatedUpdateFuture.get().getAugmentation(NetconfNode.class);
- assertEquals(aggregatedNode.getClusteredConnectionStatus().getNodeStatus().get(0).getStatus(),
- NodeStatus.Status.Connected);
- }
-
- @Test
- public void testSuccessfulCombineDeleteAttempts() throws ExecutionException, InterruptedException {
- List deleteStateFutures = Lists.newArrayList(Futures.immediateFuture(null), Futures.immediateFuture(null));
-
- ListenableFuture<Void> deleteFuture = aggregator.combineDeleteAttempts(deleteStateFutures);
- assertTrue(deleteFuture.isDone());
- assertEquals(deleteFuture.get(), null);
- }
-
- @Test
- public void testFailedCombineDeleteAttempts() {
- Exception cause = new Exception("Fail");
- List deleteStateFutures = Lists.newArrayList(Futures.immediateFuture(null), Futures.immediateFuture(null),
- Futures.immediateFailedFuture(cause));
-
- ListenableFuture<Void> deleteFuture = aggregator.combineDeleteAttempts(deleteStateFutures);
- assertTrue(deleteFuture.isDone());
-
- try {
- deleteFuture.get();
- fail("Exception expected");
- } catch(Exception e) {
- assertSame(e.getCause(), cause);
- }
- }
-}
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import akka.actor.ActorContext;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import org.opendaylight.controller.sal.core.api.Broker;
import org.opendaylight.netconf.client.NetconfClientDispatcher;
import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
-import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.topology.SchemaRepositoryProvider;
-import org.opendaylight.netconf.topology.util.TopologyUtil;
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.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
spyTopology = spy(topology);
}
- @Test(expected = UnsupportedOperationException.class)
- public void testRegisterMountPointNotSupported() {
- ActorContext context = mock(ActorContext.class);
- topology.registerMountPoint(context, NODE_ID);
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void testUnregisterMountPointNotSupported() {
- topology.unregisterMountPoint(NODE_ID);
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void testRegisterConnectionStatusListener() {
- RemoteDeviceHandler<NetconfSessionPreferences> listener = mock(RemoteDeviceHandler.class);
- topology.registerConnectionStatusListener(NODE_ID, listener);
- }
-
@Test
public void testOnSessionInitiated() {
BindingAwareBroker.ProviderContext session = mock(BindingAwareBroker.ProviderContext.class);
+++ /dev/null
-/*
- * Copyright (c) 2016 Cisco Systems, Inc. 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.impl;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.MockitoAnnotations.initMocks;
-
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.Futures;
-import java.util.ArrayList;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
-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.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
-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.NetconfNodeConnectionStatus.ConnectionStatus;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.AvailableCapabilitiesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.ClusteredConnectionStatusBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.UnavailableCapabilitiesBuilder;
-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.clustered.connection.status.NodeStatus.Status;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.clustered.connection.status.NodeStatusBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
-
-public class TopologyNodeWriterTest {
-
- private static final NodeId NODE_ID = new NodeId("testing-node");
- private static final String TOPOLOGY_ID = "testing-topology";
-
- private static final InstanceIdentifier<NetworkTopology> NETWORK_TOPOLOGY_IID = InstanceIdentifier.builder(NetworkTopology.class).build();
- private static final KeyedInstanceIdentifier<Topology, TopologyKey> TOPOLOGY_LIST_IID;
-
- private static final KeyedInstanceIdentifier<Node, NodeKey> OPERATIONAL_NODE_IID;
-
- static {
- TOPOLOGY_LIST_IID = NETWORK_TOPOLOGY_IID.child(Topology.class, new TopologyKey(new TopologyId(TOPOLOGY_ID)));
- OPERATIONAL_NODE_IID = TOPOLOGY_LIST_IID.child(Node.class, new NodeKey(new NodeId(NODE_ID)));
- }
-
- @Mock
- private DataBroker dataBroker;
-
- @Mock
- private BindingTransactionChain txChain;
-
- @Mock
- private WriteTransaction wtx;
-
- private Node operationalNode;
-
- private TopologyNodeWriter writer;
-
- @Before
- public void setUp() throws Exception {
- initMocks(this);
- doReturn(txChain).when(dataBroker).createTransactionChain(any(TransactionChainListener.class));
- doReturn(wtx).when(txChain).newWriteOnlyTransaction();
- doNothing().when(wtx).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(DataObject.class));
- doReturn(Futures.immediateCheckedFuture(null)).when(wtx).submit();
- writer = new TopologyNodeWriter(TOPOLOGY_ID, dataBroker);
-
- operationalNode = new NodeBuilder()
- .setNodeId(NODE_ID)
- .addAugmentation(NetconfNode.class,
- new NetconfNodeBuilder()
- .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
- .setPort(new PortNumber(17830))
- .setConnectionStatus(ConnectionStatus.Connected)
- .setAvailableCapabilities(new AvailableCapabilitiesBuilder().setAvailableCapability(new ArrayList<AvailableCapability>()).build())
- .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList<UnavailableCapability>()).build())
- .setClusteredConnectionStatus(
- new ClusteredConnectionStatusBuilder()
- .setNodeStatus(
- Lists.newArrayList(
- new NodeStatusBuilder()
- .setNode("10.10.10.10")
- .setStatus(Status.Connected)
- .build()))
- .build())
- .build())
- .build();
-
- }
-
- @Test
- public void testInit() throws Exception {
- writer.init(NODE_ID, operationalNode);
- // once in constructor + once in init
- verify(txChain, times(2)).newWriteOnlyTransaction();
- verify(wtx, times(2)).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(NETWORK_TOPOLOGY_IID), eq(new NetworkTopologyBuilder().build()));
- verify(wtx, times(2)).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(TOPOLOGY_LIST_IID), eq(new TopologyBuilder().setTopologyId(new TopologyId(TOPOLOGY_ID)).build()));
- // actual write
- verify(wtx, times(1)).put(eq(LogicalDatastoreType.OPERATIONAL), eq(OPERATIONAL_NODE_IID), eq(operationalNode));
-
- // once in constructor + once in init()
- verify(wtx, times(2)).submit();
- }
-
- @Test
- public void testUpdate() throws Exception {
- writer.update(NODE_ID, operationalNode);
-
- verify(txChain, times(2)).newWriteOnlyTransaction();
- verify(wtx, times(1)).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(NETWORK_TOPOLOGY_IID), eq(new NetworkTopologyBuilder().build()));
- verify(wtx, times(1)).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(TOPOLOGY_LIST_IID), eq(new TopologyBuilder().setTopologyId(new TopologyId(TOPOLOGY_ID)).build()));
- // actual write
- verify(wtx, times(1)).put(eq(LogicalDatastoreType.OPERATIONAL), eq(OPERATIONAL_NODE_IID), eq(operationalNode));
- verify(wtx, times(2)).submit();
-
- }
-
- @Test
- public void testDelete() throws Exception {
- writer.delete(NODE_ID);
- verify(txChain, times(2)).newWriteOnlyTransaction();
- verify(wtx, times(1)).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(NETWORK_TOPOLOGY_IID), eq(new NetworkTopologyBuilder().build()));
- verify(wtx, times(1)).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(TOPOLOGY_LIST_IID), eq(new TopologyBuilder().setTopologyId(new TopologyId(TOPOLOGY_ID)).build()));
- verify(wtx, times(1)).delete(eq(LogicalDatastoreType.OPERATIONAL), eq(OPERATIONAL_NODE_IID));
- verify(wtx, times(2)).submit();
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2016 Cisco Systems, Inc. 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.pipeline;
-
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import java.net.InetSocketAddress;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.netconf.api.NetconfTerminationReason;
-import org.opendaylight.netconf.client.NetconfClientSession;
-import org.opendaylight.netconf.client.NetconfClientSessionListener;
-import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-
-public class ClusteredNetconfDeviceCommunicatorTest {
-
- private static final RemoteDeviceId REMOTE_DEVICE_ID = new RemoteDeviceId("testing-device", new InetSocketAddress(9999));
-
- @Mock
- private ClusteredNetconfDevice remoteDevice;
-
- @Mock
- private EntityOwnershipService ownershipService;
-
- @Mock
- private NetconfClientSession session;
-
- @Mock
- private NetconfClientSessionListener listener1;
-
- @Mock
- private NetconfClientSessionListener listener2;
-
- @Mock
- private EntityOwnershipListenerRegistration ownershipListenerRegistration;
-
- private ClusteredNetconfDeviceCommunicator communicator;
-
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- doReturn(ownershipListenerRegistration).when(ownershipService).registerListener(
- "netconf-node/" + REMOTE_DEVICE_ID.getName(), remoteDevice);
-
- communicator = new ClusteredNetconfDeviceCommunicator(REMOTE_DEVICE_ID, remoteDevice, ownershipService, 10);
- communicator.registerNetconfClientSessionListener(listener1);
- communicator.registerNetconfClientSessionListener(listener2);
- }
-
- @Test
- public void testOnSessionDown() {
- communicator.onSessionUp(session);
-
- Exception exception = mock(Exception.class);
- communicator.onSessionDown(session, exception);
-
- verify(ownershipListenerRegistration).close();
-
- verify(listener1).onSessionDown(eq(session), eq(exception));
- verify(listener2).onSessionDown(eq(session), eq(exception));
- }
-
- @Test
- public void testOnSessionUp() {
- communicator.onSessionUp(session);
-
- verify(ownershipService).registerListener("netconf-node/" + REMOTE_DEVICE_ID.getName(), remoteDevice);
-
- verify(listener1).onSessionUp(eq(session));
- verify(listener2).onSessionUp(eq(session));
- }
-
- @Test
- public void testOnSessionTerminated() {
- communicator.onSessionUp(session);
-
- NetconfTerminationReason reason = mock(NetconfTerminationReason.class);
- communicator.onSessionTerminated(session, reason);
-
- verify(ownershipListenerRegistration).close();
-
- verify(listener1).onSessionTerminated(eq(session), eq(reason));
- verify(listener2).onSessionTerminated(eq(session), eq(reason));
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2016 Cisco Systems, Inc. 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.pipeline;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-import akka.actor.ActorSystem;
-import java.net.InetSocketAddress;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
-import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-
-public class NetconfDeviceSlaveDataBrokerTest {
-
- private static final RemoteDeviceId REMOTE_DEVICE_ID = new RemoteDeviceId("testing-device", new InetSocketAddress(9999));
-
- @Mock
- private ProxyNetconfDeviceDataBroker mockedDataBroker;
-
- @Mock
- private ActorSystem mockedActorSystem;
-
- private NetconfDeviceSlaveDataBroker slaveDataBroker;
-
- @Before
- public void setUp() {
- slaveDataBroker = new NetconfDeviceSlaveDataBroker(mockedActorSystem, REMOTE_DEVICE_ID, mockedDataBroker);
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void testRegisterDataChangeListener() {
- slaveDataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.EMPTY,
- mock(DOMDataChangeListener.class), AsyncDataBroker.DataChangeScope.SUBTREE);
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void testCreateTransactionChain() {
- slaveDataBroker.createTransactionChain(mock(TransactionChainListener.class));
- }
-
- @Test
- public void testGetSupportedExtensions() {
- assertTrue(slaveDataBroker.getSupportedExtensions().isEmpty());
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2016 Cisco Systems, Inc. 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.pipeline;
-
-import java.net.InetSocketAddress;
-import java.util.Collections;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.controller.sal.core.api.Broker;
-import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
-import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-
-public class TopologyMountPointFacadeTest {
-
- private static final RemoteDeviceId REMOTE_DEVICE_ID = new RemoteDeviceId("testing-device", new InetSocketAddress(9999));
- private static final String TOPOLOGY_ID = "testing-topology";
-
- @Mock
- Broker domBroker;
-
- @Mock
- BindingAwareBroker bindingBroker;
-
- @Mock
- RemoteDeviceHandler<NetconfSessionPreferences> connectionStatusListener1;
-
- @Mock
- RemoteDeviceHandler<NetconfSessionPreferences> connectionStatusListener2;
-
-
- private TopologyMountPointFacade mountPointFacade;
-
- @Before
- public void setUp() {
-
- MockitoAnnotations.initMocks(this);
-
- mountPointFacade = new TopologyMountPointFacade(TOPOLOGY_ID, REMOTE_DEVICE_ID, domBroker, bindingBroker);
-
- mountPointFacade.registerConnectionStatusListener(connectionStatusListener1);
- mountPointFacade.registerConnectionStatusListener(connectionStatusListener2);
-
- }
-
- @Test
- public void testOnDeviceConnected() {
- SchemaContext mockedContext = Mockito.mock(SchemaContext.class);
- NetconfSessionPreferences mockedPreferences = NetconfSessionPreferences.fromStrings(Collections.<String>emptyList());
- DOMRpcService mockedRpcService = Mockito.mock(DOMRpcService.class);
- mountPointFacade.onDeviceConnected(mockedContext, mockedPreferences, mockedRpcService);
-
- Mockito.verify(connectionStatusListener1).onDeviceConnected(mockedContext, mockedPreferences, mockedRpcService);
- Mockito.verify(connectionStatusListener2).onDeviceConnected(mockedContext, mockedPreferences, mockedRpcService);
- }
-
- @Test
- public void testOnDeviceDisconnected() {
- mountPointFacade.onDeviceDisconnected();
-
- Mockito.verify(connectionStatusListener1).onDeviceDisconnected();
- Mockito.verify(connectionStatusListener2).onDeviceDisconnected();
- }
-
- @Test
- public void testOnDeviceFailed() {
- Throwable mockedException = Mockito.mock(Throwable.class);
- mountPointFacade.onDeviceFailed(mockedException);
-
- Mockito.verify(connectionStatusListener1).onDeviceFailed(mockedException);
- Mockito.verify(connectionStatusListener2).onDeviceFailed(mockedException);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2016 Cisco Systems, Inc. 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.pipeline.tx;
-
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import akka.actor.ActorSystem;
-import akka.dispatch.ExecutionContexts;
-import akka.dispatch.Futures;
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-import java.net.InetSocketAddress;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
-import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.netconf.topology.pipeline.ProxyNetconfDeviceDataBroker;
-import org.opendaylight.netconf.topology.util.messages.NormalizedNodeMessage;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-
-public class ProxyReadOnlyTransactionTest {
- private static final RemoteDeviceId REMOTE_DEVICE_ID = new RemoteDeviceId("testing-device", new InetSocketAddress(9999));
- private static final YangInstanceIdentifier path = YangInstanceIdentifier.create();
-
- @Mock
- private ProxyNetconfDeviceDataBroker mockedProxyDataBroker;
-
- @Mock
- private ActorSystem mockedActorSystem;
-
- @Mock
- private NormalizedNodeMessage mockedNodeMessage;
-
- @Mock
- private NormalizedNode mockedNode;
-
- private ProxyReadOnlyTransaction proxyReadOnlyTx;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- when(mockedActorSystem.dispatcher()).thenReturn(ExecutionContexts.fromExecutorService(MoreExecutors.newDirectExecutorService()));
- when(mockedNodeMessage.getNode()).thenReturn(mockedNode);
-
- proxyReadOnlyTx = new ProxyReadOnlyTransaction(mockedActorSystem, REMOTE_DEVICE_ID, mockedProxyDataBroker);
- }
-
- @Test
- public void testSuccessfulRead() throws ReadFailedException {
- when(mockedProxyDataBroker.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class)))
- .thenReturn(Futures.successful(Optional.of(mockedNodeMessage)));
- CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readResultFuture = proxyReadOnlyTx.read(LogicalDatastoreType.CONFIGURATION, path);
- verify(mockedProxyDataBroker).read(eq(LogicalDatastoreType.CONFIGURATION), eq(path));
- assertTrue(readResultFuture.isDone());
- assertEquals(readResultFuture.checkedGet().get(), mockedNode);
- }
-
- @Test
- public void testFailedRead() {
- when(mockedProxyDataBroker.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class)))
- .thenReturn(Futures.<Optional<NormalizedNodeMessage>>failed(new ReadFailedException("Test read failed!")));
- CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readResultFuture = proxyReadOnlyTx.read(LogicalDatastoreType.CONFIGURATION, path);
- verify(mockedProxyDataBroker).read(eq(LogicalDatastoreType.CONFIGURATION), eq(path));
- assertTrue(readResultFuture.isDone());
- try {
- readResultFuture.checkedGet();
- fail("Exception expected");
- } catch(Exception e) {
- assertTrue(e instanceof ReadFailedException);
- }
- }
-
- @Test
- public void testDataOnPathDoesNotExistPathRead() throws ReadFailedException {
- when(mockedProxyDataBroker.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class)))
- .thenReturn(Futures.successful(Optional.absent()));
- CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readResultFuture = proxyReadOnlyTx.read(LogicalDatastoreType.CONFIGURATION, path);
- verify(mockedProxyDataBroker).read(eq(LogicalDatastoreType.CONFIGURATION), eq(path));
- assertTrue(readResultFuture.isDone());
- assertTrue(!readResultFuture.checkedGet().isPresent());
- }
-
- @Test
- public void testFailedExists() {
- when(mockedProxyDataBroker.exists(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class)))
- .thenReturn(Futures.<Boolean>failed(new ReadFailedException("Test read failed!")));
- CheckedFuture existsFuture = proxyReadOnlyTx.exists(LogicalDatastoreType.OPERATIONAL, path);
- verify(mockedProxyDataBroker).exists(eq(LogicalDatastoreType.OPERATIONAL), eq(path));
- assertTrue(existsFuture.isDone());
- try {
- existsFuture.checkedGet();
- fail("Exception expected");
- } catch(Exception e) {
- assertTrue(e instanceof ReadFailedException);
- }
- }
-
- @Test
- public void testExists() throws Exception {
- when(mockedProxyDataBroker.exists(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class)))
- .thenReturn(Futures.successful(true));
- CheckedFuture<Boolean, ReadFailedException> existsFuture = proxyReadOnlyTx.exists(LogicalDatastoreType.OPERATIONAL, path);
- verify(mockedProxyDataBroker).exists(eq(LogicalDatastoreType.OPERATIONAL), eq(path));
- assertTrue(existsFuture.isDone());
- assertTrue(existsFuture.checkedGet());
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2016 Cisco Systems, Inc. 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.pipeline.tx;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import akka.actor.ActorSystem;
-import akka.dispatch.ExecutionContexts;
-import akka.dispatch.Futures;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-import java.util.concurrent.ExecutionException;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.netconf.topology.pipeline.ProxyNetconfDeviceDataBroker;
-import org.opendaylight.netconf.topology.util.messages.NormalizedNodeMessage;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-
-public class ProxyWriteOnlyTransactionTest {
- private static final YangInstanceIdentifier path = YangInstanceIdentifier.create();
- private ArgumentCaptor<NormalizedNodeMessage> nodeMessageArgumentCaptor;
-
- @Mock
- private ProxyNetconfDeviceDataBroker mockedDelegate;
-
- @Mock
- private ActorSystem mockedActorSystem;
-
- @Mock
- private NormalizedNode<?, ?> normalizedNode;
-
- private ProxyWriteOnlyTransaction tx;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- when(mockedActorSystem.dispatcher()).thenReturn(ExecutionContexts.fromExecutorService(MoreExecutors.newDirectExecutorService()));
-
- nodeMessageArgumentCaptor = ArgumentCaptor.forClass(NormalizedNodeMessage.class);
- tx = new ProxyWriteOnlyTransaction(mockedActorSystem, mockedDelegate);
- }
-
- @Test
- public void testPut() {
- doNothing().when(mockedDelegate).put(any(LogicalDatastoreType.class), any(NormalizedNodeMessage.class));
- tx.put(LogicalDatastoreType.OPERATIONAL, path, normalizedNode);
- verify(mockedDelegate).put(eq(LogicalDatastoreType.OPERATIONAL), nodeMessageArgumentCaptor.capture());
- assertEquals(path, nodeMessageArgumentCaptor.getValue().getIdentifier());
- assertEquals(normalizedNode, nodeMessageArgumentCaptor.getValue().getNode());
- }
-
- @Test
- public void testMerge() {
- doNothing().when(mockedDelegate).merge(any(LogicalDatastoreType.class), any(NormalizedNodeMessage.class));
- tx.merge(LogicalDatastoreType.CONFIGURATION, path, normalizedNode);
- verify(mockedDelegate).merge(eq(LogicalDatastoreType.CONFIGURATION), nodeMessageArgumentCaptor.capture());
- assertEquals(path, nodeMessageArgumentCaptor.getValue().getIdentifier());
- assertEquals(normalizedNode, nodeMessageArgumentCaptor.getValue().getNode());
- }
-
- @Test
- public void testCancel() {
- when(mockedDelegate.cancel()).thenReturn(true);
- assertTrue(tx.cancel());
- verify(mockedDelegate).cancel();
- }
-
- @Test
- public void testDelete() {
- doNothing().when(mockedDelegate).delete(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class));
- tx.delete(LogicalDatastoreType.OPERATIONAL, path);
- verify(mockedDelegate).delete(eq(LogicalDatastoreType.OPERATIONAL), eq(path));
- }
-
- @Test
- public void testSuccessfulSubmit() throws Exception {
- when(mockedDelegate.submit()).thenReturn(Futures.<Void>successful(null));
- CheckedFuture submitFuture = tx.submit();
- verify(mockedDelegate).submit();
- assertTrue(submitFuture.isDone());
- assertEquals(submitFuture.checkedGet(), null);
- }
-
- @Test
- public void testFailedSubmit() {
- when(mockedDelegate.submit()).thenReturn(Futures.<Void>failed(new TransactionCommitFailedException("fail")));
- CheckedFuture submitFuture = tx.submit();
- verify(mockedDelegate).submit();
- assertTrue(submitFuture.isDone());
- try {
- submitFuture.checkedGet();
- fail("Exception expected");
- } catch(Exception e) {
- assertTrue(e instanceof TransactionCommitFailedException);
- }
- }
-
- @Test
- public void testSuccessfulCommit() throws ExecutionException, InterruptedException {
- RpcResult<TransactionStatus> rpcResult = mock(RpcResult.class);
- when(mockedDelegate.commit()).thenReturn(Futures.successful(rpcResult));
- ListenableFuture<RpcResult<TransactionStatus>> submitFuture = tx.commit();
- verify(mockedDelegate).commit();
- assertTrue(submitFuture.isDone());
- assertEquals(submitFuture.get(), rpcResult);
- }
-
- @Test
- public void testFailedCommit() {
- when(mockedDelegate.commit()).thenReturn(Futures.<RpcResult<TransactionStatus>>failed(new TransactionCommitFailedException("faile")));
- ListenableFuture<RpcResult<TransactionStatus>> submitFuture = tx.commit();
- verify(mockedDelegate).commit();
- assertTrue(submitFuture.isDone());
- try {
- submitFuture.get();
- fail("Exception expected");
- } catch(Exception e) {
- assertTrue(e.getCause() instanceof TransactionCommitFailedException);
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-include "test.conf"
-
-akka {
- # LISTEN on tcp port 2552
- remote.netty.tcp.port = 2552
-
- cluster {
- seed-nodes = [
- "akka.tcp://NetconfNode@127.0.0.1:2553",
- "akka.tcp://NetconfNode@127.0.0.1:2554"]
-
- auto-down-unreachable-after = 10s
- }
-}
+++ /dev/null
-include "test.conf"
-
-akka {
- # LISTEN on tcp port 2553
- remote.netty.tcp.port = 2553
-
- cluster {
- seed-nodes = [
- "akka.tcp://NetconfNode@127.0.0.1:2552",
- "akka.tcp://NetconfNode@127.0.0.1:2554"]
-
- auto-down-unreachable-after = 10s
- }
-}
+++ /dev/null
-include "test.conf"
-
-akka {
- # LISTEN on tcp port 2554
- remote.netty.tcp.port = 2554
-
- cluster {
- seed-nodes = [
- "akka.tcp://NetconfNode@127.0.0.1:2552",
- "akka.tcp://NetconfNode@127.0.0.1:2553"]
-
- auto-down-unreachable-after = 10s
- }
-}
+++ /dev/null
-akka {
-
- actor {
- provider = "akka.cluster.ClusterActorRefProvider"
-
- serializers {
- java = "akka.serialization.JavaSerializer"
- }
-
- serialization-bindings {
- "[B" = bytes
- "java.io.Serializable" = java
- }
- }
-
- remote {
- enabled-transports = ["akka.remote.netty.tcp"]
- netty.tcp {
- hostname = "127.0.0.1"
- }
- }
-}
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-data-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
</dependencies>
<build>
<plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Bundle-Activator>org.opendaylight.netconf.util.osgi.NetconfConfigurationActivator</Bundle-Activator>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${project.build.directory}/classes/netconf.cfg</file>
+ <type>cfg</type>
+ <classifier>config</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
import com.google.common.base.Optional;
import io.netty.channel.local.LocalAddress;
import java.net.InetSocketAddress;
+import java.util.Collection;
import java.util.concurrent.TimeUnit;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ManagedService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
}
return Optional.fromNullable(value);
}
+
+ public static java.util.Optional<NetconfConfiguration> getNetconfConfigurationService(BundleContext bundleContext) {
+ final Collection<ServiceReference<ManagedService>> serviceReferences;
+ try {
+ serviceReferences = bundleContext.getServiceReferences(ManagedService.class, null);
+ for (final ServiceReference<ManagedService> serviceReference : serviceReferences) {
+ ManagedService service = bundleContext.getService(serviceReference);
+ if (service instanceof NetconfConfiguration){
+ return java.util.Optional.of((NetconfConfiguration) service);
+ }
+ }
+ } catch (InvalidSyntaxException e) {
+ LOG.error("Unable to retrieve references for ManagedService: {}", e);
+ }
+ LOG.error("Unable to retrieve NetconfConfiguration service. Not found. Bundle netconf-util probably failed.");
+ return java.util.Optional.empty();
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.util.osgi;
+
+import java.net.InetSocketAddress;
+import java.util.Dictionary;
+import org.osgi.service.cm.ManagedService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfConfiguration implements ManagedService {
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfConfiguration.class);
+
+ private static final NetconfConfiguration instance = new NetconfConfiguration();
+ private NetconfConfigurationHolder netconfConfiguration;
+
+ public static final String KEY_SSH_ADDRESS = "ssh-address";
+ public static final String KEY_SSH_PORT = "ssh-port";
+ public static final String KEY_TCP_ADDRESS = "tcp-address";
+ public static final String KEY_TCP_PORT = "tcp-port";
+ public static final String KEY_SSH_PK_PATH = "ssh-pk-path";
+
+ public static NetconfConfiguration getInstance() {
+ return instance;
+ }
+
+ private NetconfConfiguration() {
+ netconfConfiguration = new NetconfConfigurationHolder(NetconfConfigUtil.DEFAULT_TCP_SERVER_ADRESS,
+ NetconfConfigUtil.DEFAULT_SSH_SERVER_ADRESS, NetconfConfigUtil.DEFAULT_PRIVATE_KEY_PATH);
+ }
+
+ @Override
+ public void updated(final Dictionary<String, ?> dictionaryConfig) {
+ if (dictionaryConfig == null) {
+ LOG.warn("Netconf configuration cannot be updated.");
+ return;
+ }
+ final InetSocketAddress sshServerAddress = new InetSocketAddress((String) dictionaryConfig.get(KEY_SSH_ADDRESS),
+ Integer.parseInt((String) dictionaryConfig.get(KEY_SSH_PORT)));
+ final InetSocketAddress tcpServerAddress = new InetSocketAddress((String) dictionaryConfig.get(KEY_TCP_ADDRESS),
+ Integer.parseInt((String) dictionaryConfig.get(KEY_TCP_PORT)));
+
+ netconfConfiguration = new NetconfConfigurationHolder(tcpServerAddress, sshServerAddress,
+ (String) dictionaryConfig.get(KEY_SSH_PK_PATH));
+
+ LOG.info("Netconf configuration was updated: {}", dictionaryConfig.toString());
+ }
+
+ public InetSocketAddress getSshServerAddress(){
+ return netconfConfiguration.getSshServerAddress();
+ }
+
+ public InetSocketAddress getTcpServerAddress(){
+ return netconfConfiguration.getTcpServerAddress();
+ }
+
+ public String getPrivateKeyPath() {
+ return netconfConfiguration.getPrivateKeyPath();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.util.osgi;
+
+import java.util.Hashtable;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ManagedService;
+
+public class NetconfConfigurationActivator implements BundleActivator {
+ private static final String CONFIG_PID = "netconf";
+ private ServiceRegistration configService;
+
+ @Override
+ public void start(BundleContext bundleContext) {
+ configService = bundleContext.registerService(ManagedService.class,
+ NetconfConfiguration.getInstance(), getNetconfConfigProperties());
+ }
+
+ @Override
+ public void stop(BundleContext bundleContext) {
+ if (configService != null) {
+ configService.unregister();
+ configService = null;
+ }
+ }
+
+ private Hashtable<String, String> getNetconfConfigProperties(){
+ Hashtable<String, String> properties = new Hashtable<>();
+ properties.put(Constants.SERVICE_PID, CONFIG_PID);
+ return properties;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.util.osgi;
+
+import java.net.InetSocketAddress;
+
+final class NetconfConfigurationHolder {
+
+ private final InetSocketAddress tcpServerAddress;
+ private final InetSocketAddress sshServerAddress;
+ private final String privateKeyPath;
+
+ NetconfConfigurationHolder(InetSocketAddress tcpServerAddress, InetSocketAddress sshServerAddress, String privateKeyPath){
+ this.tcpServerAddress = tcpServerAddress;
+ this.sshServerAddress = sshServerAddress;
+ this.privateKeyPath = privateKeyPath;
+ }
+
+ String getPrivateKeyPath() {
+ return privateKeyPath;
+ }
+
+ InetSocketAddress getSshServerAddress() {
+ return sshServerAddress;
+ }
+
+ InetSocketAddress getTcpServerAddress() {
+ return tcpServerAddress;
+ }
+
+}
--- /dev/null
+# netconf-tcp:
+
+tcp-address=127.0.0.1
+tcp-port=8383
+
+# netconf-ssh:
+
+ssh-address=0.0.0.0
+ssh-port=1830
+# Use Linux style path
+ssh-pk-path = ./configuration/RSA.pk
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. 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
+ -->
+
+<rpc message-id="m-0" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <copy-config>
+ <target>
+ <candidate/>
+ </target>
+ <source>
+ <running/>
+ </source>
+ </copy-config>
+</rpc>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. 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
+ -->
+
+<rpc message-id="m-0" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <edit-config>
+ <target>
+ <running/>
+ </target>
+ <default-operation>merge</default-operation>
+ <error-option>rollback-on-error</error-option>
+ <config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <c xmlns="test:namespace">
+ <a xmlns:a="urn:ietf:params:xml:ns:netconf:base:1.0" a:operation="replace">leaf-value</a>
+ </c>
+ </config>
+ </edit-config>
+</rpc>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. 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
+ -->
+
+<rpc message-id="m-0" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <edit-config>
+ <target>
+ <candidate/>
+ </target>
+ <error-option>rollback-on-error</error-option>
+ <config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <c xmlns="test:namespace">
+ <a xmlns:a="urn:ietf:params:xml:ns:netconf:base:1.0" a:operation="replace">leaf-value</a>
+ </c>
+ </config>
+ </edit-config>
+</rpc>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. 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
+ -->
+
+<rpc message-id="m-0" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <get-config>
+ <source>
+ <candidate/>
+ </source>
+ <filter xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:type="subtree">
+ <c xmlns="test:namespace"/>
+ </filter>
+ </get-config>
+</rpc>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. 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
+ -->
+
+<rpc message-id="101"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <lock>
+ <target>
+ <running/>
+ </target>
+ </lock>
+</rpc>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. 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
+ -->
+
+<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" a="64" message-id="a">
+ <data/>
+</rpc-reply>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. 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
+ -->
+
+<rpc message-id="101"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <unlock>
+ <target>
+ <running/>
+ </target>
+ </unlock>
+</rpc>
\ No newline at end of file
--- /dev/null
+<!--
+ ~ Copyright (c) 2016 Cisco Systems, Inc. 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
+ -->
+
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101">
+ <validate>
+ <source>
+ <running/>
+ </source>
+ </validate>
+</rpc>
<module>netconf-notifications-impl</module>
<module>netconf-notifications-api</module>
<module>netconf-topology</module>
- <module>abstract-topology</module>
+ <module>netconf-topology-singleton</module>
<module>netconf-topology-config</module>
<module>sal-netconf-connector</module>
<module>messagebus-netconf</module>
return new NetconfDeviceRpc(baseSchema.getSchemaContext(), listener, new NetconfMessageTransformer(baseSchema.getSchemaContext(), false, baseSchema));
}
- protected NetconfDevice(final SchemaResourcesDTO schemaResourcesDTO, final RemoteDeviceId id, final RemoteDeviceHandler<NetconfSessionPreferences> salFacade,
+ public NetconfDevice(final SchemaResourcesDTO schemaResourcesDTO, final RemoteDeviceId id, final RemoteDeviceHandler<NetconfSessionPreferences> salFacade,
final ExecutorService globalProcessingExecutor, final boolean reconnectOnSchemasChange) {
this.id = id;
this.reconnectOnSchemasChange = reconnectOnSchemasChange;
return remoteSessionCapabilities.isNotificationsSupported() && reconnectOnSchemasChange;
}
- protected void handleSalInitializationSuccess(final SchemaContext result, final NetconfSessionPreferences remoteSessionCapabilities, final DOMRpcService deviceRpc) {
+ void handleSalInitializationSuccess(final SchemaContext result, final NetconfSessionPreferences remoteSessionCapabilities, final DOMRpcService deviceRpc) {
final BaseSchema baseSchema =
remoteSessionCapabilities.isNotificationsSupported() ?
BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS :
LOG.info("{}: Netconf connector initialized successfully", id);
}
- protected void handleSalInitializationFailure(final Throwable t, final RemoteDeviceCommunicator<NetconfMessage> listener) {
+ void handleSalInitializationFailure(final Throwable t, final RemoteDeviceCommunicator<NetconfMessage> listener) {
LOG.error("{}: Initialization in sal failed, disconnecting from device", id, t);
listener.close();
onRemoteSessionDown();
import java.util.Set;
import java.util.concurrent.ExecutionException;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemas;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc;
import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseSchema;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
/**
* Issue get request to remote device and parse response to find all schemas under netconf-state/schemas
*/
- static NetconfStateSchemas create(final NetconfDeviceRpc deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
+ static NetconfStateSchemas create(final DOMRpcService deviceRpc, final NetconfSessionPreferences remoteSessionCapabilities, final RemoteDeviceId id) {
if(remoteSessionCapabilities.isMonitoringSupported() == false) {
// TODO - need to search for get-schema support, not just ietf-netconf-monitoring support
// issue might be a deviation to ietf-netconf-monitoring where get-schema is unsupported...
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
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.NetconfNodeConnectionStatus.ConnectionStatus;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.AvailableCapabilitiesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.ClusteredConnectionStatusBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.UnavailableCapabilities;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.UnavailableCapabilitiesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-final class NetconfDeviceTopologyAdapter implements AutoCloseable {
+public final class NetconfDeviceTopologyAdapter implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceTopologyAdapter.class);
public static final Function<Entry<QName, FailureReason>, UnavailableCapability> UNAVAILABLE_CAPABILITY_TRANSFORMER = new Function<Entry<QName, FailureReason>, UnavailableCapability>() {
commitTransaction(writeTx, "update");
}
+ public void updateClusteredDeviceData(boolean up, String masterAddress, NetconfDeviceCapabilities capabilities) {
+ final NetconfNode data = buildDataForNetconfClusteredNode(up, masterAddress, capabilities);
+
+ final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
+ LOG.trace(
+ "{}: Update device state transaction {} merging operational data started.",
+ id, writeTx.getIdentifier());
+ writeTx.put(LogicalDatastoreType.OPERATIONAL, id.getTopologyBindingPath().augmentation(NetconfNode.class), data, true);
+ LOG.trace(
+ "{}: Update device state transaction {} merging operational data ended.",
+ id, writeTx.getIdentifier());
+
+ commitTransaction(writeTx, "update");
+ }
+
public void setDeviceAsFailed(Throwable throwable) {
String reason = (throwable != null && throwable.getMessage() != null) ? throwable.getMessage() : UNKNOWN_REASON;
return netconfNodeBuilder.build();
}
+ private NetconfNode buildDataForNetconfClusteredNode(boolean up, String masterNodeAddress, NetconfDeviceCapabilities capabilities) {
+ List<AvailableCapability> capabilityList = new ArrayList<>();
+ capabilityList.addAll(capabilities.getNonModuleBasedCapabilities());
+ capabilityList.addAll(capabilities.getResolvedCapabilities());
+ final AvailableCapabilitiesBuilder avCapabalitiesBuilder = new AvailableCapabilitiesBuilder();
+ avCapabalitiesBuilder.setAvailableCapability(capabilityList);
+
+ final UnavailableCapabilities unavailableCapabilities =
+ new UnavailableCapabilitiesBuilder().setUnavailableCapability(capabilities.getUnresolvedCapabilites()
+ .entrySet().stream().map(UNAVAILABLE_CAPABILITY_TRANSFORMER::apply)
+ .collect(Collectors.toList())).build();
+
+ final NetconfNodeBuilder netconfNodeBuilder = new NetconfNodeBuilder()
+ .setHost(id.getHost())
+ .setPort(new PortNumber(id.getAddress().getPort()))
+ .setConnectionStatus(up ? ConnectionStatus.Connected : ConnectionStatus.Connecting)
+ .setAvailableCapabilities(avCapabalitiesBuilder.build())
+ .setUnavailableCapabilities(unavailableCapabilities)
+ .setClusteredConnectionStatus(
+ new ClusteredConnectionStatusBuilder().setNetconfMasterNode(masterNodeAddress).build());
+
+ return netconfNodeBuilder.build();
+ }
+
public void removeDeviceConfiguration() {
final WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfRpcFutureCallback;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.opendaylight.yangtools.yang.data.api.ModifyAction;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
private static final Logger LOG = LoggerFactory.getLogger(WriteCandidateTx.class);
- private static final Function<DOMRpcResult, RpcResult<TransactionStatus>> RPC_RESULT_TO_TX_STATUS = new Function<DOMRpcResult, RpcResult<TransactionStatus>>() {
- @Override
- public RpcResult<TransactionStatus> apply(final DOMRpcResult input) {
- if (isSuccess(input)) {
- return RpcResultBuilder.success(TransactionStatus.COMMITED).build();
- } else {
- final RpcResultBuilder<TransactionStatus> failed = RpcResultBuilder.failed();
- for (final RpcError rpcError : input.getErrors()) {
- failed.withError(rpcError.getErrorType(), rpcError.getTag(), rpcError.getMessage(),
- rpcError.getApplicationTag(), rpcError.getInfo(), rpcError.getCause());
- }
- return failed.build();
- }
- }
- };
-
public WriteCandidateTx(final RemoteDeviceId id, final NetconfBaseOps rpc, final boolean rollbackSupport) {
super(rpc, id, rollbackSupport);
}
private void lock() {
final FutureCallback<DOMRpcResult> lockCandidateCallback = new FutureCallback<DOMRpcResult>() {
@Override
- public void onSuccess(DOMRpcResult result) {
+ public void onSuccess(final DOMRpcResult result) {
if (isSuccess(result)) {
if (LOG.isTraceEnabled()) {
LOG.trace("Lock candidate successful");
}
@Override
- public void onFailure(Throwable t) {
+ public void onFailure(final Throwable t) {
LOG.warn("Lock candidate operation failed. {}", t);
discardChanges();
}
@Override
public synchronized ListenableFuture<RpcResult<TransactionStatus>> performCommit() {
resultsFutures.add(netOps.commit(new NetconfRpcFutureCallback("Commit", id)));
- ListenableFuture<RpcResult<TransactionStatus>> txResult = resultsToTxStatus();
+ final ListenableFuture<RpcResult<TransactionStatus>> txResult = resultsToTxStatus();
Futures.addCallback(txResult, new FutureCallback<RpcResult<TransactionStatus>>() {
@Override
- public void onSuccess(@Nullable RpcResult<TransactionStatus> result) {
+ public void onSuccess(@Nullable final RpcResult<TransactionStatus> result) {
cleanupOnSuccess();
}
@Override
- public void onFailure(Throwable t) {
+ public void onFailure(final Throwable t) {
// TODO If lock is cause of this failure cleanup will issue warning log
// cleanup is trying to do unlock, but this will fail
cleanup();
final Optional<ModifyAction> defaultOperation,
final String operation) {
- NetconfRpcFutureCallback editConfigCallback = new NetconfRpcFutureCallback("Edit candidate", id);
+ final NetconfRpcFutureCallback editConfigCallback = new NetconfRpcFutureCallback("Edit candidate", id);
if (defaultOperation.isPresent()) {
resultsFutures.add(netOps.editConfigCandidate(
}
}
}
+ leaf netconf-master-node {
+ config false;
+ type string;
+ }
}
leaf connected-message {
import static org.hamcrest.CoreMatchers.hasItem;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_QNAME;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toPath;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseSchema;
+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.monitoring.rev101004.NetconfState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
public class NetconfStateSchemasTest {
- @Test
- public void testCreate() throws Exception {
+ private static final NetconfSessionPreferences CAPS = NetconfSessionPreferences.fromStrings(Collections.singleton("urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04"));
+ private final RemoteDeviceId deviceId = new RemoteDeviceId("device", new InetSocketAddress(99));
+ private ContainerNode compositeNodeSchemas;
+ @Mock
+ private DOMRpcService rpc;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
final SchemaContext schemaContext = BaseSchema.BASE_NETCONF_CTX_WITH_NOTIFICATIONS.getSchemaContext();
final DataSchemaNode schemasNode =
((ContainerSchemaNode) schemaContext
.getDataChildByName(NetconfState.QNAME)).getDataChildByName(Schemas.QNAME);
-
final Document schemasXml = XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/netconf-state.schemas.payload.xml"));
final ToNormalizedNodeParser<Element, ContainerNode, ContainerSchemaNode> containerNodeParser = DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, schemaContext, false).getContainerNodeParser();
- final ContainerNode compositeNodeSchemas = containerNodeParser.parse(Collections.singleton(schemasXml.getDocumentElement()), (ContainerSchemaNode) schemasNode);
- final NetconfStateSchemas schemas = NetconfStateSchemas.create(new RemoteDeviceId("device", new InetSocketAddress(99)), compositeNodeSchemas);
+ compositeNodeSchemas = containerNodeParser.parse(Collections.singleton(schemasXml.getDocumentElement()), (ContainerSchemaNode) schemasNode);
+
+ }
+
+ @Test
+ public void testCreate() throws Exception {
+ final NetconfStateSchemas schemas = NetconfStateSchemas.create(deviceId, compositeNodeSchemas);
final Set<QName> availableYangSchemasQNames = schemas.getAvailableYangSchemasQNames();
assertEquals(73, availableYangSchemasQNames.size());
assertThat(availableYangSchemasQNames,
hasItem(QName.create("urn:TBD:params:xml:ns:yang:network-topology", "2013-07-12", "network-topology")));
}
+
+ @Test
+ public void testCreate2() throws Exception {
+ final ContainerNode netconfState = Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NetconfState.QNAME))
+ .withChild(compositeNodeSchemas)
+ .build();
+ final ContainerNode data = Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NetconfMessageTransformUtil.NETCONF_DATA_QNAME))
+ .withChild(netconfState)
+ .build();
+ final ContainerNode rpcReply = Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NetconfMessageTransformUtil.NETCONF_RPC_REPLY_QNAME))
+ .withChild(data)
+ .build();
+ when(rpc.invokeRpc(eq(toPath(NETCONF_GET_QNAME)), any())).thenReturn(Futures.immediateCheckedFuture(new DefaultDOMRpcResult(rpcReply)));
+ final NetconfStateSchemas stateSchemas = NetconfStateSchemas.create(rpc, CAPS, deviceId);
+ final Set<QName> availableYangSchemasQNames = stateSchemas.getAvailableYangSchemasQNames();
+ assertEquals(73, availableYangSchemasQNames.size());
+
+ assertThat(availableYangSchemasQNames,
+ hasItem(QName.create("urn:TBD:params:xml:ns:yang:network-topology", "2013-07-12", "network-topology")));
+ }
+
+ @Test
+ public void testCreateMonitoringNotSupported() throws Exception {
+ final NetconfSessionPreferences caps = NetconfSessionPreferences.fromStrings(Collections.emptySet());
+ final NetconfStateSchemas stateSchemas = NetconfStateSchemas.create(rpc, caps, deviceId);
+ final Set<QName> availableYangSchemasQNames = stateSchemas.getAvailableYangSchemasQNames();
+ Assert.assertTrue(availableYangSchemasQNames.isEmpty());
+ }
+
+ @Test
+ public void testCreateFail() throws Exception {
+ final CheckedFuture<DOMRpcResult, DOMRpcException> resultFuture =
+ Futures.immediateFailedCheckedFuture(new DOMRpcImplementationNotAvailableException("not available"));
+ when(rpc.invokeRpc(eq(toPath(NETCONF_GET_QNAME)), any())).thenReturn(resultFuture);
+ final NetconfStateSchemas stateSchemas = NetconfStateSchemas.create(rpc, CAPS, deviceId);
+ final Set<QName> availableYangSchemasQNames = stateSchemas.getAvailableYangSchemasQNames();
+ Assert.assertTrue(availableYangSchemasQNames.isEmpty());
+ }
+
+ @Test
+ public void testCreateRpcError() throws Exception {
+ final RpcError rpcError = RpcResultBuilder.newError(RpcError.ErrorType.RPC, "fail", "fail");
+ when(rpc.invokeRpc(eq(toPath(NETCONF_GET_QNAME)), any())).thenReturn(Futures.immediateCheckedFuture(new DefaultDOMRpcResult(rpcError)));
+ final NetconfStateSchemas stateSchemas = NetconfStateSchemas.create(rpc, CAPS, deviceId);
+ final Set<QName> availableYangSchemasQNames = stateSchemas.getAvailableYangSchemasQNames();
+ Assert.assertTrue(availableYangSchemasQNames.isEmpty());
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testCreateInterrupted() throws Throwable {
+ //NetconfStateSchemas.create calls Thread.currentThread().interrupt(), so it must run in its own thread
+ final Future<?> testFuture = Executors.newSingleThreadExecutor().submit(() -> {
+ final ListenableFuture interruptedFuture = mock(ListenableFuture.class);
+ try {
+ when(interruptedFuture.get()).thenThrow(new InterruptedException("interrupted"));
+ final CheckedFuture checkedFuture = Futures.makeChecked(interruptedFuture, ReadFailedException.MAPPER);
+ when(rpc.invokeRpc(eq(toPath(NETCONF_GET_QNAME)), any())).thenReturn(checkedFuture);
+ NetconfStateSchemas.create(rpc, CAPS, deviceId);
+ } catch (final InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+ }
+
+ });
+ try {
+ testFuture.get(3, TimeUnit.SECONDS);
+ } catch (final ExecutionException e) {
+ throw e.getCause();
+ }
+ }
+
+ @Test
+ public void testRemoteYangSchemaEquals() throws Exception {
+ final NetconfStateSchemas.RemoteYangSchema schema1 = new NetconfStateSchemas.RemoteYangSchema(NetconfState.QNAME);
+ final NetconfStateSchemas.RemoteYangSchema schema2 = new NetconfStateSchemas.RemoteYangSchema(NetconfState.QNAME);
+ final NetconfStateSchemas.RemoteYangSchema schema3 = new NetconfStateSchemas.RemoteYangSchema(Schemas.QNAME);
+ Assert.assertEquals(schema1, schema2);
+ Assert.assertEquals(schema2, schema1);
+ Assert.assertNotEquals(schema1, schema3);
+ Assert.assertNotEquals(schema2, schema3);
+
+ }
}
import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
private DOMMountPointService.DOMMountPointBuilder mountPointBuilder;
@Mock
private ObjectRegistration<DOMMountPoint> registration;
+ @Mock
+ private DOMNotification notification;
private NetconfDeviceSalProvider.MountInstance mountInstance;
verify(registration).close();
try {
mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, broker, rpcService, notificationService);
- } catch (IllegalStateException e) {
+ } catch (final IllegalStateException e) {
e.printStackTrace();
Assert.fail("Topology registration still present after disconnect ");
}
verify(registration).close();
}
+ @Test
+ public void testPublishNotification() throws Exception {
+ mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, broker, rpcService, notificationService);
+ verify(mountPointBuilder).addInitialSchemaContext(SCHEMA_CONTEXT);
+ verify(mountPointBuilder).addService(DOMNotificationService.class, notificationService);
+ mountInstance.publish(notification);
+ verify(notificationService).publishNotification(notification);
+ }
+
+
}
\ No newline at end of file
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.net.URI;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
private DOMNotification notification2;
private NetconfDeviceNotificationService service;
+ private ListenerRegistration<DOMNotificationListener> registration;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- SchemaPath path1 = SchemaPath.create(true, new QName(new URI("namespace1"), "path1"));
- SchemaPath path2 = SchemaPath.create(true, new QName(new URI("namespace2"), "path2"));
+ final SchemaPath path1 = SchemaPath.create(true, new QName(new URI("namespace1"), "path1"));
+ final SchemaPath path2 = SchemaPath.create(true, new QName(new URI("namespace2"), "path2"));
service = new NetconfDeviceNotificationService();
service.registerNotificationListener(listener1, path1);
- service.registerNotificationListener(listener2, path2);
+ registration = service.registerNotificationListener(listener2, path2);
doReturn(path1).when(notification1).getType();
doReturn(path2).when(notification2).getType();
verify(listener1, never()).onNotification(notification2);
}
+ @Test
+ public void testCloseRegistration() throws Exception {
+ service.publishNotification(notification2);
+ Assert.assertEquals(listener2, registration.getInstance());
+ registration.close();
+ service.publishNotification(notification2);
+ verify(listener2, times(1)).onNotification(notification2);
+ }
}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.sal.connect.netconf.sal;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.google.common.util.concurrent.Futures;
+import java.net.InetSocketAddress;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+
+public class NetconfDeviceSalProviderTest {
+
+ @Mock
+ private Broker.ProviderSession session;
+ @Mock
+ private DOMMountPointService mountpointService;
+ @Mock
+ private BindingAwareBroker.ProviderContext context;
+ @Mock
+ private WriteTransaction tx;
+ @Mock
+ private DataBroker dataBroker;
+ @Mock
+ private BindingTransactionChain chain;
+ private NetconfDeviceSalProvider provider;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ provider = new NetconfDeviceSalProvider(new RemoteDeviceId("device1", InetSocketAddress.createUnresolved("localhost", 17830)));
+ when(session.getService(DOMMountPointService.class)).thenReturn(mountpointService);
+ when(context.getSALService(DataBroker.class)).thenReturn(dataBroker);
+ when(dataBroker.createTransactionChain(any())).thenReturn(chain);
+ when(chain.newWriteOnlyTransaction()).thenReturn(tx);
+ when(tx.submit()).thenReturn(Futures.immediateCheckedFuture(null));
+ when(tx.getIdentifier()).thenReturn(tx);
+ }
+
+ @Test
+ public void onSessionInitiated() throws Exception {
+ provider.onSessionInitiated(session);
+ provider.onSessionInitiated(context);
+ Assert.assertNotNull(provider.getMountInstance());
+ Assert.assertNotNull(provider.getTopologyDatastoreAdapter());
+ }
+
+ @Test
+ public void getProviderFunctionality() throws Exception {
+ Assert.assertTrue(provider.getProviderFunctionality().isEmpty());
+ }
+
+ @Test
+ public void replaceChainIfFailed() throws Exception {
+ provider.onSessionInitiated(session);
+ provider.onSessionInitiated(context);
+ Assert.assertNotNull(provider.getMountInstance());
+ final ArgumentCaptor<TransactionChainListener> captor = ArgumentCaptor.forClass(TransactionChainListener.class);
+ verify(dataBroker).createTransactionChain(captor.capture());
+ try {
+ captor.getValue().onTransactionChainFailed(chain, tx, new Exception("chain failed"));
+ } catch (final IllegalStateException e) {
+ //expected
+ }
+ verify(dataBroker, times(2)).createTransactionChain(any());
+ }
+
+ @Test
+ public void close() throws Exception {
+ provider.onSessionInitiated(session);
+ provider.onSessionInitiated(context);
+ provider.close();
+ verify(chain).close();
+ }
+
+}
\ No newline at end of file
import static org.mockito.Mockito.verify;
import com.google.common.util.concurrent.Futures;
-
import java.net.InetSocketAddress;
-
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
readOnlyTx.read(LogicalDatastoreType.OPERATIONAL, path);
verify(rpc).invokeRpc(Mockito.eq(NetconfMessageTransformUtil.toPath(NetconfMessageTransformUtil.NETCONF_GET_QNAME)), any(NormalizedNode.class));
}
+
+ @Test
+ public void testExists() throws Exception {
+ final NetconfBaseOps netconfOps = new NetconfBaseOps(rpc, mock(SchemaContext.class));
+
+ final ReadOnlyTx readOnlyTx = new ReadOnlyTx(netconfOps, new RemoteDeviceId("a", new InetSocketAddress("localhost", 196)));
+
+ readOnlyTx.exists(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create());
+ verify(rpc).invokeRpc(Mockito.eq(NetconfMessageTransformUtil.toPath(NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME)), any(NormalizedNode.class));
+ readOnlyTx.exists(LogicalDatastoreType.OPERATIONAL, path);
+ verify(rpc).invokeRpc(Mockito.eq(NetconfMessageTransformUtil.toPath(NetconfMessageTransformUtil.NETCONF_GET_QNAME)), any(NormalizedNode.class));
+ }
+
+ @Test
+ public void testIdentifier() throws Exception {
+ final NetconfBaseOps netconfOps = new NetconfBaseOps(rpc, mock(SchemaContext.class));
+ final ReadOnlyTx tx1 = new ReadOnlyTx(netconfOps, new RemoteDeviceId("a", new InetSocketAddress("localhost", 196)));
+ final ReadOnlyTx tx2 = new ReadOnlyTx(netconfOps, new RemoteDeviceId("a", new InetSocketAddress("localhost", 196)));
+ Assert.assertNotEquals(tx1.getIdentifier(), tx2.getIdentifier());
+ }
}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.sal.connect.netconf.sal.tx;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class ReadWriteTxTest {
+ @Mock
+ private DOMDataReadTransaction delegateReadTx;
+ @Mock
+ private DOMDataWriteTransaction delegateWriteTx;
+ private ReadWriteTx tx;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ tx = new ReadWriteTx(delegateReadTx, delegateWriteTx);
+ }
+
+ @Test
+ public void submit() throws Exception {
+ final YangInstanceIdentifier id1 = TxTestUtils.getContainerId();
+ final ContainerNode containerNode = TxTestUtils.getContainerNode();
+ tx.put(LogicalDatastoreType.CONFIGURATION, id1, containerNode);
+ verify(delegateWriteTx).put(LogicalDatastoreType.CONFIGURATION, id1, containerNode);
+ final YangInstanceIdentifier id2 = TxTestUtils.getLeafId();
+ final LeafNode<String> leafNode = TxTestUtils.getLeafNode();
+ tx.merge(LogicalDatastoreType.CONFIGURATION, id2, leafNode);
+ verify(delegateWriteTx).merge(LogicalDatastoreType.CONFIGURATION, id2, leafNode);
+ tx.delete(LogicalDatastoreType.CONFIGURATION, id2);
+ verify(delegateWriteTx).delete(LogicalDatastoreType.CONFIGURATION, id2);
+ tx.submit();
+ verify(delegateWriteTx).submit();
+ }
+
+ @Test
+ public void commit() throws Exception {
+ tx.commit();
+ verify(delegateWriteTx).commit();
+ }
+
+ @Test
+ public void cancel() throws Exception {
+ tx.cancel();
+ verify(delegateWriteTx).cancel();
+ }
+
+ @Test
+ public void read() throws Exception {
+ tx.read(LogicalDatastoreType.CONFIGURATION, TxTestUtils.getContainerId());
+ verify(delegateReadTx).read(LogicalDatastoreType.CONFIGURATION, TxTestUtils.getContainerId());
+ }
+
+ @Test
+ public void exists() throws Exception {
+ final YangInstanceIdentifier id = TxTestUtils.getContainerId();
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> resultFuture =
+ Futures.immediateCheckedFuture(Optional.of(TxTestUtils.getContainerNode()));
+ when(delegateReadTx.read(LogicalDatastoreType.CONFIGURATION, id)).thenReturn(resultFuture);
+ final CheckedFuture<Boolean, ReadFailedException> exists = tx.exists(LogicalDatastoreType.CONFIGURATION, id);
+ Assert.assertTrue(exists.get());
+ }
+
+ @Test
+ public void getIdentifier() throws Exception {
+ final ReadWriteTx tx2 = new ReadWriteTx(null, null);
+ Assert.assertNotEquals(tx.getIdentifier(), tx2.getIdentifier());
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.sal.connect.netconf.sal.tx;
+
+import com.google.common.collect.ImmutableList;
+import java.io.InputStream;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+
+class TxTestUtils {
+
+ private static final QName Q_NAME_1 = QName.create("test:namespace", "2013-07-22", "c");
+ private static final QName Q_NAME_2 = QName.create(Q_NAME_1, "a");
+
+ static YangInstanceIdentifier getContainerId() {
+ return YangInstanceIdentifier.builder()
+ .node(Q_NAME_1)
+ .build();
+ }
+
+ static YangInstanceIdentifier getLeafId() {
+ return YangInstanceIdentifier.builder()
+ .node(Q_NAME_1)
+ .node(Q_NAME_2)
+ .build();
+ }
+
+ static ContainerNode getContainerNode() {
+ return Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(Q_NAME_1))
+ .build();
+ }
+
+ static LeafNode<String> getLeafNode() {
+ return Builders.<String>leafBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(Q_NAME_2))
+ .withValue("data")
+ .build();
+ }
+
+ static SchemaContext parseYangStreams(final InputStream... streams) {
+ final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR
+ .newBuild();
+ final SchemaContext schemaContext;
+ try {
+ schemaContext = reactor.buildEffective(ImmutableList.copyOf(streams));
+ } catch (final ReactorException e) {
+ throw new RuntimeException("Unable to build schema context from " + streams, e);
+ }
+ return schemaContext;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.sal.connect.netconf.sal.tx;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_LOCK_QNAME;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_TARGET_QNAME;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.toId;
+
+import com.google.common.util.concurrent.Futures;
+import java.net.InetSocketAddress;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps;
+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.netconf.base._1._0.rev110601.copy.config.input.target.ConfigTarget;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public class WriteCandidateRunningTxTest {
+ @Mock
+ private DOMRpcService rpc;
+ private NetconfBaseOps netconfOps;
+ private RemoteDeviceId id;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ final SchemaContext schemaContext = TxTestUtils.parseYangStreams(getClass().getResourceAsStream("/schemas/test-module.yang"));
+ doReturn(Futures.immediateCheckedFuture(new DefaultDOMRpcResult())).when(rpc).invokeRpc(any(), any());
+ netconfOps = new NetconfBaseOps(rpc, schemaContext);
+ id = new RemoteDeviceId("device1", InetSocketAddress.createUnresolved("0.0.0.0", 17830));
+ }
+
+ @Test
+ public void testSubmit() throws Exception {
+ final WriteCandidateRunningTx tx = new WriteCandidateRunningTx(id, netconfOps, true);
+ //check, if lock is called
+ final ContainerNode candidateLock = getLockContent(NETCONF_LOCK_QNAME, NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME);
+ final ContainerNode runningLock = getLockContent(NETCONF_LOCK_QNAME, NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME);
+ verify(rpc).invokeRpc(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_LOCK_QNAME), runningLock);
+ verify(rpc).invokeRpc(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_LOCK_QNAME), candidateLock);
+ tx.put(LogicalDatastoreType.CONFIGURATION, TxTestUtils.getContainerId(), TxTestUtils.getContainerNode());
+ tx.merge(LogicalDatastoreType.CONFIGURATION, TxTestUtils.getLeafId(), TxTestUtils.getLeafNode());
+ //check, if both edits are called
+ verify(rpc, times(2)).invokeRpc(eq(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME)), any());
+ tx.submit().get();
+ //check, if unlock is called
+ verify(rpc).invokeRpc(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME), NetconfMessageTransformUtil.COMMIT_RPC_CONTENT);
+ final ContainerNode candidateUnlock = getLockContent(NETCONF_UNLOCK_QNAME, NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME);
+ final ContainerNode runningUnlock = getLockContent(NETCONF_UNLOCK_QNAME, NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME);
+ verify(rpc).invokeRpc(SchemaPath.create(true, NETCONF_UNLOCK_QNAME), candidateUnlock);
+ verify(rpc).invokeRpc(SchemaPath.create(true, NETCONF_UNLOCK_QNAME), runningUnlock);
+ }
+
+ private static ContainerNode getLockContent(final QName op, final QName datastore) {
+ final LeafNode<Object> datastoreLeaf = Builders.leafBuilder().withNodeIdentifier(toId(datastore)).build();
+ final ChoiceNode choice = Builders.choiceBuilder()
+ .withNodeIdentifier(toId(ConfigTarget.QNAME))
+ .withChild(datastoreLeaf)
+ .build();
+ final ContainerNode target = Builders.containerBuilder()
+ .withNodeIdentifier(toId(NETCONF_TARGET_QNAME))
+ .withChild(choice).build();
+ return Builders.containerBuilder()
+ .withNodeIdentifier(toId(op))
+ .withChild(target)
+ .build();
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.sal.connect.netconf.sal.tx;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.util.concurrent.Futures;
+import java.net.InetSocketAddress;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps;
+import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public class WriteCandidateTxTest {
+
+ @Mock
+ private DOMRpcService rpc;
+ private NetconfBaseOps netconfOps;
+ private RemoteDeviceId id;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ final SchemaContext schemaContext = TxTestUtils.parseYangStreams(getClass().getResourceAsStream("/schemas/test-module.yang"));
+ doReturn(Futures.immediateCheckedFuture(new DefaultDOMRpcResult())).when(rpc).invokeRpc(any(), any());
+ netconfOps = new NetconfBaseOps(rpc, schemaContext);
+ id = new RemoteDeviceId("device1", InetSocketAddress.createUnresolved("0.0.0.0", 17830));
+ }
+
+ @Test
+ public void testSubmit() throws Exception {
+ final WriteCandidateTx tx = new WriteCandidateTx(id, netconfOps, true);
+ //check, if lock is called
+ verify(rpc).invokeRpc(eq(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_LOCK_QNAME)), any());
+
+ tx.put(LogicalDatastoreType.CONFIGURATION, TxTestUtils.getContainerId(), TxTestUtils.getContainerNode());
+ tx.merge(LogicalDatastoreType.CONFIGURATION, TxTestUtils.getLeafId(), TxTestUtils.getLeafNode());
+ //check, if both edits are called
+ verify(rpc, times(2)).invokeRpc(eq(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME)), any());
+ tx.submit().get();
+ //check, if unlock is called
+ verify(rpc).invokeRpc(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME), NetconfMessageTransformUtil.COMMIT_RPC_CONTENT);
+ verify(rpc).invokeRpc(eq(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME)), any());
+ }
+
+}
\ No newline at end of file
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Futures;
-import java.io.InputStream;
import java.net.InetSocketAddress;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
-import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
public class WriteRunningTxTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- final SchemaContext schemaContext = parseYangStreams(getClass().getResourceAsStream("/schemas/test-module.yang"));
+ final SchemaContext schemaContext = TxTestUtils.parseYangStreams(getClass().getResourceAsStream("/schemas/test-module.yang"));
doReturn(Futures.immediateCheckedFuture(new DefaultDOMRpcResult())).when(rpc).invokeRpc(any(), any());
netconfOps = new NetconfBaseOps(rpc, schemaContext);
id = new RemoteDeviceId("device1", InetSocketAddress.createUnresolved("0.0.0.0", 17830));
final WriteRunningTx tx = new WriteRunningTx(id, netconfOps, true);
//check, if lock is called
verify(rpc).invokeRpc(eq(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_LOCK_QNAME)), any());
- final QName qName1 = QName.create("test:namespace", "2013-07-22", "c");
- final YangInstanceIdentifier yid1 = YangInstanceIdentifier.builder()
- .node(qName1)
- .build();
- final QName qName2 = QName.create(qName1, "a");
- final YangInstanceIdentifier yid2 = YangInstanceIdentifier.builder()
- .node(qName1)
- .node(qName2)
- .build();
- final ContainerNode data1 = Builders.containerBuilder()
- .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(qName1))
- .build();
- final LeafNode<String> data2 = Builders.<String>leafBuilder()
- .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(qName2))
- .withValue("data")
- .build();
- tx.put(LogicalDatastoreType.CONFIGURATION, yid1, data1);
- tx.merge(LogicalDatastoreType.CONFIGURATION, yid2, data2);
+ tx.put(LogicalDatastoreType.CONFIGURATION, TxTestUtils.getContainerId(), TxTestUtils.getContainerNode());
+ tx.merge(LogicalDatastoreType.CONFIGURATION, TxTestUtils.getLeafId(), TxTestUtils.getLeafNode());
//check, if no edit-config is called before submit
verify(rpc, never()).invokeRpc(eq(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME)), any());
tx.submit().get();
//check, if unlock is called
verify(rpc).invokeRpc(eq(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME)), any());
}
-
- private static SchemaContext parseYangStreams(final InputStream... streams) {
- final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR
- .newBuild();
- final SchemaContext schemaContext;
- try {
- schemaContext = reactor.buildEffective(ImmutableList.copyOf(streams));
- } catch (final ReactorException e) {
- throw new RuntimeException("Unable to build schema context from " + streams, e);
- }
- return schemaContext;
- }
}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.sal.connect.netconf.schema.mapping;
+
+import com.google.common.base.Optional;
+import java.io.InputStream;
+import javax.xml.transform.dom.DOMSource;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.netconf.api.NetconfMessage;
+import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.netconf.sal.connect.util.MessageCounter;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.copy.config.input.target.ConfigTarget;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.edit.config.input.EditContent;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.edit.config.input.target.config.target.Candidate;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class BaseRpcSchemalessTransformerTest {
+
+ static {
+ XMLUnit.setIgnoreWhitespace(true);
+ XMLUnit.setIgnoreAttributeOrder(true);
+ }
+
+ private static final String EXP_RPC = "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ " <edit-config>\n" +
+ " <target>\n" +
+ " <candidate/>\n" +
+ " </target>\n" +
+ " <config>\n" +
+ " <top xmlns=\"http://example.com/schema/1.2/config\">\n" +
+ " <users xmlns:ns0=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ns0:operation=\"replace\">\n" +
+ " <user>\n" +
+ " <name>fred</name>\n" +
+ " </user>\n" +
+ " </users>\n" +
+ " </top>\n" +
+ " </config>\n" +
+ " </edit-config>\n" +
+ "</rpc>\n";
+
+ BaseRpcSchemalessTransformer transformer;
+
+ @Before
+ public void setUp() throws Exception {
+ transformer = new BaseRpcSchemalessTransformer(new MessageCounter());
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void toNotification() throws Exception {
+ transformer.toNotification(new NetconfMessage(XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/notification-payload.xml"))));
+ }
+
+ @Test
+ public void toRpcRequest() throws Exception {
+ final Document doc = XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/schemaless/edit-config/container.xml"));
+ final AnyXmlNode xml = Builders.anyXmlBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NetconfMessageTransformUtil.NETCONF_CONFIG_QNAME))
+ .withValue(new DOMSource(doc.getDocumentElement()))
+ .build();
+ final ChoiceNode editContent = Builders.choiceBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(EditContent.QNAME))
+ .withChild(xml)
+ .build();
+ final ChoiceNode candidate = Builders.choiceBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(ConfigTarget.QNAME))
+ .withChild(Builders.leafBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(Candidate.QNAME)).build())
+ .build();
+ final DataContainerChild<?, ?> target = Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NetconfMessageTransformUtil.NETCONF_TARGET_QNAME))
+ .withChild(candidate)
+ .build();
+ final ContainerNode editConfig = Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME))
+ .withChild(editContent)
+ .withChild(target)
+ .build();
+ final NetconfMessage msg = transformer.toRpcRequest(SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME), editConfig);
+ final Diff diff = XMLUnit.compareXML(EXP_RPC, XmlUtil.toString(msg.getDocument()));
+ Assert.assertTrue(diff.toString(), diff.similar());
+ }
+
+ @Test
+ public void toRpcResult() throws Exception {
+ final Document doc = XmlUtil.readXmlToDocument("<rpc-reply message-id=\"101\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>");
+ final InputStream stream = getClass().getResourceAsStream("/schemaless/get-config/container.xml");
+ final Element dataElement = XmlUtil.readXmlToElement(stream);
+ final Element element = (Element) doc.importNode(dataElement, true);
+ doc.getDocumentElement().appendChild(element);
+ final NetconfMessage msg = new NetconfMessage(doc);
+ final DOMRpcResult result = transformer.toRpcResult(msg, SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME));
+ Assert.assertNotNull(result.getResult());
+ final ContainerNode rpcReply = (ContainerNode) result.getResult();
+ Assert.assertEquals(NetconfMessageTransformUtil.NETCONF_RPC_REPLY_QNAME, rpcReply.getNodeType());
+ final Optional dataOpt = rpcReply.getChild(new YangInstanceIdentifier.NodeIdentifier(NetconfMessageTransformUtil.NETCONF_DATA_QNAME));
+ Assert.assertTrue(dataOpt.isPresent());
+ final AnyXmlNode data = (AnyXmlNode) dataOpt.get();
+ final Diff diff = XMLUnit.compareXML(dataElement.getOwnerDocument(), (Document) data.getValue().getNode());
+ Assert.assertTrue(diff.toString(), diff.similar());
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.sal.connect.netconf.schema.mapping;
+
+import javax.xml.transform.dom.DOMSource;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.netconf.api.NetconfMessage;
+import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.netconf.sal.connect.util.MessageCounter;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+public class SchemalessMessageTransformerTest {
+
+ static {
+ XMLUnit.setIgnoreWhitespace(true);
+ }
+
+ private static final String EXP_REQUEST = "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ "<test-rpc xmlns=\"test-ns\">\n" +
+ "<input>aaa</input>\n" +
+ "</test-rpc>\n" +
+ "</rpc>";
+ private static final String EXP_REPLY = "<rpc-reply message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ "<output xmlns=\"test-ns\">aaa</output>\n" +
+ "</rpc-reply>";
+ private static final String OK_REPLY = "<rpc-reply message-id=\"101\"\n" +
+ "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+ "<ok/>\n" +
+ "</rpc-reply>\n";
+
+ private SchemalessMessageTransformer transformer;
+ private static final QName TEST_RPC = QName.create("test-ns", "2016-10-13", "test-rpc");
+ private static final SchemaPath SCHEMA_PATH = SchemaPath.create(true, TEST_RPC);
+
+ @Before
+ public void setUp() throws Exception {
+ transformer = new SchemalessMessageTransformer(new MessageCounter());
+ }
+
+ @Test
+ public void toNotification() throws Exception {
+ final Document payload = XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/notification-payload.xml"));
+ final NetconfMessage netconfMessage = new NetconfMessage(payload);
+ final DOMNotification domNotification = transformer.toNotification(netconfMessage);
+ Assert.assertEquals(domNotification.getType().getLastComponent(), SchemalessMessageTransformer.SCHEMALESS_NOTIFICATION_PAYLOAD.getNodeType());
+ final QName qName = QName.create("org:opendaylight:notification:test:ns:yang:user-notification", "user-visited-page");
+ final AnyXmlNode dataContainerChild =
+ (AnyXmlNode) domNotification.getBody().getChild(new YangInstanceIdentifier.NodeIdentifier(qName)).get();
+ final Diff diff = XMLUnit.compareXML(payload, dataContainerChild.getValue().getNode().getOwnerDocument());
+ Assert.assertTrue(diff.toString(), diff.similar());
+
+ }
+
+ @Test
+ public void toRpcRequest() throws Exception {
+ final Node src = XmlUtil.readXmlToDocument("<test-rpc xmlns=\"test-ns\"><input>aaa</input></test-rpc>");
+ final AnyXmlNode input = Builders.anyXmlBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TEST_RPC))
+ .withValue(new DOMSource(src))
+ .build();
+ final NetconfMessage netconfMessage = transformer.toRpcRequest(SCHEMA_PATH, input);
+ final Diff diff = XMLUnit.compareXML(XmlUtil.readXmlToDocument(EXP_REQUEST), netconfMessage.getDocument());
+ Assert.assertTrue(diff.toString(), diff.similar());
+ }
+
+ @Test
+ public void toRpcResult() throws Exception {
+ final Document doc = XmlUtil.readXmlToDocument(EXP_REPLY);
+ final NetconfMessage netconfMessage = new NetconfMessage(doc);
+ final DOMRpcResult result = transformer.toRpcResult(netconfMessage, SCHEMA_PATH);
+ final DOMSource value = (DOMSource) result.getResult().getValue();
+ Assert.assertNotNull(result.getResult());
+ final Document domSourceDoc = (Document) value.getNode();
+ final Diff diff = XMLUnit.compareXML(XmlUtil.readXmlToDocument(EXP_REPLY), domSourceDoc);
+ Assert.assertTrue(diff.toString(), diff.similar());
+ }
+
+ @Test
+ public void toEmptyRpcResult() throws Exception {
+ final Document doc = XmlUtil.readXmlToDocument(OK_REPLY);
+ final DOMRpcResult result = transformer.toRpcResult(new NetconfMessage(doc), SchemaPath.create(true, NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME));
+ Assert.assertNull(result.getResult());
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.sal.connect.netconf.util;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.google.common.base.Optional;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.netconf.api.NetconfMessage;
+import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceCommunicator;
+import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc;
+import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer;
+import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.xml.sax.SAXException;
+
+public class NetconfBaseOpsTest {
+
+ static {
+ XMLUnit.setIgnoreWhitespace(true);
+ XMLUnit.setIgnoreComments(true);
+ }
+
+ private static final QName CONTAINER_Q_NAME = QName.create("test:namespace", "2013-07-22", "c");
+
+ @Mock
+ private RemoteDeviceCommunicator<NetconfMessage> listener;
+ private NetconfRpcFutureCallback callback;
+ private NetconfBaseOps baseOps;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ final InputStream okStream = getClass().getResourceAsStream("/netconfMessages/rpc-reply_ok.xml");
+ final InputStream dataStream = getClass().getResourceAsStream("/netconfMessages/rpc-reply_get.xml");
+ final NetconfMessage ok = new NetconfMessage(XmlUtil.readXmlToDocument(okStream));
+ final NetconfMessage data = new NetconfMessage(XmlUtil.readXmlToDocument(dataStream));
+ when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME)))
+ .thenReturn(RpcResultBuilder.success(data).buildFuture());
+ when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_GET_QNAME)))
+ .thenReturn(RpcResultBuilder.success(data).buildFuture());
+ when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME)))
+ .thenReturn(RpcResultBuilder.success(ok).buildFuture());
+ when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME)))
+ .thenReturn(RpcResultBuilder.success(ok).buildFuture());
+ when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME)))
+ .thenReturn(RpcResultBuilder.success(ok).buildFuture());
+ when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME)))
+ .thenReturn(RpcResultBuilder.success(ok).buildFuture());
+ when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_LOCK_QNAME)))
+ .thenReturn(RpcResultBuilder.success(ok).buildFuture());
+ when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME)))
+ .thenReturn(RpcResultBuilder.success(ok).buildFuture());
+ when(listener.sendRequest(any(), eq(NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME)))
+ .thenReturn(RpcResultBuilder.success(ok).buildFuture());
+ final SchemaContext schemaContext =
+ parseYangStreams(getClass().getResourceAsStream("/schemas/test-module.yang"));
+ final MessageTransformer<NetconfMessage> transformer = new NetconfMessageTransformer(schemaContext, true);
+ final DOMRpcService rpc = new NetconfDeviceRpc(schemaContext, listener, transformer);
+ final RemoteDeviceId id =
+ new RemoteDeviceId("device-1", InetSocketAddress.createUnresolved("localhost", 17830));
+ callback = new NetconfRpcFutureCallback("prefix", id);
+ baseOps = new NetconfBaseOps(rpc, schemaContext);
+ }
+
+ @Test
+ public void testLock() throws Exception {
+ baseOps.lock(callback, NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME);
+ verifyMessageSent("lock", NetconfMessageTransformUtil.NETCONF_LOCK_QNAME);
+ }
+
+ @Test
+ public void testLockCandidate() throws Exception {
+ baseOps.lockCandidate(callback);
+ verifyMessageSent("lock", NetconfMessageTransformUtil.NETCONF_LOCK_QNAME);
+ }
+
+ @Test
+ public void testUnlock() throws Exception {
+ baseOps.unlock(callback, NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME);
+ verifyMessageSent("unlock", NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME);
+ }
+
+ @Test
+ public void testUnlockCandidate() throws Exception {
+ baseOps.unlockCandidate(callback);
+ verifyMessageSent("unlock", NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME);
+ }
+
+ @Test
+ public void testLockRunning() throws Exception {
+ baseOps.lockRunning(callback);
+ verifyMessageSent("lock-running", NetconfMessageTransformUtil.NETCONF_LOCK_QNAME);
+ }
+
+ @Test
+ public void testUnlockRunning() throws Exception {
+ baseOps.unlockRunning(callback);
+ verifyMessageSent("unlock-running", NetconfMessageTransformUtil.NETCONF_UNLOCK_QNAME);
+ }
+
+ @Test
+ public void testDiscardChanges() throws Exception {
+ baseOps.discardChanges(callback);
+ verifyMessageSent("discardChanges", NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME);
+ }
+
+ @Test
+ public void testCommit() throws Exception {
+ baseOps.commit(callback);
+ verifyMessageSent("commit", NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME);
+ }
+
+ @Test
+ public void testValidateCandidate() throws Exception {
+ baseOps.validateCandidate(callback);
+ verifyMessageSent("validate", NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME);
+ }
+
+ @Test
+ public void testValidateRunning() throws Exception {
+ baseOps.validateRunning(callback);
+ verifyMessageSent("validate-running", NetconfMessageTransformUtil.NETCONF_VALIDATE_QNAME);
+ }
+
+
+ @Test
+ public void testCopyConfig() throws Exception {
+ baseOps.copyConfig(callback, NetconfMessageTransformUtil.NETCONF_RUNNING_QNAME,
+ NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME);
+ verifyMessageSent("copy-config", NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME);
+ }
+
+ @Test
+ public void testCopyRunningToCandidate() throws Exception {
+ baseOps.copyRunningToCandidate(callback);
+ verifyMessageSent("copy-config", NetconfMessageTransformUtil.NETCONF_COPY_CONFIG_QNAME);
+ }
+
+
+ @Test
+ public void testGetConfigRunningData() throws Exception {
+ final Optional<NormalizedNode<?, ?>> dataOpt =
+ baseOps.getConfigRunningData(callback, Optional.of(YangInstanceIdentifier.EMPTY)).get();
+ Assert.assertTrue(dataOpt.isPresent());
+ Assert.assertEquals(NetconfMessageTransformUtil.NETCONF_DATA_QNAME, dataOpt.get().getNodeType());
+ }
+
+ @Test
+ public void testGetData() throws Exception {
+ final Optional<NormalizedNode<?, ?>> dataOpt =
+ baseOps.getData(callback, Optional.of(YangInstanceIdentifier.EMPTY)).get();
+ Assert.assertTrue(dataOpt.isPresent());
+ Assert.assertEquals(NetconfMessageTransformUtil.NETCONF_DATA_QNAME, dataOpt.get().getNodeType());
+ }
+
+ @Test
+ public void testGetConfigRunning() throws Exception {
+ baseOps.getConfigRunning(callback, Optional.absent());
+ verifyMessageSent("getConfig", NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME);
+ }
+
+ @Test
+ public void testGetConfigCandidate() throws Exception {
+ baseOps.getConfigCandidate(callback, Optional.absent());
+ verifyMessageSent("getConfig_candidate", NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME);
+ }
+
+ @Test
+ public void testGetConfigCandidateWithFilter() throws Exception {
+ final YangInstanceIdentifier id = YangInstanceIdentifier.builder()
+ .node(CONTAINER_Q_NAME)
+ .build();
+ baseOps.getConfigCandidate(callback, Optional.of(id));
+ verifyMessageSent("getConfig_candidate-filter", NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME);
+ }
+
+ @Test
+ public void testGet() throws Exception {
+ baseOps.get(callback, Optional.absent());
+ verifyMessageSent("get", NetconfMessageTransformUtil.NETCONF_GET_QNAME);
+ }
+
+ @Test
+ public void testEditConfigCandidate() throws Exception {
+ final QName leafQName = QName.create(CONTAINER_Q_NAME, "a");
+ final LeafNode<Object> leaf = Builders.leafBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(leafQName))
+ .withValue("leaf-value")
+ .build();
+ final YangInstanceIdentifier leafId = YangInstanceIdentifier.builder()
+ .node(CONTAINER_Q_NAME)
+ .node(leafQName)
+ .build();
+ final DataContainerChild<?, ?> structure = baseOps.createEditConfigStrcture(Optional.of(leaf),
+ Optional.of(ModifyAction.REPLACE), leafId);
+ baseOps.editConfigCandidate(callback, structure, true);
+ verifyMessageSent("edit-config-test-module", NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME);
+ }
+
+ @Test
+ public void testEditConfigRunning() throws Exception {
+ final QName containerQName = QName.create("test:namespace", "2013-07-22", "c");
+ final QName leafQName = QName.create(containerQName, "a");
+ final LeafNode<Object> leaf = Builders.leafBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(leafQName))
+ .withValue("leaf-value")
+ .build();
+ final YangInstanceIdentifier leafId = YangInstanceIdentifier.builder()
+ .node(containerQName)
+ .node(leafQName)
+ .build();
+ final DataContainerChild<?, ?> structure = baseOps.createEditConfigStrcture(Optional.of(leaf),
+ Optional.of(ModifyAction.REPLACE), leafId);
+ baseOps.editConfigRunning(callback, structure, ModifyAction.MERGE, true);
+ verifyMessageSent("edit-config-test-module-running", NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME);
+ }
+
+ private static SchemaContext parseYangStreams(final InputStream... streams) {
+ final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR
+ .newBuild();
+ final SchemaContext schemaContext;
+ try {
+ schemaContext = reactor.buildEffective(Arrays.asList(streams));
+ } catch (final ReactorException e) {
+ throw new RuntimeException("Unable to build schema context from " + streams, e);
+ }
+ return schemaContext;
+ }
+
+ private void verifyMessageSent(final String fileName, final QName name) {
+ final String path = "/netconfMessages/" + fileName + ".xml";
+ verify(listener).sendRequest(msg(path), eq(name));
+ }
+
+ private static NetconfMessage msg(final String name) {
+ final InputStream stream = NetconfBaseOpsTest.class.getResourceAsStream(name);
+ try {
+ return argThat(new NetconfMessageMatcher(XmlUtil.readXmlToDocument(stream)));
+ } catch (SAXException | IOException e) {
+ throw new IllegalStateException("Failed to read xml file " + name, e);
+ }
+ }
+
+ private static class NetconfMessageMatcher extends BaseMatcher<NetconfMessage> {
+
+ private final Document expected;
+
+ private NetconfMessageMatcher(final Document expected) {
+ this.expected = removeAttrs(expected);
+ }
+
+ @Override
+ public boolean matches(final Object item) {
+ if (!(item instanceof NetconfMessage)) {
+ return false;
+ }
+ final NetconfMessage message = (NetconfMessage) item;
+ final Document actualDoc = removeAttrs(message.getDocument());
+ actualDoc.normalizeDocument();
+ expected.normalizeDocument();
+ final Diff diff = XMLUnit.compareXML(expected, actualDoc);
+ return diff.similar();
+ }
+
+ @Override
+ public void describeTo(final Description description) {
+ description.appendText(XmlUtil.toString(expected));
+ }
+
+ private static Document removeAttrs(final Document input) {
+ final Document copy = XmlUtil.newDocument();
+ copy.appendChild(copy.importNode(input.getDocumentElement(), true));
+ final Element element = copy.getDocumentElement();
+ final List<String> attrNames = new ArrayList<>();
+ final NamedNodeMap attributes = element.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++) {
+ final String nodeName = attributes.item(i).getNodeName();
+ if ("xmlns".equals(nodeName)) {
+ continue;
+ }
+ attrNames.add(nodeName);
+ }
+ attrNames.forEach(element::removeAttribute);
+ return copy;
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. 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.sal.connect.netconf.util;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+public class NodeContainerProxyTest {
+
+ private static final QName QNAME = QName.create("ns", "2016-10-19", "name");
+ private static final QName NODE_1_QNAME = QName.create(QNAME, "node-1");
+ private static final QName NODE_2_QNAME = QName.create(QNAME, "node-2");
+ @Mock
+ private AugmentationSchema augSchema1;
+ @Mock
+ private AugmentationSchema augSchema2;
+ @Mock
+ private DataSchemaNode schemaNode1;
+ @Mock
+ private DataSchemaNode schemaNode2;
+ private NodeContainerProxy proxy;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ final Map<QName, DataSchemaNode> childNodes = new HashMap<>();
+ childNodes.put(NODE_1_QNAME, schemaNode1);
+ childNodes.put(NODE_2_QNAME, schemaNode2);
+ final Set<AugmentationSchema> augmentations = new HashSet<>();
+ augmentations.add(augSchema1);
+ augmentations.add(augSchema2);
+ proxy = new NodeContainerProxy(QNAME, childNodes, augmentations);
+ }
+
+ @Test
+ public void testGetQName() throws Exception {
+ Assert.assertEquals(QNAME, proxy.getQName());
+ }
+
+ @Test
+ public void testGetChildNodes() throws Exception {
+ Assert.assertEquals(2, proxy.getChildNodes().size());
+ }
+
+ @Test
+ public void testGetAvailableAugmentations() throws Exception {
+ final Set<AugmentationSchema> augmentations = proxy.getAvailableAugmentations();
+ Assert.assertEquals(2, augmentations.size());
+ Assert.assertTrue(augmentations.contains(augSchema1));
+ Assert.assertTrue(augmentations.contains(augSchema2));
+ }
+
+ @Test
+ public void testGetDataChildByName() throws Exception {
+ final DataSchemaNode schemaNode = proxy.getDataChildByName(NODE_1_QNAME);
+ Assert.assertEquals(schemaNode1, schemaNode);
+ }
+
+ @Test
+ public void testGetTypeDefinitions() throws Exception {
+ Assert.assertTrue(proxy.getTypeDefinitions().isEmpty());
+ }
+
+ @Test
+ public void testGetGroupings() throws Exception {
+ Assert.assertTrue(proxy.getGroupings().isEmpty());
+ }
+
+ @Test
+ public void testGetUses() throws Exception {
+ Assert.assertTrue(proxy.getUses().isEmpty());
+ }
+
+ @Test
+ public void testGetUnknownSchemaNodes() throws Exception {
+ Assert.assertTrue(proxy.getUnknownSchemaNodes().isEmpty());
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testIsPresenceContainer() throws Exception {
+ proxy.isPresenceContainer();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testIsAugmenting() throws Exception {
+ proxy.isAugmenting();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testIsAddedByUses() throws Exception {
+ proxy.isAddedByUses();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testIsConfiguration() throws Exception {
+ proxy.isConfiguration();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetConstraints() throws Exception {
+ proxy.getConstraints();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetPath() throws Exception {
+ proxy.getPath();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetDescription() throws Exception {
+ proxy.getDescription();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetReference() throws Exception {
+ proxy.getReference();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetStatus() throws Exception {
+ proxy.getStatus();
+ }
+
+}
\ No newline at end of file
@Override
public Set<Module> getSubmodules() {
- throw new UnsupportedOperationException("Not supported operations.");
+ return new HashSet<>();
}
@Override