From: Tomas Cere Date: Mon, 24 Oct 2016 10:02:58 +0000 (+0000) Subject: Merge "Add unit tests for sal-netconf-connector transactions" X-Git-Tag: release/carbon~158 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=77eb72cb594acdcf302a9a49aeb9ced8281bab8c;hp=7af02aeff63b4891b87643df8ff6ae8f2debcb9a;p=netconf.git Merge "Add unit tests for sal-netconf-connector transactions" --- diff --git a/features/netconf-connector/pom.xml b/features/netconf-connector/pom.xml index cf4131026b..9600b0ba5a 100644 --- a/features/netconf-connector/pom.xml +++ b/features/netconf-connector/pom.xml @@ -111,10 +111,6 @@ config xml - - ${project.groupId} - abstract-topology - ${project.groupId} netconf-topology @@ -125,12 +121,6 @@ config xml - - ${project.groupId} - netconf-topology-config - clustered-config - xml - ${project.groupId} netconf-tcp @@ -147,6 +137,10 @@ org.bouncycastle bcprov-jdk15on + + ${project.groupId} + netconf-topology-singleton + ${project.groupId} diff --git a/features/netconf-connector/src/main/features/features.xml b/features/netconf-connector/src/main/features/features.xml index fe3e66dba3..27c883f221 100644 --- a/features/netconf-connector/src/main/features/features.xml +++ b/features/netconf-connector/src/main/features/features.xml @@ -38,7 +38,6 @@ mvn:org.opendaylight.netconf/sal-netconf-connector/{{VERSION}} mvn:org.opendaylight.controller.model/model-inventory/{{VERSION}} mvn:org.opendaylight.netconf/netconf-topology/{{VERSION}} - mvn:org.opendaylight.netconf/abstract-topology/{{VERSION}} mvn:org.opendaylight.netconf/sal-netconf-connector/{{VERSION}} mvn:org.opendaylight.netconf/netconf-config-dispatcher/{{VERSION}} mvn:org.opendaylight.netconf/netconf-config/{{VERSION}}/xml/config @@ -55,10 +54,10 @@ mvn:org.opendaylight.netconf/netconf-topology-config/{{VERSION}}/xml/config - - odl-netconf-ssh + + odl-netconf-ssh odl-netconf-connector - mvn:org.opendaylight.netconf/netconf-topology-config/{{VERSION}}/xml/clustered-config + mvn:org.opendaylight.netconf/netconf-topology-singleton/{{VERSION}} diff --git a/features/netconf/pom.xml b/features/netconf/pom.xml index 4862a9523a..b413f6b838 100644 --- a/features/netconf/pom.xml +++ b/features/netconf/pom.xml @@ -186,6 +186,12 @@ ${project.groupId} netconf-util + + ${project.groupId} + netconf-util + cfg + config + ${project.groupId} netconf-impl diff --git a/features/netconf/src/main/features/features.xml b/features/netconf/src/main/features/features.xml index 645f985282..b43653d2a0 100644 --- a/features/netconf/src/main/features/features.xml +++ b/features/netconf/src/main/features/features.xml @@ -44,6 +44,7 @@ odl-netconf-mapping-api odl-yangtools-yang-data mvn:org.opendaylight.netconf/netconf-util/{{VERSION}} + mvn:org.opendaylight.netconf/netconf-util/{{VERSION}}/cfg/config @@ -113,12 +114,14 @@ + odl-netconf-util odl-netconf-tcp odl-aaa-netconf-plugin mvn:org.opendaylight.netconf/netconf-ssh/{{VERSION}} + odl-netconf-util odl-netconf-impl odl-config-netty mvn:org.opendaylight.netconf/netconf-tcp/{{VERSION}} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/InitialStateProvider.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/InitialStateProvider.java deleted file mode 100644 index ae53a9dc79..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/InitialStateProvider.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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); -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/NodeListener.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/NodeListener.java deleted file mode 100644 index b49d3bb1db..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/NodeListener.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 onNodeCreated(@Nonnull NodeId nodeId, @Nonnull Node configNode); - - @Nonnull ListenableFuture onNodeUpdated(@Nonnull NodeId nodeId, @Nonnull Node configNode); - - @Nonnull ListenableFuture onNodeDeleted(@Nonnull NodeId nodeId); - - @Nonnull ListenableFuture getCurrentStatusForNode(@Nonnull NodeId nodeId); -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/NodeManager.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/NodeManager.java deleted file mode 100644 index c8ca14d252..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/NodeManager.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 { - -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/NodeManagerCallback.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/NodeManagerCallback.java deleted file mode 100644 index 670bb81ebe..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/NodeManagerCallback.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 { - - interface NodeManagerCallbackFactory { - NodeManagerCallback create(String nodeId, String topologyId, ActorSystem actorSystem); - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/RemoteNodeListener.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/RemoteNodeListener.java deleted file mode 100644 index 7a8dc59fc8..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/RemoteNodeListener.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 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 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 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 remoteGetCurrentStatusForNode(NodeId nodeId); -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/RoleChangeListener.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/RoleChangeListener.java deleted file mode 100644 index 5cf4250bcc..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/RoleChangeListener.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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; - } - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/RoleChangeStrategy.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/RoleChangeStrategy.java deleted file mode 100644 index f4f3013b7f..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/RoleChangeStrategy.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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(); - -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/StateAggregator.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/StateAggregator.java deleted file mode 100644 index d72d28027b..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/StateAggregator.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 combineCreateAttempts(final List> stateFutures); - - ListenableFuture combineUpdateAttempts(final List> stateFutures); - - ListenableFuture combineDeleteAttempts(final List> stateFutures); - -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/TopologyManager.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/TopologyManager.java deleted file mode 100644 index 3de1677369..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/TopologyManager.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 isMaster(); - - /** - * - * @param nodeId - id of the node that sessionUp/Down happened on - */ - void notifyNodeStatusChange(NodeId nodeId); - - boolean hasAllPeersUp(); - -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/TopologyManagerCallback.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/TopologyManagerCallback.java deleted file mode 100644 index 8eee06a54e..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/TopologyManagerCallback.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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); - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/ExampleNodeManagerCallback.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/ExampleNodeManagerCallback.java deleted file mode 100644 index 823c44b47a..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/ExampleNodeManagerCallback.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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 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 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 onNodeDeleted(@Nonnull final NodeId nodeId) { - return Futures.immediateFuture(null); - } - - @Nonnull - @Override - public ListenableFuture 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() { - - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/ExampleSingleStateAggregator.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/ExampleSingleStateAggregator.java deleted file mode 100644 index 6d27c26078..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/ExampleSingleStateAggregator.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 combineCreateAttempts(final List> stateFutures) { - return getSingleFuture(stateFutures); - } - - private ListenableFuture getSingleFuture(final List> stateFutures) { - Preconditions.checkArgument(stateFutures.size() == 1, "Recieved multiple results, Single result is enforced here"); - return stateFutures.get(0); - } - - @Override public ListenableFuture combineUpdateAttempts(final List> stateFutures) { - return getSingleFuture(stateFutures); - } - - @Override public ListenableFuture combineDeleteAttempts(final List> stateFutures) { - return getSingleFuture(stateFutures); - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/ExampleTopology.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/ExampleTopology.java deleted file mode 100644 index c31e18e731..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/ExampleTopology.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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)); - - } - -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/ExampleTopologyManagerCallback.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/ExampleTopologyManagerCallback.java deleted file mode 100644 index a2eed6a019..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/ExampleTopologyManagerCallback.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * 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 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 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 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 onNodeDeleted(final NodeId nodeId) { - // Trigger delete only on this node - final ListenableFuture future = nodes.get(nodeId).onNodeDeleted(nodeId); - Futures.addCallback(future, new FutureCallback() { - @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 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); - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/LoggingSalNodeWriter.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/LoggingSalNodeWriter.java deleted file mode 100644 index e4ead18352..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/example/LoggingSalNodeWriter.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 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); - } - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/BaseNodeManager.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/BaseNodeManager.java deleted file mode 100644 index f48f0c4e32..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/BaseNodeManager.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * 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 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 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 onNodeDeleted(@Nonnull final NodeId nodeId) { - LOG.debug("Deleting Node {}", nodeId.getValue()); - return delegate.onNodeDeleted(nodeId); - } - - @Nonnull - @Override - public ListenableFuture 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 onRemoteNodeCreated(final NormalizedNodeMessage message) { - return null; - } - - @Override - public Future onRemoteNodeUpdated(final NormalizedNodeMessage message) { - return null; - } - - @Override - public Future onRemoteNodeDeleted(final NodeId nodeId) { - return null; - } - - @Override - public Future 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() { - @Override - public BaseNodeManager create() throws Exception { - return new BaseNodeManager(nodeId, topologyId, actorContext.system(), delegateFactory, roleChangeStrategy); - } - }), nodeId); - } - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/BaseTopologyManager.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/BaseTopologyManager.java deleted file mode 100644 index 133aa46cf3..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/BaseTopologyManager.java +++ /dev/null @@ -1,612 +0,0 @@ -/* - * 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 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 created = new HashSet<>(); - - private final Map 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.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 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> 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> 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 settableFuture = SettableFuture.create(); - futures.add(settableFuture); - final Future scalaFuture = topologyManager.onRemoteNodeCreated(new NormalizedNodeMessage(normalizedNodeEntry.getKey(), normalizedNodeEntry.getValue())); - scalaFuture.onComplete(new OnComplete() { - @Override - public void onComplete(Throwable failure, NormalizedNodeMessage success) throws Throwable { - if (failure != null) { - settableFuture.setException(failure); - return; - } - final Entry, DataObject> fromNormalizedNode = - codecRegistry.fromNormalizedNode(success.getIdentifier(), success.getNode()); - final Node value = (Node) fromNormalizedNode.getValue(); - - settableFuture.set(value); - } - }, TypedActor.context().dispatcher()); - } - - final ListenableFuture aggregatedFuture = aggregator.combineCreateAttempts(futures); - Futures.addCallback(aggregatedFuture, new FutureCallback() { - @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 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 deleteFuture = onNodeDeleted(nodeId); - final SettableFuture createFuture = SettableFuture.create(); - final TopologyManager selfProxy = TypedActor.self(); - final ActorContext context = TypedActor.context(); - Futures.addCallback(deleteFuture, new FutureCallback() { - @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() { - @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 onNodeDeleted(final NodeId nodeId) { - final ArrayList> 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 settableFuture = SettableFuture.create(); - futures.add(settableFuture); - final Future scalaFuture = topologyManager.onRemoteNodeDeleted(nodeId); - scalaFuture.onComplete(new OnComplete() { - @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 aggregatedFuture = aggregator.combineDeleteAttempts(futures); - Futures.addCallback(aggregatedFuture, new FutureCallback() { - @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 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 isMaster() { - return new DefaultPromise().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> 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 settableFuture = SettableFuture.create(); - futures.add(settableFuture); - final Future scalaFuture = topologyManager.remoteGetCurrentStatusForNode(nodeId); - scalaFuture.onComplete(new OnComplete() { - @Override - public void onComplete(Throwable failure, NormalizedNodeMessage success) throws Throwable { - if (failure != null) { - settableFuture.setException(failure); - return; - } - final Entry, DataObject> fromNormalizedNode = - codecRegistry.fromNormalizedNode(success.getIdentifier(), success.getNode()); - final Node value = (Node) fromNormalizedNode.getValue(); - - settableFuture.set(value); - } - }, TypedActor.context().dispatcher()); - } - - final ListenableFuture aggregatedFuture = aggregator.combineUpdateAttempts(futures); - Futures.addCallback(aggregatedFuture, new FutureCallback() { - @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 future = manager.isMaster(); - future.onComplete(new OnComplete() { - @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 onRemoteNodeCreated(final NormalizedNodeMessage message) { - final Entry, DataObject> fromNormalizedNode = - codecRegistry.fromNormalizedNode(message.getIdentifier(), message.getNode()); - final InstanceIdentifier iid = (InstanceIdentifier) fromNormalizedNode.getKey(); - final Node value = (Node) fromNormalizedNode.getValue(); - - LOG.debug("TopologyManager({}) onRemoteNodeCreated received, nodeid: {}", value.getNodeId(), value); - final ListenableFuture nodeListenableFuture = onNodeCreated(value.getNodeId(), value); - final DefaultPromise promise = new DefaultPromise<>(); - Futures.addCallback(nodeListenableFuture, new FutureCallback() { - @Override - public void onSuccess(Node result) { - final Entry> 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 onRemoteNodeUpdated(final NormalizedNodeMessage message) { - final Entry, DataObject> fromNormalizedNode = - codecRegistry.fromNormalizedNode(message.getIdentifier(), message.getNode()); - final InstanceIdentifier iid = (InstanceIdentifier) fromNormalizedNode.getKey(); - final Node value = (Node) fromNormalizedNode.getValue(); - - LOG.debug("TopologyManager({}) onRemoteNodeUpdated received, nodeid: {}", id, value.getNodeId()); - - final ListenableFuture nodeListenableFuture = onNodeUpdated(value.getNodeId(), value); - final DefaultPromise promise = new DefaultPromise<>(); - Futures.addCallback(nodeListenableFuture, new FutureCallback() { - @Override - public void onSuccess(Node result) { - final Entry> 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 onRemoteNodeDeleted(final NodeId nodeId) { - LOG.debug("TopologyManager({}) onRemoteNodeDeleted received, nodeid: {}", id, nodeId.getValue()); - - final ListenableFuture listenableFuture = onNodeDeleted(nodeId); - final DefaultPromise promise = new DefaultPromise<>(); - Futures.addCallback(listenableFuture, new FutureCallback() { - @Override - public void onSuccess(Void result) { - promise.success(null); - } - - @Override - public void onFailure(Throwable t) { - promise.failure(t); - } - }); - - return promise.future(); - } - - public Future remoteGetCurrentStatusForNode(final NodeId nodeId) { - LOG.debug("TopologyManager({}) remoteGetCurrentStatusForNode received, nodeid: {}", id, nodeId.getValue()); - - final ListenableFuture listenableFuture = getCurrentStatusForNode(nodeId); - final DefaultPromise promise = new DefaultPromise<>(); - Futures.addCallback(listenableFuture, new FutureCallback() { - @Override - public void onSuccess(Node result) { - final Entry> 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, ReadFailedException> read = rTx.read(LogicalDatastoreType.CONFIGURATION, topologyListPath); - - Futures.addCallback(read, new FutureCallback>() { - @Override - public void onSuccess(Optional result) { - if (result.isPresent() && result.get().getNode() != null) { - for (final Node node : result.get().getNode()) { - final Entry> 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"); - } - }); - - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/NodeRoleChangeStrategy.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/NodeRoleChangeStrategy.java deleted file mode 100644 index 4783404b54..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/NodeRoleChangeStrategy.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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())); - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/NodeWriter.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/NodeWriter.java deleted file mode 100644 index 0b0d7b82e6..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/NodeWriter.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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); - -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/NoopRoleChangeStrategy.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/NoopRoleChangeStrategy.java deleted file mode 100644 index ea6e5d5eeb..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/NoopRoleChangeStrategy.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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) { - - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/SalNodeWriter.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/SalNodeWriter.java deleted file mode 100644 index 4f0a53a43c..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/SalNodeWriter.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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 result = transaction.submit(); - - Futures.addCallback(result, new FutureCallback() { - @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); - } - }); - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/TopologyRoleChangeStrategy.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/TopologyRoleChangeStrategy.java deleted file mode 100644 index a7fc412135..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/TopologyRoleChangeStrategy.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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, 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 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> changes) { - for (DataTreeModification change : changes) { - final DataObjectModification 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())); - } - } - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/CustomIdentifyMessage.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/CustomIdentifyMessage.java deleted file mode 100644 index 721dcf6c4d..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/CustomIdentifyMessage.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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; - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/CustomIdentifyMessageReply.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/CustomIdentifyMessageReply.java deleted file mode 100644 index 62a5b4396d..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/CustomIdentifyMessageReply.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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); - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/NormalizedNodeMessage.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/NormalizedNodeMessage.java deleted file mode 100644 index 9d12735936..0000000000 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/NormalizedNodeMessage.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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(); - } -} diff --git a/netconf/netconf-artifacts/pom.xml b/netconf/netconf-artifacts/pom.xml index 4a8b22096a..7102db1cb2 100644 --- a/netconf/netconf-artifacts/pom.xml +++ b/netconf/netconf-artifacts/pom.xml @@ -34,11 +34,6 @@ aaa-authn-odl-plugin ${project.version} - - ${project.groupId} - abstract-topology - ${project.version} - ${project.groupId} netconf-config-dispatcher @@ -148,6 +143,13 @@ netconf-util ${project.version} + + ${project.groupId} + netconf-util + ${project.version} + config + cfg + ${project.groupId} netconf-mdsal-config @@ -243,13 +245,6 @@ config xml - - ${project.groupId} - netconf-topology-config - ${project.version} - clustered-config - xml - ${project.groupId} yanglib-config @@ -287,6 +282,11 @@ ${project.version} test-jar + + ${project.groupId} + netconf-topology-singleton + ${project.version} + ${project.groupId} diff --git a/netconf/netconf-ssh/pom.xml b/netconf/netconf-ssh/pom.xml index fe563f4883..0225bdbf6f 100644 --- a/netconf/netconf-ssh/pom.xml +++ b/netconf/netconf-ssh/pom.xml @@ -93,6 +93,10 @@ netconf-client test + + org.osgi + org.osgi.compendium + @@ -118,10 +122,10 @@ - - org.opendaylight.yangtools - yang-maven-plugin - + + org.opendaylight.yangtools + yang-maven-plugin + diff --git a/netconf/netconf-ssh/src/main/java/org/opendaylight/netconf/ssh/osgi/NetconfSSHActivator.java b/netconf/netconf-ssh/src/main/java/org/opendaylight/netconf/ssh/osgi/NetconfSSHActivator.java index 9cbfac1580..14cbae81e1 100644 --- a/netconf/netconf-ssh/src/main/java/org/opendaylight/netconf/ssh/osgi/NetconfSSHActivator.java +++ b/netconf/netconf-ssh/src/main/java/org/opendaylight/netconf/ssh/osgi/NetconfSSHActivator.java @@ -7,7 +7,6 @@ */ 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; @@ -21,7 +20,7 @@ import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider; 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; @@ -79,25 +78,17 @@ public class NetconfSSHActivator implements BundleActivator { } private SshProxyServer startSSHServer(final BundleContext bundleContext) throws IOException { - final Optional 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 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( @@ -110,5 +101,4 @@ public class NetconfSSHActivator implements BundleActivator { .createSshProxyServerConfiguration()); return sshProxyServer; } - } diff --git a/netconf/netconf-tcp/pom.xml b/netconf/netconf-tcp/pom.xml index f6c8c05f05..0e45504a58 100644 --- a/netconf/netconf-tcp/pom.xml +++ b/netconf/netconf-tcp/pom.xml @@ -60,6 +60,10 @@ mockito-configuration test + + org.osgi + org.osgi.compendium + diff --git a/netconf/netconf-tcp/src/main/java/org/opendaylight/netconf/tcp/osgi/NetconfTCPActivator.java b/netconf/netconf-tcp/src/main/java/org/opendaylight/netconf/tcp/osgi/NetconfTCPActivator.java index 1f4188d827..d972a32ba7 100644 --- a/netconf/netconf-tcp/src/main/java/org/opendaylight/netconf/tcp/osgi/NetconfTCPActivator.java +++ b/netconf/netconf-tcp/src/main/java/org/opendaylight/netconf/tcp/osgi/NetconfTCPActivator.java @@ -8,11 +8,11 @@ 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; @@ -27,13 +27,10 @@ public class NetconfTCPActivator implements BundleActivator { @Override public void start(BundleContext context) { - final Optional 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", diff --git a/netconf/netconf-topology-config/pom.xml b/netconf/netconf-topology-config/pom.xml index 65135c0f81..75113816f3 100644 --- a/netconf/netconf-topology-config/pom.xml +++ b/netconf/netconf-topology-config/pom.xml @@ -43,11 +43,6 @@ xml config - - ${project.build.directory}/classes/initial/02-clustered-netconf-topology.xml - xml - clustered-config - diff --git a/netconf/netconf-topology-config/src/main/resources/initial/02-clustered-netconf-topology.xml b/netconf/netconf-topology-config/src/main/resources/initial/02-clustered-netconf-topology.xml deleted file mode 100644 index ded67f5ae6..0000000000 --- a/netconf/netconf-topology-config/src/main/resources/initial/02-clustered-netconf-topology.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - prefix:clustered-netconf-topology-impl - clustered-netconf-topology - topology-netconf - - prefix:netty-event-executor - global-event-executor - - - prefix:binding-broker-osgi-registry - binding-osgi-broker - - - prefix:dom-broker-osgi-registry - dom-broker - - - prefix:netconf-client-dispatcher - global-netconf-dispatcher - - - prefix:threadpool - global-netconf-processing-executor - - - prefix:scheduled-threadpool - global-netconf-ssh-scheduled-executor - - - prefix:shared-schema-repository - default-shared-schema-repository - - - prefix:entity-ownership-service - entity-ownership-service - - - prefix:actor-system-provider-service - actor-system-provider - - - - - - - prefix:netconf-topology - - clustered-netconf-topology - /modules/module[type='clustered-netconf-topology-impl'][name='clustered-netconf-topology'] - - - - - - - urn:opendaylight:params:xml:ns:yang:controller:netconf:topology?module=netconf-topology&revision=2015-07-27 - urn:opendaylight:params:xml:ns:yang:controller:clustered:netconf:topology?module=clustered-netconf-topology&revision=2015-11-04 - - urn:opendaylight:params:xml:ns:yang:controller:config:legacy-entity-ownership-service-provider?module=opendaylight-legacy-entity-ownership-service-provider&revision=2016-02-26 - - urn:opendaylight:params:xml:ns:yang:controller:config:actor-system-provider:service?module=actor-system-provider-service&revision=2015-10-05 - - \ No newline at end of file diff --git a/netconf/abstract-topology/pom.xml b/netconf/netconf-topology-singleton/pom.xml similarity index 64% rename from netconf/abstract-topology/pom.xml rename to netconf/netconf-topology-singleton/pom.xml index bf17207321..e247fb5071 100644 --- a/netconf/abstract-topology/pom.xml +++ b/netconf/netconf-topology-singleton/pom.xml @@ -12,15 +12,16 @@ 4.0.0 - org.opendaylight.odlparent - bundle-parent - 1.8.0-SNAPSHOT + org.opendaylight.controller + config-parent + 0.6.0-SNAPSHOT org.opendaylight.netconf - abstract-topology + netconf-topology-singleton 1.2.0-SNAPSHOT + ${project.artifactId} bundle @@ -32,67 +33,55 @@ pom import + + org.opendaylight.controller + mdsal-artifacts + 1.5.0-SNAPSHOT + pom + import + - - - + + org.opendaylight.netconf + mdsal-netconf-notification + org.opendaylight.mdsal.model ietf-topology - org.opendaylight.controller - sal-common-api + com.typesafe.akka + akka-actor_2.11 - ${project.groupId} + org.opendaylight.netconf sal-netconf-connector - org.opendaylight.controller - sal-binding-api + com.typesafe.akka + akka-cluster_2.11 org.opendaylight.controller sal-clustering-commons - - org.scala-lang - scala-library - - - com.typesafe.akka - akka-actor_${scala.version} - - - com.typesafe.akka - akka-remote_${scala.version} - - - com.typesafe.akka - akka-cluster_${scala.version} - - - com.typesafe.akka - akka-osgi_${scala.version} - - - com.typesafe - config - org.mockito mockito-all test - com.jayway.awaitility - awaitility - 1.6.5 + com.typesafe.akka + akka-testkit_2.11 test + + org.opendaylight.controller + sal-distributed-datastore + - + + \ No newline at end of file diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/api/NetconfDOMTransaction.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/api/NetconfDOMTransaction.java new file mode 100644 index 0000000000..ec9c717440 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/api/NetconfDOMTransaction.java @@ -0,0 +1,70 @@ +/* + * 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> 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 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 submit(); +} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/tx/NetconfDeviceDataBrokerProxy.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/api/NetconfTopologySingletonService.java similarity index 50% rename from netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/tx/NetconfDeviceDataBrokerProxy.java rename to netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/api/NetconfTopologySingletonService.java index 23fe120be1..37095becdf 100644 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/tx/NetconfDeviceDataBrokerProxy.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/api/NetconfTopologySingletonService.java @@ -1,12 +1,15 @@ /* - * 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 { } diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/api/RemoteDeviceConnector.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/api/RemoteDeviceConnector.java new file mode 100644 index 0000000000..bb74b754b3 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/api/RemoteDeviceConnector.java @@ -0,0 +1,28 @@ +/* + * 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(); +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/api/RemoteOperationTxProcessor.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/api/RemoteOperationTxProcessor.java new file mode 100644 index 0000000000..9023847da3 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/api/RemoteOperationTxProcessor.java @@ -0,0 +1,75 @@ +/* + * 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); + +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/MasterSalFacade.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/MasterSalFacade.java new file mode 100644 index 0000000000..8e45cbc374 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/MasterSalFacade.java @@ -0,0 +1,177 @@ +/* + * 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 { + + 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() { + @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 sendInitialDataToActor() { + final List sourceIdentifiers = + remoteSchemaContext.getAllModuleIdentifiers().stream().map(mi -> + RevisionSourceIdentifier.create(mi.getName(), + (SimpleDateFormatUtil.DEFAULT_DATE_REV == mi.getRevision() ? Optional.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); + } + } + } + +} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/NetconfDeviceSlaveDataBroker.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfDOMDataBroker.java similarity index 68% rename from netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/NetconfDeviceSlaveDataBroker.java rename to netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfDOMDataBroker.java index 23d7e10ae8..4fadb08ee4 100644 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/NetconfDeviceSlaveDataBroker.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfDOMDataBroker.java @@ -6,7 +6,7 @@ * 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; @@ -23,18 +23,20 @@ import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; 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; @@ -42,21 +44,24 @@ public class NetconfDeviceSlaveDataBroker implements DOMDataBroker{ @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 registerDataChangeListener(LogicalDatastoreType store, YangInstanceIdentifier path, DOMDataChangeListener listener, DataChangeScope triggeringScope) { + public ListenerRegistration registerDataChangeListener( + LogicalDatastoreType store, YangInstanceIdentifier path, DOMDataChangeListener listener, + DataChangeScope triggeringScope) { throw new UnsupportedOperationException(id + ": Data change listeners not supported for netconf mount point"); } diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfNodeManager.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfNodeManager.java new file mode 100644 index 0000000000..7cc3d29b86 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfNodeManager.java @@ -0,0 +1,143 @@ +/* + * 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, NetconfTopologySingletonService, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeManager.class); + + private NetconfTopologySetup setup; + private ListenerRegistration 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> changes) { + for (final DataTreeModification change : changes) { + final DataObjectModification 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 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; + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyContext.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyContext.java new file mode 100644 index 0000000000..0f8255cdaa --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyContext.java @@ -0,0 +1,169 @@ +/* + * 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 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 future = Patterns.ask(masterActorRef, new RefreshSetupMasterActorData( + netconfTopologyDeviceSetup, remoteDeviceId), NetconfTopologyUtils.TIMEOUT); + + future.onComplete(new OnComplete() { + @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()); + } + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java new file mode 100644 index 0000000000..cfd9dd8113 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java @@ -0,0 +1,243 @@ +/* + * 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, NetconfTopologySingletonService, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyManager.class); + + private final Map, NetconfTopologyContext> contexts = new HashMap<>(); + private final Map, ClusterSingletonServiceRegistration> + clusterRegistrations = new HashMap<>(); + + private ListenerRegistration 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> changes) { + for (DataTreeModification change : changes) { + final DataObjectModification rootNode = change.getRootNode(); + final InstanceIdentifier 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 instanceIdentifier, Node node) { + final NetconfTopologyContext context = contexts.get(instanceIdentifier); + context.refresh(createSetup(instanceIdentifier, node)); + } + + private void startNetconfDeviceContext(final InstanceIdentifier 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 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 registerDataTreeChangeListener(String topologyId) { + final WriteTransaction wtx = dataBroker.newWriteOnlyTransaction(); + initTopology(wtx, LogicalDatastoreType.CONFIGURATION, topologyId); + initTopology(wtx, LogicalDatastoreType.OPERATIONAL, topologyId); + Futures.addCallback(wtx.submit(), new FutureCallback() { + @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 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 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(); + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/ProxyDOMRpcService.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/ProxyDOMRpcService.java new file mode 100644 index 0000000000..c1c843014b --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/ProxyDOMRpcService.java @@ -0,0 +1,37 @@ +/* + * 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 invokeRpc(@Nonnull final SchemaPath type, + @Nullable final NormalizedNode input) { + throw new UnsupportedOperationException("InvokeRpc: DOMRpc service not working in cluster."); + } + + @Nonnull + @Override + public ListenerRegistration registerRpcListener( + @Nonnull final T listener) { + throw new UnsupportedOperationException("RegisterRpcListener: DOMRpc service not working in cluster."); + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/ProxyYangTextSourceProvider.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/ProxyYangTextSourceProvider.java new file mode 100644 index 0000000000..27514c788b --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/ProxyYangTextSourceProvider.java @@ -0,0 +1,70 @@ +/* + * 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> getProvidedSources() { + // NOOP + return Futures.successful(Sets.newHashSet()); + } + + @Override + public Future getYangTextSchemaSource( + @Nonnull final SourceIdentifier sourceIdentifier) { + + final Future scalaFuture = Patterns.ask(masterRef, + new YangTextSchemaSourceRequest(sourceIdentifier), NetconfTopologyUtils.TIMEOUT); + + final Promise.DefaultPromise promise = new Promise.DefaultPromise<>(); + + scalaFuture.onComplete(new OnComplete() { + @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(); + + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java new file mode 100644 index 0000000000..0525789d15 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java @@ -0,0 +1,425 @@ +/* + * 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 SchemaResourcesDTO. The + * SchemaResourcesDTO is essentially a container that allows for the extraction of the + * SchemaRegistry and SchemaContextFactory which should be used for a particular + * Netconf mount. Access to schemaResourcesDTOs should be surrounded by appropriate + * synchronization locks. + */ + private static final Map 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 future = deviceCommunicator + .initializeRemoteConnection(netconfTopologyDeviceSetup.getNetconfClientDispatcher(), clientConfig); + + Futures.addCallback(future, new FutureCallback() { + @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 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> 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 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 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 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 getUserCapabilities(final NetconfNode node) { + if (node.getYangModuleCapabilities() == null) { + return Optional.empty(); + } + + final List 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 deviceCache = + createDeviceFilesystemCache(moduleSchemaCacheDirectory); + repository.registerSchemaSourceListener(deviceCache); + return new NetconfDevice.SchemaResourcesDTO(repository, repository, schemaContextFactory, + new NetconfStateSchemasResolverImpl()); + } + + /** + * Creates a FilesystemSchemaSourceCache for the custom schema cache directory. + * + * @param schemaCacheDirectory The custom cache directory relative to "cache" + * @return A FilesystemSchemaSourceCache for the custom schema cache directory + */ + private FilesystemSchemaSourceCache 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 getSchemaResourcesDTOs() { + return schemaResourcesDTOs; + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteOperationTxProcessorImpl.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteOperationTxProcessorImpl.java new file mode 100644 index 0000000000..f107966b24 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteOperationTxProcessorImpl.java @@ -0,0 +1,155 @@ +/* + * 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 submitFuture = writeTx.submit(); + Futures.addCallback(submitFuture, new FutureCallback() { + @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>, ReadFailedException> readFuture = + readTx.read(store, path); + + Futures.addCallback(readFuture, new FutureCallback>>() { + + @Override + public void onSuccess(final Optional> 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 readFuture = + readTx.exists(store, path); + Futures.addCallback(readFuture, new FutureCallback() { + @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(); + } + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/SlaveSalFacade.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/SlaveSalFacade.java new file mode 100644 index 0000000000..877436d6cc --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/SlaveSalFacade.java @@ -0,0 +1,79 @@ +/* + * 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); + } + + } + + +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/actors/NetconfNodeActor.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/actors/NetconfNodeActor.java new file mode 100644 index 0000000000..75c7e62e8a --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/actors/NetconfNodeActor.java @@ -0,0 +1,235 @@ +/* + * 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 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 = + schemaRepository.getSchemaSource(sourceIdentifier, YangTextSchemaSource.class); + + Futures.addCallback(yangTextSchemaSource, new FutureCallback() { + @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 remoteSchemaContext = + getSchemaContext(masterReference); + final DOMRpcService deviceRpc = getDOMRpcService(); + + Futures.addCallback(remoteSchemaContext, new FutureCallback() { + @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 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); + } + +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/tx/NetconfMasterDOMTransaction.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/tx/NetconfMasterDOMTransaction.java new file mode 100644 index 0000000000..33680f2dfc --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/tx/NetconfMasterDOMTransaction.java @@ -0,0 +1,172 @@ +/* + * 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> read(final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + LOG.trace("{}: Read[{}] {} via NETCONF: {}", id, readTx.getIdentifier(), store, path); + + final CheckedFuture>, ReadFailedException> readFuture = readTx.read(store, path); + + final DefaultPromise> promise = new DefaultPromise<>(); + Futures.addCallback(readFuture, new FutureCallback>>() { + @Override + public void onSuccess(final Optional> 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 exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) { + LOG.trace("{}: Exists[{}] {} via NETCONF: {}", id, readTx.getIdentifier(), store, path); + + final CheckedFuture existsFuture = readTx.exists(store, path); + + final DefaultPromise promise = new DefaultPromise<>(); + Futures.addCallback(existsFuture, new FutureCallback() { + @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 submit() { + LOG.trace("{}: Submit[{}} via NETCONF", id, writeTx.getIdentifier()); + + final CheckedFuture submitFuture = writeTx.submit(); + final DefaultPromise promise = new DefaultPromise<>(); + Futures.addCallback(submitFuture, new FutureCallback() { + @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(); + } + +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/tx/NetconfProxyDOMTransaction.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/tx/NetconfProxyDOMTransaction.java new file mode 100644 index 0000000000..9a23a71da5 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/tx/NetconfProxyDOMTransaction.java @@ -0,0 +1,190 @@ +/* + * 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> read(final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + + final Future readScalaFuture = + Patterns.ask(masterContextRef, new ReadRequest(store, path), NetconfTopologyUtils.TIMEOUT); + + LOG.trace("{}: Read {} via NETCONF: {}", id, store, path); + + final DefaultPromise> promise = new DefaultPromise<>(); + + readScalaFuture.onComplete(new OnComplete() { + @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 exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) { + final Future existsScalaFuture = + Patterns.ask(masterContextRef, new ExistsRequest(store, path), NetconfTopologyUtils.TIMEOUT); + + LOG.trace("{}: Exists {} via NETCONF: {}", id, store, path); + + final DefaultPromise promise = new DefaultPromise<>(); + existsScalaFuture.onComplete(new OnComplete() { + @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 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 submit() { + final Future submitScalaFuture = + Patterns.ask(masterContextRef, new SubmitRequest(), NetconfTopologyUtils.TIMEOUT); + + LOG.trace("{}: Submit {} via NETCONF", id); + + final DefaultPromise promise = new DefaultPromise<>(); + + submitScalaFuture.onComplete(new OnComplete() { + @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(); + } + +} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/tx/ProxyReadOnlyTransaction.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/tx/NetconfReadOnlyTransaction.java similarity index 64% rename from netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/tx/ProxyReadOnlyTransaction.java rename to netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/tx/NetconfReadOnlyTransaction.java index a093e1cc8d..9b386c0a47 100644 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/tx/ProxyReadOnlyTransaction.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/tx/NetconfReadOnlyTransaction.java @@ -1,12 +1,12 @@ /* - * 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; @@ -20,19 +20,25 @@ 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.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; @@ -44,10 +50,15 @@ public class ProxyReadOnlyTransaction implements DOMDataReadOnlyTransaction{ } @Override - public CheckedFuture>, ReadFailedException> read(final LogicalDatastoreType store, final YangInstanceIdentifier path) { + public CheckedFuture>, ReadFailedException> read(final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + + LOG.trace("{}: Read {} via NETCONF: {}", id, store, path); + final Future> future = delegate.read(store, path); final SettableFuture>> settableFuture = SettableFuture.create(); - final CheckedFuture>, ReadFailedException> checkedFuture = Futures.makeChecked(settableFuture, new Function() { + final CheckedFuture>, ReadFailedException> checkedFuture; + checkedFuture = Futures.makeChecked(settableFuture, new Function() { @Nullable @Override public ReadFailedException apply(Exception cause) { @@ -56,13 +67,16 @@ public class ProxyReadOnlyTransaction implements DOMDataReadOnlyTransaction{ }); future.onComplete(new OnComplete>() { @Override - public void onComplete(Throwable throwable, Optional normalizedNodeMessage) throws Throwable { + public void onComplete(final Throwable throwable, + final Optional normalizedNodeMessage) throws Throwable { if (throwable == null) { if (normalizedNodeMessage.isPresent()) { - settableFuture.set(normalizedNodeMessage.transform(new Function>() { + settableFuture.set(normalizedNodeMessage.transform(new Function>() { + @Nullable @Override - public NormalizedNode apply(NormalizedNodeMessage input) { + public NormalizedNode apply(final NormalizedNodeMessage input) { return input.getNode(); } })); @@ -78,10 +92,15 @@ public class ProxyReadOnlyTransaction implements DOMDataReadOnlyTransaction{ } @Override - public CheckedFuture exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) { + public CheckedFuture exists(final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + + LOG.trace("{}: Exists {} via NETCONF: {}", id, store, path); + final Future existsFuture = delegate.exists(store, path); final SettableFuture settableFuture = SettableFuture.create(); - final CheckedFuture checkedFuture = Futures.makeChecked(settableFuture, new Function() { + final CheckedFuture checkedFuture; + checkedFuture = Futures.makeChecked(settableFuture, new Function() { @Nullable @Override public ReadFailedException apply(Exception cause) { @@ -90,7 +109,7 @@ public class ProxyReadOnlyTransaction implements DOMDataReadOnlyTransaction{ }); existsFuture.onComplete(new OnComplete() { @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 { diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/tx/NetconfWriteOnlyTransaction.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/tx/NetconfWriteOnlyTransaction.java new file mode 100644 index 0000000000..f938748cbf --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/tx/NetconfWriteOnlyTransaction.java @@ -0,0 +1,132 @@ +/* + * 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 submit() { + LOG.trace("{}: Submit", id); + + final Future submit = delegate.submit(); + final SettableFuture settFuture = SettableFuture.create(); + final CheckedFuture checkedFuture; + checkedFuture = Futures.makeChecked(settFuture, new Function() { + @Nullable + @Override + public TransactionCommitFailedException apply(Exception input) { + return new TransactionCommitFailedException("Transaction commit failed", input); + } + }); + submit.onComplete(new OnComplete() { + @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> commit() { + LOG.trace("{}: Commit", id); + + final Future commit = delegate.submit(); + final SettableFuture> settFuture = SettableFuture.create(); + commit.onComplete(new OnComplete() { + @Override + public void onComplete(final Throwable throwable, final Void result) throws Throwable { + if (throwable == null) { + TransactionStatus status = TransactionStatus.SUBMITED; + RpcResult rpcResult = RpcResultBuilder.success(status).build(); + settFuture.set(rpcResult); + } else { + settFuture.setException(throwable); + } + } + }, actorSystem.dispatcher()); + return settFuture; + } + + @Override + public Object getIdentifier() { + return this; + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfConnectorDTO.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfConnectorDTO.java new file mode 100644 index 0000000000..06578783be --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfConnectorDTO.java @@ -0,0 +1,48 @@ +/* + * 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 facade; + + public NetconfConnectorDTO(final NetconfDeviceCommunicator communicator, + final RemoteDeviceHandler facade) { + this.communicator = communicator; + this.facade = facade; + } + + public NetconfDeviceCommunicator getCommunicator() { + return communicator; + } + + public RemoteDeviceHandler 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 diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java new file mode 100644 index 0000000000..d607f33d2b --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java @@ -0,0 +1,254 @@ +/* + * 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 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 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 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 getInstanceIdentifier() { + return instanceIdentifier; + } + + public NetconfTopologySetupBuilder setInstanceIdentifier(final InstanceIdentifier 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(); + } + } + + +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtils.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtils.java new file mode 100644 index 0000000000..5114faecd2 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtils.java @@ -0,0 +1,117 @@ +/* + * 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 CACHE_DIRECTORY + + 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 cache/schema + 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 FilesystemSchemaSourceCache, which stores cached files in cache/schema. + public static final FilesystemSchemaSourceCache DEFAULT_CACHE = + new FilesystemSchemaSourceCache<>(DEFAULT_SCHEMA_REPOSITORY, YangTextSchemaSource.class, + new File(QUALIFIED_DEFAULT_CACHE_DIRECTORY)); + + // The default factory for creating SchemaContext 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 createTopologyListPath(final String topologyId) { + final InstanceIdentifier networkTopology = InstanceIdentifier.create(NetworkTopology.class); + return networkTopology.child(Topology.class, new TopologyKey(new TopologyId(topologyId))); + } + + public static InstanceIdentifier createTopologyNodeListPath(final NodeKey key, final String topologyId) { + return createTopologyListPath(topologyId) + .child(Node.class, new NodeKey(new NodeId(key.getNodeId().getValue()))); + } + + public static InstanceIdentifier createTopologyNodePath(final String topologyId) { + return createTopologyListPath(topologyId).child(Node.class); + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/AskForMasterMountPoint.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/AskForMasterMountPoint.java new file mode 100644 index 0000000000..4d56e1f17b --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/AskForMasterMountPoint.java @@ -0,0 +1,19 @@ +/* + * 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; +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/CreateInitialMasterActorData.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/CreateInitialMasterActorData.java new file mode 100644 index 0000000000..bab9056742 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/CreateInitialMasterActorData.java @@ -0,0 +1,38 @@ +/* + * 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 allSourceIdentifiers; + + public CreateInitialMasterActorData(final DOMDataBroker deviceDataBroker, + final List allSourceIdentifiers) { + this.deviceDataBroker = deviceDataBroker; + this.allSourceIdentifiers = allSourceIdentifiers; + } + + public DOMDataBroker getDeviceDataBroker() { + return deviceDataBroker; + } + + public List getSourceIndentifiers() { + return allSourceIdentifiers; + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/MasterActorDataInitialized.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/MasterActorDataInitialized.java new file mode 100644 index 0000000000..fa5482b8fe --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/MasterActorDataInitialized.java @@ -0,0 +1,19 @@ +/* + * 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; +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/NormalizedNodeMessage.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/NormalizedNodeMessage.java new file mode 100644 index 0000000000..b4ede5bdbf --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/NormalizedNodeMessage.java @@ -0,0 +1,59 @@ +/* + * 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 APPLIER = (instance, path, node) -> { + instance.identifier = path; + instance.node = node; + }; +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/RefreshSetupMasterActorData.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/RefreshSetupMasterActorData.java new file mode 100644 index 0000000000..fbc43f7cf9 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/RefreshSetupMasterActorData.java @@ -0,0 +1,37 @@ +/* + * 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; + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/RegisterMountPoint.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/RegisterMountPoint.java new file mode 100644 index 0000000000..0023103a5c --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/RegisterMountPoint.java @@ -0,0 +1,31 @@ +/* + * 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 allSourceIdentifiers; + + public RegisterMountPoint(final List allSourceIdentifiers) { + this.allSourceIdentifiers = allSourceIdentifiers; + } + + public List getSourceIndentifiers() { + return allSourceIdentifiers; + } + +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/UnregisterSlaveMountPoint.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/UnregisterSlaveMountPoint.java new file mode 100644 index 0000000000..303f0b465a --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/UnregisterSlaveMountPoint.java @@ -0,0 +1,19 @@ +/* + * 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; +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/YangTextSchemaSourceRequest.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/YangTextSchemaSourceRequest.java new file mode 100644 index 0000000000..ffc3d1334b --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/YangTextSchemaSourceRequest.java @@ -0,0 +1,30 @@ +/* + * 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; + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/CancelRequest.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/CancelRequest.java new file mode 100644 index 0000000000..7a73fe2e90 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/CancelRequest.java @@ -0,0 +1,13 @@ +/* + * 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; +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/DeleteRequest.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/DeleteRequest.java new file mode 100644 index 0000000000..1548dc791a --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/DeleteRequest.java @@ -0,0 +1,32 @@ +/* + * 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; + } +} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/AnnounceMasterMountPoint.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/EmptyReadResponse.java similarity index 55% rename from netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/AnnounceMasterMountPoint.java rename to netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/EmptyReadResponse.java index 6624a28d61..6e1e1bdc9f 100644 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/AnnounceMasterMountPoint.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/EmptyReadResponse.java @@ -1,17 +1,18 @@ /* - * 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() {} } diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/ExistsRequest.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/ExistsRequest.java new file mode 100644 index 0000000000..b5fae5f029 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/ExistsRequest.java @@ -0,0 +1,32 @@ +/* + * 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; + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/MergeRequest.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/MergeRequest.java new file mode 100644 index 0000000000..8c03023654 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/MergeRequest.java @@ -0,0 +1,32 @@ +/* + * 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; + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/PutRequest.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/PutRequest.java new file mode 100644 index 0000000000..41de9c22b7 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/PutRequest.java @@ -0,0 +1,32 @@ +/* + * 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; + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/ReadRequest.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/ReadRequest.java new file mode 100644 index 0000000000..d950f28557 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/ReadRequest.java @@ -0,0 +1,32 @@ +/* + * 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; + } +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/SubmitFailedReply.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/SubmitFailedReply.java new file mode 100644 index 0000000000..fe077e2fb5 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/SubmitFailedReply.java @@ -0,0 +1,18 @@ +/* + * 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; +} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/AnnounceMasterMountPointDown.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/SubmitReply.java similarity index 53% rename from netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/AnnounceMasterMountPointDown.java rename to netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/SubmitReply.java index a7c3f8714e..5ca306c6cd 100644 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/messages/AnnounceMasterMountPointDown.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/SubmitReply.java @@ -1,19 +1,18 @@ /* - * 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() { - - } } diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/SubmitRequest.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/SubmitRequest.java new file mode 100644 index 0000000000..6b6af7e773 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/SubmitRequest.java @@ -0,0 +1,13 @@ +/* + * 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; +} diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/TransactionRequest.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/TransactionRequest.java new file mode 100644 index 0000000000..b5ef9f1863 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/messages/transactions/TransactionRequest.java @@ -0,0 +1,19 @@ +/* + * 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 { +} diff --git a/netconf/netconf-topology-singleton/src/main/resources/org/opendaylight/blueprint/netconf-topology-singleton.xml b/netconf/netconf-topology-singleton/src/main/resources/org/opendaylight/blueprint/netconf-topology-singleton.xml new file mode 100644 index 0000000000..8fced1956e --- /dev/null +++ b/netconf/netconf-topology-singleton/src/main/resources/org/opendaylight/blueprint/netconf-topology-singleton.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfNodeActorTest.java b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfNodeActorTest.java new file mode 100644 index 0000000000..a77104e28d --- /dev/null +++ b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfNodeActorTest.java @@ -0,0 +1,221 @@ +/* + * 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 sourceIdentifiers = Lists.newArrayList(); + + /* Test init master data */ + + final Future 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 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 sourceIdentifiers = + Lists.newArrayList(SourceIdentifier.create("testID", Optional.absent())); + + // init master data + + final Future 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 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 result = + Futures.immediateCheckedFuture(yangTextSchemaSource); + + doReturn(result).when(schemaRepository).getSchemaSource(sourceIdentifier, YangTextSchemaSource.class); + + final Future 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 resultFail = + Futures.immediateFailedCheckedFuture(schemaSourceException); + + doReturn(resultFail).when(schemaRepository).getSchemaSource(sourceIdentifier, YangTextSchemaSource.class); + + final Future 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() : ""; + } + +} diff --git a/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java new file mode 100644 index 0000000000..9a3749c14e --- /dev/null +++ b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java @@ -0,0 +1,271 @@ +/* + * 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, NetconfTopologyContext> contexts = + (Map, NetconfTopologyContext>) fieldContexts.get(netconfTopologyManager); + + final Field fieldClusterRegistrations = NetconfTopologyManager.class.getDeclaredField("clusterRegistrations"); + fieldClusterRegistrations.setAccessible(true); + @SuppressWarnings("unchecked") + final Map, ClusterSingletonServiceRegistration> clusterRegistrations = + (Map, ClusterSingletonServiceRegistration>) + fieldClusterRegistrations.get(netconfTopologyManager); + + final Collection> changes = new ArrayList<>(); + + final InstanceIdentifier instanceIdentifier = NetconfTopologyUtils.createTopologyNodeListPath( + new NodeKey(new NodeId("node-id-1")),"topology-1"); + + final InstanceIdentifier instanceIdentifierDiferent = NetconfTopologyUtils.createTopologyNodeListPath( + new NodeKey(new NodeId("node-id-2")),"topology-2"); + + final DataTreeIdentifier rootIdentifier = + new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, instanceIdentifier); + + final DataTreeIdentifier rootIdentifierDifferent = + new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, instanceIdentifierDiferent); + + @SuppressWarnings("unchecked") + final DataObjectModification 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 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, NetconfTopologyContext> contexts = + (Map, NetconfTopologyContext>) fieldContexts.get(netconfTopologyManager); + + final Field fieldClusterRegistrations = NetconfTopologyManager.class.getDeclaredField("clusterRegistrations"); + fieldClusterRegistrations.setAccessible(true); + @SuppressWarnings("unchecked") + final Map, ClusterSingletonServiceRegistration> clusterRegistrations = + (Map, ClusterSingletonServiceRegistration>) + fieldClusterRegistrations.get(netconfTopologyManager); + + final InstanceIdentifier 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 { + + private final DataTreeIdentifier rootPath; + private final DataObjectModification rootNode; + + CustomTreeModification(DataTreeIdentifier rootPath, DataObjectModification rootNode) { + this.rootPath = rootPath; + this.rootNode = rootNode; + } + + @Nonnull + @Override + public DataTreeIdentifier getRootPath() { + return rootPath; + } + + @Nonnull + @Override + public DataObjectModification getRootNode() { + return rootNode; + } + } +} diff --git a/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImplTest.java b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImplTest.java new file mode 100644 index 0000000000..c1515abffb --- /dev/null +++ b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImplTest.java @@ -0,0 +1,271 @@ +/* + * 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")); + } + +} diff --git a/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/TestingRemoteDeviceConnectorImpl.java b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/TestingRemoteDeviceConnectorImpl.java new file mode 100644 index 0000000000..d4b4ec0492 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/TestingRemoteDeviceConnectorImpl.java @@ -0,0 +1,47 @@ +/* + * 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; + } + +} diff --git a/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/tx/ReadOnlyTransactionTest.java b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/tx/ReadOnlyTransactionTest.java new file mode 100644 index 0000000000..c491ee6fe4 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/tx/ReadOnlyTransactionTest.java @@ -0,0 +1,262 @@ +/* + * 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 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>, ReadFailedException> resultEmpty = + Futures.immediateCheckedFuture(Optional.absent()); + + doReturn(resultEmpty).when(readTx).read(storeType, instanceIdentifier); + + final CheckedFuture>, ReadFailedException> resultEmptyResponse = + slaveDataBroker.newReadOnlyTransaction().read(storeType, + instanceIdentifier); + + final Optional> 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>, ReadFailedException> resultNormalizedNodeMessage = + Futures.immediateCheckedFuture(Optional.of(outputNode)); + + doReturn(resultNormalizedNodeMessage).when(readTx).read(storeType, instanceIdentifier); + + final CheckedFuture>, ReadFailedException> resultNodeMessageResponse = + slaveDataBroker.newReadOnlyTransaction().read(storeType, instanceIdentifier); + + final Optional> 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>, ReadFailedException> resultThrowable = + Futures.immediateFailedCheckedFuture(readFailedException); + + doReturn(resultThrowable).when(readTx).read(storeType, instanceIdentifier); + + final CheckedFuture>, 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 resultTrue = + Futures.immediateCheckedFuture(true); + + doReturn(resultTrue).when(readTx).exists(storeType, instanceIdentifier); + + final CheckedFuture trueResponse = + slaveDataBroker.newReadOnlyTransaction().exists(storeType, instanceIdentifier); + + final Boolean trueMessage = trueResponse.checkedGet(TIMEOUT_SEC, TimeUnit.SECONDS); + + assertEquals(true, trueMessage); + + // Message: False + + final CheckedFuture resultFalse = Futures.immediateCheckedFuture(false); + + doReturn(resultFalse).when(readTx).exists(storeType, instanceIdentifier); + + final CheckedFuture falseResponse = + slaveDataBroker.newReadOnlyTransaction().exists(storeType, + instanceIdentifier); + + final Boolean falseMessage = falseResponse.checkedGet(TIMEOUT_SEC, TimeUnit.SECONDS); + + assertEquals(false, falseMessage); + + // Message: False, result null + + final CheckedFuture resultNull = Futures.immediateCheckedFuture(null); + + doReturn(resultNull).when(readTx).exists(storeType, instanceIdentifier); + + final CheckedFuture 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 resultThrowable = + Futures.immediateFailedCheckedFuture(readFailedException); + + doReturn(resultThrowable).when(readTx).exists(storeType, instanceIdentifier); + + final CheckedFuture resultThrowableResponse = + slaveDataBroker.newReadOnlyTransaction().exists(storeType, instanceIdentifier); + + exception.expect(ReadFailedException.class); + resultThrowableResponse.checkedGet(TIMEOUT_SEC, TimeUnit.SECONDS); + + } + + private void initializeDataTest() throws Exception { + final Future initialDataToActor = + Patterns.ask(masterRef, new CreateInitialMasterActorData(masterDataBroker, sourceIdentifiers), + TIMEOUT); + + final Object success = Await.result(initialDataToActor, TIMEOUT.duration()); + + assertTrue(success instanceof MasterActorDataInitialized); + } +} diff --git a/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/tx/WriteOnlyTransactionTest.java b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/tx/WriteOnlyTransactionTest.java new file mode 100644 index 0000000000..c9fa38f4bd --- /dev/null +++ b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/tx/WriteOnlyTransactionTest.java @@ -0,0 +1,258 @@ +/* + * 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 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 resultSubmit = Futures.immediateCheckedFuture(null); + doReturn(resultSubmit).when(writeTx).submit(); + + final CheckedFuture 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 resultSubmitTx = Futures.immediateCheckedFuture(null); + doReturn(resultSubmitTx).when(writeTx).submit(); + + final CheckedFuture 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 resultThrowable = + Futures.immediateFailedCheckedFuture(throwable); + + doReturn(resultThrowable).when(writeTx).submit(); + + final CheckedFuture 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 initialDataToActor = + Patterns.ask(masterRef, new CreateInitialMasterActorData(masterDataBroker, sourceIdentifiers), + TIMEOUT); + + final Object success = Await.result(initialDataToActor, TIMEOUT.duration()); + + assertTrue(success instanceof MasterActorDataInitialized); + } + +} diff --git a/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtilTest.java b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtilTest.java new file mode 100644 index 0000000000..9f8d153a87 --- /dev/null +++ b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologyUtilTest.java @@ -0,0 +1,59 @@ +/* + * 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 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()); + } + +} diff --git a/netconf/netconf-topology/pom.xml b/netconf/netconf-topology/pom.xml index b2488bd0ff..f0839ae945 100644 --- a/netconf/netconf-topology/pom.xml +++ b/netconf/netconf-topology/pom.xml @@ -60,32 +60,13 @@ org.opendaylight.netconf sal-netconf-connector - - org.opendaylight.controller - sal-clustering-commons - org.opendaylight.controller sal-common-api - - org.opendaylight.netconf - abstract-topology - - - com.typesafe - config - org.mockito mockito-all - 1.9.5 - test - - - com.jayway.awaitility - awaitility - 1.6.5 test diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/clustered/netconf/topology/ClusteredNetconfTopologyModule.java b/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/clustered/netconf/topology/ClusteredNetconfTopologyModule.java deleted file mode 100644 index 54be237e36..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/clustered/netconf/topology/ClusteredNetconfTopologyModule.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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()); - } - -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/clustered/netconf/topology/ClusteredNetconfTopologyModuleFactory.java b/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/clustered/netconf/topology/ClusteredNetconfTopologyModuleFactory.java deleted file mode 100644 index 0fb3a5bcc4..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/clustered/netconf/topology/ClusteredNetconfTopologyModuleFactory.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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 { - -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/AbstractNetconfTopology.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/AbstractNetconfTopology.java index e9193d0579..7174c53be5 100644 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/AbstractNetconfTopology.java +++ b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/AbstractNetconfTopology.java @@ -57,7 +57,6 @@ 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.pipeline.TopologyMountPointFacade.ConnectionStatusListenerRegistration; import org.opendaylight.protocol.framework.ReconnectStrategy; import org.opendaylight.protocol.framework.ReconnectStrategyFactory; import org.opendaylight.protocol.framework.TimedReconnectStrategy; @@ -204,16 +203,6 @@ public abstract class AbstractNetconfTopology implements NetconfTopology, Bindin @Override public abstract void onSessionInitiated(ProviderContext session); - @Override - public String getTopologyId() { - return topologyId; - } - - @Override - public DataBroker getDataBroker() { - return dataBroker; - } - @Override public ListenableFuture connectNode(NodeId nodeId, Node configNode) { LOG.info("Connecting RemoteDevice{{}} , with config {}", nodeId, configNode); @@ -449,9 +438,6 @@ public abstract class AbstractNetconfTopology implements NetconfTopology, Bindin protected abstract RemoteDeviceHandler createSalFacade(final RemoteDeviceId id, final Broker domBroker, final BindingAwareBroker bindingBroker); - @Override - public abstract ConnectionStatusListenerRegistration registerConnectionStatusListener(NodeId node, RemoteDeviceHandler listener); - @Override public void onSessionInitiated(ProviderSession session) { mountPointService = session.getService(DOMMountPointService.class); diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/NetconfTopology.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/NetconfTopology.java index 7c3b83617b..b275c7584d 100644 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/NetconfTopology.java +++ b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/NetconfTopology.java @@ -8,43 +8,15 @@ 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 connectNode(NodeId nodeId, Node configNode); ListenableFuture 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 listener); } diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/ClusteredNetconfTopology.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/ClusteredNetconfTopology.java deleted file mode 100644 index 38224553f0..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/ClusteredNetconfTopology.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * 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 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() { - @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 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 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 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 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)); - } - } -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfNodeManagerCallback.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfNodeManagerCallback.java deleted file mode 100644 index 6083281da9..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfNodeManagerCallback.java +++ /dev/null @@ -1,514 +0,0 @@ -/* - * 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, UnavailableCapability> UNAVAILABLE_CAPABILITY_TRANSFORMER = new Function, UnavailableCapability>() { - @Override - public UnavailableCapability apply(final Entry 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 topologyRefFuture = actorSystem.actorSelection(pathCreator.build()).resolveOne(FiniteDuration.create(10L, TimeUnit.SECONDS)); - topologyRefFuture.onComplete(new OnComplete() { - @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 nodeRefFuture = actorSystem.actorSelection(pathCreator.withSuffix(nodeId).build()).resolveOne(FiniteDuration.create(10L, TimeUnit.SECONDS)); - nodeRefFuture.onComplete(new OnComplete() { - @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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).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 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 connectionFuture = topologyDispatcher.connectNode(nodeId, configNode); - - Futures.addCallback(connectionFuture, new FutureCallback() { - @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() { - @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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).build()) - .build()).build(); - return currentOperationalNode; - } - }); - } - - @Nonnull - @Override - public ListenableFuture 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 connectionFuture = topologyDispatcher.connectNode(nodeId, configNode); - - Futures.addCallback(connectionFuture, new FutureCallback() { - @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() { - @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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).build()) - .build()) - .build(); - } - }); - } - - @Nonnull @Override public ListenableFuture 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 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 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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).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 diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfNodeOperationalDataAggregator.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfNodeOperationalDataAggregator.java deleted file mode 100644 index 4a739f9750..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfNodeOperationalDataAggregator.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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 combineCreateAttempts(final List> stateFutures) { - final SettableFuture future = SettableFuture.create(); - final ListenableFuture> allAsList = Futures.allAsList(stateFutures); - Futures.addCallback(allAsList, new FutureCallback>() { - @Override - public void onSuccess(final List result) { - Node base = null; - NetconfNode baseAugmentation = null; - AvailableCapabilities masterCaps = null; - UnavailableCapabilities unavailableMasterCaps = null; - final ArrayList 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 combineUpdateAttempts(final List> stateFutures) { - final SettableFuture future = SettableFuture.create(); - final ListenableFuture> allAsList = Futures.allAsList(stateFutures); - Futures.addCallback(allAsList, new FutureCallback>() { - @Override - public void onSuccess(final List result) { - Node base = null; - NetconfNode baseAugmentation = null; - AvailableCapabilities masterCaps = null; - UnavailableCapabilities unavailableMasterCaps = null; - final ArrayList 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 combineDeleteAttempts(final List> stateFutures) { - final SettableFuture future = SettableFuture.create(); - final ListenableFuture> allAsList = Futures.allAsList(stateFutures); - Futures.addCallback(allAsList, new FutureCallback>() { - @Override - public void onSuccess(final List 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; - } -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java index c1e41189e3..0553a5aa5b 100644 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java +++ b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java @@ -8,8 +8,6 @@ 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; @@ -34,11 +32,8 @@ import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalFacade; 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; @@ -84,26 +79,6 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology implements Data 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 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); diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyManagerCallback.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyManagerCallback.java deleted file mode 100644 index 3a9c8db732..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyManagerCallback.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * 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 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 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 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 onNodeDeleted(final NodeId nodeId) { - // Trigger delete only on this node - final ListenableFuture future = nodes.get(nodeId).onNodeDeleted(nodeId); - Futures.addCallback(future, new FutureCallback() { - @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 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); - } -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/TopologyNodeWriter.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/TopologyNodeWriter.java deleted file mode 100644 index 810679917c..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/TopologyNodeWriter.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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 networkTopologyPath; - private final KeyedInstanceIdentifier 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 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 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 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 result = transaction.submit(); - - Futures.addCallback(result, new FutureCallback() { - @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); - } -} diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/TopologyUtil.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/TopologyUtil.java similarity index 84% rename from netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/TopologyUtil.java rename to netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/TopologyUtil.java index d7c700d1a9..336589de40 100644 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/TopologyUtil.java +++ b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/TopologyUtil.java @@ -6,7 +6,7 @@ * 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; @@ -47,12 +47,4 @@ public final class TopologyUtil { final InstanceIdentifier networkTopology = InstanceIdentifier.create(NetworkTopology.class); return networkTopology.child(Topology.class, new TopologyKey(new TopologyId(topologyId))); } - - public static InstanceIdentifier createTopologyNodeListPath(final NodeKey key, final String topologyId) { - return createTopologyListPath(topologyId).child(Node.class, new NodeKey(new NodeId(key.getNodeId().getValue()))); - } - - public static InstanceIdentifier createTopologyNodePath(final String topologyId) { - return createTopologyListPath(topologyId).child(Node.class); - } } diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredDeviceSourcesResolver.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredDeviceSourcesResolver.java deleted file mode 100644 index 6e0c1d14ca..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredDeviceSourcesResolver.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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> getResolvedSources(); -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredDeviceSourcesResolverImpl.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredDeviceSourcesResolverImpl.java deleted file mode 100644 index 8ea8d3d0c3..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredDeviceSourcesResolverImpl.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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> sourceRegistrations; - - private final Promise> resolvedSourcesPromise; - private MasterSourceProvider remoteYangTextSourceProvider; - - public ClusteredDeviceSourcesResolverImpl(String topologyId, String nodeId, ActorSystem actorSystem, - SchemaSourceRegistry schemaRegistry, - List> 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> sourcesFuture = remoteYangTextSourceProvider.getProvidedSources(); - resolvedSourcesPromise.completeWith(sourcesFuture); - final RemoteSchemaProvider remoteProvider = new RemoteSchemaProvider(remoteYangTextSourceProvider, actorSystem.dispatcher()); - - sourcesFuture.onComplete(new OnComplete>() { - @Override - public void onComplete(Throwable throwable, Set 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> getResolvedSources() { - return resolvedSourcesPromise.future(); - } -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredNetconfDevice.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredNetconfDevice.java deleted file mode 100644 index 0542bf2406..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredNetconfDevice.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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 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 sourceIds = Sets.newHashSet(); - for(ModuleIdentifier id : result.getAllModuleIdentifiers()) { - sourceIds.add(SourceIdentifier.create(id.getName(), (SimpleDateFormatUtil.DEFAULT_DATE_REV == id.getRevision() ? Optional.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() { - @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() { - @Override - public ClusteredDeviceSourcesResolverImpl create() throws Exception { - return new ClusteredDeviceSourcesResolverImpl(topologyId, nodeId, actorSystem, schemaRegistry, sourceRegistrations); - } - }), NetconfTopologyPathCreator.CLUSTERED_DEVICE_SOURCES_RESOLVER); - - final FutureCallback schemaContextFuture = new FutureCallback() { - @Override - public void onSuccess(SchemaContext schemaContext) { - LOG.debug("{}: Schema context built successfully.", id); - - final NetconfDeviceCapabilities deviceCap = sessionPreferences.getNetconfDeviceCapabilities(); - final Set providedSourcesQnames = Sets.newHashSet(); - final Set 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>() { - @Override - public void onComplete(Throwable throwable, Set 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 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(); - } - } -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredNetconfDeviceCommunicator.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredNetconfDeviceCommunicator.java deleted file mode 100644 index 061024c1ca..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredNetconfDeviceCommunicator.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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 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); - } - } -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredNetconfDeviceMountInstanceProxy.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredNetconfDeviceMountInstanceProxy.java deleted file mode 100644 index 736751208b..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ClusteredNetconfDeviceMountInstanceProxy.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 getProviderFunctionality() { - return Collections.emptySet(); - } -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/MasterSourceProvider.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/MasterSourceProvider.java deleted file mode 100644 index f9726f4e55..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/MasterSourceProvider.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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 { -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/MasterSourceProviderImpl.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/MasterSourceProviderImpl.java deleted file mode 100644 index 618de81ea6..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/MasterSourceProviderImpl.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 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()); - } - } - } -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/MasterSourceProviderOnSameNodeException.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/MasterSourceProviderOnSameNodeException.java deleted file mode 100644 index 71f3005edd..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/MasterSourceProviderOnSameNodeException.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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 { -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/NetconfDeviceMasterDataBroker.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/NetconfDeviceMasterDataBroker.java deleted file mode 100644 index 17bb793b1f..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/NetconfDeviceMasterDataBroker.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * 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.self()); - } - - @Override - public DOMDataReadWriteTransaction newReadWriteTransaction() { - return new ReadWriteTx(new ProxyReadOnlyTransaction(actorSystem, id, TypedActor.self()), - newWriteOnlyTransaction()); - } - - @Override - public DOMDataWriteTransaction newWriteOnlyTransaction() { - writeTx = delegateBroker.newWriteOnlyTransaction(); - return new ProxyWriteOnlyTransaction(actorSystem, TypedActor.self()); - } - - @Override - public ListenerRegistration 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, DOMDataBrokerExtension> getSupportedExtensions() { - return Collections.emptyMap(); - } - - @Override - public Future> read(final LogicalDatastoreType store, final YangInstanceIdentifier path) { - final CheckedFuture>, ReadFailedException> readFuture = readTx.read(store, path); - - final DefaultPromise> promise = new DefaultPromise<>(); - Futures.addCallback(readFuture, new FutureCallback>>() { - @Override - public void onSuccess(Optional> result) { - if (!result.isPresent()) { - promise.success(Optional.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 exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) { - final CheckedFuture existsFuture = readTx.exists(store, path); - - final DefaultPromise promise = new DefaultPromise<>(); - Futures.addCallback(existsFuture, new FutureCallback() { - @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 submit() { - final CheckedFuture submitFuture = writeTx.submit(); - final DefaultPromise promise = new DefaultPromise<>(); - Futures.addCallback(submitFuture, new FutureCallback() { - @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> commit() { - final ListenableFuture> commitFuture = writeTx.commit(); - final DefaultPromise> promise = new DefaultPromise<>(); - Futures.addCallback(commitFuture, new FutureCallback>() { - @Override - public void onSuccess(RpcResult result) { - promise.success(result); - writeTx = null; - } - - @Override - public void onFailure(Throwable t) { - promise.failure(t); - writeTx = null; - } - }); - return promise.future(); - } - -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ProxyNetconfDeviceDataBroker.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ProxyNetconfDeviceDataBroker.java deleted file mode 100644 index 3ef76884f6..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/ProxyNetconfDeviceDataBroker.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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> read(LogicalDatastoreType store, YangInstanceIdentifier path); - - Future 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 submit(); - - @Deprecated - Future> commit(); -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/TopologyMountPointFacade.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/TopologyMountPointFacade.java deleted file mode 100644 index a44bf47a19..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/TopologyMountPointFacade.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * 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 { - - 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> 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 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 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 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() { - @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 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 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 listener; - - public ConnectionStatusListenerRegistration(final RemoteDeviceHandler listener) { - this.listener = listener; - } - - public void close() { - connectionStatusListeners.remove(listener); - } - } -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/messages/AnnounceClusteredDeviceSourcesResolverUp.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/messages/AnnounceClusteredDeviceSourcesResolverUp.java deleted file mode 100644 index f8328e7264..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/messages/AnnounceClusteredDeviceSourcesResolverUp.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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() {} -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/messages/AnnounceMasterOnSameNodeUp.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/messages/AnnounceMasterOnSameNodeUp.java deleted file mode 100644 index 793321c08e..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/messages/AnnounceMasterOnSameNodeUp.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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() { - - } -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/messages/AnnounceMasterSourceProviderUp.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/messages/AnnounceMasterSourceProviderUp.java deleted file mode 100644 index 7bec681f51..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/messages/AnnounceMasterSourceProviderUp.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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() { - - } -} diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/tx/ProxyWriteOnlyTransaction.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/tx/ProxyWriteOnlyTransaction.java deleted file mode 100644 index d7a3c87348..0000000000 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/pipeline/tx/ProxyWriteOnlyTransaction.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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 submit() { - final Future submit = delegate.submit(); - final SettableFuture settableFuture = SettableFuture.create(); - final CheckedFuture checkedFuture = Futures.makeChecked(settableFuture, new Function() { - @Nullable - @Override - public TransactionCommitFailedException apply(Exception input) { - return new TransactionCommitFailedException("Transaction commit failed", input); - } - }); - submit.onComplete(new OnComplete() { - @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> commit () { - final Future> commit = delegate.commit(); - final SettableFuture> settableFuture = SettableFuture.create(); - commit.onComplete(new OnComplete>() { - @Override - public void onComplete(Throwable throwable, RpcResult transactionStatusRpcResult) throws Throwable { - if (throwable == null) { - settableFuture.set(transactionStatusRpcResult); - } else { - settableFuture.setException(throwable); - } - } - }, actorSystem.dispatcher()); - return settableFuture; - } - - @Override - public Object getIdentifier () { - return this; - } -} diff --git a/netconf/netconf-topology/src/main/yang/clustered-netconf-topology.yang b/netconf/netconf-topology/src/main/yang/clustered-netconf-topology.yang deleted file mode 100644 index 6e72443fb3..0000000000 --- a/netconf/netconf-topology/src/main/yang/clustered-netconf-topology.yang +++ /dev/null @@ -1,127 +0,0 @@ -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 diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/AbstractNetconfTopologyTest.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/AbstractNetconfTopologyTest.java deleted file mode 100644 index a9d3e38081..0000000000 --- a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/AbstractNetconfTopologyTest.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * 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 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 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 getFacade() { - return salFacade; - } - - @Override - public void onSessionInitiated(BindingAwareBroker.ProviderContext session) { - - } - - @Override - protected RemoteDeviceHandler createSalFacade(RemoteDeviceId id, Broker domBroker, BindingAwareBroker bindingBroker) { - return salFacade; - } - - @Override - public TopologyMountPointFacade.ConnectionStatusListenerRegistration registerConnectionStatusListener(NodeId node, RemoteDeviceHandler 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) { - - } - } -} diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/ActorTest.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/ActorTest.java deleted file mode 100644 index 1e0ba1ab93..0000000000 --- a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/ActorTest.java +++ /dev/null @@ -1,720 +0,0 @@ -/* - * 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 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 PATHS_MASTER = Lists.newArrayList(PATH_SLAVE1, PATH_SLAVE2); - private static final List PATHS_SLAVE1 = Lists.newArrayList(PATH_MASTER, PATH_SLAVE2); - private static final List 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> settableFuture = SettableFuture.create(); - final CheckedFuture, ReadFailedException> checkedFuture = Futures.makeChecked(settableFuture, new Function() { - @Nullable - @Override - public ReadFailedException apply(Exception input) { - return new ReadFailedException("Dummy future should never return this"); - } - }); - settableFuture.set(Optional.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() { - @Override - public Boolean call() throws Exception { - return master.hasAllPeersUp(); - } - }); - - final List> 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 nodeListenableFuture = master.onNodeCreated(new NodeId(nodeid), testingNode); - futures.add(nodeListenableFuture); - Futures.addCallback(nodeListenableFuture, new FutureCallback() { - @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 nodeListenableFuture = master.onNodeUpdated(new NodeId(nodeid), testingNode); - futures.add(nodeListenableFuture); - Futures.addCallback(nodeListenableFuture, new FutureCallback() { - @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> deleteFutures = new ArrayList<>(); - for (int i = 0; i <= 1; i++) { - final String nodeid = "testing-node" + i; - final ListenableFuture nodeListenableFuture = master.onNodeDeleted(new NodeId(nodeid)); - deleteFutures.add(nodeListenableFuture); - Futures.addCallback(nodeListenableFuture, new FutureCallback() { - @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() { - @Override - public Boolean call() throws Exception { - return master.hasAllPeersUp(); - } - }); - - final List> 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 nodeListenableFuture = master.onNodeCreated(new NodeId(nodeid), testingNode); - futures.add(nodeListenableFuture); - Futures.addCallback(nodeListenableFuture, new FutureCallback() { - @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() { - @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() { - @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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).build()) - .setClusteredConnectionStatus( - new ClusteredConnectionStatusBuilder() - .setNodeStatus( - Collections.singletonList( - new NodeStatusBuilder() - .setNode("testing-node") - .setStatus(Status.Failed) - .build())) - .build()) - .build()) - .build(); - } - - @Nonnull - @Override - public ListenableFuture 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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).build()) - .setClusteredConnectionStatus( - new ClusteredConnectionStatusBuilder() - .setNodeStatus( - Collections.singletonList( - new NodeStatusBuilder() - .setNode("testing-node") - .setStatus(Status.Connected) - .build())) - .build()) - .build()) - .build()); - } - - @Nonnull - @Override - public ListenableFuture 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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).build()) - .setClusteredConnectionStatus( - new ClusteredConnectionStatusBuilder() - .setNodeStatus( - Collections.singletonList( - new NodeStatusBuilder() - .setNode("testing-node") - .setStatus(Status.Connected) - .build())) - .build()) - .build()) - .build()); - } - - @Nonnull - @Override - public ListenableFuture onNodeDeleted(@Nonnull NodeId nodeId) { - LOG.debug("Deleting node {}", nodeId); - return Futures.immediateFuture(null); - } - - @Nonnull - @Override - public ListenableFuture 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 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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).build()) - .build()) - .build()); - } - - @Override - public ListenableFuture 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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).build()) - .build()) - .build()); - } - - @Override - public ListenableFuture onNodeDeleted(NodeId nodeId) { - LOG.debug("Delete called on node {}", nodeId.getValue()); - return Futures.immediateFuture(null); - } - - @Nonnull - @Override - public ListenableFuture 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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).build()) - .build()) - .build(); - } - } - - public class TestingSuccesfulStateAggregator implements StateAggregator { - - @Override - public ListenableFuture combineCreateAttempts(List> stateFutures) { - final SettableFuture future = SettableFuture.create(); - final ListenableFuture> allAsList = Futures.allAsList(stateFutures); - Futures.addCallback(allAsList, new FutureCallback>() { - @Override - public void onSuccess(List 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 combineUpdateAttempts(List> stateFutures) { - final SettableFuture future = SettableFuture.create(); - final ListenableFuture> allAsList = Futures.allAsList(stateFutures); - Futures.addCallback(allAsList, new FutureCallback>() { - @Override - public void onSuccess(List 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 combineDeleteAttempts(List> stateFutures) { - final SettableFuture future = SettableFuture.create(); - final ListenableFuture> allAsList = Futures.allAsList(stateFutures); - Futures.addCallback(allAsList, new FutureCallback>() { - @Override - public void onSuccess(List 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; - } - } -} diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/TestingEntityOwnershipService.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/TestingEntityOwnershipService.java deleted file mode 100644 index 4b0bc31864..0000000000 --- a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/TestingEntityOwnershipService.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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 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 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)); - } - } - - } - }); - } -} diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/TestingTopologyDispatcher.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/TestingTopologyDispatcher.java deleted file mode 100644 index 28a1f97122..0000000000 --- a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/TestingTopologyDispatcher.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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 connected = new HashSet<>(); - private final Map> 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 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 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 disconnectNode(final NodeId nodeId) { - Preconditions.checkState(connected.contains(nodeId), "Node is not connected yet"); - LOG.debug("Disconnecting node {}", nodeId.getValue()); - final SettableFuture 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 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; - } -} diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/NetconfNodeOperationalDataAggregatorTest.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/NetconfNodeOperationalDataAggregatorTest.java deleted file mode 100644 index fa5b5a4257..0000000000 --- a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/NetconfNodeOperationalDataAggregatorTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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> 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.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 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.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 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 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 deleteFuture = aggregator.combineDeleteAttempts(deleteStateFutures); - assertTrue(deleteFuture.isDone()); - - try { - deleteFuture.get(); - fail("Exception expected"); - } catch(Exception e) { - assertSame(e.getCause(), cause); - } - } -} diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java index 1db1c3a7e8..2a2f2f4125 100644 --- a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java +++ b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java @@ -16,7 +16,6 @@ import static org.mockito.Mockito.times; 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; @@ -42,11 +41,8 @@ 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.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; @@ -113,23 +109,6 @@ public class NetconfTopologyImplTest { 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 listener = mock(RemoteDeviceHandler.class); - topology.registerConnectionStatusListener(NODE_ID, listener); - } - @Test public void testOnSessionInitiated() { BindingAwareBroker.ProviderContext session = mock(BindingAwareBroker.ProviderContext.class); diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/TopologyNodeWriterTest.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/TopologyNodeWriterTest.java deleted file mode 100644 index 67ba5ebf0f..0000000000 --- a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/TopologyNodeWriterTest.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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 NETWORK_TOPOLOGY_IID = InstanceIdentifier.builder(NetworkTopology.class).build(); - private static final KeyedInstanceIdentifier TOPOLOGY_LIST_IID; - - private static final KeyedInstanceIdentifier 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()).build()) - .setUnavailableCapabilities(new UnavailableCapabilitiesBuilder().setUnavailableCapability(new ArrayList()).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(); - } -} diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/ClusteredNetconfDeviceCommunicatorTest.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/ClusteredNetconfDeviceCommunicatorTest.java deleted file mode 100644 index aa6b69da51..0000000000 --- a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/ClusteredNetconfDeviceCommunicatorTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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 diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/NetconfDeviceSlaveDataBrokerTest.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/NetconfDeviceSlaveDataBrokerTest.java deleted file mode 100644 index 417978d6c1..0000000000 --- a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/NetconfDeviceSlaveDataBrokerTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/TopologyMountPointFacadeTest.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/TopologyMountPointFacadeTest.java deleted file mode 100644 index 68342a56e5..0000000000 --- a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/TopologyMountPointFacadeTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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 connectionStatusListener1; - - @Mock - RemoteDeviceHandler 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.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); - } - -} diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/tx/ProxyReadOnlyTransactionTest.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/tx/ProxyReadOnlyTransactionTest.java deleted file mode 100644 index afde0a0537..0000000000 --- a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/tx/ProxyReadOnlyTransactionTest.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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>, 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.>failed(new ReadFailedException("Test read failed!"))); - CheckedFuture>, 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>, 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.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 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 diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/tx/ProxyWriteOnlyTransactionTest.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/tx/ProxyWriteOnlyTransactionTest.java deleted file mode 100644 index 83c118fa8d..0000000000 --- a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/pipeline/tx/ProxyWriteOnlyTransactionTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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 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.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.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 rpcResult = mock(RpcResult.class); - when(mockedDelegate.commit()).thenReturn(Futures.successful(rpcResult)); - ListenableFuture> submitFuture = tx.commit(); - verify(mockedDelegate).commit(); - assertTrue(submitFuture.isDone()); - assertEquals(submitFuture.get(), rpcResult); - } - - @Test - public void testFailedCommit() { - when(mockedDelegate.commit()).thenReturn(Futures.>failed(new TransactionCommitFailedException("faile"))); - ListenableFuture> 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 diff --git a/netconf/netconf-topology/src/test/resources/netconf-node1.conf b/netconf/netconf-topology/src/test/resources/netconf-node1.conf deleted file mode 100644 index ed0aac11ed..0000000000 --- a/netconf/netconf-topology/src/test/resources/netconf-node1.conf +++ /dev/null @@ -1,14 +0,0 @@ -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 - } -} diff --git a/netconf/netconf-topology/src/test/resources/netconf-node2.conf b/netconf/netconf-topology/src/test/resources/netconf-node2.conf deleted file mode 100644 index 6090891d35..0000000000 --- a/netconf/netconf-topology/src/test/resources/netconf-node2.conf +++ /dev/null @@ -1,14 +0,0 @@ -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 - } -} diff --git a/netconf/netconf-topology/src/test/resources/netconf-node3.conf b/netconf/netconf-topology/src/test/resources/netconf-node3.conf deleted file mode 100644 index 620ede330b..0000000000 --- a/netconf/netconf-topology/src/test/resources/netconf-node3.conf +++ /dev/null @@ -1,14 +0,0 @@ -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 - } -} diff --git a/netconf/netconf-topology/src/test/resources/test.conf b/netconf/netconf-topology/src/test/resources/test.conf deleted file mode 100644 index b8c72947b5..0000000000 --- a/netconf/netconf-topology/src/test/resources/test.conf +++ /dev/null @@ -1,22 +0,0 @@ -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" - } - } -} diff --git a/netconf/netconf-util/pom.xml b/netconf/netconf-util/pom.xml index 56108b9d0d..110872bf88 100644 --- a/netconf/netconf-util/pom.xml +++ b/netconf/netconf-util/pom.xml @@ -88,10 +88,45 @@ org.opendaylight.yangtools yang-data-api + + org.osgi + org.osgi.compendium + + + org.apache.felix + maven-bundle-plugin + + + org.opendaylight.netconf.util.osgi.NetconfConfigurationActivator + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + + attach-artifact + + package + + + + ${project.build.directory}/classes/netconf.cfg + cfg + config + + + + + + org.apache.maven.plugins maven-jar-plugin diff --git a/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/osgi/NetconfConfigUtil.java b/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/osgi/NetconfConfigUtil.java index 9a6ff2e054..9d4b5a1238 100644 --- a/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/osgi/NetconfConfigUtil.java +++ b/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/osgi/NetconfConfigUtil.java @@ -11,8 +11,12 @@ package org.opendaylight.netconf.util.osgi; 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; @@ -109,4 +113,21 @@ public final class NetconfConfigUtil { } return Optional.fromNullable(value); } + + public static java.util.Optional getNetconfConfigurationService(BundleContext bundleContext) { + final Collection> serviceReferences; + try { + serviceReferences = bundleContext.getServiceReferences(ManagedService.class, null); + for (final ServiceReference 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(); + } } diff --git a/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/osgi/NetconfConfiguration.java b/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/osgi/NetconfConfiguration.java new file mode 100644 index 0000000000..e33f7e2e71 --- /dev/null +++ b/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/osgi/NetconfConfiguration.java @@ -0,0 +1,66 @@ +/* + * 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 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 diff --git a/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/osgi/NetconfConfigurationActivator.java b/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/osgi/NetconfConfigurationActivator.java new file mode 100644 index 0000000000..a752322d50 --- /dev/null +++ b/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/osgi/NetconfConfigurationActivator.java @@ -0,0 +1,41 @@ +/* + * 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 getNetconfConfigProperties(){ + Hashtable properties = new Hashtable<>(); + properties.put(Constants.SERVICE_PID, CONFIG_PID); + return properties; + } +} diff --git a/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/osgi/NetconfConfigurationHolder.java b/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/osgi/NetconfConfigurationHolder.java new file mode 100644 index 0000000000..74b3a089fa --- /dev/null +++ b/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/osgi/NetconfConfigurationHolder.java @@ -0,0 +1,37 @@ +/* + * 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; + } + +} diff --git a/netconf/netconf-util/src/main/resources/netconf.cfg b/netconf/netconf-util/src/main/resources/netconf.cfg new file mode 100644 index 0000000000..01437d891a --- /dev/null +++ b/netconf/netconf-util/src/main/resources/netconf.cfg @@ -0,0 +1,11 @@ +# 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 diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/copy-config.xml b/netconf/netconf-util/src/test/resources/netconfMessages/copy-config.xml new file mode 100644 index 0000000000..ec32fc1253 --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/copy-config.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/edit-config-test-module-running.xml b/netconf/netconf-util/src/test/resources/netconfMessages/edit-config-test-module-running.xml new file mode 100644 index 0000000000..107121d890 --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/edit-config-test-module-running.xml @@ -0,0 +1,22 @@ + + + + + + + + merge + rollback-on-error + + + leaf-value + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/edit-config-test-module.xml b/netconf/netconf-util/src/test/resources/netconfMessages/edit-config-test-module.xml new file mode 100644 index 0000000000..81907d3a15 --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/edit-config-test-module.xml @@ -0,0 +1,21 @@ + + + + + + + + rollback-on-error + + + leaf-value + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/getConfig_candidate-filter.xml b/netconf/netconf-util/src/test/resources/netconfMessages/getConfig_candidate-filter.xml new file mode 100644 index 0000000000..7ebbe15526 --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/getConfig_candidate-filter.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/lock-running.xml b/netconf/netconf-util/src/test/resources/netconfMessages/lock-running.xml new file mode 100644 index 0000000000..9c202ecc4e --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/lock-running.xml @@ -0,0 +1,16 @@ + + + + + + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/rpc-reply_get.xml b/netconf/netconf-util/src/test/resources/netconfMessages/rpc-reply_get.xml new file mode 100644 index 0000000000..b3209d740f --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/rpc-reply_get.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/unlock-running.xml b/netconf/netconf-util/src/test/resources/netconfMessages/unlock-running.xml new file mode 100644 index 0000000000..a74377a151 --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/unlock-running.xml @@ -0,0 +1,16 @@ + + + + + + + + + \ No newline at end of file diff --git a/netconf/netconf-util/src/test/resources/netconfMessages/validate-running.xml b/netconf/netconf-util/src/test/resources/netconfMessages/validate-running.xml new file mode 100644 index 0000000000..783192df22 --- /dev/null +++ b/netconf/netconf-util/src/test/resources/netconfMessages/validate-running.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/netconf/pom.xml b/netconf/pom.xml index d3e2f76f2e..925488cc63 100644 --- a/netconf/pom.xml +++ b/netconf/pom.xml @@ -47,7 +47,7 @@ netconf-notifications-impl netconf-notifications-api netconf-topology - abstract-topology + netconf-topology-singleton netconf-topology-config sal-netconf-connector messagebus-netconf diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/NetconfDevice.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/NetconfDevice.java index d11c2a82c1..04953133a3 100644 --- a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/NetconfDevice.java +++ b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/NetconfDevice.java @@ -113,7 +113,7 @@ public class NetconfDevice implements RemoteDevice salFacade, + public NetconfDevice(final SchemaResourcesDTO schemaResourcesDTO, final RemoteDeviceId id, final RemoteDeviceHandler salFacade, final ExecutorService globalProcessingExecutor, final boolean reconnectOnSchemasChange) { this.id = id; this.reconnectOnSchemasChange = reconnectOnSchemasChange; @@ -205,7 +205,7 @@ public class NetconfDevice implements RemoteDevice listener) { + void handleSalInitializationFailure(final Throwable t, final RemoteDeviceCommunicator listener) { LOG.error("{}: Initialization in sal failed, disconnecting from device", id, t); listener.close(); onRemoteSessionDown(); diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceTopologyAdapter.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceTopologyAdapter.java index 7073da98a0..b0617cfca9 100644 --- a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceTopologyAdapter.java +++ b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceTopologyAdapter.java @@ -18,6 +18,7 @@ import java.util.ArrayList; 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; @@ -29,6 +30,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev15 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; @@ -52,7 +54,7 @@ import org.opendaylight.yangtools.yang.common.QName; 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, UnavailableCapability> UNAVAILABLE_CAPABILITY_TRANSFORMER = new Function, UnavailableCapability>() { @@ -128,6 +130,21 @@ final class NetconfDeviceTopologyAdapter implements AutoCloseable { 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; @@ -167,6 +184,30 @@ final class NetconfDeviceTopologyAdapter implements AutoCloseable { return netconfNodeBuilder.build(); } + private NetconfNode buildDataForNetconfClusteredNode(boolean up, String masterNodeAddress, NetconfDeviceCapabilities capabilities) { + List 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(); diff --git a/netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang b/netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang index 07461d48d7..169d419616 100644 --- a/netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang +++ b/netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang @@ -153,6 +153,10 @@ module netconf-node-topology { } } } + leaf netconf-master-node { + config false; + type string; + } } leaf connected-message { diff --git a/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NetconfBaseOpsTest.java b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NetconfBaseOpsTest.java new file mode 100644 index 0000000000..6b47a72752 --- /dev/null +++ b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NetconfBaseOpsTest.java @@ -0,0 +1,330 @@ +/* + * 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 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 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> 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> 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 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 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 { + + 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 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 diff --git a/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NodeContainerProxyTest.java b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NodeContainerProxyTest.java new file mode 100644 index 0000000000..534a9520fc --- /dev/null +++ b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NodeContainerProxyTest.java @@ -0,0 +1,140 @@ +/* + * 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 childNodes = new HashMap<>(); + childNodes.put(NODE_1_QNAME, schemaNode1); + childNodes.put(NODE_2_QNAME, schemaNode2); + final Set 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 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 diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/rest/services/impl/ModuleImpl.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/rest/services/impl/ModuleImpl.java index b8033bbace..9857c4493f 100644 --- a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/rest/services/impl/ModuleImpl.java +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/rest/services/impl/ModuleImpl.java @@ -163,7 +163,7 @@ class ModuleImpl implements Module { @Override public Set getSubmodules() { - throw new UnsupportedOperationException("Not supported operations."); + return new HashSet<>(); } @Override