diff options
author | Marek Gradzki <mgradzki@cisco.com> | 2018-06-14 12:12:07 +0200 |
---|---|---|
committer | Marek Gradzki <mgradzki@cisco.com> | 2018-08-17 11:42:56 +0000 |
commit | 16d190d24cfb3286ffd941d690c656d7e5d73928 (patch) | |
tree | 394de8595958d7ed803bff0253d5c66d3a8a54da | |
parent | 4eee8fa4da610eced563f12f9ee935130fdb09c7 (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>
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) |