<artifactId>yang-data-impl</artifactId>
<version>0.5.9-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-broker-impl</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependencies>
<packaging>bundle</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Bundle-Activator>org.opendaylight.controller.sal.connect.netconf.NetconfProvider</Bundle-Activator>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf;
+
+import java.net.URI;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class InventoryUtils {
+
+ private static final URI INVENTORY_NAMESPACE = URI.create("urn:opendaylight:inventory");
+ private static final Date INVENTORY_REVISION = date();
+ public static final QName INVENTORY_NODES = new QName(INVENTORY_NAMESPACE, INVENTORY_REVISION, "nodes");
+ public static final QName INVENTORY_NODE = new QName(INVENTORY_NAMESPACE, INVENTORY_REVISION, "node");
+ public static final QName INVENTORY_ID = new QName(INVENTORY_NAMESPACE, INVENTORY_REVISION, "id");
+
+ public static final InstanceIdentifier INVENTORY_PATH = InstanceIdentifier.builder().node(INVENTORY_NODES)
+ .toInstance();
+ public static final QName NETCONF_INVENTORY_MOUNT = null;
+
+
+
+ private static Date date() {
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+ try {
+ return formatter.parse("2013-08-19");
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf
+
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.opendaylight.controller.md.sal.common.api.data.DataReader
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.controller.netconf.client.NetconfClient
+import org.opendaylight.controller.sal.core.api.RpcImplementation
+import static extension org.opendaylight.controller.sal.connect.netconf.NetconfMapping.*
+import java.net.InetSocketAddress
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.api.SimpleNode
+import org.opendaylight.yangtools.yang.common.QName
+import java.util.Collections
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher
+import org.opendaylight.yangtools.concepts.Registration
+
+class NetconfDevice implements DataReader<InstanceIdentifier, CompositeNode>, RpcImplementation {
+
+ var NetconfClient client;
+
+ @Property
+ var InetSocketAddress socketAddress;
+
+ @Property
+ val MountProvisionInstance mountInstance;
+
+ @Property
+ val InstanceIdentifier path;
+
+ Registration<DataReader<InstanceIdentifier,CompositeNode>> operReaderReg
+
+ Registration<DataReader<InstanceIdentifier,CompositeNode>> confReaderReg
+
+ public new(MountProvisionInstance mount,InstanceIdentifier path) {
+ _mountInstance = mount;
+ _path = path;
+ }
+
+ def start(NetconfClientDispatcher dispatcher) {
+ client = new NetconfClient("sal-netconf-connector", socketAddress, dispatcher);
+
+ confReaderReg = mountInstance.registerConfigurationReader(path,this);
+ operReaderReg = mountInstance.registerOperationalReader(path,this);
+ }
+
+ override readConfigurationData(InstanceIdentifier path) {
+ val result = invokeRpc(NETCONF_GET_CONFIG_QNAME, wrap(NETCONF_GET_CONFIG_QNAME, path.toFilterStructure()));
+ val data = result.result.getFirstCompositeByName(NETCONF_DATA_QNAME);
+ return data?.findNode(path) as CompositeNode;
+ }
+
+ override readOperationalData(InstanceIdentifier path) {
+ val result = invokeRpc(NETCONF_GET_QNAME, wrap(NETCONF_GET_QNAME, path.toFilterStructure()));
+ val data = result.result.getFirstCompositeByName(NETCONF_DATA_QNAME);
+ return data?.findNode(path) as CompositeNode;
+ }
+
+ override getSupportedRpcs() {
+ Collections.emptySet;
+ }
+
+ override invokeRpc(QName rpc, CompositeNode input) {
+ val message = rpc.toRpcMessage(input);
+ val result = client.sendMessage(message);
+ return result.toRpcResult();
+ }
+
+ def Node<?> findNode(CompositeNode node, InstanceIdentifier identifier) {
+
+ var Node<?> current = node;
+ for (arg : identifier.path) {
+ if (current instanceof SimpleNode<?>) {
+ return null;
+ } else if (current instanceof CompositeNode) {
+ val currentComposite = (current as CompositeNode);
+
+ current = currentComposite.getFirstCompositeByName(arg.nodeType);
+ if (current == null) {
+ current = currentComposite.getFirstSimpleByName(arg.nodeType);
+ }
+ if (current == null) {
+ return null;
+ }
+ }
+ }
+ return current;
+ }
+
+ public def stop() {
+ confReaderReg?.close()
+ operReaderReg?.close()
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf
+
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService
+import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService
+import org.opendaylight.controller.sal.core.api.data.DataProviderService
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.opendaylight.yangtools.yang.common.QName
+import static org.opendaylight.controller.sal.connect.netconf.InventoryUtils.*;
+import static extension org.opendaylight.controller.sal.connect.netconf.NetconfInventoryUtils.*;
+
+import org.opendaylight.controller.sal.core.api.data.DataChangeListener
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent
+import java.util.Map
+import java.util.concurrent.ConcurrentHashMap
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher
+import java.io.OptionalDataException
+import com.google.common.base.Optional
+import java.net.SocketAddress
+import java.net.InetSocketAddress
+
+class NetconfDeviceManager {
+
+ val Map<InstanceIdentifier, NetconfDevice> devices = new ConcurrentHashMap;
+
+ var ProviderSession session;
+
+ @Property
+ var DataProviderService dataService;
+
+ @Property
+ var MountProvisionService mountService;
+
+ val nodeUpdateListener = new NetconfInventoryListener(this);
+
+
+ @Property
+ var NetconfClientDispatcher dispatcher;
+
+ def void start() {
+ dataService?.registerDataChangeListener(INVENTORY_PATH, nodeUpdateListener);
+ if(dispatcher == null) {
+ dispatcher = new NetconfClientDispatcher(Optional.absent);
+ }
+ }
+
+ def netconfNodeAdded(InstanceIdentifier path, CompositeNode node) {
+ val address = node.endpointAddress;
+ val port = Integer.parseInt(node.endpointPort);
+ netconfNodeAdded(path,new InetSocketAddress(address,port))
+
+ }
+
+ def netconfNodeAdded(InstanceIdentifier path, InetSocketAddress address) {
+
+ val mountPointPath = path;
+ val mountPoint = mountService.createOrGetMountPoint(mountPointPath);
+ val localPath = InstanceIdentifier.builder().toInstance;
+ val netconfDevice = new NetconfDevice(mountPoint,localPath);
+ netconfDevice.setSocketAddress(address);
+ netconfDevice.start(dispatcher);
+ }
+
+ def netconfNodeRemoved(InstanceIdentifier path) {
+
+ }
+
+}
+
+class NetconfInventoryListener implements DataChangeListener {
+
+ val NetconfDeviceManager manager;
+
+ new(NetconfDeviceManager manager) {
+ this.manager = manager;
+ }
+
+ override onDataChanged(DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
+
+ //manager.netconfNodeAdded(path, change);
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+public class NetconfInventoryUtils {
+
+
+ public static final QName NETCONF_MOUNT = null;
+ public static final QName NETCONF_ENDPOINT = null;
+ public static final QName NETCONF_ENDPOINT_ADDRESS = null;
+ public static final QName NETCONF_ENDPOINT_PORT = null;
+
+
+ public static String getEndpointAddress(CompositeNode node) {
+ return node.getCompositesByName(NETCONF_ENDPOINT).get(0).getFirstSimpleByName(NETCONF_ENDPOINT_ADDRESS).getValue().toString();
+ }
+
+ public static String getEndpointPort(CompositeNode node) {
+ return node.getCompositesByName(NETCONF_ENDPOINT).get(0).getFirstSimpleByName(NETCONF_ENDPOINT_PORT).getValue().toString();
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf
+
+import org.opendaylight.controller.netconf.api.NetconfMessage
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.opendaylight.yangtools.yang.common.QName
+import org.opendaylight.yangtools.yang.common.RpcResult
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import java.net.URI
+import java.util.Collections
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.NodeUtils
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import java.util.concurrent.atomic.AtomicInteger
+import org.w3c.dom.Document
+import org.w3c.dom.Element
+import org.opendaylight.controller.sal.common.util.Rpcs
+
+class NetconfMapping {
+
+ public static val NETCONF_URI = URI.create("urn:ietf:params:xml:ns:netconf:base:1.0")
+ public static val NETCONF_QNAME = new QName(NETCONF_URI,null,"netconf");
+ public static val NETCONF_RPC_QNAME = new QName(NETCONF_QNAME,"rpc");
+ public static val NETCONF_GET_QNAME = new QName(NETCONF_QNAME,"get");
+ public static val NETCONF_GET_CONFIG_QNAME = new QName(NETCONF_QNAME,"get-config");
+ public static val NETCONF_RPC_REPLY_QNAME = new QName(NETCONF_QNAME,"rpc-reply");
+ public static val NETCONF_OK_QNAME = new QName(NETCONF_QNAME,"ok");
+ public static val NETCONF_DATA_QNAME = new QName(NETCONF_QNAME,"data");
+
+
+ static val messageId = new AtomicInteger(0);
+
+
+
+ static def Node<?> toFilterStructure(InstanceIdentifier identifier) {
+ var Node<?> previous = null;
+ for (component : identifier.path.reverse) {
+ val Node<?> current = component.toNode(previous);
+ previous = current;
+ }
+ return previous;
+ }
+
+ static def dispatch Node<?> toNode(NodeIdentifierWithPredicates argument, Node<?> node) {
+ val list = new ArrayList<Node<?>>();
+ for( arg : argument.keyValues.entrySet) {
+ list.add = new SimpleNodeTOImpl(arg.key,null,arg.value);
+ }
+ return new CompositeNodeTOImpl(argument.nodeType,null,list)
+ }
+
+ static def dispatch Node<?> toNode(PathArgument argument, Node<?> node) {
+ if(node != null) {
+ return new CompositeNodeTOImpl(argument.nodeType,null,Collections.singletonList(node));
+ } else {
+ return new SimpleNodeTOImpl(argument.nodeType,null,null);
+ }
+ }
+
+ static def CompositeNode toCompositeNode(NetconfMessage message) {
+ return message.toRpcResult().result;
+ }
+
+ static def NetconfMessage toRpcMessage(QName rpc, CompositeNode node) {
+ val rpcPayload = wrap(NETCONF_RPC_QNAME,node);
+ val w3cPayload = NodeUtils.buildShadowDomTree(rpcPayload);
+ w3cPayload.documentElement.setAttribute("message-id","m-"+ messageId.andIncrement);
+ return new NetconfMessage(w3cPayload);
+ }
+
+ static def RpcResult<CompositeNode> toRpcResult(NetconfMessage message) {
+ val rawRpc = message.document.toCompositeNode() as CompositeNode;
+ //rawRpc.
+
+ return Rpcs.getRpcResult(true,rawRpc,Collections.emptySet());
+ }
+
+
+ static def wrap(QName name,Node<?> node) {
+ if(node != null) {
+ return new CompositeNodeTOImpl(name,null,Collections.singletonList(node));
+ }
+ else {
+ return new CompositeNodeTOImpl(name,null,Collections.emptyList());
+ }
+ }
+
+
+ public static def Node<?> toCompositeNode(Document document) {
+ return XmlDocumentUtils.toCompositeNode(document) as Node<?>
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf;
+
+import java.util.Hashtable;
+
+import org.opendaylight.controller.sal.core.api.AbstractProvider;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.osgi.framework.BundleContext;
+
+public class NetconfProvider extends AbstractProvider {
+
+ private NetconfDeviceManager netconfDeviceManager;
+
+ @Override
+ protected void startImpl(BundleContext context) {
+ netconfDeviceManager = new NetconfDeviceManager();
+ context.registerService(NetconfDeviceManager.class, netconfDeviceManager, new Hashtable<String,String>());
+ }
+
+
+ @Override
+ public void onSessionInitiated(ProviderSession session) {
+ MountProvisionService mountService = session.getService(MountProvisionService.class);
+
+
+ netconfDeviceManager.setMountService(mountService);
+ netconfDeviceManager.start();
+ }
+
+ @Override
+ protected void stopImpl(BundleContext context) {
+
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connect.netconf;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class XmlDocumentUtils {
+
+ public static CompositeNode toCompositeNode(Document doc) {
+ return (CompositeNode) toCompositeNode(doc.getDocumentElement());
+ }
+
+ private static Node<?> toCompositeNode(Element element) {
+ String orgNamespace = element.getNamespaceURI();
+ URI biNamespace = null;
+ if (orgNamespace != null) {
+ biNamespace = URI.create(orgNamespace);
+ }
+ QName qname = new QName(biNamespace, element.getLocalName());
+
+ List<Node<?>> values = new ArrayList<>();
+ NodeList nodes = element.getChildNodes();
+ boolean isSimpleObject = false;
+ String value = null;
+ for (int i = 0; i < nodes.getLength(); i++) {
+ org.w3c.dom.Node child = nodes.item(i);
+ if (child instanceof Element) {
+ isSimpleObject = false;
+ values.add(toCompositeNode((Element) child));
+ }
+ if (!isSimpleObject && child instanceof org.w3c.dom.Text) {
+ value = element.getTextContent();
+ if (value.matches(".*\\w.*")) {
+ isSimpleObject = true;
+ break;
+ }
+ }
+ }
+
+ if (isSimpleObject) {
+ return new SimpleNodeTOImpl<>(qname, null, value);
+ }
+ return new CompositeNodeTOImpl(qname, null, values);
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.connector.netconf.test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+import io.netty.channel.ChannelFuture;
+import io.netty.util.HashedWheelTimer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLContext;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.controller.config.yang.store.api.YangStoreException;
+import org.opendaylight.controller.config.yang.store.impl.HardcodedYangStoreService;
+import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.NetconfClient;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
+import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
+import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
+import org.opendaylight.controller.netconf.impl.NetconfServerSessionListenerFactory;
+import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
+import org.opendaylight.controller.netconf.impl.SessionIdProvider;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
+import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.controller.sal.connect.netconf.InventoryUtils;
+import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
+import org.opendaylight.controller.sal.connect.netconf.NetconfDeviceManager;
+import org.opendaylight.controller.sal.connect.netconf.NetconfInventoryUtils;
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.opendaylight.controller.sal.dom.broker.DataBrokerImpl;
+import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+public class MountTest extends AbstractConfigTest {
+
+ private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
+ private static final InetSocketAddress tlsAddress = new InetSocketAddress("127.0.0.1", 12024);
+ private static final URI NETCONF_MONITORING_NS = URI.create("urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring");
+
+ private static final QName NETCONF_MONITORING = new QName(NETCONF_MONITORING_NS, new Date(2010,10,04), "ietf-netconf-monitoring");
+ private static final QName NETCONF_MONITORING_STATE = new QName(NETCONF_MONITORING,"netconf-state");
+
+
+ private NetconfMessage getConfig, getConfigCandidate, editConfig, closeSession;
+ private DefaultCommitNotificationProducer commitNot;
+ private NetconfServerDispatcher dispatch;
+ private DataProviderService dataBroker;
+ private MountPointManagerImpl mountManager;
+ private NetconfDeviceManager netconfManager;
+
+ private static QName CONFIG_MODULES = new QName(
+ URI.create("urn:opendaylight:params:xml:ns:yang:controller:config"), null, "modules");
+ private static QName CONFIG_SERVICES = new QName(
+ URI.create("urn:opendaylight:params:xml:ns:yang:controller:config"), null, "modules");
+
+ private NetconfClient createSession(final InetSocketAddress address, NetconfClientDispatcher dispatcher) throws InterruptedException {
+ final NetconfClient netconfClient = new NetconfClient("test " + address.toString(), address, 5000, dispatcher);
+ return netconfClient;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(getModuleFactories().toArray(
+ new ModuleFactory[0])));
+
+ loadMessages();
+
+ NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
+ factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
+
+ commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
+
+ dispatch = createDispatcher(Optional.<SSLContext> absent(), factoriesListener);
+ ChannelFuture s = dispatch.createServer(tcpAddress);
+ s.await();
+
+ dataBroker = new DataBrokerImpl();
+ mountManager = new MountPointManagerImpl();
+ mountManager.setDataBroker(dataBroker);
+ netconfManager = new NetconfDeviceManager();
+
+ netconfManager.setMountService(mountManager);
+ netconfManager.setDataService(dataBroker);
+ netconfManager.start();
+
+ try (NetconfClient netconfClient = createSession(tcpAddress, netconfManager.getDispatcher())) {
+ // send edit_config.xml
+ final Document rpcReply = netconfClient.sendMessage(this.editConfig).getDocument();
+ assertNotNull(rpcReply);
+ }
+ }
+
+
+ protected List<ModuleFactory> getModuleFactories() {
+ return getModuleFactoriesS();
+ }
+
+ static List<ModuleFactory> getModuleFactoriesS() {
+ return Lists.newArrayList(new TestImplModuleFactory(), new DepTestImplModuleFactory(),
+ new NetconfTestImplModuleFactory());
+ }
+
+ private void loadMessages() throws IOException, SAXException, ParserConfigurationException {
+ this.editConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/edit_config.xml");
+ this.getConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
+ this.getConfigCandidate = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig_candidate.xml");
+ this.closeSession = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/closeSession.xml");
+ }
+
+ private NetconfServerDispatcher createDispatcher(Optional<SSLContext> sslC,
+ NetconfOperationServiceFactoryListenerImpl factoriesListener) {
+ SessionIdProvider idProvider = new SessionIdProvider();
+ NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
+ new HashedWheelTimer(5000, TimeUnit.MILLISECONDS), factoriesListener, idProvider);
+
+ NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
+ factoriesListener, commitNot, idProvider);
+
+ return new NetconfServerDispatcher(sslC, serverNegotiatorFactory, listenerFactory);
+ }
+
+ private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
+ final Collection<InputStream> yangDependencies = getBasicYangs();
+ return new HardcodedYangStoreService(yangDependencies);
+ }
+
+ private Collection<InputStream> getBasicYangs() throws IOException {
+ List<String> paths = Arrays.asList("/META-INF/yang/config.yang", "/META-INF/yang/rpc-context.yang",
+ "/META-INF/yang/config-test.yang", "/META-INF/yang/config-test-impl.yang",
+ "/META-INF/yang/ietf-inet-types.yang");
+ final Collection<InputStream> yangDependencies = new ArrayList<>();
+ for (String path : paths) {
+ final InputStream is = Preconditions
+ .checkNotNull(getClass().getResourceAsStream(path), path + " not found");
+ yangDependencies.add(is);
+ }
+ return yangDependencies;
+ }
+
+ @Test
+ public void test() {
+ // MountProvisionInstance mount =
+ // Mockito.mock(MountProvisionInstance.class);
+ InstanceIdentifier path = InstanceIdentifier.builder(InventoryUtils.INVENTORY_PATH)
+ .node(InventoryUtils.INVENTORY_NODE).toInstance();
+ netconfManager.netconfNodeAdded(path, tcpAddress);
+ InstanceIdentifier mountPointPath = path;
+ MountProvisionInstance mountPoint = mountManager.getMountPoint(mountPointPath);
+
+ CompositeNode data = mountPoint.readOperationalData(InstanceIdentifier.builder().node(CONFIG_MODULES)
+ .toInstance());
+ assertNotNull(data);
+ assertEquals(CONFIG_MODULES, data.getNodeType());
+
+ CompositeNode data2 = mountPoint.readOperationalData(InstanceIdentifier.builder().toInstance());
+ assertNotNull(data2);
+
+ InstanceIdentifier fullPath = InstanceIdentifier.builder(mountPointPath).node(CONFIG_MODULES).toInstance();
+
+ CompositeNode data3 = dataBroker.readOperationalData(fullPath);
+ assertNotNull(data3);
+ assertEquals(CONFIG_MODULES, data.getNodeType());
+ }
+
+}
<spring.version>3.1.3.RELEASE</spring.version>
<jersey.version>1.17</jersey.version>
<spring-security.version>3.1.3.RELEASE</spring-security.version>
+ <netconf.version>0.2.2-SNAPSHOT</netconf.version>
+ <config.version>0.2.2-SNAPSHOT</config.version>
</properties>
<build>
<version>1.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-netconf-connector</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-it</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.thirdparty</groupId>
+ <artifactId>exificient</artifactId>
+ <version>0.9.2</version>
+ </dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-native</artifactId>
<version>${exam.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-all</artifactId>
+ <version>4.0.10.Final</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-link-mvn</artifactId>
<artifactId>org.apache.catalina.filters.CorsFilter</artifactId>
<version>7.0.42</version>
</dependency>
+
+
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-api</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-manager</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-util</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-jmx-generator</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-store-api</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-store-impl</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>logback-config</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-api</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-file-adapter</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-api</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-impl</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-util</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-client</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-mapping-api</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-netconf-connector</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-impl</artifactId>
+ <version>${netconf.version}</version>
+ </dependency>
</dependencies>
</project>
package org.opendaylight.controller.test.restconf.it;
+import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.*;
import static org.ops4j.pax.exam.CoreOptions.junitBundles;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.systemProperty;
import static org.ops4j.pax.exam.CoreOptions.maven;
+import java.net.InetSocketAddress;
+import java.net.URI;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
import javax.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.connect.netconf.InventoryUtils;
+import org.opendaylight.controller.sal.connect.netconf.NetconfDeviceManager;
+import org.opendaylight.controller.sal.connect.netconf.NetconfInventoryUtils;
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
import org.opendaylight.controller.test.sal.binding.it.TestHelper;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.CoreOptions;
import org.ops4j.pax.exam.Option;
public static final String YANG = "org.opendaylight.yangtools";
public static final String SAMPLE = "org.opendaylight.controller.samples";
+ private static QName CONFIG_MODULES = new QName(
+ URI.create("urn:opendaylight:params:xml:ns:yang:controller:config"), null, "modules");
+ private static QName CONFIG_SERVICES = new QName(
+ URI.create("urn:opendaylight:params:xml:ns:yang:controller:config"), null, "modules");
+ @Inject
+ BundleContext context;
+
+ @Inject
+ MountProvisionService mountService;
+
+ @Inject
+ DataBrokerService dataBroker;
+
+ @Inject
+ NetconfDeviceManager netconfManager;
+
@Test
public void properInitialized() throws Exception {
- Thread.sleep(30*60*1000); // Waiting for services to get wired.
- assertTrue(true);
- // assertTrue(consumer.createToast(WhiteBread.class, 5));
+ Map<QName, String> arg = Collections.singletonMap(InventoryUtils.INVENTORY_ID, "foo");
- }
+ InstanceIdentifier path = InstanceIdentifier.builder(InventoryUtils.INVENTORY_PATH)
+ .nodeWithKey(InventoryUtils.INVENTORY_NODE, InventoryUtils.INVENTORY_ID, "foo").toInstance();
- // @Inject
- // BindingAwareBroker broker;
+ netconfManager.netconfNodeAdded(path, new InetSocketAddress("127.0.0.1", 8383));
- // @Inject
- // ToastConsumer consumer;
+
+ InstanceIdentifier mountPointPath = path;
+
+ /** We retrive a mountpoint **/
+ MountProvisionInstance mountPoint = mountService.getMountPoint(mountPointPath);
+ CompositeNode data = mountPoint.readOperationalData(InstanceIdentifier.builder().node(CONFIG_MODULES)
+ .toInstance());
+ assertNotNull(data);
+ assertEquals(CONFIG_MODULES, data.getNodeType());
- @Inject
- BundleContext ctx;
+ CompositeNode data2 = mountPoint.readOperationalData(InstanceIdentifier.builder().toInstance());
+ assertNotNull(data2);
+
+ InstanceIdentifier fullPath = InstanceIdentifier.builder(mountPointPath).node(CONFIG_MODULES).toInstance();
+
+ CompositeNode data3 = dataBroker.readOperationalData(fullPath);
+ assertNotNull(data3);
+ assertEquals(CONFIG_MODULES, data.getNodeType());
+
+ //Thread.sleep(30 * 60 * 1000); // Waiting for services to get wired.
+ //assertTrue(true);
+ // assertTrue(consumer.createToast(WhiteBread.class, 5));
+ }
@Configuration
public Option[] config() {
mdSalCoreBundles(),
baseModelBundles(),
flowCapableModelBundles(),
+ configMinumumBundles(),
// mavenBundle(ODL,
// "sal-binding-broker-impl").versionAsInProject().update(), //
// mavenBundle(SAMPLE,
// "zeromq-test-provider").versionAsInProject(), //
mavenBundle(ODL, "sal-rest-connector").versionAsInProject(), //
+ mavenBundle(ODL, "sal-netconf-connector").versionAsInProject(), //
mavenBundle(YANG, "concepts").versionAsInProject(),
mavenBundle(YANG, "yang-binding").versionAsInProject(), //
mavenBundle(YANG, "yang-model-util").versionAsInProject(), //
mavenBundle(YANG, "yang-parser-api").versionAsInProject(),
mavenBundle(YANG, "yang-parser-impl").versionAsInProject(),
+
mavenBundle(YANG + ".thirdparty", "xtend-lib-osgi").versionAsInProject(), //
mavenBundle(YANG + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), //
mavenBundle("com.google.guava", "guava").versionAsInProject(), //
// earlier.
systemProperty("osgi.bundles.defaultStartLevel").value("4"),
+ systemProperty("netconf.tcp.address").value("127.0.0.1"),
+ systemProperty("netconf.tcp.port").value("8383"),
+
// Set the systemPackages (used by clustering)
systemPackages("sun.reflect", "sun.reflect.misc", "sun.misc"),
+
+ mavenBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.xerces", "2.11.0_1"),
+ mavenBundle("org.eclipse.birt.runtime.3_7_1", "org.apache.xml.resolver", "1.2.0"),
+
mavenBundle("org.slf4j", "jcl-over-slf4j").versionAsInProject(),
mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(),
mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(),
// mavenBundle("commons-fileupload",
// "commons-fileupload").versionAsInProject(),
+ mavenBundle("io.netty", "netty-handler").versionAsInProject(),
+ mavenBundle("io.netty", "netty-codec").versionAsInProject(),
+ mavenBundle("io.netty", "netty-buffer").versionAsInProject(),
+ mavenBundle("io.netty", "netty-transport").versionAsInProject(),
+ mavenBundle("io.netty", "netty-common").versionAsInProject(),
+
+ mavenBundle(ODL, "config-api").versionAsInProject(),
+ mavenBundle(ODL, "config-manager").versionAsInProject(),
+ mavenBundle(ODL, "config-util").versionAsInProject(),
+ mavenBundle(ODL, "yang-jmx-generator").versionAsInProject(),
+ mavenBundle(ODL, "yang-store-api").versionAsInProject(),
+ mavenBundle(ODL, "yang-store-impl").versionAsInProject(),
+ mavenBundle(ODL, "logback-config").versionAsInProject(),
+ mavenBundle(ODL, "config-persister-api").versionAsInProject(),
+ // mavenBundle(ODL,"config-persister-file-adapter").versionAsInProject(),
+ mavenBundle(ODL, "netconf-api").versionAsInProject(),
+ mavenBundle(ODL, "netconf-impl").versionAsInProject(),
+ mavenBundle(ODL, "netconf-client").versionAsInProject(),
+ mavenBundle(ODL, "netconf-util").versionAsInProject(),
+ mavenBundle(ODL + ".thirdparty", "ganymed", "1.0-SNAPSHOT"),
+ mavenBundle(ODL, "netconf-mapping-api").versionAsInProject(),
+ mavenBundle(ODL, "config-netconf-connector").versionAsInProject(),
+ mavenBundle(ODL, "config-persister-impl").versionAsInProject(),
+
+ mavenBundle("org.opendaylight.bgpcep", "framework").versionAsInProject(),
+ mavenBundle("org.opendaylight.bgpcep", "util").versionAsInProject(),
+ mavenBundle(YANG, "binding-generator-spi").versionAsInProject(), //
+ mavenBundle(YANG, "binding-model-api").versionAsInProject(), //
+ mavenBundle(YANG, "binding-generator-util").versionAsInProject(),
+ mavenBundle(YANG, "yang-parser-impl").versionAsInProject(),
+ mavenBundle(YANG, "binding-type-provider").versionAsInProject(),
+
+ mavenBundle("org.opendaylight.controller.thirdparty", "exificient", "0.9.2"),
+
mavenBundle("equinoxSDK381", "javax.servlet").versionAsInProject(),
mavenBundle("equinoxSDK381", "javax.servlet.jsp").versionAsInProject(),
mavenBundle("equinoxSDK381", "org.eclipse.equinox.ds").versionAsInProject(),