Add support for Openstack Neutron Trunkport APIs 15/50615/7
authorVishal Thapar <vishal.thapar@ericsson.com>
Sat, 14 Jan 2017 13:20:42 +0000 (18:50 +0530)
committerVishal Thapar <vishal.thapar@ericsson.com>
Thu, 19 Jan 2017 06:55:28 +0000 (12:25 +0530)
This adds the following:
1. Yang model for TrunkPort Openstack Neuton v2 extension
2. Implementation of API (spi, api and transcriber)
3. UTs for testing spi
4. ITs for E2E testing of API

External References:
https://blueprints.launchpad.net/neutron/+spec/vlan-aware-vms
http://specs.openstack.org/openstack/neutron-specs/specs/newton/vlan-aware-vms.html
https://wiki.openstack.org/wiki/Neutron/TrunkPort

ODL Driver: https://review.openstack.org/#/c/421895/

Change-Id: I1428e44f93a5bc4507ad5b39c1f2f9f92540fab8
Signed-off-by: Vishal Thapar <vishal.thapar@ericsson.com>
13 files changed:
integration/test/src/test/java/org/opendaylight/neutron/e2etest/ITNeutronE2E.java
integration/test/src/test/java/org/opendaylight/neutron/e2etest/NeutronTrunkTests.java [new file with mode: 0644]
model/src/main/yang/neutron-trunks.yang [new file with mode: 0644]
model/src/main/yang/neutron.yang
neutron-spi/src/main/java/org/opendaylight/neutron/spi/INeutronTrunkCRUD.java [new file with mode: 0644]
neutron-spi/src/main/java/org/opendaylight/neutron/spi/NeutronTrunk.java [new file with mode: 0644]
neutron-spi/src/main/java/org/opendaylight/neutron/spi/NeutronTrunkSubPort.java [new file with mode: 0644]
neutron-spi/src/test/java/org/opendaylight/neutron/spi/NeutronTrunkJAXBTest.java [new file with mode: 0644]
northbound-api/src/main/java/org/opendaylight/neutron/northbound/api/NeutronNorthboundRSApplication.java
northbound-api/src/main/java/org/opendaylight/neutron/northbound/api/NeutronTrunkRequest.java [new file with mode: 0644]
northbound-api/src/main/java/org/opendaylight/neutron/northbound/api/NeutronTrunksNorthbound.java [new file with mode: 0644]
transcriber/src/main/java/org/opendaylight/neutron/transcriber/NeutronTranscriberProvider.java
transcriber/src/main/java/org/opendaylight/neutron/transcriber/NeutronTrunkInterface.java [new file with mode: 0644]

index 736891e571f8615eda2d926f3120cb12c3bcd413..35870ac79c5f1120a7f0722ee959f47c3cde6fda 100644 (file)
@@ -115,6 +115,7 @@ public class ITNeutronE2E {
         NeutronSFCPortPairGroupTests.runTests(base);
         NeutronSFCPortChainTests.runTests(base);
         NeutronSFCFlowClassifierTests.runTests(base);
+        NeutronTrunkTests.runTests(base);
 
         // tests related to bugs
         NeutronBug3812Tests.runTests(base);
@@ -261,11 +262,11 @@ public class ITNeutronE2E {
         Gson gson = new Gson();
         JsonObject jsonObjectOutput = gson.fromJson(response, JsonObject.class);
         Set<Map.Entry<String, JsonElement>> entrySet = jsonObjectOutput.entrySet();
-        Assert.assertTrue("E2E Tests Failed - Json Error", (entrySet.size() > 0));
+        Assert.assertTrue("E2E Tests Failed - Json Error", entrySet.size() > 0);
         JsonElement jsonElementValue = entrySet.iterator().next().getValue();
         String key = entrySet.iterator().next().getKey();
         Assert.assertEquals(context, collectionName, key);
-        Assert.assertTrue("E2E Tests Failed - Collection not Array", (jsonElementValue.isJsonArray()));
+        Assert.assertTrue("E2E Tests Failed - Collection not Array", jsonElementValue.isJsonArray());
         JsonArray jsonArray = jsonElementValue.getAsJsonArray();
         Assert.assertNotEquals(context, jsonArray.size(), 0);
     }
@@ -280,7 +281,7 @@ public class ITNeutronE2E {
             String key = element.getKey();
             JsonElement jsonElementValue = element.getValue();
             // Query only values that are non null Primitives - Integer,Strings,character and boolean
-            if (jsonElementValue.isJsonPrimitive() && (!jsonElementValue.isJsonNull())) {
+            if (jsonElementValue.isJsonPrimitive() && !jsonElementValue.isJsonNull()) {
                 String valueStr = jsonElementValue.getAsString();
                 valueStr = valueStr.replaceAll("\\s+", "+");
                 String queryUrl = urlStr + "?" + key + "=" + valueStr;
diff --git a/integration/test/src/test/java/org/opendaylight/neutron/e2etest/NeutronTrunkTests.java b/integration/test/src/test/java/org/opendaylight/neutron/e2etest/NeutronTrunkTests.java
new file mode 100644 (file)
index 0000000..b4ffad8
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. 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.neutron.e2etest;
+
+public class NeutronTrunkTests {
+    String base;
+
+    public NeutronTrunkTests(String base) {
+        this.base = base;
+    }
+
+    public void trunk_collection_get_test() {
+        String url = base + "/trunks";
+        ITNeutronE2E.test_fetch(url, "Trunk collection GET failed");
+    }
+
+    public String singleton_trunk_create_test() {
+        String url = base + "/trunks";
+        String content = "{\"trunk\":{\"status\":\"DOWN\",\"name\":\"trunk0\",\"admin_state_up\":true, "
+                + "\"tenant_id\":\"cc3641789c8a4304abaa841c64f638d9\", "
+                + "\"port_id\":\"60aac28d-1d3a-48d9-99bc-dd4bd62e50f2\", "
+                + "\"sub_ports\":[{\"segmentation_type\":\"vlan\", "
+                + "\"port_id\":\"dca33436-2a7c-415b-aa35-14769e7834e3\",\"segmentation_id\":101}, "
+                + "{\"segmentation_type\":\"vlan\",\"port_id\":\"be28febe-bdff-45cc-8a2d-872d54e62527\", "
+                + "\"segmentation_id\":102}],\"id\":\"c935240e-4aa6-496a-841c-d113c54499b9\", "
+                + "\"description\":\"test trunk0\"} }";
+        ITNeutronE2E.test_create(url, content, "Singleton Trunk Post Failed NB");
+        return content;
+    }
+
+    public void singleton_trunk_get_with_one_query_item_test(String createJsonString) {
+        String url = base + "/trunks";
+        ITNeutronE2E.test_fetch_with_one_query_item(url, createJsonString, "trunks");
+    }
+
+    public void bulk_trunk_create_test() {
+        String url = base + "/trunks";
+        String content = "{\"trunks\":[{\"status\":\"DOWN\",\"name\":\"trunk1\",\"admin_state_up\":true, "
+                + "\"tenant_id\":\"cc3641789c8a4304abaa841c64f638d9\", "
+                + "\"port_id\":\"87927a7a-86ec-4062-946f-40222ec583ca\", "
+                + "\"sub_ports\":[{\"segmentation_type\":\"vlan\", "
+                + "\"port_id\":\"75e366aa-51b6-4ec8-9695-739c465377f7\",\"segmentation_id\":101}, "
+                + "{\"segmentation_type\":\"vlan\",\"port_id\":\"e12f8356-ff66-4948-979f-9dedb63ee299\", "
+                + "\"segmentation_id\":102}],\"id\":\"bc587c4c-de31-42b1-89c3-809add88c9b3\", "
+                + "\"description\":\"test trunk1\"},"
+                + "{\"status\":\"ACTIVE\",\"name\":\"trunk2\",\"admin_state_up\":true, "
+                + "\"tenant_id\":\"cc3641789c8a4304abaa841c64f638d9\","
+                + "\"port_id\":\"f5624c68-eda2-42c1-92a1-53094707dc36\", "
+                + "\"sub_ports\":[{\"segmentation_type\":\"vlan\", "
+                + "\"port_id\":\"2a4897de-d5ba-4bd5-8998-4f86e083e3fd\", \"segmentation_id\":101},"
+                + "{\"segmentation_type\":\"vlan\",\"port_id\":\"9dedb63e-ff66-4948-979f-e12f8356e299\", "
+                + "\"segmentation_id\":102}],"
+                + "\"id\":\"5e97b0a4-b5a3-49fd-b0cb-821bec16acfe\",\"description\":\"test trunk2\"}]}";
+        ITNeutronE2E.test_create(url, content, "Bulk Trunk Post Failed");
+    }
+
+    public void trunk_update_test() {
+        String url = base + "/trunks/c935240e-4aa6-496a-841c-d113c54499b9";
+        String content = "{\"trunk\":{\"status\":\"DOWN\",\"name\":\"trunk0\",\"admin_state_up\":true, "
+                + "\"port_id\":\"60aac28d-1d3a-48d9-99bc-dd4bd62e50f2\", "
+                + "\"sub_ports\":[{\"segmentation_type\":\"vlan\", "
+                + "\"port_id\":\"dca33436-2a7c-415b-aa35-14769e7834e3\",\"segmentation_id\":101}], "
+                + "\"id\":\"c935240e-4aa6-496a-841c-d113c54499b9\", \"description\":\"test trunk0 updated\"} }";
+        ITNeutronE2E.test_modify(url, content, "Trunk Put Failed");
+    }
+
+    public void trunk_bulk_get_test() {
+        String url = base + "/trunks"; // /c935240e-4aa6-496a-841c-d113c54499b9";
+        ITNeutronE2E.test_fetch(url, true, "Trunk Bulk Get Failed");
+    }
+
+    public void trunk_element_get_test() {
+        String url = base + "/trunks/c935240e-4aa6-496a-841c-d113c54499b9";
+        ITNeutronE2E.test_fetch(url, true, "Trunk Element Get Failed");
+    }
+
+    public void trunk_element_get_test_with_added_query() {
+        String url = base + "/trunks/c935240e-4aa6-496a-841c-d113c54499b9"
+                + "?fields=id&fields=tenant_id&fields=name&fields=port_id"
+                + "&fields=status&fields=admin_state_up&fields=sub_ports";
+        ITNeutronE2E.test_fetch(url, true, "Trunk Element Get with query Failed");
+    }
+
+    public void trunk_element_negative_get_test() {
+        String url = base + "/trunks/bc1a76cb-8767-4c3a-bb95-018b822f2130";
+        ITNeutronE2E.test_fetch(url, false, "Trunk Element Negative Get Failed");
+    }
+
+    public void trunk_delete_test() {
+        String url = base + "/trunks/c935240e-4aa6-496a-841c-d113c54499b9";
+        ITNeutronE2E.test_delete(url, "Trunk Element Delete Failed");
+    }
+
+    public static void runTests(String base) {
+        NeutronTrunkTests trunkTester = new NeutronTrunkTests(base);
+        trunkTester.trunk_collection_get_test();
+        String createJsonString = trunkTester.singleton_trunk_create_test();
+        trunkTester.singleton_trunk_get_with_one_query_item_test(createJsonString);
+        trunkTester.bulk_trunk_create_test();
+        trunkTester.trunk_update_test();
+        trunkTester.trunk_bulk_get_test();
+        trunkTester.trunk_element_get_test();
+        trunkTester.trunk_element_get_test_with_added_query();
+        trunkTester.trunk_delete_test();
+        trunkTester.trunk_element_negative_get_test();
+    }
+}
diff --git a/model/src/main/yang/neutron-trunks.yang b/model/src/main/yang/neutron-trunks.yang
new file mode 100644 (file)
index 0000000..cdf92d7
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd..  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
+ */
+ module neutron-trunks {
+    yang-version 1;
+    namespace "urn:opendaylight:neutron-trunks";
+
+    prefix neutron-trunks;
+
+    import ietf-yang-types { prefix "yang"; }
+    import neutron-networks { prefix "networks"; }
+    import neutron-attrs    { prefix "attrs"; }
+
+    organization "OpenDaylight Neutron Northbound Project";
+
+    contact "Neutron Northbound <neutron-dev@lists.opendaylight.org>";
+
+    description " This YANG module defines Openstack Neutron Trunk Ports Model. The model is based on the REST APIs
+                  exposed by the trunk service of Neutron version 2. description of the REST API is located in
+                  both the Openstack Wiki (https://wiki.openstack.org/wiki/Neutron/TrunkPort) and inside the
+                  specification for VLAN Aware VMs
+                  (http://specs.openstack.org/openstack/neutron-specs/specs/newton/vlan-aware-vms.html)";
+
+    revision "2017-01-18" {
+        description
+            "OpenStack Neutron Service Trunk Model - Version 1.";
+    }
+
+    grouping sub-port-attributes {
+        description "Decorates a single neutron port to serve as a tunneling port that a VM can use for
+                     segmented traffic. The VM in question must have the ability to encapsulate and decapsulate the
+                     traffic based on the port's tunneling protocol and tunnel id.
+                     NOTE: Currently the only supported tunneling protocol is 802.1q.";
+        leaf port-id {
+            type yang:uuid;
+            description "UUID of the neutron port to be turned into a trunk.";
+        }
+        leaf segmentation-type {
+            type networks:network-type;
+            description "Type of tunneling protocol used to encapsulate traffic in this port.";
+        }
+        leaf segmentation-id {
+            type uint32;
+            description "Tunnel id of the specific tunnel.";
+        }
+    }
+    grouping trunk-attributes {
+        description "Decorates a single neutron port to serve as a trunk port, bundling several sub ports (tunnels)
+                     together.";
+        uses attrs:base-attributes;
+        uses attrs:admin-attributes;
+        leaf port-id {
+            type yang:uuid;
+            description "UUID of the neutron port to be turned into a trunk.";
+        }
+        list sub-ports {
+            description "Bundled sub ports (tunnels), transmitted through this trunk port.";
+            key port-id;
+            unique "segmentation-type segmentation-id";
+            uses sub-port-attributes;
+        }
+    }
+    grouping trunks-attributes{
+        container trunks {
+           list trunk {
+               key uuid;
+               uses trunk-attributes;
+           }
+        }
+    }
+ }
index 17cdf23875e69fdab06001c7367b232c885a313a..2663ab22c98316088d192129376235e2ce4baa8e 100644 (file)
@@ -30,6 +30,7 @@ module neutron {
     import neutron-qos { prefix "qos"; }
     import neutron-sfc-flow-classifier { prefix "sfc-flow-classifier"; }
     import neutron-sfc { prefix "sfc"; }
+    import neutron-trunks { prefix "trunks"; }
 
     organization "OpenDaylight Neutron Group";
 
@@ -68,5 +69,6 @@ module neutron {
         uses qos:qos-attributes;
         uses sfc-flow-classifier:sfc-flow-classifiers-attributes;
         uses sfc:sfc-attributes;
+        uses trunks:trunks-attributes;
     }
 }
diff --git a/neutron-spi/src/main/java/org/opendaylight/neutron/spi/INeutronTrunkCRUD.java b/neutron-spi/src/main/java/org/opendaylight/neutron/spi/INeutronTrunkCRUD.java
new file mode 100644 (file)
index 0000000..0881269
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. 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.neutron.spi;
+
+/**
+ * This interface defines the methods for CRUD of NB trunk objects.
+ *
+ */
+
+public interface INeutronTrunkCRUD extends INeutronCRUD<NeutronTrunk> {
+    // Nothing Here.
+    // This class is defined to use reflection like INeutornTrunkCRUD.class
+}
diff --git a/neutron-spi/src/main/java/org/opendaylight/neutron/spi/NeutronTrunk.java b/neutron-spi/src/main/java/org/opendaylight/neutron/spi/NeutronTrunk.java
new file mode 100644 (file)
index 0000000..1d22124
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. 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.neutron.spi;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "trunk")
+@XmlAccessorType(XmlAccessType.NONE)
+public final class NeutronTrunk extends NeutronAdminAttributes<NeutronTrunk> implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "port_id")
+    String portId;
+
+    @XmlElement(name = "sub_ports")
+    List<NeutronTrunkSubPort> subPorts;
+
+    public NeutronTrunk() {
+    }
+
+    @Override
+    public void initDefaults() {
+        adminStateUp = true;
+        if (status == null) {
+            status = "DOWN";
+        }
+        if (subPorts == null) {
+            subPorts = new ArrayList<>();
+        }
+    }
+
+    public String getPortId() {
+        return portId;
+    }
+
+    public void setPortId(String portId) {
+        this.portId = portId;
+    }
+
+    public List<NeutronTrunkSubPort> getSubPorts() {
+        return subPorts;
+    }
+
+    public void setSubPorts(List<NeutronTrunkSubPort> subPorts) {
+        this.subPorts = subPorts;
+    }
+
+
+
+    /**
+     * This method copies selected fields from the object and returns them
+     * as a new object, suitable for marshaling.
+     *
+     * @param fields
+     *            List of attributes to be extracted
+     * @return an OpenStackTrunk object with only the selected fields
+     *             populated
+     */
+
+    @Override
+    public NeutronTrunk extractFields(List<String> fields) {
+        NeutronTrunk ans = new NeutronTrunk();
+        for (String s : fields) {
+            extractField(s, ans);
+            if ("port_id".equals(s)) {
+                ans.setPortId(this.getPortId());
+            }
+            if ("sub_ports".equals(s)) {
+                List<NeutronTrunkSubPort> subPortList = new ArrayList<>();
+                subPortList.addAll(this.getSubPorts());
+                ans.setSubPorts(subPortList);
+            }
+        }
+        return ans;
+    }
+
+    @Override
+    public String toString() {
+        return "NeutronTrunk{" + "trunkUUID='" + uuid + '\'' + ", trunkName='" + name + '\''
+                + ", tenantID='" + tenantID + '\'' + ", adminStateUp='" + adminStateUp + '\''
+                + ", status='" + status + '\'' + ", portId='" + portId + '\''
+                + ", subPorts='" + subPorts + '\'' + '}';
+    }
+}
diff --git a/neutron-spi/src/main/java/org/opendaylight/neutron/spi/NeutronTrunkSubPort.java b/neutron-spi/src/main/java/org/opendaylight/neutron/spi/NeutronTrunkSubPort.java
new file mode 100644 (file)
index 0000000..d6c98bb
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. 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.neutron.spi;
+
+import java.io.Serializable;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public final class NeutronTrunkSubPort implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name = "port_id")
+    String portId;
+
+    @XmlElement(name = "segmentation_type")
+    String segmentationType;
+
+    @XmlElement(name = "segmentation_id")
+    String segmentationId;
+
+    public NeutronTrunkSubPort() {
+    }
+
+    public String getPortId() {
+        return portId;
+    }
+
+    public void setPortId(String portId) {
+        this.portId = portId;
+    }
+
+    public String getSegmentationType() {
+        return segmentationType;
+    }
+
+    public void setSegmentationType(String segmentationType) {
+        this.segmentationType = segmentationType;
+    }
+
+    public String getSegmentationId() {
+        return segmentationId;
+    }
+
+    public void setSegmentationId(String segmentationId) {
+        this.segmentationId = segmentationId;
+    }
+
+    @Override
+    public String toString() {
+        return "subPorts{" + "portId='" + portId + '\'' + ", segmentationType='" + segmentationType + '\''
+                + ", segmentationId='" + segmentationId + '\'' + '}';
+    }
+}
diff --git a/neutron-spi/src/test/java/org/opendaylight/neutron/spi/NeutronTrunkJAXBTest.java b/neutron-spi/src/test/java/org/opendaylight/neutron/spi/NeutronTrunkJAXBTest.java
new file mode 100644 (file)
index 0000000..403d83c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. 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.neutron.spi;
+
+import javax.xml.bind.JAXBException;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class NeutronTrunkJAXBTest {
+
+    private static final String NEUTRON_TRUNK_SOURCE_JSON =
+            "{\"status\":\"DOWN\",\"name\":\"trunk-jaxb-test\",\"admin_state_up\":true, "
+            + "\"tenant_id\":\"cc3641789c8a4304abaa841c64f638d9\", "
+            + "\"port_id\":\"60aac28d-1d3a-48d9-99bc-dd4bd62e50f2\", "
+            + "\"sub_ports\":[{\"segmentation_type\":\"vlan\", "
+            + "\"port_id\":\"dca33436-2a7c-415b-aa35-14769e7834e3\",\"segmentation_id\":101}, "
+            + "{\"segmentation_type\":\"vlan\",\"port_id\":\"be28febe-bdff-45cc-8a2d-872d54e62527\", "
+            + "\"segmentation_id\":102}],\"id\":\"c935240e-4aa6-496a-841c-d113c54499b9\"}";
+
+    @Test
+    public void test_NeutronTrunk_JAXB() throws JAXBException {
+        NeutronTrunk testObject = new NeutronTrunk();
+        NeutronTrunk neutronObject = (NeutronTrunk) JaxbTestHelper.jaxbUnmarshall(testObject,
+                NEUTRON_TRUNK_SOURCE_JSON);
+        Assert.assertEquals("NeutronTrunk JAXB Test 1: Testing id failed", "c935240e-4aa6-496a-841c-d113c54499b9",
+                neutronObject.getID());
+
+        Assert.assertEquals("NeutronTrunk JAXB Test 2 : Testing Status failed", "DOWN",
+                neutronObject.getStatus());
+
+        Assert.assertEquals("NeutronTrunk JAXB Test 3 : Testing Name failed", "trunk-jaxb-test",
+                neutronObject.getName());
+
+        Assert.assertTrue("NeutronTrunk JAXB Test 4 : Testing AdminStateUp failed",
+                neutronObject.getAdminStateUp());
+
+        Assert.assertEquals("NeutronTrunk JAXB Test 5: Testing tenant_id failed",
+                "cc3641789c8a4304abaa841c64f638d9", neutronObject.getTenantID());
+
+        Assert.assertEquals("NeutronTrunk JAXB Test 6 : Testing PotId failed", "60aac28d-1d3a-48d9-99bc-dd4bd62e50f2",
+                neutronObject.getPortId());
+
+        Assert.assertEquals("NeutronTrunk JAXB Test 7 : Testing SubPorts size failed", 2,
+                neutronObject.getSubPorts().size());
+
+        NeutronTrunkSubPort subPort = neutronObject.getSubPorts().get(0);
+
+        Assert.assertEquals("NeutronTrunk JAXB Test 8 : Testing SubPort Segmentation Type failed", "vlan",
+                subPort.getSegmentationType());
+
+        Assert.assertEquals("NeutronTrunk JAXB Test 9 : Testing SubPort Segmentation Id failed", "101",
+                subPort.getSegmentationId());
+
+        Assert.assertEquals("NeutronTrunk JAXB Test 10 : Testing SubPort Port Id failed",
+                "dca33436-2a7c-415b-aa35-14769e7834e3",  subPort.getPortId());
+    }
+}
index ea35d05be6624321e84bb147ec4466a72f93a9bf..d022ce72551c61657b8cb1d413a5a2539e4d1160 100644 (file)
@@ -56,6 +56,7 @@ public final class NeutronNorthboundRSApplication extends Application {
         classes.add(NeutronSFCPortPairGroupsNorthbound.class);
         classes.add(NeutronSFCPortChainsNorthbound.class);
         classes.add(NeutronQosPolicyNorthbound.class);
+        classes.add(NeutronTrunksNorthbound.class);
 
         classes.add(MOXyJsonProvider.class);
         return classes;
diff --git a/northbound-api/src/main/java/org/opendaylight/neutron/northbound/api/NeutronTrunkRequest.java b/northbound-api/src/main/java/org/opendaylight/neutron/northbound/api/NeutronTrunkRequest.java
new file mode 100644 (file)
index 0000000..8846111
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. 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.neutron.northbound.api;
+
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import org.opendaylight.neutron.spi.NeutronTrunk;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public final class NeutronTrunkRequest implements INeutronRequest<NeutronTrunk> {
+
+    @XmlElement(name = "trunk")
+    NeutronTrunk singleton;
+
+    @XmlElement(name = "trunks")
+    List<NeutronTrunk> bulkRequest;
+
+    NeutronTrunkRequest() {
+    }
+
+    NeutronTrunkRequest(NeutronTrunk trunk) {
+        singleton = trunk;
+    }
+
+    NeutronTrunkRequest(List<NeutronTrunk> bulk) {
+        bulkRequest = bulk;
+    }
+}
diff --git a/northbound-api/src/main/java/org/opendaylight/neutron/northbound/api/NeutronTrunksNorthbound.java b/northbound-api/src/main/java/org/opendaylight/neutron/northbound/api/NeutronTrunksNorthbound.java
new file mode 100644 (file)
index 0000000..b5fcf71
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. 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.neutron.northbound.api;
+
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.List;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.neutron.spi.INeutronTrunkCRUD;
+import org.opendaylight.neutron.spi.NeutronTrunk;
+
+@Path("/trunks")
+public final class NeutronTrunksNorthbound
+        extends AbstractNeutronNorthbound<NeutronTrunk, NeutronTrunkRequest, INeutronTrunkCRUD> {
+
+    private static final String RESOURCE_NAME = "Trunk";
+
+    @Override
+    protected String getResourceName() {
+        return RESOURCE_NAME;
+    }
+
+    /**
+     * Returns a list of all Trunks.
+     */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({ @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
+            @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
+            @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
+            @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
+    public Response listGroups(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // OpenStack trunk attributes
+            @QueryParam("id") String queryUUID,
+            @QueryParam("tenant_id") String queryTenantID,
+            @QueryParam("status") String queryStatus,
+            @QueryParam("name") String queryName,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse) {
+        INeutronTrunkCRUD trunkInterface = getNeutronCRUD();
+        List<NeutronTrunk> ans = new ArrayList<>();
+        for (NeutronTrunk nsg : trunkInterface.getAll()) {
+            if ((queryUUID == null || queryUUID.equals(nsg.getID()))
+                    && (queryTenantID == null || queryTenantID.equals(nsg.getTenantID()))
+                    && (queryStatus == null || queryStatus.equals(nsg.getStatus()))
+                    && (queryName == null || queryName.equals(nsg.getName()))) {
+                if (fields.size() > 0) {
+                    ans.add(nsg.extractFields(fields));
+                } else {
+                    ans.add(nsg);
+                }
+            }
+        }
+        return Response.status(HttpURLConnection.HTTP_OK).entity(new NeutronTrunkRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific Trunk.
+     */
+    @Path("{trunkUUID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({ @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
+            @ResponseCode(code = HttpURLConnection.HTTP_UNAUTHORIZED, condition = "Unauthorized"),
+            @ResponseCode(code = HttpURLConnection.HTTP_NOT_FOUND, condition = "Not Found"),
+            @ResponseCode(code = HttpURLConnection.HTTP_NOT_IMPLEMENTED, condition = "Not Implemented"),
+            @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
+    public Response showTrunk(@PathParam("trunkUUID") String trunkUUID,
+            @QueryParam("fields") List<String> fields) {
+        return show(trunkUUID, fields);
+    }
+
+    /**
+     * Creates new Trunk.
+     */
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({ @ResponseCode(code = HttpURLConnection.HTTP_CREATED, condition = "Created"),
+            @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
+    public Response createTrunks(final NeutronTrunkRequest input) {
+        return create(input);
+    }
+
+    /**
+     * Updates a Trunk.
+     */
+    @Path("{trunkUUID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({ @ResponseCode(code = HttpURLConnection.HTTP_OK, condition = "Operation successful"),
+            @ResponseCode(code = HttpURLConnection.HTTP_NOT_FOUND, condition = "Not Found"),
+            @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
+    public Response updateTrunk(@PathParam("trunkUUID") String trunkUUID,
+            final NeutronTrunkRequest input) {
+        return update(trunkUUID, input);
+    }
+
+    /**
+     * Deletes a Trunk.
+     */
+    @Path("{trunkUUID}")
+    @DELETE
+    @StatusCodes({ @ResponseCode(code = HttpURLConnection.HTTP_NO_CONTENT, condition = "No Content"),
+            @ResponseCode(code = HttpURLConnection.HTTP_NOT_FOUND, condition = "Not Found"),
+            @ResponseCode(code = HttpURLConnection.HTTP_UNAVAILABLE, condition = "No providers available") })
+    public Response deleteTrunk(@PathParam("trunkUUID") String trunkUUID) {
+        return delete(trunkUUID);
+    }
+}
index 9e04eb277034face1f57c725d227925377317d94..79697024172fe5f0787a3be6bc574040614d114a 100644 (file)
@@ -37,6 +37,7 @@ import org.opendaylight.neutron.spi.INeutronSFCPortPairGroupCRUD;
 import org.opendaylight.neutron.spi.INeutronSecurityGroupCRUD;
 import org.opendaylight.neutron.spi.INeutronSecurityRuleCRUD;
 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
+import org.opendaylight.neutron.spi.INeutronTrunkCRUD;
 import org.opendaylight.neutron.spi.INeutronVpnIkePolicyCRUD;
 import org.opendaylight.neutron.spi.INeutronVpnIpSecPolicyCRUD;
 import org.opendaylight.neutron.spi.INeutronVpnIpSecSiteConnectionsCRUD;
@@ -50,7 +51,7 @@ public final class NeutronTranscriberProvider implements AutoCloseable, NeutronT
     private static final Logger LOGGER = LoggerFactory.getLogger(NeutronTranscriberProvider.class);
 
     private BundleContext context;
-    private DataBroker db;
+    private final DataBroker db;
     private final List<ServiceRegistration<? extends INeutronCRUD<?>>> registrations = new ArrayList<>();
     private final List<AutoCloseable> neutronInterfaces = new ArrayList<>();
 
@@ -96,6 +97,7 @@ public final class NeutronTranscriberProvider implements AutoCloseable, NeutronT
         registerCRUDInterface(INeutronSecurityGroupCRUD.class, new NeutronSecurityGroupInterface(db));
         registerCRUDInterface(INeutronSecurityRuleCRUD.class, new NeutronSecurityRuleInterface(db));
         registerCRUDInterface(INeutronSubnetCRUD.class, new NeutronSubnetInterface(db));
+        registerCRUDInterface(INeutronTrunkCRUD.class, new NeutronTrunkInterface(db));
         registerCRUDInterface(INeutronVpnIkePolicyCRUD.class, new NeutronVpnIkePolicyInterface(db));
         registerCRUDInterface(INeutronVpnIpSecPolicyCRUD.class, new NeutronVpnIpSecPolicyInterface(db));
         registerCRUDInterface(INeutronVpnIpSecSiteConnectionsCRUD.class,
diff --git a/transcriber/src/main/java/org/opendaylight/neutron/transcriber/NeutronTrunkInterface.java b/transcriber/src/main/java/org/opendaylight/neutron/transcriber/NeutronTrunkInterface.java
new file mode 100644 (file)
index 0000000..9043643
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. 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.neutron.transcriber;
+
+
+import com.google.common.collect.ImmutableBiMap;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.neutron.spi.INeutronTrunkCRUD;
+import org.opendaylight.neutron.spi.NeutronTrunk;
+import org.opendaylight.neutron.spi.NeutronTrunkSubPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeFlat;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.trunks.rev170118.trunk.attributes.SubPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.trunks.rev170118.trunk.attributes.SubPortsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.trunks.rev170118.trunks.attributes.Trunks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.trunks.rev170118.trunks.attributes.trunks.Trunk;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.trunks.rev170118.trunks.attributes.trunks.TrunkBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.trunks.rev170118.trunks.attributes.trunks.TrunkKey;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class NeutronTrunkInterface extends AbstractNeutronInterface<Trunk, Trunks, TrunkKey, NeutronTrunk>
+        implements INeutronTrunkCRUD {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NeutronTrunkInterface.class);
+    private static final ImmutableBiMap<Class<? extends NetworkTypeBase>, String> NETWORK_TYPE_MAP =
+            new ImmutableBiMap.Builder<Class<? extends NetworkTypeBase>, String>()
+            .put(NetworkTypeFlat.class, "flat").put(NetworkTypeGre.class, "gre")
+            .put(NetworkTypeVlan.class, "vlan").put(NetworkTypeVxlan.class, "vxlan").build();
+
+    NeutronTrunkInterface(DataBroker db) {
+        super(TrunkBuilder.class, db);
+    }
+
+    @Override
+    protected List<Trunk> getDataObjectList(Trunks trunks) {
+        return trunks.getTrunk();
+    }
+
+    @Override
+    protected NeutronTrunk fromMd(Trunk trunk) {
+        final NeutronTrunk result = new NeutronTrunk();
+        fromMdAdminAttributes(trunk, result);
+        if (trunk.getPortId() != null) {
+            result.setPortId(trunk.getPortId().getValue());
+        }
+        if (trunk.getSubPorts() != null) {
+            final List<NeutronTrunkSubPort> subPortList = new ArrayList<>();
+            for (final SubPorts subPort : trunk.getSubPorts()) {
+                NeutronTrunkSubPort trunkSubPort = new NeutronTrunkSubPort();
+                trunkSubPort.setPortId(subPort.getPortId().getValue());
+                trunkSubPort.setSegmentationType(NETWORK_TYPE_MAP.get(subPort.getSegmentationType()));
+                trunkSubPort.setSegmentationId(subPort.getSegmentationId().toString());
+                subPortList.add(trunkSubPort);
+            }
+            result.setSubPorts(subPortList);
+        }
+        return result;
+    }
+
+    @Override
+    protected Trunk toMd(NeutronTrunk trunk) {
+        final TrunkBuilder trunkBuilder = new TrunkBuilder();
+        toMdAdminAttributes(trunk, trunkBuilder);
+        if (trunk.getPortId() != null) {
+            trunkBuilder.setPortId(toUuid(trunk.getPortId()));
+        }
+        if (trunk.getSubPorts() != null) {
+            final List<SubPorts> subPortsList = new ArrayList<>();
+            final SubPortsBuilder subPortsBuilder = new SubPortsBuilder();
+            final ImmutableBiMap<String, Class<? extends NetworkTypeBase>> mapper = NETWORK_TYPE_MAP.inverse();
+            for (NeutronTrunkSubPort subPort: trunk.getSubPorts()) {
+                subPortsBuilder.setPortId(toUuid(subPort.getPortId()));
+                subPortsBuilder.setSegmentationType(mapper.get(subPort.getSegmentationType()));
+                subPortsBuilder.setSegmentationId(Long.valueOf(subPort.getSegmentationId()));
+                subPortsList.add(subPortsBuilder.build());
+            }
+            trunkBuilder.setSubPorts(subPortsList);
+        }
+        return trunkBuilder.build();
+    }
+}