You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by za...@apache.org on 2014/07/25 23:20:04 UTC

[1/5] Neutron Refactoring v2_0 -> v2 No options (redesign) More features (extension-related) Live tests Redesigned domain objects for create/update options.

Repository: jclouds-labs-openstack
Updated Branches:
  refs/heads/master 1f4a3c0f5 -> 9c4bd9448


http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/util/PredicateUtil.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/util/PredicateUtil.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/util/PredicateUtil.java
new file mode 100644
index 0000000..a3c39ce
--- /dev/null
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/util/PredicateUtil.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.neutron.v2.util;
+
+import com.google.common.base.Predicate;
+import org.jclouds.javax.annotation.Nullable;
+
+import java.lang.reflect.Field;
+
+public class PredicateUtil {
+
+    public static <T> Predicate<T> createIdEqualsPredicate(final String id) {
+        return new Predicate<T>() {
+            @Override
+            public boolean apply(@Nullable T input) {
+                if (input == null) return false;
+
+                try {
+                    Class clazz = input.getClass();
+                    Field field = ClassUtil.findField(clazz, "id");
+                    field.setAccessible(true);
+                    String value = (String) field.get(input);
+                    field.setAccessible(false);
+                    return value != null && value.equals(id);
+                } catch (IllegalAccessException iae) {
+                    return false;
+                }
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2_0/internal/BaseNeutronApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2_0/internal/BaseNeutronApiLiveTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2_0/internal/BaseNeutronApiLiveTest.java
index 9c57b82..de5755e 100644
--- a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2_0/internal/BaseNeutronApiLiveTest.java
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2_0/internal/BaseNeutronApiLiveTest.java
@@ -31,7 +31,7 @@ import java.util.Properties;
 public class BaseNeutronApiLiveTest extends BaseApiLiveTest<NeutronApi> {
 
    public BaseNeutronApiLiveTest() {
-      provider = "openstack-neutron";
+      provider = "openstack-neutron-legacy";
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2_0/internal/BaseNeutronExpectTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2_0/internal/BaseNeutronExpectTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2_0/internal/BaseNeutronExpectTest.java
index 3849abd..d8c024c 100644
--- a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2_0/internal/BaseNeutronExpectTest.java
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2_0/internal/BaseNeutronExpectTest.java
@@ -38,7 +38,7 @@ public class BaseNeutronExpectTest<T> extends BaseRestApiExpectTest<T> {
    protected String endpoint = "https://csnode.jclouds.org:9696/v2.0";
 
    public BaseNeutronExpectTest() {
-      provider = "openstack-neutron";
+      provider = "openstack-neutron-legacy";
       keystoneAuthWithUsernameAndPassword = KeystoneFixture.INSTANCE.initialAuthWithUsernameAndPassword(identity,
               credential);
       keystoneAuthWithUsernameAndPasswordAndTenantName = KeystoneFixture.INSTANCE.initialAuthWithUsernameAndPasswordAndTenantName(identity,

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/access.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/access.json b/openstack-neutron/src/test/resources/access.json
new file mode 100644
index 0000000..fab1645
--- /dev/null
+++ b/openstack-neutron/src/test/resources/access.json
@@ -0,0 +1,228 @@
+{
+    "access": {
+        "metadata": {
+            "roles": [
+                "9fe2ff9ee4384b1894a90878d3e92bab",
+                "b926cb0f4e2642678735f86c2b06205e",
+                "33484487e73d4da0918a19b9c7e1f8ae",
+                "f2e54c2105fb49e29479af047115cebc"
+            ],
+            "is_admin": 0
+        },
+        "user": {
+            "name": "joe",
+            "roles": [
+                {
+                    "name": "_member_"
+                },
+                {
+                    "name": "anotherrole"
+                },
+                {
+                    "name": "heat_stack_owner"
+                },
+                {
+                    "name": "Member"
+                }
+            ],
+            "id": "8fbf8e68d36e4ac7bcf912a26213bd49",
+            "roles_links": [],
+            "username": "joe"
+        },
+        "serviceCatalog": [
+            {
+                "name": "nova",
+                "type": "compute",
+                "endpoints_links": [],
+                "endpoints": [
+                    {
+                        "publicURL": "URL/v2/da0d12be20394afb851716e10a49e4a7",
+                        "id": "2122bcaa704343c19ad2578410d4961d",
+                        "internalURL": "URL/v2/da0d12be20394afb851716e10a49e4a7",
+                        "region": "RegionOne",
+                        "adminURL": "URL/v2/da0d12be20394afb851716e10a49e4a7"
+                    }
+                ]
+            },
+            {
+                "name": "neutron",
+                "type": "network",
+                "endpoints_links": [],
+                "endpoints": [
+                    {
+                        "publicURL": "URL/",
+                        "id": "65a4d3f13cfb49a6a57a04e205cc2158",
+                        "internalURL": "URL/",
+                        "region": "RegionOne",
+                        "adminURL": "URL/"
+                    }
+                ]
+            },
+            {
+                "name": "cinderv2",
+                "type": "volumev2",
+                "endpoints_links": [],
+                "endpoints": [
+                    {
+                        "publicURL": "URL/v2/da0d12be20394afb851716e10a49e4a7",
+                        "id": "31fe4d92eac44044b05be21c6f44cebc",
+                        "internalURL": "URL/v2/da0d12be20394afb851716e10a49e4a7",
+                        "region": "RegionOne",
+                        "adminURL": "URL/v2/da0d12be20394afb851716e10a49e4a7"
+                    }
+                ]
+            },
+            {
+                "name": "trove",
+                "type": "database",
+                "endpoints_links": [],
+                "endpoints": [
+                    {
+                        "publicURL": "URL/v1.0/da0d12be20394afb851716e10a49e4a7",
+                        "id": "06b7a7dbd25c4a01819c879700a9712a",
+                        "internalURL": "URL/v1.0/da0d12be20394afb851716e10a49e4a7",
+                        "region": "RegionOne",
+                        "adminURL": "URL/v1.0/da0d12be20394afb851716e10a49e4a7"
+                    }
+                ]
+            },
+            {
+                "name": "s3",
+                "type": "s3",
+                "endpoints_links": [],
+                "endpoints": [
+                    {
+                        "publicURL": "URL",
+                        "id": "93b0b67091324e8ba01b62ee0584994c",
+                        "internalURL": "URL",
+                        "region": "RegionOne",
+                        "adminURL": "URL"
+                    }
+                ]
+            },
+            {
+                "name": "glance",
+                "type": "image",
+                "endpoints_links": [],
+                "endpoints": [
+                    {
+                        "publicURL": "URL",
+                        "id": "a542e91bcfa046bfa1bf2397356d1414",
+                        "internalURL": "URL",
+                        "region": "RegionOne",
+                        "adminURL": "URL"
+                    }
+                ]
+            },
+            {
+                "name": "novav3",
+                "type": "computev3",
+                "endpoints_links": [],
+                "endpoints": [
+                    {
+                        "publicURL": "URL/v3",
+                        "id": "9c3e8abb576d483db93bcef70c67bc1d",
+                        "internalURL": "URL/v3",
+                        "region": "RegionOne",
+                        "adminURL": "URL/v3"
+                    }
+                ]
+            },
+            {
+                "name": "heat",
+                "type": "cloudformation",
+                "endpoints_links": [],
+                "endpoints": [
+                    {
+                        "publicURL": "URL/v1",
+                        "id": "6f4ca5ca9698425b85c300b3fc176c39",
+                        "internalURL": "URL/v1",
+                        "region": "RegionOne",
+                        "adminURL": "URL/v1"
+                    }
+                ]
+            },
+            {
+                "name": "cinder",
+                "type": "volume",
+                "endpoints_links": [],
+                "endpoints": [
+                    {
+                        "publicURL": "URL/v1/da0d12be20394afb851716e10a49e4a7",
+                        "id": "037039c676694a35aa28d34fce09e51d",
+                        "internalURL": "URL/v1/da0d12be20394afb851716e10a49e4a7",
+                        "region": "RegionOne",
+                        "adminURL": "URL/v1/da0d12be20394afb851716e10a49e4a7"
+                    }
+                ]
+            },
+            {
+                "name": "ec2",
+                "type": "ec2",
+                "endpoints_links": [],
+                "endpoints": [
+                    {
+                        "publicURL": "URL/services/Cloud",
+                        "id": "1d242631bccb4ff4ba7a395dbcb51648",
+                        "internalURL": "URL/services/Cloud",
+                        "region": "RegionOne",
+                        "adminURL": "URL/services/Admin"
+                    }
+                ]
+            },
+            {
+                "name": "heat",
+                "type": "orchestration",
+                "endpoints_links": [],
+                "endpoints": [
+                    {
+                        "publicURL": "URL/v1/da0d12be20394afb851716e10a49e4a7",
+                        "id": "199d00075e4a40308a6ad2aa8980d0cd",
+                        "internalURL": "URL/v1/da0d12be20394afb851716e10a49e4a7",
+                        "region": "RegionOne",
+                        "adminURL": "URL/v1/da0d12be20394afb851716e10a49e4a7"
+                    }
+                ]
+            },
+            {
+                "name": "swift",
+                "type": "object-store",
+                "endpoints_links": [],
+                "endpoints": [
+                    {
+                        "publicURL": "URL/v1/AUTH_da0d12be20394afb851716e10a49e4a7",
+                        "id": "26b2cb1efb044193b847fc3f2fb12e82",
+                        "internalURL": "URL/v1/AUTH_da0d12be20394afb851716e10a49e4a7",
+                        "region": "RegionOne",
+                        "adminURL": "URL"
+                    }
+                ]
+            },
+            {
+                "name": "keystone",
+                "type": "identity",
+                "endpoints_links": [],
+                "endpoints": [
+                    {
+                        "publicURL": "URL/v2.0",
+                        "id": "1bbfe80b50df4c4a84040aa782e42140",
+                        "internalURL": "URL/v2.0",
+                        "region": "RegionOne",
+                        "adminURL": "URL/v2.0"
+                    }
+                ]
+            }
+        ],
+        "token": {
+            "tenant": {
+                "name": "jclouds",
+                "id": "da0d12be20394afb851716e10a49e4a7",
+                "enabled": true,
+                "description": null
+            },
+            "id": "TOKEN",
+            "expires": "2014-04-28T22:48:24Z",
+            "issued_at": "2014-04-28T21:48:24.972896"
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/list_networks.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/list_networks.json b/openstack-neutron/src/test/resources/list_networks.json
index 8fa99d4..17b9e9f 100644
--- a/openstack-neutron/src/test/resources/list_networks.json
+++ b/openstack-neutron/src/test/resources/list_networks.json
@@ -1,62 +1,62 @@
-{"networks":[
-   {
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"16dba3bc-f3fa-4775-afdc-237e12c72f6a"
-   },
-   {
-      "name":"wibble",
-      "tenant_id":"1234567890",
-      "id":"1a104cf5-cb18-4d35-9407-2fd2646d9d0b"
-   },
-   {
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"31083ae2-420d-48b2-ac98-9f7a4fd8dbdc"
-   },
-   {
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"49c6d6fa-ff2a-459d-b975-75a8d31c9a89"
-   },
-   {
-      "name":"wibble",
-      "tenant_id":"1234567890",
-      "id":"5cb3d6f4-62cb-41c9-b964-ba7d9df79e4e"
-   },
-   {
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"5d51d012-3491-4db7-b1b5-6f254015015d"
-   },
-   {
-      "name":"wibble",
-      "tenant_id":"1234567890",
-      "id":"5f9cf7dc-22ca-4097-8e49-1cc8b23faf17"
-   },
-   {
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"6319ecad-6bff-48b2-9b53-02ede8cb7588"
-   },
-   {
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"6ba4c788-661f-49ab-9bf8-5f10cbbb2f57"
-   },
-   {
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"74ed170b-5069-4353-ab38-9719766dc57e"
-   },
-   {
-      "name":"wibble",
-      "tenant_id":"1234567890",
-      "id":"b71fcac1-e864-4031-8c5b-edbecd9ece36"
-   },
-   {
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"c7681895-d84d-4650-9ca0-82c72036b855"
-   }
-]}
\ No newline at end of file
+{"networks": [
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "16dba3bc-f3fa-4775-afdc-237e12c72f6a"
+    },
+    {
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "1a104cf5-cb18-4d35-9407-2fd2646d9d0b"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "31083ae2-420d-48b2-ac98-9f7a4fd8dbdc"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "49c6d6fa-ff2a-459d-b975-75a8d31c9a89"
+    },
+    {
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5cb3d6f4-62cb-41c9-b964-ba7d9df79e4e"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "5d51d012-3491-4db7-b1b5-6f254015015d"
+    },
+    {
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5f9cf7dc-22ca-4097-8e49-1cc8b23faf17"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6319ecad-6bff-48b2-9b53-02ede8cb7588"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6ba4c788-661f-49ab-9bf8-5f10cbbb2f57"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "74ed170b-5069-4353-ab38-9719766dc57e"
+    },
+    {
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "b71fcac1-e864-4031-8c5b-edbecd9ece36"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "c7681895-d84d-4650-9ca0-82c72036b855"
+    }
+]}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/list_ports.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/list_ports.json b/openstack-neutron/src/test/resources/list_ports.json
index 392ef89..29c3a2b 100644
--- a/openstack-neutron/src/test/resources/list_ports.json
+++ b/openstack-neutron/src/test/resources/list_ports.json
@@ -1,86 +1,86 @@
-{"ports":[
-   {
-      "status":"ACTIVE",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"16dba3bc-f3fa-4775-afdc-237e12c72f6a"
-   },
-   {
-      "status":"ACTIVE",
-      "network_id":"1234567890",
-      "name":"wibble",
-      "tenant_id":"1234567890",
-      "id":"1a104cf5-cb18-4d35-9407-2fd2646d9d0b"
-   },
-   {
-      "status":"ACTIVE",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"31083ae2-420d-48b2-ac98-9f7a4fd8dbdc"
-   },
-   {
-      "status":"ACTIVE",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"49c6d6fa-ff2a-459d-b975-75a8d31c9a89"
-   },
-   {
-      "status":"ACTIVE",
-      "network_id":"1234567890",
-      "name":"wibble",
-      "tenant_id":"1234567890",
-      "id":"5cb3d6f4-62cb-41c9-b964-ba7d9df79e4e"
-   },
-   {
-      "status":"ACTIVE",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"5d51d012-3491-4db7-b1b5-6f254015015d"
-   },
-   {
-      "status":"ACTIVE",
-      "network_id":"1234567890",
-      "name":"wibble",
-      "tenant_id":"1234567890",
-      "id":"5f9cf7dc-22ca-4097-8e49-1cc8b23faf17"
-   },
-   {
-      "status":"ACTIVE",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"6319ecad-6bff-48b2-9b53-02ede8cb7588"
-   },
-   {
-      "status":"ACTIVE",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"6ba4c788-661f-49ab-9bf8-5f10cbbb2f57"
-   },
-   {
-      "status":"ACTIVE",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"74ed170b-5069-4353-ab38-9719766dc57e"
-   },
-   {
-      "status":"ACTIVE",
-      "network_id":"1234567890",
-      "name":"wibble",
-      "tenant_id":"1234567890",
-      "id":"b71fcac1-e864-4031-8c5b-edbecd9ece36"
-   },
-   {
-      "status":"ACTIVE",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"c7681895-d84d-4650-9ca0-82c72036b855"
-   }
-]}
\ No newline at end of file
+{"ports": [
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "16dba3bc-f3fa-4775-afdc-237e12c72f6a"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "1a104cf5-cb18-4d35-9407-2fd2646d9d0b"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "31083ae2-420d-48b2-ac98-9f7a4fd8dbdc"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "49c6d6fa-ff2a-459d-b975-75a8d31c9a89"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5cb3d6f4-62cb-41c9-b964-ba7d9df79e4e"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "5d51d012-3491-4db7-b1b5-6f254015015d"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5f9cf7dc-22ca-4097-8e49-1cc8b23faf17"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6319ecad-6bff-48b2-9b53-02ede8cb7588"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6ba4c788-661f-49ab-9bf8-5f10cbbb2f57"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "74ed170b-5069-4353-ab38-9719766dc57e"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "b71fcac1-e864-4031-8c5b-edbecd9ece36"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "c7681895-d84d-4650-9ca0-82c72036b855"
+    }
+]}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/list_routers.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/list_routers.json b/openstack-neutron/src/test/resources/list_routers.json
index 0e5b95d..14dcfae 100644
--- a/openstack-neutron/src/test/resources/list_routers.json
+++ b/openstack-neutron/src/test/resources/list_routers.json
@@ -1,74 +1,74 @@
-{"routers":[
+{"routers": [
     {
-        "status":"ACTIVE",
-        "name":"jclouds-test",
-        "tenant_id":"1234567890",
-        "id":"16dba3bc-f3fa-4775-afdc-237e12c72f6a"
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "16dba3bc-f3fa-4775-afdc-237e12c72f6a"
     },
     {
-        "status":"ACTIVE",
-        "name":"wibble",
-        "tenant_id":"1234567890",
-        "id":"1a104cf5-cb18-4d35-9407-2fd2646d9d0b"
+        "status": "ACTIVE",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "1a104cf5-cb18-4d35-9407-2fd2646d9d0b"
     },
     {
-        "status":"ACTIVE",
-        "name":"jclouds-test",
-        "tenant_id":"1234567890",
-        "id":"31083ae2-420d-48b2-ac98-9f7a4fd8dbdc"
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "31083ae2-420d-48b2-ac98-9f7a4fd8dbdc"
     },
     {
-        "status":"ACTIVE",
-        "name":"jclouds-test",
-        "tenant_id":"1234567890",
-        "id":"49c6d6fa-ff2a-459d-b975-75a8d31c9a89"
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "49c6d6fa-ff2a-459d-b975-75a8d31c9a89"
     },
     {
-        "status":"ACTIVE",
-        "name":"wibble",
-        "tenant_id":"1234567890",
-        "id":"5cb3d6f4-62cb-41c9-b964-ba7d9df79e4e"
+        "status": "ACTIVE",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5cb3d6f4-62cb-41c9-b964-ba7d9df79e4e"
     },
     {
-        "status":"ACTIVE",
-        "name":"jclouds-test",
-        "tenant_id":"1234567890",
-        "id":"5d51d012-3491-4db7-b1b5-6f254015015d"
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "5d51d012-3491-4db7-b1b5-6f254015015d"
     },
     {
-        "status":"ACTIVE",
-        "name":"wibble",
-        "tenant_id":"1234567890",
-        "id":"5f9cf7dc-22ca-4097-8e49-1cc8b23faf17"
+        "status": "ACTIVE",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5f9cf7dc-22ca-4097-8e49-1cc8b23faf17"
     },
     {
-        "status":"ACTIVE",
-        "name":"jclouds-test",
-        "tenant_id":"1234567890",
-        "id":"6319ecad-6bff-48b2-9b53-02ede8cb7588"
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6319ecad-6bff-48b2-9b53-02ede8cb7588"
     },
     {
-        "status":"ACTIVE",
-        "name":"jclouds-test",
-        "tenant_id":"1234567890",
-        "id":"6ba4c788-661f-49ab-9bf8-5f10cbbb2f57"
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6ba4c788-661f-49ab-9bf8-5f10cbbb2f57"
     },
     {
-        "status":"ACTIVE",
-        "name":"jclouds-test",
-        "tenant_id":"1234567890",
-        "id":"74ed170b-5069-4353-ab38-9719766dc57e"
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "74ed170b-5069-4353-ab38-9719766dc57e"
     },
     {
-        "status":"ACTIVE",
-        "name":"wibble",
-        "tenant_id":"1234567890",
-        "id":"b71fcac1-e864-4031-8c5b-edbecd9ece36"
+        "status": "ACTIVE",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "b71fcac1-e864-4031-8c5b-edbecd9ece36"
     },
     {
-        "status":"ACTIVE",
-        "name":"jclouds-test",
-        "tenant_id":"1234567890",
-        "id":"c7681895-d84d-4650-9ca0-82c72036b855"
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "c7681895-d84d-4650-9ca0-82c72036b855"
     }
-]}
\ No newline at end of file
+]}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/list_subnets.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/list_subnets.json b/openstack-neutron/src/test/resources/list_subnets.json
index dc59bd5..b0061e9 100644
--- a/openstack-neutron/src/test/resources/list_subnets.json
+++ b/openstack-neutron/src/test/resources/list_subnets.json
@@ -1,98 +1,98 @@
-{"subnets":[
-   {
-      "ip_version":4,
-      "cidr":"10.0.3.0/24",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"16dba3bc-f3fa-4775-afdc-237e12c72f6a"
-   },
-   {
-      "ip_version":4,
-      "cidr":"10.0.3.0/24",
-      "network_id":"1234567890",
-      "name":"wibble",
-      "tenant_id":"1234567890",
-      "id":"1a104cf5-cb18-4d35-9407-2fd2646d9d0b"
-   },
-   {
-      "ip_version":4,
-      "cidr":"10.0.3.0/24",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"31083ae2-420d-48b2-ac98-9f7a4fd8dbdc"
-   },
-   {
-      "ip_version":4,
-      "cidr":"10.0.3.0/24",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"49c6d6fa-ff2a-459d-b975-75a8d31c9a89"
-   },
-   {
-      "ip_version":4,
-      "cidr":"10.0.3.0/24",
-      "network_id":"1234567890",
-      "name":"wibble",
-      "tenant_id":"1234567890",
-      "id":"5cb3d6f4-62cb-41c9-b964-ba7d9df79e4e"
-   },
-   {
-      "ip_version":4,
-      "cidr":"10.0.3.0/24",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"5d51d012-3491-4db7-b1b5-6f254015015d"
-   },
-   {
-      "ip_version":4,
-      "cidr":"10.0.3.0/24",
-      "network_id":"1234567890",
-      "name":"wibble",
-      "tenant_id":"1234567890",
-      "id":"5f9cf7dc-22ca-4097-8e49-1cc8b23faf17"
-   },
-   {
-      "ip_version":4,
-      "cidr":"10.0.3.0/24",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"6319ecad-6bff-48b2-9b53-02ede8cb7588"
-   },
-   {
-      "ip_version":4,
-      "cidr":"10.0.3.0/24",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"6ba4c788-661f-49ab-9bf8-5f10cbbb2f57"
-   },
-   {
-      "ip_version":4,
-      "cidr":"10.0.3.0/24",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"74ed170b-5069-4353-ab38-9719766dc57e"
-   },
-   {
-      "ip_version":4,
-      "cidr":"10.0.3.0/24",
-      "network_id":"1234567890",
-      "name":"wibble",
-      "tenant_id":"1234567890",
-      "id":"b71fcac1-e864-4031-8c5b-edbecd9ece36"
-   },
-   {
-      "ip_version":4,
-      "cidr":"10.0.3.0/24",
-      "network_id":"1234567890",
-      "name":"jclouds-test",
-      "tenant_id":"1234567890",
-      "id":"c7681895-d84d-4650-9ca0-82c72036b855"
-   }
-]}
\ No newline at end of file
+{"subnets": [
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "16dba3bc-f3fa-4775-afdc-237e12c72f6a"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "1a104cf5-cb18-4d35-9407-2fd2646d9d0b"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "31083ae2-420d-48b2-ac98-9f7a4fd8dbdc"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "49c6d6fa-ff2a-459d-b975-75a8d31c9a89"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5cb3d6f4-62cb-41c9-b964-ba7d9df79e4e"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "5d51d012-3491-4db7-b1b5-6f254015015d"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5f9cf7dc-22ca-4097-8e49-1cc8b23faf17"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6319ecad-6bff-48b2-9b53-02ede8cb7588"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6ba4c788-661f-49ab-9bf8-5f10cbbb2f57"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "74ed170b-5069-4353-ab38-9719766dc57e"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "b71fcac1-e864-4031-8c5b-edbecd9ece36"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "c7681895-d84d-4650-9ca0-82c72036b855"
+    }
+]}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/network.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/network.json b/openstack-neutron/src/test/resources/network.json
index e2d5395..06d5d07 100644
--- a/openstack-neutron/src/test/resources/network.json
+++ b/openstack-neutron/src/test/resources/network.json
@@ -1,7 +1,7 @@
-{"network":{
-   "provider:network_type":"local",
-   "status":"ACTIVE",
-   "name":"jclouds-wibble",
-   "tenant_id":"1234567890",
-   "id":"624312ff-d14b-4ba3-9834-1c78d23d574d"
-}}
\ No newline at end of file
+{"network": {
+    "provider:network_type": "local",
+    "status": "ACTIVE",
+    "name": "jclouds-wibble",
+    "tenant_id": "1234567890",
+    "id": "624312ff-d14b-4ba3-9834-1c78d23d574d"
+}}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/network_bulk_create_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/network_bulk_create_request.json b/openstack-neutron/src/test/resources/network_bulk_create_request.json
new file mode 100644
index 0000000..e732dde
--- /dev/null
+++ b/openstack-neutron/src/test/resources/network_bulk_create_request.json
@@ -0,0 +1,12 @@
+{
+    "networks": [
+        {
+            "provider:network_type": "local",
+            "name": "jclouds-wibble"
+        },
+        {
+            "provider:network_type": "local",
+            "name": "jclouds-wibble2"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/network_bulk_create_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/network_bulk_create_response.json b/openstack-neutron/src/test/resources/network_bulk_create_response.json
new file mode 100644
index 0000000..ebde974
--- /dev/null
+++ b/openstack-neutron/src/test/resources/network_bulk_create_response.json
@@ -0,0 +1,18 @@
+{
+    "networks": [
+        {
+            "provider:network_type": "local",
+            "status": "ACTIVE",
+            "name": "jclouds-wibble",
+            "tenant_id": "1234567890",
+            "id": "624312ff-d14b-4ba3-9834-1c78d23d574d"
+        },
+        {
+            "provider:network_type": "local",
+            "status": "ACTIVE",
+            "name": "jclouds-wibble2",
+            "tenant_id": "1234567890",
+            "id": "624312ff-d14b-4ba3-9834-1c78d23d574e"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/network_create_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/network_create_request.json b/openstack-neutron/src/test/resources/network_create_request.json
new file mode 100644
index 0000000..f6bcfad
--- /dev/null
+++ b/openstack-neutron/src/test/resources/network_create_request.json
@@ -0,0 +1,4 @@
+{"network": {
+    "provider:network_type": "local",
+    "name": "jclouds-wibble"
+}}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/network_create_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/network_create_response.json b/openstack-neutron/src/test/resources/network_create_response.json
new file mode 100644
index 0000000..06d5d07
--- /dev/null
+++ b/openstack-neutron/src/test/resources/network_create_response.json
@@ -0,0 +1,7 @@
+{"network": {
+    "provider:network_type": "local",
+    "status": "ACTIVE",
+    "name": "jclouds-wibble",
+    "tenant_id": "1234567890",
+    "id": "624312ff-d14b-4ba3-9834-1c78d23d574d"
+}}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/network_get_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/network_get_response.json b/openstack-neutron/src/test/resources/network_get_response.json
new file mode 100644
index 0000000..06d5d07
--- /dev/null
+++ b/openstack-neutron/src/test/resources/network_get_response.json
@@ -0,0 +1,7 @@
+{"network": {
+    "provider:network_type": "local",
+    "status": "ACTIVE",
+    "name": "jclouds-wibble",
+    "tenant_id": "1234567890",
+    "id": "624312ff-d14b-4ba3-9834-1c78d23d574d"
+}}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/network_list_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/network_list_response.json b/openstack-neutron/src/test/resources/network_list_response.json
new file mode 100644
index 0000000..17b9e9f
--- /dev/null
+++ b/openstack-neutron/src/test/resources/network_list_response.json
@@ -0,0 +1,62 @@
+{"networks": [
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "16dba3bc-f3fa-4775-afdc-237e12c72f6a"
+    },
+    {
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "1a104cf5-cb18-4d35-9407-2fd2646d9d0b"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "31083ae2-420d-48b2-ac98-9f7a4fd8dbdc"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "49c6d6fa-ff2a-459d-b975-75a8d31c9a89"
+    },
+    {
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5cb3d6f4-62cb-41c9-b964-ba7d9df79e4e"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "5d51d012-3491-4db7-b1b5-6f254015015d"
+    },
+    {
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5f9cf7dc-22ca-4097-8e49-1cc8b23faf17"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6319ecad-6bff-48b2-9b53-02ede8cb7588"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6ba4c788-661f-49ab-9bf8-5f10cbbb2f57"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "74ed170b-5069-4353-ab38-9719766dc57e"
+    },
+    {
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "b71fcac1-e864-4031-8c5b-edbecd9ece36"
+    },
+    {
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "c7681895-d84d-4650-9ca0-82c72036b855"
+    }
+]}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/network_list_response_paged1.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/network_list_response_paged1.json b/openstack-neutron/src/test/resources/network_list_response_paged1.json
new file mode 100644
index 0000000..9fe7e54
--- /dev/null
+++ b/openstack-neutron/src/test/resources/network_list_response_paged1.json
@@ -0,0 +1,40 @@
+{
+    "networks": [
+        {
+            "admin_state_up": true,
+            "id": "396f12f8-521e-4b91-8e21-2e003500433a",
+            "name": "net3",
+            "provider:network_type": "vlan",
+            "provider:physical_network": "physnet1",
+            "provider:segmentation_id": 1002,
+            "router:external": false,
+            "shared": false,
+            "status": "ACTIVE",
+            "subnets": [],
+            "tenant_id": "20bd52ff3e1b40039c312395b04683cf"
+        },
+        {
+            "admin_state_up": true,
+            "id": "71c1e68c-171a-4aa2-aca5-50ea153a3718",
+            "name": "net2",
+            "provider:network_type": "vlan",
+            "provider:physical_network": "physnet1",
+            "provider:segmentation_id": 1001,
+            "router:external": false,
+            "shared": false,
+            "status": "ACTIVE",
+            "subnets": [],
+            "tenant_id": "20bd52ff3e1b40039c312395b04683cf"
+        }
+    ],
+    "networks_links": [
+        {
+            "href": "/v2.0/networks.json?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718",
+            "rel": "next"
+        },
+        {
+            "href": "/v2.0/networks.json?marker=396f12f8-521e-4b91-8e21-2e003500433a&page_reverse=True",
+            "rel": "previous"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/network_list_response_paged2.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/network_list_response_paged2.json b/openstack-neutron/src/test/resources/network_list_response_paged2.json
new file mode 100644
index 0000000..b03714f
--- /dev/null
+++ b/openstack-neutron/src/test/resources/network_list_response_paged2.json
@@ -0,0 +1,36 @@
+{
+    "networks": [
+        {
+            "admin_state_up": true,
+            "id": "396f12f8-521e-4b91-8e21-2e003500433a_2",
+            "name": "net3",
+            "provider:network_type": "vlan",
+            "provider:physical_network": "physnet1",
+            "provider:segmentation_id": 1002,
+            "router:external": false,
+            "shared": false,
+            "status": "ACTIVE",
+            "subnets": [],
+            "tenant_id": "20bd52ff3e1b40039c312395b04683cf"
+        },
+        {
+            "admin_state_up": true,
+            "id": "71c1e68c-171a-4aa2-aca5-50ea153a3718_2",
+            "name": "net2",
+            "provider:network_type": "vlan",
+            "provider:physical_network": "physnet1",
+            "provider:segmentation_id": 1001,
+            "router:external": false,
+            "shared": false,
+            "status": "ACTIVE",
+            "subnets": [],
+            "tenant_id": "20bd52ff3e1b40039c312395b04683cf"
+        }
+    ],
+    "networks_links": [
+        {
+            "href": "/v2.0/networks.json?marker=396f12f8-521e-4b91-8e21-2e003500433a&page_reverse=True",
+            "rel": "previous"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/network_update_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/network_update_request.json b/openstack-neutron/src/test/resources/network_update_request.json
new file mode 100644
index 0000000..a9f0aee
--- /dev/null
+++ b/openstack-neutron/src/test/resources/network_update_request.json
@@ -0,0 +1,4 @@
+{"network": {
+    "provider:network_type": "local",
+    "name": "jclouds-wibble-updated"
+}}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/network_update_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/network_update_response.json b/openstack-neutron/src/test/resources/network_update_response.json
new file mode 100644
index 0000000..140b648
--- /dev/null
+++ b/openstack-neutron/src/test/resources/network_update_response.json
@@ -0,0 +1,11 @@
+{
+    "network": {
+        "status": "ACTIVE",
+        "subnets": [],
+        "name": "updated_name",
+        "admin_state_up": false,
+        "shared": false,
+        "tenant_id": "c1210485b2424d48804aad5d39c61b8f",
+        "id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766"
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/port.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/port.json b/openstack-neutron/src/test/resources/port.json
index 386303f..15629a6 100644
--- a/openstack-neutron/src/test/resources/port.json
+++ b/openstack-neutron/src/test/resources/port.json
@@ -1,7 +1,7 @@
-{"port":{
-   "status":"ACTIVE",
-   "network_id":"1234567890",
-   "name":"jclouds-wibble",
-   "tenant_id":"1234567890",
-   "id":"624312ff-d14b-4ba3-9834-1c78d23d574d"
-}}
\ No newline at end of file
+{"port": {
+    "status": "ACTIVE",
+    "network_id": "1234567890",
+    "name": "jclouds-wibble",
+    "tenant_id": "1234567890",
+    "id": "624312ff-d14b-4ba3-9834-1c78d23d574d"
+}}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/port_create_bulk_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/port_create_bulk_request.json b/openstack-neutron/src/test/resources/port_create_bulk_request.json
new file mode 100644
index 0000000..c0567c6
--- /dev/null
+++ b/openstack-neutron/src/test/resources/port_create_bulk_request.json
@@ -0,0 +1,22 @@
+{
+    "ports": [
+        {
+            "admin_state_up": true,
+            "device_id": "24df1d04-d5cb-41e1-8de5-61ed77c558df",
+            "name": "port1",
+            "network_id": "64239a54-dcc4-4b39-920b-b37c2144effa",
+            "security_groups": [
+                "dbc107f4-afcd-4d5a-9352-f68f82241d5b"
+            ]
+        },
+        {
+            "admin_state_up": false,
+            "name": "port2",
+            "network_id": "e6031bc2-901a-4c66-82da-f4c32ed89406",
+            "security_groups": [
+                "8bf3f7cc-8471-40b1-815f-9da47e79775b",
+                "dbc107f4-afcd-4d5a-9352-f68f82241d5b"
+            ]
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/port_create_bulk_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/port_create_bulk_response.json b/openstack-neutron/src/test/resources/port_create_bulk_response.json
new file mode 100644
index 0000000..3ecfb52
--- /dev/null
+++ b/openstack-neutron/src/test/resources/port_create_bulk_response.json
@@ -0,0 +1,47 @@
+{
+    "ports": [
+        {
+            "admin_state_up": true,
+            "allowed_address_pairs": [],
+            "device_id": "24df1d04-d5cb-41e1-8de5-61ed77c558df",
+            "device_owner": "",
+            "fixed_ips": [
+                {
+                    "ip_address": "10.56.4.2",
+                    "subnet_id": "b0e7435c-1512-45fb-aa9e-9a7c5932fb30"
+                }
+            ],
+            "id": "4fa2a5b2-d758-449d-80d6-dff31df9e91e",
+            "mac_address": "fa:16:3e:63:b0:82",
+            "name": "port1",
+            "network_id": "64239a54-dcc4-4b39-920b-b37c2144effa",
+            "security_groups": [
+                "dbc107f4-afcd-4d5a-9352-f68f82241d5b"
+            ],
+            "status": "DOWN",
+            "tenant_id": "d19231fc08ec4bc4829b668040d34512"
+        },
+        {
+            "admin_state_up": false,
+            "allowed_address_pairs": [],
+            "device_id": "",
+            "device_owner": "",
+            "fixed_ips": [
+                {
+                    "ip_address": "192.168.199.2",
+                    "subnet_id": "0468a7a7-290d-4127-aedd-6c9449775a24"
+                }
+            ],
+            "id": "d3c059b8-40fd-489a-8d17-97bde9370987",
+            "mac_address": "fa:16:3e:86:09:06",
+            "name": "port2",
+            "network_id": "e6031bc2-901a-4c66-82da-f4c32ed89406",
+            "security_groups": [
+                "8bf3f7cc-8471-40b1-815f-9da47e79775b",
+                "dbc107f4-afcd-4d5a-9352-f68f82241d5b"
+            ],
+            "status": "DOWN",
+            "tenant_id": "d19231fc08ec4bc4829b668040d34512"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/port_create_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/port_create_request.json b/openstack-neutron/src/test/resources/port_create_request.json
new file mode 100644
index 0000000..d9e8d33
--- /dev/null
+++ b/openstack-neutron/src/test/resources/port_create_request.json
@@ -0,0 +1,14 @@
+{
+    "port": {
+        "admin_state_up": true,
+        "device_id": "d6b4d3a5-c700-476f-b609-1493dd9dadc0",
+        "name": "port1",
+        "network_id": "6aeaf34a-c482-4bd3-9dc3-7faf36412f12",
+        "allowed_address_pairs": [
+            {
+                "ip_address": "111.222.333.444",
+                "mac_address": "12"
+            }
+        ]
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/port_create_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/port_create_response.json b/openstack-neutron/src/test/resources/port_create_response.json
new file mode 100644
index 0000000..696ac44
--- /dev/null
+++ b/openstack-neutron/src/test/resources/port_create_response.json
@@ -0,0 +1,29 @@
+{
+    "port": {
+        "admin_state_up": true,
+        "device_id": "d6b4d3a5-c700-476f-b609-1493dd9dadc0",
+        "device_owner": "",
+        "allowed_address_pairs": [
+            {
+                "ip_address": "192.168.1.1",
+                "mac_address": "12:12"
+            },
+            {
+                "mac_address": "12:13",
+                "ip_address": "192.168.1.2"
+            }
+        ],
+        "fixed_ips": [
+            {
+                "ip_address": "192.168.111.4",
+                "subnet_id": "22b44fc2-4ffb-4de4-b0f9-69d58b37ae27"
+            }
+        ],
+        "id": "ebe69f1e-bc26-4db5-bed0-c0afb4afe3db",
+        "mac_address": "fa:16:3e:a6:50:c1",
+        "name": "port1",
+        "network_id": "6aeaf34a-c482-4bd3-9dc3-7faf36412f12",
+        "status": "ACTIVE",
+        "tenant_id": "cf1a5775e766426cb1968766d0191908"
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/port_get_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/port_get_response.json b/openstack-neutron/src/test/resources/port_get_response.json
new file mode 100644
index 0000000..d9c154d
--- /dev/null
+++ b/openstack-neutron/src/test/resources/port_get_response.json
@@ -0,0 +1,10 @@
+{"port": {
+    "status": "ACTIVE",
+    "network_id": "1234567890",
+    "name": "jclouds-wibble",
+    "tenant_id": "1234567890",
+    "id": "624312ff-d14b-4ba3-9834-1c78d23d574d",
+    "binding:vnic_type": "normal",
+    "binding:vif_type": "hyperv",
+    "binding:vif_details": {"name1": "value1", "name2": {"mapname2": 3}}
+}}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/port_list_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/port_list_response.json b/openstack-neutron/src/test/resources/port_list_response.json
new file mode 100644
index 0000000..29c3a2b
--- /dev/null
+++ b/openstack-neutron/src/test/resources/port_list_response.json
@@ -0,0 +1,86 @@
+{"ports": [
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "16dba3bc-f3fa-4775-afdc-237e12c72f6a"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "1a104cf5-cb18-4d35-9407-2fd2646d9d0b"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "31083ae2-420d-48b2-ac98-9f7a4fd8dbdc"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "49c6d6fa-ff2a-459d-b975-75a8d31c9a89"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5cb3d6f4-62cb-41c9-b964-ba7d9df79e4e"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "5d51d012-3491-4db7-b1b5-6f254015015d"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5f9cf7dc-22ca-4097-8e49-1cc8b23faf17"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6319ecad-6bff-48b2-9b53-02ede8cb7588"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6ba4c788-661f-49ab-9bf8-5f10cbbb2f57"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "74ed170b-5069-4353-ab38-9719766dc57e"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "b71fcac1-e864-4031-8c5b-edbecd9ece36"
+    },
+    {
+        "status": "ACTIVE",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "c7681895-d84d-4650-9ca0-82c72036b855"
+    }
+]}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/port_list_response_paged1.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/port_list_response_paged1.json b/openstack-neutron/src/test/resources/port_list_response_paged1.json
new file mode 100644
index 0000000..f3bd818
--- /dev/null
+++ b/openstack-neutron/src/test/resources/port_list_response_paged1.json
@@ -0,0 +1,48 @@
+{
+    "ports": [
+        {
+            "admin_state_up": true,
+            "device_id": "257614cc-e178-4c92-9c61-3b28d40eca44",
+            "device_owner": "",
+            "fixed_ips": [
+                {
+                    "ip_address": "192.168.111.3",
+                    "subnet_id": "22b44fc2-4ffb-4de4-b0f9-69d58b37ae27"
+                }
+            ],
+            "id": "24e6637e-c521-45fc-8b8b-d7331aa3c99f",
+            "mac_address": "fa:16:3e:0f:3f:b5",
+            "name": "",
+            "network_id": "6aeaf34a-c482-4bd3-9dc3-7faf36412f12",
+            "status": "ACTIVE",
+            "tenant_id": "cf1a5775e766426cb1968766d0191908"
+        },
+        {
+            "admin_state_up": true,
+            "device_id": "d266f9de-fe2c-4705-93b3-9da71168c93b",
+            "device_owner": "",
+            "fixed_ips": [
+                {
+                    "ip_address": "192.168.111.2",
+                    "subnet_id": "22b44fc2-4ffb-4de4-b0f9-69d58b37ae27"
+                }
+            ],
+            "id": "e54dfd9b-ce6e-47f7-af47-1609cfd1cdb0",
+            "mac_address": "fa:16:3e:f5:41:7f",
+            "name": "",
+            "network_id": "6aeaf34a-c482-4bd3-9dc3-7faf36412f12",
+            "status": "ACTIVE",
+            "tenant_id": "cf1a5775e766426cb1968766d0191908"
+        }
+    ],
+    "ports_links": [
+        {
+            "href": "/v2.0/ports.json?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718",
+            "rel": "next"
+        },
+        {
+            "href": "/v2.0/ports.json?marker=396f12f8-521e-4b91-8e21-2e003500433a&page_reverse=True",
+            "rel": "previous"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/port_list_response_paged2.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/port_list_response_paged2.json b/openstack-neutron/src/test/resources/port_list_response_paged2.json
new file mode 100644
index 0000000..ccd4c93
--- /dev/null
+++ b/openstack-neutron/src/test/resources/port_list_response_paged2.json
@@ -0,0 +1,44 @@
+{
+    "ports": [
+        {
+            "admin_state_up": true,
+            "device_id": "257614cc-e178-4c92-9c61-3b28d40eca44_3",
+            "device_owner": "",
+            "fixed_ips": [
+                {
+                    "ip_address": "192.168.111.3",
+                    "subnet_id": "22b44fc2-4ffb-4de4-b0f9-69d58b37ae27"
+                }
+            ],
+            "id": "24e6637e-c521-45fc-8b8b-d7331aa3c99f-2_3",
+            "mac_address": "fa:16:3e:0f:3f:b5",
+            "name": "3",
+            "network_id": "6aeaf34a-c482-4bd3-9dc3-7faf36412f12",
+            "status": "ACTIVE",
+            "tenant_id": "cf1a5775e766426cb1968766d0191908"
+        },
+        {
+            "admin_state_up": true,
+            "device_id": "d266f9de-fe2c-4705-93b3-9da71168c93b",
+            "device_owner": "",
+            "fixed_ips": [
+                {
+                    "ip_address": "192.168.111.2",
+                    "subnet_id": "22b44fc2-4ffb-4de4-b0f9-69d58b37ae27"
+                }
+            ],
+            "id": "e54dfd9b-ce6e-47f7-af47-1609cfd1cdb0_4",
+            "mac_address": "fa:16:3e:f5:41:7f",
+            "name": "4",
+            "network_id": "6aeaf34a-c482-4bd3-9dc3-7faf36412f12",
+            "status": "ACTIVE",
+            "tenant_id": "cf1a5775e766426cb1968766d0191908"
+        }
+    ],
+    "ports_links": [
+        {
+            "href": "/v2.0/ports.json?marker=396f12f8-521e-4b91-8e21-2e003500433a&page_reverse=True",
+            "rel": "previous"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/port_update_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/port_update_request.json b/openstack-neutron/src/test/resources/port_update_request.json
new file mode 100644
index 0000000..f5af476
--- /dev/null
+++ b/openstack-neutron/src/test/resources/port_update_request.json
@@ -0,0 +1,8 @@
+{
+    "port": {
+        "security_groups": [
+            "85cc3048-abc3-43cc-89b3-377341426ac5",
+            "c5ab5c29-2c99-44cb-a4b8-e70a88b77799"
+        ]
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/port_update_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/port_update_response.json b/openstack-neutron/src/test/resources/port_update_response.json
new file mode 100644
index 0000000..b88db25
--- /dev/null
+++ b/openstack-neutron/src/test/resources/port_update_response.json
@@ -0,0 +1,23 @@
+{
+    "port": {
+        "admin_state_up": true,
+        "device_id": "24df1d04-d5cb-41e1-8de5-61ed77c558df",
+        "device_owner": "compute:None",
+        "fixed_ips": [
+            {
+                "ip_address": "10.0.0.3",
+                "subnet_id": "3b498f11-0a20-43ed-b992-0e4202d5f930"
+            }
+        ],
+        "id": "1d8591f4-7b62-428e-857d-e82a15e5a7f1",
+        "mac_address": "fa:16:3e:b6:da:54",
+        "name": "",
+        "network_id": "abaf2e70-4305-4e8d-ac70-3e4cc5f66a07",
+        "security_groups": [
+            "85cc3048-abc3-43cc-89b3-377341426ac5",
+            "c5ab5c29-2c99-44cb-a4b8-e70a88b77799"
+        ],
+        "status": "ACTIVE",
+        "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550"
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router.json b/openstack-neutron/src/test/resources/router.json
index 0b45db9..b39e3c8 100644
--- a/openstack-neutron/src/test/resources/router.json
+++ b/openstack-neutron/src/test/resources/router.json
@@ -1,7 +1,9 @@
-{"router":{
-    "status":"ACTIVE",
-    "external_gateway_info":{"network_id":"624312ff-d14b-4ba3-9834-1c78d23d574d"},
-    "name":"jclouds-wibble",
-    "tenant_id":"1234567890",
-    "id":"16dba3bc-f3fa-4775-afdc-237e12c72f6a"
-}}
\ No newline at end of file
+{"router": {
+    "status": "ACTIVE",
+    "external_gateway_info": {
+        "network_id": "624312ff-d14b-4ba3-9834-1c78d23d574d"
+    },
+    "name": "jclouds-wibble",
+    "tenant_id": "1234567890",
+    "id": "16dba3bc-f3fa-4775-afdc-237e12c72f6a"
+}}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router_add_interface_port_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router_add_interface_port_request.json b/openstack-neutron/src/test/resources/router_add_interface_port_request.json
new file mode 100644
index 0000000..bae800a
--- /dev/null
+++ b/openstack-neutron/src/test/resources/router_add_interface_port_request.json
@@ -0,0 +1,3 @@
+{
+    "port_id": "portid"
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router_add_interface_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router_add_interface_request.json b/openstack-neutron/src/test/resources/router_add_interface_request.json
new file mode 100644
index 0000000..107e6e4
--- /dev/null
+++ b/openstack-neutron/src/test/resources/router_add_interface_request.json
@@ -0,0 +1,3 @@
+{
+    "subnet_id": "a2f1f29d-571b-4533-907f-5803ab96ead1"
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router_add_interface_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router_add_interface_response.json b/openstack-neutron/src/test/resources/router_add_interface_response.json
new file mode 100644
index 0000000..d28007c
--- /dev/null
+++ b/openstack-neutron/src/test/resources/router_add_interface_response.json
@@ -0,0 +1,4 @@
+{
+    "subnet_id": "a2f1f29d-571b-4533-907f-5803ab96ead1",
+    "port_id": "3a44f4e5-1694-493a-a1fb-393881c673a4"
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router_create_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router_create_request.json b/openstack-neutron/src/test/resources/router_create_request.json
new file mode 100644
index 0000000..106e5d4
--- /dev/null
+++ b/openstack-neutron/src/test/resources/router_create_request.json
@@ -0,0 +1,9 @@
+{
+    "router": {
+        "name": "another_router",
+        "external_gateway_info": {
+            "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b"
+        },
+        "admin_state_up": true
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router_create_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router_create_response.json b/openstack-neutron/src/test/resources/router_create_response.json
new file mode 100644
index 0000000..d851d76
--- /dev/null
+++ b/openstack-neutron/src/test/resources/router_create_response.json
@@ -0,0 +1,12 @@
+{
+    "router": {
+        "status": "ACTIVE",
+        "external_gateway_info": {
+            "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b"
+        },
+        "name": "another_router",
+        "admin_state_up": true,
+        "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3",
+        "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e"
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router_get_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router_get_response.json b/openstack-neutron/src/test/resources/router_get_response.json
new file mode 100644
index 0000000..77bdebf
--- /dev/null
+++ b/openstack-neutron/src/test/resources/router_get_response.json
@@ -0,0 +1,12 @@
+{
+    "router": {
+        "status": "ACTIVE",
+        "external_gateway_info": {
+            "network_id": "3c5bcddd-6af9-4e6b-9c3e-c153e521cab8"
+        },
+        "name": "router1",
+        "admin_state_up": true,
+        "tenant_id": "33a40233088643acb66ff6eb0ebea679",
+        "id": "a9254bdb-2613-4a13-ac4c-adc581fba50d"
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router_list_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router_list_response.json b/openstack-neutron/src/test/resources/router_list_response.json
new file mode 100644
index 0000000..14dcfae
--- /dev/null
+++ b/openstack-neutron/src/test/resources/router_list_response.json
@@ -0,0 +1,74 @@
+{"routers": [
+    {
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "16dba3bc-f3fa-4775-afdc-237e12c72f6a"
+    },
+    {
+        "status": "ACTIVE",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "1a104cf5-cb18-4d35-9407-2fd2646d9d0b"
+    },
+    {
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "31083ae2-420d-48b2-ac98-9f7a4fd8dbdc"
+    },
+    {
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "49c6d6fa-ff2a-459d-b975-75a8d31c9a89"
+    },
+    {
+        "status": "ACTIVE",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5cb3d6f4-62cb-41c9-b964-ba7d9df79e4e"
+    },
+    {
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "5d51d012-3491-4db7-b1b5-6f254015015d"
+    },
+    {
+        "status": "ACTIVE",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5f9cf7dc-22ca-4097-8e49-1cc8b23faf17"
+    },
+    {
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6319ecad-6bff-48b2-9b53-02ede8cb7588"
+    },
+    {
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6ba4c788-661f-49ab-9bf8-5f10cbbb2f57"
+    },
+    {
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "74ed170b-5069-4353-ab38-9719766dc57e"
+    },
+    {
+        "status": "ACTIVE",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "b71fcac1-e864-4031-8c5b-edbecd9ece36"
+    },
+    {
+        "status": "ACTIVE",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "c7681895-d84d-4650-9ca0-82c72036b855"
+    }
+]}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router_list_response_paged1.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router_list_response_paged1.json b/openstack-neutron/src/test/resources/router_list_response_paged1.json
new file mode 100644
index 0000000..ef67e54
--- /dev/null
+++ b/openstack-neutron/src/test/resources/router_list_response_paged1.json
@@ -0,0 +1,34 @@
+{
+    "routers": [
+        {
+            "status": "ACTIVE",
+            "external_gateway_info": {
+                "network_id": "3c5bcddd-6af9-4e6b-9c3e-c153e521cab8"
+            },
+            "name": "router1",
+            "admin_state_up": true,
+            "tenant_id": "33a40233088643acb66ff6eb0ebea679",
+            "id": "a9254bdb-2613-4a13-ac4c-adc581fba50d"
+        },
+        {
+            "status": "ACTIVE",
+            "external_gateway_info": {
+                "network_id": "3c5bcddd-6af9-4e6b-9c3e-c153e521cab8_2"
+            },
+            "name": "router2",
+            "admin_state_up": true,
+            "tenant_id": "33a40233088643acb66ff6eb0ebea679_2",
+            "id": "a9254bdb-2613-4a13-ac4c-adc581fba50d_2"
+        }
+    ],
+    "routers_links": [
+        {
+            "href": "/v2.0/routers.json?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718",
+            "rel": "next"
+        },
+        {
+            "href": "/v2.0/routers.json?marker=396f12f8-521e-4b91-8e21-2e003500433a&page_reverse=True",
+            "rel": "previous"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router_list_response_paged2.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router_list_response_paged2.json b/openstack-neutron/src/test/resources/router_list_response_paged2.json
new file mode 100644
index 0000000..decec75
--- /dev/null
+++ b/openstack-neutron/src/test/resources/router_list_response_paged2.json
@@ -0,0 +1,30 @@
+{
+    "routers": [
+        {
+            "status": "ACTIVE",
+            "external_gateway_info": {
+                "network_id": "3c5bcddd-6af9-4e6b-9c3e-c153e521cab8_3"
+            },
+            "name": "router3",
+            "admin_state_up": true,
+            "tenant_id": "33a40233088643acb66ff6eb0ebea679_3",
+            "id": "a9254bdb-2613-4a13-ac4c-adc581fba50d_3"
+        },
+        {
+            "status": "ACTIVE",
+            "external_gateway_info": {
+                "network_id": "3c5bcddd-6af9-4e6b-9c3e-c153e521cab8_4"
+            },
+            "name": "router4",
+            "admin_state_up": true,
+            "tenant_id": "33a40233088643acb66ff6eb0ebea679_4",
+            "id": "a9254bdb-2613-4a13-ac4c-adc581fba50d_4"
+        }
+    ],
+    "routers_links": [
+        {
+            "href": "/v2.0/routers.json?marker=396f12f8-521e-4b91-8e21-2e003500433a&page_reverse=True",
+            "rel": "previous"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router_remove_interface_port_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router_remove_interface_port_request.json b/openstack-neutron/src/test/resources/router_remove_interface_port_request.json
new file mode 100644
index 0000000..bae800a
--- /dev/null
+++ b/openstack-neutron/src/test/resources/router_remove_interface_port_request.json
@@ -0,0 +1,3 @@
+{
+    "port_id": "portid"
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router_remove_interface_subnet_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router_remove_interface_subnet_request.json b/openstack-neutron/src/test/resources/router_remove_interface_subnet_request.json
new file mode 100644
index 0000000..107e6e4
--- /dev/null
+++ b/openstack-neutron/src/test/resources/router_remove_interface_subnet_request.json
@@ -0,0 +1,3 @@
+{
+    "subnet_id": "a2f1f29d-571b-4533-907f-5803ab96ead1"
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router_update_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router_update_request.json b/openstack-neutron/src/test/resources/router_update_request.json
new file mode 100644
index 0000000..351c427
--- /dev/null
+++ b/openstack-neutron/src/test/resources/router_update_request.json
@@ -0,0 +1,7 @@
+{
+    "router": {
+        "external_gateway_info": {
+            "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b"
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/router_update_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/router_update_response.json b/openstack-neutron/src/test/resources/router_update_response.json
new file mode 100644
index 0000000..d851d76
--- /dev/null
+++ b/openstack-neutron/src/test/resources/router_update_response.json
@@ -0,0 +1,12 @@
+{
+    "router": {
+        "status": "ACTIVE",
+        "external_gateway_info": {
+            "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b"
+        },
+        "name": "another_router",
+        "admin_state_up": true,
+        "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3",
+        "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e"
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/subnet.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/subnet.json b/openstack-neutron/src/test/resources/subnet.json
index abc5ceb..58c4382 100644
--- a/openstack-neutron/src/test/resources/subnet.json
+++ b/openstack-neutron/src/test/resources/subnet.json
@@ -1,8 +1,8 @@
-{"subnet":{
-   "ip_version":4,
-   "cidr":"10.0.3.0/24",
-   "network_id":"1234567890",
-   "name":"jclouds-wibble",
-   "tenant_id":"1234567890",
-   "id":"624312ff-d14b-4ba3-9834-1c78d23d574d"
-}}
\ No newline at end of file
+{"subnet": {
+    "ip_version": 4,
+    "cidr": "10.0.3.0/24",
+    "network_id": "1234567890",
+    "name": "jclouds-wibble",
+    "tenant_id": "1234567890",
+    "id": "624312ff-d14b-4ba3-9834-1c78d23d574d"
+}}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/subnet_bulk_create_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/subnet_bulk_create_request.json b/openstack-neutron/src/test/resources/subnet_bulk_create_request.json
new file mode 100644
index 0000000..0bb8460
--- /dev/null
+++ b/openstack-neutron/src/test/resources/subnet_bulk_create_request.json
@@ -0,0 +1,14 @@
+{
+    "subnets": [
+        {
+            "cidr": "192.168.199.0/24",
+            "ip_version": 4,
+            "network_id": "e6031bc2-901a-4c66-82da-f4c32ed89406"
+        },
+        {
+            "cidr": "10.56.4.0/22",
+            "ip_version": 4,
+            "network_id": "64239a54-dcc4-4b39-920b-b37c2144effa"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/subnet_bulk_create_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/subnet_bulk_create_response.json b/openstack-neutron/src/test/resources/subnet_bulk_create_response.json
new file mode 100644
index 0000000..f643084
--- /dev/null
+++ b/openstack-neutron/src/test/resources/subnet_bulk_create_response.json
@@ -0,0 +1,48 @@
+{
+    "subnets": [
+        {
+            "allocation_pools": [
+                {
+                    "end": "192.168.199.254",
+                    "start": "192.168.199.2"
+                }
+            ],
+            "cidr": "192.168.199.0/24",
+            "dns_nameservers": [
+
+            ],
+            "enable_dhcp": true,
+            "gateway_ip": "192.168.199.1",
+            "host_routes": [
+
+            ],
+            "id": "0468a7a7-290d-4127-aedd-6c9449775a24",
+            "ip_version": 4,
+            "name": "",
+            "network_id": "e6031bc2-901a-4c66-82da-f4c32ed89406",
+            "tenant_id": "d19231fc08ec4bc4829b668040d34512"
+        },
+        {
+            "allocation_pools": [
+                {
+                    "end": "10.56.7.254",
+                    "start": "10.56.4.2"
+                }
+            ],
+            "cidr": "10.56.4.0/22",
+            "dns_nameservers": [
+
+            ],
+            "enable_dhcp": true,
+            "gateway_ip": "10.56.4.1",
+            "host_routes": [
+
+            ],
+            "id": "b0e7435c-1512-45fb-aa9e-9a7c5932fb30",
+            "ip_version": 4,
+            "name": "",
+            "network_id": "64239a54-dcc4-4b39-920b-b37c2144effa",
+            "tenant_id": "d19231fc08ec4bc4829b668040d34512"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/subnet_create_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/subnet_create_request.json b/openstack-neutron/src/test/resources/subnet_create_request.json
new file mode 100644
index 0000000..49a53b6
--- /dev/null
+++ b/openstack-neutron/src/test/resources/subnet_create_request.json
@@ -0,0 +1,6 @@
+{"subnet": {
+    "ip_version": 4,
+    "cidr": "10.0.3.0/24",
+    "network_id": "1234567890",
+    "name": "jclouds-wibble"
+}}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/subnet_create_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/subnet_create_response.json b/openstack-neutron/src/test/resources/subnet_create_response.json
new file mode 100644
index 0000000..58c4382
--- /dev/null
+++ b/openstack-neutron/src/test/resources/subnet_create_response.json
@@ -0,0 +1,8 @@
+{"subnet": {
+    "ip_version": 4,
+    "cidr": "10.0.3.0/24",
+    "network_id": "1234567890",
+    "name": "jclouds-wibble",
+    "tenant_id": "1234567890",
+    "id": "624312ff-d14b-4ba3-9834-1c78d23d574d"
+}}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/subnet_get_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/subnet_get_response.json b/openstack-neutron/src/test/resources/subnet_get_response.json
new file mode 100644
index 0000000..aead0f9
--- /dev/null
+++ b/openstack-neutron/src/test/resources/subnet_get_response.json
@@ -0,0 +1,9 @@
+{"subnet": {
+    "ip_version": 4,
+    "cidr": "10.0.3.0/24",
+    "network_id": "1234567890",
+    "name": "jclouds-wibble",
+    "tenant_id": "1234567890",
+    "id": "624312ff-d14b-4ba3-9834-1c78d23d574d",
+    "ipv6_address_mode": "slaac"
+}}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/subnet_list_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/subnet_list_response.json b/openstack-neutron/src/test/resources/subnet_list_response.json
new file mode 100644
index 0000000..b0061e9
--- /dev/null
+++ b/openstack-neutron/src/test/resources/subnet_list_response.json
@@ -0,0 +1,98 @@
+{"subnets": [
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "16dba3bc-f3fa-4775-afdc-237e12c72f6a"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "1a104cf5-cb18-4d35-9407-2fd2646d9d0b"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "31083ae2-420d-48b2-ac98-9f7a4fd8dbdc"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "49c6d6fa-ff2a-459d-b975-75a8d31c9a89"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5cb3d6f4-62cb-41c9-b964-ba7d9df79e4e"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "5d51d012-3491-4db7-b1b5-6f254015015d"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "5f9cf7dc-22ca-4097-8e49-1cc8b23faf17"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6319ecad-6bff-48b2-9b53-02ede8cb7588"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "6ba4c788-661f-49ab-9bf8-5f10cbbb2f57"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "74ed170b-5069-4353-ab38-9719766dc57e"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "wibble",
+        "tenant_id": "1234567890",
+        "id": "b71fcac1-e864-4031-8c5b-edbecd9ece36"
+    },
+    {
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "network_id": "1234567890",
+        "name": "jclouds-test",
+        "tenant_id": "1234567890",
+        "id": "c7681895-d84d-4650-9ca0-82c72036b855"
+    }
+]}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/subnet_list_response_pages1.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/subnet_list_response_pages1.json b/openstack-neutron/src/test/resources/subnet_list_response_pages1.json
new file mode 100644
index 0000000..10b3aaa
--- /dev/null
+++ b/openstack-neutron/src/test/resources/subnet_list_response_pages1.json
@@ -0,0 +1,30 @@
+{
+    "subnets": [
+        {
+            "ip_version": 4,
+            "cidr": "10.0.3.0/24",
+            "network_id": "1234567890",
+            "name": "jclouds-test",
+            "tenant_id": "1234567890",
+            "id": "16dba3bc-f3fa-4775-afdc-237e12c72f6a"
+        },
+        {
+            "ip_version": 4,
+            "cidr": "10.0.3.0/24",
+            "network_id": "1234567890",
+            "name": "wibble",
+            "tenant_id": "1234567890",
+            "id": "1a104cf5-cb18-4d35-9407-2fd2646d9d0b"
+        }
+    ],
+    "subnets_links": [
+        {
+            "href": "/v2.0/subnets.json?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718",
+            "rel": "next"
+        },
+        {
+            "href": "/v2.0/subnets.json?marker=396f12f8-521e-4b91-8e21-2e003500433a&page_reverse=True",
+            "rel": "previous"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/subnet_list_response_pages2.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/subnet_list_response_pages2.json b/openstack-neutron/src/test/resources/subnet_list_response_pages2.json
new file mode 100644
index 0000000..0319fbe
--- /dev/null
+++ b/openstack-neutron/src/test/resources/subnet_list_response_pages2.json
@@ -0,0 +1,26 @@
+{
+    "subnets": [
+        {
+            "ip_version": 4,
+            "cidr": "10.0.3.0/24",
+            "network_id": "1234567890",
+            "name": "jclouds-test",
+            "tenant_id": "1234567890",
+            "id": "6319ecad-6bff-48b2-9b53-02ede8cb7588"
+        },
+        {
+            "ip_version": 4,
+            "cidr": "10.0.3.0/24",
+            "network_id": "1234567890",
+            "name": "jclouds-test",
+            "tenant_id": "1234567890",
+            "id": "6ba4c788-661f-49ab-9bf8-5f10cbbb2f57"
+        }
+    ],
+    "subnets_links": [
+        {
+            "href": "/v2.0/subnets.json?marker=396f12f8-521e-4b91-8e21-2e003500433a&page_reverse=True",
+            "rel": "previous"
+        }
+    ]
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/subnet_update_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/subnet_update_request.json b/openstack-neutron/src/test/resources/subnet_update_request.json
new file mode 100644
index 0000000..6345647
--- /dev/null
+++ b/openstack-neutron/src/test/resources/subnet_update_request.json
@@ -0,0 +1,6 @@
+{
+    "subnet": {
+        "gateway_ip": "10.0.3.254",
+        "name": "new_name"
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/resources/subnet_update_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/subnet_update_response.json b/openstack-neutron/src/test/resources/subnet_update_response.json
new file mode 100644
index 0000000..40c65e9
--- /dev/null
+++ b/openstack-neutron/src/test/resources/subnet_update_response.json
@@ -0,0 +1,18 @@
+{
+    "subnet": {
+        "name": "new_name",
+        "network_id": "ed2e3c10-2e43-4297-9006-2863a2d1abbc",
+        "tenant_id": "c1210485b2424d48804aad5d39c61b8f",
+        "allocation_pools": [
+            {
+                "start": "10.0.3.20",
+                "end": "10.0.3.150"
+            }
+        ],
+        "gateway_ip": "10.0.3.254",
+        "ip_version": 4,
+        "cidr": "10.0.3.0/24",
+        "enable_dhcp": true,
+        "id": "9436e561-47bf-436a-b1f1-fe23a926e031"
+    }
+}


[3/5] Neutron Refactoring v2_0 -> v2 No options (redesign) More features (extension-related) Live tests Redesigned domain objects for create/update options.

Posted by za...@apache.org.
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/features/PortApi.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/features/PortApi.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/features/PortApi.java
new file mode 100644
index 0000000..356111e
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/features/PortApi.java
@@ -0,0 +1,150 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.features;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
+import org.jclouds.Fallbacks;
+import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404;
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.neutron.v2.domain.Port;
+import org.jclouds.openstack.neutron.v2.domain.Ports;
+import org.jclouds.openstack.neutron.v2.fallbacks.EmptyPortsFallback;
+import org.jclouds.openstack.neutron.v2.functions.ParsePorts;
+import org.jclouds.openstack.neutron.v2.functions.PortsToPagedIterable;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.annotations.WrapWith;
+
+import javax.inject.Named;
+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.core.MediaType;
+import java.util.List;
+
+/**
+ * Provides synchronous access to Port operations on the openstack Neutron API.
+ * <p/>
+ * A port represents a virtual switch port on a logical network switch where all the interfaces attached to a given network are connected.
+ * <p/>
+ * A port has an administrative state which is either 'DOWN' or 'ACTIVE'. Ports which are administratively down will not be able to receive/send traffic.
+ * @see <a href=
+ *      "http://docs.openstack.org/api/openstack-network/2.0/content/Ports.html">api doc</a>
+ */
+@Beta
+@Path("/v2.0/ports")
+@RequestFilters(AuthenticateRequest.class)
+@Consumes(MediaType.APPLICATION_JSON)
+public interface PortApi {
+
+   /**
+    * Returns the list of all ports currently defined in Neutron for the current tenant. The list provides the unique
+    * identifier of each network configured for the tenant.
+    *
+    * @return the list of all port references configured for the tenant
+    */
+   @Named("port:list")
+   @GET
+   @Transform(PortsToPagedIterable.class)
+   @ResponseParser(ParsePorts.class)
+   @Fallback(EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<Port> list();
+
+   /**
+    * @see <a href="http://docs.openstack.org/api/openstack-network/2.0/content/pagination.html">api doc</a>
+    */
+   @Named("port:list")
+   @GET
+   @ResponseParser(ParsePorts.class)
+   @Fallback(EmptyPortsFallback.class)
+   Ports list(PaginationOptions options);
+
+   /**
+    * Returns the specific port
+    *
+    * @param id the id of the port to return
+    * @return Port or null if not found
+    */
+   @Named("port:get")
+   @GET
+   @Path("/{id}")
+   @SelectJson("port")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Nullable
+   Port get(@PathParam("id") String id);
+
+   /**
+    * Create a new port in the specified network
+    *
+    * @param port the port details
+    * @return a reference of the newly-created port
+    */
+   @Named("port:create")
+   @POST
+   @SelectJson("port")
+   Port create(@WrapWith("port") Port.CreateOptions port);
+
+   /**
+    * Create multiple ports
+    *
+    * @param ports the bulk of ports to create
+    * @return list of references of the newly-created ports
+    */
+   @Named("port:createBulk")
+   @POST
+   @SelectJson("ports")
+   FluentIterable<Port> createBulk(@WrapWith("ports") List<Port.CreateOptions> ports);
+
+   /**
+    * Update a port
+    *
+    * @param id the id of the port to update
+    * @param port CreatePort with just the attributes to update
+    * @return true if update successful, false if not
+    */
+   @Named("port:update")
+   @PUT
+   @Path("/{id}")
+   @SelectJson("port")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   Port update(@PathParam("id") String id, @WrapWith("port") Port.UpdateOptions port);
+
+   /**
+    * Delete a port
+    *
+    * @param id the id of the port to delete
+    * @return true if delete successful, false if not
+    */
+   @Named("port:delete")
+   @DELETE
+   @Path("/{id}")
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean delete(@PathParam("id") String id);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/features/SubnetApi.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/features/SubnetApi.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/features/SubnetApi.java
new file mode 100644
index 0000000..a50e486
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/features/SubnetApi.java
@@ -0,0 +1,146 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.features;
+
+import com.google.common.collect.FluentIterable;
+import org.jclouds.Fallbacks;
+import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404;
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.neutron.v2.domain.Subnet;
+import org.jclouds.openstack.neutron.v2.domain.Subnets;
+import org.jclouds.openstack.neutron.v2.fallbacks.EmptySubnetsFallback;
+import org.jclouds.openstack.neutron.v2.functions.ParseSubnets;
+import org.jclouds.openstack.neutron.v2.functions.SubnetsToPagedIterable;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.annotations.WrapWith;
+
+import javax.inject.Named;
+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.core.MediaType;
+import java.util.List;
+
+/**
+ * Provides synchronous access to Subnet operations on the Openstack Neutron API.
+ *
+ * @see <a href=
+ *      "http://docs.openstack.org/api/openstack-network/2.0/content/Subnets.html">api doc</a>
+ */
+@Path("/v2.0/subnets")
+@RequestFilters(AuthenticateRequest.class)
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public interface SubnetApi {
+
+   /**
+    * Returns the list of all subnets currently defined in Neutron for the current tenant. The list provides the unique
+    * identifier of each subnet configured for the tenant.
+    *
+    * @return the list of all subnet references configured for the tenant
+    */
+   @Named("subnet:list")
+   @GET
+   @ResponseParser(ParseSubnets.class)
+   @Transform(SubnetsToPagedIterable.class)
+   @Fallback(EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<Subnet> list();
+
+   /**
+    * @see <a href="http://docs.openstack.org/api/openstack-network/2.0/content/pagination.html">api doc</a>
+    */
+   @Named("subnet:list")
+   @GET
+   @ResponseParser(ParseSubnets.class)
+   @Fallback(EmptySubnetsFallback.class)
+   Subnets list(PaginationOptions options);
+
+   /**
+    * Returns the specific Subnet.
+    *
+    * @param id the id of the subnet to return
+    * @return Subnet or null if not found
+    */
+   @Named("subnet:get")
+   @GET
+   @Path("/{id}")
+   @SelectJson("subnet")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Nullable
+   Subnet get(@PathParam("id") String id);
+
+   /**
+    * Create a subnet within a specified network
+    *
+    * @param subnet the subnet to be created
+    * @return a reference of the newly-created subnet
+    */
+   @Named("subnet:create")
+   @POST
+   @SelectJson("subnet")
+   Subnet create(@WrapWith("subnet") Subnet.CreateOptions subnet);
+
+   /**
+    * Create multiple subnets
+    *
+    * @param subnets the bulk of subnets to create
+    * @return list of references of the newly-created subnets
+    */
+   @Named("subnet:createBulk")
+   @POST
+   @SelectJson("subnets")
+   FluentIterable<Subnet> createBulk(@WrapWith("subnets") List<Subnet.CreateOptions> subnets);
+
+   /**
+    * Update a subnet
+    *
+    * @param id the id of the subnet to update
+    * @return true if update was successful, false if not
+    */
+   @Named("subnet:update")
+   @PUT
+   @Path("/{id}")
+   @SelectJson("subnet")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   Subnet update(@PathParam("id") String id, @WrapWith("subnet") Subnet.UpdateOptions subnet);
+
+   /**
+    * Delete a subnet
+    *
+    * @param id the id of the subnet to delete
+    * @return true if delete successful, false if not
+    */
+   @Named("subnet:delete")
+   @DELETE
+   @Path("/{id}")
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean delete(@PathParam("id") String id);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/NetworksToPagedIterable.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/NetworksToPagedIterable.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/NetworksToPagedIterable.java
new file mode 100644
index 0000000..1c96f8d
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/NetworksToPagedIterable.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.functions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.Arg0ToPagedIterable;
+import org.jclouds.openstack.neutron.v2.NeutronApi;
+import org.jclouds.openstack.neutron.v2.domain.Network;
+import org.jclouds.openstack.neutron.v2.features.NetworkApi;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+
+import javax.inject.Inject;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Makes Networks work as a PagedIterable.
+ */
+public class NetworksToPagedIterable extends Arg0ToPagedIterable.FromCaller<Network, NetworksToPagedIterable> {
+
+   private final NeutronApi api;
+
+   @Inject
+   protected NetworksToPagedIterable(NeutronApi api) {
+      this.api = checkNotNull(api, "api");
+   }
+
+   @Override
+   protected Function<Object, IterableWithMarker<Network>> markerToNextForArg0(Optional<Object> arg0) {
+      String zone = arg0.isPresent() ? arg0.get().toString() : null;
+      final NetworkApi networkApi = api.getNetworkApiForZone(zone);
+      return new Function<Object, IterableWithMarker<Network>>() {
+
+         @SuppressWarnings("unchecked")
+         @Override
+         public IterableWithMarker<Network> apply(Object input) {
+            PaginationOptions paginationOptions = PaginationOptions.class.cast(input);
+            return IterableWithMarker.class.cast(networkApi.list(paginationOptions));
+         }
+
+         @Override
+         public String toString() {
+            return "listNetworks()";
+         }
+      };
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseNetworks.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseNetworks.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseNetworks.java
new file mode 100644
index 0000000..0f9b8aa
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseNetworks.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.functions;
+
+
+import com.google.inject.TypeLiteral;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.neutron.v2.domain.Networks;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Used by jclouds to provide more specific collections and fallbacks.
+ */
+@Singleton
+public class ParseNetworks extends ParseJson<Networks> {
+
+   @Inject
+   public ParseNetworks(Json json) {
+      super(json, TypeLiteral.get(Networks.class));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParsePorts.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParsePorts.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParsePorts.java
new file mode 100644
index 0000000..ab169dd
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParsePorts.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.functions;
+
+import com.google.inject.TypeLiteral;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.neutron.v2.domain.Ports;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Used by jclouds to provide more specific collections and fallbacks.
+ */
+@Singleton
+public class ParsePorts extends ParseJson<Ports> {
+
+   @Inject
+   public ParsePorts(Json json) {
+      super(json, TypeLiteral.get(Ports.class));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseRouters.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseRouters.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseRouters.java
new file mode 100644
index 0000000..f0acde7
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseRouters.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.functions;
+
+import com.google.inject.TypeLiteral;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.neutron.v2.domain.Routers;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Used by jclouds to provide more specific collections and fallbacks.
+ */
+@Singleton
+public class ParseRouters extends ParseJson<Routers> {
+
+   @Inject
+   public ParseRouters(Json json) {
+      super(json, TypeLiteral.get(Routers.class));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseSubnets.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseSubnets.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseSubnets.java
new file mode 100644
index 0000000..0c985ee
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseSubnets.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.functions;
+
+import com.google.inject.TypeLiteral;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.neutron.v2.domain.Subnets;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Used by jclouds to provide more specific collections and fallbacks.
+ */
+@Singleton
+public class ParseSubnets extends ParseJson<Subnets> {
+
+   @Inject
+   public ParseSubnets(Json json) {
+      super(json, TypeLiteral.get(Subnets.class));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/PortsToPagedIterable.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/PortsToPagedIterable.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/PortsToPagedIterable.java
new file mode 100644
index 0000000..4a163f2
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/PortsToPagedIterable.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.functions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.Arg0ToPagedIterable;
+import org.jclouds.openstack.neutron.v2.NeutronApi;
+import org.jclouds.openstack.neutron.v2.domain.Port;
+import org.jclouds.openstack.neutron.v2.features.PortApi;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+
+import javax.inject.Inject;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Ensures Ports works as a paged iterable.
+ */
+public class PortsToPagedIterable extends Arg0ToPagedIterable.FromCaller<Port, PortsToPagedIterable> {
+
+   private final NeutronApi api;
+
+   @Inject
+   protected PortsToPagedIterable(NeutronApi api) {
+      this.api = checkNotNull(api, "api");
+   }
+
+   @Override
+   protected Function<Object, IterableWithMarker<Port>> markerToNextForArg0(Optional<Object> arg0) {
+      String zone = arg0.isPresent() ? arg0.get().toString() : null;
+      final PortApi portApi = api.getPortApiForZone(zone);
+      return new Function<Object, IterableWithMarker<Port>>() {
+
+         @SuppressWarnings("unchecked")
+         @Override
+         public IterableWithMarker<Port> apply(Object input) {
+            PaginationOptions paginationOptions = PaginationOptions.class.cast(input);
+            return IterableWithMarker.class.cast(portApi.list(paginationOptions));
+         }
+
+         @Override
+         public String toString() {
+            return "listPortsInDetail()";
+         }
+      };
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/RouterToPagedIterable.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/RouterToPagedIterable.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/RouterToPagedIterable.java
new file mode 100644
index 0000000..e23c0ac
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/RouterToPagedIterable.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.functions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.Arg0ToPagedIterable;
+import org.jclouds.openstack.neutron.v2.NeutronApi;
+import org.jclouds.openstack.neutron.v2.domain.Router;
+import org.jclouds.openstack.neutron.v2.extensions.RouterApi;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+
+import javax.inject.Inject;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Ensures Routers works as PagedIterable.
+ */
+public class RouterToPagedIterable extends Arg0ToPagedIterable.FromCaller<Router, RouterToPagedIterable> {
+
+   private final NeutronApi api;
+
+   @Inject
+   protected RouterToPagedIterable(NeutronApi api) {
+      this.api = checkNotNull(api, "api");
+   }
+
+   @Override
+   protected Function<Object, IterableWithMarker<Router>> markerToNextForArg0(Optional<Object> arg0) {
+      String zone = arg0.isPresent() ? arg0.get().toString() : null;
+      final RouterApi routerApi = api.getRouterExtensionForZone(zone).get();
+      return new Function<Object, IterableWithMarker<Router>>() {
+
+         @SuppressWarnings("unchecked")
+         @Override
+         public IterableWithMarker<Router> apply(Object input) {
+            PaginationOptions paginationOptions = PaginationOptions.class.cast(input);
+            return IterableWithMarker.class.cast(routerApi.list(paginationOptions));
+         }
+
+         @Override
+         public String toString() {
+            return "listRouters()";
+         }
+      };
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/SubnetsToPagedIterable.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/SubnetsToPagedIterable.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/SubnetsToPagedIterable.java
new file mode 100644
index 0000000..64e46d1
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/SubnetsToPagedIterable.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.functions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.Arg0ToPagedIterable;
+import org.jclouds.openstack.neutron.v2.NeutronApi;
+import org.jclouds.openstack.neutron.v2.domain.Subnet;
+import org.jclouds.openstack.neutron.v2.features.SubnetApi;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+
+import javax.inject.Inject;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Ensures Subnets works as a PagedIterable.
+ */
+public class SubnetsToPagedIterable extends Arg0ToPagedIterable.FromCaller<Subnet, SubnetsToPagedIterable> {
+
+   private final NeutronApi api;
+
+   @Inject
+   protected SubnetsToPagedIterable(NeutronApi api) {
+      this.api = checkNotNull(api, "api");
+   }
+
+   @Override
+   protected Function<Object, IterableWithMarker<Subnet>> markerToNextForArg0(Optional<Object> arg0) {
+      String zone = arg0.isPresent() ? arg0.get().toString() : null;
+      final SubnetApi subnetApi = api.getSubnetApiForZone(zone);
+      return new Function<Object, IterableWithMarker<Subnet>>() {
+
+         @SuppressWarnings("unchecked")
+         @Override
+         public IterableWithMarker<Subnet> apply(Object input) {
+            PaginationOptions paginationOptions = PaginationOptions.class.cast(input);
+            return IterableWithMarker.class.cast(subnetApi.list(paginationOptions));
+         }
+
+         @Override
+         public String toString() {
+            return "listSubnets()";
+         }
+      };
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/handlers/NeutronErrorHandler.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/handlers/NeutronErrorHandler.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/handlers/NeutronErrorHandler.java
new file mode 100644
index 0000000..5aaaae5
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/handlers/NeutronErrorHandler.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.handlers;
+
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import javax.inject.Singleton;
+
+import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
+
+/**
+ * This will parse and set an appropriate exception on the command object.
+ */
+@Singleton
+public class NeutronErrorHandler implements HttpErrorHandler {
+   public void handleError(HttpCommand command, HttpResponse response) {
+      // it is important to always read fully and close streams
+      byte[] data = closeClientButKeepContentStream(response);
+      String message = data != null ? new String(data) : null;
+
+      Exception exception = message != null ? new HttpResponseException(command, response, message)
+            : new HttpResponseException(command, response);
+      message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
+            response.getStatusLine());
+      switch (response.getStatusCode()) {
+         case 400:
+            break;
+         case 401:
+         case 403:
+            exception = new AuthorizationException(message, exception);
+            break;
+         case 404:
+            if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
+               exception = new ResourceNotFoundException(message, exception);
+            }
+            break;
+         case 409:
+            exception = new IllegalStateException(exception.getMessage(), exception);
+            break;
+      }
+      command.setException(exception);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/options/EmptyOptions.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/options/EmptyOptions.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/options/EmptyOptions.java
new file mode 100644
index 0000000..381abc1
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/options/EmptyOptions.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.options;
+
+import com.google.inject.Inject;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import java.util.Map;
+
+/**
+ * This class is used for methods who don't need a wrapper around their JSON body
+ *
+ */
+public class EmptyOptions implements MapBinder {
+
+   @Inject
+   private BindToJsonPayload jsonBinder;
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      return bindToRequest(request, (Object) postParams);
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      return jsonBinder.bindToRequest(request, input);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/NeutronApi.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/NeutronApi.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/NeutronApi.java
index 045b98b..55515df 100644
--- a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/NeutronApi.java
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/NeutronApi.java
@@ -38,7 +38,9 @@ import java.util.Set;
  * <p/>
  *
  * @see <a href="http://docs.openstack.org/api/openstack-network/2.0/content/">api doc</a>
+ * @deprecated Use v2 instead of v2_0
  */
+@Deprecated
 public interface NeutronApi extends Closeable {
    /**
     * @return the Zone codes configured

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/NeutronApiMetadata.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/NeutronApiMetadata.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/NeutronApiMetadata.java
index 4681d82..1c09c11 100644
--- a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/NeutronApiMetadata.java
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/NeutronApiMetadata.java
@@ -37,6 +37,7 @@ import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERV
 /**
  * Implementation of {@link org.jclouds.apis.ApiMetadata} for Neutron 2.0 API
  */
+@Deprecated
 public class NeutronApiMetadata extends BaseHttpApiMetadata<NeutronApi> {
 
    @Override
@@ -63,7 +64,7 @@ public class NeutronApiMetadata extends BaseHttpApiMetadata<NeutronApi> {
 
       protected Builder() {
          super(NeutronApi.class);
-         id("openstack-neutron")
+         id("openstack-neutron-legacy")
             .name("OpenStack Neutron API")
             .identityName("${tenantName}:${userName} or ${userName}, if your keystone supports a default tenant")
             .credentialName("${password}")

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/config/NeutronHttpApiModule.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/config/NeutronHttpApiModule.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/config/NeutronHttpApiModule.java
index fe3d74c..521453a 100644
--- a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/config/NeutronHttpApiModule.java
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/config/NeutronHttpApiModule.java
@@ -16,11 +16,12 @@
  */
 package org.jclouds.openstack.neutron.v2_0.config;
 
-import java.net.URI;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import javax.inject.Provider;
-import javax.inject.Singleton;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Multimap;
+import com.google.inject.Provides;
 import org.jclouds.http.HttpErrorHandler;
 import org.jclouds.http.annotation.ClientError;
 import org.jclouds.http.annotation.Redirection;
@@ -34,26 +35,27 @@ import org.jclouds.openstack.v2_0.functions.PresentWhenExtensionAnnotationNamesp
 import org.jclouds.rest.ConfiguresHttpApi;
 import org.jclouds.rest.config.HttpApiModule;
 import org.jclouds.rest.functions.ImplicitOptionalConverter;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.Multimap;
-import com.google.inject.Provides;
+
+import javax.inject.Provider;
+import javax.inject.Singleton;
+import java.net.URI;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Configures the Neutron connection.
  */
+@Deprecated
 @ConfiguresHttpApi
 public class NeutronHttpApiModule extends HttpApiModule<NeutronApi> {
-   
+
    @Override
    protected void configure() {
       bind(DateAdapter.class).to(Iso8601DateAdapter.class);
       bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.class);
       super.configure();
    }
-   
+
    @Provides
    @Singleton
    public Multimap<URI, URI> aliases() {
@@ -72,7 +74,7 @@ public class NeutronHttpApiModule extends HttpApiModule<NeutronApi> {
                }
             });
    }
-   
+
    @Override
    protected void bindErrorHandlers() {
       bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(NeutronErrorHandler.class);

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/extensions/RouterApi.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/extensions/RouterApi.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/extensions/RouterApi.java
index 05d009c..b740271 100644
--- a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/extensions/RouterApi.java
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/extensions/RouterApi.java
@@ -59,7 +59,9 @@ import static org.jclouds.openstack.keystone.v2_0.KeystoneFallbacks.EmptyPaginat
  *
  * @see <a href=
  *      "http://docs.openstack.org/api/openstack-network/2.0/content/router_ext.html">api doc</a>
+ * @deprecated Use v2 instead of v2_0
  */
+@Deprecated
 @Path("/v2.0/routers")
 @RequestFilters(AuthenticateRequest.class)
 @Consumes(MediaType.APPLICATION_JSON)

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/NetworkApi.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/NetworkApi.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/NetworkApi.java
index a8b819f..f11fe7c 100644
--- a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/NetworkApi.java
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/NetworkApi.java
@@ -59,7 +59,9 @@ import static org.jclouds.openstack.keystone.v2_0.KeystoneFallbacks.EmptyPaginat
  *
  * @see <a href=
  *      "http://docs.openstack.org/api/openstack-network/2.0/content/Networks.html">api doc</a>
+ * @deprecated Use v2 instead of v2_0
  */
+@Deprecated
 @Path("/v2.0/networks")
 @RequestFilters(AuthenticateRequest.class)
 @Consumes(MediaType.APPLICATION_JSON)

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/PortApi.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/PortApi.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/PortApi.java
index c19b77b..0b6b8a6 100644
--- a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/PortApi.java
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/PortApi.java
@@ -62,7 +62,9 @@ import static org.jclouds.openstack.keystone.v2_0.KeystoneFallbacks.EmptyPaginat
 
  * @see <a href=
  *      "http://docs.openstack.org/api/openstack-network/2.0/content/Ports.html">api doc</a>
+ * @deprecated Use v2 instead of v2_0
  */
+@Deprecated
 @Path("/v2.0/ports")
 @RequestFilters(AuthenticateRequest.class)
 @Consumes(MediaType.APPLICATION_JSON)

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/SubnetApi.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/SubnetApi.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/SubnetApi.java
index 0c38050..27dcddb 100644
--- a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/SubnetApi.java
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/SubnetApi.java
@@ -58,7 +58,9 @@ import static org.jclouds.openstack.keystone.v2_0.KeystoneFallbacks.EmptyPaginat
 
  * @see <a href=
  *      "http://docs.openstack.org/api/openstack-network/2.0/content/Subnets.html">api doc</a>
+ * @deprecated Use v2 instead of v2_0
  */
+@Deprecated
 @Path("/v2.0/subnets")
 @RequestFilters(AuthenticateRequest.class)
 @Consumes(MediaType.APPLICATION_JSON)

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/openstack-neutron/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
index c16b23d..2365644 100644
--- a/openstack-neutron/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
+++ b/openstack-neutron/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
@@ -16,3 +16,4 @@
 #
 
 org.jclouds.openstack.neutron.v2_0.NeutronApiMetadata
+org.jclouds.openstack.neutron.v2.NeutronApiMetadata

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/NeutronApiMetadataTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/NeutronApiMetadataTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/NeutronApiMetadataTest.java
new file mode 100644
index 0000000..5a06b96
--- /dev/null
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/NeutronApiMetadataTest.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.TypeToken;
+import org.jclouds.View;
+import org.jclouds.apis.internal.BaseApiMetadataTest;
+import org.testng.annotations.Test;
+
+/**
+ * The Neutron metadata test.
+ */
+@Test(groups = "unit", testName = "NeutronApiMetadataTest")
+public class NeutronApiMetadataTest extends BaseApiMetadataTest {
+   public NeutronApiMetadataTest() {
+      super(new NeutronApiMetadata(), ImmutableSet.<TypeToken<? extends View>>of());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/NetworkApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/NetworkApiLiveTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/NetworkApiLiveTest.java
new file mode 100644
index 0000000..47b02da
--- /dev/null
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/NetworkApiLiveTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.features;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+import org.jclouds.openstack.neutron.v2.domain.Network;
+import org.jclouds.openstack.neutron.v2.domain.NetworkType;
+import org.jclouds.openstack.neutron.v2.internal.BaseNeutronApiLiveTest;
+import org.jclouds.openstack.neutron.v2.util.PredicateUtil;
+import org.testng.annotations.Test;
+
+import java.util.Set;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Tests parsing and Guice wiring of NetworkApi
+ */
+@Test(groups = "live", testName = "NetworkApiLiveTest")
+public class NetworkApiLiveTest extends BaseNeutronApiLiveTest {
+
+   public void testCreateUpdateAndDeleteNetwork() {
+      for (String zone : api.getConfiguredRegions()) {
+         NetworkApi networkApi = api.getNetworkApiForZone(zone);
+         Network net = networkApi.create(Network.createOptions("jclouds-test").networkType(NetworkType.LOCAL).build());
+         Network test = networkApi.create(Network.createOptions("jclouds-test").build());
+         assertNotNull(net);
+
+         /* List and get tests */
+         Network networkList = api.getNetworkApiForZone(zone).list().concat().toSet().iterator().next();
+         assertNotNull(networkList);
+         Network networkGet = api.getNetworkApiForZone(zone).get(networkList.getId());
+         assertEquals(networkList, networkGet);
+         /****/
+
+         Network network = networkApi.get(net.getId());
+
+         assertEquals(network.getId(), net.getId());
+         assertEquals(network.getName(), "jclouds-test");
+         assertEquals(network.getNetworkType(), NetworkType.LOCAL);
+         assertTrue(network.getSubnets().isEmpty());
+         assertNotNull(networkApi.update(net.getId(), Network.updateOptions().name("jclouds-live-test").build()));
+
+         network = networkApi.get(net.getId());
+
+         assertEquals(network.getId(), net.getId());
+         assertEquals(network.getName(), "jclouds-live-test");
+         assertTrue(network.getSubnets().isEmpty());
+
+         Network net2 = networkApi.create(Network.createOptions("jclouds-test2").networkType(NetworkType.LOCAL).build());
+         assertNotNull(net2);
+
+         assertTrue(networkApi.delete(net.getId()));
+         assertTrue(networkApi.delete(net2.getId()));
+         assertTrue(networkApi.delete(test.getId()));
+      }
+   }
+
+   public void testBulkCreateNetwork() {
+      for (String zone : api.getConfiguredRegions()) {
+         NetworkApi networkApi = api.getNetworkApiForZone(zone);
+         Set<Network> nets = networkApi.createBulk(
+               ImmutableList.of(
+                  Network.createOptions("jclouds-live-test-1").networkType(NetworkType.LOCAL).adminStateUp(true).build(),
+                  Network.createOptions("jclouds-live-test-2").networkType(NetworkType.LOCAL).adminStateUp(false).build(),
+                  Network.createOptions("jclouds-live-test-3").networkType(NetworkType.LOCAL).adminStateUp(false).build()
+               )
+         ).toSet();
+         Set<Network> existingNets = networkApi.list().concat().toSet();
+
+         assertNotNull(nets);
+         assertTrue(!nets.isEmpty());
+         assertEquals(nets.size(), 3);
+
+         for (Network net : nets) {
+            Predicate<Network> idEqualsPredicate = PredicateUtil.createIdEqualsPredicate(net.getId());
+            assertEquals(1, Sets.filter(existingNets, idEqualsPredicate).size());
+            assertTrue(networkApi.delete(net.getId()));
+         }
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/NetworkApiMockTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/NetworkApiMockTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/NetworkApiMockTest.java
new file mode 100644
index 0000000..c00a784
--- /dev/null
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/NetworkApiMockTest.java
@@ -0,0 +1,464 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.features;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import org.jclouds.openstack.neutron.v2.NeutronApi;
+import org.jclouds.openstack.neutron.v2.domain.Network;
+import org.jclouds.openstack.neutron.v2.domain.NetworkStatus;
+import org.jclouds.openstack.neutron.v2.domain.NetworkType;
+import org.jclouds.openstack.neutron.v2.domain.Networks;
+import org.jclouds.openstack.neutron.v2.internal.BaseNeutronApiMockTest;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Tests NetworkApi Guice wiring and parsing
+ *
+ */
+@Test
+public class NetworkApiMockTest extends BaseNeutronApiMockTest {
+
+   public void testCreateNetwork() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201).setBody(stringFromResource("/network_create_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         Network.CreateOptions createNetwork = Network.createOptions("jclouds-wibble")
+               .networkType(NetworkType.LOCAL)
+               .build();
+
+         Network network = api.create(createNetwork);
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "POST", "/v2.0/networks", "/network_create_request.json");
+
+         /*
+          * Check response
+          */
+         assertNotNull(network);
+         assertEquals(network.getName(),"jclouds-wibble");
+         assertEquals(network.getNetworkType(), NetworkType.LOCAL);
+         assertEquals(network.getTenantId(), "1234567890");
+         assertEquals(network.getStatus(), NetworkStatus.ACTIVE);
+         assertEquals(network.getId(), "624312ff-d14b-4ba3-9834-1c78d23d574d");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testCreateNetworkFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404).setBody(stringFromResource("/network_create_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         Network.CreateOptions createNetwork = Network.createOptions("jclouds-wibble")
+               .networkType(NetworkType.LOCAL)
+               .build();
+
+         Network network = api.create(createNetwork);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListSpecificPageNetwork() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/network_list_response_paged1.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         Networks networks = api.list(PaginationOptions.Builder.limit(2).marker("abcdefg"));
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/networks?limit=2&marker=abcdefg");
+
+         /*
+          * Check response
+          */
+         assertNotNull(networks);
+         assertEquals(networks.first().get().getId(),"396f12f8-521e-4b91-8e21-2e003500433a");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   // These fail tests uncover issues with the fallback annotations.
+   public void testListSpecificPageNetworkFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404).setBody(stringFromResource("/network_list_response_paged1.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         Networks networks = api.list(PaginationOptions.Builder.limit(2).marker("abcdefg"));
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/networks?limit=2&marker=abcdefg");
+
+         /*
+          * Check response
+          */
+         assertTrue(networks.isEmpty());
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListPagedNetwork() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/network_list_response_paged1.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/network_list_response_paged2.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         // Note: Lazy! Have to actually look at the collection.
+         List<Network> networks = api.list().concat().toList();
+         assertEquals(networks.size(), 4);
+         // look at last element
+         assertEquals(networks.get(3).getId(), "71c1e68c-171a-4aa2-aca5-50ea153a3718_2");
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 3);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/networks");
+         assertRequest(server.takeRequest(), "GET", "/v2.0/networks?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718");
+
+         /*
+          * Check response
+          */
+         assertNotNull(networks);
+         assertEquals(networks.get(0).getId(),"396f12f8-521e-4b91-8e21-2e003500433a");
+         assertEquals(networks.get(3).getId(),"71c1e68c-171a-4aa2-aca5-50ea153a3718_2");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListPagedNetworkFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404).setBody(stringFromResource("/network_list_response_paged1.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         // Note: Lazy! Have to actually look at the collection.
+         List<Network> networks = api.list().concat().toList();
+
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/networks");
+
+         /*
+          * Check response
+          */
+         assertTrue(networks.isEmpty());
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testGetNetwork() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/network_get_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         Network network = api.get("12345");
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/networks/12345");
+
+         /*
+          * Check response
+          */
+         assertNotNull(network);
+         assertEquals(network.getName(),"jclouds-wibble");
+         assertEquals(network.getId(),"624312ff-d14b-4ba3-9834-1c78d23d574d");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testGetNetworkFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         Network network = api.get("12345");
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/networks/12345");
+
+         /*
+          * Check response
+          */
+         assertNull(network);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testCreateNetworkBulk() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201).setBody(stringFromResource("/network_bulk_create_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         Network.CreateOptions createNetwork1 = Network.createOptions("jclouds-wibble")
+               .networkType(NetworkType.LOCAL)
+               .build();
+
+         Network.CreateOptions createNetwork2 = Network.createOptions("jclouds-wibble2")
+               .networkType(NetworkType.LOCAL)
+               .build();
+
+         FluentIterable<Network> networks = api.createBulk(ImmutableList.of(createNetwork1, createNetwork2));
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "POST", "/v2.0/networks", "/network_bulk_create_request.json");
+
+         /*
+          * Check response
+          */
+         assertNotNull(networks);
+         assertEquals(networks.size(), 2);
+         assertEquals(networks.get(0).getName(), "jclouds-wibble");
+         assertEquals(networks.get(0).getNetworkType(), NetworkType.LOCAL);
+         assertEquals(networks.get(0).getTenantId(), "1234567890");
+         assertEquals(networks.get(0).getStatus(), NetworkStatus.ACTIVE);
+         assertEquals(networks.get(0).getId(), "624312ff-d14b-4ba3-9834-1c78d23d574d");
+
+         assertEquals(networks.get(1).getName(), "jclouds-wibble2");
+         assertEquals(networks.get(1).getNetworkType(), NetworkType.LOCAL);
+         assertEquals(networks.get(1).getTenantId(), "1234567890");
+         assertEquals(networks.get(1).getStatus(), NetworkStatus.ACTIVE);
+         assertEquals(networks.get(1).getId(), "624312ff-d14b-4ba3-9834-1c78d23d574e");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testCreateNetworkBulkFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         Network.CreateOptions createNetwork1 = Network.createOptions("jclouds-wibble")
+               .networkType(NetworkType.LOCAL)
+               .build();
+
+         Network.CreateOptions createNetwork2 = Network.createOptions("jclouds-wibble2")
+               .networkType(NetworkType.LOCAL)
+               .build();
+
+         FluentIterable<Network> networks = api.createBulk(ImmutableList.of(createNetwork1, createNetwork2));
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testUpdateNetwork() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201).setBody(stringFromResource("/network_update_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         Network.UpdateOptions updateNetwork = Network.updateOptions()
+               .name("jclouds-wibble-updated")
+               .networkType(NetworkType.LOCAL)
+               .build();
+
+         Network network = api.update("123456", updateNetwork);
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/networks/123456","/network_update_request.json");
+
+         /*
+          * Check response
+          */
+         assertNotNull(network);
+         assertEquals(network.getName(),"updated_name");
+         assertEquals(network.getId(),"fc68ea2c-b60b-4b4f-bd82-94ec81110766");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testUpdateNetworkFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         Network.UpdateOptions updateNetwork = Network.updateOptions()
+               .name("jclouds-wibble-updated")
+               .networkType(NetworkType.LOCAL)
+               .build();
+
+         Network network = api.update("123456", updateNetwork);
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/networks/123456");
+
+         /*
+          * Check response
+          */
+         assertNull(network);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testDeleteNetwork() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         boolean result = api.delete("123456");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "DELETE", "/v2.0/networks/123456");
+
+         /*
+          * Check response
+          */
+         assertTrue(result);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testDeleteNetworkFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         NetworkApi api = neutronApi.getNetworkApiForZone("RegionOne");
+
+         boolean result = api.delete("123456");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "DELETE", "/v2.0/networks/123456");
+
+         /*
+          * Check response
+          */
+         assertFalse(result);
+      } finally {
+         server.shutdown();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiLiveTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiLiveTest.java
new file mode 100644
index 0000000..eec5a79
--- /dev/null
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiLiveTest.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.features;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import org.jclouds.openstack.neutron.v2.domain.IP;
+import org.jclouds.openstack.neutron.v2.domain.Network;
+import org.jclouds.openstack.neutron.v2.domain.NetworkType;
+import org.jclouds.openstack.neutron.v2.domain.Port;
+import org.jclouds.openstack.neutron.v2.domain.Subnet;
+import org.jclouds.openstack.neutron.v2.internal.BaseNeutronApiLiveTest;
+import org.jclouds.openstack.neutron.v2.util.PredicateUtil;
+import org.testng.annotations.Test;
+
+import java.util.Set;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Tests PortApi in combination with the Network & SubnetApi
+ */
+@Test(groups = "live", testName = "PortApiLiveTest")
+public class PortApiLiveTest extends BaseNeutronApiLiveTest {
+
+   public void testCreateUpdateAndDeletePort() {
+      for (String zone : api.getConfiguredRegions()) {
+         NetworkApi networkApi = api.getNetworkApiForZone(zone);
+         SubnetApi subnetApi = api.getSubnetApiForZone(zone);
+         PortApi portApi = api.getPortApiForZone(zone);
+         String networkId = networkApi.create(
+               Network.createOptions("JClouds-Live-Network").networkType(NetworkType.LOCAL).build()).getId();
+         String ipv4SubnetId = subnetApi.create(Subnet.createOptions(networkId, "198.51.100.0/24").ipVersion(4)
+               .name("JClouds-Live-IPv4-Subnet").build()).getId();
+         String ipv6SubnetId = subnetApi.create(Subnet.createOptions(networkId, "a1ca:1e1:c:107d::/96").ipVersion(6)
+               .name("JClouds-Live-IPv6-Subnet").build()).getId();
+
+         assertNotNull(networkId);
+         assertNotNull(ipv4SubnetId);
+         assertNotNull(ipv6SubnetId);
+
+         String ipv4PortId = portApi.create(Port.createOptions(networkId).name("JClouds-Live-IPv4-Port")
+               .fixedIps(ImmutableSet.copyOf(getFixedAddresses(ipv4SubnetId))).build()).getId();
+         String ipv6PortId = portApi.create(Port.createOptions(networkId).name("JClouds-Live-IPv6-Port")
+               .fixedIps(ImmutableSet.copyOf(getFixedAddresses(ipv6SubnetId))).build()).getId();
+
+         /* List and get test */
+         Port portList = api.getPortApiForZone(zone).list().concat().toSet().iterator().next();
+         assertNotNull(portList);
+         Port portGet = api.getPortApiForZone(zone).get(portList.getId());
+         assertEquals(portList, portGet);
+         /****/
+
+         assertNotNull(ipv4PortId);
+         assertNotNull(ipv6PortId);
+
+         Port ipv4Port = portApi.get(ipv4PortId);
+         assertNotNull(ipv4Port);
+         assertEquals(ipv4Port.getId(), ipv4PortId);
+         assertEquals(ipv4Port.getName(), "JClouds-Live-IPv4-Port");
+
+         Port ipv6Port = portApi.get(ipv6PortId);
+         assertNotNull(ipv6Port);
+         assertEquals(ipv6Port.getId(), ipv6PortId);
+         assertEquals(ipv6Port.getName(), "JClouds-Live-IPv6-Port");
+
+         assertNotNull(portApi.update(ipv4PortId, Port.updateOptions().name("Updated").build()));
+         Port updatedIpv4Port = portApi.get(ipv4PortId);
+         assertEquals(updatedIpv4Port.getName(), "Updated");
+
+         assertTrue(portApi.delete(ipv4PortId));
+         assertTrue(portApi.delete(ipv6PortId));
+         assertTrue(subnetApi.delete(ipv4SubnetId));
+         assertTrue(subnetApi.delete(ipv6SubnetId));
+         assertTrue(networkApi.delete(networkId));
+      }
+   }
+
+   public void testBulkCreatePort() {
+      for (String zone : api.getConfiguredRegions()) {
+         NetworkApi networkApi = api.getNetworkApiForZone(zone);
+         SubnetApi subnetApi = api.getSubnetApiForZone(zone);
+         PortApi portApi = api.getPortApiForZone(zone);
+
+         String networkId = networkApi.create(
+               Network.createOptions("JClouds-Live-Network").networkType(NetworkType.LOCAL).build()).getId();
+         String ipv4SubnetId = subnetApi.create(Subnet.createOptions(networkId, "198.51.100.0/24").ipVersion(4)
+               .name("JClouds-Live-IPv4-Subnet").build()).getId();
+         String ipv6SubnetId = subnetApi.create(Subnet.createOptions(networkId, "a1ca:1e1:c:107d::/96").ipVersion(6)
+               .name("JClouds-Live-IPv6-Subnet").build()).getId();
+
+         assertNotNull(networkId);
+         assertNotNull(ipv4SubnetId);
+         assertNotNull(ipv6SubnetId);
+
+         Set<? extends Port> ports = portApi.createBulk(
+               ImmutableList.of(
+                     Port.createOptions(networkId).name("JClouds-Live-IPv4-Subnet-1")
+                           .fixedIps(ImmutableSet.copyOf(getFixedAddresses(ipv4SubnetId))).build(),
+                     Port.createOptions(networkId).name("JClouds-Live-IPv4-Subnet-2")
+                           .fixedIps(ImmutableSet.copyOf(getFixedAddresses(ipv4SubnetId))).build(),
+                     Port.createOptions(networkId).name("JClouds-Live-IPv6-Subnet-1")
+                           .fixedIps(ImmutableSet.copyOf(getFixedAddresses(ipv6SubnetId))).build(),
+                     Port.createOptions(networkId).name("JClouds-Live-IPv6-Subnet-2")
+                           .fixedIps(ImmutableSet.copyOf(getFixedAddresses(ipv6SubnetId))).build()
+               )
+         ).toSet();
+         Set<? extends Port> existingPorts = portApi.list().concat().toSet();
+
+         assertNotNull(ports);
+         assertFalse(ports.isEmpty());
+         assertEquals(ports.size(), 4);
+
+         for (Port port : ports) {
+            Predicate<Port> idEqualsPredicate = PredicateUtil.createIdEqualsPredicate(port.getId());
+            assertEquals(1, Sets.filter(existingPorts, idEqualsPredicate).size());
+            assertTrue(portApi.delete(port.getId()));
+         }
+         assertTrue(subnetApi.delete(ipv4SubnetId));
+         assertTrue(subnetApi.delete(ipv6SubnetId));
+         assertTrue(networkApi.delete(networkId));
+      }
+   }
+
+   public Set<IP> getFixedAddresses(String subnetId) {
+      return ImmutableSet.of(
+         IP.builder().subnetId(subnetId).build()
+      );
+   }
+}


[2/5] Neutron Refactoring v2_0 -> v2 No options (redesign) More features (extension-related) Live tests Redesigned domain objects for create/update options.

Posted by za...@apache.org.
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiMockTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiMockTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiMockTest.java
new file mode 100644
index 0000000..22258b2
--- /dev/null
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiMockTest.java
@@ -0,0 +1,492 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.features;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import org.jclouds.openstack.neutron.v2.NeutronApi;
+import org.jclouds.openstack.neutron.v2.domain.AddressPair;
+import org.jclouds.openstack.neutron.v2.domain.NetworkStatus;
+import org.jclouds.openstack.neutron.v2.domain.Port;
+import org.jclouds.openstack.neutron.v2.domain.Ports;
+import org.jclouds.openstack.neutron.v2.domain.VIFType;
+import org.jclouds.openstack.neutron.v2.domain.VNICType;
+import org.jclouds.openstack.neutron.v2.internal.BaseNeutronApiMockTest;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Map;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Tests NetworkApi Guice wiring and parsing
+ *
+ */
+@Test
+public class PortApiMockTest extends BaseNeutronApiMockTest {
+
+   public void testCreatePort() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(201).setBody(stringFromResource("/port_create_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         Port.CreateOptions createPort = Port.createOptions("6aeaf34a-c482-4bd3-9dc3-7faf36412f12")
+               .name("port1")
+               .adminStateUp(true)
+               .deviceId("d6b4d3a5-c700-476f-b609-1493dd9dadc0")
+               .allowedAddressPairs(ImmutableSet.of(AddressPair.createOptions("12", "111.222.333.444").build()))
+               .build();
+
+         Port port = api.create(createPort);
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "POST", "/v2.0/ports", "/port_create_request.json");
+
+         /*
+          * Check response
+          */
+         assertNotNull(port);
+         assertEquals(port.getAllowedAddressPairs().iterator().next().getIpAddress(),"192.168.1.1");
+         assertEquals(port.getAllowedAddressPairs().iterator().next().getMacAddress(),"12:12");
+         assertEquals(port.getName(), "port1");
+         assertEquals(port.getStatus(), NetworkStatus.ACTIVE);
+         assertEquals(port.getId(), "ebe69f1e-bc26-4db5-bed0-c0afb4afe3db");
+         assertEquals(port.getDeviceId(), "d6b4d3a5-c700-476f-b609-1493dd9dadc0");
+         assertEquals(port.getDeviceOwner(), "");
+         assertEquals(port.getMacAddress(), "fa:16:3e:a6:50:c1");
+         assertEquals(port.getNetworkId(), "6aeaf34a-c482-4bd3-9dc3-7faf36412f12");
+         assertEquals(port.getFixedIps().iterator().next().getIpAddress(), "192.168.111.4");
+         assertEquals(port.getFixedIps().iterator().next().getSubnetId(), "22b44fc2-4ffb-4de4-b0f9-69d58b37ae27");
+         assertEquals(port.getTenantId(), "cf1a5775e766426cb1968766d0191908");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testCreatePortFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         Port.CreateOptions createPort = Port.createOptions("6aeaf34a-c482-4bd3-9dc3-7faf36412f12")
+               .name("port1")
+               .adminStateUp(true)
+               .deviceId("d6b4d3a5-c700-476f-b609-1493dd9dadc0")
+               .allowedAddressPairs(ImmutableSet.of(AddressPair.createOptions("12","111.222.333.444").build()))
+               .build();
+
+         Port port = api.create(createPort);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListSpecificPagePort() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/port_list_response_paged1.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         Ports ports = api.list(PaginationOptions.Builder.limit(2).marker("abcdefg"));
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/ports?limit=2&marker=abcdefg");
+
+         /*
+          * Check response
+          */
+         assertNotNull(ports);
+         assertEquals(ports.size(), 2);
+         assertEquals(ports.first().get().getId(),"24e6637e-c521-45fc-8b8b-d7331aa3c99f");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListSpecificPagePortFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         Ports ports = api.list(PaginationOptions.Builder.limit(2).marker("abcdefg"));
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/ports?limit=2&marker=abcdefg");
+
+         /*
+          * Check response
+          */
+         assertTrue(ports.isEmpty());
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListPagedPort() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/port_list_response_paged1.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/port_list_response_paged2.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         // Note: Lazy! Have to actually look at the collection.
+         List<Port> ports = api.list().concat().toList();
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 3);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/ports");
+         assertRequest(server.takeRequest(), "GET", "/v2.0/ports?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718");
+
+         /*
+          * Check response
+          */
+         assertNotNull(ports);
+         assertEquals(ports.size(), 4);
+         assertEquals(ports.get(0).getId(),"24e6637e-c521-45fc-8b8b-d7331aa3c99f");
+         assertEquals(ports.get(3).getId(),"e54dfd9b-ce6e-47f7-af47-1609cfd1cdb0_4");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListPagedPortFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         // Note: Lazy! Have to actually look at the collection.
+         List<Port> ports = api.list().concat().toList();
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/ports");
+
+         /*
+          * Check response
+          */
+         assertTrue(ports.isEmpty());
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testCreateBulkPort() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(201).setBody(stringFromResource("/port_create_bulk_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         Port.CreateOptions createPort1 = Port.createOptions("64239a54-dcc4-4b39-920b-b37c2144effa")
+               .name("port1")
+               .adminStateUp(true)
+               .deviceId("24df1d04-d5cb-41e1-8de5-61ed77c558df")
+               .securityGroups(ImmutableSet.of("dbc107f4-afcd-4d5a-9352-f68f82241d5b"))
+               .build();
+
+         Port.CreateOptions createPort2 = Port.createOptions("e6031bc2-901a-4c66-82da-f4c32ed89406")
+               .name("port2")
+               .adminStateUp(false)
+               .securityGroups(
+                     ImmutableSet.of("8bf3f7cc-8471-40b1-815f-9da47e79775b", "dbc107f4-afcd-4d5a-9352-f68f82241d5b"))
+               .build();
+
+         FluentIterable<Port> ports = api.createBulk(ImmutableList.of(createPort1, createPort2));
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "POST", "/v2.0/ports", "/port_create_bulk_request.json");
+
+         /*
+          * Check response
+          */
+         assertNotNull(ports);
+         assertEquals(ports.size(), 2);
+         assertEquals(ports.get(0).getName(), "port1");
+         assertEquals(ports.get(1).getName(), "port2");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testCreateBulkPortFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         Port.CreateOptions createPort1 = Port.createOptions("64239a54-dcc4-4b39-920b-b37c2144effa")
+               .name("port1")
+               .adminStateUp(true)
+               .deviceId("24df1d04-d5cb-41e1-8de5-61ed77c558df")
+               .securityGroups(ImmutableSet.of("dbc107f4-afcd-4d5a-9352-f68f82241d5b"))
+               .build();
+
+         Port.CreateOptions createPort2 = Port.createOptions("e6031bc2-901a-4c66-82da-f4c32ed89406")
+               .name("port2")
+               .adminStateUp(false)
+               .securityGroups(
+                     ImmutableSet.of("8bf3f7cc-8471-40b1-815f-9da47e79775b", "dbc107f4-afcd-4d5a-9352-f68f82241d5b"))
+               .build();
+
+         FluentIterable<Port> ports = api.createBulk(ImmutableList.of(createPort1, createPort2));
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testGetPort() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(201).setBody(stringFromResource("/port_get_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         Port port = api.get("12345");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/ports/12345");
+
+         /*
+          * Check response
+          */
+         assertNotNull(port);
+         assertEquals(port.getName(), "jclouds-wibble");
+         assertEquals(port.getStatus(), NetworkStatus.ACTIVE);
+         assertEquals(port.getId(), "624312ff-d14b-4ba3-9834-1c78d23d574d");
+         assertEquals(port.getTenantId(), "1234567890");
+         assertEquals(port.getNetworkId(), "1234567890");
+         assertEquals(port.getVnicType(), VNICType.NORMAL);
+         assertEquals(port.getVifType(), VIFType.HYPERV);
+         assertEquals(port.getVifDetails().get("name1"), "value1");
+         assertEquals(((Map<String, Double>)port.getVifDetails().get("name2")).get("mapname2").intValue(), 3);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testGetPortFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         Port port = api.get("12345");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/ports/12345");
+
+         /*
+          * Check response
+          */
+         assertNull(port);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testUpdatePort() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(201).setBody(stringFromResource("/port_update_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         Port.UpdateOptions updatePort = Port.updateOptions()
+               .securityGroups(
+                     ImmutableSet.of("85cc3048-abc3-43cc-89b3-377341426ac5", "c5ab5c29-2c99-44cb-a4b8-e70a88b77799"))
+               .build();
+
+         Port port = api.update("12345", updatePort);
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/ports/12345", "/port_update_request.json");
+
+         /*
+          * Check response
+          */
+         assertNotNull(port);
+         assertEquals(port.getId(), "1d8591f4-7b62-428e-857d-e82a15e5a7f1");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testUpdatePortFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         Port.UpdateOptions updatePort = Port.updateOptions()
+               .securityGroups(ImmutableSet.of("85cc3048-abc3-43cc-89b3-377341426ac5","c5ab5c29-2c99-44cb-a4b8-e70a88b77799"))
+               .build();
+
+         Port port = api.update("12345", updatePort);
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/ports/12345", "/port_update_request.json");
+
+         /*
+          * Check response
+          */
+         assertNull(port);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testDeletePort() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         boolean result = api.delete("12345");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "DELETE", "/v2.0/ports/12345");
+
+         /*
+          * Check response
+          */
+         assertTrue(result);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testDeletePortFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         PortApi api = neutronApi.getPortApiForZone("RegionOne");
+
+         boolean result = api.delete("12345");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "DELETE", "/v2.0/ports/12345");
+
+         /*
+          * Check response
+          */
+         assertFalse(result);
+      } finally {
+         server.shutdown();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/RouterApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/RouterApiLiveTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/RouterApiLiveTest.java
new file mode 100644
index 0000000..69625a3
--- /dev/null
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/RouterApiLiveTest.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.neutron.v2.features;
+
+import org.jclouds.openstack.neutron.v2.domain.ExternalGatewayInfo;
+import org.jclouds.openstack.neutron.v2.domain.Network;
+import org.jclouds.openstack.neutron.v2.domain.NetworkType;
+import org.jclouds.openstack.neutron.v2.domain.Port;
+import org.jclouds.openstack.neutron.v2.domain.Router;
+import org.jclouds.openstack.neutron.v2.domain.RouterInterface;
+import org.jclouds.openstack.neutron.v2.domain.Subnet;
+import org.jclouds.openstack.neutron.v2.extensions.RouterApi;
+import org.jclouds.openstack.neutron.v2.internal.BaseNeutronApiLiveTest;
+import org.testng.annotations.Test;
+
+import java.util.Set;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Tests parsing and Guice wiring of RouterApi
+ */
+@Test(groups = "live", testName = "RouterApiLiveTest")
+public class RouterApiLiveTest extends BaseNeutronApiLiveTest {
+
+   public void testCreateUpdateAndDeleteRouter() {
+      for (String zone : api.getConfiguredRegions()) {
+         RouterApi routerApi = api.getRouterExtensionForZone(zone).get();
+         NetworkApi networkApi = api.getNetworkApiForZone(zone);
+         SubnetApi subnetApi = api.getSubnetApiForZone(zone);
+
+         Network network = networkApi.create(
+               Network.createOptions("jclouds-network-test").external(true).networkType(NetworkType.LOCAL).build());
+         assertNotNull(network);
+
+         Subnet subnet = subnetApi.create(Subnet.createOptions(network.getId(), "192.168.0.0/16").ipVersion(4).build());
+         assertNotNull(subnet);
+
+         Router router = routerApi.create(Router.createOptions().name("jclouds-router-test")
+            .externalGatewayInfo(ExternalGatewayInfo.builder().networkId(network.getId()).build()).build());
+         assertNotNull(router);
+
+         /* List and Get test */
+         Set<Router> routers = api.getRouterExtensionForZone(zone).get().list().concat().toSet();
+         Router routerList = routers.iterator().next();
+         Router routerGet = api.getRouterExtensionForZone(zone).get().get(routerList.getId());
+
+         assertNotNull(routerGet);
+         assertEquals(routerGet, routerList);
+         /***/
+
+         routerGet = routerApi.get(router.getId());
+
+         assertEquals(routerGet.getName(), router.getName());
+         assertEquals(routerGet.getId(), router.getId());
+         assertEquals(routerGet.getExternalGatewayInfo(), router.getExternalGatewayInfo());
+
+         Router routerUpdate = routerApi.update(router.getId(), Router.updateOptions().name("jclouds-router-test-rename").build());
+         assertNotNull(routerUpdate);
+         assertEquals(routerUpdate.getName(), "jclouds-router-test-rename");
+
+         routerGet = routerApi.get(router.getId());
+
+         assertEquals(routerGet.getId(), router.getId());
+         assertEquals(routerGet.getName(), "jclouds-router-test-rename");
+
+         assertTrue(routerApi.delete(router.getId()));
+         assertTrue(subnetApi.delete(subnet.getId()));
+         assertTrue(networkApi.delete(network.getId()));
+      }
+   }
+
+   public void testCreateAndDeleteRouterInterfaceForSubnet() {
+      for (String zone : api.getConfiguredRegions()) {
+         RouterApi routerApi = api.getRouterExtensionForZone(zone).get();
+         NetworkApi networkApi = api.getNetworkApiForZone(zone);
+         SubnetApi subnetApi = api.getSubnetApiForZone(zone);
+
+         Network network = networkApi.create(Network.createOptions("jclouds-network-test").external(true).networkType(NetworkType.LOCAL).build());
+         assertNotNull(network);
+
+         Subnet subnet = subnetApi.create(Subnet.createOptions(network.getId(), "192.168.0.0/16").ipVersion(4).build());
+         assertNotNull(subnet);
+
+         Network network2 = networkApi.create(Network.createOptions("jclouds-network-test2").external(true).networkType(NetworkType.LOCAL).build());
+         assertNotNull(network2);
+
+         Subnet subnet2 = subnetApi.create(Subnet.createOptions(network2.getId(), "192.169.0.0/16").ipVersion(4).build());
+         assertNotNull(subnet2);
+
+         Router router = routerApi.create(Router.createOptions().name("jclouds-router-test").build());
+         assertNotNull(router);
+
+         RouterInterface routerInterface = routerApi.addInterfaceForSubnet(router.getId(), subnet.getId());
+         assertNotNull(routerInterface);
+
+         RouterInterface routerInterface2 = routerApi.addInterfaceForSubnet(router.getId(), subnet2.getId());
+         assertNotNull(routerInterface2);
+
+         assertTrue(routerApi.removeInterfaceForSubnet(router.getId(), subnet.getId()));
+         assertTrue(routerApi.removeInterfaceForSubnet(router.getId(), subnet2.getId()));
+         assertTrue(routerApi.delete(router.getId()));
+         assertTrue(subnetApi.delete(subnet.getId()));
+         assertTrue(networkApi.delete(network.getId()));
+         assertTrue(subnetApi.delete(subnet2.getId()));
+         assertTrue(networkApi.delete(network2.getId()));
+      }
+   }
+
+   public void testCreateAndDeleteRouterInterfaceForPort() {
+      for (String zone : api.getConfiguredRegions()) {
+         RouterApi routerApi = api.getRouterExtensionForZone(zone).get();
+         NetworkApi networkApi = api.getNetworkApiForZone(zone);
+         SubnetApi subnetApi = api.getSubnetApiForZone(zone);
+         PortApi portApi = api.getPortApiForZone(zone);
+
+         Network network = networkApi.create(Network.createOptions("jclouds-network-test").external(true).networkType(NetworkType.LOCAL).build());
+         assertNotNull(network);
+
+         Subnet subnet = subnetApi.create(Subnet.createOptions(network.getId(), "192.168.0.0/16").ipVersion(4).build());
+         assertNotNull(subnet);
+
+         Network network2 = networkApi.create(Network.createOptions("jclouds-network-test2").external(true).networkType(NetworkType.LOCAL).build());
+         assertNotNull(network2);
+
+         Subnet subnet2 = subnetApi.create(Subnet.createOptions(network2.getId(), "192.169.0.0/16").ipVersion(4).build());
+         assertNotNull(subnet2);
+
+         Port port = portApi.create(Port.createOptions(network.getId()).build());
+         assertNotNull(port);
+
+         Port port2 = portApi.create(Port.createOptions(network2.getId()).build());
+         assertNotNull(port2);
+
+         Router router = routerApi.create(Router.createOptions().name("jclouds-router-test").build());
+         assertNotNull(router);
+
+         RouterInterface routerInterface = routerApi.addInterfaceForPort(router.getId(), port.getId());
+         assertNotNull(routerInterface);
+
+         RouterInterface routerInterface2 = routerApi.addInterfaceForPort(router.getId(), port2.getId());
+         assertNotNull(routerInterface2);
+
+         assertTrue(routerApi.removeInterfaceForPort(router.getId(), port.getId()));
+         assertTrue(routerApi.removeInterfaceForPort(router.getId(), port2.getId()));
+         assertTrue(routerApi.delete(router.getId()));
+         assertTrue(subnetApi.delete(subnet.getId()));
+         assertTrue(networkApi.delete(network.getId()));
+         assertTrue(subnetApi.delete(subnet2.getId()));
+         assertTrue(networkApi.delete(network2.getId()));
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/RouterApiMockTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/RouterApiMockTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/RouterApiMockTest.java
new file mode 100644
index 0000000..bcbb8db
--- /dev/null
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/RouterApiMockTest.java
@@ -0,0 +1,631 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.features;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import org.jclouds.openstack.neutron.v2.NeutronApi;
+import org.jclouds.openstack.neutron.v2.domain.ExternalGatewayInfo;
+import org.jclouds.openstack.neutron.v2.domain.NetworkStatus;
+import org.jclouds.openstack.neutron.v2.domain.Router;
+import org.jclouds.openstack.neutron.v2.domain.RouterInterface;
+import org.jclouds.openstack.neutron.v2.domain.Routers;
+import org.jclouds.openstack.neutron.v2.extensions.RouterApi;
+import org.jclouds.openstack.neutron.v2.internal.BaseNeutronApiMockTest;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+/**
+ * Tests NetworkApi Guice wiring and parsing
+ *
+ */
+@Test
+public class RouterApiMockTest extends BaseNeutronApiMockTest {
+
+   public void testCreateRouter() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(201).setBody(stringFromResource("/router_create_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         Router.CreateOptions createRouter = Router.createOptions().name("another_router").adminStateUp(true)
+               .externalGatewayInfo(ExternalGatewayInfo.builder().networkId("8ca37218-28ff-41cb-9b10-039601ea7e6b").build())
+               .build();
+
+         Router router = api.create(createRouter);
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "POST", "/v2.0/routers", "/router_create_request.json");
+
+         /*
+          * Check response
+          */
+         assertNotNull(router);
+         assertEquals(router.getName(), "another_router");
+         assertEquals(router.getExternalGatewayInfo().getNetworkId(), "8ca37218-28ff-41cb-9b10-039601ea7e6b");
+         assertEquals(router.getStatus(), NetworkStatus.ACTIVE);
+         assertEquals(router.isAdminStateUp().booleanValue(), true);
+         assertEquals(router.getId(), "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e");
+         assertEquals(router.getTenantId(), "6b96ff0cb17a4b859e1e575d221683d3");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testCreateRouterFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         Router.CreateOptions createRouter = Router.createOptions().name("another_router").adminStateUp(true)
+               .externalGatewayInfo(ExternalGatewayInfo.builder().networkId("8ca37218-28ff-41cb-9b10-039601ea7e6b").build())
+               .build();
+
+         Router router = api.create(createRouter);
+         fail("Should have failed with not found exception");
+
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListSpecificPagePort() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/router_list_response_paged1.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         Routers routers = api.list(PaginationOptions.Builder.limit(2).marker("abcdefg"));
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/routers?limit=2&marker=abcdefg");
+
+         /*
+          * Check response
+          */
+         assertNotNull(routers);
+         assertEquals(routers.size(), 2);
+         assertEquals(routers.first().get().getId(),"a9254bdb-2613-4a13-ac4c-adc581fba50d");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListSpecificPagePortFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         Routers routers = api.list(PaginationOptions.Builder.limit(2).marker("abcdefg"));
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/routers?limit=2&marker=abcdefg");
+
+         /*
+          * Check response
+          */
+         assertNotNull(routers);
+         assertTrue(routers.isEmpty());
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListPagedRouter() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/router_list_response_paged1.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/router_list_response_paged2.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         // Note: Lazy! Have to actually look at the collection.
+         List<Router> routers = api.list().concat().toList();
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 3);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/routers");
+         assertRequest(server.takeRequest(), "GET", "/v2.0/routers?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718");
+
+         /*
+          * Check response
+          */
+         assertNotNull(routers);
+         assertEquals(routers.size(), 4);
+         assertEquals(routers.get(0).getId(),"a9254bdb-2613-4a13-ac4c-adc581fba50d");
+         assertEquals(routers.get(3).getId(),"a9254bdb-2613-4a13-ac4c-adc581fba50d_4");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListPagedRouterFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         // Note: Lazy! Have to actually look at the collection.
+         List<Router> routers = api.list().concat().toList();
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/routers");
+
+         /*
+          * Check response
+          */
+         assertNotNull(routers);
+         assertTrue(routers.isEmpty());
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testGetRouter() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(201).setBody(stringFromResource("/router_get_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         Router router = api.get("12345");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/routers/12345");
+
+         /*
+          * Check response
+          */
+         assertNotNull(router);
+         assertEquals(router.getName(), "router1");
+         assertEquals(router.getExternalGatewayInfo().getNetworkId(), "3c5bcddd-6af9-4e6b-9c3e-c153e521cab8");
+         assertEquals(router.getStatus(), NetworkStatus.ACTIVE);
+         assertEquals(router.isAdminStateUp().booleanValue(), true);
+         assertEquals(router.getId(), "a9254bdb-2613-4a13-ac4c-adc581fba50d");
+         assertEquals(router.getTenantId(), "33a40233088643acb66ff6eb0ebea679");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testGetRouterFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         Router router = api.get("12345");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/routers/12345");
+
+         /*
+          * Check response
+          */
+         assertNull(router);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testUpdateRouter() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(201).setBody(stringFromResource("/router_update_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         Router.UpdateOptions updateOptions = Router.updateOptions()
+               .externalGatewayInfo(
+                     ExternalGatewayInfo.builder().networkId("8ca37218-28ff-41cb-9b10-039601ea7e6b").build())
+               .build();
+
+         Router router = api.update("12345", updateOptions);
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/routers/12345", "/router_update_request.json");
+
+         /*
+          * Check response
+          */
+         assertNotNull(router);
+         assertEquals(router.getName(), "another_router");
+         assertEquals(router.getExternalGatewayInfo().getNetworkId(), "8ca37218-28ff-41cb-9b10-039601ea7e6b");
+         assertEquals(router.getStatus(), NetworkStatus.ACTIVE);
+         assertEquals(router.isAdminStateUp().booleanValue(), true);
+         assertEquals(router.getId(), "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e");
+         assertEquals(router.getTenantId(), "6b96ff0cb17a4b859e1e575d221683d3");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testUpdateRouterFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         Router.UpdateOptions updateOptions = Router.updateOptions()
+               .externalGatewayInfo(
+                     ExternalGatewayInfo.builder().networkId("8ca37218-28ff-41cb-9b10-039601ea7e6b").build())
+               .build();
+
+         Router router = api.update("12345", updateOptions);
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/routers/12345", "/router_update_request.json");
+
+         /*
+          * Check response
+          */
+         assertNull(router);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testDeleteRouter() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(201)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         boolean result = api.delete("12345");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "DELETE", "/v2.0/routers/12345");
+
+         /*
+          * Check response
+          */
+         assertTrue(result);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testDeleteRouterFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         boolean result = api.delete("12345");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "DELETE", "/v2.0/routers/12345");
+
+         /*
+          * Check response
+          */
+         assertFalse(result);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testAddRouterInterfaceForSubnet() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(201).setBody(stringFromResource("/router_add_interface_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         RouterInterface routerInterface = api.addInterfaceForSubnet("12345", "a2f1f29d-571b-4533-907f-5803ab96ead1");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/routers/12345/add_router_interface", "/router_add_interface_request.json");
+
+         /*
+          * Check response
+          */
+         assertNotNull(routerInterface);
+         assertEquals(routerInterface.getSubnetId(), "a2f1f29d-571b-4533-907f-5803ab96ead1");
+         assertEquals(routerInterface.getPortId(), "3a44f4e5-1694-493a-a1fb-393881c673a4");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testAddRouterInterfaceForSubnetFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         RouterInterface routerInterface = api.addInterfaceForSubnet("12345", "a2f1f29d-571b-4533-907f-5803ab96ead1");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/routers/12345/add_router_interface", "/router_add_interface_request.json");
+
+         /*
+          * Check response
+          */
+         assertNull(routerInterface);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testAddRouterInterfaceForPort() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(201).setBody(stringFromResource("/router_add_interface_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         RouterInterface routerInterface = api.addInterfaceForPort("12345", "portid");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/routers/12345/add_router_interface", "/router_add_interface_port_request.json");
+
+         /*
+          * Check response
+          */
+         assertNotNull(routerInterface);
+         assertEquals(routerInterface.getSubnetId(), "a2f1f29d-571b-4533-907f-5803ab96ead1");
+         assertEquals(routerInterface.getPortId(), "3a44f4e5-1694-493a-a1fb-393881c673a4");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testAddRouterInterfaceForPortFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         RouterInterface routerInterface = api.addInterfaceForPort("12345", "portid");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/routers/12345/add_router_interface", "/router_add_interface_port_request.json");
+
+         /*
+          * Check response
+          */
+         assertNull(routerInterface);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testRemoveRouterInterfaceForSubnet() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(201)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         boolean result = api.removeInterfaceForSubnet("12345", "a2f1f29d-571b-4533-907f-5803ab96ead1");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/routers/12345/remove_router_interface", "/router_remove_interface_subnet_request.json");
+
+         /*
+          * Check response
+          */
+         assertTrue(result);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testRemoveRouterInterfaceForSubnetFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         boolean result = api.removeInterfaceForSubnet("12345", "a2f1f29d-571b-4533-907f-5803ab96ead1");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/routers/12345/remove_router_interface", "/router_remove_interface_subnet_request.json");
+
+         /*
+          * Check response
+          */
+         assertFalse(result);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testRemoveRouterInterfaceForPort() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(201)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         boolean result = api.removeInterfaceForPort("12345", "portid");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/routers/12345/remove_router_interface", "/router_remove_interface_port_request.json");
+
+         /*
+          * Check response
+          */
+         assertTrue(result);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testRemoveRouterInterfaceForPortFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(
+            new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         RouterApi api = neutronApi.getRouterExtensionForZone("RegionOne").get();
+
+         boolean result = api.removeInterfaceForPort("12345", "portid");
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/routers/12345/remove_router_interface", "/router_remove_interface_port_request.json");
+
+         /*
+          * Check response
+          */
+         assertFalse(result);
+      } finally {
+         server.shutdown();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/SubnetApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/SubnetApiLiveTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/SubnetApiLiveTest.java
new file mode 100644
index 0000000..84b8228
--- /dev/null
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/SubnetApiLiveTest.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.features;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import org.jclouds.openstack.neutron.v2.domain.AllocationPool;
+import org.jclouds.openstack.neutron.v2.domain.HostRoute;
+import org.jclouds.openstack.neutron.v2.domain.Network;
+import org.jclouds.openstack.neutron.v2.domain.NetworkType;
+import org.jclouds.openstack.neutron.v2.domain.Subnet;
+import org.jclouds.openstack.neutron.v2.internal.BaseNeutronApiLiveTest;
+import org.jclouds.openstack.neutron.v2.util.PredicateUtil;
+import org.testng.annotations.Test;
+
+import java.util.Set;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Tests subnet api in combination with the network api
+ */
+@Test(groups = "live", testName = "SubnetApiLiveTest")
+public class SubnetApiLiveTest extends BaseNeutronApiLiveTest {
+
+   public void testCreateUpdateAndDeleteSubnet() {
+      for (String zone : api.getConfiguredRegions()) {
+         NetworkApi networkApi = api.getNetworkApiForZone(zone);
+         String networkId = networkApi.create(Network.createOptions("jclouds-live-test").networkType(NetworkType.LOCAL).build()).getId();
+
+         SubnetApi subnetApi = api.getSubnetApiForZone(zone);
+         ImmutableSet<AllocationPool> allocationPools = ImmutableSet.of(
+            AllocationPool.builder().start("a3:bc00::10").end("a3:bc00::20").build(),
+            AllocationPool.builder().start("a3:bc00::50").end("a3:bc00::90").build()
+         );
+         ImmutableSet<HostRoute> hostRoutes = ImmutableSet.of(
+            HostRoute.builder().destinationCidr("a3:bc00::/48").nextHop("a3:bc00::0004").build()
+         );
+         Subnet subnet = subnetApi.create(Subnet.createOptions(networkId, "a3:bc00::/48").ipVersion(6).allocationPools(allocationPools).hostRoutes(hostRoutes).build());
+         assertNotNull(subnet);
+
+         /* Test list and get */
+         Subnet subnetList = api.getSubnetApiForZone(zone).list().concat().toSet().iterator().next();
+         assertNotNull(subnetList);
+         Subnet subnetGet = api.getSubnetApiForZone(zone).get(subnetList.getId());
+         assertEquals(subnetList, subnetGet);
+         /***/
+
+         Subnet retrievedSubnet = subnetApi.get(subnet.getId());
+
+         assertEquals(retrievedSubnet.getId(), subnet.getId());
+         assertEquals(retrievedSubnet.getCidr(), "a3:bc00::/48");
+         assertTrue(retrievedSubnet.getDnsNameservers().isEmpty());
+         assertEquals(retrievedSubnet.getAllocationPools().size(), 2);
+         assertEquals(retrievedSubnet.getHostRoutes().size(), 1);
+         assertNotNull(subnetApi.update(retrievedSubnet.getId(), Subnet.updateOptions().name("jclouds-live-test-update").build()));
+
+         retrievedSubnet = subnetApi.get(retrievedSubnet.getId());
+
+         assertEquals(retrievedSubnet.getId(), subnet.getId());
+         assertEquals(retrievedSubnet.getName(), "jclouds-live-test-update");
+         assertTrue(retrievedSubnet.getDnsNameservers().isEmpty());
+
+         Subnet subnet2 = subnetApi.create(Subnet.createOptions(networkId, "a3:bd01::/48").ipVersion(6).build());
+         assertNotNull(subnet2);
+
+         assertTrue(subnetApi.delete(subnet.getId()));
+         assertTrue(subnetApi.delete(subnet2.getId()));
+         assertTrue(networkApi.delete(networkId));
+      }
+   }
+
+   public void testBulkCreateSubnet() {
+      for (String zone : api.getConfiguredRegions()) {
+         NetworkApi networkApi = api.getNetworkApiForZone(zone);
+         String networkId = networkApi.create(Network.createOptions("jclouds-live-test").networkType(NetworkType.LOCAL).build()).getId();
+
+         SubnetApi subnetApi = api.getSubnetApiForZone(zone);
+         Set<? extends Subnet> subnets = subnetApi.createBulk(
+               ImmutableList.of(
+                  Subnet.createOptions("jclouds-live-test-1", "a3:bd01::/48").ipVersion(6).networkId(networkId).build(),
+                  Subnet.createOptions("jclouds-live-test-2", "a3:bd02::/48").ipVersion(6).networkId(networkId).build(),
+                  Subnet.createOptions("jclouds-live-test-3", "a3:bd03::/48").ipVersion(6).networkId(networkId).build()
+               )
+         ).toSet();
+         Set<Subnet> existingSubnets = subnetApi.list().concat().toSet();
+
+         assertNotNull(subnets);
+         assertTrue(!subnets.isEmpty());
+         assertEquals(subnets.size(), 3);
+
+         for (Subnet net : subnets) {
+            Predicate<Subnet> idEqualsPredicate = PredicateUtil.createIdEqualsPredicate(net.getId());
+            assertEquals(1, Sets.filter(existingSubnets, idEqualsPredicate).size());
+            assertTrue(subnetApi.delete(net.getId()));
+         }
+         assertTrue(networkApi.delete(networkId));
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/SubnetApiMockTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/SubnetApiMockTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/SubnetApiMockTest.java
new file mode 100644
index 0000000..7e725bf
--- /dev/null
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/SubnetApiMockTest.java
@@ -0,0 +1,472 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.features;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import org.jclouds.openstack.neutron.v2.NeutronApi;
+import org.jclouds.openstack.neutron.v2.domain.IPv6DHCPMode;
+import org.jclouds.openstack.neutron.v2.domain.Subnet;
+import org.jclouds.openstack.neutron.v2.domain.Subnets;
+import org.jclouds.openstack.neutron.v2.internal.BaseNeutronApiMockTest;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Tests NetworkApi Guice wiring and parsing
+ *
+ */
+@Test
+public class SubnetApiMockTest extends BaseNeutronApiMockTest {
+
+   public void testCreateSubnet() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201).setBody(stringFromResource("/subnet_create_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         Subnet.CreateOptions createSubnet = Subnet.createOptions("1234567890", "10.0.3.0/24")
+               .name("jclouds-wibble")
+               .ipVersion(4)
+               .build();
+
+         Subnet subnet = api.create(createSubnet);
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "POST", "/v2.0/subnets", "/subnet_create_request.json");
+
+         /*
+          * Check response
+          */
+         assertNotNull(subnet);
+         assertEquals(subnet.getName(),"jclouds-wibble");
+         assertEquals(subnet.getIpVersion().intValue(), 4);
+         assertEquals(subnet.getCidr(), "10.0.3.0/24");
+         assertEquals(subnet.getTenantId(), "1234567890");
+         assertEquals(subnet.getId(), "624312ff-d14b-4ba3-9834-1c78d23d574d");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testCreateSubnetFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         Subnet.CreateOptions createSubnet = Subnet.createOptions("1234567890", "cidr")
+               .name("jclouds-wibble")
+               .ipVersion(4)
+               .build();
+
+         Subnet subnet = api.create(createSubnet);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListSpecificPageSubnet() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/subnet_list_response_pages1.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         Subnets subnets = api.list(PaginationOptions.Builder.limit(2).marker("abcdefg"));
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/subnets?limit=2&marker=abcdefg");
+
+         /*
+          * Check response
+          */
+         assertNotNull(subnets);
+         assertEquals(subnets.first().get().getId(),"16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListSpecificPageSubnetFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         Subnets subnets = api.list(PaginationOptions.Builder.limit(2).marker("abcdefg"));
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/subnets?limit=2&marker=abcdefg");
+
+         /*
+          * Check response
+          */
+         assertTrue(subnets.isEmpty());
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListPagedSubnet() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/subnet_list_response_pages1.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/subnet_list_response_pages2.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         // Note: Lazy! Have to actually look at the collection.
+         List<Subnet> subnets = api.list().concat().toList();
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 3);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/subnets");
+         assertRequest(server.takeRequest(), "GET", "/v2.0/subnets?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718");
+
+         /*
+          * Check response
+          */
+         assertNotNull(subnets);
+         assertEquals(subnets.size(), 4);
+         assertEquals(subnets.get(0).getId(),"16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+         assertEquals(subnets.get(3).getId(),"6ba4c788-661f-49ab-9bf8-5f10cbbb2f57");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testListPagedSubnetFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         // Note: Lazy! Have to actually look at the collection.
+         List<Subnet> subnets = api.list().concat().toList();
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/subnets");
+
+         /*
+          * Check response
+          */
+         assertTrue(subnets.isEmpty());
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testGetSubnet() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/subnet_get_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         Subnet subnet = api.get("12345");
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/subnets/12345");
+
+         /*
+          * Check response
+          */
+         assertNotNull(subnet);
+         assertEquals(subnet.getName(),"jclouds-wibble");
+         assertEquals(subnet.getId(),"624312ff-d14b-4ba3-9834-1c78d23d574d");
+         assertEquals(subnet.getTenantId(),"1234567890");
+         assertEquals(subnet.getIPv6AddressMode(), IPv6DHCPMode.SLAAC);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testGetSubnetFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         Subnet subnet = api.get("12345");
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "GET", "/v2.0/subnets/12345");
+
+         /*
+          * Check response
+          */
+         assertNull(subnet);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testCreateBulkSubnet() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201).setBody(stringFromResource("/subnet_bulk_create_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         Subnet.CreateOptions createSubnet1 = Subnet.createOptions("e6031bc2-901a-4c66-82da-f4c32ed89406",
+               "192.168.199.0/24")
+               .ipVersion(4)
+               .build();
+
+         Subnet.CreateOptions createSubnet2 = Subnet.createOptions("64239a54-dcc4-4b39-920b-b37c2144effa",
+               "10.56.4.0/22")
+               .ipVersion(4)
+               .build();
+
+         FluentIterable<Subnet> subnets = api.createBulk(ImmutableList.of(createSubnet1, createSubnet2));
+
+         /*
+          * Check request
+          */
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "POST", "/v2.0/subnets", "/subnet_bulk_create_request.json");
+
+         /*
+          * Check response
+          */
+         assertNotNull(subnets);
+         assertEquals(subnets.size(), 2);
+         assertEquals(subnets.get(0).getName(), "");
+         assertEquals(subnets.get(0).getIpVersion().intValue(), 4);
+         assertEquals(subnets.get(0).getCidr(), "192.168.199.0/24");
+         assertTrue(subnets.get(0).getDnsNameservers().isEmpty());
+         assertTrue(subnets.get(0).getEnableDhcp());
+         assertTrue(subnets.get(0).getHostRoutes().isEmpty());
+         assertEquals(subnets.get(0).getTenantId(), "d19231fc08ec4bc4829b668040d34512");
+         assertEquals(subnets.get(0).getId(), "0468a7a7-290d-4127-aedd-6c9449775a24");
+         assertEquals(subnets.get(0).getNetworkId(), "e6031bc2-901a-4c66-82da-f4c32ed89406");
+         assertEquals(subnets.get(0).getAllocationPools().iterator().next().getStart(), "192.168.199.2");
+         assertEquals(subnets.get(0).getAllocationPools().iterator().next().getEnd(), "192.168.199.254");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testCreateBulkSubnetFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         Subnet.CreateOptions createSubnet1 = Subnet.createOptions("e6031bc2-901a-4c66-82da-f4c32ed89406",
+               "192.168.199.0/24")
+               .ipVersion(4)
+               .build();
+
+         Subnet.CreateOptions createSubnet2 = Subnet.createOptions("64239a54-dcc4-4b39-920b-b37c2144effa",
+               "10.56.4.0/22")
+               .ipVersion(4)
+               .build();
+
+         FluentIterable<Subnet> subnets = api.createBulk(ImmutableList.of(createSubnet1, createSubnet2));
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testUpdateSubnet() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/subnet_update_response.json"))));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         Subnet.UpdateOptions updateSubnet = Subnet.updateOptions()
+               .name("new_name")
+               .gatewayIp("10.0.3.254")
+               .build();
+
+         Subnet subnet = api.update("12345", updateSubnet);
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/subnets/12345", "/subnet_update_request.json");
+
+         /*
+          * Check response
+          */
+         assertNotNull(subnet);
+         assertEquals(subnet.getName(),"new_name");
+         assertEquals(subnet.getId(),"9436e561-47bf-436a-b1f1-fe23a926e031");
+         assertEquals(subnet.getTenantId(),"c1210485b2424d48804aad5d39c61b8f");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testUpdateSubnetFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         Subnet.UpdateOptions updateSubnet = Subnet.updateOptions()
+               .name("new_name")
+               .gatewayIp("10.0.3.254")
+               .build();
+
+         Subnet subnet = api.update("12345", updateSubnet);
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "PUT", "/v2.0/subnets/12345", "/subnet_update_request.json");
+
+         /*
+          * Check response
+          */
+         assertNull(subnet);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testDeleteSubnet() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         boolean result = api.delete("12345");
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "DELETE", "/v2.0/subnets/12345");
+
+         /*
+          * Check response
+          */
+         assertTrue(result);
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void testDeleteSubnetFail() throws IOException, InterruptedException, URISyntaxException {
+      MockWebServer server = mockOpenStackServer();
+      server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
+      server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404)));
+
+      try {
+         NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides);
+         SubnetApi api = neutronApi.getSubnetApiForZone("RegionOne");
+
+         boolean result = api.delete("12345");
+
+         /*
+          * Check request
+          */
+         assertEquals(server.getRequestCount(), 2);
+         assertAuthentication(server);
+         assertRequest(server.takeRequest(), "DELETE", "/v2.0/subnets/12345");
+
+         /*
+          * Check response
+          */
+         assertFalse(result);
+      } finally {
+         server.shutdown();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/internal/BaseNeutronApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/internal/BaseNeutronApiLiveTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/internal/BaseNeutronApiLiveTest.java
new file mode 100644
index 0000000..7ebcaf6
--- /dev/null
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/internal/BaseNeutronApiLiveTest.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.internal;
+
+import org.jclouds.apis.BaseApiLiveTest;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
+import org.jclouds.openstack.neutron.v2.NeutronApi;
+import org.testng.annotations.Test;
+
+import java.util.Properties;
+
+/**
+ * Tests behavior of {@code NeutronApi}
+ *
+ */
+@Test(groups = "live")
+public class BaseNeutronApiLiveTest extends BaseApiLiveTest<NeutronApi> {
+
+   public BaseNeutronApiLiveTest() {
+      provider = "openstack-neutron";
+   }
+
+   @Override
+   protected Properties setupProperties() {
+      Properties props = super.setupProperties();
+      setIfTestSystemPropertyPresent(props, KeystoneProperties.CREDENTIAL_TYPE);
+      return props;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/internal/BaseNeutronApiMockTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/internal/BaseNeutronApiMockTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/internal/BaseNeutronApiMockTest.java
new file mode 100644
index 0000000..a1ac790
--- /dev/null
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/internal/BaseNeutronApiMockTest.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.internal;
+
+import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
+import org.jclouds.openstack.neutron.v2.NeutronApi;
+import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest;
+
+import java.util.Properties;
+
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+
+/**
+ * Base class for writing Neutron Mock tests
+ *
+ */
+public class BaseNeutronApiMockTest extends BaseOpenStackMockTest<NeutronApi> {
+   protected Properties overrides;
+   /**
+    * Base Mock Test
+    */
+   public BaseNeutronApiMockTest() {
+      overrides = new Properties();
+      //overrides.setProperty(SERVICE_TYPE, "neutron");
+      overrides.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/util/ClassUtil.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/util/ClassUtil.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/util/ClassUtil.java
new file mode 100644
index 0000000..b9ba915
--- /dev/null
+++ b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/util/ClassUtil.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.neutron.v2.util;
+
+import java.lang.reflect.Field;
+
+public class ClassUtil {
+
+    public static Field findField(Class clazz, String fieldName) {
+        Field fieldToFind = null;
+        if (clazz.getSuperclass() != null)
+            fieldToFind = findField(clazz.getSuperclass(), fieldName);
+
+        if (fieldToFind != null)
+            return fieldToFind;
+
+        for (Field field : clazz.getDeclaredFields()) {
+            if (field.getName().equals(fieldName))
+                return field;
+        }
+        return null;
+    }
+
+}


[4/5] Neutron Refactoring v2_0 -> v2 No options (redesign) More features (extension-related) Live tests Redesigned domain objects for create/update options.

Posted by za...@apache.org.
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Port.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Port.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Port.java
new file mode 100644
index 0000000..404961f
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Port.java
@@ -0,0 +1,765 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.javax.annotation.Nullable;
+
+import javax.inject.Named;
+import java.beans.ConstructorProperties;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A Neutron port
+ *
+ * @see <a
+ *      href="http://docs.openstack.org/api/openstack-network/1.0/content/Ports.html">api
+ *      doc</a>
+ */
+public class Port {
+
+   private String id;
+   private NetworkStatus status;
+
+   // Extensions
+
+   // portbindings.py
+   // The service will return the vif type for the specific port.
+   @Named("binding:vif_type")
+   private VIFType vifType;
+   // The service may return a dictionary containing additional
+   // information needed by the interface driver. The set of items
+   // returned may depend on the value of VIF_TYPE.
+   @Named("binding:vif_details")
+   private ImmutableMap<String, Object> vifDetails;
+
+   // Plugins
+
+   // qos.py
+   @Named("queue_id")
+   private String qosQueueId;
+
+   private String name;
+   @Named("network_id")
+   private String networkId;
+   @Named("admin_state_up")
+   private Boolean adminStateUp;
+   @Named("mac_address")
+   private String macAddress;
+   @Named("fixed_ips")
+   private ImmutableSet<IP> fixedIps;
+   @Named("device_id")
+   private String deviceId;
+   @Named("device_owner")
+   private String deviceOwner;
+   @Named("tenant_id")
+   private String tenantId;
+   @Named("security_groups")
+   private ImmutableSet<String> securityGroups;
+
+   // Extensions
+
+   // allowedaddresspairs.py
+   @Named("allowed_address_pairs")
+   private ImmutableSet<AddressPair> allowedAddressPairs;
+
+   // extra_dhcp_opt.py
+   @Named("extra_dhcp_opts")
+   private ImmutableSet<ExtraDhcpOption> extraDhcpOptions;
+
+   // portbindings.py
+   // The type of vnic that this port should be attached to
+   @Named("binding:vnic_type")
+   private VNICType vnicType;
+   // In some cases different implementations may be run on different hosts.
+   // The host on which the port will be allocated.
+   @Named("binding:host_id")
+   private String hostId;
+   // The profile will be a dictionary that enables the application running
+   // on the specific host to pass and receive vif port specific information to
+   // the plugin.
+   @Named("binding:profile")
+   private ImmutableMap<String, Object> profile;
+
+   // portsecurity.py
+   @Named("port_security_enabled")
+   private Boolean portSecurity;
+
+   // Plugins
+
+   // n1kv.py
+   @Named("n1kv:profile_id")
+   private String profileId;
+
+   // maclearning.py
+   @Named("mac_learning_enabled")
+   private Boolean macLearning;
+
+   // qos.py
+   @Named("rxtx_factor")
+   private Integer qosRxtxFactor;
+
+   @ConstructorProperties({"id", "status", "binding:vif_type", "binding:vif_details", "queue_id", "name", "network_id",
+         "admin_state_up", "mac_address", "fixed_ips", "device_id", "device_owner", "tenant_id", "security_groups",
+         "allowed_address_pairs", "extra_dhcp_opts", "binding:vnic_type", "binding:host_id", "binding:profile",
+         "port_security_enabled", "n1kv:profile_id", "mac_learning_enabled", "rxtx_factor"})
+   protected Port(String id, NetworkStatus status, VIFType vifType, Map<String, Object> vifDetails, String qosQueueId,
+         String name, String networkId, Boolean adminStateUp, String macAddress, ImmutableSet<IP> fixedIps, String deviceId,
+         String deviceOwner, String tenantId, ImmutableSet<String> securityGroups, ImmutableSet<AddressPair> allowedAddressPairs,
+         ImmutableSet<ExtraDhcpOption> extraDhcpOptions, VNICType vnicType, String hostId, Map<String, Object> profile,
+         Boolean portSecurity, String profileId, Boolean macLearning, Integer qosRxtxFactor) {
+      this.id = id;
+      this.status = status;
+      this.vifType = vifType;
+      // This will not be needed once jclouds core supports ImmutableMap deserialization
+      this.vifDetails = vifDetails !=null ? ImmutableMap.copyOf(vifDetails) : null;
+      this.qosQueueId = qosQueueId;
+      this.name = name;
+      this.networkId = networkId;
+      this.adminStateUp = adminStateUp;
+      this.macAddress = macAddress;
+      this.fixedIps = fixedIps;
+      this.deviceId = deviceId;
+      this.deviceOwner = deviceOwner;
+      this.tenantId = tenantId;
+      this.securityGroups = securityGroups;
+      this.allowedAddressPairs = allowedAddressPairs;
+      this.extraDhcpOptions = extraDhcpOptions;
+      this.vnicType = vnicType;
+      this.hostId = hostId;
+      this.profile = profile != null ? ImmutableMap.copyOf(profile) : null;
+      this.portSecurity = portSecurity;
+      this.profileId = profileId;
+      this.macLearning = macLearning;
+      this.qosRxtxFactor = qosRxtxFactor;
+   }
+
+   /**
+    * Default constructor.
+    */
+   private Port() {}
+
+   /**
+    * Copy constructor
+    * @param port
+    */
+   private Port(Port port) {
+      this(port.id,
+      port.status,
+      port.vifType,
+      port.vifDetails,
+      port.qosQueueId,
+      port.name,
+      port.networkId,
+      port.adminStateUp,
+      port.macAddress,
+      port.fixedIps,
+      port.deviceId,
+      port.deviceOwner,
+      port.tenantId,
+      port.securityGroups,
+      port.allowedAddressPairs,
+      port.extraDhcpOptions,
+      port.vnicType,
+      port.hostId,
+      port.profile,
+      port.portSecurity,
+      port.profileId,
+      port.macLearning,
+      port.qosRxtxFactor);
+   }
+
+   /**
+    * @return the id of the Port
+    */
+   @Nullable
+   public String getId() {
+      return id;
+   }
+
+   /**
+    * @return the status of the Port
+    */
+   @Nullable
+   public NetworkStatus getStatus() {
+      return status;
+   }
+
+   /**
+    *
+    * @return the vifType of the Port. Visible to only administrative users.
+    *
+    */
+   @Nullable
+   public VIFType getVifType() {
+      return vifType;
+   }
+
+   /**
+    * @return the vifDetails of the Port. A dictionary that enables the application to pass information about functions
+    * that Networking API v2.0 provides. Specify the following value: port_filter : Boolean to define whether
+    * Networking API v2.0 provides port filtering features such as security group and anti-MAC/IP spoofing. Visible to
+    * only administrative users.
+    */
+   @Nullable
+   public ImmutableMap<String, Object> getVifDetails() {
+      return vifDetails;
+   }
+
+   /**
+    * @return the qosQueueId of the Port
+    */
+   @Nullable
+   public String getQosQueueId() {
+      return qosQueueId;
+   }
+
+   /**
+    * @return the name of the Port
+    */
+   @Nullable
+   public String getName() {
+      return name;
+   }
+
+   /**
+    * @return the id of the network where this port is associated with.
+    */
+   @Nullable
+   public String getNetworkId() {
+      return networkId;
+   }
+
+   /**
+    * @return the administrative state of port. If false, port does not forward packets.
+    */
+   @Nullable
+   public boolean isAdminStateUp() {
+      return adminStateUp;
+   }
+
+   /**
+    * @return the macAddress of the Port
+    */
+   @Nullable
+   public String getMacAddress() {
+      return macAddress;
+   }
+
+   /**
+    * @return the set of fixed ips this port has been assigned.
+    */
+   @Nullable
+   public ImmutableSet<IP> getFixedIps() {
+      return fixedIps;
+   }
+
+   /**
+    * @return the id of the device (e.g. server) using this port.
+    */
+   @Nullable
+   public String getDeviceId() {
+      return deviceId;
+   }
+
+   /**
+    * @return the entity (e.g.: dhcp agent) using this port.
+    */
+   @Nullable
+   public String getDeviceOwner() {
+      return deviceOwner;
+   }
+
+   /**
+    * @return the tenantId of the Port
+    */
+   @Nullable
+   public String getTenantId() {
+      return tenantId;
+   }
+
+   /**
+    * @return the set of security groups
+    */
+   @Nullable
+   public ImmutableSet<String> getSecurityGroups() {
+      return securityGroups;
+   }
+
+   /**
+    * @return the allowedAddressPairs of the Port
+    */
+   @Nullable
+   public ImmutableSet<AddressPair> getAllowedAddressPairs() {
+      return allowedAddressPairs;
+   }
+
+   /**
+    * @return the extraDhcpOptions of the Port
+    */
+   @Nullable
+   public ImmutableSet<ExtraDhcpOption> getExtraDhcpOptions() {
+      return extraDhcpOptions;
+   }
+
+   /**
+    * @return the vnicType of the Port. This extended attribute is visible to only port owners and administrative users.
+    * Specifies a value of normal (virtual nic), direct (pci passthrough), or macvtap (virtual interface with a
+    * tap-like software interface). These values support SR-IOV PCI passthrough networking. The ML2 plug-in supports
+    * the vnic_type.
+    */
+   @Nullable
+   public VNICType getVnicType() {
+      return vnicType;
+   }
+
+   /**
+    * @return the hostId of the Port. The ID of the host where the port is allocated. In some cases, different
+    * implementations can run on different hosts. Visible to only administrative users.
+    */
+   @Nullable
+   public String getHostId() {
+      return hostId;
+   }
+
+   /**
+    * @return the profile of the Port. A dictionary that enables the application to pass information about functions
+    * that the Networking API provides. To enable or disable port filtering features such as security group and
+    * anti-MAC/IP spoofing, specify port_filter: True or port_filter: False. Visible to only administrative users.
+    */
+   @Nullable
+   public ImmutableMap<String, Object> getProfile() {
+      return profile;
+   }
+
+   /**
+    * @return the portSecurity of the Port
+    */
+   @Nullable
+   public Boolean isPortSecurity() {
+      return portSecurity;
+   }
+
+   /**
+    * @return the profileId of the Port
+    */
+   @Nullable
+   public String getProfileId() {
+      return profileId;
+   }
+
+   /**
+    * @return the macLearning of the Port
+    */
+   @Nullable
+   public Boolean isMacLearning() {
+      return macLearning;
+   }
+
+   /**
+    * @return the qosRxtxFactor of the Port
+    */
+   @Nullable
+   public Integer getQosRxtxFactor() {
+      return qosRxtxFactor;
+   }
+
+   @Override
+   public boolean equals(Object o) {
+      if (this == o)
+         return true;
+      if (o == null || getClass() != o.getClass())
+         return false;
+
+      Port that = (Port) o;
+
+      return Objects.equal(this.id, that.id) &&
+            Objects.equal(this.status, that.status) &&
+            Objects.equal(this.vifType, that.vifType) &&
+            Objects.equal(this.vifDetails, that.vifDetails) &&
+            Objects.equal(this.qosQueueId, that.qosQueueId) &&
+            Objects.equal(this.name, that.name) &&
+            Objects.equal(this.networkId, that.networkId) &&
+            Objects.equal(this.adminStateUp, that.adminStateUp) &&
+            Objects.equal(this.macAddress, that.macAddress) &&
+            Objects.equal(this.fixedIps, that.fixedIps) &&
+            Objects.equal(this.deviceId, that.deviceId) &&
+            Objects.equal(this.deviceOwner, that.deviceOwner) &&
+            Objects.equal(this.tenantId, that.tenantId) &&
+            Objects.equal(this.securityGroups, that.securityGroups) &&
+            Objects.equal(this.allowedAddressPairs, that.allowedAddressPairs) &&
+            Objects.equal(this.extraDhcpOptions, that.extraDhcpOptions) &&
+            Objects.equal(this.vnicType, that.vnicType) &&
+            Objects.equal(this.hostId, that.hostId) &&
+            Objects.equal(this.profile, that.profile) &&
+            Objects.equal(this.portSecurity, that.portSecurity) &&
+            Objects.equal(this.profileId, that.profileId) &&
+            Objects.equal(this.macLearning, that.macLearning) &&
+            Objects.equal(this.qosRxtxFactor, that.qosRxtxFactor);
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id, status, vifType, vifDetails, qosQueueId, name,
+            networkId, adminStateUp, macAddress, fixedIps, deviceId,
+            deviceOwner, tenantId, securityGroups, allowedAddressPairs, extraDhcpOptions,
+            vnicType, hostId, profile, portSecurity, profileId,
+            macLearning, qosRxtxFactor);
+   }
+
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this)
+            .add("id", id)
+            .add("status", status)
+            .add("vifType", vifType)
+            .add("vifDetails", vifDetails)
+            .add("qosQueueId", qosQueueId)
+            .add("name", name)
+            .add("networkId", networkId)
+            .add("adminStateUp", adminStateUp)
+            .add("macAddress", macAddress)
+            .add("fixedIps", fixedIps)
+            .add("deviceId", deviceId)
+            .add("deviceOwner", deviceOwner)
+            .add("tenantId", tenantId)
+            .add("securityGroups", securityGroups)
+            .add("allowedAddressPairs", allowedAddressPairs)
+            .add("extraDhcpOptions", extraDhcpOptions)
+            .add("vnicType", vnicType)
+            .add("hostId", hostId)
+            .add("profile", profile)
+            .add("portSecurity", portSecurity)
+            .add("profileId", profileId)
+            .add("macLearning", macLearning)
+            .add("qosRxtxFactor", qosRxtxFactor)
+            .toString();
+   }
+
+   /*
+    * Methods to get the Create and Update builders follow
+    */
+
+   /**
+    * @return the Builder for creating a new Router
+    */
+   public static CreateBuilder createOptions(String networkId) {
+      return new CreateBuilder(networkId);
+   }
+
+   /**
+    * @return the Builder for updating a Router
+    */
+   public static UpdateBuilder updateOptions() {
+      return new UpdateBuilder();
+   }
+
+   private static abstract class Builder<ParameterizedBuilderType> {
+      protected Port port;
+
+      /**
+       * No-parameters constructor used when updating.
+       */
+      private Builder() {
+         port = new Port();
+      }
+
+      protected abstract ParameterizedBuilderType self();
+
+      /**
+       * Provide the name to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#getName()
+       */
+      public ParameterizedBuilderType name(String name) {
+         port.name = name;
+         return self();
+      }
+
+      /**
+       * Provide the networkId to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#getNetworkId()
+       */
+      public ParameterizedBuilderType networkId(String networkId) {
+         port.networkId = networkId;
+         return self();
+      }
+
+      /**
+       * Provide the adminStateUp to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#isAdminStateUp()
+       */
+      public ParameterizedBuilderType adminStateUp(boolean adminStateUp) {
+         port.adminStateUp = adminStateUp;
+         return self();
+      }
+
+      /**
+       * Provide the macAddress to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#getMacAddress()
+       */
+      public ParameterizedBuilderType macAddress(String macAddress) {
+         port.macAddress = macAddress;
+         return self();
+      }
+
+      /**
+       * Provide the fixedIps to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#getFixedIps()
+       */
+      public ParameterizedBuilderType fixedIps(ImmutableSet<IP> fixedIps) {
+         port.fixedIps = fixedIps;
+         return self();
+      }
+
+      /**
+       * Provide the deviceId to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#getDeviceId()
+       */
+      public ParameterizedBuilderType deviceId(String deviceId) {
+         port.deviceId = deviceId;
+         return self();
+      }
+
+      /**
+       * Provide the deviceOwner to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#getDeviceOwner()
+       */
+      public ParameterizedBuilderType deviceOwner(String deviceOwner) {
+         port.deviceOwner = deviceOwner;
+         return self();
+      }
+
+      /**
+       * Provide the tenantId to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#getTenantId()
+       */
+      public ParameterizedBuilderType tenantId(String tenantId) {
+         port.tenantId = tenantId;
+         return self();
+      }
+
+      /**
+       * Provide the tenantId to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#getSecurityGroups()
+       */
+      public ParameterizedBuilderType securityGroups(ImmutableSet<String> securityGroups) {
+         port.securityGroups = securityGroups;
+         return self();
+      }
+
+      /**
+       * Provide the allowedAddressPairs to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#getAllowedAddressPairs()
+       */
+      public ParameterizedBuilderType allowedAddressPairs(ImmutableSet<AddressPair> allowedAddressPairs) {
+         port.allowedAddressPairs = allowedAddressPairs;
+         return self();
+      }
+
+      /**
+       * Provide the extraDhcpOptions to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#getExtraDhcpOptions()
+       */
+      public ParameterizedBuilderType extraDhcpOptions(ImmutableSet<ExtraDhcpOption> extraDhcpOptions) {
+         port.extraDhcpOptions = extraDhcpOptions;
+         return self();
+      }
+
+      /**
+       * Provide the vnicType to the Port's Builder.
+       * Specify a value of normal (virtual nic), direct (pci passthrough), or macvtap (virtual interface with a
+       * tap-like software interface). These values support SR-IOV PCI passthrough networking. The ML2 plug-in supports
+       * the vnic_type.
+       *
+       * @return the Builder.
+       * @see Port#getVnicType()
+       */
+      public ParameterizedBuilderType vnicType(VNICType vnicType) {
+         port.vnicType = vnicType;
+         return self();
+      }
+
+      /**
+       * Provide the hostId to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#getHostId()
+       */
+      public ParameterizedBuilderType hostId(String hostId) {
+         port.hostId = hostId;
+         return self();
+      }
+
+      /**
+       * Provide the profile to the Port's Builder.
+       * This attribute is a dictionary that can be used (with admin credentials) to supply information influencing the
+       * binding of the port. This functionality is needed for SR-IOV PCI passthrough.
+       *
+       * @return the Builder.
+       * @see Port#getProfile()
+       */
+      public ParameterizedBuilderType profile(ImmutableMap<String, Object> profile) {
+         port.profile = profile;
+         return self();
+      }
+
+      /**
+       * Provide the portSecurity to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#isPortSecurity()
+       */
+      public ParameterizedBuilderType portSecurity(boolean portSecurity) {
+         port.portSecurity = portSecurity;
+         return self();
+      }
+
+      /**
+       * Provide the profileId to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#getProfileId()
+       */
+      public ParameterizedBuilderType profileId(String profileId) {
+         port.profileId = profileId;
+         return self();
+      }
+
+      /**
+       * Provide the macLearning to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#isMacLearning()
+       */
+      public ParameterizedBuilderType macLearning(boolean macLearning) {
+         port.macLearning = macLearning;
+         return self();
+      }
+
+      /**
+       * Provide the qosRxtxFactor to the Port's Builder.
+       *
+       * @return the Builder.
+       * @see Port#getQosRxtxFactor()
+       */
+      public ParameterizedBuilderType qosRxtxFactor(int qosRxtxFactor) {
+         port.qosRxtxFactor = qosRxtxFactor;
+         return self();
+      }
+   }
+
+   /**
+    * Create and Update builders (inheriting from Builder)
+    */
+   public static class CreateBuilder extends Builder<CreateBuilder> {
+      /**
+       *
+       * Supply required properties for creating a Builder
+       */
+      private CreateBuilder(String networkId) {
+         port.networkId = networkId;
+      }
+
+      /**
+       * @return a CreateOptions constructed with this Builder.
+       */
+      public CreateOptions build() {
+         return new CreateOptions(port);
+      }
+
+      protected CreateBuilder self() {
+         return this;
+      }
+   }
+
+   /**
+    * Create and Update builders (inheriting from Builder)
+    */
+   public static class UpdateBuilder extends Builder<UpdateBuilder> {
+      /**
+       * Supply required properties for updating a Builder
+       */
+      private UpdateBuilder() {
+      }
+
+      /**
+       * @return a UpdateOptions constructed with this Builder.
+       */
+      public UpdateOptions build() {
+         return new UpdateOptions(port);
+      }
+
+      protected UpdateBuilder self() {
+         return this;
+      }
+   }
+
+   /**
+    * Create and Update options - extend the domain class, passed to API update and create calls.
+    * Essentially the same as the domain class. Ensure validation and safe typing.
+    */
+   public static class CreateOptions extends Port {
+      /**
+       * Copy constructor
+       */
+      private CreateOptions(Port port) {
+         super(port);
+         checkNotNull(port.networkId, "networkId should not be null");
+      }
+   }
+
+   /**
+    * Create and Update options - extend the domain class, passed to API update and create calls.
+    * Essentially the same as the domain class. Ensure validation and safe typing.
+    */
+   public static class UpdateOptions extends Port {
+      /**
+       * Copy constructor
+       */
+      private UpdateOptions(Port port) {
+         super(port);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Ports.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Ports.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Ports.java
new file mode 100644
index 0000000..f7a6d5d
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Ports.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.PaginatedCollection;
+
+import java.beans.ConstructorProperties;
+
+/**
+ * A collection of Networks
+ */
+public class Ports extends PaginatedCollection<Port> {
+   public static final Ports EMPTY = new Ports(ImmutableSet.<Port> of(), ImmutableSet.<Link> of());
+
+   @ConstructorProperties({ "ports", "ports_links" })
+   protected Ports(Iterable<Port> ports, Iterable<Link> portsLinks) {
+      super(ports, portsLinks);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Router.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Router.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Router.java
new file mode 100644
index 0000000..fb50d07
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Router.java
@@ -0,0 +1,285 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.base.Objects;
+import org.jclouds.javax.annotation.Nullable;
+
+import javax.inject.Named;
+import java.beans.ConstructorProperties;
+
+/**
+ * A Neutron Router
+ *
+ * @see <a
+ *      href="http://docs.openstack.org/api/openstack-network/2.0/content/router_ext_concepts.html">api
+ *      doc</a>
+ */
+public class Router {
+
+   private String id;
+   private NetworkStatus status;
+
+   private String name;
+   @Named("tenant_id")
+   private String tenantId;
+   @Named("admin_state_up")
+   private Boolean adminStateUp;
+   @Named("external_gateway_info")
+   private ExternalGatewayInfo externalGatewayInfo;
+
+   /**
+    * @param id
+    * @param status
+    * @param name
+    * @param tenantId
+    * @param adminStateUp
+    * @param externalGatewayInfo
+    */
+   @ConstructorProperties({"id", "status", "name", "tenant_id", "admin_state_up", "external_gateway_info"})
+   private Router(String id, NetworkStatus status, String name, String tenantId, Boolean adminStateUp, ExternalGatewayInfo externalGatewayInfo) {
+      this.id = id;
+      this.status = status;
+      this.name = name;
+      this.tenantId = tenantId;
+      this.adminStateUp = adminStateUp;
+      this.externalGatewayInfo = externalGatewayInfo;
+   }
+
+   /**
+    * Default constructor.
+    */
+   private Router() {}
+
+   /**
+    * Copy constructor
+    * @param router
+    */
+   private Router(Router router) {
+      this(router.id, router.status, router.name, router.tenantId, router.adminStateUp, router.externalGatewayInfo);
+   }
+
+   /**
+    * @return the id of the Router
+    */
+   @Nullable
+   public String getId() {
+      return id;
+   }
+
+   /**
+    * @return the status of the Router
+    */
+   @Nullable
+   public NetworkStatus getStatus() {
+      return status;
+   }
+
+   /**
+    * @return the name of the Router
+    */
+   @Nullable
+   public String getName() {
+      return name;
+   }
+
+   /**
+    * @return the tenantId of the Router
+    */
+   @Nullable
+   public String getTenantId() {
+      return tenantId;
+   }
+
+   /**
+    * @return the adminStateUp of the Router
+    */
+   @Nullable
+   public Boolean isAdminStateUp() {
+      return adminStateUp;
+   }
+
+   /**
+    * @return the externalGatewayInfo of the Router
+    */
+   @Nullable
+   public ExternalGatewayInfo getExternalGatewayInfo() {
+      return externalGatewayInfo;
+   }
+
+   /**
+    * @return the Builder for creating a new Router
+    */
+   public static CreateBuilder createOptions() {
+      return new CreateBuilder();
+   }
+
+   /**
+    * @return the Builder for updating a Router
+    */
+   public static UpdateBuilder updateOptions() {
+      return new UpdateBuilder();
+   }
+
+   @Override
+   public boolean equals(Object o) {
+      if (this == o)
+         return true;
+      if (o == null || getClass() != o.getClass())
+         return false;
+
+      Router that = (Router) o;
+
+      return Objects.equal(this.id, that.id) &&
+            Objects.equal(this.status, that.status) &&
+            Objects.equal(this.name, that.name) &&
+            Objects.equal(this.tenantId, that.tenantId) &&
+            Objects.equal(this.adminStateUp, that.adminStateUp) &&
+            Objects.equal(this.externalGatewayInfo, that.externalGatewayInfo);
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id, status, name, tenantId, adminStateUp, externalGatewayInfo);
+   }
+
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this)
+            .add("id", id)
+            .add("status", status)
+            .add("name", name)
+            .add("tenantId", tenantId)
+            .add("adminStateUp", adminStateUp)
+            .add("externalGatewayInfo", externalGatewayInfo)
+            .toString();
+   }
+
+   private static abstract class Builder<ParameterizedBuilderType> {
+      protected Router router;
+
+      /**
+       * No-parameters constructor used when updating.
+       * */
+      private Builder() {
+         router = new Router();
+      }
+
+      protected abstract ParameterizedBuilderType self();
+
+      /**
+       * Provide the name to the Router's Builder.
+       *
+       * @return the Builder.
+       * @see Router#getName()
+       */
+      public ParameterizedBuilderType name(String name) {
+         router.name = name;
+         return self();
+      }
+
+      /**
+       * Provide the tenantId to the Router's Builder.
+       *
+       * @return the Builder.
+       * @see Router#getTenantId()
+       */
+      public ParameterizedBuilderType tenantId(String tenantId) {
+         router.tenantId = tenantId;
+         return self();
+      }
+
+      /**
+       * Provide the adminStateUp to the Router's Builder.
+       *
+       * @return the Builder.
+       * @see Router#isAdminStateUp()
+       */
+      public ParameterizedBuilderType adminStateUp(boolean adminStateUp) {
+         router.adminStateUp = adminStateUp;
+         return self();
+      }
+
+      /**
+       * Provide the externalGatewayInfo to the Router's Builder.
+       *
+       * @return the Builder.
+       * @see Router#getExternalGatewayInfo()
+       */
+      public ParameterizedBuilderType externalGatewayInfo(ExternalGatewayInfo externalGatewayInfo) {
+         router.externalGatewayInfo = externalGatewayInfo;
+         return self();
+      }
+   }
+
+   public static class CreateBuilder extends Builder<CreateBuilder> {
+      /**
+       * Supply required properties for creating a Builder
+       */
+      private CreateBuilder() {
+      }
+
+      /**
+       * @return a CreateOptions constructed with this Builder.
+       */
+      public CreateOptions build() {
+         return new CreateOptions(router);
+      }
+
+      protected CreateBuilder self() {
+         return this;
+      }
+   }
+
+   public static class UpdateBuilder extends Builder<UpdateBuilder> {
+      /**
+       * Supply required properties for updating a Builder
+       */
+      private UpdateBuilder() {
+      }
+
+      /**
+       * @return a UpdateOptions constructed with this Builder.
+       */
+      public UpdateOptions build() {
+         return new UpdateOptions(router);
+      }
+
+      protected UpdateBuilder self() {
+         return this;
+      }
+   }
+
+   public static class CreateOptions extends Router{
+      /**
+       * Copy constructor
+       */
+      private CreateOptions(Router router) {
+         super(router);
+      }
+   }
+   public static class UpdateOptions extends Router{
+      /**
+       * Copy constructor
+       */
+      private UpdateOptions(Router router) {
+         super(router);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RouterInterface.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RouterInterface.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RouterInterface.java
new file mode 100644
index 0000000..091bf99
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RouterInterface.java
@@ -0,0 +1,136 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.base.Objects;
+
+import javax.inject.Named;
+
+/**
+ * A Neutron Router Interface
+ *
+ * @see <a
+ *      href="http://docs.openstack.org/api/openstack-network/2.0/content/router_add_interface.html">api
+ *      doc</a>
+ */
+public class RouterInterface {
+
+   @Named("subnet_id")
+   protected final String subnetId;
+   @Named("port_id")
+   protected final String portId;
+
+   protected RouterInterface(String subnetId, String portId) {
+      this.subnetId = subnetId;
+      this.portId = portId;
+   }
+
+   /**
+    * @return the subnetId of the RouterInterface
+    */
+   public String getSubnetId() {
+      return subnetId;
+   }
+
+   /**
+    * @return the portId of the RouterInterface
+    */
+   public String getPortId() {
+      return portId;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(subnetId, portId);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      RouterInterface that = RouterInterface.class.cast(obj);
+      return Objects.equal(this.subnetId, that.subnetId) && Objects.equal(this.portId, that.portId);
+   }
+
+   protected Objects.ToStringHelper string() {
+      return Objects.toStringHelper(this).add("subnetId", subnetId).add("portId", portId);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   /**
+    * @return the Builder for RouterInterface
+    */
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   /**
+    * Gets a Builder configured as this object.
+    */
+   public Builder toBuilder() {
+      return new Builder().fromRouterInterface(this);
+   }
+
+   public static class Builder {
+      protected String subnetId;
+      protected String portId;
+
+      /**
+       * Provide the subnetId to the RouterInterface's Builder.
+       *
+       * @return the Builder.
+       * @see RouterInterface#getSubnetId()
+       */
+      public Builder subnetId(String subnetId) {
+         this.subnetId = subnetId;
+         return this;
+      }
+
+      /**
+       * Provide the portId to the RouterInterface's Builder.
+       *
+       * @return the Builder.
+       * @see RouterInterface#getPortId()
+       */
+      public Builder portId(String portId) {
+         this.portId = portId;
+         return this;
+      }
+
+      /**
+       * @return a RouterInterface constructed with this Builder.
+       */
+      public RouterInterface build() {
+         return new RouterInterface(subnetId, portId);
+      }
+
+      /**
+       * @return a Builder from another RouterInterface.
+       */
+      public Builder fromRouterInterface(RouterInterface in) {
+         return this.subnetId(in.getSubnetId()).portId(in.getPortId());
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Routers.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Routers.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Routers.java
new file mode 100644
index 0000000..8f926bf
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Routers.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.PaginatedCollection;
+
+import java.beans.ConstructorProperties;
+
+/**
+ * A collection of Networks
+ */
+public class Routers extends PaginatedCollection<Router> {
+   public static final Routers EMPTY = new Routers(ImmutableSet.<Router> of(), ImmutableSet.<Link> of());
+
+   @ConstructorProperties({ "routers", "routers_links" })
+   protected Routers(Iterable<Router> routers, Iterable<Link> routersLinks) {
+      super(routers, routersLinks);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Subnet.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Subnet.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Subnet.java
new file mode 100644
index 0000000..31d3327
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Subnet.java
@@ -0,0 +1,467 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.javax.annotation.Nullable;
+
+import javax.inject.Named;
+import java.beans.ConstructorProperties;
+import java.util.Collection;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A Neutron subnet
+ *
+ * @see <a href="http://docs.openstack.org/api/openstack-network/2.0/content/Subnets.html">api doc</a>
+ */
+public class Subnet {
+
+   private String id;
+
+   private String name;
+   @Named("network_id")
+   private String networkId;
+   @Named("tenant_id")
+   private String tenantId;
+   // Cannot be used for updates.
+   @Named("allocation_pools")
+   private ImmutableSet<AllocationPool> allocationPools;
+   @Named("gateway_ip")
+   private String gatewayIp;
+   @Named("ip_version")
+   private Integer ipVersion;
+   private String cidr;
+   @Named("enable_dhcp")
+   private Boolean enableDhcp;
+   @Named("dns_nameservers")
+   private ImmutableSet<String> dnsNameServers;
+   @Named("host_routes")
+   private ImmutableSet<HostRoute> hostRoutes;
+   @Named("ipv6_address_mode")
+   private IPv6DHCPMode ipv6AddressMode;
+   @Named("ipv6_ra_mode")
+   private IPv6DHCPMode ipv6RaMode;
+
+   @ConstructorProperties({"id", "name", "network_id", "tenant_id", "allocation_pools", "gateway_ip", "ip_version",
+         "cidr", "enable_dhcp", "dns_nameservers", "host_routes", "ipv6_address_mode", "ipv6_ra_mode"})
+   private Subnet(String id, String name, String networkId, String tenantId, ImmutableSet<AllocationPool> allocationPools,
+         String gatewayIp, Integer ipVersion, String cidr, Boolean enableDhcp, ImmutableSet<String> dnsNameServers, ImmutableSet<HostRoute> hostRoutes,
+         IPv6DHCPMode ipv6AddressMode, IPv6DHCPMode ipv6RaMode) {
+      this.id = id;
+      this.name = name;
+      this.networkId = networkId;
+      this.tenantId = tenantId;
+      this.allocationPools = allocationPools;
+      this.gatewayIp = gatewayIp;
+      this.ipVersion = ipVersion;
+      this.cidr = cidr;
+      this.enableDhcp = enableDhcp;
+      this.dnsNameServers = dnsNameServers;
+      this.hostRoutes = hostRoutes;
+      this.ipv6AddressMode = ipv6AddressMode;
+      this.ipv6RaMode = ipv6RaMode;
+   }
+
+   /**
+    * Default constructor.
+    */
+   private Subnet() {}
+
+   /**
+    * Copy constructor
+    * @param subnet
+    */
+   private Subnet(Subnet subnet) {
+      this(subnet.id,
+            subnet.name,
+            subnet.networkId,
+            subnet.tenantId,
+            subnet.allocationPools,
+            subnet.gatewayIp,
+            subnet.ipVersion,
+            subnet.cidr,
+            subnet.enableDhcp,
+            subnet.dnsNameServers,
+            subnet.hostRoutes,
+            subnet.ipv6AddressMode,
+            subnet.ipv6RaMode);
+   }
+
+   /**
+    * @return the id of the subnet
+    */
+   @Nullable
+   public String getId() {
+      return this.id;
+   }
+
+   /**
+    * @return the name of the subnet
+    */
+   @Nullable
+   public String getName() {
+      return this.name;
+   }
+
+   /**
+    * @return the id of the network this subnet is associated with.
+    */
+   @Nullable
+   public String getNetworkId() {
+      return networkId;
+   }
+
+   /**
+    * @return the id of the tenant where this entity is associated with.
+    */
+   @Nullable
+   public String getTenantId() {
+      return tenantId;
+   }
+
+   /**
+    * @return the sub-ranges of CIDR available for dynamic allocation to ports.
+    */
+   @Nullable
+   public ImmutableSet<AllocationPool> getAllocationPools() {
+      return allocationPools;
+   }
+
+   /**
+    * @return the default gateway used by devices in this subnet.
+    */
+   @Nullable
+   public String getGatewayIp() {
+      return gatewayIp;
+   }
+
+   /**
+    * @return the IP version used by this subnet.
+    */
+   @Nullable
+   public Integer getIpVersion() {
+      return ipVersion;
+   }
+
+   /**
+    * @return the CIDR representing the IP range for this subnet, based on IP version.
+    */
+   @Nullable
+   public String getCidr() {
+      return cidr;
+   }
+
+   /**
+    * @return true if DHCP is enabled for this subnet, false if not.
+    */
+   @Nullable
+   public Boolean getEnableDhcp() {
+      return enableDhcp;
+   }
+
+   /**
+    * @return Configurable maximum amount of name servers per subnet. The default is 5.
+    */
+   @Nullable
+   public ImmutableSet<String> getDnsNameservers() {
+      return dnsNameServers;
+   }
+
+   /**
+    * @return Configurable maximum amount of routes per subnet. The default is 20.
+    */
+   @Nullable
+   public ImmutableSet<HostRoute> getHostRoutes() {
+      return hostRoutes;
+   }
+
+   /**
+    * @return The IP v6 Address Mode.
+    */
+   @Nullable
+   public IPv6DHCPMode getIPv6AddressMode() {
+      return ipv6AddressMode;
+   }
+
+   /**
+    * @return The IP v6 Router Advertisement mode.
+    */
+   @Nullable
+   public IPv6DHCPMode getIPv6RAMode() {
+      return ipv6RaMode;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id, name, networkId, tenantId, allocationPools, gatewayIp,
+            ipVersion, cidr, enableDhcp, dnsNameServers, hostRoutes,
+            ipv6AddressMode, ipv6RaMode);
+   }
+
+   @Override
+   public boolean equals(Object o) {
+      if (this == o)
+         return true;
+      if (o == null || getClass() != o.getClass())
+         return false;
+
+      Subnet that = (Subnet) o;
+
+      return Objects.equal(this.id, that.id) &&
+            Objects.equal(this.name, that.name) &&
+            Objects.equal(this.networkId, that.networkId) &&
+            Objects.equal(this.tenantId, that.tenantId) &&
+            Objects.equal(this.allocationPools, that.allocationPools) &&
+            Objects.equal(this.gatewayIp, that.gatewayIp) &&
+            Objects.equal(this.ipVersion, that.ipVersion) &&
+            Objects.equal(this.cidr, that.cidr) &&
+            Objects.equal(this.enableDhcp, that.enableDhcp) &&
+            Objects.equal(this.dnsNameServers, that.dnsNameServers) &&
+            Objects.equal(this.hostRoutes, that.hostRoutes) &&
+            Objects.equal(this.ipv6AddressMode, that.ipv6AddressMode) &&
+            Objects.equal(this.ipv6RaMode, that.ipv6RaMode);
+   }
+
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this)
+            .add("id", id)
+            .add("name", name)
+            .add("networkId", networkId)
+            .add("tenantId", tenantId)
+            .add("allocationPools", allocationPools)
+            .add("gatewayIp", gatewayIp)
+            .add("ipVersion", ipVersion)
+            .add("cidr", cidr)
+            .add("enableDhcp", enableDhcp)
+            .add("dnsNameServers", dnsNameServers)
+            .add("hostRoutes", hostRoutes)
+            .add("ipv6AddressMode", ipv6AddressMode)
+            .add("ipv6RaMode", ipv6RaMode)
+            .toString();
+   }
+
+   /*
+    * Methods to get the Create and Update builders follow
+    */
+
+   /**
+    * @return the Builder for creating a new Router
+    */
+   public static CreateBuilder createOptions(String networkId, String cidr) {
+      return new CreateBuilder(networkId, cidr);
+   }
+
+   /**
+    * @return the Builder for updating a Router
+    */
+   public static UpdateBuilder updateOptions() {
+      return new UpdateBuilder();
+   }
+
+   private static abstract class Builder<ParameterizedBuilderType> {
+      protected Subnet subnet;
+
+      /**
+       * No-parameters constructor used when updating.
+       */
+      private Builder() {
+         subnet = new Subnet();
+      }
+
+      protected abstract ParameterizedBuilderType self();
+
+      /**
+       * @see Subnet#getName()
+       */
+      public ParameterizedBuilderType name(String name) {
+         subnet.name = name;
+         return self();
+      }
+
+      /**
+       * @see Subnet#getNetworkId()
+       */
+      public ParameterizedBuilderType networkId(String networkId) {
+         subnet.networkId = networkId;
+         return self();
+      }
+
+      /**
+       * Only administrators can specify a tenant ID that is not their own.
+       * As it is optional, this is usually omitted in requests.
+       * @see Subnet#getTenantId()
+       */
+      public ParameterizedBuilderType tenantId(String tenantId) {
+         subnet.tenantId = tenantId;
+         return self();
+      }
+
+      /**
+       * @see Subnet#getAllocationPools()
+       */
+      public ParameterizedBuilderType allocationPools(Collection<AllocationPool> allocationPools) {
+         subnet.allocationPools = ImmutableSet.copyOf(allocationPools);
+         return self();
+      }
+
+      /**
+       * @see Subnet#getGatewayIp()
+       */
+      public ParameterizedBuilderType gatewayIp(String gatewayIp) {
+         subnet.gatewayIp = gatewayIp;
+         return self();
+      }
+
+      /**
+       * @see Subnet#getIpVersion()
+       */
+      public ParameterizedBuilderType ipVersion(int ipVersion) {
+         subnet.ipVersion = ipVersion;
+         return self();
+      }
+
+      /**
+       * @see Subnet#getCidr()
+       */
+      public ParameterizedBuilderType cidr(String cidr) {
+         subnet.cidr = cidr;
+         return self();
+      }
+
+      /**
+       * @see Subnet#getEnableDhcp()
+       */
+      public ParameterizedBuilderType enableDhcp(Boolean enableDhcp) {
+         subnet.enableDhcp = enableDhcp;
+         return self();
+      }
+
+      /**
+       * @see Subnet#getDnsNameservers()
+       */
+      public ParameterizedBuilderType dnsNameServers(ImmutableSet<String> dnsNameServers) {
+         subnet.dnsNameServers = dnsNameServers;
+         return self();
+      }
+
+      /**
+       * @see Subnet#getHostRoutes()
+       */
+      public ParameterizedBuilderType hostRoutes(ImmutableSet<HostRoute> hostRoutes) {
+         subnet.hostRoutes = hostRoutes;
+         return self();
+      }
+
+      /**
+       * @see Subnet#getIPv6RAMode()
+       */
+      public ParameterizedBuilderType ipv6RaMode(IPv6DHCPMode ipv6RaMode) {
+         subnet.ipv6RaMode = ipv6RaMode;
+         return self();
+      }
+
+      /**
+       * @see Subnet#getIPv6AddressMode()
+       */
+      public ParameterizedBuilderType ipv6AddressMode(IPv6DHCPMode ipv6AddressMode) {
+         subnet.ipv6AddressMode = ipv6AddressMode;
+         return self();
+      }
+   }
+
+   /**
+    * Create and Update builders (inheriting from Builder)
+    */
+   public static class CreateBuilder extends Builder<CreateBuilder> {
+      /**
+       *
+       * Supply required properties for creating a Builder
+       */
+      private CreateBuilder(String networkId, String cidr) {
+         subnet.networkId = networkId;
+         subnet.cidr = cidr;
+      }
+
+      /**
+       * @return a CreateOptions constructed with this Builder.
+       */
+      public CreateOptions build() {
+         return new CreateOptions(subnet);
+      }
+
+      protected CreateBuilder self() {
+         return this;
+      }
+   }
+
+   /**
+    * Create and Update builders (inheriting from Builder)
+    */
+   public static class UpdateBuilder extends Builder<UpdateBuilder> {
+      /**
+       * Supply required properties for updating a Builder
+       */
+      private UpdateBuilder() {
+      }
+
+      /**
+       * @return a UpdateOptions constructed with this Builder.
+       */
+      public UpdateOptions build() {
+         return new UpdateOptions(subnet);
+      }
+
+      protected UpdateBuilder self() {
+         return this;
+      }
+   }
+
+   /**
+    * Create and Update options - extend the domain class, passed to API update and create calls.
+    * Essentially the same as the domain class. Ensure validation and safe typing.
+    */
+   public static class CreateOptions extends Subnet {
+      /**
+       * Copy constructor
+       */
+      private CreateOptions(Subnet subnet) {
+         super(subnet);
+         checkNotNull(subnet.networkId, "networkId should not be null");
+         checkNotNull(subnet.cidr, "cidr should not be null");
+      }
+   }
+
+   /**
+    * Create and Update options - extend the domain class, passed to API update and create calls.
+    * Essentially the same as the domain class. Ensure validation and safe typing.
+    */
+   public static class UpdateOptions extends Subnet {
+      /**
+       * Copy constructor
+       */
+      private UpdateOptions(Subnet subnet) {
+         super(subnet);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Subnets.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Subnets.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Subnets.java
new file mode 100644
index 0000000..ac36a2b
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Subnets.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.PaginatedCollection;
+
+import java.beans.ConstructorProperties;
+
+/**
+ * A collection of Networks
+ */
+public class Subnets extends PaginatedCollection<Subnet> {
+   public static final Subnets EMPTY = new Subnets(ImmutableSet.<Subnet> of(), ImmutableSet.<Link> of());
+
+   @ConstructorProperties({ "subnets", "subnets_links" })
+   protected Subnets(Iterable<Subnet> subnets, Iterable<Link> subnetsLinks) {
+      super(subnets, subnetsLinks);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/VIFType.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/VIFType.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/VIFType.java
new file mode 100644
index 0000000..0c53e77
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/VIFType.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.neutron.v2.domain;
+
+public enum VIFType {
+   UNBOUND("unbound"),
+   BINDING_FAILED("binding_failed"),
+   IOVISOR("iovisor"),
+   OVS("ovs"),
+   BRIDGE("bridge"),
+   _802_QBG("802.1qbg"),
+   _802_QBH("802.1qbh"),
+   HYPERV("hyperv"),
+   MIDONET("midonet"),
+   MLNX_DIRECT("mlnx_direct"),
+   MLNX_HOSTDEV("hostdev"),
+   OTHER("other"),
+   /**
+    * Used by jclouds when the service returns an unknown value other than null.
+    */
+   UNRECOGNIZED("unrecognized");
+
+   private String name;
+
+   private VIFType(String name) {
+      this.name = name;
+   }
+
+   public String toString() {
+      return name;
+   }
+
+   /**
+    * This provides GSON enum support in jclouds.
+    * */
+   public static VIFType fromValue(String name){
+      if (name != null) {
+         for (VIFType value : VIFType.values()) {
+            if (name.equalsIgnoreCase(value.name)) {
+               return value;
+            }
+         }
+         return UNRECOGNIZED;
+      }
+      return null;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/VNICType.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/VNICType.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/VNICType.java
new file mode 100644
index 0000000..b67063d
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/VNICType.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.neutron.v2.domain;
+
+/**
+ * Enumerates supported VNIC types.
+ */
+public enum VNICType {
+   NORMAL("normal"),
+   DIRECT("direct"),
+   MACVTAP("macvtap"),
+   /**
+    * Used by jclouds when the service returns an unknown value other than null.
+    */
+   UNRECOGNIZED("unrecognized");
+
+   private String name;
+
+   private VNICType(String name) {
+      this.name = name;
+   }
+
+   public String toString() {
+      return name;
+   }
+
+   /**
+    * This provides GSON enum support in jclouds.
+    * */
+   public static VNICType fromValue(String name){
+      if (name != null) {
+         for (VNICType value : VNICType.values()) {
+            if (name.equalsIgnoreCase(value.name)) {
+               return value;
+            }
+         }
+         return UNRECOGNIZED;
+      }
+      return null;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/extensions/RouterApi.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/extensions/RouterApi.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/extensions/RouterApi.java
new file mode 100644
index 0000000..1012117
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/extensions/RouterApi.java
@@ -0,0 +1,197 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.extensions;
+
+import com.google.common.annotations.Beta;
+import org.jclouds.Fallbacks;
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.neutron.v2.domain.Router;
+import org.jclouds.openstack.neutron.v2.domain.RouterInterface;
+import org.jclouds.openstack.neutron.v2.domain.Routers;
+import org.jclouds.openstack.neutron.v2.fallbacks.EmptyRoutersFallback;
+import org.jclouds.openstack.neutron.v2.functions.ParseRouters;
+import org.jclouds.openstack.neutron.v2.functions.RouterToPagedIterable;
+import org.jclouds.openstack.neutron.v2.options.EmptyOptions;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.annotations.WrapWith;
+
+import javax.inject.Named;
+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.core.MediaType;
+
+/**
+ * Provides synchronous access to Router operations on the OpenStack Neutron API.
+ * <p/>
+ * A logical entity for forwarding packets across internal subnets and NATting them on external
+ * networks through an appropriate external gateway.
+ *
+ * @see <a href=
+ *      "http://docs.openstack.org/api/openstack-network/2.0/content/router_ext.html">api doc</a>
+ */
+@Beta
+@Path("/v2.0/routers")
+@RequestFilters(AuthenticateRequest.class)
+@Consumes(MediaType.APPLICATION_JSON)
+public interface RouterApi {
+
+   /**
+    * Returns the list of all routers currently defined in Neutron for the current tenant. The list provides the unique
+    * identifier of each router configured for the tenant
+    *
+    * @return the list of all router references configured for the tenant.
+    */
+   @Named("router:list")
+   @GET
+   @Transform(RouterToPagedIterable.class)
+   @ResponseParser(ParseRouters.class)
+   @Fallback(Fallbacks.EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<Router> list();
+
+   /**
+    * @see <a href="http://docs.openstack.org/api/openstack-network/2.0/content/pagination.html">api doc</a>
+    */
+   @Named("router:list")
+   @GET
+   @ResponseParser(ParseRouters.class)
+   @Fallback(EmptyRoutersFallback.class)
+   Routers list(PaginationOptions options);
+
+   /**
+    * Returns a Routers collection that should contain a single router with the id requested.
+    *
+    * @param id the id of the router to return
+    * @return Routers collection or empty if not found
+    */
+   @Named("router:get")
+   @GET
+   @Path("/{id}")
+   @SelectJson("router")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Nullable
+   Router get(@PathParam("id") String id);
+
+   /**
+    * Create a new router
+    *
+    * @param router Options for creating a router
+    * @return the newly created router
+    */
+   @Named("router:create")
+   @POST
+   @SelectJson("router")
+   Router create(@WrapWith("router") Router.CreateOptions router);
+
+   /**
+    * Update a router
+    *
+    * @param id the id of the router to update
+    * @param router Contains only the attributes to update
+    * @return The modified router
+    */
+   @Named("router:update")
+   @PUT
+   @Path("/{id}")
+   @SelectJson("router")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Nullable
+   Router update(@PathParam("id") String id, @WrapWith("router") Router.UpdateOptions router);
+
+   /**
+    * Deletes the specified router
+    *
+    * @param id the id of the router to delete
+    * @return true if delete successful, false if not
+    */
+   @Named("router:delete")
+   @DELETE
+   @Path("/{id}")
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean delete(@PathParam("id") String id);
+
+   /**
+    * Add a interface to a router to connect to the specified subnet
+    *
+    * @param routerId the id of the router to create the interface at
+    * @param subnetId the id of the subnet to connect with the interface
+    * @return the newly-created router interface
+    */
+   @Named("router:addInterfaceForSubnet")
+   @PUT
+   @Path("/{id}/add_router_interface")
+   @MapBinder(EmptyOptions.class)
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Nullable
+   RouterInterface addInterfaceForSubnet(@PathParam("id") String routerId, @PayloadParam("subnet_id") String subnetId);
+
+   /**
+    * Add a interface to a router to connect to the specified port
+    *
+    * @param routerId the id of the router to create the interface at
+    * @param portId the id of the port to connect with the interface
+    * @return the newly-created router interface
+    */
+   @Named("router:addInterfaceForPort")
+   @PUT
+   @Path("/{id}/add_router_interface")
+   @MapBinder(EmptyOptions.class)
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Nullable
+   RouterInterface addInterfaceForPort(@PathParam("id") String routerId, @PayloadParam("port_id") String portId);
+
+   /**
+    * Remove the interface where the specified subnet is connected to
+    *
+    * @param routerId the id of the router to remove the interface from
+    * @param subnetId the id of the subnet to disconnect from the interface
+    */
+   @Named("router:removeInterfaceForSubnet")
+   @PUT
+   @Path("/{id}/remove_router_interface")
+   @MapBinder(EmptyOptions.class)
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean removeInterfaceForSubnet(@PathParam("id") String routerId, @PayloadParam("subnet_id") String subnetId);
+
+   /**
+    * Remove the interface where the specified port is connected to
+    *
+    * @param routerId the id of the router to remove the interface from
+    * @param portId the id of the port to disconnect from the interface
+    */
+   @Named("router:removeInterfaceForPort")
+   @PUT
+   @Path("/{id}/remove_router_interface")
+   @MapBinder(EmptyOptions.class)
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean removeInterfaceForPort(@PathParam("id") String routerId, @PayloadParam("port_id") String portId);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyNetworksFallback.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyNetworksFallback.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyNetworksFallback.java
new file mode 100644
index 0000000..3a859a9
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyNetworksFallback.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.neutron.v2.fallbacks;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.jclouds.Fallback;
+import org.jclouds.openstack.neutron.v2.domain.Networks;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.propagate;
+import static com.google.common.util.concurrent.Futures.immediateFuture;
+import static org.jclouds.http.HttpUtils.contains404;
+import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
+
+public class EmptyNetworksFallback implements Fallback<Networks> {
+
+   public ListenableFuture<Networks> create(Throwable t) throws Exception {
+      return immediateFuture(createOrPropagate(t));
+   }
+
+   @Override
+   public Networks createOrPropagate(Throwable t) throws Exception {
+      if ((getFirstThrowableOfType(checkNotNull(t, "throwable"), ResourceNotFoundException.class) != null)
+            || contains404(t)) {
+         return Networks.EMPTY;
+      }
+      throw propagate(t);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyPortsFallback.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyPortsFallback.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyPortsFallback.java
new file mode 100644
index 0000000..2ca5c84
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyPortsFallback.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.neutron.v2.fallbacks;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.jclouds.Fallback;
+import org.jclouds.openstack.neutron.v2.domain.Ports;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.propagate;
+import static com.google.common.util.concurrent.Futures.immediateFuture;
+import static org.jclouds.http.HttpUtils.contains404;
+import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
+
+public class EmptyPortsFallback implements Fallback<Ports> {
+
+   public ListenableFuture<Ports> create(Throwable t) throws Exception {
+      return immediateFuture(createOrPropagate(t));
+   }
+
+   @Override
+   public Ports createOrPropagate(Throwable t) throws Exception {
+      if ((getFirstThrowableOfType(checkNotNull(t, "throwable"), ResourceNotFoundException.class) != null)
+            || contains404(t)) {
+         return Ports.EMPTY;
+      }
+      throw propagate(t);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyRoutersFallback.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyRoutersFallback.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyRoutersFallback.java
new file mode 100644
index 0000000..7019510
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyRoutersFallback.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.neutron.v2.fallbacks;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.jclouds.Fallback;
+import org.jclouds.openstack.neutron.v2.domain.Routers;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.propagate;
+import static com.google.common.util.concurrent.Futures.immediateFuture;
+import static org.jclouds.http.HttpUtils.contains404;
+import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
+
+public class EmptyRoutersFallback implements Fallback<Routers> {
+
+   public ListenableFuture<Routers> create(Throwable t) throws Exception {
+      return immediateFuture(createOrPropagate(t));
+   }
+
+   @Override
+   public Routers createOrPropagate(Throwable t) throws Exception {
+      if ((getFirstThrowableOfType(checkNotNull(t, "throwable"), ResourceNotFoundException.class) != null)
+            || contains404(t)) {
+         return Routers.EMPTY;
+      }
+      throw propagate(t);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptySubnetsFallback.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptySubnetsFallback.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptySubnetsFallback.java
new file mode 100644
index 0000000..6f86023
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptySubnetsFallback.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.neutron.v2.fallbacks;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.jclouds.Fallback;
+import org.jclouds.openstack.neutron.v2.domain.Subnets;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.propagate;
+import static com.google.common.util.concurrent.Futures.immediateFuture;
+import static org.jclouds.http.HttpUtils.contains404;
+import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
+
+public class EmptySubnetsFallback implements Fallback<Subnets> {
+
+   public ListenableFuture<Subnets> create(Throwable t) throws Exception {
+      return immediateFuture(createOrPropagate(t));
+   }
+
+   @Override
+   public Subnets createOrPropagate(Throwable t) throws Exception {
+      if ((getFirstThrowableOfType(checkNotNull(t, "throwable"), ResourceNotFoundException.class) != null)
+            || contains404(t)) {
+         return Subnets.EMPTY;
+      }
+      throw propagate(t);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/features/NetworkApi.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/features/NetworkApi.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/features/NetworkApi.java
new file mode 100644
index 0000000..cd02cac
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/features/NetworkApi.java
@@ -0,0 +1,152 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.features;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import org.jclouds.Fallbacks;
+import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404;
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.neutron.v2.domain.Network;
+import org.jclouds.openstack.neutron.v2.domain.Networks;
+import org.jclouds.openstack.neutron.v2.fallbacks.EmptyNetworksFallback;
+import org.jclouds.openstack.neutron.v2.functions.NetworksToPagedIterable;
+import org.jclouds.openstack.neutron.v2.functions.ParseNetworks;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.annotations.WrapWith;
+
+import javax.inject.Named;
+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.core.MediaType;
+
+/**
+ * Provides synchronous access to Network operations on the openstack Neutron API.
+ * <p/>
+ * Each tenant can define one or more networks. A network is a virtual isolated layer-2 broadcast domain reserved to the
+ * tenant. A tenant can create several ports for a network, and plug virtual interfaces into these ports.
+ *
+ * @see <a href=
+ *      "http://docs.openstack.org/api/openstack-network/2.0/content/Networks.html">api doc</a>
+ */
+@Beta
+@Path("/v2.0/networks")
+@RequestFilters(AuthenticateRequest.class)
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public interface NetworkApi {
+
+   /**
+    * Returns all networks currently defined in Neutron for the current tenant.
+    *
+    * @return the list of all networks configured for the tenant
+    */
+   @Named("network:list")
+   @GET
+   @ResponseParser(ParseNetworks.class)
+   @Transform(NetworksToPagedIterable.class)
+   @Fallback(EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<Network> list();
+
+   /**
+    * @see <a href="http://docs.openstack.org/api/openstack-network/2.0/content/pagination.html">api doc</a>
+    */
+   @Named("network:list")
+   @GET
+   @ResponseParser(ParseNetworks.class)
+   @Fallback(EmptyNetworksFallback.class)
+   Networks list(PaginationOptions options);
+
+   /**
+    * Return a specific network
+    *
+    * @param id the id of the network to return
+    * @return Network or null if not found
+    */
+   @Named("network:get")
+   @GET
+   @Path("/{id}")
+   @SelectJson("network")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Nullable
+   Network get(@PathParam("id") String id);
+
+   /**
+    * Create a new network with the specified type
+    *
+    * @param network Describes the network to be created.
+    * @return a reference of the newly-created network
+    */
+   @Named("network:create")
+   @POST
+   @SelectJson("network")
+   Network create(@WrapWith("network") Network.CreateOptions network);
+
+   /**
+    * Create multiple networks
+    *
+    * @param networks the bulk of networks to create
+    * @return list of references of the newly-created networks
+    */
+   @Named("network:createBulk")
+   @POST
+   @SelectJson("networks")
+   FluentIterable<Network> createBulk(@WrapWith("networks") ImmutableList<Network.CreateOptions> networks);
+
+   /**
+    * Update a network
+    *
+    * @param id the id of the network to update
+    * @param network the network to update
+    * @return true if update successful, false if not
+    */
+   @Named("network:update")
+   @PUT
+   @Path("/{id}")
+   @SelectJson("network")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Nullable
+   Network update(@PathParam("id") String id, @WrapWith("network") Network.UpdateOptions network);
+
+   /**
+    * Deletes the specified network
+    *
+    * @param id the id of the network to delete
+    * @return true if delete was successful, false if not
+    */
+   @Named("network:delete")
+   @DELETE
+   @Path("/{id}")
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean delete(@PathParam("id") String id);
+}


[5/5] git commit: Neutron Refactoring v2_0 -> v2 No options (redesign) More features (extension-related) Live tests Redesigned domain objects for create/update options.

Posted by za...@apache.org.
Neutron Refactoring v2_0 -> v2 No options (redesign) More features (extension-related) Live tests Redesigned domain objects for create/update options.


Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/commit/9c4bd944
Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/tree/9c4bd944
Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/diff/9c4bd944

Branch: refs/heads/master
Commit: 9c4bd94485730d0037a79b3c697f0819efa388f8
Parents: 1f4a3c0
Author: Zack Shoylev <za...@rackspace.com>
Authored: Mon Apr 14 18:48:42 2014 -0500
Committer: Zack Shoylev <za...@rackspace.com>
Committed: Fri Jul 25 16:12:53 2014 -0500

----------------------------------------------------------------------
 openstack-neutron/pom.xml                       |   5 +
 .../openstack/neutron/v2/NeutronApi.java        |  81 ++
 .../neutron/v2/NeutronApiMetadata.java          | 101 +++
 .../neutron/v2/config/NeutronHttpApiModule.java |  84 ++
 .../neutron/v2/domain/AddressPair.java          | 182 +++++
 .../neutron/v2/domain/AllocationPool.java       | 133 ++++
 .../neutron/v2/domain/ExternalGatewayInfo.java  | 128 ++++
 .../neutron/v2/domain/ExtraDhcpOption.java      | 161 ++++
 .../openstack/neutron/v2/domain/HostRoute.java  | 118 +++
 .../jclouds/openstack/neutron/v2/domain/IP.java | 132 ++++
 .../neutron/v2/domain/IPv6DHCPMode.java         |  57 ++
 .../openstack/neutron/v2/domain/Network.java    | 647 ++++++++++++++++
 .../neutron/v2/domain/NetworkSegment.java       | 163 ++++
 .../neutron/v2/domain/NetworkStatus.java        |  57 ++
 .../neutron/v2/domain/NetworkType.java          |  69 ++
 .../openstack/neutron/v2/domain/Networks.java   |  35 +
 .../openstack/neutron/v2/domain/Port.java       | 765 +++++++++++++++++++
 .../openstack/neutron/v2/domain/Ports.java      |  35 +
 .../openstack/neutron/v2/domain/Router.java     | 285 +++++++
 .../neutron/v2/domain/RouterInterface.java      | 136 ++++
 .../openstack/neutron/v2/domain/Routers.java    |  35 +
 .../openstack/neutron/v2/domain/Subnet.java     | 467 +++++++++++
 .../openstack/neutron/v2/domain/Subnets.java    |  35 +
 .../openstack/neutron/v2/domain/VIFType.java    |  62 ++
 .../openstack/neutron/v2/domain/VNICType.java   |  56 ++
 .../neutron/v2/extensions/RouterApi.java        | 197 +++++
 .../v2/fallbacks/EmptyNetworksFallback.java     |  45 ++
 .../v2/fallbacks/EmptyPortsFallback.java        |  45 ++
 .../v2/fallbacks/EmptyRoutersFallback.java      |  45 ++
 .../v2/fallbacks/EmptySubnetsFallback.java      |  45 ++
 .../neutron/v2/features/NetworkApi.java         | 152 ++++
 .../openstack/neutron/v2/features/PortApi.java  | 150 ++++
 .../neutron/v2/features/SubnetApi.java          | 146 ++++
 .../v2/functions/NetworksToPagedIterable.java   |  64 ++
 .../neutron/v2/functions/ParseNetworks.java     |  38 +
 .../neutron/v2/functions/ParsePorts.java        |  37 +
 .../neutron/v2/functions/ParseRouters.java      |  37 +
 .../neutron/v2/functions/ParseSubnets.java      |  37 +
 .../v2/functions/PortsToPagedIterable.java      |  64 ++
 .../v2/functions/RouterToPagedIterable.java     |  66 ++
 .../v2/functions/SubnetsToPagedIterable.java    |  64 ++
 .../v2/handlers/NeutronErrorHandler.java        |  62 ++
 .../neutron/v2/options/EmptyOptions.java        |  47 ++
 .../openstack/neutron/v2_0/NeutronApi.java      |   2 +
 .../neutron/v2_0/NeutronApiMetadata.java        |   3 +-
 .../v2_0/config/NeutronHttpApiModule.java       |  30 +-
 .../neutron/v2_0/extensions/RouterApi.java      |   2 +
 .../neutron/v2_0/features/NetworkApi.java       |   2 +
 .../neutron/v2_0/features/PortApi.java          |   2 +
 .../neutron/v2_0/features/SubnetApi.java        |   2 +
 .../services/org.jclouds.apis.ApiMetadata       |   1 +
 .../neutron/v2/NeutronApiMetadataTest.java      |  35 +
 .../neutron/v2/features/NetworkApiLiveTest.java | 100 +++
 .../neutron/v2/features/NetworkApiMockTest.java | 464 +++++++++++
 .../neutron/v2/features/PortApiLiveTest.java    | 149 ++++
 .../neutron/v2/features/PortApiMockTest.java    | 492 ++++++++++++
 .../neutron/v2/features/RouterApiLiveTest.java  | 171 +++++
 .../neutron/v2/features/RouterApiMockTest.java  | 631 +++++++++++++++
 .../neutron/v2/features/SubnetApiLiveTest.java  | 118 +++
 .../neutron/v2/features/SubnetApiMockTest.java  | 472 ++++++++++++
 .../v2/internal/BaseNeutronApiLiveTest.java     |  46 ++
 .../v2/internal/BaseNeutronApiMockTest.java     |  41 +
 .../openstack/neutron/v2/util/ClassUtil.java    |  39 +
 .../neutron/v2/util/PredicateUtil.java          |  47 ++
 .../v2_0/internal/BaseNeutronApiLiveTest.java   |   2 +-
 .../v2_0/internal/BaseNeutronExpectTest.java    |   2 +-
 .../src/test/resources/access.json              | 228 ++++++
 .../src/test/resources/list_networks.json       | 124 +--
 .../src/test/resources/list_ports.json          | 172 ++---
 .../src/test/resources/list_routers.json        | 100 +--
 .../src/test/resources/list_subnets.json        | 196 ++---
 .../src/test/resources/network.json             |  14 +-
 .../resources/network_bulk_create_request.json  |  12 +
 .../resources/network_bulk_create_response.json |  18 +
 .../test/resources/network_create_request.json  |   4 +
 .../test/resources/network_create_response.json |   7 +
 .../test/resources/network_get_response.json    |   7 +
 .../test/resources/network_list_response.json   |  62 ++
 .../resources/network_list_response_paged1.json |  40 +
 .../resources/network_list_response_paged2.json |  36 +
 .../test/resources/network_update_request.json  |   4 +
 .../test/resources/network_update_response.json |  11 +
 openstack-neutron/src/test/resources/port.json  |  14 +-
 .../resources/port_create_bulk_request.json     |  22 +
 .../resources/port_create_bulk_response.json    |  47 ++
 .../src/test/resources/port_create_request.json |  14 +
 .../test/resources/port_create_response.json    |  29 +
 .../src/test/resources/port_get_response.json   |  10 +
 .../src/test/resources/port_list_response.json  |  86 +++
 .../resources/port_list_response_paged1.json    |  48 ++
 .../resources/port_list_response_paged2.json    |  44 ++
 .../src/test/resources/port_update_request.json |   8 +
 .../test/resources/port_update_response.json    |  23 +
 .../src/test/resources/router.json              |  16 +-
 .../router_add_interface_port_request.json      |   3 +
 .../resources/router_add_interface_request.json |   3 +
 .../router_add_interface_response.json          |   4 +
 .../test/resources/router_create_request.json   |   9 +
 .../test/resources/router_create_response.json  |  12 +
 .../src/test/resources/router_get_response.json |  12 +
 .../test/resources/router_list_response.json    |  74 ++
 .../resources/router_list_response_paged1.json  |  34 +
 .../resources/router_list_response_paged2.json  |  30 +
 .../router_remove_interface_port_request.json   |   3 +
 .../router_remove_interface_subnet_request.json |   3 +
 .../test/resources/router_update_request.json   |   7 +
 .../test/resources/router_update_response.json  |  12 +
 .../src/test/resources/subnet.json              |  16 +-
 .../resources/subnet_bulk_create_request.json   |  14 +
 .../resources/subnet_bulk_create_response.json  |  48 ++
 .../test/resources/subnet_create_request.json   |   6 +
 .../test/resources/subnet_create_response.json  |   8 +
 .../src/test/resources/subnet_get_response.json |   9 +
 .../test/resources/subnet_list_response.json    |  98 +++
 .../resources/subnet_list_response_pages1.json  |  30 +
 .../resources/subnet_list_response_pages2.json  |  26 +
 .../test/resources/subnet_update_request.json   |   6 +
 .../test/resources/subnet_update_response.json  |  18 +
 118 files changed, 9762 insertions(+), 342 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/pom.xml
----------------------------------------------------------------------
diff --git a/openstack-neutron/pom.xml b/openstack-neutron/pom.xml
index bb62eba..20d0d47 100644
--- a/openstack-neutron/pom.xml
+++ b/openstack-neutron/pom.xml
@@ -100,6 +100,11 @@
       <artifactId>logback-classic</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.squareup.okhttp</groupId>
+      <artifactId>mockwebserver</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <profiles>

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApi.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApi.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApi.java
new file mode 100644
index 0000000..1f78ba9
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApi.java
@@ -0,0 +1,81 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2;
+
+import com.google.common.base.Optional;
+import com.google.inject.Provides;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.location.Zone;
+import org.jclouds.location.functions.ZoneToEndpoint;
+import org.jclouds.openstack.neutron.v2.extensions.RouterApi;
+import org.jclouds.openstack.neutron.v2.features.NetworkApi;
+import org.jclouds.openstack.neutron.v2.features.PortApi;
+import org.jclouds.openstack.neutron.v2.features.SubnetApi;
+import org.jclouds.openstack.v2_0.features.ExtensionApi;
+import org.jclouds.rest.annotations.Delegate;
+import org.jclouds.rest.annotations.EndpointParam;
+
+import java.io.Closeable;
+import java.util.Set;
+
+/**
+ * Provides synchronous access to Neutron.
+ * <p/>
+ *
+ * @see <a href="http://docs.openstack.org/api/openstack-network/2.0/content/">api doc</a>
+ */
+public interface NeutronApi extends Closeable {
+   /**
+    * @return the Zone codes configured
+    */
+   @Provides
+   @Zone
+   Set<String> getConfiguredRegions();
+
+   /**
+    * Provides synchronous access to Extension features.
+    */
+   @Delegate
+   ExtensionApi getExtensionApiForZone(
+           @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
+
+   /**
+    * Provides synchronous access to Network features.
+    */
+   @Delegate
+   NetworkApi getNetworkApiForZone(@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
+
+   /**
+    * Provides synchronous access to Subnet features
+    */
+   @Delegate
+   SubnetApi getSubnetApiForZone(@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
+
+   /**
+    * Provides synchronous access to Port features.
+    */
+   @Delegate
+   PortApi getPortApiForZone(@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
+
+   /**
+    * Provides synchronous access to Router features.
+    */
+   @Delegate
+   Optional<? extends RouterApi> getRouterExtensionForZone(@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApiMetadata.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApiMetadata.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApiMetadata.java
new file mode 100644
index 0000000..9e6aa94
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApiMetadata.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.openstack.keystone.v2_0.config.AuthenticationApiModule;
+import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.ZoneModule;
+import org.jclouds.openstack.neutron.v2.config.NeutronHttpApiModule;
+import org.jclouds.openstack.v2_0.ServiceType;
+import org.jclouds.rest.internal.BaseHttpApiMetadata;
+
+import java.net.URI;
+import java.util.Properties;
+
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
+import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
+
+/**
+ * Implementation of {@link org.jclouds.apis.ApiMetadata} for Neutron 2.0 API
+ *
+ */
+public class NeutronApiMetadata extends BaseHttpApiMetadata<NeutronApi> {
+
+   @Override
+   public Builder toBuilder() {
+      return new Builder().fromApiMetadata(this);
+   }
+
+   public NeutronApiMetadata() {
+      this(new Builder());
+   }
+
+   protected NeutronApiMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = BaseHttpApiMetadata.defaultProperties();
+      properties.setProperty(SERVICE_TYPE, ServiceType.NETWORK);
+      properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
+      return properties;
+   }
+
+   public static class Builder extends BaseHttpApiMetadata.Builder<NeutronApi, Builder> {
+
+      protected Builder() {
+         super(NeutronApi.class);
+         id("openstack-neutron")
+            .name("OpenStack Neutron API")
+            .identityName("${tenantName}:${userName} or ${userName}, if your keystone supports a default tenant")
+            .credentialName("${password}")
+            .endpointName("Neutron base url ending in /v2.0/")
+            .documentation(URI.create("http://docs.openstack.org/api/openstack-network/2.0/content/"))
+            .version("2.0")
+            .defaultEndpoint("http://localhost:5000/v2.0/")
+            .defaultProperties(NeutronApiMetadata.defaultProperties())
+            .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
+               .add(AuthenticationApiModule.class)
+               .add(KeystoneAuthenticationModule.class)
+               .add(ZoneModule.class)
+               .add(NeutronHttpApiModule.class).build());
+      }
+
+      @Override
+      public NeutronApiMetadata build() {
+         return new NeutronApiMetadata(this);
+      }
+
+      @Override
+      public Builder fromApiMetadata(ApiMetadata in) {
+         super.fromApiMetadata(in);
+         return this;
+      }
+
+      @Override
+      protected Builder self() {
+         return this;
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/config/NeutronHttpApiModule.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/config/NeutronHttpApiModule.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/config/NeutronHttpApiModule.java
new file mode 100644
index 0000000..9274813
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/config/NeutronHttpApiModule.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.config;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Multimap;
+import com.google.inject.Provides;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.http.annotation.Redirection;
+import org.jclouds.http.annotation.ServerError;
+import org.jclouds.json.config.GsonModule.DateAdapter;
+import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
+import org.jclouds.openstack.neutron.v2.NeutronApi;
+import org.jclouds.openstack.neutron.v2.handlers.NeutronErrorHandler;
+import org.jclouds.openstack.v2_0.domain.Extension;
+import org.jclouds.openstack.v2_0.functions.PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet;
+import org.jclouds.rest.ConfiguresHttpApi;
+import org.jclouds.rest.config.HttpApiModule;
+import org.jclouds.rest.functions.ImplicitOptionalConverter;
+
+import javax.inject.Provider;
+import javax.inject.Singleton;
+import java.net.URI;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Configures the Neutron connection.
+ *
+ */
+@ConfiguresHttpApi
+public class NeutronHttpApiModule extends HttpApiModule<NeutronApi> {
+
+   @Override
+   protected void configure() {
+      bind(DateAdapter.class).to(Iso8601DateAdapter.class);
+      bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.class);
+      super.configure();
+   }
+
+   @Provides
+   @Singleton
+   public Multimap<URI, URI> aliases() {
+       return ImmutableMultimap.<URI, URI>builder()
+          .build();
+   }
+
+   @Provides
+   @Singleton
+   public LoadingCache<String, Set<? extends Extension>> provideExtensionsByZone(final Provider<NeutronApi> quantumApi) {
+      return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS)
+            .build(new CacheLoader<String, Set<? extends Extension>>() {
+               @Override
+               public Set<? extends Extension> load(String key) throws Exception {
+                  return quantumApi.get().getExtensionApiForZone(key).list();
+               }
+            });
+   }
+
+   @Override
+   protected void bindErrorHandlers() {
+      bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(NeutronErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(NeutronErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(NeutronErrorHandler.class);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AddressPair.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AddressPair.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AddressPair.java
new file mode 100644
index 0000000..4e222af
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AddressPair.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.base.Objects;
+
+import javax.inject.Named;
+import java.beans.ConstructorProperties;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Contains a mapping between a MAC address and an IP address.
+ */
+public class AddressPair  {
+
+   @Named("mac_address")
+   private String macAddress;
+   @Named("ip_address")
+   private String ipAddress;
+
+   @ConstructorProperties({"mac_address", "ip_address"})
+   protected AddressPair(String macAddress, String ipAddress) {
+      checkNotNull(macAddress, "mac address should not be null");
+      checkNotNull(ipAddress, "ip should not be null");
+      this.macAddress = macAddress;
+      this.ipAddress = ipAddress;
+   }
+
+   /**
+    * Copy constructor
+    * @param addressPair
+    */
+   private AddressPair(AddressPair addressPair) {
+      this(addressPair.getMacAddress(), addressPair.getIpAddress());
+   }
+
+   /**
+    * Default constructor
+    */
+   private AddressPair() {}
+
+   /**
+    * @return the macAddress of the AddressPair
+    */
+   public String getMacAddress() {
+      return macAddress;
+   }
+
+   /**
+    * @return the ipAddress of the AddressPair
+    */
+   public String getIpAddress() {
+      return ipAddress;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(macAddress, ipAddress);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      AddressPair that = AddressPair.class.cast(obj);
+      return Objects.equal(this.macAddress, that.macAddress) && Objects.equal(this.ipAddress, that.ipAddress);
+   }
+
+   protected Objects.ToStringHelper string() {
+      return Objects.toStringHelper(this).add("macAddress", macAddress).add("ipAddress", ipAddress);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   /**
+    * Returns a builder, but requires the user to specify any parameters required when creating a resource.
+    * In this case, both parameters are required.
+    * @return the Builder for AddressPair
+    */
+   public static Builder createOptions(String macAddress, String ipAddress) {
+      return new Builder(macAddress, ipAddress);
+   }
+
+   /**
+    * Returns a builder, but requires the user to specify any parameters required when updating a resource.
+    * In this case, there are none.
+    * @return the Builder for AddressPair
+    */
+   public static Builder updateOptions() {
+      return new Builder();
+   }
+
+   /**
+    * Gets a Builder configured as this object.
+    */
+   public Builder toBuilder() {
+      return new Builder().fromAddressPair(this);
+   }
+
+   public static class Builder {
+      // Keep track of the builder's state.
+      private AddressPair addressPair;
+
+      /**
+       * No-parameters constructor used when updating.
+       * */
+      private Builder() {
+         addressPair = new AddressPair();
+      }
+
+      /**
+       * Required parameters constructor used when creating.
+       * @param macAddress
+       * @param ipAddress
+       */
+      private Builder(String macAddress, String ipAddress) {
+         addressPair = new AddressPair();
+         addressPair.macAddress = macAddress;
+         addressPair.ipAddress = ipAddress;
+      }
+
+      /**
+       * Provide the macAddress to the AddressPair's Builder.
+       *
+       * @return the Builder.
+       * @see AddressPair#getMacAddress()
+       */
+      public Builder macAddress(String macAddress) {
+         addressPair.macAddress = macAddress;
+         return this;
+      }
+
+      /**
+       * Provide the ipAddress to the AddressPair's Builder.
+       *
+       * @return the Builder.
+       * @see AddressPair#getIpAddress()
+       */
+      public Builder ipAddress(String ipAddress) {
+         addressPair.ipAddress = ipAddress;
+         return this;
+      }
+
+      /**
+       * @return a AddressPair constructed with this Builder.
+       */
+      public AddressPair build() {
+         // Use the copy constructor to copy the builder's state (config) object and pass back to the user.
+         // Immutability is preserved, and fields are defined only once.
+         return new AddressPair(addressPair);
+      }
+
+      /**
+       * @return a Builder from another AddressPair.
+       */
+      public Builder fromAddressPair(AddressPair in) {
+         return this.macAddress(in.getMacAddress()).ipAddress(in.getIpAddress());
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AllocationPool.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AllocationPool.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AllocationPool.java
new file mode 100644
index 0000000..6df93cd
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AllocationPool.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.base.Objects;
+
+/**
+ * A Neutron Subnet Allocation Pool
+ * Contains a start and an end IP address describing the pool.
+ *
+ * @see <a
+ *      href="http://docs.openstack.org/api/openstack-network/2.0/content/Subnets.html">api
+ *      doc</a>
+ */
+public class AllocationPool {
+
+   protected final String start;
+   protected final String end;
+
+   protected AllocationPool(String start, String end) {
+      this.start = start;
+      this.end = end;
+   }
+
+   /**
+    * @return the start of the AllocationPool
+    */
+   public String getStart() {
+      return start;
+   }
+
+   /**
+    * @return the end of the AllocationPool
+    */
+   public String getEnd() {
+      return end;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(start, end);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      AllocationPool that = AllocationPool.class.cast(obj);
+      return Objects.equal(this.start, that.start) && Objects.equal(this.end, that.end);
+   }
+
+   protected Objects.ToStringHelper string() {
+      return Objects.toStringHelper(this).add("start", start).add("end", end);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   /**
+    * @return the Builder for AllocationPool
+    */
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   /**
+    * Gets a Builder configured as this object.
+    */
+   public Builder toBuilder() {
+      return new Builder().fromAllocationPool(this);
+   }
+
+   public static class Builder {
+      protected String start;
+      protected String end;
+
+      /**
+       * Provide the start to the AllocationPool's Builder.
+       *
+       * @return the Builder.
+       * @see AllocationPool#getStart()
+       */
+      public Builder start(String start) {
+         this.start = start;
+         return this;
+      }
+
+      /**
+       * Provide the end to the AllocationPool's Builder.
+       *
+       * @return the Builder.
+       * @see AllocationPool#getEnd()
+       */
+      public Builder end(String end) {
+         this.end = end;
+         return this;
+      }
+
+      /**
+       * @return a AllocationPool constructed with this Builder.
+       */
+      public AllocationPool build() {
+         return new AllocationPool(start, end);
+      }
+
+      /**
+       * @return a Builder from another AllocationPool.
+       */
+      public Builder fromAllocationPool(AllocationPool in) {
+         return this.start(in.getStart()).end(in.getEnd());
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/ExternalGatewayInfo.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/ExternalGatewayInfo.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/ExternalGatewayInfo.java
new file mode 100644
index 0000000..d66bc04
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/ExternalGatewayInfo.java
@@ -0,0 +1,128 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.base.Objects;
+
+import javax.inject.Named;
+
+/**
+ * Information on the external gateway for the router
+ */
+public class ExternalGatewayInfo {
+
+   @Named("network_id")
+   protected final String networkId;
+   @Named("enable_snat")
+   protected final Boolean enableSnat;
+
+   protected ExternalGatewayInfo(String networkId, Boolean enableSnat) {
+      this.networkId = networkId;
+      this.enableSnat = enableSnat;
+   }
+
+   /**
+    * @return the networkId of the ExternalGatewayInfo
+    */
+   public String getNetworkId() {
+      return networkId;
+   }
+
+   /**
+    * @return the enableSnat status of the ExternalGatewayInfo
+    */
+   public Boolean getEnableSnat() {
+      return enableSnat;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(networkId, enableSnat);
+   }
+
+   @Override
+   public boolean equals(Object o) {
+      if (this == o)
+         return true;
+      if (o == null || getClass() != o.getClass())
+         return false;
+
+      ExternalGatewayInfo that = (ExternalGatewayInfo) o;
+
+      return Objects.equal(this.networkId, that.networkId) &&
+            Objects.equal(this.enableSnat, that.enableSnat);
+   }
+
+   /**
+    * @return the Builder for ExternalGatewayInfo
+    */
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   /**
+    * Gets a Builder configured as this object.
+    */
+   public Builder toBuilder() {
+      return new Builder().fromExternalGatewayInfo(this);
+   }
+
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this)
+            .add("networkId", networkId)
+            .add("enableSnat", enableSnat)
+            .toString();
+   }
+
+   public static class Builder {
+      protected String networkId;
+      protected Boolean enableSnat;
+
+      /**
+       * Provide the networkId to the ExternalGatewayInfo's Builder.
+       *
+       * @return the Builder.
+       * @see ExternalGatewayInfo#getNetworkId()
+       */
+      public Builder networkId(String networkId) {
+         this.networkId = networkId;
+         return this;
+      }
+
+      public Builder enableSnat(boolean enableSnat) {
+         this.enableSnat = enableSnat;
+         return this;
+      }
+
+      /**
+       * @return a ExternalGatewayInfo constructed with this Builder.
+       */
+      public ExternalGatewayInfo build() {
+         return new ExternalGatewayInfo(networkId, enableSnat);
+      }
+
+      /**
+       * @return a Builder from another ExternalGatewayInfo.
+       */
+      public Builder fromExternalGatewayInfo(ExternalGatewayInfo in) {
+         return this.networkId(in.getNetworkId()).enableSnat(in.getEnableSnat());
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/ExtraDhcpOption.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/ExtraDhcpOption.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/ExtraDhcpOption.java
new file mode 100644
index 0000000..6b7dfd8
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/ExtraDhcpOption.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.base.Objects;
+
+import javax.inject.Named;
+
+/**
+ * This is used to provide additional DHCP-related options to Subnet. This is
+ * based on a neutron extension.
+ * For example PXE boot options to DHCP clients can be specified (e.g. tftp-server,
+ * server-ip-address, bootfile-name)
+ *
+ * @see <a
+ *      href="http://docs.openstack.org/api/openstack-network/2.0/content/Subnets.html">api
+ *      doc</a>
+ */
+public class ExtraDhcpOption {
+
+   protected final String id;
+   @Named("opt_name")
+   protected final String optionName;
+   @Named("opt_value")
+   protected final String optionValue;
+
+   protected ExtraDhcpOption(String id, String optionName, String optionValue) {
+      this.id = id;
+      this.optionName = optionName;
+      this.optionValue = optionValue;
+   }
+
+   /**
+    * @return the id of the ExtraDhcpOption
+    */
+   public String getId() {
+      return id;
+   }
+
+   /**
+    * @return the optionName of the ExtraDhcpOption
+    */
+   public String getOptionName() {
+      return optionName;
+   }
+
+   /**
+    * @return the optionValue of the ExtraDhcpOption
+    */
+   public String getOptionValue() {
+      return optionValue;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id, optionName, optionValue);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      ExtraDhcpOption that = ExtraDhcpOption.class.cast(obj);
+      return Objects.equal(this.id, that.id) && Objects.equal(this.optionName, that.optionName)
+            && Objects.equal(this.optionValue, that.optionValue);
+   }
+
+   protected Objects.ToStringHelper string() {
+      return Objects.toStringHelper(this).add("id", id).add("optionName", optionName).add("optionValue", optionValue);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   /**
+    * @return the Builder for ExtraDhcpOption
+    */
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   /**
+    * Gets a Builder configured as this object.
+    */
+   public Builder toBuilder() {
+      return new Builder().fromExtraDhcpOption(this);
+   }
+
+   public static class Builder {
+      protected String id;
+      protected String optionName;
+      protected String optionValue;
+
+      /**
+       * Provide the id to the ExtraDhcpOption's Builder.
+       *
+       * @return the Builder.
+       * @see ExtraDhcpOption#getId()
+       */
+      public Builder id(String id) {
+         this.id = id;
+         return this;
+      }
+
+      /**
+       * Provide the optionName to the ExtraDhcpOption's Builder.
+       *
+       * @return the Builder.
+       * @see ExtraDhcpOption#getOptionName()
+       */
+      public Builder optionName(String optionName) {
+         this.optionName = optionName;
+         return this;
+      }
+
+      /**
+       * Provide the optionValue to the ExtraDhcpOption's Builder.
+       *
+       * @return the Builder.
+       * @see ExtraDhcpOption#getOptionValue()
+       */
+      public Builder optionValue(String optionValue) {
+         this.optionValue = optionValue;
+         return this;
+      }
+
+      /**
+       * @return a ExtraDhcpOption constructed with this Builder.
+       */
+      public ExtraDhcpOption build() {
+         return new ExtraDhcpOption(id, optionName, optionValue);
+      }
+
+      /**
+       * @return a Builder from another ExtraDhcpOption.
+       */
+      public Builder fromExtraDhcpOption(ExtraDhcpOption in) {
+         return this.id(in.getId()).optionName(in.getOptionName()).optionValue(in.getOptionValue());
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/HostRoute.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/HostRoute.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/HostRoute.java
new file mode 100644
index 0000000..04c3bda
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/HostRoute.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+
+import javax.inject.Named;
+
+/**
+ * A Neutron Subnet Host Route
+ *
+ * @see <a href="http://docs.openstack.org/api/openstack-network/2.0/content/Subnets.html">api doc</a>
+ */
+public class HostRoute {
+
+   @Named("destination")
+   private final String destinationCidr;
+   @Named("nexthop")
+   private final String nextHop;
+
+   protected HostRoute(String destinationCidr, String nextHop) {
+      this.destinationCidr = destinationCidr;
+      this.nextHop = nextHop;
+   }
+
+   /**
+    * @return the destination CIDR for this route.
+    */
+   public String getDestinationCidr() {
+      return destinationCidr;
+   }
+
+   /**
+    * @return the IP of the next hop to forward traffic to.
+    */
+   public String getNextHop() {
+      return nextHop;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(destinationCidr, nextHop);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      HostRoute that = HostRoute.class.cast(obj);
+      return Objects.equal(this.destinationCidr, that.destinationCidr) && Objects.equal(this.nextHop, that.nextHop);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper(this)
+            .add("destinationCidr", destinationCidr).add("nextHop", nextHop);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return new Builder().fromHostRoute(this);
+   }
+
+   public static class Builder {
+      protected String destinationCidr;
+      protected String nextHop;
+
+      /**
+       * This should be a valid CIDR.
+       * @see HostRoute#getDestinationCidr()
+       */
+      public Builder destinationCidr(String destinationCidr) {
+         this.destinationCidr = destinationCidr;
+         return this;
+      }
+
+      /**
+       * This should be a valid IP address.
+       * @see HostRoute#getNextHop()
+       */
+      public Builder nextHop(String nextHop) {
+         this.nextHop = nextHop;
+         return this;
+      }
+
+      public HostRoute build() {
+         return new HostRoute(destinationCidr, nextHop);
+      }
+
+      public Builder fromHostRoute(HostRoute in) {
+         return this.destinationCidr(in.getDestinationCidr()).nextHop(in.getNextHop());
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/IP.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/IP.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/IP.java
new file mode 100644
index 0000000..1885e99
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/IP.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.base.Objects;
+
+import javax.inject.Named;
+
+/**
+ * Describes an IP address
+ */
+public class IP {
+
+   @Named("ip_address")
+   protected final String ipAddress;
+   @Named("subnet_id")
+   protected final String subnetId;
+
+   protected IP(String ipAddress, String subnetId) {
+      this.ipAddress = ipAddress;
+      this.subnetId = subnetId;
+   }
+
+   /**
+    * @return the ipAddress of the IP
+    */
+   public String getIpAddress() {
+      return ipAddress;
+   }
+
+   /**
+    * @return the subnetId of the IP
+    */
+   public String getSubnetId() {
+      return subnetId;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(ipAddress, subnetId);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      IP that = IP.class.cast(obj);
+      return Objects.equal(this.ipAddress, that.ipAddress) && Objects.equal(this.subnetId, that.subnetId);
+   }
+
+   protected Objects.ToStringHelper string() {
+      return Objects.toStringHelper(this).add("ipAddress", ipAddress).add("subnetId", subnetId);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   /**
+    * @return the Builder for IP
+    */
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   /**
+    * Gets a Builder configured as this object.
+    */
+   public Builder toBuilder() {
+      return new Builder().fromIP(this);
+   }
+
+   public static class Builder {
+      protected String ipAddress;
+      protected String subnetId;
+
+      /**
+       * Provide the ipAddress to the IP's Builder.
+       *
+       * @return the Builder.
+       * @see IP#getIpAddress()
+       */
+      public Builder ipAddress(String ipAddress) {
+         this.ipAddress = ipAddress;
+         return this;
+      }
+
+      /**
+       * Provide the subnetId to the IP's Builder.
+       *
+       * @return the Builder.
+       * @see IP#getSubnetId()
+       */
+      public Builder subnetId(String subnetId) {
+         this.subnetId = subnetId;
+         return this;
+      }
+
+      /**
+       * @return a IP constructed with this Builder.
+       */
+      public IP build() {
+         return new IP(ipAddress, subnetId);
+      }
+
+      /**
+       * @return a Builder from another IP.
+       */
+      public Builder fromIP(IP in) {
+         return this.ipAddress(in.getIpAddress()).subnetId(in.getSubnetId());
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/IPv6DHCPMode.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/IPv6DHCPMode.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/IPv6DHCPMode.java
new file mode 100644
index 0000000..f985041
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/IPv6DHCPMode.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.neutron.v2.domain;
+
+/**
+ * Enumerates DHCP modes for UPv6
+ */
+public enum IPv6DHCPMode {
+   OFF("off"),
+   SLAAC("slaac"),
+   DHCPV6_STATEFUL("dhcpv6-stateful"),
+   DHCPV6_STATELESS("dhcpv6-stateless"),
+   /**
+    * Used by jclouds when the service returns an unknown value other than null.
+    */
+   UNRECOGNIZED("unrecognized");
+
+   private String name;
+
+   private IPv6DHCPMode(String name) {
+      this.name = name;
+   }
+
+   public String toString() {
+      return name;
+   }
+
+   /**
+    * This provides GSON enum support in jclouds.
+    * */
+   public static IPv6DHCPMode fromValue(String name){
+      if (name != null) {
+         for (IPv6DHCPMode value : IPv6DHCPMode.values()) {
+            if (name.equalsIgnoreCase(value.name)) {
+               return value;
+            }
+         }
+         return UNRECOGNIZED;
+      }
+      return null;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Network.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Network.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Network.java
new file mode 100644
index 0000000..1810fa2
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Network.java
@@ -0,0 +1,647 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.javax.annotation.Nullable;
+
+import javax.inject.Named;
+import java.beans.ConstructorProperties;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A Neutron network
+ *
+ * @see <a
+ *      href="http://docs.openstack.org/api/openstack-network/2.0/content/Networks.html">api
+ *      doc</a>
+ */
+public class Network {
+
+   private String id;
+   private NetworkStatus status;
+   private ImmutableSet<String> subnets;
+
+   private String name;
+   @Named("admin_state_up")
+   private Boolean adminStateUp;
+   private Boolean shared;
+   @Named("tenant_id")
+   private String tenantId;
+
+   // providernet.py: Provider Networks Extension
+   @Named("provider:network_type")
+   private NetworkType networkType;
+   @Named("provider:physical_network")
+   private String physicalNetworkName;
+   @Named("provider:segmentation_id")
+   private Integer segmentationId;
+
+   // external_net.py: Configurable external gateway modes extension
+   @Named("router:external")
+   private Boolean external;
+
+   // portsecurity.py: VMWare port security
+   @Named("port_security_enabled")
+   private Boolean portSecurity;
+
+   // n1kv.py: Cisco plugin extension; admin rights might be needed
+   @Named("n1kv:profile_id")
+   // UUID
+   private String profileId;
+   @Named("n1kv:multicast_ip")
+   private String multicastIp;
+   @Named("n1kv:segment_add")
+   private String segmentAdd;
+   @Named("n1kv:segment_del")
+   private String segmentDel;
+   @Named("n1kv:member_segments")
+   private String memberSegments;
+
+   // multiprovidernet.py: Multiprovider net extension; Segments and provider
+   // values cannot both be set.
+   private ImmutableSet<NetworkSegment> segments;
+
+   // flavor.py: Flavor support for network and router
+   @Named("flavor:network")
+   private String networkFlavor;
+
+   @ConstructorProperties({"id", "status", "subnets", "name", "admin_state_up", "shared", "tenant_id",
+         "provider:network_type", "provider:physical_network", "provider:segmentation_id", "router:external",
+         "port_security_enabled", "n1kv:profile_id", "n1kv:multicast_ip", "n1kv:segment_add", "n1kv:segment_del",
+         "n1kv:member_segments", "segments", "flavor:network"})
+   private Network(String id, NetworkStatus status, ImmutableSet<String> subnets, String name, Boolean adminStateUp,
+         Boolean shared, String tenantId, NetworkType networkType, String physicalNetworkName, Integer segmentationId,
+         Boolean external, Boolean portSecurity, String profileId, String multicastIp, String segmentAdd,
+         String segmentDel, String memberSegments, ImmutableSet<NetworkSegment> segments, String networkFlavor) {
+      // No checkNotNulls. With Neutron, any of these properties can be left null when used in an update.
+      this.id = id;
+      this.status = status;
+      this.subnets = subnets;
+      this.name = name;
+      this.adminStateUp = adminStateUp;
+      this.shared = shared;
+      this.tenantId = tenantId;
+      this.networkType = networkType;
+      this.physicalNetworkName = physicalNetworkName;
+      this.segmentationId = segmentationId;
+      this.external = external;
+      this.portSecurity = portSecurity;
+      this.profileId = profileId;
+      this.multicastIp = multicastIp;
+      this.segmentAdd = segmentAdd;
+      this.segmentDel = segmentDel;
+      this.memberSegments = memberSegments;
+      this.segments = segments;
+      this.networkFlavor = networkFlavor;
+   }
+
+   /**
+    * Default constructor.
+    */
+   private Network() {}
+
+   /**
+    * Copy constructor
+    * @param network
+    */
+   private Network(Network network) {
+      this(network.id,
+      network.status,
+      network.subnets,
+      network.name,
+      network.adminStateUp,
+      network.shared,
+      network.tenantId,
+      network.networkType,
+      network.physicalNetworkName,
+      network.segmentationId,
+      network.external,
+      network.portSecurity,
+      network.profileId,
+      network.multicastIp,
+      network.segmentAdd,
+      network.segmentDel,
+      network.memberSegments,
+      network.segments,
+      network.networkFlavor);
+   }
+
+   /**
+    * @return the id of the Network
+    */
+   @Nullable
+   public String getId() {
+      return id;
+   }
+
+   /**
+    * @return the status of the Network
+    */
+   @Nullable
+   public NetworkStatus getStatus() {
+      return status;
+   }
+
+   /**
+    * @return the subnets of the Network
+    */
+   @Nullable
+   public ImmutableSet<String> getSubnets() {
+      return subnets;
+   }
+
+   /**
+    * @return the name of the Network
+    */
+   @Nullable
+   public String getName() {
+      return name;
+   }
+
+   /**
+    * @return the adminStateUp of the Network
+    */
+   @Nullable
+   public Boolean isAdminStateUp() {
+      return adminStateUp;
+   }
+
+   /**
+    * The shared attribute can be used to create a public network, i.e.: a network which is shared with all other tenants.
+    * Control of the shared attribute could be reserved to particular users only, such as administrators.
+    * In this case, regular users trying to create a shared network will receive a 403 - Forbidden error.
+    * @return true if the network resource can be accessed by any tenant or not, false if not
+    */
+   @Nullable
+   public Boolean isShared() {
+      return shared;
+   }
+
+   /**
+    * @return the tenantId of the Network
+    */
+   @Nullable
+   public String getTenantId() {
+      return tenantId;
+   }
+
+   /**
+    * @return the networkType of the Network
+    */
+   @Nullable
+   public NetworkType getNetworkType() {
+      return networkType;
+   }
+
+   /**
+    * @return the physicalNetworkName of the Network
+    */
+   @Nullable
+   public String getPhysicalNetworkName() {
+      return physicalNetworkName;
+   }
+
+   /**
+    * @return the segmentationId of the Network
+    */
+   @Nullable
+   public Integer getSegmentationId() {
+      return segmentationId;
+   }
+
+   /**
+    * Adds external network attribute to network resource.
+    * @return the external of the Network
+    */
+   @Nullable
+   public Boolean isExternal() {
+      return external;
+   }
+
+   /**
+    * @return the portSecurity of the Network
+    */
+   @Nullable
+   public Boolean isPortSecurity() {
+      return portSecurity;
+   }
+
+   /**
+    * @return the profileId of the Network
+    */
+   @Nullable
+   public String getProfileId() {
+      return profileId;
+   }
+
+   /**
+    * @return the multicastIp of the Network
+    */
+   @Nullable
+   public String getMulticastIp() {
+      return multicastIp;
+   }
+
+   /**
+    * @return the segmentAdd of the Network
+    */
+   @Nullable
+   public String getSegmentAdd() {
+      return segmentAdd;
+   }
+
+   /**
+    * @return the segmentDel of the Network
+    */
+   @Nullable
+   public String getSegmentDel() {
+      return segmentDel;
+   }
+
+   /**
+    * @return the memberSegments of the Network
+    */
+   @Nullable
+   public String getMemberSegments() {
+      return memberSegments;
+   }
+
+   /**
+    * @return the segments of the Network
+    */
+   @Nullable
+   public ImmutableSet<NetworkSegment> getSegments() {
+      return segments;
+   }
+
+   /**
+    * @return the networkFlavor of the Network
+    */
+   @Nullable
+   public String getNetworkFlavor() {
+      return networkFlavor;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id, status, subnets, name, adminStateUp, shared, tenantId, networkType,
+            physicalNetworkName, segmentationId, external, portSecurity, profileId, multicastIp, segmentAdd, segmentDel,
+            memberSegments, segments, networkFlavor);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      Network that = Network.class.cast(obj);
+      return Objects.equal(this.id, that.id)
+            && Objects.equal(this.status, that.status)
+            && Objects.equal(this.subnets, that.subnets)
+            && Objects.equal(this.name, that.name)
+            && Objects.equal(this.adminStateUp, that.adminStateUp)
+            && Objects.equal(this.shared, that.shared)
+            && Objects.equal(this.tenantId, that.tenantId)
+            && Objects.equal(this.networkType, that.networkType)
+            && Objects.equal(this.physicalNetworkName, that.physicalNetworkName)
+            && Objects.equal(this.segmentationId, that.segmentationId)
+            && Objects.equal(this.external, that.external)
+            && Objects.equal(this.portSecurity, that.portSecurity)
+            && Objects.equal(this.profileId, that.profileId)
+            && Objects.equal(this.multicastIp, that.multicastIp)
+            && Objects.equal(this.segmentAdd, that.segmentAdd)
+            && Objects.equal(this.segmentDel, that.segmentDel)
+            && Objects.equal(this.memberSegments, that.memberSegments)
+            && Objects.equal(this.segments, that.segments)
+            && Objects.equal(this.networkFlavor, that.networkFlavor);
+   }
+
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this)
+            .add("id", id)
+            .add("status", status)
+            .add("subnets", subnets)
+            .add("name", name)
+            .add("adminStateUp", adminStateUp)
+            .add("shared", shared)
+            .add("tenantId", tenantId)
+            .add("networkType", networkType)
+            .add("physicalNetworkName", physicalNetworkName)
+            .add("segmentationId", segmentationId)
+            .add("external", external)
+            .add("portSecurity", portSecurity)
+            .add("profileId", profileId)
+            .add("multicastIp", multicastIp)
+            .add("segmentAdd", segmentAdd)
+            .add("segmentDel", segmentDel)
+            .add("memberSegments", memberSegments)
+            .add("segments", segments)
+            .add("networkFlavor", networkFlavor)
+            .toString();
+   }
+
+   /*
+    * Methods to get the Create and Update builders follow
+    */
+
+   /**
+    * @return the Builder for creating a new Router
+    */
+   public static CreateBuilder createOptions(String name) {
+      return new CreateBuilder(name);
+   }
+
+   /**
+    * @return the Builder for updating a Router
+    */
+   public static UpdateBuilder updateOptions() {
+      return new UpdateBuilder();
+   }
+
+   private static abstract class Builder<ParameterizedBuilderType> {
+      protected Network network;
+
+      /**
+       * No-parameters constructor used when updating.
+       * */
+      private Builder() {
+         network = new Network();
+      }
+
+      protected abstract ParameterizedBuilderType self();
+
+      /**
+       * Provide the name to the Network's Builder.
+       *
+       * @return the Builder.
+       * @see Network#getName()
+       */
+      public ParameterizedBuilderType name(String name) {
+         network.name = name;
+         return self();
+      }
+
+      /**
+       * Provide the adminStateUp to the Network's Builder.
+       *
+       * @return the Builder.
+       * @see Network#isAdminStateUp()
+       */
+      public ParameterizedBuilderType adminStateUp(Boolean adminStateUp) {
+         network.adminStateUp = adminStateUp;
+         return self();
+      }
+
+      /**
+       * Provide the shared to the Network's Builder.
+       *
+       * @return the Builder.
+       * @see Network#isShared()
+       */
+      public ParameterizedBuilderType shared(Boolean shared) {
+         network.shared = shared;
+         return self();
+      }
+
+      /**
+       * Provide the tenantId to the Network's Builder.
+       *
+       * @return the Builder.
+       * @see Network#getTenantId()
+       */
+      public ParameterizedBuilderType tenantId(String tenantId) {
+         network.tenantId = tenantId;
+         return self();
+      }
+
+      /**
+       * Provide the networkType to the Network's Builder.
+       *
+       * @return the Builder.
+       * @see Network#getNetworkType()
+       */
+      public ParameterizedBuilderType networkType(NetworkType networkType) {
+         network.networkType = networkType;
+         return self();
+      }
+
+      /**
+       * Provide the physicalNetworkName to the Network's Builder.
+       *
+       * @return the Builder.
+       * @see Network#getPhysicalNetworkName()
+       */
+      public ParameterizedBuilderType physicalNetworkName(String physicalNetworkName) {
+         network.physicalNetworkName = physicalNetworkName;
+         return self();
+      }
+
+      /**
+       * Provide the segmentationId to the Network's Builder.
+       *
+       * @return the Builder.
+       * @see Network#getSegmentationId()
+       */
+      public ParameterizedBuilderType segmentationId(Integer segmentationId) {
+         network.segmentationId = segmentationId;
+         return self();
+      }
+
+      /**
+       * Adds external network attribute to network resource.
+       *
+       * @return the Builder.
+       * @see Network#isExternal()
+       */
+      public ParameterizedBuilderType external(Boolean external) {
+         network.external = external;
+         return self();
+      }
+
+      /**
+       * Provide the portSecurity to the Network's Builder.
+       *
+       * @return the Builder.
+       * @see Network#isPortSecurity()
+       */
+      public ParameterizedBuilderType portSecurity(Boolean portSecurity) {
+         network.portSecurity = portSecurity;
+         return self();
+      }
+
+      /**
+       * Provide the profileId to the Network's Builder.
+       *
+       * @return the Builder.
+       * @see Network#getProfileId()
+       */
+      public ParameterizedBuilderType profileId(String profileId) {
+         network.profileId = profileId;
+         return self();
+      }
+
+      /**
+       * Provide the multicastIp to the Network's Builder.
+       *
+       * @return the Builder.
+       * @see Network#getMulticastIp()
+       */
+      public ParameterizedBuilderType multicastIp(String multicastIp) {
+         network.multicastIp = multicastIp;
+         return self();
+      }
+
+      /**
+       * Provide the segmentAdd to the Network's Builder.
+       * Cisco plugin extension; admin right might be needed to use this.
+       *
+       * @return the Builder.
+       * @see Network#getSegmentAdd()
+       */
+      public ParameterizedBuilderType segmentAdd(String segmentAdd) {
+         network.segmentAdd = segmentAdd;
+         return self();
+      }
+
+      /**
+       * Provide the segmentDel to the Network's Builder.
+       * Cisco plugin extension; admin right might be needed to use this.
+       *
+       * @return the Builder.
+       * @see Network#getSegmentDel()
+       */
+      public ParameterizedBuilderType segmentDel(String segmentDel) {
+         network.segmentDel = segmentDel;
+         return self();
+      }
+
+      /**
+       * Provide the memberSegments to the Network's Builder.
+       * Cisco plugin extension; admin right might be needed to use this.
+       *
+       * @return the Builder.
+       * @see Network#getMemberSegments()
+       */
+      public ParameterizedBuilderType memberSegments(String memberSegments) {
+         network.memberSegments = memberSegments;
+         return self();
+      }
+
+      /**
+       * Provide the segments to the Network's Builder.
+       * Multiprovider extension.
+       *
+       * @return the Builder.
+       * @see Network#getSegments()
+       */
+      public ParameterizedBuilderType segments(ImmutableSet<NetworkSegment> segments) {
+         network.segments = segments;
+         return self();
+      }
+
+      /**
+       * Provide the networkFlavor to the Network's Builder.
+       *
+       * @return the Builder.
+       * @see Network#getNetworkFlavor()
+       */
+      public ParameterizedBuilderType networkFlavor(String networkFlavor) {
+         network.networkFlavor = networkFlavor;
+         return self();
+      }
+   }
+
+   /**
+    * Create and Update builders (inheriting from Builder)
+    */
+   public static class CreateBuilder extends Builder<CreateBuilder> {
+      /**
+       * Supply required properties for creating a Builder
+       */
+      private CreateBuilder(String name) {
+         network.name = name;
+      }
+
+      /**
+       * @return a CreateOptions constructed with this Builder.
+       */
+      public CreateOptions build() {
+         return new CreateOptions(network);
+      }
+
+      protected CreateBuilder self() {
+         return this;
+      }
+   }
+
+   /**
+    * Create and Update builders (inheriting from Builder)
+    */
+   public static class UpdateBuilder extends Builder<UpdateBuilder> {
+      /**
+       * Supply required properties for updating a Builder
+       */
+      private UpdateBuilder() {
+      }
+
+      /**
+       * @return a UpdateOptions constructed with this Builder.
+       */
+      public UpdateOptions build() {
+         return new UpdateOptions(network);
+      }
+
+      protected UpdateBuilder self() {
+         return this;
+      }
+   }
+
+   /**
+    * Create and Update options - extend the domain class, passed to API update and create calls.
+    * Essentially the same as the domain class. Ensure validation and safe typing.
+    */
+   public static class CreateOptions extends Network {
+      /**
+       * Copy constructor
+       */
+      private CreateOptions(Network network) {
+         super(network);
+         checkNotNull(network.name, "name should not be null");
+      }
+   }
+
+   /**
+    * Create and Update options - extend the domain class, passed to API update and create calls.
+    * Essentially the same as the domain class. Ensure validation and safe typing.
+    */
+   public static class UpdateOptions extends Network  {
+      /**
+       * Copy constructor
+       */
+      private UpdateOptions(Network network) {
+         super(network);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/NetworkSegment.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/NetworkSegment.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/NetworkSegment.java
new file mode 100644
index 0000000..3406746
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/NetworkSegment.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.base.Objects;
+
+import javax.inject.Named;
+
+/**
+ * A Neutron Network Segment
+ * Segments and provider values cannot both be set.
+ *
+ * @see <a
+ *      href="http://docs.openstack.org/api/openstack-network/2.0/content/Subnets.html">api
+ *      doc</a>
+ */
+public class NetworkSegment {
+
+   @Named("provider:network_type")
+   protected final NetworkType networkType;
+   @Named("provider:physical_network")
+   protected final String physicalNetwork;
+   @Named("provider:segmentation_id")
+   protected final int segmentationId;
+
+   protected NetworkSegment(NetworkType networkType, String physicalNetwork, int segmentationId) {
+      this.networkType = networkType;
+      this.physicalNetwork = physicalNetwork;
+      this.segmentationId = segmentationId;
+   }
+
+   /**
+    * @return the networkType of the NetworkSegment
+    */
+   public NetworkType getNetworkType() {
+      return networkType;
+   }
+
+   /**
+    * @return the physicalNetwork of the NetworkSegment
+    */
+   public String getPhysicalNetwork() {
+      return physicalNetwork;
+   }
+
+   /**
+    * @return the segmentationId of the NetworkSegment
+    */
+   public int getSegmentationId() {
+      return segmentationId;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(networkType, physicalNetwork, segmentationId);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      NetworkSegment that = NetworkSegment.class.cast(obj);
+      return Objects.equal(this.networkType, that.networkType)
+            && Objects.equal(this.physicalNetwork, that.physicalNetwork)
+            && Objects.equal(this.segmentationId, that.segmentationId);
+   }
+
+   protected Objects.ToStringHelper string() {
+      return Objects.toStringHelper(this).add("networkType", networkType).add("physicalNetwork", physicalNetwork)
+            .add("segmentationId", segmentationId);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   /**
+    * @return the Builder for NetworkSegment
+    */
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   /**
+    * Gets a Builder configured as this object.
+    */
+   public Builder toBuilder() {
+      return new Builder().fromNetworkSegment(this);
+   }
+
+   public static class Builder {
+      protected NetworkType networkType;
+      protected String physicalNetwork;
+      protected int segmentationId;
+
+      /**
+       * Provide the networkType to the NetworkSegment's Builder.
+       *
+       * @return the Builder.
+       * @see NetworkSegment#getNetworkType()
+       */
+      public Builder networkType(NetworkType networkType) {
+         this.networkType = networkType;
+         return this;
+      }
+
+      /**
+       * Provide the physicalNetwork to the NetworkSegment's Builder.
+       *
+       * @return the Builder.
+       * @see NetworkSegment#getPhysicalNetwork()
+       */
+      public Builder physicalNetwork(String physicalNetwork) {
+         this.physicalNetwork = physicalNetwork;
+         return this;
+      }
+
+      /**
+       * Provide the segmentationId to the NetworkSegment's Builder.
+       *
+       * @return the Builder.
+       * @see NetworkSegment#getSegmentationId()
+       */
+      public Builder segmentationId(int segmentationId) {
+         this.segmentationId = segmentationId;
+         return this;
+      }
+
+      /**
+       * @return a NetworkSegment constructed with this Builder.
+       */
+      public NetworkSegment build() {
+         return new NetworkSegment(networkType, physicalNetwork, segmentationId);
+      }
+
+      /**
+       * @return a Builder from another NetworkSegment.
+       */
+      public Builder fromNetworkSegment(NetworkSegment in) {
+         return this.networkType(in.getNetworkType()).physicalNetwork(in.getPhysicalNetwork())
+               .segmentationId(in.getSegmentationId());
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/NetworkStatus.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/NetworkStatus.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/NetworkStatus.java
new file mode 100644
index 0000000..059ffa7
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/NetworkStatus.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.neutron.v2.domain;
+
+public enum NetworkStatus {
+   ACTIVE("active"),
+   DOWN("down"),
+   BUILD("build"),
+   ERROR("error"),
+   /**
+    * Used by jclouds when the service returns an unknown value other than null.
+    */
+   UNRECOGNIZED("unrecognized");
+
+   private final String name;
+
+   private NetworkStatus(String name) {
+      this.name = name;
+   }
+
+   @Override
+   public String toString() {
+      return name();
+   }
+
+   /**
+    * This provides GSON enum support in jclouds.
+    * @param name The string representation of this enum value.
+    * @return The corresponding enum value.
+    */
+   public static NetworkStatus fromValue(String name) {
+      if (name != null) {
+         for (NetworkStatus value : NetworkStatus.values()) {
+           if (name.equalsIgnoreCase(value.name)) {
+             return value;
+           }
+         }
+         return UNRECOGNIZED;
+       }
+       return null;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/NetworkType.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/NetworkType.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/NetworkType.java
new file mode 100644
index 0000000..5281cdf
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/NetworkType.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.neutron.v2.domain;
+
+/**
+ * Enumerates supported Network types.
+ */
+public enum NetworkType {
+   /**
+    * Used to describe a local network.
+    */
+   LOCAL("local"),
+   /**
+    * Used to describe a flat network.
+    */
+   FLAT("flat"),
+   /**
+    * Used to describe a VLAN network. NetworkSegment might have to be set.
+    */
+   VLAN("vlan"),
+   GRE("gre"),
+   /**
+    * Used by jclouds when the service returns an unknown value other than null.
+    */
+   UNRECOGNIZED("unrecognized");
+
+   private String name;
+
+   private NetworkType(String name) {
+      this.name = name;
+   }
+
+   @Override
+   public String toString() {
+      return name;
+   }
+
+   /**
+    * This provides GSON enum support in jclouds.
+    * @param name The string representation of this enum value.
+    * @return The corresponding enum value.
+    */
+   public static NetworkType fromValue(String name) {
+      if (name != null) {
+         for (NetworkType value : NetworkType.values()) {
+           if (name.equalsIgnoreCase(value.name)) {
+             return value;
+           }
+         }
+         return UNRECOGNIZED;
+       }
+       return null;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/9c4bd944/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Networks.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Networks.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Networks.java
new file mode 100644
index 0000000..45f6c56
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Networks.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.neutron.v2.domain;
+
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.PaginatedCollection;
+
+import java.beans.ConstructorProperties;
+
+/**
+ * A collection of Networks
+ */
+public class Networks extends PaginatedCollection<Network> {
+   public static final Networks EMPTY = new Networks(ImmutableSet.<Network> of(), ImmutableSet.<Link> of());
+
+   @ConstructorProperties({ "networks", "networks_links" })
+   protected Networks(Iterable<Network> networks, Iterable<Link> networksLinks) {
+      super(networks, networksLinks);
+   }
+}