Hostconfig for Openstack in VPP renderer 17/48217/4
authorTomas Cechvala <tcechval@cisco.com>
Thu, 10 Nov 2016 14:38:54 +0000 (15:38 +0100)
committerTomas Cechvala <tcechval@cisco.com>
Tue, 15 Nov 2016 15:48:56 +0000 (15:48 +0000)
Different underlay technologies may be used in multinode
environment (ovs, vpp, etc.)

Configuration for hosts on a particular node may be passed to
Openstack by using hostconfigs feature.

If GBP discoveres a VPP capable node, neutron-vpp-mapper
(if installed) will react to this by exposing a config
specific for the node into
/restconf/operational/neutron:neutron/hostconfigs

On the Openstack side, pseudo-agent-binding port binding
controller (networking-odl) will periodically scan the
datatree mentioned above and if it finds data, it will update
agent database (neutron) with them.

Later on, if someone is going to boot nova instance, nova will
bind the port in such a way as the configuration in agent DB for
the given node tells it.

E.g. if vif_type is 'ovs', a port will be created and bound to
OVS. If it's 'vhostuser' nova will bind the port to a vhostuser
socket (which path is also specified in the config)

How to enable hostconfig feature in Devstack/Openstack:
modify ml2.conf by adding the following lines:
port_binding_controller=pseudo-agentdb-binding
ODL_HOSTCONF_URI=restconf/operational/neutron:neutron/hostconfigs
URL=<your_url, e.g http://127.0.0.1:8080/>

Change-Id: I43dd10a4dc0d7bb62ab3c9f0c6b100718b528cad
Signed-off-by: Tomas Cechvala <tcechval@cisco.com>
neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/NeutronVppMapper.java
neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/SocketInfo.java
neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/hostconfigs/VppNodeListener.java [new file with mode: 0644]
neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/util/HostconfigUtil.java [new file with mode: 0644]
neutron-vpp-mapper/src/test/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/hostconfigs/TestResources.java [new file with mode: 0644]
neutron-vpp-mapper/src/test/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/hostconfigs/VppNodeListenerTest.java [new file with mode: 0644]
neutron-vpp-mapper/src/test/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/util/HostconfigUtilTest.java [new file with mode: 0644]

index e1b17f1a91cce9baee01032c9564578046c11426..994778564c6897e8bfec8c93c7eb3c968482bac0 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.groupbasedpolicy.neutron.vpp.mapper;\r
 \r
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
+import org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.hostconfigs.VppNodeListener;\r
 import org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.processors.NeutronListener;\r
 import org.slf4j.Logger;\r
 import org.slf4j.LoggerFactory;\r
@@ -16,10 +17,12 @@ import org.slf4j.LoggerFactory;
 public class NeutronVppMapper implements AutoCloseable {\r
 \r
     NeutronListener neutronListener;\r
+    VppNodeListener vppNodeListener;\r
     private static final Logger LOG = LoggerFactory.getLogger(NeutronVppMapper.class);\r
 \r
     public NeutronVppMapper(String socketPath, String socketPrefix, DataBroker dataBroker) {\r
         SocketInfo socketInfo = new SocketInfo(socketPath, socketPrefix);\r
+        vppNodeListener = new VppNodeListener(dataBroker, socketInfo);\r
         neutronListener = new NeutronListener(dataBroker, socketInfo);\r
         LOG.info("Neutron VPP started!");\r
     }\r
@@ -27,5 +30,6 @@ public class NeutronVppMapper implements AutoCloseable {
     @Override\r
     public void close() {\r
         neutronListener.close();\r
+        vppNodeListener.close();\r
     }\r
 }\r
index 3c07060314affdfb8495f7b8468ef4a4250ddcd9..c98a07c158922ddc1cbb95c67ef5a1063d7097f0 100644 (file)
@@ -12,6 +12,7 @@ public class SocketInfo {
 \r
     private String socketPath;\r
     private String socketPrefix;\r
+    private final String PORT_ID = "$PORT_ID";\r
 \r
     public SocketInfo(String socketPath, String socketPrefix) {\r
         this.socketPath = socketPath;\r
@@ -26,6 +27,10 @@ public class SocketInfo {
         return socketPrefix;\r
     }\r
 \r
+    public String getVhostUserSocket() {\r
+        return new StringBuilder().append(socketPath).append(socketPrefix).append(PORT_ID).toString();\r
+    }\r
+\r
     @Override\r
     public int hashCode() {\r
         final int prime = 31;\r
diff --git a/neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/hostconfigs/VppNodeListener.java b/neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/hostconfigs/VppNodeListener.java
new file mode 100644 (file)
index 0000000..39b3a85
--- /dev/null
@@ -0,0 +1,102 @@
+/*\r
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.hostconfigs;\r
+\r
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;\r
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;\r
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;\r
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;\r
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
+import org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.SocketInfo;\r
+import org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.util.HostconfigUtil;\r
+import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;\r
+import org.opendaylight.groupbasedpolicy.util.DataTreeChangeHandler;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.Renderers;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererKey;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererNodes;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNode;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.Hostconfigs;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.Hostconfig;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.HostconfigKey;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+public class VppNodeListener extends DataTreeChangeHandler<RendererNode> {\r
+\r
+    private static final Logger LOG = LoggerFactory.getLogger(VppNodeListener.class);\r
+\r
+    private SocketInfo socketInfo;\r
+    public static final RendererName VPP_RENDERER_NAME = new RendererName("vpp-renderer");\r
+\r
+    public VppNodeListener(DataBroker dataBroker, SocketInfo socketInfo) {\r
+        super(dataBroker);\r
+        this.socketInfo = socketInfo;\r
+        registerDataTreeChangeListener(new DataTreeIdentifier<>(\r
+                LogicalDatastoreType.OPERATIONAL, getVppNodeWildcardIid()));\r
+    }\r
+\r
+    private InstanceIdentifier<RendererNode> getVppNodeWildcardIid() {\r
+        return InstanceIdentifier.builder(Renderers.class)\r
+            .child(Renderer.class, new RendererKey(VPP_RENDERER_NAME))\r
+            .child(RendererNodes.class)\r
+            .child(RendererNode.class)\r
+            .build();\r
+    }\r
+\r
+    @Override\r
+    protected void onWrite(DataObjectModification<RendererNode> rootNode,\r
+            InstanceIdentifier<RendererNode> rootIdentifier) {\r
+        writeData(rootNode.getDataAfter());\r
+    }\r
+\r
+    @Override\r
+    protected void onDelete(DataObjectModification<RendererNode> rootNode,\r
+            InstanceIdentifier<RendererNode> rootIdentifier) {\r
+        deleteData(rootNode.getDataBefore());\r
+    }\r
+\r
+    @Override\r
+    protected void onSubtreeModified(DataObjectModification<RendererNode> rootNode,\r
+            InstanceIdentifier<RendererNode> rootIdentifier) {\r
+        deleteData(rootNode.getDataAfter());\r
+        writeData(rootNode.getDataBefore());\r
+    }\r
+\r
+    private void writeData(RendererNode rendererNode) {\r
+        NodeKey nodeKey = rendererNode.getNodePath().firstKeyOf(Node.class);\r
+        WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();\r
+        Hostconfig hcData = HostconfigUtil.createHostconfigsDataFor(nodeKey.getNodeId(), socketInfo);\r
+        wTx.put(LogicalDatastoreType.OPERATIONAL, hostconfigIid(nodeKey.getNodeId()), hcData);\r
+        DataStoreHelper.submitToDs(wTx);\r
+        LOG.info("Hostconfig data written to DS for VPP node {}", nodeKey);\r
+    }\r
+\r
+    private InstanceIdentifier<Hostconfig> hostconfigIid(NodeId nodeId) {\r
+        return InstanceIdentifier.builder(Neutron.class)\r
+            .child(Hostconfigs.class)\r
+            .child(Hostconfig.class, new HostconfigKey(nodeId.getValue(), HostconfigUtil.L2_HOST_TYPE))\r
+            .build();\r
+    }\r
+\r
+    private void deleteData(RendererNode rendererNode) {\r
+        NodeKey nodeKey = rendererNode.getNodePath().firstKeyOf(Node.class);\r
+        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();\r
+        DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, hostconfigIid(nodeKey.getNodeId()), rwTx);\r
+        DataStoreHelper.submitToDs(rwTx);\r
+        LOG.info("Hostconfig data removed from DS for VPP node {}", nodeKey);\r
+    }\r
+}\r
diff --git a/neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/util/HostconfigUtil.java b/neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/util/HostconfigUtil.java
new file mode 100644 (file)
index 0000000..487c9c7
--- /dev/null
@@ -0,0 +1,72 @@
+/*\r
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.util;\r
+\r
+import java.util.List;\r
+\r
+import org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.SocketInfo;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.Hostconfig;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.HostconfigBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;\r
+\r
+import com.google.common.base.Preconditions;\r
+import com.google.common.collect.Lists;\r
+import com.google.gson.JsonArray;\r
+import com.google.gson.JsonObject;\r
+\r
+\r
+public class HostconfigUtil {\r
+\r
+    public static final String L2_HOST_TYPE = "ODL L2";\r
+    private static final String VHOST_USER = "vhostuser";\r
+    private static final String VNIC_TYPE = "normal";\r
+    private static final String HAS_DATAPATH_TYPE_NETDEV = "False";\r
+    private static final String SUPPORT_VHOST_USER = "True";\r
+    private static final String VHOSTUSER_MODE = "server";\r
+    private static final List<String> supportedNetworkTypes = Lists.newArrayList("local", "vlan", "vxlan", "gre");\r
+\r
+    public static Hostconfig createHostconfigsDataFor(NodeId nodeId, SocketInfo socketInfo) {\r
+        Preconditions.checkNotNull(nodeId);\r
+        Preconditions.checkNotNull(socketInfo);\r
+        JsonObject odlL2 = new JsonObject();\r
+        odlL2.add("allowed_network_types", buildSupportedNetworkTypes());\r
+        odlL2.add("supported_vnic_types", buildSupportedVnicTypes(socketInfo));\r
+        return new HostconfigBuilder().setHostId(nodeId.getValue())\r
+            .setHostType(L2_HOST_TYPE)\r
+            .setConfig(odlL2.toString())\r
+            .build();\r
+    }\r
+\r
+    private static JsonArray buildSupportedNetworkTypes() {\r
+        JsonArray networkTypes = new JsonArray();\r
+        supportedNetworkTypes.forEach(networkTypes::add);\r
+        return networkTypes;\r
+    }\r
+\r
+    private static JsonArray buildSupportedVnicTypes(SocketInfo socketInfo) {\r
+        JsonArray supportedVnicTypes = new JsonArray();\r
+        JsonObject supportedVnicType = new JsonObject();\r
+        supportedVnicType.addProperty("vnic_type", VNIC_TYPE);\r
+        supportedVnicType.addProperty("vif_type", VHOST_USER);\r
+        supportedVnicType.add("vif_details", buildVifDetails(socketInfo));\r
+        supportedVnicTypes.add(supportedVnicType);\r
+        return supportedVnicTypes;\r
+    }\r
+\r
+    private static JsonObject buildVifDetails(SocketInfo socketInfo) {\r
+        JsonObject vifDetails = new JsonObject();\r
+        vifDetails.addProperty("has_datapath_type_netdev", HAS_DATAPATH_TYPE_NETDEV);\r
+        vifDetails.addProperty("support_vhost_user", SUPPORT_VHOST_USER);\r
+        vifDetails.addProperty("port_prefix", socketInfo.getSocketPrefix());\r
+        vifDetails.addProperty("vhostuser_socket_dir", socketInfo.getSocketPath());\r
+        vifDetails.addProperty("vhostuser_mode", VHOSTUSER_MODE);\r
+        vifDetails.addProperty("vhostuser_socket", socketInfo.getVhostUserSocket());\r
+        return vifDetails;\r
+    }\r
+}\r
diff --git a/neutron-vpp-mapper/src/test/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/hostconfigs/TestResources.java b/neutron-vpp-mapper/src/test/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/hostconfigs/TestResources.java
new file mode 100644 (file)
index 0000000..50c8be8
--- /dev/null
@@ -0,0 +1,101 @@
+/*\r
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.hostconfigs;\r
+\r
+import java.util.concurrent.ExecutionException;\r
+\r
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;\r
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;\r
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;\r
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
+import org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.util.HostconfigUtil;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.Renderers;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererKey;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererNodes;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNode;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNodeBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.nodes.RendererNodeKey;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.Hostconfigs;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.Hostconfig;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.HostconfigKey;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
+\r
+import com.google.common.base.Optional;\r
+\r
+public class TestResources extends AbstractDataBrokerTest {\r
+\r
+    protected DataBroker dataBroker;\r
+\r
+    void setDataBroker() {\r
+        this.dataBroker = getDataBroker();\r
+    }\r
+\r
+    void writeTopologyNode(TopologyId topologyId, NodeId nodeId) throws InterruptedException, ExecutionException {\r
+        WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();\r
+        wTx.put(LogicalDatastoreType.CONFIGURATION, createNodeIid(topologyId, nodeId), new NodeBuilder().setNodeId(nodeId).build(), true);\r
+        wTx.submit().get();\r
+    }\r
+\r
+    void writeRendererNode(InstanceIdentifier<Node> nodeIid) throws InterruptedException,\r
+            ExecutionException {\r
+        InstanceIdentifier<RendererNode> rendererNodeIid = createRendererNodeIid(nodeIid);\r
+        RendererNode rendererNode = new RendererNodeBuilder().setNodePath(nodeIid).build();\r
+        WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();\r
+        wTx.put(LogicalDatastoreType.OPERATIONAL, rendererNodeIid, rendererNode, true);\r
+        wTx.submit().get();\r
+    }\r
+\r
+    void deleteRendererNode(InstanceIdentifier<Node> nodeIid) throws InterruptedException, ExecutionException {\r
+        InstanceIdentifier<RendererNode> rendererNodeIid = createRendererNodeIid(nodeIid);\r
+        WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();\r
+        wTx.delete(LogicalDatastoreType.OPERATIONAL, rendererNodeIid);\r
+        wTx.submit().get();\r
+    }\r
+\r
+    Optional<Hostconfig> readHostconfig(NodeId nodeId) throws InterruptedException, ExecutionException {\r
+        ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();\r
+        Optional<Hostconfig> opt = rTx.read(LogicalDatastoreType.OPERATIONAL, createHostconfigWildcardNodeIid(nodeId))\r
+            .get();\r
+        rTx.close();\r
+        return opt;\r
+    }\r
+\r
+    static InstanceIdentifier<Node> createNodeIid(TopologyId topologyId, NodeId nodeId) {\r
+        return InstanceIdentifier.builder(NetworkTopology.class)\r
+            .child(Topology.class, new TopologyKey(topologyId))\r
+            .child(Node.class, new NodeKey(nodeId))\r
+            .build();\r
+    }\r
+\r
+    InstanceIdentifier<RendererNode> createRendererNodeIid(InstanceIdentifier<Node> nodeIid) {\r
+        return InstanceIdentifier.builder(Renderers.class)\r
+            .child(Renderer.class, new RendererKey(VppNodeListener.VPP_RENDERER_NAME))\r
+            .child(RendererNodes.class)\r
+            .child(RendererNode.class, new RendererNodeKey(nodeIid))\r
+            .build();\r
+    }\r
+\r
+    InstanceIdentifier<Hostconfig> createHostconfigWildcardNodeIid(NodeId nodeId) {\r
+        return InstanceIdentifier.builder(Neutron.class)\r
+            .child(Hostconfigs.class)\r
+            .child(Hostconfig.class, new HostconfigKey(nodeId.getValue(), HostconfigUtil.L2_HOST_TYPE))\r
+            .build();\r
+    }\r
+}\r
diff --git a/neutron-vpp-mapper/src/test/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/hostconfigs/VppNodeListenerTest.java b/neutron-vpp-mapper/src/test/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/hostconfigs/VppNodeListenerTest.java
new file mode 100644 (file)
index 0000000..12c1ec9
--- /dev/null
@@ -0,0 +1,57 @@
+/*\r
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.\r
+ * \r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.hostconfigs;\r
+\r
+import static org.junit.Assert.assertFalse;\r
+import static org.junit.Assert.assertTrue;\r
+\r
+import java.util.concurrent.ExecutionException;\r
+\r
+import org.junit.After;\r
+import org.junit.Before;\r
+import org.junit.Test;\r
+import org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.SocketInfo;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
+\r
+public class VppNodeListenerTest extends TestResources {\r
+\r
+    private TopologyId topologyId = new TopologyId("topology1");\r
+    private NodeId nodeId = new NodeId("node1");\r
+    private InstanceIdentifier<Node> nodeIid = createNodeIid(topologyId, nodeId);\r
+    private VppNodeListener vppNodeListener;\r
+\r
+    @Before\r
+    public void init() throws InterruptedException, ExecutionException {\r
+        String socketPath = "/tmp/";\r
+        String socketPrefix = "socket_";\r
+        setDataBroker();\r
+        vppNodeListener = new VppNodeListener(dataBroker, new SocketInfo(socketPath, socketPrefix));\r
+        writeTopologyNode(topologyId, nodeId);\r
+        writeRendererNode(createNodeIid(topologyId, nodeId));\r
+    }\r
+\r
+    @Test\r
+    public void writeDataTest() throws InterruptedException, ExecutionException {\r
+        assertTrue(readHostconfig(nodeId).isPresent());\r
+    }\r
+\r
+    @Test\r
+    public void deleteDataTest() throws InterruptedException, ExecutionException {\r
+        deleteRendererNode(nodeIid);\r
+        assertFalse(readHostconfig(nodeId).isPresent());\r
+    }\r
+\r
+    @After\r
+    public void after() {\r
+        vppNodeListener.close();\r
+    }\r
+}\r
diff --git a/neutron-vpp-mapper/src/test/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/util/HostconfigUtilTest.java b/neutron-vpp-mapper/src/test/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/util/HostconfigUtilTest.java
new file mode 100644 (file)
index 0000000..dc32d35
--- /dev/null
@@ -0,0 +1,36 @@
+/*\r
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.util;\r
+\r
+import static org.junit.Assert.assertEquals;\r
+import static org.junit.Assert.assertTrue;\r
+\r
+import org.junit.Test;\r
+import org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.SocketInfo;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.Hostconfig;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;\r
+\r
+\r
+public class HostconfigUtilTest {\r
+\r
+    private final NodeId NODE_ID = new NodeId("node1");\r
+    private final String HOST_TYPE = "ODL L2";\r
+    private final String PATH = "/tmp/";\r
+    private final String PREFIX = "socket_";\r
+    private final String VHOSTUSER = "vhostuser";\r
+\r
+    @Test\r
+    public void createHostconfigsDataForTest() {\r
+        Hostconfig hc = HostconfigUtil.createHostconfigsDataFor(NODE_ID, new SocketInfo(PATH, PREFIX));\r
+        assertEquals(hc.getHostId(), NODE_ID.getValue());\r
+        assertEquals(hc.getHostType(), HOST_TYPE);\r
+        assertTrue(hc.getConfig().contains(PATH));\r
+        assertTrue(hc.getConfig().contains(VHOSTUSER));\r
+    }\r
+}\r