Neutron Model update 34/51534/10
authorRitu Sood <ritu.sood@intel.com>
Tue, 7 Feb 2017 02:09:04 +0000 (18:09 -0800)
committerIsaku Yamahata <isaku.yamahata@gmail.com>
Fri, 17 Mar 2017 01:24:14 +0000 (01:24 +0000)
This patch includes Neutron API/model changes being
introduced.
1) Status field to be moved to operational datastore
Breaking out the status field from this patch
for ease of review and merge process.
Link to status field patch
https://git.opendaylight.org/gerrit/#/c/51981/
2) Project id field is going to depreciate tenant id
https://lists.opendaylight.org/pipermail/neutron-dev/2016-December/001083.html
This fix addresses top level tenant-id used my most models.
Some models internally also use tenant-id in sub-fields. Those
cases will be addressed in Nitrogen.
3) revision number field to be added. This is a monotonic
counter that will be updated whenever an object is updated
on the neutron server.

Change-Id: I8a76fe5ff1147a9e4456c0713913377f266cec24
Signed-off-by: Ritu Sood <ritu.sood@intel.com>
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
integration/test/src/test/java/org/opendaylight/neutron/e2etest/ITNeutronE2E.java
integration/test/src/test/java/org/opendaylight/neutron/e2etest/NeutronProjectIdTests.java [new file with mode: 0644]
integration/test/src/test/java/org/opendaylight/neutron/e2etest/NeutronRevisionNumberTests.java [new file with mode: 0644]
model/src/main/yang/neutron-attrs.yang
neutron-spi/src/main/java/org/opendaylight/neutron/spi/INeutronObject.java
neutron-spi/src/main/java/org/opendaylight/neutron/spi/NeutronObject.java
northbound-api/src/main/java/org/opendaylight/neutron/northbound/api/AbstractNeutronNorthbound.java
transcriber/src/main/java/org/opendaylight/neutron/transcriber/AbstractNeutronInterface.java

index 35870ac79c5f1120a7f0722ee959f47c3cde6fda..910ea8218ba8fcd7f351f6ba81bcc9e463cf32da 100644 (file)
@@ -116,7 +116,8 @@ public class ITNeutronE2E {
         NeutronSFCPortChainTests.runTests(base);
         NeutronSFCFlowClassifierTests.runTests(base);
         NeutronTrunkTests.runTests(base);
-
+        NeutronRevisionNumberTests.runTests(base);
+        NeutronProjectIdTests.runTests(base);
         // tests related to bugs
         NeutronBug3812Tests.runTests(base);
         TempestPortsIpV6TestJSON.runTests(base);
diff --git a/integration/test/src/test/java/org/opendaylight/neutron/e2etest/NeutronProjectIdTests.java b/integration/test/src/test/java/org/opendaylight/neutron/e2etest/NeutronProjectIdTests.java
new file mode 100644 (file)
index 0000000..1aac649
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 Intel Corp.
+ *
+ * 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 NeutronProjectIdTests {
+    String base;
+
+    public NeutronProjectIdTests(String base) {
+        this.base = base;
+    }
+
+    public void collection_get_test() {
+        String url = base + "/fw/firewalls";
+        ITNeutronE2E.test_fetch(url, "RevisionID Collection GET failed");
+    }
+
+    public String singleton_create_test() {
+        String url = base + "/fw/firewalls";
+        String content = " { \"firewall\": { \"admin_state_up\": true," + "\"description\": \"\","
+                + "\"firewall_policy_id\": \"c69933c1-b472-44f9-8226-30dc4ffd454c\","
+                + "\"id\": \"4b0ef8f4-82c7-44d4-a4fb-6177f9a21977\","
+                + "\"name\": \"\","
+                + "\"project_id\": \"45977fa2dbd7482098dd68d0d8970117\" } }";
+        ITNeutronE2E.test_create(url, content, "RevisionID Singleton Post Failed");
+        return content;
+    }
+
+    public void singleton_get_with_one_query_item_test(String createJsonString) {
+        String url = base + "/fw/firewalls";
+        ITNeutronE2E.test_fetch_with_one_query_item(url, createJsonString, "firewalls");
+    }
+
+    public void modify_test() {
+        String url = base + "/fw/firewalls/4b0ef8f4-82c7-44d4-a4fb-6177f9a21977";
+        String content = " { \"firewall\": { \"admin_state_up\": false," + "\"description\": \"\","
+                + "\"firewall_policy_id\": \"c69933c1-b472-44f9-8226-30dc4ffd454c\","
+                + "\"id\": \"4b0ef8f4-82c7-44d4-a4fb-6177f9a21977\","
+                + "\"name\": \"\","
+                + "\"project_id\": \"45977fa2dbd7482098dd68d0d8970117\" } }";
+        ITNeutronE2E.test_modify(url, content, "RevisionID Singleton Post Failed");
+    }
+
+    public void element_get_test() {
+        String url = base + "/fw/firewalls/4b0ef8f4-82c7-44d4-a4fb-6177f9a21977";
+        ITNeutronE2E.test_fetch(url, true, "RevisionID Element Get Failed");
+    }
+
+    public void delete_test() {
+        String url = base + "/fw/firewalls/4b0ef8f4-82c7-44d4-a4fb-6177f9a21977";
+        ITNeutronE2E.test_delete(url, "RevisionID Delete Failed");
+    }
+
+    public String singleton_create_test_with_tenant_id() {
+        String url = base + "/fw/firewalls";
+        String content = " { \"firewall\": { \"admin_state_up\": true," + "\"description\": \"\","
+                + "\"firewall_policy_id\": \"c69933c1-b472-44f9-8226-30dc4ffd454c\","
+                + "\"id\": \"5b0ef8f4-82c7-44d4-a4fb-6177f9a21977\","
+                + "\"name\": \"\","
+                + "\"tenant_id\": \"55988fb3dbd7482098dd68d0d8970228\","
+                + "\"project_id\": \"45977fa2dbd7482098dd68d0d8970117\" } }";
+        ITNeutronE2E.test_create(url, content, "RevisionID Singleton Post Failed");
+        return content;
+    }
+
+    public void delete_test_with_tenant_id() {
+        String url = base + "/fw/firewalls/5b0ef8f4-82c7-44d4-a4fb-6177f9a21977";
+        ITNeutronE2E.test_delete(url, "RevisionID Delete Failed");
+    }
+
+    public static void runTests(String base) {
+        NeutronProjectIdTests tester = new NeutronProjectIdTests(base);
+        String createJsonString = tester.singleton_create_test();
+        tester.singleton_get_with_one_query_item_test(createJsonString);
+        tester.element_get_test();
+        tester.collection_get_test();
+        tester.modify_test();
+        tester.delete_test();
+        tester.singleton_create_test_with_tenant_id();
+        tester.delete_test_with_tenant_id();
+    }
+}
diff --git a/integration/test/src/test/java/org/opendaylight/neutron/e2etest/NeutronRevisionNumberTests.java b/integration/test/src/test/java/org/opendaylight/neutron/e2etest/NeutronRevisionNumberTests.java
new file mode 100644 (file)
index 0000000..e4b40fc
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2017 Intel, Corp.
+ *
+ * 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 NeutronRevisionNumberTests {
+
+    String base;
+
+    public NeutronRevisionNumberTests(String base) {
+        this.base = base;
+    }
+
+    public void subnet_create_test() {
+        String url = base + "/subnets";
+        String content = " { \"subnets\": [ " + " { \"allocation_pools\": [ "
+                + " { \"end\": \"192.168.199.254\", \"start\": \"192.168.199.2\" } ], "
+                + " \"cidr\": \"192.168.199.0/24\", " + " \"dns_nameservers\": [\"8.8.8.8\"], "
+                + " \"enable_dhcp\": true, " + " \"gateway_ip\": \"192.168.199.1\", "
+                + " \"host_routes\":[ { \"destination\":\"0.0.0.0/0\", " + " \"nexthop\":\"192.168.199.3\" }, "
+                + " { \"destination\":\"192.168.0.0/24\", " + " \"nexthop\":\"192.168.199.4\" } ], "
+                + " \"id\": \"1468a7a7-290d-4127-aedd-6c9449775a24\", " + " \"ip_version\": 4, " + " \"name\": \"\", "
+                + " \"network_id\": \"af374017-c9ae-4a1d-b799-ab73111476e2\", "
+                + " \"tenant_id\": \"4fd44f30292945e481c7b8a0c8908869\" }, { "
+                + " \"allocation_pools\": [ { \"end\": \"10.56.7.254\", \"start\": \"10.56.4.2\" } ], "
+                + " \"cidr\": \"10.56.4.0/22\", " + " \"dns_nameservers\": [\"8.8.8.8\", \"8.8.8.4\"], "
+                + " \"enable_dhcp\": true, " + " \"gateway_ip\": \"10.56.4.1\", "
+                + " \"host_routes\":[ { \"destination\":\"0.0.0.0/0\", " + " \"nexthop\":\"10.56.4.3\" }, "
+                + " { \"destination\":\"192.168.0.0/24\", " + " \"nexthop\":\"10.56.4.4\" } ], "
+                + " \"id\": \"c0e7435c-1512-45fb-aa9e-9a7c5932fb30\", " + " \"ip_version\": 4, " + " \"name\": \"\", "
+                + " \"network_id\": \"af374017-c9ae-4a1d-b799-ab73111476e2\", "
+                + " \"tenant_id\": \"4fd44f30292945e481c7b8a0c8908869\" } ] }";
+        ITNeutronE2E.test_create(url, content, "Revision Number Post Failed");
+    }
+
+    public void subnet_update_test() {
+        String url = base + "/subnets/c0e7435c-1512-45fb-aa9e-9a7c5932fb30";
+        String content = " { \"subnet\": { " + " \"name\": \"my_subnet\", " + " \"enable_dhcp\": true, "
+                + " \"network_id\": \"af374017-c9ae-4a1d-b799-ab73111476e2\", "
+                + " \"tenant_id\": \"4fd44f30292945e481c7b8a0c8908869\", "
+                + " \"dns_nameservers\": [\"8.8.8.8\", \"8.8.8.4\"], "
+                + " \"allocation_pools\": [ { \"start\": \"10.0.0.2\", \"end\": \"10.0.0.254\" } ], "
+                + " \"host_routes\": [{ \"destination\":\"192.168.0.0/24\", " + " \"nexthop\":\"10.0.0.11\" } ], "
+                + " \"ip_version\": 4, " + " \"gateway_ip\": \"10.0.0.1\", " + " \"cidr\": \"10.0.0.0/24\", "
+                + "\"revision_number\": 3, "
+                + " \"id\": \"c0e7435c-1512-45fb-aa9e-9a7c5932fb30\" } }";
+        ITNeutronE2E.test_modify(url, content, "Revision Number Put Failed");
+    }
+
+    public void subnet_update_test_with_old_value() {
+        String url = base + "/subnets/c0e7435c-1512-45fb-aa9e-9a7c5932fb30";
+        String content = " { \"subnet\": { " + " \"name\": \"my_subnet\", " + " \"enable_dhcp\": true, "
+                + " \"network_id\": \"af374017-c9ae-4a1d-b799-ab73111476e2\", "
+                + " \"tenant_id\": \"4fd44f30292945e481c7b8a0c8908869\", "
+                + " \"dns_nameservers\": [\"8.8.8.8\", \"8.8.8.4\"], "
+                + " \"allocation_pools\": [ { \"start\": \"10.0.0.2\", \"end\": \"10.0.0.254\" } ], "
+                + " \"host_routes\": [{ \"destination\":\"192.168.0.0/24\", " + " \"nexthop\":\"10.0.0.11\" } ], "
+                + " \"ip_version\": 4, " + " \"gateway_ip\": \"10.0.0.1\", " + " \"cidr\": \"10.0.0.0/24\", "
+                + "\"revision_number\": 2, "
+                + " \"id\": \"c0e7435c-1512-45fb-aa9e-9a7c5932fb30\" } }";
+        ITNeutronE2E.test_modify(url, content, "Revision Number Put Failed");
+    }
+
+    public void subnet_update_test_with_no_value() {
+        String url = base + "/subnets/c0e7435c-1512-45fb-aa9e-9a7c5932fb30";
+        String content = " { \"subnet\": { " + " \"name\": \"my_subnet\", " + " \"enable_dhcp\": true, "
+                + " \"network_id\": \"af374017-c9ae-4a1d-b799-ab73111476e2\", "
+                + " \"tenant_id\": \"4fd44f30292945e481c7b8a0c8908869\", "
+                + " \"dns_nameservers\": [\"8.8.8.8\", \"8.8.8.4\"], "
+                + " \"allocation_pools\": [ { \"start\": \"10.0.0.2\", \"end\": \"10.0.0.254\" } ], "
+                + " \"host_routes\": [{ \"destination\":\"192.168.0.0/24\", " + " \"nexthop\":\"10.0.0.11\" } ], "
+                + " \"ip_version\": 4, " + " \"gateway_ip\": \"10.0.0.1\", " + " \"cidr\": \"10.0.0.0/24\", "
+                + " \"id\": \"c0e7435c-1512-45fb-aa9e-9a7c5932fb30\" } }";
+        ITNeutronE2E.test_modify(url, content, "Revision Number Put Failed");
+    }
+
+    public void subnet_element_get_test() {
+        String url = base + "/subnets/c0e7435c-1512-45fb-aa9e-9a7c5932fb30";
+        ITNeutronE2E.test_fetch(url, true, "Revision Number Element Get Failed");
+    }
+
+    public void subnet_delete_test() {
+        String url = base + "/subnets/c0e7435c-1512-45fb-aa9e-9a7c5932fb30";
+        ITNeutronE2E.test_delete(url, "Revision Number Element Delete Failed");
+    }
+
+    public static void runTests(String base) {
+        NeutronRevisionNumberTests tester = new NeutronRevisionNumberTests(base);
+        tester.subnet_create_test();
+        tester.subnet_element_get_test();
+        tester.subnet_update_test();
+        tester.subnet_update_test_with_old_value();
+        tester.subnet_update_test_with_no_value();
+        tester.subnet_delete_test();
+    }
+}
index 1d1f41c8318b0c26b44af6a7a3b1d0b8cd1daa35..a2d2bf669a631dab26309b38cd93dd3a2b706f7d 100644 (file)
@@ -40,9 +40,24 @@ module neutron-attrs {
         }
 
         leaf tenant-id {
+            status deprecated;
             type yang:uuid;
             description "The UUID of the tenant that will own the object.";
         }
+
+        leaf project-id {
+            type string {
+                length "0..255";
+            }
+            description "The id of the project.";
+        }
+
+        leaf revision-number {
+            type int64;
+            description "The revision number of the resource. Used as monotonic
+                         counter that is updated whenever an object is updated
+                         on neutron server";
+        }
     }
 
     grouping admin-attributes {
index ad2913c73b38657a0232d6972f02ecc31a4aa6e3..9d9bbcf5786d73ed286fce2086d7bf02b935a085 100644 (file)
@@ -27,6 +27,14 @@ public interface INeutronObject<T extends INeutronObject> {
 
     void setTenantID(Uuid tenantID);
 
+    String getProjectID();
+
+    void setProjectID(String projectID);
+
+    Long getRevisionNumber();
+
+    void setRevisionNumber(Long revisionNumber);
+
     void initDefaults();
 
     T extractFields(List<String> fields);
index f6858669e71649645daaa1a4de1622bb4d1cf892..61e9b030b1a19683606afb41c84032b98ff01663 100644 (file)
@@ -27,6 +27,12 @@ public abstract class NeutronObject<T extends NeutronObject> extends NeutronID
     @XmlElement(name = "tenant_id")
     String tenantID;
 
+    @XmlElement(name = "project_id")
+    String projectID;
+
+    @XmlElement(name = "revision_number")
+    Long revisionNumber;
+
     public NeutronObject() {
         super();
     }
@@ -57,8 +63,34 @@ public abstract class NeutronObject<T extends NeutronObject> extends NeutronID
         return "NeutronObject [id=" + uuid + ", tenantID=" + tenantID + "]";
     }
 
+    @Override
+    public void setProjectID(String projectID) {
+        this.projectID = projectID;
+    }
+
+    @Override
+    public String getProjectID() {
+        return this.projectID;
+    }
+
+    @Override
+    public Long getRevisionNumber() {
+        return revisionNumber;
+    }
+
+    @Override
+    public void setRevisionNumber(Long revisionNumber) {
+        this.revisionNumber = revisionNumber;
+    }
+
     @Override
     public void initDefaults() {
+        if (projectID != null && tenantID == null) {
+            tenantID = projectID;
+        }
+        if (projectID == null && tenantID != null) {
+            projectID = tenantID;
+        }
     }
 
     @Override
@@ -71,5 +103,11 @@ public abstract class NeutronObject<T extends NeutronObject> extends NeutronID
         if (field.equals("tenant_id")) {
             ans.setTenantID(this.getTenantID());
         }
+        if (field.equals("project_id")) {
+            ans.setProjectID(this.getProjectID());
+        }
+        if (field.equals("revision_number")) {
+            ans.setRevisionNumber(this.getRevisionNumber());
+        }
     }
 }
index cad9f32bff528145225684678e54d441346c59f3..76c7967014ef83376c7ea74894bed3ab10167405 100644 (file)
@@ -121,6 +121,21 @@ public abstract class AbstractNeutronNorthbound<T extends INeutronObject<T>, R e
     protected void updateDelta(String uuid, T delta, T original) {
     }
 
+    private boolean checkRevisionNumber(T original, T delta) {
+        // If new update is null ignore the original revision number
+        if (delta.getRevisionNumber() == null) {
+            return false;
+        }
+        // If what is stored is null no need for comparison
+        if (original.getRevisionNumber() == null) {
+            return false;
+        }
+        if (original.getRevisionNumber() > delta.getRevisionNumber()) {
+            return true;
+        }
+        return false;
+    }
+
     protected Response update(String uuid, final R input) {
         I neutronCRUD = getNeutronCRUD();
         if (!input.isSingleton()) {
@@ -131,8 +146,10 @@ public abstract class AbstractNeutronNorthbound<T extends INeutronObject<T>, R e
         if (original == null) {
             throw new ResourceNotFoundException(uuidNoExist());
         }
+        if (checkRevisionNumber(original, delta)) {
+            return Response.status(HttpURLConnection.HTTP_OK).build();
+        }
         updateDelta(uuid, delta, original);
-
         /*
          * update the object and return it
          */
index 0244a16e5a79e8be462ba0e1af3bb0decf6cd35f..58e7456d9025441c8b14662b7bbb5f652626d964 100644 (file)
@@ -78,9 +78,11 @@ public abstract class AbstractNeutronInterface<T extends DataObject & Identifiab
     private final Class<? extends Builder<T>> builderClass;
     private final Method setUuid;
     private final Method setTenantId;
+    private final Method setProjectId;
     private final Method setName;
     private final Method setAdminStateUp;
     private final Method setStatus;
+    private final Method setRevisionNumber;
 
     AbstractNeutronInterface(Class<? extends Builder<T>> builderClass, DataBroker db) {
         this.db = Preconditions.checkNotNull(db);
@@ -101,9 +103,14 @@ public abstract class AbstractNeutronInterface<T extends DataObject & Identifiab
             setTenantId = builderClass.getDeclaredMethod("setTenantId", Uuid.class);
             if (INeutronBaseAttributes.class.isAssignableFrom(neutronObjectClass)) {
                 setName = builderClass.getDeclaredMethod("setName", String.class);
+                setProjectId = builderClass.getDeclaredMethod("setProjectId", String.class);
+                setRevisionNumber = builderClass.getDeclaredMethod("setRevisionNumber", Long.class);
             } else {
                 setName = null;
+                setProjectId = null;
+                setRevisionNumber = null;
             }
+
             if (INeutronAdminAttributes.class.isAssignableFrom(neutronObjectClass)) {
                 setAdminStateUp = builderClass.getDeclaredMethod("setAdminStateUp", Boolean.class);
                 setStatus = builderClass.getDeclaredMethod("setStatus", String.class);
@@ -140,6 +147,9 @@ public abstract class AbstractNeutronInterface<T extends DataObject & Identifiab
             if (neutronObject.getTenantID() != null && !neutronObject.getTenantID().isEmpty()) {
                 setTenantId.invoke(builder, toUuid(neutronObject.getTenantID()));
             }
+            if (neutronObject.getProjectID() != null) {
+                setProjectId.invoke(builder, neutronObject.getTenantID());
+            }
         } catch (IllegalAccessException | InvocationTargetException e) {
             throw new IllegalArgumentException(e);
         }
@@ -153,6 +163,9 @@ public abstract class AbstractNeutronInterface<T extends DataObject & Identifiab
         if (baseAttributes.getTenantId() != null) {
             answer.setTenantID(baseAttributes.getTenantId());
         }
+        if (baseAttributes.getProjectId() != null) {
+            answer.setProjectID(baseAttributes.getProjectId());
+        }
     }
 
     protected <S1 extends INeutronBaseAttributes<S1>, M extends BaseAttributes, B extends Builder<M>>
@@ -162,6 +175,9 @@ public abstract class AbstractNeutronInterface<T extends DataObject & Identifiab
             if (neutronObject.getName() != null) {
                 setName.invoke(builder, neutronObject.getName());
             }
+            if (neutronObject.getRevisionNumber() != null) {
+                setRevisionNumber.invoke(builder, neutronObject.getRevisionNumber());
+            }
         } catch (IllegalAccessException | InvocationTargetException e) {
             throw new IllegalArgumentException(e);
         }
@@ -173,6 +189,9 @@ public abstract class AbstractNeutronInterface<T extends DataObject & Identifiab
         if (baseAttributes.getName() != null) {
             answer.setName(baseAttributes.getName());
         }
+        if (baseAttributes.getRevisionNumber() != null) {
+            answer.setRevisionNumber(baseAttributes.getRevisionNumber());
+        }
     }
 
     protected <S1 extends INeutronAdminAttributes<S1>, M extends BaseAttributes & AdminAttributes, B extends Builder<M>>