summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Gradzki <mgradzki@cisco.com>2018-06-14 12:12:07 +0200
committerMarek Gradzki <mgradzki@cisco.com>2018-08-17 11:42:56 +0000
commit16d190d24cfb3286ffd941d690c656d7e5d73928 (patch)
tree394de8595958d7ed803bff0253d5c66d3a8a54da
parent4eee8fa4da610eced563f12f9ee935130fdb09c7 (diff)
HC2VPP-343: enable validation for acl list
This patch moves all validation for acl list to VppAclValidator, implementation of Validator interface brought by (HONEYCOMB-431): https://gerrit.fd.io/r/#/c/14022/ To test <validate> RPC, run ncclient tests with: ./edit_config.py acl/copy_config_unsupported-acl-type.xml -v Support for <validate> RPC requres: https://gerrit.fd.io/r/#/c/14040/ Change-Id: Iea591a76022e893f6aaf2a52637f45cadb284e4e Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
-rw-r--r--acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclValidator.java84
-rw-r--r--acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java80
-rw-r--r--acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclValidator.java178
-rw-r--r--acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java5
-rw-r--r--acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/VppAclCustomizerTest.java28
-rw-r--r--acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/VppAclValidatorTest.java (renamed from acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/AclReferenceCheckTest.java)67
-rw-r--r--acl/acl-impl/src/test/resources/acl/ipv4/ipv4-acl.json17
-rw-r--r--acl/acl-impl/src/test/resources/interface-acl/acl-references.json (renamed from acl/acl-impl/src/test/resources/reference/acl-references.json)0
-rw-r--r--examples/ncclient/acl/copy_config_unsupported-acl-type.xml15
-rwxr-xr-xexamples/ncclient/acl/test_invalid_acl.sh18
-rwxr-xr-xexamples/ncclient/edit_config.py43
11 files changed, 338 insertions, 197 deletions
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclValidator.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclValidator.java
deleted file mode 100644
index c73841596..000000000
--- a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclValidator.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.acl.util.acl;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-import javax.annotation.Nonnull;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AclBase;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.Matches;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.AceType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.VppAcl;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.VppMacipAcl;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.access.lists.acl.access.list.entries.ace.matches.ace.type.VppMacipAce;
-
-/**
- * Validate Acl data if processable by vpp
- */
-public interface AclValidator {
-
- Set<Class<? extends AclBase>> SUPPORTED_ACL_TYPES = ImmutableSet.of(VppAcl.class, VppMacipAcl.class);
-
- Map<Class<? extends AclBase>, Class<? extends AceType>> ACL_ACE_PAIRS = ImmutableMap.of(
- VppAcl.class, VppAce.class,
- VppMacipAcl.class, VppMacipAce.class);
-
- static void isSupportedAclType(final Acl acl) {
- checkArgument(SUPPORTED_ACL_TYPES.contains(acl.getAclType()),
- "Unsupported Acl type %s detected for acl %s, allowed types are %s", acl.getAclType(),
- acl.getAclName(), SUPPORTED_ACL_TYPES);
- }
-
- static void hasConsistentAceTypeForAclType(final Acl acl) {
- checkTypesSame(acl.getAccessListEntries().getAce(), acl.getAclName(),
- checkNotNull(ACL_ACE_PAIRS.get(acl.getAclType()), "Unsupported ACL type %s for ACL %s",
- acl.getAclType(), acl.getAclName()));
- }
-
- static void checkTypesSame(final List<Ace> aces, final String aclName, final Class<? extends AceType> aceType) {
- final Set<AceType> unsupportedAceTypes = aces.stream()
- .map(Ace::getMatches)
- .map(Matches::getAceType)
- .filter(aceType::equals)
- .collect(Collectors.toSet());
- checkArgument(unsupportedAceTypes.isEmpty(), "Detected unsupported ace types [%s] for ACL %s, expected %s",
- unsupportedAceTypes, aclName, aceType);
- }
-
- static void hasAceList(final Acl acl) {
- //checks if aces are defined
- checkArgument(!checkNotNull(checkNotNull(acl.getAccessListEntries(), "No access list entries defined")
- .getAce(), "No aces defined")
- .isEmpty(), "Empty ace list defined");
- }
-
- default void validateAcl(@Nonnull final Acl acl) {
- hasAceList(acl);
- isSupportedAclType(acl);
- hasConsistentAceTypeForAclType(acl);
- }
-}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java
index 7da38bc94..00cd8a56c 100644
--- a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java
+++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java
@@ -16,45 +16,22 @@
package io.fd.hc2vpp.acl.write;
-import static com.google.common.base.Preconditions.checkState;
-import static io.fd.hc2vpp.acl.write.VppAclCustomizer.AclReferenceCheck.checkAclReferenced;
-import static java.lang.String.format;
-import static java.util.Collections.emptyList;
-import static java.util.Optional.ofNullable;
-
-import com.google.common.base.Optional;
import io.fd.hc2vpp.acl.util.AclContextManager;
import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer;
import io.fd.hc2vpp.acl.util.acl.AclDataExtractor;
-import io.fd.hc2vpp.acl.util.acl.AclValidator;
import io.fd.hc2vpp.acl.util.acl.AclWriter;
import io.fd.honeycomb.translate.MappingContext;
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.acl.future.FutureJVppAclFacade;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AclBase;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.InterfaceAclAttributes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceAugmentation;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclsBaseAttributes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppMacipAclsBaseAttributes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.Egress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.Ingress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.VppAcl;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.VppMacipAcl;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
public class VppAclCustomizer extends FutureJVppAclCustomizer
- implements ListWriterCustomizer<Acl, AclKey>, AclValidator, AclDataExtractor, AclWriter {
+ implements ListWriterCustomizer<Acl, AclKey>, AclDataExtractor, AclWriter {
private final AclContextManager standardAclContext;
private final AclContextManager macIpAclContext;
@@ -70,8 +47,6 @@ public class VppAclCustomizer extends FutureJVppAclCustomizer
@Override
public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataAfter,
@Nonnull final WriteContext writeContext) throws WriteFailedException {
- validateAcl(dataAfter);
-
final MappingContext mappingContext = writeContext.getMappingContext();
if (isStandardAcl(dataAfter)) {
@@ -89,8 +64,6 @@ public class VppAclCustomizer extends FutureJVppAclCustomizer
public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
@Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext)
throws WriteFailedException {
- validateAcl(dataAfter);
-
final MappingContext mappingContext = writeContext.getMappingContext();
if (isStandardAcl(dataAfter)) {
@@ -113,14 +86,6 @@ public class VppAclCustomizer extends FutureJVppAclCustomizer
@Override
public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore,
@Nonnull final WriteContext writeContext) throws WriteFailedException {
- validateAcl(dataBefore);
-
- final List<Interface> references = checkAclReferenced(writeContext, dataBefore);
- // references must be check, to not leave dead references in configuration
- checkState(references.isEmpty(),
- "%s cannot be removed, it is referenced in following interfaces %s", dataBefore,
- references);
-
final MappingContext mappingContext = writeContext.getMappingContext();
if (isStandardAcl(dataBefore)) {
@@ -133,47 +98,4 @@ public class VppAclCustomizer extends FutureJVppAclCustomizer
new IllegalArgumentException("Unsupported acl option"));
}
}
-
- static final class AclReferenceCheck {
-
- static List<Interface> checkAclReferenced(@Nonnull final WriteContext writeContext,
- @Nonnull final Acl acl) {
- final Optional<Interfaces> readAfter = writeContext.readAfter(InstanceIdentifier.create(Interfaces.class));
- if (!readAfter.isPresent() || readAfter.get().getInterface() == null) {
- return Collections.emptyList();
- }
-
- final List<Interface> interfaces = readAfter.get().getInterface();
- final Class<? extends AclBase> aclType = acl.getAclType();
- final String aclName = acl.getAclName();
-
- if (aclType.equals(VppAcl.class)) {
- return interfaces.stream()
- .filter(iface -> ofNullable(iface.getAugmentation(VppAclInterfaceAugmentation.class))
- .map(InterfaceAclAttributes::getAcl)
- .filter(references ->
- checkVppAcls(references.getIngress(), aclName) ||
- checkVppAcls(references.getEgress(), aclName)).isPresent()
- ).collect(Collectors.toList());
- } else if (aclType.equals(VppMacipAcl.class)) {
- return interfaces.stream()
- .filter(iface -> ofNullable(iface.getAugmentation(VppAclInterfaceAugmentation.class))
- .map(InterfaceAclAttributes::getAcl)
- .map(aclAttr -> aclAttr.getIngress())
- .map(VppMacipAclsBaseAttributes::getVppMacipAcl)
- .filter(vppMacipAcl -> vppMacipAcl.getName().equals(aclName))
- .isPresent())
- .collect(Collectors.toList());
- } else {
- throw new IllegalArgumentException(format("Acl type %s not supported", aclType));
- }
- }
-
- static boolean checkVppAcls(@Nullable final VppAclsBaseAttributes attrs, @Nonnull final String name) {
- return ofNullable(attrs).map(VppAclsBaseAttributes::getVppAcls)
- .orElse(emptyList())
- .stream().anyMatch(acl -> acl.getName().equals(name));
-
- }
- }
}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclValidator.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclValidator.java
new file mode 100644
index 000000000..e1f4c8dc0
--- /dev/null
+++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclValidator.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2018 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.acl.write;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static java.lang.String.format;
+import static java.util.Collections.emptyList;
+import static java.util.Optional.ofNullable;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import io.fd.hc2vpp.acl.util.acl.AclDataExtractor;
+import io.fd.honeycomb.translate.write.DataValidationFailedException.CreateValidationFailedException;
+import io.fd.honeycomb.translate.write.DataValidationFailedException.DeleteValidationFailedException;
+import io.fd.honeycomb.translate.write.DataValidationFailedException.UpdateValidationFailedException;
+import io.fd.honeycomb.translate.write.Validator;
+import io.fd.honeycomb.translate.write.WriteContext;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AclBase;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.AccessListEntries;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.Matches;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.AceType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.InterfaceAclAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclsBaseAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppMacipAclsBaseAttributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.VppAcl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.VppMacipAcl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.access.lists.acl.access.list.entries.ace.matches.ace.type.VppMacipAce;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public final class VppAclValidator implements Validator<Acl>, AclDataExtractor {
+
+ private static final Set<Class<? extends AclBase>> SUPPORTED_ACL_TYPES =
+ ImmutableSet.of(VppAcl.class, VppMacipAcl.class);
+ private static final Map<Class<? extends AclBase>, Class<? extends AceType>> ACL_ACE_PAIRS =
+ ImmutableMap.of(VppAcl.class, VppAce.class, VppMacipAcl.class, VppMacipAce.class);
+
+ @Override
+ public void validateWrite(final InstanceIdentifier<Acl> id, final Acl dataAfter, final WriteContext ctx)
+ throws CreateValidationFailedException {
+ try {
+ validateAcl(dataAfter);
+ } catch (RuntimeException e) {
+ throw new CreateValidationFailedException(id, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void validateUpdate(final InstanceIdentifier<Acl> id, final Acl dataBefore, final Acl dataAfter,
+ final WriteContext ctx) throws UpdateValidationFailedException {
+ try {
+ validateAcl(dataAfter);
+ } catch (RuntimeException e) {
+ throw new UpdateValidationFailedException(id, dataBefore, dataAfter, e);
+ }
+ }
+
+ @Override
+ public void validateDelete(final InstanceIdentifier<Acl> id, final Acl dataBefore, final WriteContext ctx)
+ throws DeleteValidationFailedException {
+ try {
+ validateAcl(dataBefore);
+ final List<Interface> references = checkAclReferenced(ctx, dataBefore);
+ // references must be check, to not leave dead references in configuration
+ checkState(references.isEmpty(),
+ "%s cannot be removed, it is referenced in following interfaces %s", dataBefore, references);
+ } catch (RuntimeException e) {
+ throw new DeleteValidationFailedException(id, e);
+ }
+ }
+
+ private static void validateAcl(@Nonnull final Acl acl) {
+ hasAceList(acl);
+ isSupportedAclType(acl);
+ hasConsistentAceTypeForAclType(acl);
+ }
+
+ private static void hasAceList(final Acl acl) {
+ final AccessListEntries accessListEntries = acl.getAccessListEntries();
+ checkArgument(accessListEntries != null, "The access-list-entries container is not defined.");
+ final List<Ace> ace = accessListEntries.getAce();
+ checkArgument(ace != null, "The ace list is not defined.");
+ checkArgument(!ace.isEmpty(), "The ace list is empty.");
+ }
+
+ private static void isSupportedAclType(final Acl acl) {
+ checkArgument(SUPPORTED_ACL_TYPES.contains(acl.getAclType()),
+ "Unsupported Acl type %s detected for acl %s, allowed types are %s", acl.getAclType(),
+ acl.getAclName(), SUPPORTED_ACL_TYPES);
+ }
+
+ private static void hasConsistentAceTypeForAclType(final Acl acl) {
+ checkTypesSame(acl.getAccessListEntries().getAce(), acl.getAclName(),
+ checkNotNull(ACL_ACE_PAIRS.get(acl.getAclType()), "Unsupported ACL type %s for ACL %s",
+ acl.getAclType(), acl.getAclName()));
+ }
+
+ private static void checkTypesSame(final List<Ace> aces, final String aclName,
+ final Class<? extends AceType> aceType) {
+ final Set<AceType> unsupportedAceTypes = aces.stream()
+ .map(Ace::getMatches)
+ .map(Matches::getAceType)
+ .filter(aceType::equals)
+ .collect(Collectors.toSet());
+ checkArgument(unsupportedAceTypes.isEmpty(), "Detected unsupported ace types [%s] for ACL %s, expected %s",
+ unsupportedAceTypes, aclName, aceType);
+ }
+
+ @VisibleForTesting
+ static List<Interface> checkAclReferenced(@Nonnull final WriteContext writeContext,
+ @Nonnull final Acl acl) {
+ final Optional<Interfaces> readAfter = writeContext.readAfter(InstanceIdentifier.create(Interfaces.class));
+ if (!readAfter.isPresent() || readAfter.get().getInterface() == null) {
+ return Collections.emptyList();
+ }
+
+ final List<Interface> interfaces = readAfter.get().getInterface();
+ final Class<? extends AclBase> aclType = acl.getAclType();
+ final String aclName = acl.getAclName();
+
+ if (aclType.equals(VppAcl.class)) {
+ return interfaces.stream()
+ .filter(iface -> ofNullable(iface.getAugmentation(VppAclInterfaceAugmentation.class))
+ .map(InterfaceAclAttributes::getAcl)
+ .filter(references ->
+ checkVppAcls(references.getIngress(), aclName) ||
+ checkVppAcls(references.getEgress(), aclName)).isPresent()
+ ).collect(Collectors.toList());
+ } else if (aclType.equals(VppMacipAcl.class)) {
+ return interfaces.stream()
+ .filter(iface -> ofNullable(iface.getAugmentation(VppAclInterfaceAugmentation.class))
+ .map(InterfaceAclAttributes::getAcl)
+ .map(aclAttr -> aclAttr.getIngress())
+ .map(VppMacipAclsBaseAttributes::getVppMacipAcl)
+ .filter(vppMacipAcl -> vppMacipAcl.getName().equals(aclName))
+ .isPresent())
+ .collect(Collectors.toList());
+ } else {
+ throw new IllegalArgumentException(format("Acl type %s not supported", aclType));
+ }
+ }
+
+ private static boolean checkVppAcls(@Nullable final VppAclsBaseAttributes attrs, @Nonnull final String name) {
+ return ofNullable(attrs).map(VppAclsBaseAttributes::getVppAcls)
+ .orElse(emptyList())
+ .stream().anyMatch(acl -> acl.getName().equals(name));
+ }
+}
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java
index 2b95f0b60..883cf4f1f 100644
--- a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java
+++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java
@@ -21,6 +21,7 @@ import static io.fd.hc2vpp.acl.write.factory.InterfaceAclWriterFactory.aclHandle
import io.fd.hc2vpp.acl.util.factory.AclFactory;
import io.fd.hc2vpp.acl.write.VppAclCustomizer;
+import io.fd.hc2vpp.acl.write.VppAclValidator;
import io.fd.honeycomb.translate.impl.write.GenericListWriter;
import io.fd.honeycomb.translate.write.WriterFactory;
import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
@@ -37,7 +38,9 @@ public class VppAclWriterFactory extends AbstractAclWriterFactory implements Wri
registry.subtreeAddBefore(vppAclChildren(InstanceIdentifier.create(Acl.class)),
new GenericListWriter<>(rootNode.child(Acl.class),
- new VppAclCustomizer(futureAclFacade, standardAclContext, macIpAClContext)),
+ new VppAclCustomizer(futureAclFacade, standardAclContext, macIpAClContext),
+ new VppAclValidator()
+ ),
aclHandledChildren(ACL_IID));
}
}
diff --git a/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/VppAclCustomizerTest.java b/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/VppAclCustomizerTest.java
index 63633aa75..a3fa6db0e 100644
--- a/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/VppAclCustomizerTest.java
+++ b/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/VppAclCustomizerTest.java
@@ -18,9 +18,7 @@ package io.fd.hc2vpp.acl.write;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -43,7 +41,6 @@ import io.fd.vpp.jvpp.acl.types.AclRule;
import io.fd.vpp.jvpp.acl.types.MacipAclRule;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
-import java.util.Collections;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -53,10 +50,6 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.cont
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceAugmentation;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceStateAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.VppAcl;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -278,27 +271,6 @@ public class VppAclCustomizerTest extends WriterCustomizerTest implements AclTes
assertEquals(aclIndex, aclDelRequestCaptor.getValue().aclIndex);
}
- @Test
- public void deleteCurrentAttributesUdpReferenced(
- @InjectTestData(resourcePath = "/acl/standard/standard-acl-udp.json")
- AccessLists standardAcls,
- @InjectTestData(resourcePath = "/acl/standard/interface-ref-acl-udp.json")
- Interfaces references) throws Exception {
- // TODO - HONEYCOMB-349 - change after resolving to specific node injection
- when(writeContext.readAfter(InstanceIdentifier.create(Interfaces.class))).thenReturn(
- Optional.of(new InterfacesBuilder().setInterface(references.getInterface()).build()));
-
- final int aclIndex = 4;
- when(standardAclContext.getAclIndex("standard-acl", mappingContext)).thenReturn(aclIndex);
- try {
- aclCustomizer.deleteCurrentAttributes(validId, standardAcls.getAcl().get(0), writeContext);
- } catch (IllegalStateException e) {
- verify(aclApi, never()).aclDel(any(AclDel.class));
- return;
- }
- fail("IllegalStateException should have been thrown");
- }
-
private void verifyUdpRequest(final int aclIndex) {
final AclAddReplace request = aclAddReplaceRequestCaptor.getValue();
assertEquals(aclIndex, request.aclIndex);
diff --git a/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/AclReferenceCheckTest.java b/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/VppAclValidatorTest.java
index 8d89845f6..287e53f80 100644
--- a/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/AclReferenceCheckTest.java
+++ b/acl/acl-impl/src/test/java/io/fd/hc2vpp/acl/write/VppAclValidatorTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Copyright (c) 2018 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.
@@ -16,7 +16,7 @@
package io.fd.hc2vpp.acl.write;
-import static io.fd.hc2vpp.acl.write.VppAclCustomizer.AclReferenceCheck.checkAclReferenced;
+import static io.fd.hc2vpp.acl.write.VppAclValidator.checkAclReferenced;
import static java.util.stream.Collectors.toSet;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
@@ -28,33 +28,90 @@ import com.google.common.base.Optional;
import io.fd.hc2vpp.acl.AclTestSchemaContext;
import io.fd.honeycomb.test.tools.HoneycombTestRunner;
import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.translate.write.DataValidationFailedException;
import io.fd.honeycomb.translate.write.WriteContext;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AccessLists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.VppAcl;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.VppMacipAcl;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
@RunWith(HoneycombTestRunner.class)
-public class AclReferenceCheckTest implements AclTestSchemaContext {
+public class VppAclValidatorTest implements AclTestSchemaContext {
+
+ private static final InstanceIdentifier<Acl> ID = InstanceIdentifier.create(AccessLists.class)
+ .child(Acl.class, new AclKey("standard-acl", VppAcl.class));
- @InjectTestData(id = "/ietf-interfaces:interfaces", resourcePath = "/reference/acl-references.json")
+ @InjectTestData(id = "/ietf-interfaces:interfaces", resourcePath = "/interface-acl/acl-references.json")
private Interfaces interfaces;
@Mock
private WriteContext writeContext;
+ private VppAclValidator validator;
+
@Before
public void init(){
initMocks(this);
when(writeContext.readAfter(InstanceIdentifier.create(Interfaces.class))).thenReturn(Optional.of(interfaces));
+ validator = new VppAclValidator();
+ }
+
+ @Test
+ public void testValidateWrite(
+ @InjectTestData(resourcePath = "/acl/standard/standard-acl-icmp.json") AccessLists acls)
+ throws DataValidationFailedException.CreateValidationFailedException {
+ validator.validateWrite(ID, acls.getAcl().get(0), writeContext);
+ }
+
+ @Test(expected = DataValidationFailedException.CreateValidationFailedException.class)
+ public void testValidateWriteEmptyAcl()
+ throws DataValidationFailedException.CreateValidationFailedException {
+ validator.validateWrite(ID, new AclBuilder().build(), writeContext);
+ }
+
+ @Test
+ public void testValidateUpdate(
+ @InjectTestData(resourcePath = "/acl/standard/standard-acl-icmp.json") AccessLists acls)
+ throws DataValidationFailedException.UpdateValidationFailedException {
+ final Acl data = acls.getAcl().get(0);
+ validator.validateUpdate(ID, data, data, writeContext);
+ }
+
+ @Test(expected = DataValidationFailedException.UpdateValidationFailedException.class)
+ public void testValidateUpdateUnsupportedType(
+ @InjectTestData(resourcePath = "/acl/ipv4/ipv4-acl.json") AccessLists acls)
+ throws DataValidationFailedException.UpdateValidationFailedException {
+ final Acl data = acls.getAcl().get(0);
+ validator.validateUpdate(ID, data, data, writeContext);
+ }
+
+ @Test
+ public void testValidateDelete(
+ @InjectTestData(resourcePath = "/acl/standard/standard-acl-icmp.json") AccessLists acls)
+ throws DataValidationFailedException.DeleteValidationFailedException {
+ validator.validateDelete(ID, acls.getAcl().get(0), writeContext);
+ }
+
+ @Test(expected = DataValidationFailedException.DeleteValidationFailedException.class)
+ public void testValidateDeleteReferenced(
+ @InjectTestData(resourcePath = "/acl/standard/standard-acl-udp.json")
+ AccessLists standardAcls,
+ @InjectTestData(resourcePath = "/acl/standard/interface-ref-acl-udp.json")
+ Interfaces references) throws Exception {
+ when(writeContext.readAfter(InstanceIdentifier.create(Interfaces.class))).thenReturn(
+ Optional.of(new InterfacesBuilder().setInterface(references.getInterface()).build()));
+ validator.validateDelete(ID, standardAcls.getAcl().get(0), writeContext);
}
@Test
diff --git a/acl/acl-impl/src/test/resources/acl/ipv4/ipv4-acl.json b/acl/acl-impl/src/test/resources/acl/ipv4/ipv4-acl.json
new file mode 100644
index 000000000..04a08ff44
--- /dev/null
+++ b/acl/acl-impl/src/test/resources/acl/ipv4/ipv4-acl.json
@@ -0,0 +1,17 @@
+{
+ "access-lists": {
+ "acl": [
+ {
+ "acl-name": "standard-acl",
+ "acl-type": "ipv4-acl",
+ "access-list-entries": {
+ "ace": [
+ {
+ "rule-name": "rule1"
+ }
+ ]
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/acl/acl-impl/src/test/resources/reference/acl-references.json b/acl/acl-impl/src/test/resources/interface-acl/acl-references.json
index 63c9e20c9..63c9e20c9 100644
--- a/acl/acl-impl/src/test/resources/reference/acl-references.json
+++ b/acl/acl-impl/src/test/resources/interface-acl/acl-references.json
diff --git a/examples/ncclient/acl/copy_config_unsupported-acl-type.xml b/examples/ncclient/acl/copy_config_unsupported-acl-type.xml
new file mode 100644
index 000000000..b86a11924
--- /dev/null
+++ b/examples/ncclient/acl/copy_config_unsupported-acl-type.xml
@@ -0,0 +1,15 @@
+<!--
+ ~ Copyright (c) 2018 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
+ -->
+<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <access-lists xmlns="urn:ietf:params:xml:ns:yang:ietf-access-control-list" xc:operation="create">
+ <acl>
+ <acl-name>acl0</acl-name>
+ <acl-type>ipv4-acl</acl-type>
+ </acl>
+ </access-lists>
+</config>
diff --git a/examples/ncclient/acl/test_invalid_acl.sh b/examples/ncclient/acl/test_invalid_acl.sh
new file mode 100755
index 000000000..aedb842af
--- /dev/null
+++ b/examples/ncclient/acl/test_invalid_acl.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (c) 2018 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.
+
+DIR_NAME=$(dirname $0)
+
+${DIR_NAME}/../test_copy_config.sh ${DIR_NAME}/copy_config_acl.xml ${DIR_NAME}/expected_config_acl.xml
diff --git a/examples/ncclient/edit_config.py b/examples/ncclient/edit_config.py
new file mode 100755
index 000000000..cafb7d475
--- /dev/null
+++ b/examples/ncclient/edit_config.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python2
+#
+# Copyright (c) 2018 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.
+
+import argparse
+import logging
+from ncclient import manager
+
+
+def _edit_config(config_filename, host='localhost', port=2831, username='admin', password='admin',
+ validate=False, commit=False):
+ with manager.connect(host=host, port=port, username=username, password=password, hostkey_verify=False) as m:
+ logger.info("Connected to HC")
+ with open(config_filename, 'r') as f:
+ ret = m.edit_config(config=f.read())
+ logger.debug("EditConfig successful:\n%s" % ret)
+ validate = m.validate()
+ logger.debug("Validate successful:\n%s" % validate)
+ commit = m.commit()
+ logger.debug("Commit successful:\n%s" % commit)
+
+if __name__ == '__main__':
+ logger = logging.getLogger("hc2vpp.examples.edit_config")
+ logging.basicConfig(level=logging.WARNING)
+ argparser = argparse.ArgumentParser(description="Configures VPP using <edit-config> RPC")
+ argparser.add_argument('config_filename', help="name of XML file with <config> element")
+ argparser.add_argument('-v', '--validate', help="sends <validate> RPC is <edit-config> was successful",
+ action="store_true")
+ argparser.add_argument('-c', '--commit', help="commits candidate configuration",
+ action="store_true")
+ args = argparser.parse_args()
+ _edit_config(args.config_filename, validate=args.validate, commit=args.commit)