Bug 6251 - Exclude flawed models from mount point 90/43690/3
authorJakub Morvay <jmorvay@cisco.com>
Wed, 10 Aug 2016 20:02:51 +0000 (22:02 +0200)
committerTomas Cere <tcere@cisco.com>
Thu, 11 Aug 2016 12:16:13 +0000 (12:16 +0000)
Flawed models that cannot be parsed by Yangtools are ignored when
building schema context for mountpoint.

Change-Id: I32585bcf34ae9df153c7147566828ba887f466de
Signed-off-by: Jakub Morvay <jmorvay@cisco.com>
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/NetconfDevice.java
netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/NetconfDeviceTest.java

index 3edbaf1018099b140f91298c615225814b31098e..31aa51a3b9caaa239d3fd9880b34f6b5072cf6c7 100644 (file)
@@ -21,6 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
@@ -489,11 +490,23 @@ public class NetconfDevice implements RemoteDevice<NetconfSessionPreferences, Ne
             if (!qNameOfMissingSource.isEmpty()) {
                 capabilities.addUnresolvedCapabilities(qNameOfMissingSource, UnavailableCapability.FailureReason.MissingSource);
             }
-            return stripMissingSource(requiredSources, missingSource);
+            return stripUnavailableSource(requiredSources, missingSource);
         }
 
         private Collection<SourceIdentifier> handleSchemaResolutionException(final Collection<SourceIdentifier> requiredSources, final SchemaResolutionException resolutionException) {
             // In case resolution error, try only with resolved sources
+            // There are two options why schema resolution exception occurred : unsatisfied imports or flawed model
+            // FIXME Do we really have assurance that these two cases cannot happen at once?
+            if (resolutionException.getFailedSource() != null) {
+                // flawed model - exclude it
+                final SourceIdentifier failedSourceId = resolutionException.getFailedSource();
+                LOG.warn("{}: Unable to build schema context, failed to resolve source {}, will reattempt without it", id, failedSourceId);
+                LOG.warn("{}: Unable to build schema context, failed to resolve source {}, will reattempt without it", id, resolutionException);
+                capabilities.addUnresolvedCapabilities(getQNameFromSourceIdentifiers(Collections.singleton(failedSourceId)),
+                        UnavailableCapability.FailureReason.UnableToResolve);
+                return stripUnavailableSource(requiredSources, resolutionException.getFailedSource());
+            }
+            // unsatisfied imports
             final Set<SourceIdentifier> unresolvedSources = resolutionException.getUnsatisfiedImports().keySet();
             capabilities.addUnresolvedCapabilities(getQNameFromSourceIdentifiers(unresolvedSources), UnavailableCapability.FailureReason.UnableToResolve);
             LOG.warn("{}: Unable to build schema context, unsatisfied imports {}, will reattempt with resolved only", id, resolutionException.getUnsatisfiedImports());
@@ -505,7 +518,7 @@ public class NetconfDevice implements RemoteDevice<NetconfSessionPreferences, Ne
             return new NetconfDeviceRpc(result, listener, new NetconfMessageTransformer(result, true));
         }
 
-        private Collection<SourceIdentifier> stripMissingSource(final Collection<SourceIdentifier> requiredSources, final SourceIdentifier sIdToRemove) {
+        private Collection<SourceIdentifier> stripUnavailableSource(final Collection<SourceIdentifier> requiredSources, final SourceIdentifier sIdToRemove) {
             final LinkedList<SourceIdentifier> sourceIdentifiers = Lists.newLinkedList(requiredSources);
             final boolean removed = sourceIdentifiers.remove(sIdToRemove);
             Preconditions.checkState(removed, "{}: Trying to remove {} from {} failed", id, sIdToRemove, requiredSources);
index c47060cdb80f4fa23c6627c51399f60a09b8a990..ae6726b7802f64efcdde29e272711e85a315af1c 100644 (file)
@@ -115,6 +115,51 @@ public class NetconfDeviceTest {
         }
     };
 
+    @Test
+    public void testNetconfDeviceFlawedModelFailedResolution() throws Exception {
+        final RemoteDeviceHandler<NetconfSessionPreferences> facade = getFacade();
+        final NetconfDeviceCommunicator listener = getListener();
+
+        final SchemaContextFactory schemaFactory = getSchemaFactory();
+        final SchemaContext schema = getSchema();
+        final SchemaRepository schemaRepository = getSchemaRepository();
+
+        final SchemaResolutionException schemaResolutionException =
+                new SchemaResolutionException("fail first", TEST_SID, new Throwable("YangTools parser fail"));
+        doAnswer(invocation -> {
+            if (((Collection<?>) invocation.getArguments()[0]).size() == 2) {
+                return Futures.immediateFailedCheckedFuture(schemaResolutionException);
+            } else {
+                return Futures.immediateCheckedFuture(schema);
+            }
+        }).when(schemaFactory).createSchemaContext(anyCollectionOf(SourceIdentifier.class));
+
+        final NetconfDeviceSchemasResolver stateSchemasResolver = (deviceRpc, remoteSessionCapabilities, id) -> {
+            final Module first = Iterables.getFirst(schema.getModules(), null);
+            final QName qName = QName.create(first.getQNameModule(), first.getName());
+            final NetconfStateSchemas.RemoteYangSchema source1 = new NetconfStateSchemas.RemoteYangSchema(qName);
+            final NetconfStateSchemas.RemoteYangSchema source2 = new NetconfStateSchemas.RemoteYangSchema(QName.create(first.getQNameModule(), "test-module2"));
+            return new NetconfStateSchemas(Sets.newHashSet(source1, source2));
+        };
+
+        final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO
+                = new NetconfDevice.SchemaResourcesDTO(getSchemaRegistry(), schemaRepository, schemaFactory, stateSchemasResolver);
+
+        final NetconfDevice device = new NetconfDeviceBuilder()
+                .setReconnectOnSchemasChange(true)
+                .setSchemaResourcesDTO(schemaResourcesDTO)
+                .setGlobalProcessingExecutor(getExecutor())
+                .setId(getId())
+                .setSalFacade(facade)
+                .build();
+        // Monitoring supported
+        final NetconfSessionPreferences sessionCaps = getSessionCaps(true, Lists.newArrayList(TEST_CAPABILITY, TEST_CAPABILITY2));
+        device.onRemoteSessionUp(sessionCaps, listener);
+
+        Mockito.verify(facade, Mockito.timeout(5000)).onDeviceConnected(any(SchemaContext.class), any(NetconfSessionPreferences.class), any(NetconfDeviceRpc.class));
+        Mockito.verify(schemaFactory, times(2)).createSchemaContext(anyCollectionOf(SourceIdentifier.class));
+    }
+
     @Test
     public void testNetconfDeviceFailFirstSchemaFailSecondEmpty() throws Exception {
         final ArrayList<String> capList = Lists.newArrayList(TEST_CAPABILITY);