HONEYCOMB-296 - Reference checking in Locator set 82/4582/6
authorJan Srnicek <[email protected]>
Thu, 12 Jan 2017 08:59:30 +0000 (09:59 +0100)
committerMarek Gradzki <[email protected]>
Thu, 12 Jan 2017 09:23:36 +0000 (09:23 +0000)
Reference must be checked while removing to prevent
dead references

Change-Id: I37cb426f73a3fa64d4e6795062d8d7affc0cbb2b
Signed-off-by: Jan Srnicek <[email protected]>
lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/translate/write/LocatorSetCustomizer.java
lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/translate/write/LocatorSetCustomizerTest.java
vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/ReferenceCheck.java [new file with mode: 0644]

index b125d40..8c41372 100755 (executable)
@@ -20,17 +20,29 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static java.nio.charset.StandardCharsets.UTF_8;
 
-import io.fd.hc2vpp.lisp.translate.read.trait.LocatorSetReader;
-import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import com.google.common.base.Optional;
 import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
 import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
 import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.common.translate.util.ReferenceCheck;
+import io.fd.hc2vpp.lisp.translate.read.trait.LocatorSetReader;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
 import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.write.WriteFailedException;
 import io.fd.vpp.jvpp.core.dto.LispAddDelLocatorSet;
 import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.DpSubtableGrouping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.Lisp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.dp.subtable.grouping.LocalMappings;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.dp.subtable.grouping.local.mappings.LocalMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.eid.table.grouping.EidTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.eid.table.grouping.eid.table.VniTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.lisp.feature.data.grouping.LispFeatureData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.locator.sets.grouping.locator.sets.LocatorSet;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.locator.sets.grouping.locator.sets.LocatorSetKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.locator.sets.grouping.locator.sets.locator.set.Interface;
@@ -44,7 +56,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  */
 public class LocatorSetCustomizer extends FutureJVppCustomizer
         implements ListWriterCustomizer<LocatorSet, LocatorSetKey>, ByteDataTranslator,
-        LocatorSetReader {
+        LocatorSetReader, ReferenceCheck {
 
     private final NamingContext locatorSetContext;
 
@@ -85,11 +97,48 @@ public class LocatorSetCustomizer extends FutureJVppCustomizer
                                         @Nonnull LocatorSet dataBefore,
                                         @Nonnull WriteContext writeContext) throws WriteFailedException {
         final String locatorSetName = dataBefore.getName();
+
+        final Optional<EidTable> eidTableData = writeContext.readAfter(InstanceIdentifier.create(Lisp.class)
+                .child(LispFeatureData.class)
+                .child(EidTable.class));
+
+        if (eidTableData.isPresent()) {
+            // due to non-functional LeafRefValidation, it must be checked like this
+            final List<VniTable> vniTables =
+                    Optional.fromNullable(eidTableData.get().getVniTable()).or(Collections.emptyList());
+            checkReferenceExist(id, vrfReferences(vniTables, locatorSetName));
+            checkReferenceExist(id, bdReferences(vniTables, locatorSetName));
+        }
+
         addDelLocatorSetAndReply(false, dataBefore.getName(), id);
         //removes mapping after successful delete
         locatorSetContext.removeName(locatorSetName, writeContext.getMappingContext());
     }
 
+    private Collection<LocalMapping> bdReferences(final List<VniTable> vniTables,
+                                                  final String locatorSetName) {
+        return vniTables.stream()
+                .map(vniTable -> java.util.Optional.ofNullable(vniTable.getBridgeDomainSubtable())
+                        .map(DpSubtableGrouping::getLocalMappings)
+                        .map(LocalMappings::getLocalMapping)
+                        .orElse(Collections.emptyList()))
+                .flatMap(Collection::stream)
+                .filter(localMapping -> locatorSetName.equals(localMapping.getLocatorSet()))
+                .collect(Collectors.toSet());
+    }
+
+    private static Collection<LocalMapping> vrfReferences(final List<VniTable> vniTables,
+                                                          final String locatorSetName) {
+        return vniTables.stream()
+                .map(vniTable -> java.util.Optional.ofNullable(vniTable.getVrfSubtable())
+                        .map(DpSubtableGrouping::getLocalMappings)
+                        .map(LocalMappings::getLocalMapping)
+                        .orElse(Collections.emptyList()))
+                .flatMap(Collection::stream)
+                .filter(localMapping -> locatorSetName.equals(localMapping.getLocatorSet()))
+                .collect(Collectors.toSet());
+    }
+
     private int addDelLocatorSetAndReply(final boolean add, final String name, final InstanceIdentifier<LocatorSet> id)
             throws WriteFailedException {
 
index b29e1a0..734dddd 100755 (executable)
@@ -40,6 +40,14 @@ import java.util.Arrays;
 import java.util.concurrent.ExecutionException;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.Lisp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.dp.subtable.grouping.LocalMappingsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.dp.subtable.grouping.local.mappings.LocalMappingBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.eid.table.grouping.EidTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.eid.table.grouping.EidTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.eid.table.grouping.eid.table.VniTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.eid.table.grouping.eid.table.vni.table.VrfSubtableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.lisp.feature.data.grouping.LispFeatureData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.locator.sets.grouping.LocatorSets;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.locator.sets.grouping.locator.sets.LocatorSet;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.locator.sets.grouping.locator.sets.LocatorSetBuilder;
@@ -49,6 +57,15 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 public class LocatorSetCustomizerTest extends WriterCustomizerTest {
 
+    private static final InstanceIdentifier<EidTable>
+            EID_TABLE_ID = InstanceIdentifier.create(Lisp.class)
+            .child(LispFeatureData.class)
+            .child(EidTable.class);
+
+    private static final LocatorSet LOCATOR_SET_TO_DELETE = new LocatorSetBuilder()
+            .setName("Locator")
+            .build();
+
     private LocatorSetCustomizer customizer;
 
     @Override
@@ -126,10 +143,25 @@ public class LocatorSetCustomizerTest extends WriterCustomizerTest {
 
     @Test
     public void testDeleteCurrentAttributes() throws InterruptedException, ExecutionException, WriteFailedException {
-        LocatorSet locatorSet = new LocatorSetBuilder()
-                .setName("Locator")
-                .build();
+        when(writeContext.readAfter(EID_TABLE_ID)).thenReturn(Optional.absent());
+        verifySuccessfullDelete(LOCATOR_SET_TO_DELETE);
+    }
+
+    @Test
+    public void testDeleteCurrentAttributesWithoutLocalMappingContainer()
+            throws InterruptedException, ExecutionException, WriteFailedException {
+        when(writeContext.readAfter(EID_TABLE_ID)).thenReturn(eidTableDataWithoutLocalMappingContainer());
+        verifySuccessfullDelete(LOCATOR_SET_TO_DELETE);
+    }
+
+    @Test
+    public void testDeleteCurrentAttributesWithoutLocalMappingValues()
+            throws InterruptedException, ExecutionException, WriteFailedException {
+        when(writeContext.readAfter(EID_TABLE_ID)).thenReturn(eidTableDataWithoutLocalMappingValues());
+        verifySuccessfullDelete(LOCATOR_SET_TO_DELETE);
+    }
 
+    private void verifySuccessfullDelete(final LocatorSet locatorSet) throws WriteFailedException {
         ArgumentCaptor<LispAddDelLocatorSet> locatorSetCaptor = ArgumentCaptor.forClass(LispAddDelLocatorSet.class);
 
         when(api.lispAddDelLocatorSet(any(LispAddDelLocatorSet.class)))
@@ -145,4 +177,55 @@ public class LocatorSetCustomizerTest extends WriterCustomizerTest {
         assertEquals("Locator", new String(request.locatorSetName));
         assertEquals(0, request.isAdd);
     }
+
+    @Test
+    public void testDeleteReferenced() throws InterruptedException, ExecutionException, WriteFailedException {
+        when(writeContext.readAfter(EID_TABLE_ID))
+                .thenReturn(eidTableData());
+
+        ArgumentCaptor<LispAddDelLocatorSet> locatorSetCaptor = ArgumentCaptor.forClass(LispAddDelLocatorSet.class);
+
+        when(api.lispAddDelLocatorSet(any(LispAddDelLocatorSet.class)))
+                .thenReturn(future(new LispAddDelLocatorSetReply()));
+
+        try {
+            customizer.deleteCurrentAttributes(null, LOCATOR_SET_TO_DELETE, writeContext);
+        } catch (IllegalStateException e) {
+            verify(api, times(0)).lispAddDelLocatorSet(locatorSetCaptor.capture());
+            return;
+        }
+        fail("testDeleteReferenced should have failed");
+    }
+
+    private static Optional<EidTable> eidTableData() {
+        return Optional.of(new EidTableBuilder()
+                .setVniTable(
+                        Arrays.asList(new VniTableBuilder()
+                                .setVrfSubtable(new VrfSubtableBuilder()
+                                        .setLocalMappings(new LocalMappingsBuilder()
+                                                .setLocalMapping(Arrays.asList(
+                                                        new LocalMappingBuilder().setLocatorSet("Locator")
+                                                                .build(),
+                                                        new LocalMappingBuilder()
+                                                                .setLocatorSet("OtherLocatorSet").build()
+                                                )).build()).build()).build())).build());
+    }
+
+    private static Optional<EidTable> eidTableDataWithoutLocalMappingValues() {
+        return Optional.of(new EidTableBuilder()
+                .setVniTable(
+                        Arrays.asList(new VniTableBuilder()
+                                .setVrfSubtable(new VrfSubtableBuilder()
+                                        .setLocalMappings(new LocalMappingsBuilder().build()).build()).build()))
+                .build());
+    }
+
+    private static Optional<EidTable> eidTableDataWithoutLocalMappingContainer() {
+        return Optional.of(new EidTableBuilder()
+                .setVniTable(
+                        Arrays.asList(new VniTableBuilder().setVrfSubtable(new VrfSubtableBuilder().build()).build()))
+                .build());
+    }
+
+
 }
diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/ReferenceCheck.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/ReferenceCheck.java
new file mode 100644 (file)
index 0000000..847f28a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.common.translate.util;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Checks references exist, and throws if present
+ */
+public interface ReferenceCheck {
+
+    /**
+     * Checks if references are present, and throw if so
+     *
+     * @throws IllegalStateException if any references present
+     */
+    default <T extends DataObject> void checkReferenceExist(@Nonnull final InstanceIdentifier<?> locSetId,
+                                                                  final Collection<T> references) {
+        checkState(references == null || references.isEmpty(), "%s is referenced in %s", locSetId, references);
+    }
+}