netconf-console unit tests added 36/45836/7
authorRudolf Brisuda <rudolf.brisuda@pantheon.tech>
Mon, 19 Sep 2016 15:51:23 +0000 (17:51 +0200)
committerRudolf Brisuda <rbrisuda@cisco.com>
Thu, 13 Oct 2016 11:09:04 +0000 (11:09 +0000)
Change-Id: I3975e0740935dbbe6bc65f6e3ea3febf56507f39
Signed-off-by: Rudolf Brisuda <rudolf.brisuda@pantheon.tech>
14 files changed:
netconf/netconf-console/pom.xml
netconf/netconf-console/src/main/java/org/opendaylight/netconf/console/commands/NetconfCommandUtils.java
netconf/netconf-console/src/main/java/org/opendaylight/netconf/console/commands/NetconfConnectDeviceCommand.java
netconf/netconf-console/src/main/java/org/opendaylight/netconf/console/commands/NetconfDisconnectDeviceCommand.java
netconf/netconf-console/src/main/java/org/opendaylight/netconf/console/commands/NetconfShowDeviceCommand.java
netconf/netconf-console/src/main/java/org/opendaylight/netconf/console/commands/NetconfUpdateDeviceCommand.java
netconf/netconf-console/src/test/java/org/opendaylight/netconf/console/commands/NetconfCommandUtilsTest.java [new file with mode: 0644]
netconf/netconf-console/src/test/java/org/opendaylight/netconf/console/commands/NetconfCommandsImplCallsTest.java [new file with mode: 0644]
netconf/netconf-console/src/test/java/org/opendaylight/netconf/console/impl/NetconfCommandsImplTest.java [new file with mode: 0644]
netconf/netconf-console/src/test/java/org/opendaylight/netconf/console/impl/NetconfConsoleProviderTest.java [new file with mode: 0644]
netconf/netconf-console/src/test/resources/schemas/ietf-inet-types@2013-07-15.yang [new file with mode: 0644]
netconf/netconf-console/src/test/resources/schemas/netconf-node-topology.yang [new file with mode: 0644]
netconf/netconf-console/src/test/resources/schemas/network-topology@2013-10-21.yang [new file with mode: 0644]
netconf/netconf-console/src/test/resources/schemas/yang-ext.yang [new file with mode: 0644]

index 8e4e05f93c1a1e701ac9596320f153c71ef14591..b4c260009a615fa554bed8cd1dbc160583ee25be 100644 (file)
@@ -40,5 +40,29 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <artifactId>sal-netconf-connector</artifactId>
       <version>${mdsal.version}</version>
     </dependency>
+      <dependency>
+          <groupId>org.mockito</groupId>
+          <artifactId>mockito-all</artifactId>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-distributed-datastore</artifactId>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.powermock</groupId>
+          <artifactId>powermock-module-junit4</artifactId>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.powermock</groupId>
+          <artifactId>powermock-api-mockito</artifactId>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.powermock</groupId>
+          <artifactId>powermock-core</artifactId>
+      </dependency>
   </dependencies>
 </project>
\ No newline at end of file
index 67024f910b005a9c8d4c28742c87761a4516c454..40ac48f17c633613afc9a1dd9be39db3ae5d86d0 100644 (file)
@@ -25,11 +25,13 @@ public class NetconfCommandUtils {
         if (Strings.isNullOrEmpty(devicePort)) {
             return false;
         }
-        Integer port = Integer.parseInt(devicePort);
-        if (port != null && port >= 0 && port <= 65535) {
-            return true;
+        Integer port;
+        try {
+            port = Integer.parseInt(devicePort);
+        } catch (NumberFormatException e) {
+          return false;
         }
-        return false;
+        return port >= 0 && port <= 65535;
     }
 
     public static boolean isIpValid(final String deviceIp) {
index 322f3d2cbe79340fa283d1705494db4929dd7dc5..a41839789c4ad1a5ed3f3d53e403bbe713ba3e19 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.netconf.console.commands;
 
+import com.google.common.annotations.VisibleForTesting;
 import org.apache.karaf.shell.commands.Command;
 import org.apache.karaf.shell.commands.Option;
 import org.apache.karaf.shell.console.AbstractAction;
@@ -30,6 +31,13 @@ public class NetconfConnectDeviceCommand extends AbstractAction {
         this.service = service;
     }
 
+    @VisibleForTesting
+    NetconfConnectDeviceCommand(final NetconfCommands service, final String deviceIp, final String devicePort) {
+        this.service = service;
+        this.deviceIp = deviceIp;
+        this.devicePort = devicePort;
+    }
+
     @Option(name = "-i",
             aliases = { "--ipaddress" },
             description = "IP address of the netconf device",
index 94361901fdd123b96189cca32598f678d2658a06..b1abf2fa254d7a9f2bac9009245a99f1e0f48211 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.netconf.console.commands;
 
+import com.google.common.annotations.VisibleForTesting;
 import org.apache.karaf.shell.commands.Command;
 import org.apache.karaf.shell.commands.Option;
 import org.apache.karaf.shell.console.AbstractAction;
@@ -24,6 +25,15 @@ public class NetconfDisconnectDeviceCommand extends AbstractAction {
         this.service = service;
     }
 
+    @VisibleForTesting
+    NetconfDisconnectDeviceCommand(final NetconfCommands service, final String deviceId, final String deviceIp,
+                                   final String devicePort) {
+        this.service = service;
+        this.deviceId = deviceId;
+        this.deviceIp = deviceIp;
+        this.devicePort = devicePort;
+    }
+
     @Option(name = "-i",
             aliases = { "--ipaddress" },
             description = "IP address of the netconf device",
index b50ea715493a732c47853f03131e889b96a6e90e..46d36dceb53e39a5d078bacafd8aa3a60f7f1caf 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.netconf.console.commands;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Strings;
 import java.util.List;
 import java.util.Map;
@@ -28,6 +29,15 @@ public class NetconfShowDeviceCommand extends AbstractAction {
         this.service = service;
     }
 
+    @VisibleForTesting
+    NetconfShowDeviceCommand(final NetconfCommands service, final String deviceId, final String deviceIp,
+                             final String devicePort) {
+        this.service = service;
+        this.deviceId = deviceId;
+        this.deviceIp = deviceIp;
+        this.devicePort = devicePort;
+    }
+
     @Option(name = "-id",
             aliases = { "--identifier" },
             description = "Node Identifier of the netconf device",
index b03556948e3e29b45469fad02ab99a19c8566898..79b6bb498e4d0b6e00f596749fa5264ce9164323 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.netconf.console.commands;
 
+import com.google.common.annotations.VisibleForTesting;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -26,6 +27,12 @@ public class NetconfUpdateDeviceCommand extends AbstractAction {
         this.service = service;
     }
 
+    @VisibleForTesting
+    NetconfUpdateDeviceCommand(final NetconfCommands service, final String newIp) {
+        this.service = service;
+        this.newIp = newIp;
+    }
+
     @Option(name = "-id",
             aliases = { "--nodeId" },
             description = "NETCONF node ID of the netconf device",
diff --git a/netconf/netconf-console/src/test/java/org/opendaylight/netconf/console/commands/NetconfCommandUtilsTest.java b/netconf/netconf-console/src/test/java/org/opendaylight/netconf/console/commands/NetconfCommandUtilsTest.java
new file mode 100644 (file)
index 0000000..0c19ce2
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.console.commands;
+
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+
+import org.junit.Test;
+
+public class NetconfCommandUtilsTest {
+
+    @Test
+    public void testIsPortValid() {
+        final boolean portTrue = NetconfCommandUtils.isPortValid("65535");
+        final boolean portTrue2 = NetconfCommandUtils.isPortValid("0");
+
+        final boolean portFalse = NetconfCommandUtils.isPortValid("123x");
+        final boolean portFalse2 = NetconfCommandUtils.isPortValid("65536");
+        final boolean portFalse3 = NetconfCommandUtils.isPortValid("");
+
+        assertTrue(portTrue);
+        assertTrue(portTrue2);
+        assertFalse(portFalse);
+        assertFalse(portFalse2);
+        assertFalse(portFalse3);
+
+    }
+
+    @Test
+    public void testIsIpValid() {
+        final boolean ipTrue = NetconfCommandUtils.isIpValid("0.0.0.0");
+        final boolean ipTrue2 = NetconfCommandUtils.isIpValid("255.255.255.255");
+
+        final boolean ipFalse = NetconfCommandUtils.isIpValid("256.1.1.1");
+        final boolean ipFalse2 = NetconfCommandUtils.isIpValid("123.145.12.x");
+        final boolean ipFalse3 = NetconfCommandUtils.isIpValid("");
+
+        assertTrue(ipTrue);
+        assertTrue(ipTrue2);
+        assertFalse(ipFalse);
+        assertFalse(ipFalse2);
+        assertFalse(ipFalse3);
+    }
+}
diff --git a/netconf/netconf-console/src/test/java/org/opendaylight/netconf/console/commands/NetconfCommandsImplCallsTest.java b/netconf/netconf-console/src/test/java/org/opendaylight/netconf/console/commands/NetconfCommandsImplCallsTest.java
new file mode 100644 (file)
index 0000000..0b52925
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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.console.commands;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+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 java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.opendaylight.netconf.console.api.NetconfCommands;
+import org.opendaylight.netconf.console.utils.NetconfConsoleConstants;
+
+public class NetconfCommandsImplCallsTest {
+
+    @Mock
+    private NetconfCommands netconfCommands;
+
+    @Before
+    public void setUp(){
+        initMocks(this);
+    }
+
+    @Test
+    public void testConnectDeviceCommand() throws Exception {
+        NetconfConnectDeviceCommand netconfConnectDeviceCommand =
+                new NetconfConnectDeviceCommand(netconfCommands);
+        netconfConnectDeviceCommand.doExecute();
+        verify(netconfCommands, times(0)).connectDevice(any(), any());
+
+        netconfConnectDeviceCommand = new NetconfConnectDeviceCommand(netconfCommands, "192.168.1.1", "7777");
+
+        netconfConnectDeviceCommand.doExecute();
+        doNothing().when(netconfCommands).connectDevice(any(), any());
+        verify(netconfCommands, times(1)).connectDevice(any(), any());
+    }
+
+    @Test
+    public void testDisconnectDeviceCommand() throws Exception {
+        NetconfDisconnectDeviceCommand netconfDisconnectDeviceCommand = new NetconfDisconnectDeviceCommand(netconfCommands);
+        netconfDisconnectDeviceCommand.doExecute();
+
+        verify(netconfCommands, times(0)).connectDevice(any(), any());
+
+        netconfDisconnectDeviceCommand = new NetconfDisconnectDeviceCommand(netconfCommands, "deviceId", null, null);
+
+        doReturn(true).when(netconfCommands).disconnectDevice(any());
+        netconfDisconnectDeviceCommand.doExecute();
+
+        verify(netconfCommands, times(1)).disconnectDevice(any());
+
+        netconfDisconnectDeviceCommand =
+                new NetconfDisconnectDeviceCommand(netconfCommands, null, "192.168.1.1", "7777");
+
+        doReturn(true).when(netconfCommands).disconnectDevice(any(), any());
+        netconfDisconnectDeviceCommand.doExecute();
+
+        verify(netconfCommands, times(1)).disconnectDevice(any(), any());
+    }
+
+    @Test
+    public void testListDeviceCommand() throws Exception {
+        final NetconfListDevicesCommand netconfListDeviceCommand = new NetconfListDevicesCommand(netconfCommands);
+        doReturn(getDeviceHashMap()).when(netconfCommands).listDevices();
+
+        netconfListDeviceCommand.doExecute();
+
+        verify(netconfCommands, times(1)).listDevices();
+    }
+
+    @Test
+    public void testShowDeviceCommand() throws Exception {
+        NetconfShowDeviceCommand netconfShowDeviceCommand = new NetconfShowDeviceCommand(netconfCommands);
+        netconfShowDeviceCommand.doExecute();
+
+        verify(netconfCommands, times(0)).showDevice(any());
+
+        netconfShowDeviceCommand = new NetconfShowDeviceCommand(netconfCommands, "deviceId", null, null);
+
+        doReturn(getDeviceHashMap()).when(netconfCommands).showDevice(any());
+        netconfShowDeviceCommand.doExecute();
+
+        verify(netconfCommands, times(1)).showDevice(any());
+
+        netconfShowDeviceCommand = new NetconfShowDeviceCommand(netconfCommands, null, "192.168.1.1", "7777");
+
+        doReturn(getDeviceHashMap()).when(netconfCommands).showDevice(any(), any());
+        netconfShowDeviceCommand.doExecute();
+
+        verify(netconfCommands, times(1)).showDevice(any(), any());
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testUpdateDeviceCommand() throws Exception {
+        final NetconfUpdateDeviceCommand netconfUpdateDeviceCommand =
+                new NetconfUpdateDeviceCommand(netconfCommands, "192.168.1.1");
+
+        final ArgumentCaptor<HashMap> hashMapArgumentCaptor = ArgumentCaptor.forClass(HashMap.class);
+
+        doReturn("").when(netconfCommands).updateDevice(anyString(), anyString(), anyString(), any());
+
+        netconfUpdateDeviceCommand.doExecute();
+
+        verify(netconfCommands, times(1)).updateDevice(anyString(), anyString(), anyString(), hashMapArgumentCaptor.capture());
+
+        assertTrue(hashMapArgumentCaptor.getValue().containsKey(NetconfConsoleConstants.NETCONF_IP));
+        assertEquals("192.168.1.1", hashMapArgumentCaptor.getValue().get(NetconfConsoleConstants.NETCONF_IP));
+    }
+
+    private HashMap getDeviceHashMap() {
+        final HashMap<String, Map<String, List<String>>> devices = new HashMap<>();
+        final HashMap<String, List<String>> deviceMap = new HashMap<>();
+        deviceMap.put(NetconfConsoleConstants.NETCONF_IP, Lists.newArrayList("192.168.1.1"));
+        deviceMap.put(NetconfConsoleConstants.NETCONF_PORT, Lists.newArrayList("7777"));
+        deviceMap.put(NetconfConsoleConstants.STATUS, Lists.newArrayList("connecting"));
+        deviceMap.put(NetconfConsoleConstants.AVAILABLE_CAPABILITIES, Lists.newArrayList("cap1", "cap2", "cap3"));
+        devices.put("device", deviceMap);
+        return devices;
+    }
+
+}
diff --git a/netconf/netconf-console/src/test/java/org/opendaylight/netconf/console/impl/NetconfCommandsImplTest.java b/netconf/netconf-console/src/test/java/org/opendaylight/netconf/console/impl/NetconfCommandsImplTest.java
new file mode 100644 (file)
index 0000000..96c5b27
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * 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.console.impl;
+
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNull;
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+
+import com.google.common.collect.ImmutableList;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javassist.ClassPool;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.databroker.ConcurrentDOMDataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.MountPointService;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.binding.impl.BindingDOMDataBrokerAdapter;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+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.store.impl.InMemoryDOMDataStoreFactory;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.core.spi.data.DOMStore;
+import org.opendaylight.netconf.console.utils.NetconfConsoleConstants;
+import org.opendaylight.netconf.console.utils.NetconfConsoleUtils;
+import org.opendaylight.netconf.console.utils.NetconfIidFactory;
+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.HostBuilder;
+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;
+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.AvailableCapabilitiesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.network.topology.topology.topology.types.TopologyNetconf;
+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.binding.data.codec.gen.impl.DataObjectSerializerGenerator;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
+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.util.concurrent.SpecialExecutors;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+
+public class NetconfCommandsImplTest {
+
+    private static final String NODE_ID = "NodeID";
+    private static final String IP = "192.168.1.1";
+    private static final int PORT = 1234;
+    private static final NetconfNodeConnectionStatus.ConnectionStatus CONN_STATUS =
+            NetconfNodeConnectionStatus.ConnectionStatus.Connected;
+    private static final String CAP_PREFIX = "prefix";
+
+    private DataBroker dataBroker;
+    private SchemaContext schemaContext;
+    private NetconfCommandsImpl netconfCommands;
+
+    @Before
+    public void setUp() throws TransactionCommitFailedException, TimeoutException, InterruptedException {
+        schemaContext = parseYangStreams(getYangSchemas());
+        schemaContext.getModules();
+        final SchemaService schemaService = createSchemaService();
+
+        final DOMStore operStore = InMemoryDOMDataStoreFactory.create("DOM-OPER", schemaService);
+        final DOMStore configStore = InMemoryDOMDataStoreFactory.create("DOM-CFG", schemaService);
+
+        final EnumMap<LogicalDatastoreType, DOMStore> datastores = new EnumMap<>(LogicalDatastoreType.class);
+        datastores.put(LogicalDatastoreType.CONFIGURATION, configStore);
+        datastores.put(LogicalDatastoreType.OPERATIONAL, operStore);
+
+        final ExecutorService listenableFutureExecutor = SpecialExecutors.newBlockingBoundedCachedThreadPool(
+                16, 16, "CommitFutures");
+
+        final ConcurrentDOMDataBroker cDOMDataBroker = new ConcurrentDOMDataBroker(datastores, listenableFutureExecutor);
+
+        final ClassPool pool = ClassPool.getDefault();
+        final DataObjectSerializerGenerator generator = StreamWriterGenerator.create(JavassistUtils.forClassPool(pool));
+        final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(generator);
+        final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
+        codecRegistry.onBindingRuntimeContextUpdated(BindingRuntimeContext.create(moduleInfoBackedContext, schemaContext));
+
+        final GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
+        final BindingToNormalizedNodeCodec bindingToNormalized = new BindingToNormalizedNodeCodec(loading, codecRegistry);
+        bindingToNormalized.onGlobalContextUpdated(schemaContext);
+        dataBroker = new BindingDOMDataBrokerAdapter(cDOMDataBroker, bindingToNormalized);
+
+        final MountPointService mountPointService = mock(MountPointService.class);
+        netconfCommands = new NetconfCommandsImpl(dataBroker, mountPointService);
+    }
+
+    @Test
+    public void testListDevice() throws TimeoutException, TransactionCommitFailedException {
+        createTopology(LogicalDatastoreType.OPERATIONAL);
+
+        final Map map = netconfCommands.listDevices();
+        map.containsKey(NetconfConsoleConstants.NETCONF_ID);
+        assertTrue(map.containsKey(NODE_ID));
+
+        final Map mapNode = (Map) map.get(NODE_ID);
+        assertBaseNodeAttributes(mapNode);
+    }
+
+    @Test
+    public void testShowDevice() throws TimeoutException, TransactionCommitFailedException {
+        createTopology(LogicalDatastoreType.OPERATIONAL);
+
+        final Map mapCorrect = netconfCommands.showDevice(IP, String.valueOf(PORT));
+        mapCorrect.containsKey(NetconfConsoleConstants.NETCONF_ID);
+        assertTrue(mapCorrect.containsKey(NODE_ID));
+
+        assertBaseNodeAttributesImmutableList((Map) mapCorrect.get(NODE_ID));
+
+        final Map mapWrongPort = netconfCommands.showDevice(IP, "1");
+        assertFalse(mapWrongPort.containsKey(NODE_ID));
+
+        final Map mapWrongIP = netconfCommands.showDevice("1.1.1.1", String.valueOf(PORT));
+        assertFalse(mapWrongIP.containsKey(NODE_ID));
+
+        final Map mapId = netconfCommands.showDevice(NODE_ID);
+        assertTrue(mapId.containsKey(NODE_ID));
+        assertBaseNodeAttributesImmutableList((Map) mapId.get(NODE_ID));
+    }
+
+    @Test
+    public void testConnectDisconnectDevice() throws InterruptedException, TimeoutException, TransactionCommitFailedException {
+        final NetconfNode netconfNode = new NetconfNodeBuilder().setPort(new PortNumber(7777)).
+                setHost(HostBuilder.getDefaultInstance("10.10.1.1")).build();
+
+        createTopology(LogicalDatastoreType.CONFIGURATION);
+        netconfCommands.connectDevice(netconfNode, "netconf-ID");
+        NetconfConsoleUtils.waitForUpdate("10.10.1.1");
+
+        final Topology topology = NetconfConsoleUtils.read(LogicalDatastoreType.CONFIGURATION,
+                NetconfIidFactory.NETCONF_TOPOLOGY_IID, dataBroker);
+        final List<Node> nodes = topology.getNode();
+        assertEquals(2, nodes.size());
+
+        final Optional<Node> storedNode = nodes.stream().filter(node ->
+                node.getKey().getNodeId().getValue().equals("netconf-ID")).findFirst();
+
+        assertTrue(storedNode.isPresent());
+
+        NetconfNode storedNetconfNode = storedNode.get().getAugmentation(NetconfNode.class);
+        assertEquals(7777, storedNetconfNode.getPort().getValue().longValue());
+        assertEquals("10.10.1.1", storedNetconfNode.getHost().getIpAddress().getIpv4Address().getValue());
+
+        netconfCommands.disconnectDevice("netconf-ID");
+
+        final Topology topologyDeleted = NetconfConsoleUtils.read(LogicalDatastoreType.CONFIGURATION,
+                NetconfIidFactory.NETCONF_TOPOLOGY_IID, dataBroker);
+        final List<Node> nodesDeleted = topologyDeleted.getNode();
+        assertEquals(1, nodesDeleted.size());
+
+        final Optional<Node> storedNodeDeleted = nodesDeleted.stream().filter(node ->
+                node.getKey().getNodeId().getValue().equals("netconf-ID")).findFirst();
+
+        assertFalse(storedNodeDeleted.isPresent());
+    }
+
+    @Test
+    public void testUpdateDevice() throws TimeoutException, TransactionCommitFailedException {
+        //We need both, read data from OPERATIONAL DS and update data in CONFIGURATIONAL DS
+        createTopology(LogicalDatastoreType.OPERATIONAL);
+        createTopology(LogicalDatastoreType.CONFIGURATION);
+
+        final Map<String, String> update = new HashMap<>();
+        update.put(NetconfConsoleConstants.NETCONF_IP, "7.7.7.7");
+        update.put(NetconfConsoleConstants.TCP_ONLY, "true");
+
+        netconfCommands.updateDevice(NODE_ID, "admin", "admin", update);
+        NetconfConsoleUtils.waitForUpdate("7.7.7.7");
+
+        final Topology topology = NetconfConsoleUtils.read(LogicalDatastoreType.CONFIGURATION,
+                NetconfIidFactory.NETCONF_TOPOLOGY_IID, dataBroker);
+        final List<Node> nodes = topology.getNode();
+        assertEquals(1, nodes.size());
+
+        final Optional<Node> storedNode = nodes.stream().filter(node ->
+                node.getKey().getNodeId().getValue().equals(NODE_ID)).findFirst();
+        assertTrue(storedNode.isPresent());
+
+        NetconfNode storedNetconfNode = storedNode.get().getAugmentation(NetconfNode.class);
+        assertEquals("7.7.7.7", storedNetconfNode.getHost().getIpAddress().getIpv4Address().getValue());
+    }
+
+    @Test
+    public void testNetconfNodeFromIp() throws TimeoutException, TransactionCommitFailedException {
+        final List<Node> nodesNotExist = NetconfConsoleUtils.getNetconfNodeFromIp(IP, dataBroker);
+        assertNull(nodesNotExist);
+        createTopology(LogicalDatastoreType.OPERATIONAL);
+        final List<Node> nodes = NetconfConsoleUtils.getNetconfNodeFromIp(IP, dataBroker);
+        assertNotNull(nodes);
+        assertEquals(1, nodes.size());
+    }
+
+    private void createTopology(LogicalDatastoreType dataStoreType) throws TransactionCommitFailedException, TimeoutException {
+        final List<Node> nodes = new ArrayList<>();
+        final Node node = getNetconfNode(NODE_ID, IP, PORT, CONN_STATUS, CAP_PREFIX);
+        nodes.add(node);
+
+        final Topology topology = new TopologyBuilder().
+                setKey(new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName()))).
+                setTopologyId(new TopologyId(TopologyNetconf.QNAME.getLocalName())).setNode(nodes).build();
+
+        final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+        writeTransaction.put(dataStoreType, NetconfIidFactory.NETCONF_TOPOLOGY_IID, topology);
+        writeTransaction.submit().checkedGet(2, TimeUnit.SECONDS);
+    }
+
+    private Node getNetconfNode(String nodeIdent, String ip, int portNumber, NetconfNodeConnectionStatus.ConnectionStatus cs,
+                                String notificationCapabilityPrefix) {
+
+        final Host host = HostBuilder.getDefaultInstance(ip);
+        final PortNumber port = new PortNumber(portNumber);
+
+        final List<String> avCapList = new ArrayList<>();
+        avCapList.add(notificationCapabilityPrefix + "_availableCapabilityString1");
+        final AvailableCapabilities avCaps = new AvailableCapabilitiesBuilder().setAvailableCapability(avCapList).build();
+
+        final NetconfNode nn = new NetconfNodeBuilder().setConnectionStatus(cs).setHost(host).setPort(port).
+                setAvailableCapabilities(avCaps).build();
+        final NodeId nodeId = new NodeId(nodeIdent);
+        final NodeKey nk = new NodeKey(nodeId);
+        final NodeBuilder nb = new NodeBuilder();
+        nb.setKey(nk);
+        nb.setNodeId(nodeId);
+        nb.addAugmentation(NetconfNode.class, nn);
+        return nb.build();
+    }
+
+    private void assertBaseNodeAttributes(Map mapNode) {
+
+        assertTrue(mapNode.containsKey(NetconfConsoleConstants.NETCONF_ID));
+        assertTrue(mapNode.containsKey(NetconfConsoleConstants.NETCONF_IP));
+        assertTrue(mapNode.containsKey(NetconfConsoleConstants.NETCONF_PORT));
+        assertTrue(mapNode.containsKey(NetconfConsoleConstants.STATUS));
+
+        assertEquals(NODE_ID, mapNode.get(NetconfConsoleConstants.NETCONF_ID));
+        assertEquals(IP, mapNode.get(NetconfConsoleConstants.NETCONF_IP));
+        assertEquals(String.valueOf(PORT), mapNode.get(NetconfConsoleConstants.NETCONF_PORT));
+        assertEquals(CONN_STATUS.name().toLowerCase(), mapNode.get(NetconfConsoleConstants.STATUS));
+    }
+
+    private void assertBaseNodeAttributesImmutableList(Map mapNode) {
+        assertTrue(mapNode.containsKey(NetconfConsoleConstants.NETCONF_ID));
+        assertTrue(mapNode.containsKey(NetconfConsoleConstants.NETCONF_IP));
+        assertTrue(mapNode.containsKey(NetconfConsoleConstants.NETCONF_PORT));
+        assertTrue(mapNode.containsKey(NetconfConsoleConstants.STATUS));
+
+        assertEquals(ImmutableList.of(NODE_ID), mapNode.get(NetconfConsoleConstants.NETCONF_ID));
+        assertEquals(ImmutableList.of(IP), mapNode.get(NetconfConsoleConstants.NETCONF_IP));
+        assertEquals(ImmutableList.of(String.valueOf(PORT)), mapNode.get(NetconfConsoleConstants.NETCONF_PORT));
+        assertEquals(ImmutableList.of(CONN_STATUS.name()), mapNode.get(NetconfConsoleConstants.STATUS));
+    }
+
+    private List<InputStream> getYangSchemas() {
+        final List<String> schemaPaths = Arrays.asList("/schemas/network-topology@2013-10-21.yang",
+                "/schemas/ietf-inet-types@2013-07-15.yang", "/schemas/yang-ext.yang", "/schemas/netconf-node-topology.yang");
+        final List<InputStream> schemas = new ArrayList<>();
+        for (String schemaPath : schemaPaths) {
+            final InputStream resourceAsStream = getClass().getResourceAsStream(schemaPath);
+            schemas.add(resourceAsStream);
+        }
+        return schemas;
+    }
+
+    private static SchemaContext parseYangStreams(final List<InputStream> streams) {
+        CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR
+                .newBuild();
+        final SchemaContext schemaContext;
+        try {
+            schemaContext = reactor.buildEffective(streams);
+        } catch (ReactorException e) {
+            throw new RuntimeException("Unable to build schema context from " + streams, e);
+        }
+        return schemaContext;
+    }
+
+    private SchemaService createSchemaService() {
+        return new SchemaService() {
+
+            @Override
+            public void addModule(Module module) {
+            }
+
+            @Override
+            public void removeModule(Module module) {
+
+            }
+
+            @Override
+            public SchemaContext getSessionContext() {
+                return schemaContext;
+            }
+
+            @Override
+            public SchemaContext getGlobalContext() {
+                return schemaContext;
+            }
+
+            @Override
+            public ListenerRegistration<SchemaContextListener> registerSchemaContextListener(final SchemaContextListener listener) {
+                listener.onGlobalContextUpdated(getGlobalContext());
+                return new ListenerRegistration<SchemaContextListener>() {
+                    @Override
+                    public void close() {
+
+                    }
+
+                    @Override
+                    public SchemaContextListener getInstance() {
+                        return listener;
+                    }
+                };
+            }
+        };
+    }
+}
diff --git a/netconf/netconf-console/src/test/java/org/opendaylight/netconf/console/impl/NetconfConsoleProviderTest.java b/netconf/netconf-console/src/test/java/org/opendaylight/netconf/console/impl/NetconfConsoleProviderTest.java
new file mode 100644 (file)
index 0000000..ef20f81
--- /dev/null
@@ -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.console.impl;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+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.powermock.api.mockito.PowerMockito.when;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.BDDMockito;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.MountPointService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.netconf.console.api.NetconfCommands;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(FrameworkUtil.class)
+public class NetconfConsoleProviderTest {
+
+    @Test
+    public void testProvider() throws Exception {
+        final NetconfConsoleProvider netconfConsoleProvider = new NetconfConsoleProvider();
+
+        PowerMockito.mockStatic(FrameworkUtil.class);
+
+        final BindingAwareBroker.ProviderContext session = mock(BindingAwareBroker.ProviderContext.class);
+        final MountPointService mountPointService = mock(MountPointService.class);
+        final BundleContext bundleContext = mock(BundleContext.class);
+        final DataBroker dataBroker = mock(DataBroker.class);
+        final Bundle bundle = mock(Bundle.class);
+
+        doReturn(dataBroker).when(session).getSALService(DataBroker.class);
+        doReturn(mountPointService).when(session).getSALService(MountPointService.class);
+        BDDMockito.given(FrameworkUtil.getBundle(any())).willReturn(bundle);
+        when(bundle.getBundleContext()).thenReturn(bundleContext);
+
+        netconfConsoleProvider.onSessionInitiated(session);
+
+        verify(bundleContext, times(1)).registerService(eq(NetconfCommands.class), any(NetconfCommandsImpl.class), eq(null));
+
+    }
+}
diff --git a/netconf/netconf-console/src/test/resources/schemas/ietf-inet-types@2013-07-15.yang b/netconf/netconf-console/src/test/resources/schemas/ietf-inet-types@2013-07-15.yang
new file mode 100644 (file)
index 0000000..5c6f139
--- /dev/null
@@ -0,0 +1,457 @@
+module ietf-inet-types {
+
+  namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+  prefix "inet";
+
+  organization
+   "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+  contact
+   "WG Web:   <http://tools.ietf.org/wg/netmod/>
+    WG List:  <mailto:netmod@ietf.org>
+
+    WG Chair: David Kessens
+              <mailto:david.kessens@nsn.com>
+
+    WG Chair: Juergen Schoenwaelder
+              <mailto:j.schoenwaelder@jacobs-university.de>
+
+    Editor:   Juergen Schoenwaelder
+              <mailto:j.schoenwaelder@jacobs-university.de>";
+
+  description
+   "This module contains a collection of generally useful derived
+    YANG data types for Internet addresses and related things.
+
+    Copyright (c) 2013 IETF Trust and the persons identified as
+    authors of the code.  All rights reserved.
+
+    Redistribution and use in source and binary forms, with or
+    without modification, is permitted pursuant to, and subject
+    to the license terms contained in, the Simplified BSD License
+    set forth in Section 4.c of the IETF Trust's Legal Provisions
+    Relating to IETF Documents
+    (http://trustee.ietf.org/license-info).
+
+    This version of this YANG module is part of RFC 6991; see
+    the RFC itself for full legal notices.";
+
+  revision 2013-07-15 {
+    description
+     "This revision adds the following new data types:
+      - ip-address-no-zone
+      - ipv4-address-no-zone
+      - ipv6-address-no-zone";
+    reference
+     "RFC 6991: Common YANG Data Types";
+  }
+
+  revision 2010-09-24 {
+    description
+     "Initial revision.";
+    reference
+     "RFC 6021: Common YANG Data Types";
+  }
+
+  /*** collection of types related to protocol fields ***/
+
+  typedef ip-version {
+    type enumeration {
+      enum unknown {
+        value "0";
+        description
+         "An unknown or unspecified version of the Internet
+          protocol.";
+      }
+      enum ipv4 {
+        value "1";
+        description
+         "The IPv4 protocol as defined in RFC 791.";
+      }
+      enum ipv6 {
+        value "2";
+        description
+         "The IPv6 protocol as defined in RFC 2460.";
+      }
+    }
+    description
+     "This value represents the version of the IP protocol.
+
+      In the value set and its semantics, this type is equivalent
+      to the InetVersion textual convention of the SMIv2.";
+    reference
+     "RFC  791: Internet Protocol
+      RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+      RFC 4001: Textual Conventions for Internet Network Addresses";
+  }
+
+  typedef dscp {
+    type uint8 {
+      range "0..63";
+    }
+    description
+     "The dscp type represents a Differentiated Services Code Point
+      that may be used for marking packets in a traffic stream.
+      In the value set and its semantics, this type is equivalent
+      to the Dscp textual convention of the SMIv2.";
+    reference
+     "RFC 3289: Management Information Base for the Differentiated
+                Services Architecture
+      RFC 2474: Definition of the Differentiated Services Field
+                (DS Field) in the IPv4 and IPv6 Headers
+      RFC 2780: IANA Allocation Guidelines For Values In
+                the Internet Protocol and Related Headers";
+  }
+
+  typedef ipv6-flow-label {
+    type uint32 {
+      range "0..1048575";
+    }
+    description
+     "The ipv6-flow-label type represents the flow identifier or Flow
+      Label in an IPv6 packet header that may be used to
+      discriminate traffic flows.
+
+      In the value set and its semantics, this type is equivalent
+      to the IPv6FlowLabel textual convention of the SMIv2.";
+    reference
+     "RFC 3595: Textual Conventions for IPv6 Flow Label
+      RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+  }
+
+  typedef port-number {
+    type uint16 {
+      range "0..65535";
+    }
+    description
+     "The port-number type represents a 16-bit port number of an
+      Internet transport-layer protocol such as UDP, TCP, DCCP, or
+      SCTP.  Port numbers are assigned by IANA.  A current list of
+      all assignments is available from <http://www.iana.org/>.
+
+      Note that the port number value zero is reserved by IANA.  In
+      situations where the value zero does not make sense, it can
+      be excluded by subtyping the port-number type.
+      In the value set and its semantics, this type is equivalent
+      to the InetPortNumber textual convention of the SMIv2.";
+    reference
+     "RFC  768: User Datagram Protocol
+      RFC  793: Transmission Control Protocol
+      RFC 4960: Stream Control Transmission Protocol
+      RFC 4340: Datagram Congestion Control Protocol (DCCP)
+      RFC 4001: Textual Conventions for Internet Network Addresses";
+  }
+
+  /*** collection of types related to autonomous systems ***/
+
+  typedef as-number {
+    type uint32;
+    description
+     "The as-number type represents autonomous system numbers
+      which identify an Autonomous System (AS).  An AS is a set
+      of routers under a single technical administration, using
+      an interior gateway protocol and common metrics to route
+      packets within the AS, and using an exterior gateway
+      protocol to route packets to other ASes.  IANA maintains
+      the AS number space and has delegated large parts to the
+      regional registries.
+
+      Autonomous system numbers were originally limited to 16
+      bits.  BGP extensions have enlarged the autonomous system
+      number space to 32 bits.  This type therefore uses an uint32
+      base type without a range restriction in order to support
+      a larger autonomous system number space.
+
+      In the value set and its semantics, this type is equivalent
+      to the InetAutonomousSystemNumber textual convention of
+      the SMIv2.";
+    reference
+     "RFC 1930: Guidelines for creation, selection, and registration
+                of an Autonomous System (AS)
+      RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+      RFC 4001: Textual Conventions for Internet Network Addresses
+      RFC 6793: BGP Support for Four-Octet Autonomous System (AS)
+                Number Space";
+  }
+
+  /*** collection of types related to IP addresses and hostnames ***/
+
+  typedef ip-address {
+    type union {
+      type inet:ipv4-address;
+      type inet:ipv6-address;
+    }
+    description
+     "The ip-address type represents an IP address and is IP
+      version neutral.  The format of the textual representation
+      implies the IP version.  This type supports scoped addresses
+      by allowing zone identifiers in the address format.";
+    reference
+     "RFC 4007: IPv6 Scoped Address Architecture";
+  }
+
+  typedef ipv4-address {
+    type string {
+      pattern
+        '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+      +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+      + '(%[\p{N}\p{L}]+)?';
+    }
+    description
+      "The ipv4-address type represents an IPv4 address in
+       dotted-quad notation.  The IPv4 address may include a zone
+       index, separated by a % sign.
+
+       The zone index is used to disambiguate identical address
+       values.  For link-local addresses, the zone index will
+       typically be the interface index number or the name of an
+       interface.  If the zone index is not present, the default
+       zone of the device will be used.
+
+       The canonical format for the zone index is the numerical
+       format";
+  }
+
+  typedef ipv6-address {
+    type string {
+      pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+            + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+            + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+            + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+            + '(%[\p{N}\p{L}]+)?';
+      pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+            + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+            + '(%.+)?';
+    }
+    description
+     "The ipv6-address type represents an IPv6 address in full,
+      mixed, shortened, and shortened-mixed notation.  The IPv6
+      address may include a zone index, separated by a % sign.
+
+      The zone index is used to disambiguate identical address
+      values.  For link-local addresses, the zone index will
+      typically be the interface index number or the name of an
+      interface.  If the zone index is not present, the default
+      zone of the device will be used.
+
+      The canonical format of IPv6 addresses uses the textual
+      representation defined in Section 4 of RFC 5952.  The
+      canonical format for the zone index is the numerical
+      format as described in Section 11.2 of RFC 4007.";
+    reference
+     "RFC 4291: IP Version 6 Addressing Architecture
+      RFC 4007: IPv6 Scoped Address Architecture
+      RFC 5952: A Recommendation for IPv6 Address Text
+                Representation";
+  }
+
+  typedef ip-address-no-zone {
+    type union {
+      type inet:ipv4-address-no-zone;
+      type inet:ipv6-address-no-zone;
+    }
+    description
+     "The ip-address-no-zone type represents an IP address and is
+      IP version neutral.  The format of the textual representation
+      implies the IP version.  This type does not support scoped
+      addresses since it does not allow zone identifiers in the
+      address format.";
+    reference
+     "RFC 4007: IPv6 Scoped Address Architecture";
+  }
+
+  typedef ipv4-address-no-zone {
+    type inet:ipv4-address {
+      pattern '[0-9\.]*';
+    }
+    description
+      "An IPv4 address without a zone index.  This type, derived from
+       ipv4-address, may be used in situations where the zone is
+       known from the context and hence no zone index is needed.";
+  }
+
+  typedef ipv6-address-no-zone {
+    type inet:ipv6-address {
+      pattern '[0-9a-fA-F:\.]*';
+    }
+    description
+      "An IPv6 address without a zone index.  This type, derived from
+       ipv6-address, may be used in situations where the zone is
+       known from the context and hence no zone index is needed.";
+    reference
+     "RFC 4291: IP Version 6 Addressing Architecture
+      RFC 4007: IPv6 Scoped Address Architecture
+      RFC 5952: A Recommendation for IPv6 Address Text
+                Representation";
+  }
+
+  typedef ip-prefix {
+    type union {
+      type inet:ipv4-prefix;
+      type inet:ipv6-prefix;
+    }
+    description
+     "The ip-prefix type represents an IP prefix and is IP
+      version neutral.  The format of the textual representations
+      implies the IP version.";
+  }
+
+  typedef ipv4-prefix {
+    type string {
+      pattern
+         '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+       +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+       + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+    }
+    description
+     "The ipv4-prefix type represents an IPv4 address prefix.
+      The prefix length is given by the number following the
+      slash character and must be less than or equal to 32.
+
+      A prefix length value of n corresponds to an IP address
+      mask that has n contiguous 1-bits from the most
+      significant bit (MSB) and all other bits set to 0.
+
+      The canonical format of an IPv4 prefix has all bits of
+      the IPv4 address set to zero that are not part of the
+      IPv4 prefix.";
+  }
+
+  typedef ipv6-prefix {
+    type string {
+      pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+            + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+            + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+            + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+            + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+      pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+            + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+            + '(/.+)';
+    }
+    description
+     "The ipv6-prefix type represents an IPv6 address prefix.
+      The prefix length is given by the number following the
+      slash character and must be less than or equal to 128.
+
+      A prefix length value of n corresponds to an IP address
+      mask that has n contiguous 1-bits from the most
+      significant bit (MSB) and all other bits set to 0.
+
+      The IPv6 address should have all bits that do not belong
+      to the prefix set to zero.
+
+      The canonical format of an IPv6 prefix has all bits of
+      the IPv6 address set to zero that are not part of the
+      IPv6 prefix.  Furthermore, the IPv6 address is represented
+      as defined in Section 4 of RFC 5952.";
+    reference
+     "RFC 5952: A Recommendation for IPv6 Address Text
+                Representation";
+  }
+
+  /*** collection of domain name and URI types ***/
+
+  typedef domain-name {
+    type string {
+      pattern
+        '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+      + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+      + '|\.';
+      length "1..253";
+    }
+    description
+     "The domain-name type represents a DNS domain name.  The
+      name SHOULD be fully qualified whenever possible.
+
+      Internet domain names are only loosely specified.  Section
+      3.5 of RFC 1034 recommends a syntax (modified in Section
+      2.1 of RFC 1123).  The pattern above is intended to allow
+      for current practice in domain name use, and some possible
+      future expansion.  It is designed to hold various types of
+      domain names, including names used for A or AAAA records
+      (host names) and other records, such as SRV records.  Note
+      that Internet host names have a stricter syntax (described
+      in RFC 952) than the DNS recommendations in RFCs 1034 and
+      1123, and that systems that want to store host names in
+      schema nodes using the domain-name type are recommended to
+      adhere to this stricter standard to ensure interoperability.
+
+      The encoding of DNS names in the DNS protocol is limited
+      to 255 characters.  Since the encoding consists of labels
+      prefixed by a length bytes and there is a trailing NULL
+      byte, only 253 characters can appear in the textual dotted
+      notation.
+
+      The description clause of schema nodes using the domain-name
+      type MUST describe when and how these names are resolved to
+      IP addresses.  Note that the resolution of a domain-name value
+      may require to query multiple DNS records (e.g., A for IPv4
+      and AAAA for IPv6).  The order of the resolution process and
+      which DNS record takes precedence can either be defined
+      explicitly or may depend on the configuration of the
+      resolver.
+
+      Domain-name values use the US-ASCII encoding.  Their canonical
+      format uses lowercase US-ASCII characters.  Internationalized
+      domain names MUST be A-labels as per RFC 5890.";
+    reference
+     "RFC  952: DoD Internet Host Table Specification
+      RFC 1034: Domain Names - Concepts and Facilities
+      RFC 1123: Requirements for Internet Hosts -- Application
+                and Support
+      RFC 2782: A DNS RR for specifying the location of services
+                (DNS SRV)
+      RFC 5890: Internationalized Domain Names in Applications
+                (IDNA): Definitions and Document Framework";
+  }
+
+  typedef host {
+    type union {
+      type inet:ip-address;
+      type inet:domain-name;
+    }
+    description
+     "The host type represents either an IP address or a DNS
+      domain name.";
+  }
+
+  typedef uri {
+    type string;
+    description
+     "The uri type represents a Uniform Resource Identifier
+      (URI) as defined by STD 66.
+
+      Objects using the uri type MUST be in US-ASCII encoding,
+      and MUST be normalized as described by RFC 3986 Sections
+      6.2.1, 6.2.2.1, and 6.2.2.2.  All unnecessary
+      percent-encoding is removed, and all case-insensitive
+      characters are set to lowercase except for hexadecimal
+      digits, which are normalized to uppercase as described in
+      Section 6.2.2.1.
+
+      The purpose of this normalization is to help provide
+      unique URIs.  Note that this normalization is not
+      sufficient to provide uniqueness.  Two URIs that are
+      textually distinct after this normalization may still be
+      equivalent.
+
+      Objects using the uri type may restrict the schemes that
+      they permit.  For example, 'data:' and 'urn:' schemes
+      might not be appropriate.
+
+      A zero-length URI is not a valid URI.  This can be used to
+      express 'URI absent' where required.
+
+      In the value set and its semantics, this type is equivalent
+      to the Uri SMIv2 textual convention defined in RFC 5017.";
+    reference
+     "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+      RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+                Group: Uniform Resource Identifiers (URIs), URLs,
+                and Uniform Resource Names (URNs): Clarifications
+                and Recommendations
+      RFC 5017: MIB Textual Conventions for Uniform Resource
+                Identifiers (URIs)";
+  }
+
+}
diff --git a/netconf/netconf-console/src/test/resources/schemas/netconf-node-topology.yang b/netconf/netconf-console/src/test/resources/schemas/netconf-node-topology.yang
new file mode 100644 (file)
index 0000000..62b88b9
--- /dev/null
@@ -0,0 +1,243 @@
+module netconf-node-topology {
+    namespace "urn:opendaylight:netconf-node-topology";
+    prefix "nettop";
+
+    import network-topology { prefix nt; revision-date 2013-10-21; }
+    import yang-ext { prefix ext; revision-date "2013-07-09";}
+    import ietf-inet-types { prefix inet; revision-date "2013-07-15"; }
+
+    revision "2015-01-14" {
+        description "Initial revision of Topology model";
+    }
+
+    augment "/nt:network-topology/nt:topology/nt:topology-types" {
+        container topology-netconf {
+        }
+    }
+
+    grouping netconf-node-credentials {
+
+        choice credentials {
+            config true;
+            case login-password {
+                leaf username {
+                    type string;
+                }
+
+                leaf password {
+                    type string;
+                }
+            }
+        }
+    }
+
+    grouping netconf-node-connection-parameters {
+
+        leaf host {
+            type inet:host;
+        }
+
+        leaf port {
+            type inet:port-number;
+        }
+
+        leaf tcp-only {
+            config true;
+            type boolean;
+        }
+
+        leaf schemaless {
+            type boolean;
+            default false;
+        }
+
+        container yang-module-capabilities {
+            config true;
+            leaf override {
+                type boolean;
+                default false;
+                description "Whether to override or merge this list of capabilities with capabilities from device";
+            }
+
+            leaf-list capability {
+                type string;
+                description "Set a list of capabilities to override capabilities provided in device's hello message.
+                             Can be used for devices that do not report any yang modules in their hello message";
+            }
+        }
+
+        leaf reconnect-on-changed-schema {
+            config true;
+            type boolean;
+            default false;
+            description "If true, the connector would auto disconnect/reconnect when schemas are changed in the remote device.
+                         The connector subscribes (right after connect) to base netconf notifications and listens for netconf-capability-change notification";
+        }
+
+        leaf connection-timeout-millis {
+            description "Specifies timeout in milliseconds after which connection must be established.";
+            config true;
+            type uint32;
+            default 20000;
+        }
+
+        leaf default-request-timeout-millis {
+            description "Timeout for blocking operations within transactions.";
+            config true;
+            type uint32;
+            default 60000;
+        }
+
+        leaf max-connection-attempts {
+            description "Maximum number of connection retries. Non positive value or null is interpreted as infinity.";
+            config true;
+            type uint32;
+            default 0; // retry forever
+        }
+
+        leaf between-attempts-timeout-millis {
+            description "Initial timeout in milliseconds to wait between connection attempts. Will be multiplied by sleep-factor with every additional attempt";
+            config true;
+            type uint16;
+            default 2000;
+        }
+
+        leaf sleep-factor {
+            config true;
+            type decimal64 {
+                fraction-digits 1;
+            }
+            default 1.5;
+        }
+
+        // Keepalive configuration
+        leaf keepalive-delay {
+            config true;
+            type uint32;
+            default 120;
+            description "Netconf connector sends keepalive RPCs while the session is idle, this delay specifies the delay between keepalive RPC in seconds
+                         If a value <1 is provided, no keepalives will be sent";
+        }
+
+        leaf concurrent-rpc-limit {
+            config true;
+            type uint16;
+            default 0;
+            description "Limit of concurrent messages that can be send before reply messages are received.
+                         If value <1 is provided, no limit will be enforced";
+        }
+    }
+
+    grouping netconf-node-connection-status {
+
+        leaf connection-status {
+            config false;
+            type enumeration {
+                enum connecting;
+                enum connected;
+                enum unable-to-connect;
+            }
+        }
+
+        container clustered-connection-status {
+            config false;
+            list node-status {
+                leaf node {
+                    type string;
+                }
+                leaf status {
+                    type enumeration {
+                        enum connected;
+                        enum unavailable;
+                        enum failed;
+                    }
+                }
+            }
+        }
+
+        leaf connected-message {
+            config false;
+            type string;
+        }
+
+        container available-capabilities {
+            config false;
+            leaf-list available-capability {
+                type string;
+            }
+        }
+
+        container unavailable-capabilities {
+            config false;
+            list unavailable-capability {
+                leaf capability {
+                    type string;
+                }
+
+                leaf failure-reason {
+                    type enumeration {
+                        enum missing-source;
+                        enum unable-to-resolve;
+                    }
+                }
+            }
+        }
+
+        container pass-through {
+            when "../connection-status = connected";
+            description
+                "When the underlying node is connected, its NETCONF context
+                is available verbatim under this container through the
+                mount extension.";
+        }
+
+    }
+
+    grouping netconf-schema-storage {
+        leaf schema-cache-directory {
+            config true;
+            type string;
+            default "schema";
+            description "The destination schema repository for yang files relative to the cache directory.  This may be specified per netconf mount
+                         so that the loaded yang files are stored to a distinct directory to avoid potential conflict.";
+        }
+
+        container yang-library {
+            leaf yang-library-url {
+                config true;
+                type inet:uri;
+                description "Yang library to be plugged as additional source provider into the shared schema repository";
+            }
+
+            // credentials for basic http authentication
+            leaf username {
+                config true;
+                type string;
+            }
+
+            leaf password {
+                config true;
+                type string;
+            }
+        }
+    }
+
+    grouping netconf-node-fields {
+
+        uses netconf-node-credentials;
+
+        uses netconf-node-connection-parameters;
+
+        uses netconf-node-connection-status;
+
+        uses netconf-schema-storage;
+
+    }
+
+    augment "/nt:network-topology/nt:topology/nt:node" {
+        when "../../nt:topology-types/topology-netconf";
+        ext:augment-identifier "netconf-node";
+
+        uses netconf-node-fields;
+    }
+}
diff --git a/netconf/netconf-console/src/test/resources/schemas/network-topology@2013-10-21.yang b/netconf/netconf-console/src/test/resources/schemas/network-topology@2013-10-21.yang
new file mode 100644 (file)
index 0000000..dc5dcad
--- /dev/null
@@ -0,0 +1,339 @@
+module network-topology  {
+    yang-version 1;
+    namespace "urn:TBD:params:xml:ns:yang:network-topology";
+    // replace with IANA namespace when assigned
+    prefix "nt";
+
+    import ietf-inet-types { prefix "inet"; revision-date 2013-07-15; }
+
+    organization "TBD";
+
+    contact "WILL-BE-DEFINED-LATER";
+
+    description
+        "This module defines a model for the topology of a network.
+        Key design decisions are as follows:
+        A topology consists of a set of nodes and links.
+        Links are point-to-point and unidirectional.
+        Bidirectional connections need to be represented through
+        two separate links.
+        Multipoint connections, broadcast domains etc can be represented
+        through a hierarchy of nodes, then connecting nodes at
+        upper layers of the hierarchy.";
+
+    revision 2013-10-21 {
+        description
+            "Initial revision.";
+    }
+
+    typedef topology-id {
+        type inet:uri;
+        description
+            "An identifier for a topology.";
+    }
+
+    typedef node-id {
+        type inet:uri;
+        description
+            "An identifier for a node in a topology.
+            The identifier may be opaque.
+            The identifier SHOULD be chosen such that the same node in a
+            real network topology will always be identified through the
+            same identifier, even if the model is instantiated in separate
+            datastores. An implementation MAY choose to capture semantics
+            in the identifier, for example to indicate the type of node
+            and/or the type of topology that the node is a part of.";
+    }
+
+
+    typedef link-id {
+        type inet:uri;
+        description
+            "An identifier for a link in a topology.
+            The identifier may be opaque.
+            The identifier SHOULD be chosen such that the same link in a
+            real network topology will always be identified through the
+            same identifier, even if the model is instantiated in separate
+            datastores. An implementation MAY choose to capture semantics
+            in the identifier, for example to indicate the type of link
+            and/or the type of topology that the link is a part of.";
+    }
+
+    typedef tp-id {
+        type inet:uri;
+        description
+            "An identifier for termination points on a node.
+            The identifier may be opaque.
+            The identifier SHOULD be chosen such that the same TP in a
+            real network topology will always be identified through the
+            same identifier, even if the model is instantiated in separate
+            datastores. An implementation MAY choose to capture semantics
+            in the identifier, for example to indicate the type of TP
+            and/or the type of node and topology that the TP is a part of.";
+    }
+
+    typedef tp-ref {
+        type leafref {
+            path "/network-topology/topology/node/termination-point/tp-id";
+        }
+        description
+            "A type for an absolute reference to a termination point.
+            (This type should not be used for relative references.
+            In such a case, a relative path should be used instead.)";
+    }
+    typedef topology-ref {
+        type leafref {
+            path "/network-topology/topology/topology-id";
+        }
+        description
+            "A type for an absolute reference a topology instance.";
+    }
+
+    typedef node-ref {
+        type leafref {
+            path "/network-topology/topology/node/node-id";
+        }
+        description
+
+            "A type for an absolute reference to a node instance.
+            (This type should not be used for relative references.
+            In such a case, a relative path should be used instead.)";
+    }
+
+    typedef link-ref {
+        type leafref {
+            path "/network-topology/topology/link/link-id";
+        }
+        description
+            "A type for an absolute reference a link instance.
+            (This type should not be used for relative references.
+            In such a case, a relative path should be used instead.)";
+    }
+
+    grouping tp-attributes {
+        description
+            "The data objects needed to define a termination point.
+            (This only includes a single leaf at this point, used
+            to identify the termination point.)
+            Provided in a grouping so that in addition to the datastore,
+            the data can also be included in notifications.";
+        leaf tp-id {
+            type tp-id;
+        }
+        leaf-list tp-ref {
+            type tp-ref;
+            config false;
+            description
+                "The leaf list identifies any termination points that the
+                termination point is dependent on, or maps onto.
+                Those termination points will themselves be contained
+                in a supporting node.
+                This dependency information can be inferred from
+                the dependencies between links.  For this reason,
+                this item is not separately configurable.  Hence no
+                corresponding constraint needs to be articulated.
+                The corresponding information is simply provided by the
+                implementing system.";
+        }
+    }
+
+    grouping node-attributes {
+        description
+            "The data objects needed to define a node.
+            The objects are provided in a grouping so that in addition to
+            the datastore, the data can also be included in notifications
+            as needed.";
+
+        leaf node-id {
+            type node-id;
+            description
+                "The identifier of a node in the topology.
+                A node is specific to a topology to which it belongs.";
+        }
+        list supporting-node {
+            description
+                "This list defines vertical layering information for nodes.
+                It allows to capture for any given node, which node (or nodes)
+                in the corresponding underlay topology it maps onto.
+                A node can map to zero, one, or more nodes below it;
+                accordingly there can be zero, one, or more elements in the list.
+                If there are specific layering requirements, for example
+                specific to a particular type of topology that only allows
+                for certain layering relationships, the choice
+                below can be augmented with additional cases.
+                A list has been chosen rather than a leaf-list in order
+                to provide room for augmentations, e.g. for
+                statistics or priorization information associated with
+                supporting nodes.";
+            // This is not what was published in the initial draft,
+            // added topology-ref leaf and added it to the key
+            key "topology-ref node-ref";
+            leaf topology-ref {
+                type topology-ref;
+            }
+            leaf node-ref {
+                type node-ref;
+            }
+        }
+    }
+
+    grouping link-attributes {
+        // This is a grouping, not defined inline with the link definition itself,
+        // so it can be included in a notification, if needed
+        leaf link-id {
+            type link-id;
+            description
+                "The identifier of a link in the topology.
+                A link is specific to a topology to which it belongs.";
+        }
+        container source {
+            leaf source-node {
+                mandatory true;
+                type node-ref;
+                description
+                    "Source node identifier, must be in same topology.";
+            }
+            leaf source-tp {
+                type tp-ref;
+                description
+                    "Termination point within source node that terminates the link.";
+
+            }
+        }
+        container destination {
+            leaf dest-node {
+                mandatory true;
+                type node-ref;
+                description
+                    "Destination node identifier, must be in same topology.";
+            }
+            leaf dest-tp {
+                type tp-ref;
+                description
+                    "Termination point within destination node that terminates the link.";
+            }
+        }
+        list supporting-link {
+            key "link-ref";
+            leaf link-ref {
+                type link-ref;
+            }
+        }
+    }
+
+
+    container network-topology {
+        list topology {
+            description "
+                This is the model of an abstract topology.
+                A topology contains nodes and links.
+                Each topology MUST be identified by
+                unique topology-id for reason that a network could contain many
+                topologies.
+            ";
+            key "topology-id";
+            leaf topology-id {
+                type topology-id;
+                description "
+                    It is presumed that a datastore will contain many topologies. To
+                    distinguish between topologies it is vital to have UNIQUE
+                    topology identifiers.
+                ";
+            }
+            leaf server-provided {
+                type boolean;
+                config false;
+                description "
+                    Indicates whether the topology is configurable by clients,
+                    or whether it is provided by the server.  This leaf is
+
+                    populated by the server implementing the model.
+                    It is set to false for topologies that are created by a client;
+                    it is set to true otherwise.  If it is set to true, any
+                    attempt to edit the topology MUST be rejected.
+                ";
+            }
+            container topology-types {
+                description
+                    "This container is used to identify the type, or types
+                    (as a topology can support several types simultaneously),
+                    of the topology.
+                    Topology types are the subject of several integrity constraints
+                    that an implementing server can validate in order to
+                    maintain integrity of the datastore.
+                    Topology types are indicated through separate data nodes;
+                    the set of topology types is expected to increase over time.
+                    To add support for a new topology, an augmenting module
+                    needs to augment this container with a new empty optional
+                    container to indicate the new topology type.
+                    The use of a container allows to indicate a subcategorization
+                    of topology types.
+                    The container SHALL NOT be augmented with any data nodes
+                    that serve a purpose other than identifying a particular
+                    topology type.
+                ";
+            }
+            list underlay-topology {
+                key "topology-ref";
+                leaf topology-ref {
+                    type topology-ref;
+                }
+                // a list, not a leaf-list, to allow for potential augmentation
+                // with properties specific to the underlay topology,
+                // such as statistics, preferences, or cost.
+                description
+                    "Identifies the topology, or topologies, that this topology
+                    is dependent on.";
+            }
+
+            list node {
+                description "The list of network nodes defined for the topology.";
+                key "node-id";
+                uses node-attributes;
+                must "boolean(../underlay-topology[*]/node[./supporting-nodes/node-ref])";
+                    // This constraint is meant to ensure that a referenced node is in fact
+                    // a node in an underlay topology.
+                list termination-point {
+                    description
+
+                        "A termination point can terminate a link.
+                        Depending on the type of topology, a termination point could,
+                        for example, refer to a port or an interface.";
+                    key "tp-id";
+                    uses tp-attributes;
+                }
+            }
+
+            list link {
+                description "
+                    A Network Link connects a by Local (Source) node and
+                    a Remote (Destination) Network Nodes via a set of the
+                    nodes' termination points.
+                    As it is possible to have several links between the same
+                    source and destination nodes, and as a link could potentially
+                    be re-homed between termination points, to ensure that we
+                    would always know to distinguish between links, every link
+                    is identified by a dedicated link identifier.
+                    Note that a link models a point-to-point link, not a multipoint
+                    link.
+                    Layering dependencies on links in underlay topologies are
+                    not represented as the layering information of nodes and of
+                    termination points is sufficient.
+                ";
+                key "link-id";
+                uses link-attributes;
+                must "boolean(../underlay-topology/link[./supporting-link])";
+                    // Constraint: any supporting link must be part of an underlay topology
+                must "boolean(../node[./source/source-node])";
+                    // Constraint: A link must have as source a node of the same topology
+                must "boolean(../node[./destination/dest-node])";
+                    // Constraint: A link must have as source a destination of the same topology
+                must "boolean(../node/termination-point[./source/source-tp])";
+                    // Constraint: The source termination point must be contained in the source node
+                must "boolean(../node/termination-point[./destination/dest-tp])";
+                    // Constraint: The destination termination point must be contained
+                    // in the destination node
+            }
+        }
+    }
+}
diff --git a/netconf/netconf-console/src/test/resources/schemas/yang-ext.yang b/netconf/netconf-console/src/test/resources/schemas/yang-ext.yang
new file mode 100644 (file)
index 0000000..0fbe94d
--- /dev/null
@@ -0,0 +1,79 @@
+module yang-ext {
+    yang-version 1;
+    namespace "urn:opendaylight:yang:extension:yang-ext";
+    prefix "ext";
+    
+    contact "Anton Tkacik <ttkacik@cisco.com>";
+
+    description 
+            "Copyright (c) 2013 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";
+
+    revision "2013-07-09" {
+        description "";
+    }
+
+    // Augmentation name
+
+    extension "augment-identifier" {
+        description 
+           "YANG language extension which assigns an identifier to 
+            augmentation. Augment identifier is used to identify
+            specific augment statement by name. 
+
+            The identifier syntax is defined formally defined by the rule
+            'identifier' in Section 12 of RFC 6020.
+
+            All augment identifiers defined in a namespace MUST be unique.
+            The namespace of augment identifiers is shared by module and
+            its submodules.";
+
+            /*
+                Discussion:
+                This extension allows for ease of development / debug
+                of YANG modules and it is suitable for code generation,
+                where each augment statement is nicely identified by
+                unique name instead of combination of augment target
+                and when condition. 
+            */
+        argument "identifier";
+    }
+
+
+    // Context-aware RPCs
+
+    grouping rpc-context-ref {
+        description 
+           "A reference to RPC context.";
+        leaf context-instance {
+            type instance-identifier;
+            description "Pointer to the context. ";
+        }
+    }
+
+    extension "rpc-context-instance" {
+        description
+           "YANG language extension which defines enclosing (parent) 
+            schema node as referencable context for RPCs.
+
+            The argument is identity which is used to identify RPC context
+            type.";
+
+        argument "context-type";
+    }
+
+    extension "context-reference" {
+        argument "context-type";
+    }
+
+    extension "context-instance" {
+        argument "context-type";
+    }
+    
+    extension "instance-target" {
+       argument "path";
+    }
+}