You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ev...@apache.org on 2013/09/12 22:52:33 UTC

[4/5] OpenStack Neutron v2.0 implementation

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/domain/State.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/domain/State.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/domain/State.java
new file mode 100644
index 0000000..1379ab7
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/domain/State.java
@@ -0,0 +1,29 @@
+/*
+ * 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_0.domain;
+
+/**
+ * The possible state of an entity
+ *
+ * @author Nick Livens
+ * @see <a href="http://docs.openstack.org/api/openstack-network/2.0/content/Concepts-d1e369.html">api doc</a>
+ */
+public enum State {
+   ACTIVE, DOWN, BUILD, ERROR
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/domain/Subnet.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/domain/Subnet.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/domain/Subnet.java
new file mode 100644
index 0000000..c1c8625
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/domain/Subnet.java
@@ -0,0 +1,264 @@
+/*
+ * 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_0.domain;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableSet;
+
+import java.beans.ConstructorProperties;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * A Neutron network
+ *
+ * @author Nick Livens
+ * @see <a href="http://docs.openstack.org/api/openstack-network/2.0/content/Subnets.html">api doc</a>
+ */
+public class Subnet extends ReferenceWithName {
+
+   private final String networkId;
+   private final String gatewayIp;
+   private final Integer ipVersion;
+   private final String cidr;
+   private final Set<AllocationPool> allocationPools;
+   private final Boolean enableDhcp;
+   private final Set<String> dnsNameServers;
+   private final Set<HostRoute> hostRoutes;
+
+   @ConstructorProperties({
+      "id", "tenant_id", "name", "network_id", "gateway_ip", "ip_version", "cidr", "allocation_pools", "enable_dhcp", "dns_nameservers", "host_routes"
+   })
+   protected Subnet(String id, String tenantId, String name, String networkId,
+                    String gatewayIp, Integer ipVersion, String cidr, Set<AllocationPool> allocationPools,
+                    Boolean enableDhcp, Set<String> dnsNameServers, Set<HostRoute> hostRoutes) {
+      super(id, tenantId, name);
+      this.networkId = networkId;
+      this.gatewayIp = gatewayIp;
+      this.ipVersion = ipVersion;
+      this.cidr = cidr;
+      this.allocationPools = allocationPools != null ? ImmutableSet.copyOf(allocationPools) : ImmutableSet.<AllocationPool>of();
+      this.enableDhcp = enableDhcp;
+      this.dnsNameServers = dnsNameServers != null ? ImmutableSet.copyOf(dnsNameServers) : ImmutableSet.<String>of();
+      this.hostRoutes = hostRoutes != null ? ImmutableSet.copyOf(hostRoutes) : ImmutableSet.<HostRoute>of();
+   }
+
+   /**
+    * @return the id of the network this subnet is associated with
+    */
+   public String getNetworkId() {
+      return networkId;
+   }
+
+   /**
+    * @return the default gateway used by devices in this subnet
+    */
+   public String getGatewayIp() {
+      return gatewayIp;
+   }
+
+   /**
+    * @return the ip version used by this subnet
+    */
+   public Integer getIpVersion() {
+      return ipVersion;
+   }
+
+   /**
+    * @return the cidr representing the IP range for this subnet, based on IP version
+    */
+   public String getCidr() {
+      return cidr;
+   }
+
+   /**
+    * @return the sub-ranges of cidr available for dynamic allocation to ports
+    */
+   public Set<AllocationPool> getAllocationPools() {
+      return allocationPools;
+   }
+
+   /**
+    * @return true if DHCP is enabled for this subnet, false if not.
+    */
+   public Boolean getEnableDhcp() {
+      return enableDhcp;
+   }
+
+   /**
+    * @return the set of DNS name servers used by hosts in this subnet.
+    */
+   public Set<String> getDnsNameServers() {
+      return dnsNameServers;
+   }
+
+   /**
+    * @return the set of routes that should be used by devices with IPs from this subnet
+    */
+   public Set<HostRoute> getHostRoutes() {
+      return hostRoutes;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(super.hashCode(), networkId, gatewayIp, ipVersion, cidr,
+         allocationPools, enableDhcp, dnsNameServers, hostRoutes);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      Subnet that = Subnet.class.cast(obj);
+      return super.equals(obj)
+         && Objects.equal(this.networkId, that.networkId)
+         && Objects.equal(this.gatewayIp, that.gatewayIp)
+         && Objects.equal(this.ipVersion, that.ipVersion)
+         && Objects.equal(this.cidr, that.cidr)
+         && Objects.equal(this.allocationPools, that.allocationPools)
+         && Objects.equal(this.enableDhcp, that.enableDhcp)
+         && Objects.equal(this.dnsNameServers, that.dnsNameServers)
+         && Objects.equal(this.hostRoutes, that.hostRoutes);
+   }
+
+   protected ToStringHelper string() {
+      return super.string()
+         .add("networkId", networkId)
+         .add("gatewayIp", gatewayIp)
+         .add("ipVersion", ipVersion)
+         .add("cidr", cidr)
+         .add("enableDHCP", enableDhcp)
+         .add("allocationPools", allocationPools)
+         .add("dnsNameServers", dnsNameServers)
+         .add("hostRoutes", hostRoutes);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder<?> toBuilder() {
+      return new ConcreteBuilder().fromSubnet(this);
+   }
+
+   public static abstract class Builder<T extends Builder<T>> extends ReferenceWithName.Builder<T> {
+      protected String networkId;
+      protected String gatewayIp;
+      protected Integer ipVersion;
+      protected String cidr;
+      protected Set<AllocationPool> allocationPools;
+      protected Boolean enableDhcp;
+      protected Set<String> dnsNameServers;
+      protected Set<HostRoute> hostRoutes;
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.domain.Subnet#getNetworkId()
+       */
+      public T networkId(String networkId) {
+         this.networkId = networkId;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.domain.Subnet#getGatewayIp()
+       */
+      public T gatewayIp(String gatewayIp) {
+         this.gatewayIp = gatewayIp;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.domain.Subnet#getIpVersion()
+       */
+      public T ipVersion(Integer ipVersion) {
+         this.ipVersion = ipVersion;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.domain.Subnet#getCidr()
+       */
+      public T cidr(String cidr) {
+         this.cidr = cidr;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.domain.Subnet#getAllocationPools()
+       */
+      public T allocationPools(Collection<AllocationPool> allocationPools) {
+         this.allocationPools = ImmutableSet.copyOf(allocationPools);
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.domain.Subnet#getEnableDhcp()
+       */
+      public T enableDhcp(Boolean enableDhcp) {
+         this.enableDhcp = enableDhcp;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.domain.Subnet#getDnsNameServers()
+       */
+      public T dnsNameServers(Collection<String> dnsNameServers) {
+         this.dnsNameServers = ImmutableSet.copyOf(dnsNameServers);
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.domain.Subnet#getHostRoutes()
+       */
+      public T hostRoutes(Collection<HostRoute> hostRoutes) {
+         this.hostRoutes = ImmutableSet.copyOf(hostRoutes);
+         return self();
+      }
+
+      public Subnet build() {
+         return new Subnet(id, tenantId, name, networkId, gatewayIp, ipVersion, cidr, allocationPools, enableDhcp, dnsNameServers, hostRoutes);
+      }
+
+      public T fromSubnet(Subnet in) {
+         return super.fromReference(in)
+               .networkId(in.getNetworkId())
+               .gatewayIp(in.getGatewayIp())
+               .ipVersion(in.getIpVersion())
+               .cidr(in.getCidr())
+               .allocationPools(in.getAllocationPools())
+               .enableDhcp(in.getEnableDhcp())
+               .dnsNameServers(in.getDnsNameServers())
+               .hostRoutes(in.getHostRoutes());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/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
new file mode 100644
index 0000000..22d8416
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/NetworkApi.java
@@ -0,0 +1,172 @@
+/**
+ * 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_0.features;
+
+import com.google.common.collect.FluentIterable;
+import org.jclouds.Fallbacks;
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.neutron.v2_0.domain.Network;
+import org.jclouds.openstack.neutron.v2_0.domain.ReferenceWithName;
+import org.jclouds.openstack.neutron.v2_0.functions.ParseNetworkDetails;
+import org.jclouds.openstack.neutron.v2_0.functions.ParseNetworks;
+import org.jclouds.openstack.neutron.v2_0.options.CreateNetworkBulkOptions;
+import org.jclouds.openstack.neutron.v2_0.options.CreateNetworkOptions;
+import org.jclouds.openstack.neutron.v2_0.options.UpdateNetworkOptions;
+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.QueryParams;
+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 javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.core.MediaType;
+
+import static org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404;
+import static org.jclouds.openstack.keystone.v2_0.KeystoneFallbacks.EmptyPaginatedCollectionOnNotFoundOr404;
+
+/**
+ * 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.
+ *
+ * @author Adam Lowe
+ * @author Nick Livens
+ * @see <a href=
+ *      "http://docs.openstack.org/api/openstack-network/2.0/content/Networks.html">api doc</a>
+ */
+@Path("/v2.0/networks")
+@RequestFilters(AuthenticateRequest.class)
+@Consumes(MediaType.APPLICATION_JSON)
+public interface NetworkApi {
+
+   /**
+    * Returns the list of all networks 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 network references configured for the tenant
+    */
+   @Named("network:list")
+   @GET
+   @ResponseParser(ParseNetworks.class)
+   @Transform(ParseNetworks.ToPagedIterable.class)
+   @Fallback(EmptyPagedIterableOnNotFoundOr404.class)
+   @QueryParams(keys = {"fields", "fields", "fields"}, values = {"id", "tenant_id", "name"})
+   PagedIterable<? extends ReferenceWithName> list();
+
+   @Named("network:list")
+   @GET
+   @ResponseParser(ParseNetworks.class)
+   @Fallback(EmptyPaginatedCollectionOnNotFoundOr404.class)
+   @QueryParams(keys = {"fields", "fields", "fields"}, values = {"id", "tenant_id", "name"})
+   PaginatedCollection<? extends ReferenceWithName> list(PaginationOptions options);
+
+   /**
+    * 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(ParseNetworkDetails.class)
+   @Transform(ParseNetworkDetails.ToPagedIterable.class)
+   @Fallback(EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<? extends Network> listInDetail();
+
+   @Named("network:list")
+   @GET
+   @ResponseParser(ParseNetworkDetails.class)
+   @Fallback(EmptyPaginatedCollectionOnNotFoundOr404.class)
+   PaginatedCollection<? extends Network> listInDetail(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)
+   Network get(@PathParam("id") String id);
+
+   /**
+    * Create a new network with the specified type
+    *
+    * @param options optional arguments
+    * @return a reference of the newly-created network
+    */
+   @Named("network:create")
+   @POST
+   @SelectJson("network")
+   @MapBinder(CreateNetworkOptions.class)
+   Network create(CreateNetworkOptions... options);
+
+   /**
+    * 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")
+   @MapBinder(CreateNetworkBulkOptions.class)
+   FluentIterable<? extends Network> createBulk(CreateNetworkBulkOptions networks);
+
+   /**
+    * Update a network
+    *
+    * @param id the id of the network to update
+    * @param options the attributes to update
+    * @return true if update successful, false if not
+    */
+   @Named("network:update")
+   @PUT
+   @Path("/{id}")
+   @MapBinder(UpdateNetworkOptions.class)
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean update(@PathParam("id") String id, UpdateNetworkOptions... options);
+
+   /**
+    * 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);
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/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
new file mode 100644
index 0000000..12d923d
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/PortApi.java
@@ -0,0 +1,175 @@
+/**
+ * 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_0.features;
+
+import com.google.common.collect.FluentIterable;
+import org.jclouds.Fallbacks;
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.neutron.v2_0.domain.Port;
+import org.jclouds.openstack.neutron.v2_0.domain.ReferenceWithName;
+import org.jclouds.openstack.neutron.v2_0.functions.ParsePortDetails;
+import org.jclouds.openstack.neutron.v2_0.functions.ParsePorts;
+import org.jclouds.openstack.neutron.v2_0.options.CreatePortBulkOptions;
+import org.jclouds.openstack.neutron.v2_0.options.CreatePortOptions;
+import org.jclouds.openstack.neutron.v2_0.options.UpdatePortOptions;
+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.QueryParams;
+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 javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.core.MediaType;
+
+import static org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404;
+import static org.jclouds.openstack.keystone.v2_0.KeystoneFallbacks.EmptyPaginatedCollectionOnNotFoundOr404;
+
+/**
+ * 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.
+
+ * @author Nick Livens
+ * @see <a href=
+ *      "http://docs.openstack.org/api/openstack-network/2.0/content/Ports.html">api doc</a>
+ */
+@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
+   @ResponseParser(ParsePorts.class)
+   @Transform(ParsePorts.ToPagedIterable.class)
+   @Fallback(EmptyPagedIterableOnNotFoundOr404.class)
+   @QueryParams(keys = {"fields", "fields", "fields"}, values = {"id", "tenant_id", "name"})
+   PagedIterable<? extends ReferenceWithName> list();
+
+   @Named("port:list")
+   @GET
+   @ResponseParser(ParsePorts.class)
+   @Fallback(EmptyPaginatedCollectionOnNotFoundOr404.class)
+   @QueryParams(keys = {"fields", "fields", "fields"}, values = {"id", "tenant_id", "name"})
+   PaginatedCollection<? extends ReferenceWithName> list(PaginationOptions options);
+
+   /**
+    * Returns the set of ports currently defined in Neutron for the requested network.
+    *
+    * @return the list of all ports configured for the tenant
+    */
+   @Named("port:list")
+   @GET
+   @ResponseParser(ParsePortDetails.class)
+   @Transform(ParsePortDetails.ToPagedIterable.class)
+   @Fallback(EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<? extends Port> listInDetail();
+
+   @Named("port:list")
+   @GET
+   @ResponseParser(ParsePortDetails.class)
+   @Fallback(EmptyPaginatedCollectionOnNotFoundOr404.class)
+   PaginatedCollection<? extends Port> listInDetail(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)
+   Port get(@PathParam("id") String id);
+
+   /**
+    * Create a new port in the specified network
+    *
+    * @param networkId the id of the network to associate this port with
+    * @param options optional arguments
+    * @return a reference of the newly-created port
+    */
+   @Named("port:create")
+   @POST
+   @SelectJson("port")
+   @MapBinder(CreatePortOptions.class)
+   Port create(@PayloadParam("network_id") String networkId, CreatePortOptions... options);
+
+   /**
+    * 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")
+   @MapBinder(CreatePortBulkOptions.class)
+   FluentIterable<? extends Port> createBulk(CreatePortBulkOptions ports);
+
+   /**
+    * Update a port
+    *
+    * @param id the id of the port to update
+    * @param options the attributes to update
+    * @return true if update successful, false if not
+    */
+   @Named("port:update")
+   @PUT
+   @Path("/{id}")
+   @MapBinder(UpdatePortOptions.class)
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean update(@PathParam("id") String id, UpdatePortOptions... options);
+
+   /**
+    * 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/incubator-jclouds-labs-openstack/blob/895476f1/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
new file mode 100644
index 0000000..d08ca7b
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/features/SubnetApi.java
@@ -0,0 +1,174 @@
+/**
+ * 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_0.features;
+
+import com.google.common.collect.FluentIterable;
+import org.jclouds.Fallbacks;
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.neutron.v2_0.domain.ReferenceWithName;
+import org.jclouds.openstack.neutron.v2_0.domain.Subnet;
+import org.jclouds.openstack.neutron.v2_0.functions.ParseSubnetDetails;
+import org.jclouds.openstack.neutron.v2_0.functions.ParseSubnets;
+import org.jclouds.openstack.neutron.v2_0.options.CreateSubnetBulkOptions;
+import org.jclouds.openstack.neutron.v2_0.options.CreateSubnetOptions;
+import org.jclouds.openstack.neutron.v2_0.options.UpdateSubnetOptions;
+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.QueryParams;
+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 javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.core.MediaType;
+
+import static org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404;
+import static org.jclouds.openstack.keystone.v2_0.KeystoneFallbacks.EmptyPaginatedCollectionOnNotFoundOr404;
+
+/**
+ * Provides synchronous access to Subnet operations on the Openstack Neutron API.
+ *
+
+ * @author Nick Livens
+ * @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)
+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(ParseSubnets.ToPagedIterable.class)
+   @Fallback(EmptyPagedIterableOnNotFoundOr404.class)
+   @QueryParams(keys = {"fields", "fields", "fields"}, values = {"id", "tenant_id", "name"})
+   PagedIterable<? extends ReferenceWithName> list();
+
+   @Named("subnet:list")
+   @GET
+   @ResponseParser(ParseSubnets.class)
+   @Fallback(EmptyPaginatedCollectionOnNotFoundOr404.class)
+   @QueryParams(keys = {"fields", "fields", "fields"}, values = {"id", "tenant_id", "name"})
+   PaginatedCollection<? extends ReferenceWithName> list(PaginationOptions options);
+
+   /**
+    * Returns all subnets currently defined in Neutron for the current tenant.
+    *
+    * @return the list of all subnets configured for the tenant
+    */
+   @Named("subnet:list")
+   @GET
+   @ResponseParser(ParseSubnetDetails.class)
+   @Transform(ParseSubnetDetails.ToPagedIterable.class)
+   @Fallback(EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<? extends Subnet> listInDetail();
+
+   @Named("subnet:list")
+   @GET
+   @ResponseParser(ParseSubnetDetails.class)
+   @Fallback(EmptyPaginatedCollectionOnNotFoundOr404.class)
+   PaginatedCollection<? extends Subnet> listInDetail(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)
+   Subnet get(@PathParam("id") String id);
+
+   /**
+    * Create a subnet within a specified network
+    *
+    * @param networkId the id of the network to associate the subnet with
+    * @param ipVersion the ip version of this subnet
+    * @param cidr the cidr for this subnet
+    * @param options optional arugments
+    * @return a reference of the newly-created subnet
+    */
+   @Named("subnet:create")
+   @POST
+   @SelectJson("subnet")
+   @MapBinder(CreateSubnetOptions.class)
+   Subnet create(@PayloadParam("network_id") String networkId, @PayloadParam("ip_version") Integer ipVersion,
+                            @PayloadParam("cidr") String cidr, CreateSubnetOptions... options);
+
+   /**
+    * 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")
+   @MapBinder(CreateSubnetBulkOptions.class)
+   FluentIterable<? extends Subnet> createBulk(CreateSubnetBulkOptions subnets);
+
+   /**
+    * Update a subnet
+    *
+    * @param id the id of the subnet to update
+    * @param options the attributes to update
+    * @return true if update was successful, false if not
+    */
+   @Named("subnet:update")
+   @PUT
+   @Path("/{id}")
+   @MapBinder(UpdateSubnetOptions.class)
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean update(@PathParam("id") String id, UpdateSubnetOptions... options);
+
+   /**
+    * 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/incubator-jclouds-labs-openstack/blob/895476f1/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseNetworkDetails.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseNetworkDetails.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseNetworkDetails.java
new file mode 100644
index 0000000..af4e608
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseNetworkDetails.java
@@ -0,0 +1,91 @@
+/*
+ * 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_0.functions;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.inject.TypeLiteral;
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.Arg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.neutron.v2_0.NeutronApi;
+import org.jclouds.openstack.neutron.v2_0.domain.Network;
+import org.jclouds.openstack.neutron.v2_0.features.NetworkApi;
+import org.jclouds.openstack.neutron.v2_0.functions.ParseNetworkDetails.Networks;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.beans.ConstructorProperties;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+/**
+ * @author Nick Livens
+ */
+@Beta
+@Singleton
+public class ParseNetworkDetails extends ParseJson<Networks> {
+   static class Networks extends PaginatedCollection<Network> {
+
+      @ConstructorProperties({ "networks", "networks_links" })
+      protected Networks(Iterable<Network> networks, Iterable<Link> networks_links) {
+         super(networks, networks_links);
+      }
+
+   }
+
+   @Inject
+   public ParseNetworkDetails(Json json) {
+      super(json, TypeLiteral.get(Networks.class));
+   }
+
+   public static class ToPagedIterable extends Arg0ToPagedIterable.FromCaller<Network, ToPagedIterable> {
+
+      private final NeutronApi api;
+
+      @Inject
+      protected ToPagedIterable(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) {
+               return IterableWithMarker.class.cast(networkApi.listInDetail(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "list()";
+            }
+         };
+      }
+
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseNetworks.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseNetworks.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseNetworks.java
new file mode 100644
index 0000000..da628bc
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseNetworks.java
@@ -0,0 +1,91 @@
+/*
+ * 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_0.functions;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.inject.TypeLiteral;
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.Arg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.neutron.v2_0.NeutronApi;
+import org.jclouds.openstack.neutron.v2_0.domain.ReferenceWithName;
+import org.jclouds.openstack.neutron.v2_0.features.NetworkApi;
+import org.jclouds.openstack.neutron.v2_0.functions.ParseNetworks.Networks;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.beans.ConstructorProperties;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+/**
+ * @author Nick Livens
+ */
+@Beta
+@Singleton
+public class ParseNetworks extends ParseJson<Networks> {
+   static class Networks extends PaginatedCollection<ReferenceWithName> {
+
+      @ConstructorProperties({ "networks", "networks_links" })
+      protected Networks(Iterable<ReferenceWithName> networks, Iterable<Link> networks_links) {
+         super(networks, networks_links);
+      }
+
+   }
+
+   @Inject
+   public ParseNetworks(Json json) {
+      super(json, TypeLiteral.get(Networks.class));
+   }
+
+   public static class ToPagedIterable extends Arg0ToPagedIterable.FromCaller<ReferenceWithName, ToPagedIterable> {
+
+      private final NeutronApi api;
+
+      @Inject
+      protected ToPagedIterable(NeutronApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<ReferenceWithName>> markerToNextForArg0(Optional<Object> arg0) {
+         String zone = arg0.isPresent() ? arg0.get().toString() : null;
+         final NetworkApi networkApi = api.getNetworkApiForZone(zone);
+         return new Function<Object, IterableWithMarker<ReferenceWithName>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<ReferenceWithName> apply(Object input) {
+               return IterableWithMarker.class.cast(networkApi.list(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "list()";
+            }
+         };
+      }
+
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParsePortDetails.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParsePortDetails.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParsePortDetails.java
new file mode 100644
index 0000000..e57dadd
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParsePortDetails.java
@@ -0,0 +1,92 @@
+/*
+ * 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_0.functions;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.inject.TypeLiteral;
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.Arg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.neutron.v2_0.NeutronApi;
+import org.jclouds.openstack.neutron.v2_0.domain.Port;
+import org.jclouds.openstack.neutron.v2_0.domain.ReferenceWithName;
+import org.jclouds.openstack.neutron.v2_0.features.PortApi;
+import org.jclouds.openstack.neutron.v2_0.functions.ParsePortDetails.Ports;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.beans.ConstructorProperties;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+/**
+ * @author Nick Livens
+ */
+@Beta
+@Singleton
+public class ParsePortDetails extends ParseJson<Ports> {
+   static class Ports extends PaginatedCollection<Port> {
+
+      @ConstructorProperties({ "ports", "ports_links" })
+      protected Ports(Iterable<Port> ports, Iterable<Link> ports_links) {
+         super(ports, ports_links);
+      }
+
+   }
+
+   @Inject
+   public ParsePortDetails(Json json) {
+      super(json, TypeLiteral.get(Ports.class));
+   }
+
+   public static class ToPagedIterable extends Arg0ToPagedIterable.FromCaller<ReferenceWithName, ToPagedIterable> {
+
+      private final NeutronApi api;
+
+      @Inject
+      protected ToPagedIterable(NeutronApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<ReferenceWithName>> markerToNextForArg0(Optional<Object> arg0) {
+         String zone = arg0.isPresent() ? arg0.get().toString() : null;
+         final PortApi portApi = api.getPortApiForZone(zone);
+         return new Function<Object, IterableWithMarker<ReferenceWithName>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<ReferenceWithName> apply(Object input) {
+               return IterableWithMarker.class.cast(portApi.listInDetail(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "list()";
+            }
+         };
+      }
+
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParsePorts.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParsePorts.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParsePorts.java
new file mode 100644
index 0000000..837dc56
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParsePorts.java
@@ -0,0 +1,92 @@
+/*
+ * 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_0.functions;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.inject.TypeLiteral;
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.Arg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.neutron.v2_0.NeutronApi;
+import org.jclouds.openstack.neutron.v2_0.domain.ReferenceWithName;
+import org.jclouds.openstack.neutron.v2_0.features.NetworkApi;
+import org.jclouds.openstack.neutron.v2_0.features.PortApi;
+import org.jclouds.openstack.neutron.v2_0.functions.ParsePorts.Ports;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.beans.ConstructorProperties;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+/**
+ * @author Nick Livens
+ */
+@Beta
+@Singleton
+public class ParsePorts extends ParseJson<Ports> {
+   static class Ports extends PaginatedCollection<ReferenceWithName> {
+
+      @ConstructorProperties({ "ports", "ports_links" })
+      protected Ports(Iterable<ReferenceWithName> ports, Iterable<Link> ports_links) {
+         super(ports, ports_links);
+      }
+
+   }
+
+   @Inject
+   public ParsePorts(Json json) {
+      super(json, TypeLiteral.get(Ports.class));
+   }
+
+   public static class ToPagedIterable extends Arg0ToPagedIterable.FromCaller<ReferenceWithName, ToPagedIterable> {
+
+      private final NeutronApi api;
+
+      @Inject
+      protected ToPagedIterable(NeutronApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<ReferenceWithName>> markerToNextForArg0(Optional<Object> arg0) {
+         String zone = arg0.isPresent() ? arg0.get().toString() : null;
+         final PortApi portApi = api.getPortApiForZone(zone);
+         return new Function<Object, IterableWithMarker<ReferenceWithName>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<ReferenceWithName> apply(Object input) {
+               return IterableWithMarker.class.cast(portApi.list(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "list()";
+            }
+         };
+      }
+
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseSubnetDetails.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseSubnetDetails.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseSubnetDetails.java
new file mode 100644
index 0000000..433dbca
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseSubnetDetails.java
@@ -0,0 +1,91 @@
+/*
+ * 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_0.functions;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.inject.TypeLiteral;
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.Arg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.neutron.v2_0.NeutronApi;
+import org.jclouds.openstack.neutron.v2_0.domain.Subnet;
+import org.jclouds.openstack.neutron.v2_0.features.SubnetApi;
+import org.jclouds.openstack.neutron.v2_0.functions.ParseSubnetDetails.Subnets;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.beans.ConstructorProperties;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+/**
+ * @author Nick Livens
+ */
+@Beta
+@Singleton
+public class ParseSubnetDetails extends ParseJson<Subnets> {
+   static class Subnets extends PaginatedCollection<Subnet> {
+
+      @ConstructorProperties({ "subnets", "subnets_links" })
+      protected Subnets(Iterable<Subnet> subnets, Iterable<Link> subnets_links) {
+         super(subnets, subnets_links);
+      }
+
+   }
+
+   @Inject
+   public ParseSubnetDetails(Json json) {
+      super(json, TypeLiteral.get(Subnets.class));
+   }
+
+   public static class ToPagedIterable extends Arg0ToPagedIterable.FromCaller<Subnet, ToPagedIterable> {
+
+      private final NeutronApi api;
+
+      @Inject
+      protected ToPagedIterable(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) {
+               return IterableWithMarker.class.cast(subnetApi.listInDetail(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "list()";
+            }
+         };
+      }
+
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseSubnets.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseSubnets.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseSubnets.java
new file mode 100644
index 0000000..1f0f61e
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/functions/ParseSubnets.java
@@ -0,0 +1,91 @@
+/*
+ * 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_0.functions;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.inject.TypeLiteral;
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.Arg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.neutron.v2_0.NeutronApi;
+import org.jclouds.openstack.neutron.v2_0.domain.ReferenceWithName;
+import org.jclouds.openstack.neutron.v2_0.features.SubnetApi;
+import org.jclouds.openstack.neutron.v2_0.functions.ParseSubnets.Subnets;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.beans.ConstructorProperties;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+/**
+ * @author Nick Livens
+ */
+@Beta
+@Singleton
+public class ParseSubnets extends ParseJson<Subnets> {
+   static class Subnets extends PaginatedCollection<ReferenceWithName> {
+
+      @ConstructorProperties({ "subnets", "subnets_links" })
+      protected Subnets(Iterable<ReferenceWithName> subnets, Iterable<Link> subnets_links) {
+         super(subnets, subnets_links);
+      }
+
+   }
+
+   @Inject
+   public ParseSubnets(Json json) {
+      super(json, TypeLiteral.get(Subnets.class));
+   }
+
+   public static class ToPagedIterable extends Arg0ToPagedIterable.FromCaller<ReferenceWithName, ToPagedIterable> {
+
+      private final NeutronApi api;
+
+      @Inject
+      protected ToPagedIterable(NeutronApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<ReferenceWithName>> markerToNextForArg0(Optional<Object> arg0) {
+         String zone = arg0.isPresent() ? arg0.get().toString() : null;
+         final SubnetApi subnetApi = api.getSubnetApiForZone(zone);
+         return new Function<Object, IterableWithMarker<ReferenceWithName>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<ReferenceWithName> apply(Object input) {
+               return IterableWithMarker.class.cast(subnetApi.list(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "list()";
+            }
+         };
+      }
+
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/handlers/NeutronErrorHandler.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/handlers/NeutronErrorHandler.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/handlers/NeutronErrorHandler.java
new file mode 100644
index 0000000..97dbb35
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/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_0.handlers;
+
+import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
+
+import javax.inject.Singleton;
+
+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;
+
+/**
+ * This will parse and set an appropriate exception on the command object.
+ *
+ * @author Nick Livens
+ *
+ */
+@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;
+      }
+      command.setException(exception);
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreateNetworkBulkOptions.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreateNetworkBulkOptions.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreateNetworkBulkOptions.java
new file mode 100644
index 0000000..6c08e7e
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreateNetworkBulkOptions.java
@@ -0,0 +1,142 @@
+/**
+ * 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_0.options;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.openstack.neutron.v2_0.domain.BulkNetwork;
+import org.jclouds.openstack.neutron.v2_0.domain.NetworkType;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import javax.inject.Inject;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.neutron.v2_0.options.CreateNetworkOptions.CreateNetworkRequest;
+
+/**
+ * @author Nick Livens
+ */
+public class CreateNetworkBulkOptions implements MapBinder {
+
+   @Inject
+   private BindToJsonPayload jsonBinder;
+
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder<?> toBuilder() {
+      return new ConcreteBuilder().fromCreateNetworkOptions(this);
+   }
+
+   public static abstract class Builder<T extends Builder<T>> {
+      protected abstract T self();
+
+      protected List<BulkNetwork> networks;
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreateNetworkBulkOptions#getNetworks()
+       */
+      public T networks(Collection<BulkNetwork> networks) {
+         this.networks = ImmutableList.copyOf(networks);
+         return self();
+      }
+
+      public CreateNetworkBulkOptions build() {
+         return new CreateNetworkBulkOptions(networks);
+      }
+
+      public T fromCreateNetworkOptions(CreateNetworkBulkOptions in) {
+         return this.networks(in.getNetworks());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+   private final List<BulkNetwork> networks;
+
+   protected CreateNetworkBulkOptions() {
+      this.networks = Lists.newArrayList();
+   }
+
+   public CreateNetworkBulkOptions(List<BulkNetwork> networks) {
+      this.networks = networks != null ? ImmutableList.copyOf(networks) : Lists.<BulkNetwork>newArrayList();
+   }
+
+   /**
+    * @return the list of networks to create
+    */
+   public List<BulkNetwork> getNetworks() {
+      return networks;
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      List<CreateNetworkRequest> createNetworkRequests = Lists.newArrayList();
+
+      for (BulkNetwork network : this.networks) {
+         if (network.getNetworkType() != null) {
+            //Validations for each NetworkType
+            if (network.getNetworkType() == NetworkType.FLAT) {
+               checkNotNull(network.getPhysicalNetworkName(), "physicalNetworkName must be present when networkType=FLAT");
+            } else if (network.getNetworkType() == NetworkType.VLAN) {
+               checkNotNull(network.getPhysicalNetworkName(), "physicalNetworkName must be present when networkType=VLAN");
+               checkNotNull(network.getSegmentationId(), "segmentationId must be present when networkType=VLAN");
+            } else if (network.getNetworkType() == NetworkType.GRE) {
+               checkNotNull(network.getSegmentationId(), "segmentationId must be present when NetworkType=GRE");
+            }
+         }
+
+         CreateNetworkRequest createNetworkRequest = new CreateNetworkRequest();
+         if (network.getName() != null)
+            createNetworkRequest.name = network.getName();
+         if (network.getAdminStateUp() != null)
+            createNetworkRequest.admin_state_up = network.getAdminStateUp();
+         if (network.getExternal() != null)
+            createNetworkRequest.external = network.getExternal();
+         if (network.getNetworkType() != null)
+            createNetworkRequest.networkType = network.getNetworkType().getValue();
+         if (network.getPhysicalNetworkName() != null && (network.getNetworkType() == NetworkType.FLAT || network.getNetworkType() == NetworkType.VLAN))
+            createNetworkRequest.physicalNetworkName = network.getPhysicalNetworkName();
+         if (network.getSegmentationId() != null && (network.getNetworkType() == NetworkType.VLAN || network.getNetworkType() == NetworkType.GRE))
+            createNetworkRequest.segmentationId = network.getSegmentationId();
+
+         createNetworkRequests.add(createNetworkRequest);
+      }
+
+      return bindToRequest(request, ImmutableMap.of("networks", createNetworkRequests));
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      return jsonBinder.bindToRequest(request, input);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreateNetworkOptions.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreateNetworkOptions.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreateNetworkOptions.java
new file mode 100644
index 0000000..68c9202
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreateNetworkOptions.java
@@ -0,0 +1,244 @@
+/**
+ * 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_0.options;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.gson.annotations.SerializedName;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.openstack.neutron.v2_0.domain.NetworkType;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import javax.inject.Inject;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * @author Nick Livens
+ */
+public class CreateNetworkOptions implements MapBinder {
+
+   @Inject
+   private BindToJsonPayload jsonBinder;
+
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder<?> toBuilder() {
+      return new ConcreteBuilder().fromCreateNetworkOptions(this);
+   }
+
+   public static abstract class Builder<T extends Builder<T>> {
+      protected abstract T self();
+
+      protected String name;
+      protected Boolean adminStateUp;
+      protected Boolean external;
+      protected NetworkType networkType;
+      protected String physicalNetworkName;
+      protected Integer segmentationId;
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreateNetworkOptions#getName()
+       */
+      public T name(String name) {
+         this.name = name;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreateNetworkOptions#getAdminStateUp()
+       */
+      public T adminStateUp(Boolean adminStateUp) {
+         this.adminStateUp = adminStateUp;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreateNetworkOptions#getExternal()
+       */
+      public T external(Boolean external) {
+         this.external = external;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreateNetworkOptions#getNetworkType()
+       */
+      public T networkType(NetworkType networkType) {
+         this.networkType = networkType;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreateNetworkOptions#getPhysicalNetworkName()
+       */
+      public T physicalNetworkName(String physicalNetworkName) {
+         this.physicalNetworkName = physicalNetworkName;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreateNetworkOptions#getSegmentationId()
+       */
+      public T segmentationId(Integer segmentationId) {
+         this.segmentationId = segmentationId;
+         return self();
+      }
+
+      public CreateNetworkOptions build() {
+         return new CreateNetworkOptions(name, adminStateUp, external, networkType, physicalNetworkName, segmentationId);
+      }
+
+      public T fromCreateNetworkOptions(CreateNetworkOptions in) {
+         return this.name(in.getName())
+            .adminStateUp(in.getAdminStateUp())
+            .external(in.getExternal())
+            .networkType(in.getNetworkType())
+            .physicalNetworkName(in.getPhysicalNetworkName())
+            .segmentationId(in.getSegmentationId());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+   protected static class CreateNetworkRequest {
+      protected String name;
+      protected Boolean admin_state_up;
+      @SerializedName("router:external")
+      protected Boolean external;
+      @SerializedName("provider:network_type")
+      protected String networkType;
+      @SerializedName("provider:physical_network")
+      protected String physicalNetworkName;
+      @SerializedName("provider:segmentation_id")
+      protected Integer segmentationId;
+   }
+
+   private final String name;
+   private final Boolean adminStateUp;
+   private final Boolean external;
+   private final NetworkType networkType;
+   private final String physicalNetworkName;
+   private final Integer segmentationId;
+
+   protected CreateNetworkOptions() {
+      this.name = null;
+      this.adminStateUp = null;
+      this.external = null;
+      this.networkType = null;
+      this.physicalNetworkName = null;
+      this.segmentationId = null;
+   }
+
+   public CreateNetworkOptions(String name, Boolean adminStateUp, Boolean external, NetworkType networkType, String physicalNetworkName, Integer segmentationId) {
+      this.name = name;
+      this.adminStateUp = adminStateUp;
+      this.external = external;
+      this.networkType = networkType;
+      this.physicalNetworkName = physicalNetworkName;
+      this.segmentationId = segmentationId;
+   }
+
+   /**
+    * @return the name of the network
+    */
+   public String getName() {
+      return name;
+   }
+
+   /**
+    * @return the administrative state of network. If false, the network does not forward packets.
+    */
+   public Boolean getAdminStateUp() {
+      return adminStateUp;
+   }
+
+   /**
+    * @return true if network is external, false if not
+    */
+   public Boolean getExternal() {
+      return external;
+   }
+
+   /**
+    * @return the type of the network
+    */
+   public NetworkType getNetworkType() {
+      return networkType;
+   }
+
+   /**
+    * @return the physical network name
+    */
+   public String getPhysicalNetworkName() {
+      return physicalNetworkName;
+   }
+
+   /**
+    * @return the segmentation id of the network
+    */
+   public Integer getSegmentationId() {
+      return segmentationId;
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      if (this.networkType != null) {
+         //Validations for each NetworkType
+         if (this.networkType == NetworkType.FLAT) {
+            checkNotNull(this.physicalNetworkName, "physicalNetworkName must be present when networkType=FLAT");
+         } else if (this.networkType == NetworkType.VLAN) {
+            checkNotNull(this.physicalNetworkName, "physicalNetworkName must be present when networkType=VLAN");
+            checkNotNull(this.segmentationId, "segmentationId must be present when networkType=VLAN");
+         } else if (this.networkType == NetworkType.GRE) {
+            checkNotNull(this.segmentationId, "segmentationId must be present when NetworkType=GRE");
+         }
+      }
+
+      CreateNetworkRequest createNetworkRequest = new CreateNetworkRequest();
+      if (this.name != null)
+         createNetworkRequest.name = this.name;
+      if (this.adminStateUp != null)
+         createNetworkRequest.admin_state_up = this.adminStateUp;
+      if (this.external != null)
+         createNetworkRequest.external = this.external;
+      if (this.networkType != null)
+         createNetworkRequest.networkType = this.networkType.getValue();
+      if (this.physicalNetworkName != null && (networkType == NetworkType.FLAT || networkType == NetworkType.VLAN))
+         createNetworkRequest.physicalNetworkName = this.physicalNetworkName;
+      if (this.segmentationId != null && (networkType == NetworkType.VLAN || networkType == NetworkType.GRE))
+         createNetworkRequest.segmentationId = this.segmentationId;
+
+      return bindToRequest(request, ImmutableMap.of("network", createNetworkRequest));
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      return jsonBinder.bindToRequest(request, input);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreatePortBulkOptions.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreatePortBulkOptions.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreatePortBulkOptions.java
new file mode 100644
index 0000000..510786f
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreatePortBulkOptions.java
@@ -0,0 +1,137 @@
+/**
+ * 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_0.options;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.openstack.neutron.v2_0.domain.BulkPort;
+import org.jclouds.openstack.neutron.v2_0.domain.IP;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import javax.inject.Inject;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * @author Nick Livens
+ */
+public class CreatePortBulkOptions implements MapBinder {
+
+   @Inject
+   private BindToJsonPayload jsonBinder;
+
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder<?> toBuilder() {
+      return new ConcreteBuilder().fromCreatePortBulkOptions(this);
+   }
+
+   public static abstract class Builder<T extends Builder<T>> {
+      protected abstract T self();
+
+      protected List<BulkPort> ports;
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreatePortBulkOptions#getPorts()
+       */
+      public T ports(Collection<BulkPort> ports) {
+         this.ports = ImmutableList.copyOf(ports);
+         return self();
+      }
+
+      public CreatePortBulkOptions build() {
+         return new CreatePortBulkOptions(this.ports);
+      }
+
+      public T fromCreatePortBulkOptions(CreatePortBulkOptions in) {
+         return this.ports(in.getPorts());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+   private final List<BulkPort> ports;
+
+   protected CreatePortBulkOptions() {
+      this.ports = Lists.newArrayList();
+   }
+
+   public CreatePortBulkOptions(List<BulkPort> ports) {
+      this.ports = ports;
+   }
+
+   /**
+    * @return the list of ports to create
+    */
+   public List<BulkPort> getPorts() {
+      return ports;
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      List<CreatePortOptions.CreatePortRequest> createPortRequests = Lists.newArrayList();
+
+      for (BulkPort port : this.ports) {
+         CreatePortOptions.CreatePortRequest createPortRequest = new CreatePortOptions.CreatePortRequest(checkNotNull(port.getNetworkId(), "network id parameter not present"));
+
+         if (port.getName() != null)
+            createPortRequest.name = port.getName();
+         if (port.getAdminStateUp() != null)
+            createPortRequest.admin_state_up = port.getAdminStateUp();
+         if (port.getDeviceId() != null)
+            createPortRequest.device_id = port.getDeviceId();
+         if (port.getDeviceOwner() != null)
+            createPortRequest.device_owner = port.getDeviceOwner();
+         if (port.getMacAddress() != null)
+            createPortRequest.mac_address = port.getMacAddress();
+         if (!port.getFixedIps().isEmpty()) {
+            createPortRequest.fixed_ips = Sets.newHashSet();
+            for (IP fixedIp : port.getFixedIps()) {
+               CreatePortOptions.CreatePortRequest.IP requestIp = new CreatePortOptions.CreatePortRequest.IP();
+               requestIp.subnet_id = fixedIp.getSubnetId();
+               requestIp.ip_address = fixedIp.getIpAddress();
+               createPortRequest.fixed_ips.add(requestIp);
+            }
+         }
+
+         createPortRequests.add(createPortRequest);
+      }
+
+      return bindToRequest(request, ImmutableMap.of("ports", createPortRequests));
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      return jsonBinder.bindToRequest(request, input);
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/895476f1/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreatePortOptions.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreatePortOptions.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreatePortOptions.java
new file mode 100644
index 0000000..730bd09
--- /dev/null
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2_0/options/CreatePortOptions.java
@@ -0,0 +1,245 @@
+/**
+ * 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_0.options;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.openstack.neutron.v2_0.domain.IP;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import javax.inject.Inject;
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * @author Nick Livens
+ */
+public class CreatePortOptions implements MapBinder {
+
+   @Inject
+   private BindToJsonPayload jsonBinder;
+
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder<?> toBuilder() {
+      return new ConcreteBuilder().fromCreatePortOptions(this);
+   }
+
+   public static abstract class Builder<T extends Builder<T>> {
+      protected abstract T self();
+
+      protected String name;
+      protected String deviceId;
+      protected String deviceOwner;
+      protected String macAddress;
+      protected Set<IP> fixedIps;
+      protected Boolean adminStateUp;
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreatePortOptions#getName()
+       */
+      public T name(String name) {
+         this.name = name;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreatePortOptions#getDeviceId()
+       */
+      public T deviceId(String deviceId) {
+         this.deviceId = deviceId;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreatePortOptions#getDeviceOwner()
+       */
+      public T deviceOwner(String deviceOwner) {
+         this.deviceOwner = deviceOwner;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreatePortOptions#getMacAddress()
+       */
+      public T macAddress(String macAddress) {
+         this.macAddress = macAddress;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreatePortOptions#getFixedIps()
+       */
+      public T fixedIps(Set<IP> fixedIps) {
+         this.fixedIps = fixedIps;
+         return self();
+      }
+
+      /**
+       * @see org.jclouds.openstack.neutron.v2_0.options.CreatePortOptions#getAdminStateUp()
+       */
+      public T adminStateUp(Boolean adminStateUp) {
+         this.adminStateUp = adminStateUp;
+         return self();
+      }
+
+      public CreatePortOptions build() {
+         return new CreatePortOptions(name, deviceId, deviceOwner, macAddress, fixedIps, adminStateUp);
+      }
+
+      public T fromCreatePortOptions(CreatePortOptions options) {
+         return this.name(options.getName())
+            .deviceId(options.getDeviceId())
+            .deviceOwner(options.getDeviceOwner())
+            .macAddress(options.getMacAddress())
+            .fixedIps(options.getFixedIps())
+            .adminStateUp(options.getAdminStateUp());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+   protected static class CreatePortRequest {
+      protected String network_id;
+      protected String name;
+      protected String device_id;
+      protected String device_owner;
+      protected String mac_address;
+      protected Set<IP> fixed_ips;
+      protected Boolean admin_state_up;
+
+      protected CreatePortRequest(String networkId) {
+         this.network_id = networkId;
+      }
+
+      protected static final class IP {
+         protected String ip_address;
+         protected String subnet_id;
+      }
+   }
+
+   private final String name;
+   private final String deviceId;
+   private final String deviceOwner;
+   private final String macAddress;
+   private final Set<IP> fixedIps;
+   private final Boolean adminStateUp;
+
+   protected CreatePortOptions() {
+      this.name = null;
+      this.deviceId = null;
+      this.deviceOwner = null;
+      this.macAddress = null;
+      this.fixedIps = Sets.newHashSet();
+      this.adminStateUp = null;
+   }
+
+   public CreatePortOptions(String name, String deviceId, String deviceOwner, String macAddress,
+                            Set<IP> fixedIps, Boolean adminStateUp) {
+      this.name = name;
+      this.deviceId = deviceId;
+      this.deviceOwner = deviceOwner;
+      this.macAddress = macAddress;
+      this.fixedIps = fixedIps != null ? ImmutableSet.copyOf(fixedIps) : Sets.<IP>newHashSet();
+      this.adminStateUp = adminStateUp;
+   }
+
+   public String getName() {
+      return name;
+   }
+
+   /**
+    * @return the id of the device (e.g. server) which will use this port.
+    */
+   public String getDeviceId() {
+      return deviceId;
+   }
+
+   /**
+    * @return the entity (e.g.: dhcp agent) who will be using this port.
+    */
+   public String getDeviceOwner() {
+      return deviceOwner;
+   }
+
+   /**
+    * @return the mac address of this port
+    */
+   public String getMacAddress() {
+      return macAddress;
+   }
+
+   /**
+    * @return the set of fixed ips this port will get assigned
+    */
+   public Set<IP> getFixedIps() {
+      return fixedIps;
+   }
+
+   /**
+    * @return the administrative state of port. If false, port does not forward packets.
+    */
+   public Boolean getAdminStateUp() {
+      return adminStateUp;
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      CreatePortRequest createPortRequest = new CreatePortRequest(checkNotNull(postParams.get("network_id"), "networkId not present").toString());
+
+      if (this.name != null)
+         createPortRequest.name = this.name;
+      if (this.deviceId != null)
+         createPortRequest.device_id = this.deviceId;
+      if (this.deviceOwner != null)
+         createPortRequest.device_owner = this.deviceOwner;
+      if (this.macAddress != null)
+         createPortRequest.mac_address = this.macAddress;
+      if (!this.fixedIps.isEmpty()) {
+         createPortRequest.fixed_ips = Sets.newHashSet();
+         for (IP ip : this.fixedIps) {
+            CreatePortRequest.IP requestIp = new CreatePortRequest.IP();
+            requestIp.subnet_id = ip.getSubnetId();
+            requestIp.ip_address = ip.getIpAddress();
+            createPortRequest.fixed_ips.add(requestIp);
+         }
+      }
+      if (this.adminStateUp != null)
+         createPortRequest.admin_state_up = this.adminStateUp;
+
+      return bindToRequest(request, ImmutableMap.of("port", createPortRequest));
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      return jsonBinder.bindToRequest(request, input);
+   }
+}