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()
+      );
+   }
+}

Reply via email to