* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.restconf.rest;
+package org.opendaylight.restconf;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
import org.opendaylight.controller.sal.core.api.Broker;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
-import org.opendaylight.restconf.RestConnectorProvider;
import org.opendaylight.restconf.handlers.SchemaContextHandler;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
* 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.restconf.rest.impl.schema.context;
+
+package org.opendaylight.restconf.handlers;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
* 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.restconf.parser.builder;
+
+package org.opendaylight.restconf.parser;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
-import org.opendaylight.restconf.parser.IdentifierCodec;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.rest.services.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.ALLOWED_KEYWORDS;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.MOUNT_POINT;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.NOT_EXISTING_MODULE;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.NOT_EXISTING_MODULE_BEHIND_MOUNT_POINT;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.NOT_REGISTERED_MOUNT_POINT;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.TEST_MODULE;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.TEST_MODULE_BEHIND_MOUNT_POINT;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.TEST_MODULE_BEHIND_NOT_REGISTERED_MOUNT_POINT;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.getExpectedModules;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.getExpectedModulesBehindMountPoint;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupCustomRestconfModule;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupCustomRestconfModuleMountPoint;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupMissingRestconfModule;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupMissingRestconfModuleMountPoint;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupNormal;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupNormalMountPoint;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.setupNullMountPointService;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.verifyModule;
+import static org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.verifyModules;
+
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
+import org.opendaylight.restconf.Draft11.RestconfModule;
+import org.opendaylight.restconf.handlers.DOMMountPointServiceHandler;
+import org.opendaylight.restconf.handlers.SchemaContextHandler;
+import org.opendaylight.restconf.rest.services.api.RestconfModulesService;
+import org.opendaylight.restconf.rest.services.impl.RestconfModulesServiceTestUtils.TestModule;
+import org.opendaylight.restconf.utils.RestconfConstants;
+import org.opendaylight.restconf.utils.mapping.RestconfMappingNodeConstants;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableDataContainerAttrNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+/**
+ * Unit tests of the {@link RestconfModulesServiceImpl}
+ *
+ */
+public class RestconfModulesServiceTest {
+ @Rule public ExpectedException thrown = ExpectedException.none();
+
+ /**
+ * Test non-null init of {@link RestconfModulesServiceImpl}.
+ */
+ @Test
+ public void restconfModulesServiceImplInitTest() {
+ assertNotNull("Modules service should be initialized and not null",
+ new RestconfModulesServiceImpl(mock(SchemaContextHandler.class),
+ mock(DOMMountPointServiceHandler.class)));
+ }
+
+ /**
+ * Test getting all modules supported by the server. Retrieved modules are verified by the name, namespace and
+ * revision.
+ */
+ @Test
+ public void getModulesTest() throws Exception {
+ // load schema context with testing modules and correct Restconf module
+ final RestconfModulesService modulesService = setupNormal();
+
+ // make test
+ final NormalizedNodeContext nodeContext = modulesService.getModules(null);
+
+ // check if expected modules were loaded
+ assertNotNull("Node context cannot be null", nodeContext);
+ final Collection<?> modules = (Collection<?>) ((ContainerNode) nodeContext .getData())
+ .getValue().iterator().next().getValue();
+ final Set<TestModule> loadedModules = new HashSet<>();
+
+ for (final Object node : modules) {
+ final Iterator mapEntries = ((AbstractImmutableDataContainerAttrNode) node).getChildren().entrySet()
+ .iterator();
+ final TestModule loadedModule = new TestModule();
+
+ while (mapEntries.hasNext()) {
+ final Entry e = ((SimpleImmutableEntry) mapEntries.next());
+ final String key = ((NodeIdentifier) e.getKey()).getNodeType().getLocalName();
+
+ assertTrue("Not allowed keyword", ALLOWED_KEYWORDS.contains(key));
+
+ switch (key) {
+ case RestconfMappingNodeConstants.NAME:
+ loadedModule.setName((String) ((LeafNode) e.getValue()).getValue());
+ break;
+ case RestconfMappingNodeConstants.NAMESPACE:
+ loadedModule.setNamespace((String) ((LeafNode) e.getValue()).getValue());
+ break;
+ case RestconfMappingNodeConstants.REVISION:
+ loadedModule.setRevision((String) ((LeafNode) e.getValue()).getValue());
+ break;
+ case RestconfMappingNodeConstants.FEATURE:
+ break;
+ }
+ }
+
+ loadedModules.add(loadedModule);
+ }
+
+ verifyModules(getExpectedModules(), loadedModules);
+ }
+
+ /**
+ * Test getting all modules supported by the mount point. Retrieved modules are verified by the name, namespace and
+ * revision.
+ */
+ @Test
+ public void getModulesMountPointTest() throws Exception {
+ // load testing modules and correct Restconf module behind mount point
+ final RestconfModulesService modulesService = setupNormalMountPoint();
+
+ // make test
+ final NormalizedNodeContext nodeContext = modulesService.getModules(MOUNT_POINT, null);
+
+ // check if expected modules were loaded, use module name as map key
+ assertNotNull("Node context cannot be null", nodeContext);
+ final Collection<?> modules = (Collection<?>) ((ContainerNode) nodeContext .getData())
+ .getValue().iterator().next().getValue();
+ final Set<TestModule> loadedModules = new HashSet<>();
+
+ for (final Object node : modules) {
+ final Iterator mapEntries = ((AbstractImmutableDataContainerAttrNode) node).getChildren().entrySet()
+ .iterator();
+ final TestModule loadedModule = new TestModule();
+
+ while (mapEntries.hasNext()) {
+ final Entry e = ((SimpleImmutableEntry) mapEntries.next());
+ final String key = ((NodeIdentifier) e.getKey()).getNodeType().getLocalName();
+
+ assertTrue("Not allowed keyword", ALLOWED_KEYWORDS.contains(key));
+
+ switch (key) {
+ case RestconfMappingNodeConstants.NAME:
+ loadedModule.setName((String) ((LeafNode) e.getValue()).getValue());
+ break;
+ case RestconfMappingNodeConstants.NAMESPACE:
+ loadedModule.setNamespace((String) ((LeafNode) e.getValue()).getValue());
+ break;
+ case RestconfMappingNodeConstants.REVISION:
+ loadedModule.setRevision((String) ((LeafNode) e.getValue()).getValue());
+ break;
+ case RestconfMappingNodeConstants.FEATURE:
+ break;
+ }
+ }
+
+ loadedModules.add(loadedModule);
+ }
+
+ verifyModules(getExpectedModulesBehindMountPoint(), loadedModules);
+ }
+
+ /**
+ * Test getting the specific module supported by the server. Module name, revision, namespace and features are
+ * compared to have expected values.
+ */
+ @Test
+ public void getModuleTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupNormal();
+
+ // get test module
+ final NormalizedNodeContext nodeContext = modulesService.getModule(TEST_MODULE, null);
+
+ // verify loaded module
+ assertNotNull("Node context cannot be null", nodeContext);
+ final MapEntryNode node = ((MapNode) nodeContext.getData()).getValue().iterator().next();
+ final Iterator mapEntries = ((AbstractImmutableDataContainerAttrNode) node).getChildren().entrySet().iterator();
+ verifyModule("module1", "module:1", "2014-01-01", Collections.emptySet(), mapEntries);
+ }
+
+ /**
+ * Test getting the specific module supported by the mount point.
+ */
+ @Test
+ public void getModuleMountPointTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupNormalMountPoint();
+
+ // get test module schemaContextBehindMountPoint mount point
+ final NormalizedNodeContext nodeContext = modulesService.getModule(TEST_MODULE_BEHIND_MOUNT_POINT, null);
+
+ // verify loaded module
+ assertNotNull("Node context cannot be null", nodeContext);
+ final MapEntryNode node = ((MapNode) nodeContext.getData()).getValue().iterator().next();
+ final Iterator mapEntries = ((AbstractImmutableDataContainerAttrNode) node).getChildren().entrySet().iterator();
+ verifyModule("module1-behind-mount-point", "module:1:behind:mount:point", "2014-02-03",
+ Collections.emptySet(), mapEntries);
+ }
+
+ /**
+ * Test getting all modules supported by the server if Restconf module is <code>null</code>. Test is expected to
+ * fail with <code>NullPointerException</code>.
+ */
+ @Test
+ public void getModulesWithoutRestconfModuleNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupMissingRestconfModule();
+
+ // make test
+ this.thrown.expect(NullPointerException.class);
+ modulesService.getModules(null);
+ }
+
+ /**
+ * Test getting all modules supported by the mount point if Restconf module is <code>null</code>. Test is expected
+ * to fail with <code>NullPointerException</code>.
+ */
+ @Test
+ public void getModulesWithoutRestconfModuleMountPointNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupMissingRestconfModuleMountPoint();
+
+ // make test
+ this.thrown.expect(NullPointerException.class);
+ modulesService.getModules(MOUNT_POINT, null);
+ }
+
+ /**
+ * Test getting all modules supported by the mount point with <code>null</code> value of
+ * identifier for mount point. Test is expected to fail with <code>NullPointerException</code>.
+ */
+ @Test
+ public void getModulesWithNullIdentifierOfMountPointNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupNormalMountPoint();
+
+ // make test
+ this.thrown.expect(NullPointerException.class);
+ modulesService.getModules(null, null);
+ }
+
+ /**
+ * Test getting all modules supported by the mount point if identifier does
+ * not contains {@link RestconfConstants#MOUNT}. Catching
+ * {@link RestconfDocumentedException} and testing error tyupe, error tag and error status code.
+ */
+ @Test
+ public void getModulesWithoutMountConstantInMountPointIdentifierNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupNormalMountPoint();
+
+ try {
+ modulesService.getModules(MOUNT_POINT.replace("/" + RestconfConstants.MOUNT + "/", ""), null);
+ fail("Test should fail due to missing " + RestconfConstants.MOUNT + " constant in mount point identifier");
+ } catch (final RestconfDocumentedException e) {
+ assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
+ assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
+ assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
+ }
+ }
+
+ /**
+ * Test getting all modules supported by the server when Restconf module does not contain node with name
+ * {@link RestconfModule#MODULES_CONTAINER_SCHEMA_NODE}. Test is expected to fail with
+ * <code>RestconfDocumentedException</code> and error type, error tag and error status code are compared to
+ * expected values.
+ */
+ @Test
+ public void getModulesRestconfModuleWithMissingContainerModulesNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupCustomRestconfModule(
+ "restconf-module-with-missing-container-modules");
+
+ // make test
+ try {
+ modulesService.getModules(null);
+ fail("Test should fail due to missing " + RestconfModule.MODULES_CONTAINER_SCHEMA_NODE
+ + " node in Restconf module");
+ } catch (final RestconfDocumentedException e) {
+ assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
+ assertEquals("Error tag is not correct", ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
+ assertEquals("Error status code is not correct", 404, e.getErrors().get(0).getErrorTag().getStatusCode());
+ }
+ }
+
+ /**
+ * Test getting all modules supported by the server when Restconf module contains node with name
+ * {@link RestconfModule#MODULES_CONTAINER_SCHEMA_NODE} but it is not of type {@link ContainerSchemaNode}. Test is
+ * expected to fail with <code>IllegalStateException</code>.
+ */
+ @Test
+ public void getModulesRestconfModuleWithIllegalContainerModulesNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupCustomRestconfModule(
+ "restconf-module-with-illegal-container-modules");
+
+ // make test
+ this.thrown.expect(IllegalStateException.class);
+ modulesService.getModules(null);
+ }
+
+ /**
+ * Test getting all modules supported by the mount point when Restconf module does not contain node with name
+ * {@link RestconfModule#MODULES_CONTAINER_SCHEMA_NODE}. Test is expected to fail with
+ * <code>RestconfDocumentedException</code> and error type, error tag and error status code are compared to
+ * expected values.
+ */
+ @Test
+ public void getModulesRestconfModuleWithMissingContainerModulesMountPointNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupCustomRestconfModuleMountPoint(
+ "restconf-module-with-missing-container-modules");
+
+ try {
+ modulesService.getModules(MOUNT_POINT, null);
+ fail("Test should fail due to missing " + RestconfModule.MODULES_CONTAINER_SCHEMA_NODE
+ + " node in Restconf module");
+ } catch (final RestconfDocumentedException e) {
+ assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
+ assertEquals("Error tag is not correct", ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
+ assertEquals("Error status code is not correct", 404, e.getErrors().get(0).getErrorTag().getStatusCode());
+ }
+ }
+
+ /**
+ * Test getting all modules supported by the mount point when Restconf module contains node with name
+ * {@link RestconfModule#MODULES_CONTAINER_SCHEMA_NODE} but it is not of type {@link ContainerSchemaNode}. Test
+ * is expected to fail with <code>IllegalStateException</code>.
+ */
+ @Test
+ public void getModulesRestconfModuleWithIllegalContainerModulesMountPointNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupCustomRestconfModuleMountPoint(
+ "restconf-module-with-illegal-container-modules");
+
+ // make test
+ this.thrown.expect(IllegalStateException.class);
+ modulesService.getModules(MOUNT_POINT, null);
+ }
+
+ /**
+ * Test of getting specific module supported by the server/mount point with <code>null</code> identifier. Test is
+ * expected to fail with <code>NullPointerException</code>.
+ */
+ @Test
+ public void getModuleWithNullIdentifierNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = spy(new RestconfModulesServiceImpl(
+ mock(SchemaContextHandler.class),
+ mock(DOMMountPointServiceHandler.class)));
+
+ // make test
+ this.thrown.expect(NullPointerException.class);
+ modulesService.getModule(null, null);
+ }
+
+ /**
+ * Testing getting specific module supported by the server with module identifier which
+ * does not exist in <code>SchemaContext</code>. Catching {@link RestconfDocumentedException}
+ * and testing error type, error tag and error status code.
+ */
+ @Test
+ public void getModuleNotExistModuleNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupNormal();
+
+ // make test
+ try {
+ modulesService.getModule(NOT_EXISTING_MODULE, null);
+ fail("Test should fail due to searching for not-existing module");
+ } catch (final RestconfDocumentedException e) {
+ assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
+ assertEquals("Error tag is not correct", ErrorTag.UNKNOWN_ELEMENT, e.getErrors().get(0).getErrorTag());
+ assertEquals("Error code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
+ }
+ }
+
+ /**
+ * Testing getting specific module supported by the mount point with module identifier which
+ * does not exist in <code>SchemaContext</code>. Catching {@link RestconfDocumentedException}
+ * and testing error type, error tag and error status code.
+ */
+ @Test
+ public void getModuleNotExistModuleMountPointNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupNormalMountPoint();
+
+ // make test
+ try {
+ modulesService.getModule(NOT_EXISTING_MODULE_BEHIND_MOUNT_POINT, null);
+ fail("Test should fail due to searching for not-existing module");
+ } catch (final RestconfDocumentedException e) {
+ assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
+ assertEquals("Error tag is not correct", ErrorTag.UNKNOWN_ELEMENT, e.getErrors().get(0).getErrorTag());
+ assertEquals("Error code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
+ }
+ }
+
+ /**
+ * Test getting specific module supported by the server when Restconf module is null. Test is expected to fail
+ * with <code>NullPointerException</code>.
+ */
+ @Test
+ public void getModuleWithoutRestconfModuleNegativeTest() throws Exception {
+ // prepare conditions
+ final RestconfModulesService modulesService = setupMissingRestconfModule();
+
+ this.thrown.expect(NullPointerException.class);
+ modulesService.getModule(TEST_MODULE, null);
+ }
+
+ /**
+ * Test getting specific module supported by the mount point when Restconf module is null. Test is expected to fail
+ * with <code>NullPointerException</code>.
+ */
+ @Test
+ public void getModuleWithoutRestconfModuleMountPointNegativeTest() throws Exception {
+ // prepare conditions
+ final RestconfModulesService modulesService = setupMissingRestconfModuleMountPoint();
+
+ this.thrown.expect(NullPointerException.class);
+ modulesService.getModule(TEST_MODULE_BEHIND_MOUNT_POINT, null);
+ }
+
+ /**
+ * Test getting specific module supported by the server when Restconf module does not contain node with
+ * name {@link RestconfModule#MODULE_LIST_SCHEMA_NODE}. Test is expected to fail with
+ * <code>RestconfDocumentedException</code> and error type, error tag and error status code are compared to
+ * expected values.
+ */
+ @Test
+ public void getModuleRestconfModuleWithMissingListModuleNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService =
+ setupCustomRestconfModule("restconf-module-with-missing-list-module");
+
+ // make test
+ try {
+ modulesService.getModule(TEST_MODULE, null);
+ fail("Test should fail due to missing " + RestconfModule.MODULE_LIST_SCHEMA_NODE
+ + " node in Restconf module");
+ } catch (final RestconfDocumentedException e) {
+ assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
+ assertEquals("Error tag is not correct", ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
+ assertEquals("Error code is not correct", 404, e.getErrors().get(0).getErrorTag().getStatusCode());
+ }
+ }
+
+ /**
+ * Test getting specific module supported by the server when Restconf module contains node with name
+ * {@link RestconfModule#MODULE_LIST_SCHEMA_NODE} but it is not of type {@link ListSchemaNode}. Test is expected
+ * to fail with <code>IllegalStateException</code>.
+ */
+ @Test
+ public void getModuleRestconfModuleWitIllegalListSchemaNodeNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupCustomRestconfModule(
+ "restconf-module-with-illegal-list-module");
+
+ // make test
+ this.thrown.expect(IllegalStateException.class);
+ modulesService.getModule(TEST_MODULE, null);
+ }
+
+ /**
+ * Test getting specific module supported by the mount point when Restconf module does not contain node with
+ * name {@link RestconfModule#MODULE_LIST_SCHEMA_NODE}. Test is expected to fail with
+ * <code>RestconfDocumentedException</code> and error type, error tag and error status code are compared to
+ * expected values.
+ */
+ @Test
+ public void getModuleRestconfModuleWithMissingListModuleMountPointNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService =
+ setupCustomRestconfModuleMountPoint("restconf-module-with-missing-list-module");
+
+ // make test
+ try {
+ modulesService.getModule(TEST_MODULE_BEHIND_MOUNT_POINT, null);
+ fail("Test should fail due to missing " + RestconfModule.MODULE_LIST_SCHEMA_NODE
+ + " node in Restconf module");
+ } catch (final RestconfDocumentedException e) {
+ assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
+ assertEquals("Error tag is not correct", ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
+ assertEquals("Error code is not correct", 404, e.getErrors().get(0).getErrorTag().getStatusCode());
+ }
+ }
+
+ /**
+ * Test getting specific module supported by the mount point when Restconf module contains node with name
+ * {@link RestconfModule#MODULE_LIST_SCHEMA_NODE} but it is not of type {@link ListSchemaNode}. Test is expected
+ * to fail with <code>IllegalStateException</code>.
+ */
+ @Test
+ public void getModuleRestconfModuleWitIllegalListModuleMountPointNegativeTest() throws Exception {
+ // prepare condition
+ final RestconfModulesService modulesService = setupCustomRestconfModuleMountPoint(
+ "restconf-module-with-illegal-list-module");
+
+ // make test
+ this.thrown.expect(IllegalStateException.class);
+ modulesService.getModule(TEST_MODULE_BEHIND_MOUNT_POINT, null);
+ }
+
+ /**
+ * Negative test of specific module supported by the mount point when <code>DOMMountPointServiceHandler</code>
+ * contains <code>null</code> reference to <code>DOMMountPointService</code>. Test is expected to fail with
+ * <code>NullPointerException</code>.
+ */
+ @Test
+ public void getModuleMissingMountPointServiceNegativeTest() throws Exception {
+ // prepare conditions
+ final RestconfModulesService modulesService = setupNullMountPointService();
+
+ // make test
+ this.thrown.expect(NullPointerException.class);
+ modulesService.getModule(TEST_MODULE_BEHIND_MOUNT_POINT, null);
+ }
+
+ /**
+ * Negative test of getting all modules supported by the mount point when <code>DOMMountPointServiceHandler</code>
+ * contains <code>null</code> reference to <code>DOMMountPointService</code>. Test is expected to fail with
+ * <code>NullPointerException</code>.
+ */
+ @Test
+ public void getModulesMissingMountPointServiceNegativeTest() throws Exception {
+ // prepare conditions
+ final RestconfModulesService modulesService = setupNullMountPointService();
+
+ // make test
+ this.thrown.expect(NullPointerException.class);
+ modulesService.getModules(MOUNT_POINT, null);
+ }
+
+ /**
+ * Negative test of getting specific module supported by the mount point when specified mount point is not found
+ * (it is not registered in <code>DOMMountPointService</code>). Test is expected to fail with
+ * <code>IllegalStateException</code>.
+ */
+ @Test
+ public void getModuleMountPointNotFoundNegativeTest() throws Exception {
+ // prepare conditions
+ final RestconfModulesService modulesService = setupNormalMountPoint();
+
+ // make test
+ this.thrown.expect(IllegalStateException.class);
+ modulesService.getModule(TEST_MODULE_BEHIND_NOT_REGISTERED_MOUNT_POINT, null);
+ }
+
+ /**
+ * Negative test of getting all modules supported by the mount point when specified mount point is not found (it
+ * is not registered in <code>DOMMountPointService</code>). Test is expected to fail with
+ * <code>IllegalStateException</code>.
+ */
+ @Test
+ public void getModulesMountPointNotFoundNegativeTest() throws Exception {
+ // prepare conditions
+ final RestconfModulesService modulesService = setupNormalMountPoint();
+
+ // make test
+ this.thrown.expect(IllegalStateException.class);
+ modulesService.getModules(NOT_REGISTERED_MOUNT_POINT, null);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.rest.services.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.ImmutableClassToInstanceMap;
+import com.google.common.collect.Maps;
+import java.io.File;
+import java.net.URI;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.dom.broker.impl.mount.DOMMountPointServiceImpl;
+import org.opendaylight.controller.md.sal.dom.broker.spi.mount.SimpleDOMMountPoint;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.restconf.Draft11;
+import org.opendaylight.restconf.handlers.DOMMountPointServiceHandler;
+import org.opendaylight.restconf.handlers.SchemaContextHandler;
+import org.opendaylight.restconf.utils.RestconfConstants;
+import org.opendaylight.restconf.utils.mapping.RestconfMappingNodeConstants;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
+import org.opendaylight.yangtools.yang.parser.util.NamedFileInputStream;
+
+class RestconfModulesServiceTestUtils {
+ static final String MOUNT_POINT = "/mount-point-1:cont/" + RestconfConstants.MOUNT + "/";
+ static final String NOT_REGISTERED_MOUNT_POINT = "/mount-point-1:listA/" + RestconfConstants.MOUNT + "/";
+
+ static final String TEST_MODULE = "module1/2014-01-01";
+ static final String NOT_EXISTING_MODULE = "not-existing/2016-01-01";
+
+ static final String TEST_MODULE_BEHIND_MOUNT_POINT = MOUNT_POINT
+ + "module1-behind-mount-point/2014-02-03";
+
+ static final String NOT_EXISTING_MODULE_BEHIND_MOUNT_POINT = MOUNT_POINT
+ + NOT_EXISTING_MODULE;
+
+ static final String TEST_MODULE_BEHIND_NOT_REGISTERED_MOUNT_POINT = NOT_REGISTERED_MOUNT_POINT
+ + "module1-behind-mount-point/2014-02-03";
+
+ // allowed leafs of list of modules
+ static final List<String> ALLOWED_KEYWORDS = Arrays.asList(
+ RestconfMappingNodeConstants.NAME, RestconfMappingNodeConstants.REVISION,
+ RestconfMappingNodeConstants.NAMESPACE, RestconfMappingNodeConstants.FEATURE);
+
+ static final String MODULES_PATH = "/modules";
+ static final String MODULES_WITHOUT_RESTCONF_MODULE_PATH = "/modules/modules-without-restconf-module";
+ static final String MOUNT_POINTS_PATH = "/modules/mount-points";
+ static final String MODULES_BEHIND_MOUNT_POINT_PATH = "/modules/modules-behind-mount-point";
+
+ static final String CUSTOM_RESTCONF_MODULES_PATH =
+ "/modules/restconf-module-testing/";
+ static final String CUSTOM_RESTCONF_MODULES_MOUNT_POINT_PATH =
+ "/modules/restconf-module-testing-mount-point/";
+
+ private RestconfModulesServiceTestUtils() { throw new UnsupportedOperationException("Util class"); }
+
+ /**
+ * Get all expected modules supported by the server
+ * @return <code>Set</code> of expected modules
+ * @throws Exception
+ */
+ static final Set<Module> getExpectedModules() throws Exception {
+ return TestRestconfUtils.loadSchemaContext(MODULES_PATH).getModules();
+ }
+
+ /**
+ * Get all expected modules behind mount point
+ * @return <code>Set</code> of expected modules
+ * @throws Exception
+ */
+ static final Set<Module> getExpectedModulesBehindMountPoint() throws Exception {
+ return TestRestconfUtils.loadSchemaContext(MODULES_BEHIND_MOUNT_POINT_PATH).getModules();
+ }
+
+ /**
+ * Verify if correct modules were loaded into Restconf module by comparison with expected modules.
+ * @param expectedModules Expected modules
+ * @param loadedModules Loaded modules into Restconf module
+ */
+ static final void verifyModules(final Set<Module> expectedModules, final Set<TestModule> loadedModules) {
+ final Set<TestModule> expectedModulesTransformed = new HashSet<>();
+ expectedModules.forEach((x) -> expectedModulesTransformed.add(
+ new TestModule(x.getName(), x.getNamespace(), x.getRevision())));
+ assertEquals("Loaded modules are not as expected", expectedModulesTransformed, loadedModules);
+ }
+
+ /**
+ * Verify id correct module was loaded into Restconf module by comparison of loaded and expected values of name,
+ * namespace, revision and features.
+ * @param expectedName Expected name
+ * @param expectedNamespace Expected namespace
+ * @param expectedRevision Expected revision
+ * @param expectedFeatures Expected features
+ * @param loadedModuleEntries Loaded values
+ */
+ static final void verifyModule(final String expectedName, final String expectedNamespace,
+ final String expectedRevision, final Set<Object> expectedFeatures,
+ final Iterator loadedModuleEntries) {
+ while (loadedModuleEntries.hasNext()) {
+ final Entry e = ((AbstractMap.SimpleImmutableEntry) loadedModuleEntries.next());
+ final String key = ((YangInstanceIdentifier.NodeIdentifier) e.getKey()).getNodeType().getLocalName();
+
+ assertTrue("Not allowed keyword", ALLOWED_KEYWORDS.contains(key));
+
+ switch (key) {
+ case RestconfMappingNodeConstants.NAME:
+ assertEquals("Not correct module was found",
+ expectedName, ((LeafNode) e.getValue()).getValue());
+ break;
+ case RestconfMappingNodeConstants.NAMESPACE:
+ assertEquals("Not correct module was found",
+ expectedNamespace, ((LeafNode) e.getValue()).getValue());
+ break;
+ case RestconfMappingNodeConstants.REVISION:
+ assertEquals("Not correct module was found",
+ expectedRevision, ((LeafNode) e.getValue()).getValue());
+ break;
+ case RestconfMappingNodeConstants.FEATURE:
+ assertEquals("Not correct module was found",
+ expectedFeatures, ((LeafSetNode) e.getValue()).getValue());
+ break;
+ }
+ }
+ }
+
+ /**
+ * Prepare <code>RestconfModulesServiceImpl</code> with <code>SchemaContext</code> containing correct Restconf
+ * module and testing modules supported by the server.
+ * @return <code>RestconfModulesServiceImpl</code>
+ * @throws Exception
+ */
+ static final RestconfModulesServiceImpl setupNormal() throws Exception {
+ final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class);
+ when(schemaContextHandler.get()).thenReturn(TestRestconfUtils.loadSchemaContext(MODULES_PATH));
+ return new RestconfModulesServiceImpl(schemaContextHandler, null);
+ }
+
+ /**
+ * Prepare <code>RestconfModulesServiceImpl</code> with <code>SchemaContext</code> containing correct Restconf
+ * module and testing modules behind mount point.
+ * @return <code>RestconfModulesServiceImpl</code>
+ * @throws Exception
+ */
+ static final RestconfModulesServiceImpl setupNormalMountPoint() throws Exception {
+ final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class);
+
+ final Collection<File> yangFiles = TestRestconfUtils.loadFiles(MODULES_PATH);
+ yangFiles.addAll(TestRestconfUtils.loadFiles(MOUNT_POINTS_PATH));
+ when(schemaContextHandler.get()).thenReturn(TestRestconfUtils.parseYangSources(yangFiles));
+
+ final DOMMountPointServiceHandler mountPointServiceHandler = mock(DOMMountPointServiceHandler.class);
+ when(mountPointServiceHandler.get()).thenReturn(getMountPointService());
+
+ return new RestconfModulesServiceImpl(schemaContextHandler, mountPointServiceHandler);
+ }
+
+ /**
+ * Mock <code>SchemaContext</code> to load custom (modified) Restconf module.
+ * @param restconfModuleName Path of custom Restconf module
+ * @return <code>RestconfModulesServiceImpl</code>
+ * @throws Exception
+ */
+ static final RestconfModulesServiceImpl setupCustomRestconfModule(final String restconfModuleName)
+ throws Exception {
+ final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class);
+ final SchemaContext schemaContext = mock(SchemaContext.class);
+ when(schemaContextHandler.get()).thenReturn(schemaContext);
+
+ when(schemaContext.findModuleByNamespaceAndRevision(any(URI.class), any(Date.class))).thenAnswer(invocation -> {
+ final Object[] args = invocation.getArguments();
+ if (args[0] == Draft11.RestconfModule.IETF_RESTCONF_QNAME.getNamespace()
+ && args[1] == Draft11.RestconfModule.IETF_RESTCONF_QNAME.getRevision()) {
+ return parseCustomRestconfSource(restconfModuleName).findModuleByName(
+ restconfModuleName, (Date) args[1]);
+ } else {
+ return TestRestconfUtils.loadSchemaContext(MODULES_PATH).findModuleByNamespaceAndRevision(
+ (URI) args[0], (Date) args[1]);
+ }
+ });
+
+ when(schemaContext.findModuleByName(any(String.class), any(Date.class))).thenAnswer(invocation -> {
+ final Object[] args = invocation.getArguments();
+ return TestRestconfUtils.loadSchemaContext(MODULES_PATH).findModuleByName(
+ (String) args[0], (Date) args[1]);
+ });
+
+ return new RestconfModulesServiceImpl(schemaContextHandler, null);
+ }
+
+ /**
+ * Mock <code>SchemaContext</code> to load custom (modified) Restconf module and prepare mount point.
+ * @param restconfModuleName
+ * @return <code>RestconfModulesServiceImpl</code>
+ * @throws Exception
+ */
+ static final RestconfModulesServiceImpl setupCustomRestconfModuleMountPoint(
+ final String restconfModuleName)throws Exception {
+ final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class);
+ when(schemaContextHandler.get()).thenReturn(
+ parseCustomRestconfSourceMountPoint(restconfModuleName));
+
+ final DOMMountPointServiceHandler mountPointServiceHandler = mock(DOMMountPointServiceHandler.class);
+ final DOMMountPointService mountPointService = getMountPointService();
+ when(mountPointServiceHandler.get()).thenReturn(mountPointService);
+
+ return new RestconfModulesServiceImpl(schemaContextHandler, mountPointServiceHandler);
+ }
+
+ /**
+ * Prepare <code>RestconfModulesServiceImpl</code> with <code>SchemaContext</code> without Restconf module.
+ * @return <code>RestconfModulesServiceImpl</code>
+ * @throws Exception
+ */
+ static final RestconfModulesServiceImpl setupMissingRestconfModule() throws Exception {
+ final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class);
+ when(schemaContextHandler.get()).thenReturn(TestRestconfUtils.loadSchemaContext(
+ MODULES_WITHOUT_RESTCONF_MODULE_PATH));
+
+ return new RestconfModulesServiceImpl(schemaContextHandler, null);
+ }
+
+ /**
+ * Prepare <code>RestconfModulesServiceImpl</code> with <code>SchemaContext</code> without Restconf module and
+ * mount point.
+ * @return <code>RestconfModulesServiceImpl</code>
+ * @throws Exception
+ */
+ static final RestconfModulesServiceImpl setupMissingRestconfModuleMountPoint() throws Exception {
+ final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class);
+ when(schemaContextHandler.get()).thenReturn(TestRestconfUtils.loadSchemaContext(
+ MODULES_WITHOUT_RESTCONF_MODULE_PATH));
+
+ final DOMMountPointServiceHandler mountPointServiceHandler = mock(DOMMountPointServiceHandler.class);
+ when(mountPointServiceHandler.get()).thenReturn(getMountPointService());
+
+ return new RestconfModulesServiceImpl(schemaContextHandler, mountPointServiceHandler);
+ }
+
+ /**
+ * Prepare <code>RestconfModulesServiceImpl</code> with <code>SchemaContext</code> with testing modules and mount
+ * points but <code>DOMMountPointServiceHandler</code> will contain <code>null</code> reference to
+ * <code>DOMMountPointService</code>.
+ * @return <code>RestconfModulesServiceImpl</code>
+ * @throws Exception
+ */
+ static final RestconfModulesServiceImpl setupNullMountPointService() throws Exception {
+ final SchemaContextHandler schemaContextHandler = mock(SchemaContextHandler.class);
+
+ final Collection<File> yangFiles = TestRestconfUtils.loadFiles(MODULES_PATH);
+ yangFiles.addAll(TestRestconfUtils.loadFiles(MOUNT_POINTS_PATH));
+
+ when(schemaContextHandler.get()).thenReturn(TestRestconfUtils.parseYangSources(yangFiles));
+
+ final DOMMountPointServiceHandler mountPointServiceHandler = mock(DOMMountPointServiceHandler.class);
+ when(mountPointServiceHandler.get()).thenReturn(null);
+
+ return new RestconfModulesServiceImpl(schemaContextHandler, mountPointServiceHandler);
+ }
+
+ /**
+ * Create <code>DOMMountPointService</code> with one registered <code>SimpleDOMMountPoint</code>.
+ * @return <code>DOMMountPointService</code>
+ * @throws Exception
+ */
+ private static DOMMountPointService getMountPointService() throws Exception {
+ final DOMMountPointService mountPointService = new DOMMountPointServiceImpl();
+ ((DOMMountPointServiceImpl) mountPointService).registerMountPoint(
+ SimpleDOMMountPoint.create(
+ YangInstanceIdentifier.builder().node(
+ QName.create("mount:point:1", "2016-01-01", "cont")).build(),
+ ImmutableClassToInstanceMap.copyOf(Maps.newHashMap()),
+ TestRestconfUtils.loadSchemaContext(
+ MODULES_BEHIND_MOUNT_POINT_PATH)));
+
+ return mountPointService;
+ }
+
+ /**
+ * Parse custom sources for creating <code>SchemaContext</code> containing Restconf module specified by
+ * <code>restconfName</code> its dependencies and one testing module.
+ * @param restconfName File name of custom Restconf module
+ * @return <code>SchemaContext</code> containing custom Restconf module
+ */
+ private static SchemaContext parseCustomRestconfSource(final String restconfName) throws Exception {
+ final String restconf = TestRestconfUtils.class.getResource(
+ CUSTOM_RESTCONF_MODULES_PATH + restconfName + ".yang").getPath();
+ final String yangTypes = TestRestconfUtils.class.getResource(
+ CUSTOM_RESTCONF_MODULES_PATH + "ietf-yang-types.yang").getPath();
+ final String inetTypes = TestRestconfUtils.class.getResource(
+ CUSTOM_RESTCONF_MODULES_PATH + "ietf-inet-types.yang").getPath();
+ final String testModule = TestRestconfUtils.class.getResource(
+ MODULES_PATH + "/module1.yang").getPath();
+
+ final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(restconf), restconf)));
+ reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(yangTypes), yangTypes)));
+ reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(inetTypes), inetTypes)));
+ reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(testModule), testModule)));
+
+ return reactor.buildEffective();
+ }
+
+ /**
+ * Parse custom sources for creating <code>SchemaContext</code> containing Restconf module specified by
+ * <code>restconfName</code> its dependencies and one mount point.
+ * @param restconfName File name of custom Restconf module
+ * @return <code>SchemaContext</code> containing custom Restconf module with one mount point
+ */
+ private static SchemaContext parseCustomRestconfSourceMountPoint(String restconfName) throws Exception {
+ final String restconf = TestRestconfUtils.class.getResource(
+ CUSTOM_RESTCONF_MODULES_MOUNT_POINT_PATH
+ + restconfName + "/" + restconfName + ".yang").getPath();
+ final String yangTypes = TestRestconfUtils.class.getResource(
+ CUSTOM_RESTCONF_MODULES_MOUNT_POINT_PATH + "ietf-yang-types.yang").getPath();
+ final String inetTypes = TestRestconfUtils.class.getResource(
+ CUSTOM_RESTCONF_MODULES_MOUNT_POINT_PATH + "ietf-inet-types.yang").getPath();
+ final String mountPoint = TestRestconfUtils.class.getResource(
+ CUSTOM_RESTCONF_MODULES_MOUNT_POINT_PATH + "mount-point-1.yang").getPath();
+
+ final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(restconf), restconf)));
+ reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(yangTypes), yangTypes)));
+ reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(inetTypes), inetTypes)));
+ reactor.addSource(new YangStatementSourceImpl(new NamedFileInputStream(new File(mountPoint), mountPoint)));
+
+ return reactor.buildEffective();
+ }
+
+
+ /**
+ * Module representation containing name, namespace and revision for easier comparison of modules.
+ */
+ static final class TestModule {
+ private String name;
+ private String namespace;
+ private String revision;
+
+ TestModule() {}
+
+ TestModule(String name, URI namespace, Date revision) {
+ this.name = name;
+ this.namespace = namespace.toString();
+ this.revision = SimpleDateFormatUtil.getRevisionFormat().format(revision);
+ }
+
+ String getName() {
+ return name;
+ }
+
+ void setName(String name) {
+ this.name = name;
+ }
+
+ String getNamespace() {
+ return namespace;
+ }
+
+ void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ String getRevision() {
+ return revision;
+ }
+
+ void setRevision(String revision) {
+ this.revision = revision;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ TestModule that = (TestModule) o;
+
+ if (name != null ? !name.equals(that.name) : that.name != null) return false;
+ if (namespace != null ? !namespace.equals(that.namespace) : that.namespace != null) return false;
+ return revision != null ? revision.equals(that.revision) : that.revision == null;
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = name != null ? name.hashCode() : 0;
+ result = 31 * result + (namespace != null ? namespace.hashCode() : 0);
+ result = 31 * result + (revision != null ? revision.hashCode() : 0);
+ return result;
+ }
+ }
+}
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.restconf.rest.impl.services;
+package org.opendaylight.restconf.rest.services.impl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.restconf.rest.impl.services;
+package org.opendaylight.restconf.rest.services.impl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import org.opendaylight.restconf.Draft11;
import org.opendaylight.restconf.handlers.SchemaContextHandler;
import org.opendaylight.restconf.rest.services.api.RestconfStreamsService;
-import org.opendaylight.restconf.rest.services.impl.RestconfStreamsServiceImpl;
import org.opendaylight.restconf.utils.mapping.RestconfMappingNodeConstants;
import org.opendaylight.restconf.utils.mapping.RestconfMappingStreamConstants;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
reference
"RFC 2578: Structure of Management Information Version 2 (SMIv2)";
}
-
+
typedef yang-identifier {
type string {
length "1..max";
reference
"RFC 6020: YANG - A Data Modeling Language for the Network
Configuration Protocol (NETCONF)";
- }
+ }
/*** collection of date and time related types ***/
--- /dev/null
+module module1 {
+ namespace "module:1";
+ prefix "mod1";
+ revision "2014-01-01";
+
+ rpc dummy-rpc1-module1 {
+ }
+
+ rpc dummy-rpc2-module1 {
+ }
+
+}
\ No newline at end of file
--- /dev/null
+module module2 {
+ namespace "module:2";
+ prefix "mod2";
+ revision "2014-01-02";
+
+ rpc dummy-rpc1-module2 {
+ }
+
+ rpc dummy-rpc2-module2 {
+ }
+}
\ No newline at end of file
--- /dev/null
+module module3 {
+ namespace "module:3";
+ prefix "mod3";
+ revision "2014-01-03";
+}
\ No newline at end of file
--- /dev/null
+module mount-point-1 {
+ namespace "mount:point:1";
+ prefix "point1";
+ revision "2016-01-01";
+
+ container cont {
+ }
+
+ list listA {
+ }
+}
\ No newline at end of file
container cont {
}
+
+ list listA {
+ }
}
\ No newline at end of file
--- /dev/null
+ 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 Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ 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) 2010 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 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of protocol field related types ***/
+
+ 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 flow-label type represents 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 autonomous system related types ***/
+
+ 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 ASs'. 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 4893: BGP Support for Four-octet AS Number Space
+ RFC 4001: Textual Conventions for Internet Network Addresses";
+ }
+
+ /*** collection of IP address and hostname related types ***/
+
+ 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 representations
+ implies the IP version.";
+ }
+
+ 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 compressed
+ format described in RFC 4291, Section 2.2, item 2 with the
+ following additional rules: the :: substitution must be
+ applied to the longest sequence of all-zero 16-bit chunks
+ in an IPv6 address. If there is a tie, the first sequence
+ of all-zero 16-bit chunks is replaced by ::. Single
+ all-zero 16-bit chunks are not compressed. The canonical
+ format uses lowercase characters and leading zeros are
+ not allowed. The canonical format for the zone index is
+ the numerical format as described in RFC 4007, Section
+ 11.2.";
+ 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 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, IPv6 address is represented
+ in the compressed format described in RFC 4291, Section
+ 2.2, item 2 with the following additional rules: the ::
+ substitution must be applied to the longest sequence of
+ all-zero 16-bit chunks in an IPv6 address. If there is
+ a tie, the first sequence of all-zero 16-bit chunks is
+ replaced by ::. Single all-zero 16-bit chunks are not
+ compressed. The canonical format uses lowercase
+ characters and leading zeros are not allowed.";
+ reference
+ "RFC 4291: IP Version 6 Addressing Architecture";
+ }
+
+ /*** 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
+ explicitely or it 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 encoded in punycode as described in RFC
+ 3492";
+ 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 3492: Punycode: A Bootstring encoding of Unicode for
+ Internationalized Domain Names in Applications
+ (IDNA)
+ RFC 5891: Internationalizing Domain Names in Applications
+ (IDNA): Protocol";
+ }
+
+ 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)";
+ }
+
+ }
--- /dev/null
+ module ietf-yang-types {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+ prefix "yang";
+
+ 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 Partain
+ <mailto:david.partain@ericsson.com>
+
+ WG Chair: David Kessens
+ <mailto:david.kessens@nsn.com>
+
+ Editor: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>";
+
+ description
+ "This module contains a collection of generally useful derived
+ YANG data types.
+
+ Copyright (c) 2010 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 6021; see
+ the RFC itself for full legal notices.";
+
+ revision 2010-09-24 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 6021: Common YANG Data Types";
+ }
+
+ /*** collection of counter and gauge types ***/
+
+ typedef counter32 {
+ type uint32;
+ description
+ "The counter32 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter32 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter32 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter32.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter32 {
+ type yang:counter32;
+ default "0";
+ description
+ "The zero-based-counter32 type represents a counter32
+ that has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^32-1 (4294967295 decimal), when it
+ wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter32 textual convention of the SMIv2.";
+ reference
+ "RFC 4502: Remote Network Monitoring Management Information
+ Base Version 2";
+ }
+
+ typedef counter64 {
+ type uint64;
+ description
+ "The counter64 type represents a non-negative integer
+ that monotonically increases until it reaches a
+ maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Counters have no defined 'initial' value, and thus, a
+ single value of a counter has (in general) no information
+ content. Discontinuities in the monotonically increasing
+ value normally occur at re-initialization of the
+ management system, and at other times as specified in the
+ description of a schema node using this type. If such
+ other times can occur, for example, the creation of
+ a schema node of type counter64 at times other than
+ re-initialization, then a corresponding schema node
+ should be defined, with an appropriate type, to indicate
+ the last discontinuity.
+
+ The counter64 type should not be used for configuration
+ schema nodes. A default statement SHOULD NOT be used in
+ combination with the type counter64.
+
+ In the value set and its semantics, this type is equivalent
+ to the Counter64 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef zero-based-counter64 {
+ type yang:counter64;
+ default "0";
+ description
+ "The zero-based-counter64 type represents a counter64 that
+ has the defined 'initial' value zero.
+
+ A schema node of this type will be set to zero (0) on creation
+ and will thereafter increase monotonically until it reaches
+ a maximum value of 2^64-1 (18446744073709551615 decimal),
+ when it wraps around and starts increasing again from zero.
+
+ Provided that an application discovers a new schema node
+ of this type within the minimum time to wrap, it can use the
+ 'initial' value as a delta. It is important for a management
+ station to be aware of this minimum time and the actual time
+ between polls, and to discard data if the actual time is too
+ long or there is no defined minimum time.
+
+ In the value set and its semantics, this type is equivalent
+ to the ZeroBasedCounter64 textual convention of the SMIv2.";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ typedef gauge32 {
+ type uint32;
+ description
+ "The gauge32 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^32-1 (4294967295 decimal), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge32 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge32 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the Gauge32 type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef gauge64 {
+ type uint64;
+ description
+ "The gauge64 type represents a non-negative integer, which
+ may increase or decrease, but shall never exceed a maximum
+ value, nor fall below a minimum value. The maximum value
+ cannot be greater than 2^64-1 (18446744073709551615), and
+ the minimum value cannot be smaller than 0. The value of
+ a gauge64 has its maximum value whenever the information
+ being modeled is greater than or equal to its maximum
+ value, and has its minimum value whenever the information
+ being modeled is smaller than or equal to its minimum value.
+ If the information being modeled subsequently decreases
+ below (increases above) the maximum (minimum) value, the
+ gauge64 also decreases (increases).
+
+ In the value set and its semantics, this type is equivalent
+ to the CounterBasedGauge64 SMIv2 textual convention defined
+ in RFC 2856";
+ reference
+ "RFC 2856: Textual Conventions for Additional High Capacity
+ Data Types";
+ }
+
+ /*** collection of identifier related types ***/
+
+ typedef object-identifier {
+ type string {
+ pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ + '(\.(0|([1-9]\d*)))*';
+ }
+ description
+ "The object-identifier type represents administratively
+ assigned names in a registration-hierarchical-name tree.
+
+ Values of this type are denoted as a sequence of numerical
+ non-negative sub-identifier values. Each sub-identifier
+ value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
+ are separated by single dots and without any intermediate
+ whitespace.
+
+ The ASN.1 standard restricts the value space of the first
+ sub-identifier to 0, 1, or 2. Furthermore, the value space
+ of the second sub-identifier is restricted to the range
+ 0 to 39 if the first sub-identifier is 0 or 1. Finally,
+ the ASN.1 standard requires that an object identifier
+ has always at least two sub-identifier. The pattern
+ captures these restrictions.
+
+ Although the number of sub-identifiers is not limited,
+ module designers should realize that there may be
+ implementations that stick with the SMIv2 limit of 128
+ sub-identifiers.
+
+ This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+ since it is not restricted to 128 sub-identifiers. Hence,
+ this type SHOULD NOT be used to represent the SMIv2 OBJECT
+ IDENTIFIER type, the object-identifier-128 type SHOULD be
+ used instead.";
+ reference
+ "ISO9834-1: Information technology -- Open Systems
+ Interconnection -- Procedures for the operation of OSI
+ Registration Authorities: General procedures and top
+ arcs of the ASN.1 Object Identifier tree";
+ }
+
+
+
+
+ typedef object-identifier-128 {
+ type object-identifier {
+ pattern '\d*(\.\d*){1,127}';
+ }
+ description
+ "This type represents object-identifiers restricted to 128
+ sub-identifiers.
+
+ In the value set and its semantics, this type is equivalent
+ to the OBJECT IDENTIFIER type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef yang-identifier {
+ type string {
+ length "1..max";
+ pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
+ pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
+ }
+ description
+ "A YANG identifier string as defined by the 'identifier'
+ rule in Section 12 of RFC 6020. An identifier must
+ start with an alphabetic character or an underscore
+ followed by an arbitrary sequence of alphabetic or
+ numeric characters, underscores, hyphens, or dots.
+
+ A YANG identifier MUST NOT start with any possible
+ combination of the lowercase or uppercase character
+ sequence 'xml'.";
+ reference
+ "RFC 6020: YANG - A Data Modeling Language for the Network
+ Configuration Protocol (NETCONF)";
+ }
+
+ /*** collection of date and time related types ***/
+
+ typedef date-and-time {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ + '(Z|[\+\-]\d{2}:\d{2})';
+ }
+ description
+ "The date-and-time type is a profile of the ISO 8601
+ standard for representation of dates and times using the
+ Gregorian calendar. The profile is defined by the
+ date-time production in Section 5.6 of RFC 3339.
+
+ The date-and-time type is compatible with the dateTime XML
+ schema type with the following notable exceptions:
+
+ (a) The date-and-time type does not allow negative years.
+
+ (b) The date-and-time time-offset -00:00 indicates an unknown
+ time zone (see RFC 3339) while -00:00 and +00:00 and Z all
+ represent the same time zone in dateTime.
+
+ (c) The canonical format (see below) of data-and-time values
+ differs from the canonical format used by the dateTime XML
+ schema type, which requires all times to be in UTC using the
+ time-offset 'Z'.
+
+ This type is not equivalent to the DateAndTime textual
+ convention of the SMIv2 since RFC 3339 uses a different
+ separator between full-date and full-time and provides
+ higher resolution of time-secfrac.
+
+ The canonical format for date-and-time values with a known time
+ zone uses a numeric time zone offset that is calculated using
+ the device's configured known offset to UTC time. A change of
+ the device's offset to UTC time will cause date-and-time values
+ to change accordingly. Such changes might happen periodically
+ in case a server follows automatically daylight saving time
+ (DST) time zone offset changes. The canonical format for
+ date-and-time values with an unknown time zone (usually referring
+ to the notion of local time) uses the time-offset -00:00.";
+ reference
+ "RFC 3339: Date and Time on the Internet: Timestamps
+ RFC 2579: Textual Conventions for SMIv2
+ XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+ }
+
+ typedef timeticks {
+ type uint32;
+ description
+ "The timeticks type represents a non-negative integer that
+ represents the time, modulo 2^32 (4294967296 decimal), in
+ hundredths of a second between two epochs. When a schema
+ node is defined that uses this type, the description of
+ the schema node identifies both of the reference epochs.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeTicks type of the SMIv2.";
+ reference
+ "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+ }
+
+ typedef timestamp {
+ type yang:timeticks;
+ description
+ "The timestamp type represents the value of an associated
+ timeticks schema node at which a specific occurrence happened.
+ The specific occurrence must be defined in the description
+ of any schema node defined using this type. When the specific
+ occurrence occurred prior to the last time the associated
+ timeticks attribute was zero, then the timestamp value is
+ zero. Note that this requires all timestamp values to be
+ reset to zero when the value of the associated timeticks
+ attribute reaches 497+ days and wraps around to zero.
+
+ The associated timeticks schema node must be specified
+ in the description of any schema node using this type.
+
+ In the value set and its semantics, this type is equivalent
+ to the TimeStamp textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of generic address types ***/
+
+ typedef phys-address {
+ type string {
+ pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+ }
+ description
+ "Represents media- or physical-level addresses represented
+ as a sequence octets, each octet represented by two hexadecimal
+ numbers. Octets are separated by colons. The canonical
+ representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the PhysAddress textual convention of the SMIv2.";
+ reference
+ "RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ typedef mac-address {
+ type string {
+ pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+ }
+ description
+ "The mac-address type represents an IEEE 802 MAC address.
+ The canonical representation uses lowercase characters.
+
+ In the value set and its semantics, this type is equivalent
+ to the MacAddress textual convention of the SMIv2.";
+ reference
+ "IEEE 802: IEEE Standard for Local and Metropolitan Area
+ Networks: Overview and Architecture
+ RFC 2579: Textual Conventions for SMIv2";
+ }
+
+ /*** collection of XML specific types ***/
+
+ typedef xpath1.0 {
+ type string;
+ description
+ "This type represents an XPATH 1.0 expression.
+
+ When a schema node is defined that uses this type, the
+ description of the schema node MUST specify the XPath
+ context in which the XPath expression is evaluated.";
+ reference
+ "XPATH: XML Path Language (XPath) Version 1.0";
+ }
+
+ }
--- /dev/null
+module mount-point-1 {
+ namespace "mount:point:1";
+ prefix "point1";
+ revision "2016-01-01";
+
+ container cont {
+ }
+
+ list listA {
+ }
+}
\ No newline at end of file
--- /dev/null
+module restconf-module-with-illegal-container-modules {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+ 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 XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ /** changed from container modules to list modules for testing purposes **/
+ list modules {
+ description
+ "Contains a list of module description entries.
+ These modules are currently loaded into the server.";
+
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one module currently
+ supported by the server.";
+
+ leaf name {
+ type yang:yang-identifier;
+ description "The YANG module name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module revision date. An empty string is
+ used if no revision statement is present in the
+ YANG module.";
+ }
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server.";
+ }
+ leaf-list deviation {
+ type yang:yang-identifier;
+ description
+ "List of YANG deviation module names used by this
+ server to modify the conformance of the module
+ associated with this entry.";
+ }
+ }
+ }
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+ }
\ No newline at end of file
--- /dev/null
+module restconf-module-with-illegal-list-module {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+ 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 XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ container modules {
+ description
+ "Contains a list of module description entries.
+ These modules are currently loaded into the server.";
+
+ /** changed from list module to container module for testing purposes **/
+ container module {
+ description
+ "Each entry represents one module currently
+ supported by the server.";
+
+ leaf name {
+ type yang:yang-identifier;
+ description "The YANG module name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module revision date. An empty string is
+ used if no revision statement is present in the
+ YANG module.";
+ }
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server.";
+ }
+ leaf-list deviation {
+ type yang:yang-identifier;
+ description
+ "List of YANG deviation module names used by this
+ server to modify the conformance of the module
+ associated with this entry.";
+ }
+ }
+ }
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+ }
\ No newline at end of file
--- /dev/null
+module restconf-module-with-missing-container-modules {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+ 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 XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ // removed container modules for testing purposes
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+ }
\ No newline at end of file
--- /dev/null
+module restconf-module-with-missing-list-module {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+ 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 XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ container modules {
+ description
+ "Contains a list of module description entries.
+ These modules are currently loaded into the server.";
+
+ // removed list module for testing purposes + added list test-list
+ list test-list {
+ leaf test-leaf {
+ type string;
+ }
+ }
+ }
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+ }
\ No newline at end of file
--- /dev/null
+module restconf-module-with-illegal-container-modules {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-restconf-rmwicm";
+ prefix "restconf";
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+
+ Editor: Kent Watsen
+ <mailto:kwatsen@juniper.net>
+
+ Editor: Rex Fernando
+ <mailto:rex@cisco.com>";
+
+ description
+ "This module contains conceptual YANG specifications
+ for the YANG Patch and error content that is used in
+ RESTCONF protocol messages. A conceptual container
+ representing the RESTCONF API nodes (media type
+ application/yang.api).
+
+ Note that the YANG definitions within this module do not
+ represent configuration data of any kind.
+ The YANG grouping statements provide a normative syntax
+ for XML and JSON message encoding purposes.
+ 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 XXXX; see
+ the RFC itself for full legal notices.";
+
+ // RFC Ed.: replace XXXX with actual RFC number and remove this
+ // note.
+
+ // RFC Ed.: remove this note
+ // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+ // RFC Ed.: update the date below with the date of RFC publication
+ // and remove this note.
+ revision 2013-10-19 {
+ description
+ "Initial revision.";
+ reference
+ "RFC XXXX: RESTCONF Protocol.";
+ }
+
+ typedef data-resource-identifier {
+ type string {
+ length "1 .. max";
+ }
+ description
+ "Contains a Data Resource Identifier formatted string
+ to identify a specific data node. The data node that
+ uses this data type SHOULD define the document root
+ for data resource identifiers. The default document
+ root is the target datastore conceptual root node.
+ Data resource identifiers are defined relative to
+ this document root.";
+ reference
+ "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+ }
+
+ // this typedef is TBD; not currently used
+ typedef datastore-identifier {
+ type union {
+ type enumeration {
+ enum candidate {
+ description
+ "Identifies the NETCONF shared candidate datastore.";
+ reference
+ "RFC 6241, section 8.3";
+ }
+ enum running {
+ description
+ "Identifies the NETCONF running datastore.";
+ reference
+ "RFC 6241, section 5.1";
+ }
+ enum startup {
+ description
+ "Identifies the NETCONF startup datastore.";
+ reference
+ "RFC 6241, section 8.7";
+ }
+ }
+ type string;
+ }
+ description
+ "Contains a string to identify a specific datastore.
+ The enumerated datastore identifier values are
+ reserved for standard datastore names.";
+ }
+
+ typedef revision-identifier {
+ type string {
+ pattern '\d{4}-\d{2}-\d{2}';
+ }
+ description
+ "Represents a specific date in YYYY-MM-DD format.
+ TBD: make pattern more precise to exclude leading zeros.";
+ }
+
+ grouping yang-patch {
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch edit request message.";
+
+ container yang-patch {
+ description
+ "Represents a conceptual sequence of datastore edits,
+ called a patch. Each patch is given a client-assigned
+ patch identifier. Each edit MUST be applied
+ in ascending order, and all edits MUST be applied.
+ If any errors occur, then the target datastore MUST NOT
+ be changed by the patch operation.
+
+ A patch MUST be validated by the server to be a
+ well-formed message before any of the patch edits
+ are validated or attempted.
+
+ YANG datastore validation (defined in RFC 6020, section
+ 8.3.3) is performed after all edits have been
+ individually validated.
+
+ It is possible for a datastore constraint violation to occur
+ due to any node in the datastore, including nodes not
+ included in the edit list. Any validation errors MUST
+ be reported in the reply message.";
+
+ reference
+ "RFC 6020, section 8.3.";
+
+ leaf patch-id {
+ type string;
+ description
+ "An arbitrary string provided by the client to identify
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch. Error messages returned by the server pertaining
+ to this patch will be identified by this patch-id value.";
+ }
+
+ leaf comment {
+ type string {
+ length "0 .. 1024";
+ }
+ description
+ "An arbitrary string provided by the client to describe
+ the entire patch. This value SHOULD be present in any
+ audit logging records generated by the server for the
+ patch.";
+ }
+
+ list edit {
+ key edit-id;
+ ordered-by user;
+
+ description
+ "Represents one edit within the YANG Patch
+ request message.";
+ leaf edit-id {
+ type string;
+ description
+ "Arbitrary string index for the edit.
+ Error messages returned by the server pertaining
+ to a specific edit will be identified by this
+ value.";
+ }
+
+ leaf operation {
+ type enumeration {
+ enum create {
+ description
+ "The target data node is created using the
+ supplied value, only if it does not already
+ exist.";
+ }
+ enum delete {
+ description
+ "Delete the target node, only if the data resource
+ currently exists, otherwise return an error.";
+ }
+ enum insert {
+ description
+ "Insert the supplied value into a user-ordered
+ list or leaf-list entry. The target node must
+ represent a new data resource.";
+ }
+ enum merge {
+ description
+ "The supplied value is merged with the target data
+ node.";
+ }
+ enum move {
+ description
+ "Move the target node. Reorder a user-ordered
+ list or leaf-list. The target node must represent
+ an existing data resource.";
+ }
+ enum replace {
+ description
+ "The supplied value is used to replace the target
+ data node.";
+ }
+ enum remove {
+ description
+ "Delete the target node if it currently exists.";
+ }
+ }
+ mandatory true;
+ description
+ "The datastore operation requested for the associated
+ edit entry";
+ }
+
+ leaf target {
+ type data-resource-identifier;
+ mandatory true;
+ description
+ "Identifies the target data resource for the edit
+ operation.";
+ }
+
+ leaf point {
+ when "(../operation = 'insert' or " +
+ "../operation = 'move') and " +
+ "(../where = 'before' or ../where = 'after')" {
+ description
+ "Point leaf only applies for insert or move
+ operations, before or after an existing entry.";
+ }
+ type data-resource-identifier;
+ description
+ "The absolute URL path for the data node that is being
+ used as the insertion point or move point for the
+ target of this edit entry.";
+ }
+
+ leaf where {
+ when "../operation = 'insert' or ../operation = 'move'" {
+ description
+ "Where leaf only applies for insert or move
+ operations.";
+ }
+ type enumeration {
+ enum before {
+ description
+ "Insert or move a data node before the data resource
+ identified by the 'point' parameter.";
+ }
+ enum after {
+ description
+ "Insert or move a data node after the data resource
+ identified by the 'point' parameter.";
+ }
+ enum first {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the first entry.";
+ }
+ enum last {
+ description
+ "Insert or move a data node so it becomes ordered
+ as the last entry.";
+ }
+
+ }
+ default last;
+ description
+ "Identifies where a data resource will be inserted or
+ moved. YANG only allows these operations for
+ list and leaf-list data nodes that are ordered-by
+ user.";
+ }
+
+ anyxml value {
+ when "(../operation = 'create' or " +
+ "../operation = 'merge' " +
+ "or ../operation = 'replace' or " +
+ "../operation = 'insert')" {
+ description
+ "Value node only used for create, merge,
+ replace, and insert operations";
+ }
+ description
+ "Value used for this edit operation.";
+ }
+ }
+ }
+
+ } // grouping yang-patch
+
+
+ grouping yang-patch-status {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ YANG Patch status response message.";
+
+ container yang-patch-status {
+ description
+ "A container representing the response message
+ sent by the server after a YANG Patch edit
+ request message has been processed.";
+
+ leaf patch-id {
+ type string;
+ description
+ "The patch-id value used in the request";
+ }
+
+ choice global-status {
+ description
+ "Report global errors or complete success.
+ If there is no case selected then errors
+ are reported in the edit-status container.";
+
+ case global-errors {
+ uses errors;
+ description
+ "This container will be present if global
+ errors unrelated to a specific edit occurred.";
+ }
+ leaf ok {
+ type empty;
+ description
+ "This leaf will be present if the request succeeded
+ and there are no errors reported in the edit-status
+ container.";
+ }
+ }
+
+ container edit-status {
+ description
+ "This container will be present if there are
+ edit-specific status responses to report.";
+
+ list edit {
+ key edit-id;
+
+ description
+ "Represents a list of status responses,
+ corresponding to edits in the YANG Patch
+ request message. If an edit entry was
+ skipped or not reached by the server,
+ then this list will not contain a corresponding
+ entry for that edit.";
+
+ leaf edit-id {
+ type string;
+ description
+ "Response status is for the edit list entry
+ with this edit-id value.";
+ }
+ choice edit-status-choice {
+ description
+ "A choice between different types of status
+ responses for each edit entry.";
+ leaf ok {
+ type empty;
+ description
+ "This edit entry was invoked without any
+ errors detected by the server associated
+ with this edit.";
+ }
+ leaf location {
+ type inet:uri;
+ description
+ "Contains the Location header value that would be
+ returned if this edit causes a new resource to be
+ created. If the edit identified by the same edit-id
+ value was successfully invoked and a new resource
+ was created, then this field will be returned
+ instead of 'ok'.";
+ }
+ case errors {
+ uses errors;
+ description
+ "The server detected errors associated with the
+ edit identified by the same edit-id value.";
+ }
+ }
+ }
+ }
+ }
+ } // grouping yang-patch-status
+
+
+ grouping errors {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of a
+ YANG Patch errors report within a response message.";
+
+ container errors {
+ config false; // needed so list error does not need a key
+ description
+ "Represents an error report returned by the server if
+ a request results in an error.";
+
+ list error {
+ description
+ "An entry containing information about one
+ specific error that occurred while processing
+ a RESTCONF request.";
+ reference "RFC 6241, Section 4.3";
+
+ leaf error-type {
+ type enumeration {
+ enum transport {
+ description "The transport layer";
+ }
+ enum rpc {
+ description "The rpc or notification layer";
+ }
+ enum protocol {
+ description "The protocol operation layer";
+ }
+ enum application {
+ description "The server application layer";
+ }
+ }
+ mandatory true;
+ description
+ "The protocol layer where the error occurred.";
+ }
+
+ leaf error-tag {
+ type string;
+ mandatory true;
+ description
+ "The enumerated error tag.";
+ }
+
+ leaf error-app-tag {
+ type string;
+ description
+ "The application-specific error tag.";
+ }
+
+ leaf error-path {
+ type data-resource-identifier;
+ description
+ "The target data resource identifier associated
+ with the error, if any.";
+ }
+ leaf error-message {
+ type string;
+ description
+ "A message describing the error.";
+ }
+
+ container error-info {
+ description
+ "A container allowing additional information
+ to be included in the error report.";
+ // arbitrary anyxml content here
+ }
+ }
+ }
+ } // grouping errors
+
+
+ grouping restconf {
+
+ description
+ "A grouping that contains a YANG container
+ representing the syntax and semantics of
+ the RESTCONF API resource.";
+
+ container restconf {
+ description
+ "Conceptual container representing the
+ application/yang.api resource type.";
+
+ container config {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ unified configuration datastore containing YANG data
+ nodes. The child nodes of this container are
+ configuration data resources (application/yang.data)
+ defined as top-level YANG data nodes from the modules
+ advertised by the server in /restconf/modules.";
+ }
+
+ container operational {
+ description
+ "Container representing the application/yang.datastore
+ resource type. Represents the conceptual root of the
+ operational data supported by the server. The child
+ nodes of this container are operational data resources
+ (application/yang.data) defined as top-level
+ YANG data nodes from the modules advertised by
+ the server in /restconf/modules.";
+ }
+
+ /** changed from container modules to list modules for testing purposes **/
+ list modules {
+ description
+ "Contains a list of module description entries.
+ These modules are currently loaded into the server.";
+
+ list module {
+ key "name revision";
+ description
+ "Each entry represents one module currently
+ supported by the server.";
+
+ leaf name {
+ type yang:yang-identifier;
+ description "The YANG module name.";
+ }
+ leaf revision {
+ type union {
+ type revision-identifier;
+ type string { length 0; }
+ }
+ description
+ "The YANG module revision date. An empty string is
+ used if no revision statement is present in the
+ YANG module.";
+ }
+ leaf namespace {
+ type inet:uri;
+ mandatory true;
+ description
+ "The XML namespace identifier for this module.";
+ }
+ leaf-list feature {
+ type yang:yang-identifier;
+ description
+ "List of YANG feature names from this module that are
+ supported by the server.";
+ }
+ leaf-list deviation {
+ type yang:yang-identifier;
+ description
+ "List of YANG deviation module names used by this
+ server to modify the conformance of the module
+ associated with this entry.";
+ }
+ }
+ }
+
+ container operations {
+ description
+ "Container for all operation resources
+ (application/yang.operation),
+
+ Each resource is represented as an empty leaf with the
+ name of the RPC operation from the YANG rpc statement.
+
+ E.g.;
+
+ POST /restconf/operations/show-log-errors
+
+ leaf show-log-errors {
+ type empty;
+ }
+ ";
+ }
+
+ container streams {
+ description
+ "Container representing the notification event streams
+ supported by the server.";
+ reference
+ "RFC 5277, Section 3.4, <streams> element.";
+
+ list stream {
+ key name;
+ description
+ "Each entry describes an event stream supported by
+ the server.";
+
+ leaf name {
+ type string;
+ description "The stream name";
+ reference "RFC 5277, Section 3.4, <name> element.";
+ }
+
+ leaf description {
+ type string;
+ description "Description of stream content";
+ reference
+ "RFC 5277, Section 3.4, <description> element.";
+ }
+
+ leaf replay-support {
+ type boolean;
+ description
+ "Indicates if replay buffer supported for this stream";
+ reference
+ "RFC 5277, Section 3.4, <replaySupport> element.";
+ }
+
+ leaf replay-log-creation-time {
+ type yang:date-and-time;
+ description
+ "Indicates the time the replay log for this stream
+ was created.";
+ reference
+ "RFC 5277, Section 3.4, <replayLogCreationTime>
+ element.";
+ }
+
+ leaf events {
+ type empty;
+ description
+ "Represents the entry point for establishing
+ notification delivery via server sent events.";
+ }
+ }
+ }
+
+ leaf version {
+ type enumeration {
+ enum "1.0" {
+ description
+ "Version 1.0 of the RESTCONF protocol.";
+ }
+ }
+ config false;
+ description
+ "Contains the RESTCONF protocol version.";
+ }
+ }
+ } // grouping restconf
+
+
+ grouping notification {
+ description
+ "Contains the notification message wrapper definition.";
+
+ container notification {
+ description
+ "RESTCONF notification message wrapper.";
+ leaf event-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time the event was generated by the
+ event source.";
+ reference
+ "RFC 5277, section 4, <eventTime> element.";
+ }
+
+ /* The YANG-specific notification container is encoded
+ * after the 'event-time' element. The format
+ * corresponds to the notificationContent element
+ * in RFC 5277, section 4. For example:
+ *
+ * module example-one {
+ * ...
+ * notification event1 { ... }
+ *
+ * }
+ *
+ * Encoded as element 'event1' in the namespace
+ * for module 'example-one'.
+ */
+ }
+ } // grouping notification
+
+ }
\ No newline at end of file