From 433e422d60c59f47b76682f18affa161d0301be4 Mon Sep 17 00:00:00 2001 From: Michal Cmarada Date: Thu, 2 Jun 2016 18:41:54 +0200 Subject: [PATCH] Introduced InterfaceManager in VPP renderer - creates vhostuser interfaces on VPP (vhostuser interface is not assigned to any bridge domain) - trigger is creating of vpp-endpoint from on vpp-renderer.yang - does not handle case when a netconf device is connected after vpp-endpoint was created Change-Id: I11ea9e0446d9297129b9a928a8417b95944739e1 Signed-off-by: Martin Sunal Signed-off-by: Michal Cmarada --- .../groupbasedpolicy/util/IidFactory.java | 19 +- renderers/vpp/pom.xml | 7 + .../config/vpp_provider/impl/VppRenderer.java | 30 +- .../vpp/commands/VhostUserCommand.java | 48 ++- .../renderer/vpp/event/DtoChangeEvent.java | 135 +++++++ .../renderer/vpp/event/NodeOperEvent.java | 50 +++ .../vpp/event/VppEndpointConfEvent.java | 20 ++ .../renderer/vpp/iface/InterfaceManager.java | 201 +++++++++++ .../iface/VppEndpointLocationProvider.java | 137 ++++++++ .../vpp/listener/RendererPolicyListener.java | 53 +++ .../vpp/listener/VppEndpointListener.java | 65 ++++ .../vpp/listener/VppNodeListener.java | 9 +- .../vpp/util/MountedDataBrokerProvider.java | 40 +++ .../src/main/yang/vbd/v3po@2015-01-05.yang | 328 ++++++++++-------- .../vpp/commands/VhostUserCommandTest.java | 9 +- .../vpp/event/DtoChangeEventTest.java | 95 +++++ .../renderer/vpp/event/NodeOperEventTest.java | 139 ++++++++ .../vpp/event/VppEndpointConfEventTest.java | 73 ++++ .../vpp/iface/InterfaceManagerTest.java | 181 ++++++++++ .../vpp/listener/VppEndpointListenerTest.java | 143 ++++++++ .../vpp/manager/VppManagerDataStoreTest.java | 3 +- 21 files changed, 1606 insertions(+), 179 deletions(-) create mode 100644 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/DtoChangeEvent.java create mode 100644 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/NodeOperEvent.java create mode 100644 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/VppEndpointConfEvent.java create mode 100644 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManager.java create mode 100644 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/VppEndpointLocationProvider.java create mode 100644 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/RendererPolicyListener.java create mode 100644 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppEndpointListener.java create mode 100644 renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/MountedDataBrokerProvider.java create mode 100644 renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/DtoChangeEventTest.java create mode 100644 renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/NodeOperEventTest.java create mode 100644 renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/VppEndpointConfEventTest.java create mode 100644 renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManagerTest.java create mode 100644 renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppEndpointListenerTest.java diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/IidFactory.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/IidFactory.java index f04cf4118..b9a85bd55 100644 --- a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/IidFactory.java +++ b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/IidFactory.java @@ -115,7 +115,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.store.rev151215.statistics.store.StatisticRecord; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.store.rev151215.statistics.store.StatisticRecordKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; public class IidFactory { @@ -465,12 +464,22 @@ public class IidFactory { .build(); } - public static InstanceIdentifier providerAddressEndpointLocationIid(String provider, - Class addrType, String addr, Class cType, + public static InstanceIdentifier providerAddressEndpointLocationIid( + String provider, Class addrType, String addr, Class cType, ContextId containment) { + return providerAddressEndpointLocationIid(new ProviderName(provider), + new ProviderAddressEndpointLocationKey(addr, addrType, containment, cType)); + } + + public static InstanceIdentifier providerAddressEndpointLocationIid( + ProviderName provider, ProviderAddressEndpointLocationKey providerAddressEndpointLocationKey) { + return locationProviderIid(provider).child(ProviderAddressEndpointLocation.class, + providerAddressEndpointLocationKey); + } + + public static InstanceIdentifier locationProviderIid(ProviderName provider) { return InstanceIdentifier.builder(LocationProviders.class) - .child(LocationProvider.class, new LocationProviderKey(new ProviderName(provider))) - .child(ProviderAddressEndpointLocation.class, new ProviderAddressEndpointLocationKey(addr, addrType, containment, cType)) + .child(LocationProvider.class, new LocationProviderKey(provider)) .build(); } diff --git a/renderers/vpp/pom.xml b/renderers/vpp/pom.xml index 6ff00a804..c13abe18e 100644 --- a/renderers/vpp/pom.xml +++ b/renderers/vpp/pom.xml @@ -74,6 +74,13 @@ test-jar test + + org.opendaylight.groupbasedpolicy + groupbasedpolicy + ${project.version} + test-jar + test + junit junit diff --git a/renderers/vpp/src/main/java/org/opendaylight/controller/config/yang/config/vpp_provider/impl/VppRenderer.java b/renderers/vpp/src/main/java/org/opendaylight/controller/config/yang/config/vpp_provider/impl/VppRenderer.java index d0e9ac411..668fc62b9 100644 --- a/renderers/vpp/src/main/java/org/opendaylight/controller/config/yang/config/vpp_provider/impl/VppRenderer.java +++ b/renderers/vpp/src/main/java/org/opendaylight/controller/config/yang/config/vpp_provider/impl/VppRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, @@ -11,15 +11,19 @@ package org.opendaylight.controller.config.yang.config.vpp_provider.impl; import java.util.List; import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.MountPointService; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; +import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager; +import org.opendaylight.groupbasedpolicy.renderer.vpp.listener.VppEndpointListener; import org.opendaylight.groupbasedpolicy.renderer.vpp.listener.VppNodeListener; import org.opendaylight.groupbasedpolicy.renderer.vpp.manager.VppNodeManager; import org.opendaylight.groupbasedpolicy.renderer.vpp.sf.AllowAction; import org.opendaylight.groupbasedpolicy.renderer.vpp.sf.EtherTypeClassifier; +import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider; import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererBuilder; @@ -35,6 +39,7 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import com.google.common.eventbus.EventBus; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; @@ -52,9 +57,13 @@ public class VppRenderer implements AutoCloseable, BindingAwareProvider { .setSupportedParameterValues(new EtherTypeClassifier(null).getSupportedParameterValues()) .build()); - private DataBroker dataBroker; + private final DataBroker dataBroker; + private VppNodeManager vppNodeManager; + private InterfaceManager interfaceManager; + private VppNodeListener vppNodeListener; + private VppEndpointListener vppEndpointListener; public VppRenderer(DataBroker dataBroker, BindingAwareBroker bindingAwareBroker) { this.dataBroker = Preconditions.checkNotNull(dataBroker); @@ -67,6 +76,12 @@ public class VppRenderer implements AutoCloseable, BindingAwareProvider { if (vppNodeListener != null) { vppNodeListener.close(); } + if (vppEndpointListener != null) { + vppEndpointListener.close(); + } + if (interfaceManager != null) { + interfaceManager.close(); + } unregisterFromRendererManager(); } @@ -74,9 +89,16 @@ public class VppRenderer implements AutoCloseable, BindingAwareProvider { public void onSessionInitiated(BindingAwareBroker.ProviderContext providerContext) { LOG.info("starting vpp renderer"); - // vpp-node-manager + MountPointService mountService = Preconditions.checkNotNull(providerContext.getSALService(MountPointService.class)); + MountedDataBrokerProvider mountDataProvider = new MountedDataBrokerProvider(mountService); vppNodeManager = new VppNodeManager(dataBroker, providerContext); - vppNodeListener = new VppNodeListener(dataBroker, vppNodeManager); + + EventBus dtoEventBus = new EventBus("DTO events"); + interfaceManager = new InterfaceManager(mountDataProvider, dataBroker); + dtoEventBus.register(interfaceManager); + + vppNodeListener = new VppNodeListener(dataBroker, vppNodeManager, dtoEventBus); + vppEndpointListener = new VppEndpointListener(dataBroker, dtoEventBus); registerToRendererManager(); } diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommand.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommand.java index a47d04f1b..132160336 100644 --- a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommand.java +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommand.java @@ -8,10 +8,10 @@ package org.opendaylight.groupbasedpolicy.renderer.vpp.commands; -import com.google.common.base.Preconditions; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General; +import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General.Operations; import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; @@ -21,11 +21,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentationBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUserBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBasedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.attributes.interconnection.BridgeBasedBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class VhostUserCommand extends AbstractInterfaceCommand { +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; + +public class VhostUserCommand extends AbstractInterfaceCommand { private static final Logger LOG = LoggerFactory.getLogger(VhostUserCommand.class); private String socket; @@ -64,15 +67,15 @@ public class VhostUserCommand extends AbstractInterfaceCommand { switch (getOperation()) { case PUT: - LOG.info("Executing Add operation for command: {}", this); + LOG.debug("Executing Add operation for command: {}", this); put(readWriteTransaction); break; case DELETE: - LOG.info("Executing Delete operation for command: {}", this); + LOG.debug("Executing Delete operation for command: {}", this); delete(readWriteTransaction); break; case MERGE: - LOG.info("Executing Update operation for command: {}", this); + LOG.debug("Executing Update operation for command: {}", this); merge(readWriteTransaction); break; default: @@ -82,8 +85,6 @@ public class VhostUserCommand extends AbstractInterfaceCommand { } private void put(ReadWriteTransaction readWriteTransaction) { - Preconditions.checkNotNull(name, "Interface name should not be null"); - InterfaceBuilder interfaceBuilder = getVhostUserInterfaceBuilder(); readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, @@ -91,8 +92,6 @@ public class VhostUserCommand extends AbstractInterfaceCommand { } private void merge(ReadWriteTransaction readWriteTransaction) { - Preconditions.checkNotNull(name, "Interface name should not be null"); - InterfaceBuilder interfaceBuilder = getVhostUserInterfaceBuilder(); readWriteTransaction.merge(LogicalDatastoreType.CONFIGURATION, @@ -110,14 +109,14 @@ public class VhostUserCommand extends AbstractInterfaceCommand { .setLinkUpDownTrapEnable(Interface.LinkUpDownTrapEnable.Enabled); // Create the vhost augmentation - VppInterfaceAugmentation vppAugmentation = - new VppInterfaceAugmentationBuilder() - .setVhostUser(new VhostUserBuilder().setRole(role).setSocket(socket).build()) - .setL2(new L2Builder() - .setInterconnection(new BridgeBasedBuilder().setBridgeDomain(bridgeDomain).build()).build()) - .build(); - - interfaceBuilder.addAugmentation(VppInterfaceAugmentation.class, vppAugmentation); + VppInterfaceAugmentationBuilder vppAugmentationBuilder = new VppInterfaceAugmentationBuilder() + .setVhostUser(new VhostUserBuilder().setRole(role).setSocket(socket).build()); + if (!Strings.isNullOrEmpty(bridgeDomain)) { + vppAugmentationBuilder.setL2(new L2Builder() + .setInterconnection(new BridgeBasedBuilder().setBridgeDomain(bridgeDomain).build()).build()); + } + + interfaceBuilder.addAugmentation(VppInterfaceAugmentation.class, vppAugmentationBuilder.build()); return interfaceBuilder; } @@ -131,6 +130,15 @@ public class VhostUserCommand extends AbstractInterfaceCommand { } + @Override + public String toString() { + return "VhostUserCommand [socket=" + socket + ", role=" + role + ", bridgeDomain=" + bridgeDomain + + ", operation=" + operation + ", name=" + name + ", description=" + description + ", enabled=" + + enabled + "]"; + } + + + public static class VhostUserCommandBuilder { private String name; @@ -213,7 +221,9 @@ public class VhostUserCommand extends AbstractInterfaceCommand { public VhostUserCommand build() { Preconditions.checkArgument(this.name != null); Preconditions.checkArgument(this.operation != null); - Preconditions.checkArgument(this.socket != null); + if (operation == Operations.PUT) { + Preconditions.checkArgument(this.socket != null); + } return new VhostUserCommand(this); } diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/DtoChangeEvent.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/DtoChangeEvent.java new file mode 100644 index 000000000..182cc4c1c --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/DtoChangeEvent.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.event; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + +public abstract class DtoChangeEvent { + + protected final InstanceIdentifier iid; + protected final Optional before; + protected final Optional after; + + public static enum DtoModificationType { + CREATED, UPDATED, DELETED; + } + + public DtoChangeEvent(@Nonnull InstanceIdentifier iid, @Nullable T before, @Nullable T after) { + this.iid = Preconditions.checkNotNull(iid); + Preconditions.checkArgument(!(before == null && after == null), + "before and after cannot be null at the same time"); + this.before = Optional.fromNullable(before); + this.after = Optional.fromNullable(after); + } + + public @Nonnull InstanceIdentifier getIid() { + return iid; + } + + public Optional getBefore() { + return before; + } + + public Optional getAfter() { + return after; + } + + /** + * Returns:
+ * {@link DtoModificationType#CREATED} - when {@link #isDtoCreated()} is {@code true}
+ * {@link DtoModificationType#UPDATED} - when {@link #isDtoUpdated()} is {@code true}
+ * {@link DtoModificationType#DELETED} - when {@link #isDtoDeleted()} is {@code true} + * + * @return DtoModificationType + */ + public @Nonnull DtoModificationType getDtoModificationType() { + if (isDtoCreated()) { + return DtoModificationType.CREATED; + } + if (isDtoUpdated()) { + return DtoModificationType.UPDATED; + } + if (isDtoDeleted()) { + return DtoModificationType.DELETED; + } + throw new IllegalStateException("Unknown DTO modification type."); + } + + /** + * Checks if {@link #getBefore()} is NOT present and if {@link #getAfter()} is present + * + * @return {@code true} if DTO is created; {@code false} otherwise + */ + public boolean isDtoCreated() { + return !before.isPresent() && after.isPresent(); + } + + /** + * Checks if {@link #getBefore()} is present and if {@link #getAfter()} is present + * + * @return {@code true} if DTO is updated; {@code false} otherwise + */ + public boolean isDtoUpdated() { + return before.isPresent() && after.isPresent(); + } + + /** + * Checks if {@link #getBefore()} is present and if {@link #getAfter()} is NOT present + * + * @return {@code true} if DTO is deleted; {@code false} otherwise + */ + public boolean isDtoDeleted() { + return before.isPresent() && !after.isPresent(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((after == null) ? 0 : after.hashCode()); + result = prime * result + ((before == null) ? 0 : before.hashCode()); + result = prime * result + ((iid == null) ? 0 : iid.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof DtoChangeEvent)) + return false; + DtoChangeEvent other = (DtoChangeEvent) obj; + if (after == null) { + if (other.after != null) + return false; + } else if (!after.equals(other.after)) + return false; + if (before == null) { + if (other.before != null) + return false; + } else if (!before.equals(other.before)) + return false; + if (iid == null) { + if (other.iid != null) + return false; + } else if (!iid.equals(other.iid)) + return false; + return true; + } + +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/NodeOperEvent.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/NodeOperEvent.java new file mode 100644 index 000000000..2ad415453 --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/NodeOperEvent.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.event; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + +public class NodeOperEvent extends DtoChangeEvent { + + public NodeOperEvent(InstanceIdentifier iid, Node before, Node after) { + super(iid, before, after); + if (before != null) { + Preconditions.checkArgument(before.getAugmentation(NetconfNode.class) != null); + } + if (after != null) { + Preconditions.checkArgument(after.getAugmentation(NetconfNode.class) != null); + } + } + + public boolean isAfterConnected() { + return isConnected(after); + } + + public boolean isBeforeConnected() { + return isConnected(before); + } + + private static boolean isConnected(Optional potentialNode) { + if (!potentialNode.isPresent()) { + return false; + } + NetconfNode netconfNode = potentialNode.get().getAugmentation(NetconfNode.class); + if (ConnectionStatus.Connected == netconfNode.getConnectionStatus()) { + return true; + } + return false; + } + +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/VppEndpointConfEvent.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/VppEndpointConfEvent.java new file mode 100644 index 000000000..8034a6a63 --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/VppEndpointConfEvent.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.event; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class VppEndpointConfEvent extends DtoChangeEvent { + + public VppEndpointConfEvent(InstanceIdentifier iid, VppEndpoint before, VppEndpoint after) { + super(iid, before, after); + } + +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManager.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManager.java new file mode 100644 index 000000000..c4940e216 --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManager.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.iface; + +import javax.annotation.Nonnull; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.ConfigCommand; +import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand; +import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand.VhostUserCommandBuilder; +import org.opendaylight.groupbasedpolicy.renderer.vpp.event.NodeOperEvent; +import org.opendaylight.groupbasedpolicy.renderer.vpp.event.VppEndpointConfEvent; +import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General.Operations; +import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint.InterfaceTypeChoice; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.VhostUserCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.eventbus.Subscribe; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; + +public class InterfaceManager implements AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(InterfaceManager.class); + private final MountedDataBrokerProvider mountDataProvider; + private final VppEndpointLocationProvider vppEndpointLocationProvider; + + public InterfaceManager(@Nonnull MountedDataBrokerProvider mountDataProvider, @Nonnull DataBroker dataProvider) { + this.mountDataProvider = Preconditions.checkNotNull(mountDataProvider); + this.vppEndpointLocationProvider = new VppEndpointLocationProvider(dataProvider); + } + + @Subscribe + public void vppEndpointChanged(VppEndpointConfEvent event) { + switch (event.getDtoModificationType()) { + case CREATED: + vppEndpointCreated(event.getAfter().get()); + break; + case UPDATED: + vppEndpointDeleted(event.getBefore().get()); + vppEndpointCreated(event.getAfter().get()); + break; + case DELETED: + vppEndpointDeleted(event.getBefore().get()); + break; + } + } + + private void vppEndpointCreated(VppEndpoint vppEndpoint) { + Optional potentialIfaceCommand = createInterfaceWithoutBdCommand(vppEndpoint, Operations.PUT); + if (!potentialIfaceCommand.isPresent()) { + return; + } + ConfigCommand ifaceWithoutBdCommand = potentialIfaceCommand.get(); + InstanceIdentifier vppNodeIid = vppEndpoint.getVppNodePath(); + Optional potentialVppDataProvider = mountDataProvider.getDataBrokerForMountPoint(vppNodeIid); + if (!potentialVppDataProvider.isPresent()) { + LOG.debug("Cannot get data broker for mount point {}", vppNodeIid); + return; + } + DataBroker vppDataBroker = potentialVppDataProvider.get(); + createIfaceOnVpp(ifaceWithoutBdCommand, vppDataBroker, vppEndpoint, vppNodeIid); + } + + private void createIfaceOnVpp(ConfigCommand createIfaceWithoutBdCommand, DataBroker vppDataBroker, + VppEndpoint vppEndpoint, InstanceIdentifier vppNodeIid) { + ReadWriteTransaction rwTx = vppDataBroker.newReadWriteTransaction(); + createIfaceWithoutBdCommand.execute(rwTx); + Futures.addCallback(rwTx.submit(), new FutureCallback() { + + @Override + public void onSuccess(Void result) { + LOG.debug("Create interface on VPP command was successful:\nVPP: {}\nCommand: {}", vppNodeIid, + createIfaceWithoutBdCommand); + vppEndpointLocationProvider.createLocationForVppEndpoint(vppEndpoint); + } + + @Override + public void onFailure(Throwable t) { + LOG.error("Create interface on VPP command was NOT successful:\nVPP: {}\nCommand: {}", vppNodeIid, + createIfaceWithoutBdCommand, t); + } + }); + } + + private void vppEndpointDeleted(VppEndpoint vppEndpoint) { + Optional potentialIfaceCommand = createInterfaceWithoutBdCommand(vppEndpoint, Operations.DELETE); + if (!potentialIfaceCommand.isPresent()) { + return; + } + ConfigCommand ifaceWithoutBdCommand = potentialIfaceCommand.get(); + InstanceIdentifier vppNodeIid = vppEndpoint.getVppNodePath(); + Optional potentialVppDataProvider = mountDataProvider.getDataBrokerForMountPoint(vppNodeIid); + if (!potentialVppDataProvider.isPresent()) { + LOG.debug("Cannot get data broker for mount point {}", vppNodeIid); + return; + } + DataBroker vppDataBroker = potentialVppDataProvider.get(); + deleteIfaceOnVpp(ifaceWithoutBdCommand, vppDataBroker, vppEndpoint, vppNodeIid); + } + + private void deleteIfaceOnVpp(ConfigCommand deleteIfaceWithoutBdCommand, DataBroker vppDataBroker, + VppEndpoint vppEndpoint, InstanceIdentifier vppNodeIid) { + ReadWriteTransaction rwTx = vppDataBroker.newReadWriteTransaction(); + deleteIfaceWithoutBdCommand.execute(rwTx); + Futures.addCallback(rwTx.submit(), new FutureCallback() { + + @Override + public void onSuccess(Void result) { + LOG.debug("Delete interface on VPP command was successful:\nVPP: {}\nCommand: {}", vppNodeIid, + deleteIfaceWithoutBdCommand); + vppEndpointLocationProvider.deleteLocationForVppEndpoint(vppEndpoint); + } + + @Override + public void onFailure(Throwable t) { + LOG.error("Delete interface on VPP command was NOT successful:\nVPP: {}\nCommand: {}", vppNodeIid, + deleteIfaceWithoutBdCommand, t); + } + }); + } + + @Subscribe + public void vppNodeChanged(NodeOperEvent event) { + switch (event.getDtoModificationType()) { + case CREATED: + if (event.isAfterConnected()) { + // TODO read VppEndpoints or cache them during vppEndpointChanged() + } + break; + case UPDATED: + if (!event.isBeforeConnected() && event.isAfterConnected()) { + // TODO reconciliation - diff between disconnected snapshot and current snapshot + } + break; + case DELETED: + if (event.isBeforeConnected()) { + // TODO we could do snapshot of VppEndpoints + // which can be used for reconciliation + } + break; + } + } + + private static Optional createInterfaceWithoutBdCommand(@Nonnull VppEndpoint vppEp, + @Nonnull Operations operations) { + if (!hasNodeAndInterface(vppEp)) { + LOG.debug("Interface command is not created for {}", vppEp); + return Optional.absent(); + } + VhostUserCommandBuilder builder = VhostUserCommand.builder(); + builder.setName(vppEp.getVppInterfaceName()); + InterfaceTypeChoice interfaceTypeChoice = vppEp.getInterfaceTypeChoice(); + if (interfaceTypeChoice instanceof VhostUserCase) { + VhostUserCase vhostUserIface = (VhostUserCase) interfaceTypeChoice; + String socket = vhostUserIface.getSocket(); + if (Strings.isNullOrEmpty(socket)) { + LOG.debug("Vhost user interface command is not created because socket is missing. {}", vppEp); + return Optional.absent(); + } + builder.setSocket(socket); + builder.setRole(VhostUserRole.Client); + } + VhostUserCommand vhostUserCommand = + builder.setOperation(operations).setDescription(vppEp.getDescription()).build(); + return Optional.of(vhostUserCommand); + } + + private static boolean hasNodeAndInterface(VppEndpoint vppEp) { + if (vppEp.getVppNodePath() == null) { + LOG.trace("vpp-node is missing. {}", vppEp); + return false; + } + if (Strings.isNullOrEmpty(vppEp.getVppInterfaceName())) { + LOG.trace("vpp-interface-name is missing. {}", vppEp); + return false; + } + return true; + } + + @Override + public void close() throws Exception { + vppEndpointLocationProvider.close(); + } + +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/VppEndpointLocationProvider.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/VppEndpointLocationProvider.java new file mode 100644 index 000000000..f1e8c1ecc --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/VppEndpointLocationProvider.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.iface; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.groupbasedpolicy.util.IidFactory; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.ProviderName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProvider; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProviderBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocationKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; + +public class VppEndpointLocationProvider implements AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(VppEndpointLocationProvider.class); + public static final ProviderName VPP_ENDPOINT_LOCATION_PROVIDER = + new ProviderName("VPP endpoint location provider"); + public static final long PROVIDER_PRIORITY = 10L; + private static final String INTERFACE_PATH = "/ietf-interfaces:interfaces/ietf-interfaces:interface"; + private final DataBroker dataProvider; + + public VppEndpointLocationProvider(DataBroker dataProvider) { + this.dataProvider = Preconditions.checkNotNull(dataProvider); + LocationProvider locationProvider = new LocationProviderBuilder().setProvider(VPP_ENDPOINT_LOCATION_PROVIDER) + .setPriority(PROVIDER_PRIORITY) + .build(); + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + wTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.locationProviderIid(VPP_ENDPOINT_LOCATION_PROVIDER), + locationProvider, true); + + Futures.addCallback(wTx.submit(), new FutureCallback() { + + @Override + public void onSuccess(Void result) { + LOG.trace("{} was created", VPP_ENDPOINT_LOCATION_PROVIDER.getValue()); + } + + @Override + public void onFailure(Throwable t) { + LOG.error("{} was NOT created", VPP_ENDPOINT_LOCATION_PROVIDER.getValue()); + } + }); + } + + public void createLocationForVppEndpoint(VppEndpoint vppEndpoint) { + ProviderAddressEndpointLocation providerAddressEndpointLocation = + createProviderAddressEndpointLocation(vppEndpoint); + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + wTx.put(LogicalDatastoreType.CONFIGURATION, + IidFactory.providerAddressEndpointLocationIid(VPP_ENDPOINT_LOCATION_PROVIDER, + providerAddressEndpointLocation.getKey()), + providerAddressEndpointLocation); + + Futures.addCallback(wTx.submit(), new FutureCallback() { + + @Override + public void onSuccess(Void result) { + LOG.trace("{} provides location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(), + providerAddressEndpointLocation); + } + + @Override + public void onFailure(Throwable t) { + LOG.error("{} failed to provide location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(), + providerAddressEndpointLocation, t); + } + }); + } + + public static ProviderAddressEndpointLocation createProviderAddressEndpointLocation(VppEndpoint vppEndpoint) { + String restIfacePath = INTERFACE_PATH + createRestInterfaceKey(vppEndpoint.getVppInterfaceName()); + AbsoluteLocation absoluteLocation = new AbsoluteLocationBuilder() + .setLocationType(new ExternalLocationCaseBuilder().setExternalNodeMountPoint(vppEndpoint.getVppNodePath()) + .setExternalNodeConnector(restIfacePath) + .build()) + .build(); + return new ProviderAddressEndpointLocationBuilder() + .setKey(createProviderAddressEndpointLocationKey(vppEndpoint)) + .setAbsoluteLocation(absoluteLocation) + .build(); + } + + public void deleteLocationForVppEndpoint(VppEndpoint vppEndpoint) { + ProviderAddressEndpointLocationKey provAddrEpLocKey = createProviderAddressEndpointLocationKey(vppEndpoint); + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + wTx.delete(LogicalDatastoreType.CONFIGURATION, + IidFactory.providerAddressEndpointLocationIid(VPP_ENDPOINT_LOCATION_PROVIDER, provAddrEpLocKey)); + Futures.addCallback(wTx.submit(), new FutureCallback() { + + @Override + public void onSuccess(Void result) { + LOG.trace("{} removes location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(), provAddrEpLocKey); + } + + @Override + public void onFailure(Throwable t) { + LOG.error("{} failed to remove location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(), + provAddrEpLocKey, t); + } + }); + } + + private static ProviderAddressEndpointLocationKey createProviderAddressEndpointLocationKey(VppEndpoint vppEndpoint) { + return new ProviderAddressEndpointLocationKey(vppEndpoint.getAddress(), vppEndpoint.getAddressType(), + vppEndpoint.getContextId(), vppEndpoint.getContextType()); + } + + private static String createRestInterfaceKey(String ifaceName) { + return "[ietf-interfaces:name='" + ifaceName + "']"; + } + + @Override + public void close() throws Exception { + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + wTx.delete(LogicalDatastoreType.CONFIGURATION, IidFactory.locationProviderIid(VPP_ENDPOINT_LOCATION_PROVIDER)); + wTx.submit(); + } +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/RendererPolicyListener.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/RendererPolicyListener.java new file mode 100644 index 000000000..fdbbae5a6 --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/RendererPolicyListener.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.listener; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; +import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.groupbasedpolicy.util.DataTreeChangeHandler; +import org.opendaylight.groupbasedpolicy.util.IidFactory; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicy; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class RendererPolicyListener extends DataTreeChangeHandler { + + // TODO move to common place + private static final RendererName RENDERER_NAME = new RendererName("VPP renderer"); + + protected RendererPolicyListener(DataBroker dataProvider) { + super(dataProvider); + registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, + IidFactory.rendererIid(RENDERER_NAME).child(RendererPolicy.class))); + } + + @Override + protected void onWrite(DataObjectModification rootNode, + InstanceIdentifier rootIdentifier) { + // TODO Auto-generated method stub + + } + + @Override + protected void onDelete(DataObjectModification rootNode, + InstanceIdentifier rootIdentifier) { + // TODO Auto-generated method stub + + } + + @Override + protected void onSubtreeModified(DataObjectModification rootNode, + InstanceIdentifier rootIdentifier) { + // TODO Auto-generated method stub + + } + +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppEndpointListener.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppEndpointListener.java new file mode 100644 index 000000000..5c31684b1 --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppEndpointListener.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.listener; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; +import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.groupbasedpolicy.renderer.vpp.event.VppEndpointConfEvent; +import org.opendaylight.groupbasedpolicy.util.DataTreeChangeHandler; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; +import com.google.common.eventbus.EventBus; + +public class VppEndpointListener extends DataTreeChangeHandler { + + private static final Logger LOG = LoggerFactory.getLogger(VppEndpointListener.class); + private EventBus eventBus; + + public VppEndpointListener(DataBroker dataProvider, EventBus eventBus) { + super(dataProvider); + this.eventBus = Preconditions.checkNotNull(eventBus); + registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, + InstanceIdentifier.builder(Config.class).child(VppEndpoint.class).build())); + } + + @Override + protected void onWrite(DataObjectModification rootNode, + InstanceIdentifier rootIdentifier) { + VppEndpointConfEvent event = + new VppEndpointConfEvent(rootIdentifier, rootNode.getDataBefore(), rootNode.getDataAfter()); + LOG.trace("Dispatching event on write: {}", event); + eventBus.post(event); + } + + @Override + protected void onDelete(DataObjectModification rootNode, + InstanceIdentifier rootIdentifier) { + VppEndpointConfEvent event = + new VppEndpointConfEvent(rootIdentifier, rootNode.getDataBefore(), rootNode.getDataAfter()); + LOG.trace("Dispatching event on delete: {}", event); + eventBus.post(event); + } + + @Override + protected void onSubtreeModified(DataObjectModification rootNode, + InstanceIdentifier rootIdentifier) { + VppEndpointConfEvent event = + new VppEndpointConfEvent(rootIdentifier, rootNode.getDataBefore(), rootNode.getDataAfter()); + LOG.trace("Dispatching event on subtree modified: {}", event); + eventBus.post(event); + } + +} diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppNodeListener.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppNodeListener.java index df39b165f..086b51953 100644 --- a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppNodeListener.java +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppNodeListener.java @@ -18,6 +18,7 @@ import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.groupbasedpolicy.renderer.vpp.event.NodeOperEvent; import org.opendaylight.groupbasedpolicy.renderer.vpp.manager.VppNodeManager; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; @@ -28,6 +29,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; +import com.google.common.eventbus.EventBus; public class VppNodeListener implements DataTreeChangeListener, AutoCloseable { @@ -35,9 +37,11 @@ public class VppNodeListener implements DataTreeChangeListener, AutoClosea private final ListenerRegistration listenerRegistration; private final VppNodeManager nodeManager; + private final EventBus eventBus; - public VppNodeListener(DataBroker dataBroker, VppNodeManager nodeManager) { + public VppNodeListener(DataBroker dataBroker, VppNodeManager nodeManager, EventBus eventBus) { this.nodeManager = Preconditions.checkNotNull(nodeManager); + this.eventBus = Preconditions.checkNotNull(eventBus); // Register listener final DataTreeIdentifier networkTopologyPath = new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class).child(Node.class).build()); @@ -54,6 +58,9 @@ public class VppNodeListener implements DataTreeChangeListener, AutoClosea DataObjectModification rootNode = modification.getRootNode(); Node dataAfter = rootNode.getDataAfter(); Node dataBefore = rootNode.getDataBefore(); + NodeOperEvent event = + new NodeOperEvent(modification.getRootPath().getRootIdentifier(), dataBefore, dataAfter); + eventBus.post(event); nodeManager.syncNodes(dataAfter, dataBefore); } } diff --git a/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/MountedDataBrokerProvider.java b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/MountedDataBrokerProvider.java new file mode 100644 index 000000000..071e14df4 --- /dev/null +++ b/renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/MountedDataBrokerProvider.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.util; + +import javax.annotation.Nonnull; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.MountPoint; +import org.opendaylight.controller.md.sal.binding.api.MountPointService; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + +public class MountedDataBrokerProvider { + + private static final Logger LOG = LoggerFactory.getLogger(MountedDataBrokerProvider.class); + private final MountPointService mountService; + + public MountedDataBrokerProvider(@Nonnull MountPointService mountService) { + this.mountService = Preconditions.checkNotNull(mountService); + } + + public Optional getDataBrokerForMountPoint(@Nonnull InstanceIdentifier iidToMountPoint) { + Optional potentialMountPoint = mountService.getMountPoint(iidToMountPoint); + if (!potentialMountPoint.isPresent()) { + LOG.debug("Mount point does not exist for {}", iidToMountPoint); + return Optional.absent(); + } + return potentialMountPoint.get().getService(DataBroker.class); + } +} diff --git a/renderers/vpp/src/main/yang/vbd/v3po@2015-01-05.yang b/renderers/vpp/src/main/yang/vbd/v3po@2015-01-05.yang index 3a71ffd46..c1210a923 100644 --- a/renderers/vpp/src/main/yang/vbd/v3po@2015-01-05.yang +++ b/renderers/vpp/src/main/yang/vbd/v3po@2015-01-05.yang @@ -100,6 +100,26 @@ module v3po { } } + identity vxlan-gpe-tunnel { + base if:interface-type; + } + + typedef vxlan-gpe-vni { + description "VNI used in a VXLAN-GPE tunnel"; + type uint32 { + range "0..16777215"; + } + } + + typedef vxlan-gpe-next-protocol { + type enumeration { + enum ipv4; + enum ipv6; + enum ethernet; + enum nsh; + } + } + grouping bridge-domain-attributes { leaf flood { type boolean; @@ -183,6 +203,33 @@ module v3po { } } + grouping ethernet-base-attributes { + leaf mtu { + type uint16 { + range "64..9216"; + } + units "octets"; + default 9216; + description + "The size, in octets, of the largest packet that the + hardware interface will send and receive."; + } + } + + grouping ethernet-state-attributes { + leaf manufacturer-description { + type string; + config false; + } + leaf duplex { + type enumeration { + enum "half"; + enum "full"; + } + config false; + } + } + grouping vhost-user-interface-base-attributes { leaf socket { type string { @@ -193,25 +240,69 @@ module v3po { type vhost-user-role; default "server"; } + description "vhost-user settings"; } grouping vhost-user-interface-state-attributes { - leaf features { - type uint64; - config false; - } - leaf virtio-net-hdr-size { - type uint32; - config false; - } - leaf num-memory-regions { - type uint32; - config false; - } - leaf connect-error { - type string; - config false; - } + leaf features { + type uint64; + config false; + } + leaf virtio-net-hdr-size { + type uint32; + config false; + } + leaf num-memory-regions { + type uint32; + config false; + } + leaf connect-error { + type string; + config false; + } + } + + grouping vxlan-base-attributes { + // FIXME: this should be in an vxlan-specific extension + leaf src { + /*mandatory true;*/ + type inet:ip-address; + } + leaf dst { + /*mandatory true;*/ + type inet:ip-address; + } + leaf vni { + /*mandatory true;*/ + type vxlan-vni; + } + leaf encap-vrf-id { + type uint32; + } + } + + grouping vxlan-gpe-base-attributes { + leaf local { + /*mandatory true;*/ + type inet:ip-address; + } + leaf remote { + /*mandatory true;*/ + type inet:ip-address; + } + leaf vni { + /*mandatory true;*/ + type vxlan-gpe-vni; + } + leaf next-protocol { + type vxlan-gpe-next-protocol; + } + leaf encap-vrf-id { + type uint32; + } + leaf decap-vrf-id { + type uint32; + } } grouping vlan-tag-rewrite-attributes { @@ -231,83 +322,16 @@ module v3po { } } - augment /if:interfaces/if:interface { - ext:augment-identifier "vpp-interface-augmentation"; - - // FIXME using ietf-interfaces model for vpp interfaces makes it hard to implement because: - // 1. The link between interface type and this augmentation is unclear - // 2. Only this augmentation with combination of ifc type is trigger to do something for vpp, what if user only configures base interface stuff ? + We need to get leaves defined by ietf-interfaces when we are processing this augment - - container sub-interface { - when "../if:type = 'v3po:sub-interface'"; - leaf super-interface { - type if:interface-ref; - } - uses sub-interface-base-attributes; - } - - container tap { - when "../if:type = 'v3po:tap'"; - uses tap-interface-base-attributes; - uses tap-interface-config-attributes; - } - - container ethernet { - when "../if:type = 'ianaift:ethernetCsmacd'"; - leaf mtu { - type uint16 { - range "64..9216"; - } - units "octets"; - default 9216; - description - "The size, in octets, of the largest packet that the - hardware interface will send and receive."; - } - } - container routing { - leaf vrf-id { - type uint32; - default 0; - } - } - container vhost-user { - when "../if:type = 'v3po:vhost-user'"; - uses vhost-user-interface-base-attributes; - description "vhost-user settings"; - } - container vxlan { - // FIXME: this should be in an vxlan-specific extension - when "../if:type = 'v3po:vxlan-tunnel'"; - - leaf src { - /*mandatory true;*/ - type inet:ip-address; - } - leaf dst { - /*mandatory true;*/ - type inet:ip-address; - } - leaf vni { - /*mandatory true;*/ - type vxlan-vni; - } - leaf encap-vrf-id { - type uint32; - } - } - container l2 { + grouping l2-attributes { description "Parameters for configuring Layer2 features on interfaces."; - must "(not (../if:ipv4[if:enabled = 'true']/if:address/if:ip) and " + - "not (../if:ipv6[if:enabled = 'true']/if:address/if:ip))"; choice interconnection { case xconnect-based { leaf xconnect-outgoing-interface { /* Don't allow selection of this interface */ must "../../if:name != current()"; - type if:interface-ref; + type if:interface-ref; // todo use interface-state-ref for operational data? description "L2 xconnect mode"; } @@ -341,9 +365,66 @@ module v3po { } } } - container vlan-tag-rewrite { + container vlan-tag-rewrite { // todo valid only for sub-interfaces uses vlan-tag-rewrite-attributes; } + } + + augment /if:interfaces/if:interface { + ext:augment-identifier "vpp-interface-augmentation"; + + // FIXME using ietf-interfaces model for vpp interfaces makes it hard to implement because: + // 1. The link between interface type and this augmentation is unclear + // 2. Only this augmentation with combination of ifc type is trigger to do something for vpp, what if user only configures base interface stuff ? + We need to get leaves defined by ietf-interfaces when we are processing this augment + // 3. The ietf-interfaces model does not define groupings which makes types reuse difficult + + container sub-interface { + when "../if:type = 'v3po:sub-interface'"; + leaf super-interface { + type if:interface-ref; + } + uses sub-interface-base-attributes; + } + + container tap { + when "../if:type = 'v3po:tap'"; + uses tap-interface-base-attributes; + uses tap-interface-config-attributes; + } + + container ethernet { + when "../if:type = 'ianaift:ethernetCsmacd'"; + uses ethernet-base-attributes; + } + + container routing { + leaf vrf-id { // todo no routing info for oper, is it possible to get it from the vpp? + type uint32; + default 0; + } + } + + container vhost-user { + when "../if:type = 'v3po:vhost-user'"; + uses vhost-user-interface-base-attributes; + } + + container vxlan { + when "../if:type = 'v3po:vxlan-tunnel'"; + uses vxlan-base-attributes; + } + + container l2 { + must "(not (../if:ipv4[if:enabled = 'true']/if:address/if:ip) and " + + "not (../if:ipv6[if:enabled = 'true']/if:address/if:ip))"; + + uses l2-attributes; + } + + container vxlan-gpe { + when "../if:type = 'v3po:vxlan-gpe-tunnel'"; + + uses vxlan-gpe-base-attributes; } } @@ -401,79 +482,36 @@ module v3po { container tap { when "../if:type = 'v3po:tap'"; - uses tap-interface-base-attributes { - refine tap-name { - config false; - } - } + uses tap-interface-base-attributes; } container ethernet { when "../if:type = 'ianaift:ethernetCsmacd'"; - leaf mtu { - type uint16; - } - leaf manufacturer-description { - type string; - } - leaf duplex { - type enumeration { - enum "half"; - enum "full"; - } - } + uses ethernet-base-attributes; + uses ethernet-state-attributes; } + container vhost-user { when "../if:type = 'v3po:vhost-user'"; - uses vhost-user-interface-base-attributes { - refine socket { - config false; - } - refine role { - config false; - } - } + uses vhost-user-interface-base-attributes; uses vhost-user-interface-state-attributes; } + container vxlan { when "../if:type = 'v3po:vxlan-tunnel'"; + uses vxlan-base-attributes; + } + container vxlan-gpe { + when "../if:type = 'v3po:vxlan-gpe-tunnel'"; - leaf src { - type inet:ip-address; - } - leaf dst { - type inet:ip-address; - } - - leaf vni { - type uint32; - } - leaf encap-vrf-id { - type uint32; - } + uses vxlan-gpe-base-attributes; } + container l2 { - choice interconnection { - case xconnect-based { - leaf xconnect-outgoing-interface { - type if:interface-ref; - } - } - case bridge-based { - leaf bridge-domain { - type bridge-domain-ref; - } - leaf split-horizon-group { - type uint8; - } - leaf bridged-virtual-interface { - type boolean; - } - } - } - container vlan-tag-rewrite { - uses vlan-tag-rewrite-attributes; - } + must "(not (../if:ipv4[if:enabled = 'true']/if:address/if:ip) and " + + "not (../if:ipv6[if:enabled = 'true']/if:address/if:ip))"; + + uses l2-attributes; } } diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommandTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommandTest.java index 63dc7b2de..56a3da326 100644 --- a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommandTest.java +++ b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/commands/VhostUserCommandTest.java @@ -8,7 +8,6 @@ package org.opendaylight.groupbasedpolicy.renderer.vpp.commands; -import com.google.common.base.Optional; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -20,17 +19,19 @@ import org.opendaylight.groupbasedpolicy.renderer.vpp.VppRendererDataBrokerTest; import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General; import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory; import org.opendaylight.groupbasedpolicy.util.DataStoreHelper; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole; -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.v3po.rev150105.VppInterfaceAugmentation; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentationBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUserBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBased; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBasedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.attributes.interconnection.BridgeBased; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.attributes.interconnection.BridgeBasedBuilder; + +import com.google.common.base.Optional; public class VhostUserCommandTest extends VppRendererDataBrokerTest { diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/DtoChangeEventTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/DtoChangeEventTest.java new file mode 100644 index 000000000..b01938e90 --- /dev/null +++ b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/DtoChangeEventTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.event; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class DtoChangeEventTest { + + private final static TopologyKey TOPO_KEY = new TopologyKey(new TopologyId("topo1")); + private final static NodeKey NODE_KEY = new NodeKey(new NodeId("node1")); + private final static InstanceIdentifier NODE_IID = InstanceIdentifier.builder(NetworkTopology.class) + .child(Topology.class, TOPO_KEY) + .child(Node.class, NODE_KEY) + .build(); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private static class DummyDtoEvent extends DtoChangeEvent { + + public DummyDtoEvent(InstanceIdentifier iid, Node before, Node after) { + super(iid, before, after); + } + } + + @Test + public void testConstructor_nodeCreated() { + Node node = new NodeBuilder().setKey(NODE_KEY).build(); + DummyDtoEvent event = new DummyDtoEvent(NODE_IID, null, node); + Assert.assertNotNull(event.getIid()); + Assert.assertTrue(event.getAfter().isPresent()); + Assert.assertFalse(event.getBefore().isPresent()); + Assert.assertEquals(DtoChangeEvent.DtoModificationType.CREATED, event.getDtoModificationType()); + Assert.assertTrue(event.isDtoCreated()); + Assert.assertFalse(event.isDtoDeleted()); + Assert.assertFalse(event.isDtoUpdated()); + } + + @Test + public void testConstructor_nodeDeleted() { + Node node = new NodeBuilder().setKey(NODE_KEY).build(); + DummyDtoEvent event = new DummyDtoEvent(NODE_IID, node, null); + Assert.assertNotNull(event.getIid()); + Assert.assertFalse(event.getAfter().isPresent()); + Assert.assertTrue(event.getBefore().isPresent()); + Assert.assertEquals(DtoChangeEvent.DtoModificationType.DELETED, event.getDtoModificationType()); + Assert.assertFalse(event.isDtoCreated()); + Assert.assertTrue(event.isDtoDeleted()); + Assert.assertFalse(event.isDtoUpdated()); + } + + @Test + public void testConstructor_nodeUpdated() { + Node node = new NodeBuilder().setKey(NODE_KEY).build(); + DummyDtoEvent event = new DummyDtoEvent(NODE_IID, node, node); + Assert.assertNotNull(event.getIid()); + Assert.assertTrue(event.getAfter().isPresent()); + Assert.assertTrue(event.getBefore().isPresent()); + Assert.assertEquals(DtoChangeEvent.DtoModificationType.UPDATED, event.getDtoModificationType()); + Assert.assertFalse(event.isDtoCreated()); + Assert.assertFalse(event.isDtoDeleted()); + Assert.assertTrue(event.isDtoUpdated()); + } + + @Test + public void testConstructor_nullNodes_Exception() { + thrown.expect(IllegalArgumentException.class); + new DummyDtoEvent(NODE_IID, null, null); + } + + @Test + public void testConstructor_nullIid_Exception() { + Node node = new NodeBuilder().setKey(NODE_KEY).build(); + thrown.expect(NullPointerException.class); + new DummyDtoEvent(null, node, node); + } +} diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/NodeOperEventTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/NodeOperEventTest.java new file mode 100644 index 000000000..67f12cd9f --- /dev/null +++ b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/NodeOperEventTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.event; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class NodeOperEventTest { + + private final static TopologyKey TOPO_KEY = new TopologyKey(new TopologyId("topo1")); + private final static NodeKey NODE_KEY = new NodeKey(new NodeId("node1")); + private final static InstanceIdentifier NODE_IID = InstanceIdentifier.builder(NetworkTopology.class) + .child(Topology.class, TOPO_KEY) + .child(Node.class, NODE_KEY) + .build(); + private final static NetconfNode NETCONF_NODE_AUG_CONNECTED = + new NetconfNodeBuilder().setConnectionStatus(ConnectionStatus.Connected).build(); + private final static NetconfNode NETCONF_NODE_AUG_CONNECTING = + new NetconfNodeBuilder().setConnectionStatus(ConnectionStatus.Connecting).build(); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testConstructor_nodeCreated() { + Node node = new NodeBuilder().setKey(NODE_KEY) + .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTED) + .build(); + NodeOperEvent event = new NodeOperEvent(NODE_IID, null, node); + Assert.assertTrue(event.getAfter().isPresent()); + Assert.assertFalse(event.getBefore().isPresent()); + } + + @Test + public void testConstructor_nodeDeleted() { + Node node = new NodeBuilder().setKey(NODE_KEY) + .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTED) + .build(); + NodeOperEvent event = new NodeOperEvent(NODE_IID, node, null); + Assert.assertFalse(event.getAfter().isPresent()); + Assert.assertTrue(event.getBefore().isPresent()); + } + + @Test + public void testConstructor_nodeUpdated() { + Node node = new NodeBuilder().setKey(NODE_KEY) + .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTED) + .build(); + NodeOperEvent event = new NodeOperEvent(NODE_IID, node, node); + Assert.assertTrue(event.getAfter().isPresent()); + Assert.assertTrue(event.getBefore().isPresent()); + } + + @Test + public void testConstructor_beforeNodeMissingNetconfNodeAug_Exception() { + Node node = new NodeBuilder().setKey(NODE_KEY).build(); + thrown.expect(IllegalArgumentException.class); + new NodeOperEvent(NODE_IID, node, null); + } + + @Test + public void testConstructor_afterNodeMissingNetconfNodeAug_Exception() { + Node node = new NodeBuilder().setKey(NODE_KEY).build(); + thrown.expect(IllegalArgumentException.class); + new NodeOperEvent(NODE_IID, null, node); + } + + @Test + public void testConstructor_nullNodes_Exception() { + thrown.expect(IllegalArgumentException.class); + new NodeOperEvent(NODE_IID, null, null); + } + + @Test + public void testConstructor_nullIid_Exception() { + Node node = new NodeBuilder().setKey(NODE_KEY) + .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTED) + .build(); + thrown.expect(NullPointerException.class); + new NodeOperEvent(null, node, node); + } + + @Test + public void testIsAfterConnected() { + Node node = new NodeBuilder().setKey(NODE_KEY) + .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTED) + .build(); + NodeOperEvent event = new NodeOperEvent(NODE_IID, null, node); + Assert.assertTrue(event.isAfterConnected()); + } + + @Test + public void testIsBeforeConnected() { + Node node = new NodeBuilder().setKey(NODE_KEY) + .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTED) + .build(); + NodeOperEvent event = new NodeOperEvent(NODE_IID, node, null); + Assert.assertTrue(event.isBeforeConnected()); + } + + @Test + public void testIsAfterConnected_false() { + Node node = new NodeBuilder().setKey(NODE_KEY) + .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTING) + .build(); + NodeOperEvent event = new NodeOperEvent(NODE_IID, null, node); + Assert.assertFalse(event.isAfterConnected()); + } + + @Test + public void testIsBeforeConnected_false() { + Node node = new NodeBuilder().setKey(NODE_KEY) + .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTING) + .build(); + NodeOperEvent event = new NodeOperEvent(NODE_IID, null, node); + Assert.assertFalse(event.isBeforeConnected()); + } + +} diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/VppEndpointConfEventTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/VppEndpointConfEventTest.java new file mode 100644 index 000000000..d37fbfd53 --- /dev/null +++ b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/event/VppEndpointConfEventTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.event; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.AddressType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.ContextType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class VppEndpointConfEventTest { + + private final static String ADDRESS = "1.1.1.1/32"; + private final static ContextId CONTEXT_ID = new ContextId("ctx1"); + private final static VppEndpointKey BASIC_VPP_EP_KEY = + new VppEndpointKey(ADDRESS, AddressType.class, CONTEXT_ID, ContextType.class); + private final static InstanceIdentifier BASIC_VPP_EP_IID = + InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, BASIC_VPP_EP_KEY).build(); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testConstructor_vppEpCreated() { + VppEndpoint vppEndpoint = basicVppEpBuilder().build(); + VppEndpointConfEvent event = new VppEndpointConfEvent(BASIC_VPP_EP_IID, null, vppEndpoint); + Assert.assertTrue(event.getAfter().isPresent()); + Assert.assertFalse(event.getBefore().isPresent()); + } + + @Test + public void testConstructor_vppEpDeleted() { + VppEndpoint vppEndpoint = basicVppEpBuilder().build(); + VppEndpointConfEvent event = new VppEndpointConfEvent(BASIC_VPP_EP_IID, vppEndpoint, null); + Assert.assertFalse(event.getAfter().isPresent()); + Assert.assertTrue(event.getBefore().isPresent()); + } + + @Test + public void testConstructor_vppEpUpdated() { + VppEndpoint vppEndpoint = basicVppEpBuilder().build(); + VppEndpointConfEvent event = new VppEndpointConfEvent(BASIC_VPP_EP_IID, vppEndpoint, vppEndpoint); + Assert.assertTrue(event.getAfter().isPresent()); + Assert.assertTrue(event.getBefore().isPresent()); + } + + @Test + public void testConstructor_nullVppEp_Exception() { + thrown.expect(IllegalArgumentException.class); + new VppEndpointConfEvent(BASIC_VPP_EP_IID, null, null); + } + + private VppEndpointBuilder basicVppEpBuilder() { + return new VppEndpointBuilder().setAddress(ADDRESS) + .setAddressType(AddressType.class) + .setContextId(CONTEXT_ID) + .setContextType(ContextType.class); + } + +} diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManagerTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManagerTest.java new file mode 100644 index 000000000..f2be66421 --- /dev/null +++ b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManagerTest.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.iface; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.groupbasedpolicy.renderer.vpp.event.VppEndpointConfEvent; +import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider; +import org.opendaylight.groupbasedpolicy.test.CustomDataBrokerTest; +import org.opendaylight.groupbasedpolicy.util.IidFactory; +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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.LocationProviders; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProvider; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.AddressType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.ContextType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.VhostUserCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.attributes.Interconnection; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.attributes.interconnection.BridgeBased; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import com.google.common.base.Optional; +import com.google.common.base.Strings; + +public class InterfaceManagerTest extends CustomDataBrokerTest { + + private final static String ADDRESS = "1.1.1.1/32"; + private final static ContextId CONTEXT_ID = new ContextId("ctx1"); + private final static String IFACE_NAME = "ifaceName1"; + private final static VppEndpointKey BASIC_VPP_EP_KEY = + new VppEndpointKey(ADDRESS, AddressType.class, CONTEXT_ID, ContextType.class); + private final static InstanceIdentifier BASIC_VPP_EP_IID = + InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, BASIC_VPP_EP_KEY).build(); + private final static TopologyKey TOPO_KEY = new TopologyKey(new TopologyId("topo1")); + private final static NodeKey NODE_KEY = new NodeKey(new NodeId("node1")); + private final static InstanceIdentifier NODE_IID = InstanceIdentifier.builder(NetworkTopology.class) + .child(Topology.class, TOPO_KEY) + .child(Node.class, NODE_KEY) + .build(); + private final static String SOCKET = "socket1"; + + private InterfaceManager manager; + private MountedDataBrokerProvider mountedDataProviderMock; + private DataBroker mountPointDataBroker; + private DataBroker dataBroker; + + @Override + public Collection> getClassesFromModules() { + return Arrays.asList(Node.class, VppEndpoint.class, Interfaces.class, BridgeDomains.class, + LocationProviders.class); + } + + @Before + public void init() throws Exception { + mountedDataProviderMock = Mockito.mock(MountedDataBrokerProvider.class); + mountPointDataBroker = getDataBroker(); + setup(); // initialize new data broker for ODL data store + dataBroker = getDataBroker(); + Mockito.when(mountedDataProviderMock.getDataBrokerForMountPoint(Mockito.any(InstanceIdentifier.class))) + .thenReturn(Optional.of(mountPointDataBroker)); + manager = new InterfaceManager(mountedDataProviderMock, dataBroker); + } + + @Test + public void testVppEndpointChanged_created() throws Exception { + VppEndpoint vhostEp = vhostVppEpBuilder().build(); + VppEndpointConfEvent event = new VppEndpointConfEvent(BASIC_VPP_EP_IID, null, vhostEp); + + manager.vppEndpointChanged(event); + // assert state on data store behind mount point + ReadOnlyTransaction rTxMount = mountPointDataBroker.newReadOnlyTransaction(); + Optional potentialIface = + rTxMount.read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.builder(Interfaces.class) + .child(Interface.class, new InterfaceKey(vhostEp.getVppInterfaceName())) + .build()).get(); + Assert.assertTrue(potentialIface.isPresent()); + Interface iface = potentialIface.get(); + Assert.assertEquals(VhostUser.class, iface.getType()); + Assert.assertTrue(iface.isEnabled()); + VppInterfaceAugmentation vppIface = iface.getAugmentation(VppInterfaceAugmentation.class); + Assert.assertNotNull(vppIface); + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser vhostUserIface = + vppIface.getVhostUser(); + Assert.assertNotNull(vhostUserIface); + Assert.assertEquals(VhostUserRole.Client, vhostUserIface.getRole()); + Assert.assertEquals(SOCKET, vhostUserIface.getSocket()); + L2 l2Iface = vppIface.getL2(); + if (l2Iface != null) { + Interconnection interconnection = l2Iface.getInterconnection(); + if (interconnection != null) { + if (interconnection instanceof BridgeBased) { + BridgeBased bridgeL2Iface = (BridgeBased) interconnection; + Assert.assertTrue(Strings.isNullOrEmpty(bridgeL2Iface.getBridgeDomain())); + } + } + } + // assert state on ODL data store + ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction(); + Optional optLocationProvider = rTx.read(LogicalDatastoreType.CONFIGURATION, IidFactory.locationProviderIid(VppEndpointLocationProvider.VPP_ENDPOINT_LOCATION_PROVIDER)).get(); + Assert.assertTrue(optLocationProvider.isPresent()); + List epLocs = optLocationProvider.get().getProviderAddressEndpointLocation(); + Assert.assertNotNull(epLocs); + Assert.assertEquals(1, epLocs.size()); + ProviderAddressEndpointLocation epLoc = VppEndpointLocationProvider.createProviderAddressEndpointLocation(vhostEp); + Assert.assertEquals(epLoc, epLocs.get(0)); + } + + @Test + public void testVppEndpointChanged_deleted() throws Exception { + VppEndpoint vhostEp = vhostVppEpBuilder().build(); + VppEndpointConfEvent createVppEpEvent = new VppEndpointConfEvent(BASIC_VPP_EP_IID, null, vhostEp); + VppEndpointConfEvent deleteVppEpEvent = new VppEndpointConfEvent(BASIC_VPP_EP_IID, vhostEp, null); + + manager.vppEndpointChanged(createVppEpEvent); + manager.vppEndpointChanged(deleteVppEpEvent); + // assert state on data store behind mount point + ReadOnlyTransaction rTxMount = mountPointDataBroker.newReadOnlyTransaction(); + Optional potentialIface = + rTxMount.read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.builder(Interfaces.class) + .child(Interface.class, new InterfaceKey(vhostEp.getVppInterfaceName())) + .build()).get(); + Assert.assertFalse(potentialIface.isPresent()); + // assert state on ODL data store + ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction(); + ProviderAddressEndpointLocation providerAddressEndpointLocation = + VppEndpointLocationProvider.createProviderAddressEndpointLocation(vhostEp); + InstanceIdentifier providerAddressEndpointLocationIid = IidFactory + .providerAddressEndpointLocationIid(VppEndpointLocationProvider.VPP_ENDPOINT_LOCATION_PROVIDER, + providerAddressEndpointLocation.getKey()); + Optional optProvEpLoc = + rTx.read(LogicalDatastoreType.CONFIGURATION, providerAddressEndpointLocationIid).get(); + Assert.assertFalse(optProvEpLoc.isPresent()); + } + + private VppEndpointBuilder vhostVppEpBuilder() { + return basicVppEpBuilder().setVppInterfaceName(IFACE_NAME) + .setVppNodePath(NODE_IID) + .setInterfaceTypeChoice(new VhostUserCaseBuilder().setSocket(SOCKET).build()); + } + + private VppEndpointBuilder basicVppEpBuilder() { + return new VppEndpointBuilder().setAddress(ADDRESS) + .setAddressType(AddressType.class) + .setContextId(CONTEXT_ID) + .setContextType(ContextType.class); + } +} diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppEndpointListenerTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppEndpointListenerTest.java new file mode 100644 index 000000000..37c68c8a0 --- /dev/null +++ b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/listener/VppEndpointListenerTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.vpp.listener; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.groupbasedpolicy.renderer.vpp.event.VppEndpointConfEvent; +import org.opendaylight.groupbasedpolicy.test.CustomDataBrokerTest; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.LocationProviders; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.AddressType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.ContextType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.Forwarding; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import com.google.common.base.Optional; +import com.google.common.eventbus.EventBus; + +public class VppEndpointListenerTest extends CustomDataBrokerTest { + + private final static String ADDRESS = "1.1.1.1/32"; + private final static ContextId CONTEXT_ID = new ContextId("ctx1"); + private final static String IFACE_NAME = "ifaceName"; + + private DataBroker dataBroker; + private VppEndpointListener listener; + private EventBus eventBusMock; + + @Override + public Collection> getClassesFromModules() { + return Arrays.asList(Node.class, VppEndpoint.class, Forwarding.class, LocationProviders.class); + } + + @Before + public void init() { + dataBroker = getDataBroker(); + eventBusMock = Mockito.mock(EventBus.class); + listener = new VppEndpointListener(dataBroker, eventBusMock); + } + + @Test + public void testOnWrite() throws Exception { + ArgumentCaptor argVppEpEvent = ArgumentCaptor.forClass(VppEndpointConfEvent.class); + VppEndpoint vppEndpoint = new VppEndpointBuilder().setAddress(ADDRESS) + .setAddressType(AddressType.class) + .setContextId(CONTEXT_ID) + .setContextType(ContextType.class) + .build(); + InstanceIdentifier vppEpIid = + InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEndpoint.getKey()).build(); + WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction(); + wTx.put(LogicalDatastoreType.CONFIGURATION, vppEpIid, vppEndpoint); + wTx.submit().get(); + + Mockito.verify(eventBusMock).post(argVppEpEvent.capture()); + VppEndpointConfEvent capturedVppEpEvent = argVppEpEvent.getValue(); + Assert.assertEquals(vppEpIid, capturedVppEpEvent.getIid()); + assertEqualsOptional(null, capturedVppEpEvent.getBefore()); + assertEqualsOptional(vppEndpoint, capturedVppEpEvent.getAfter()); + } + + @Test + public void testOnDelete() throws Exception { + ArgumentCaptor argVppEpEvent = ArgumentCaptor.forClass(VppEndpointConfEvent.class); + VppEndpoint vppEndpoint = new VppEndpointBuilder().setAddress(ADDRESS) + .setAddressType(AddressType.class) + .setContextId(CONTEXT_ID) + .setContextType(ContextType.class) + .build(); + InstanceIdentifier vppEpIid = + InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEndpoint.getKey()).build(); + WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction(); + wTx.put(LogicalDatastoreType.CONFIGURATION, vppEpIid, vppEndpoint); + wTx.submit().get(); + wTx = getDataBroker().newWriteOnlyTransaction(); + wTx.delete(LogicalDatastoreType.CONFIGURATION, vppEpIid); + wTx.submit().get(); + + Mockito.verify(eventBusMock, Mockito.times(2)).post(argVppEpEvent.capture()); + VppEndpointConfEvent capturedVppEpEvent = argVppEpEvent.getAllValues().get(1); + Assert.assertEquals(vppEpIid, capturedVppEpEvent.getIid()); + assertEqualsOptional(vppEndpoint, capturedVppEpEvent.getBefore()); + assertEqualsOptional(null, capturedVppEpEvent.getAfter()); + } + + @Test + public void testOnSubtreeModified() throws Exception { + ArgumentCaptor argVppEpEvent = ArgumentCaptor.forClass(VppEndpointConfEvent.class); + VppEndpointBuilder vppEndpointBuilder = new VppEndpointBuilder().setAddress(ADDRESS) + .setAddressType(AddressType.class) + .setContextId(CONTEXT_ID) + .setContextType(ContextType.class); + VppEndpoint vppEndpoint = vppEndpointBuilder.build(); + InstanceIdentifier vppEpIid = + InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEndpoint.getKey()).build(); + WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction(); + wTx.put(LogicalDatastoreType.CONFIGURATION, vppEpIid, vppEndpoint); + wTx.submit().get(); + VppEndpoint modifiedVppEndpoint = vppEndpointBuilder.setVppInterfaceName(IFACE_NAME).build(); + wTx = getDataBroker().newWriteOnlyTransaction(); + wTx.put(LogicalDatastoreType.CONFIGURATION, vppEpIid, modifiedVppEndpoint); + wTx.submit().get(); + + Mockito.verify(eventBusMock, Mockito.times(2)).post(argVppEpEvent.capture()); + VppEndpointConfEvent capturedFirstVppEpEvent = argVppEpEvent.getAllValues().get(0); + Assert.assertEquals(vppEpIid, capturedFirstVppEpEvent.getIid()); + assertEqualsOptional(null, capturedFirstVppEpEvent.getBefore()); + assertEqualsOptional(vppEndpoint, capturedFirstVppEpEvent.getAfter()); + VppEndpointConfEvent capturedSecondVppEpEvent = argVppEpEvent.getAllValues().get(1); + Assert.assertEquals(vppEpIid, capturedSecondVppEpEvent.getIid()); + assertEqualsOptional(vppEndpoint, capturedSecondVppEpEvent.getBefore()); + assertEqualsOptional(modifiedVppEndpoint, capturedSecondVppEpEvent.getAfter()); + } + + private void assertEqualsOptional(T expected, Optional actual) { + if (expected == null) { + Assert.assertFalse(actual.isPresent()); + } else { + Assert.assertTrue(actual.isPresent()); + Assert.assertEquals(expected, actual.get()); + } + } + +} diff --git a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/manager/VppManagerDataStoreTest.java b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/manager/VppManagerDataStoreTest.java index 537adc7ed..f5d3518ac 100644 --- a/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/manager/VppManagerDataStoreTest.java +++ b/renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/manager/VppManagerDataStoreTest.java @@ -2,6 +2,7 @@ package org.opendaylight.groupbasedpolicy.renderer.vpp.manager; import com.google.common.base.Optional; +import com.google.common.eventbus.EventBus; import com.google.common.util.concurrent.CheckedFuture; import org.junit.After; import org.junit.Assert; @@ -74,7 +75,7 @@ public class VppManagerDataStoreTest extends VppRendererDataBrokerTest { Mockito.when(mountPoint.getService(Matchers.>any())).thenReturn(Optional.of(dataBroker2)); dataBroker = getDataBroker(); vppNodeManager = new VppNodeManager(dataBroker, providerContext); - vppNodeListener = new VppNodeListener(dataBroker, vppNodeManager); + vppNodeListener = new VppNodeListener(dataBroker, vppNodeManager, new EventBus()); } private Node createNode(final String name, NetconfNodeConnectionStatus.ConnectionStatus status) { -- 2.36.6