JCLOUDS-1300: Subnetwork fixes and reuse the TemplateOptions.networks

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

Branch: refs/heads/master
Commit: c83a08a8d6390e7e43553f209214916695fb8aa0
Parents: 2ec28df
Author: Ignasi Barrera <[email protected]>
Authored: Thu May 25 10:06:49 2017 +0200
Committer: Ignasi Barrera <[email protected]>
Committed: Wed May 31 09:25:55 2017 +0200

----------------------------------------------------------------------
 .../GoogleComputeEngineApi.java                 |  4 -
 .../GoogleComputeEngineServiceAdapter.java      | 55 ++++++++------
 ...GoogleComputeEngineServiceContextModule.java | 16 +++-
 .../compute/domain/internal/RegionAndName.java  | 53 +++++++++++++
 .../compute/loaders/SubnetworkLoader.java       | 30 ++++----
 .../GoogleComputeEngineTemplateOptions.java     | 24 ------
 ...desWithGroupEncodedIntoNameThenAddToSet.java | 77 +++++++++++++------
 .../GoogleComputeEngineHttpApiModule.java       |  2 -
 .../googlecomputeengine/domain/Network.java     | 31 ++++----
 .../googlecomputeengine/domain/NewInstance.java | 39 +---------
 .../googlecomputeengine/domain/Subnetwork.java  | 13 ++--
 .../features/NetworkApi.java                    | 30 +++++---
 .../features/SubnetworkApi.java                 | 11 +--
 .../options/NetworkCreationOptions.java         | 27 +++++--
 .../options/SubnetworkCreationOptions.java      | 17 +++--
 .../GoogleComputeEngineServiceMockTest.java     | 56 ++++++++++++++
 .../compute/functions/ResourcesMockTest.java    | 18 +++++
 .../features/FirewallApiLiveTest.java           |  3 +-
 .../features/InstanceApiLiveTest.java           |  9 ++-
 .../features/InstanceApiMockTest.java           |  4 +
 .../features/InstanceApiWindowsLiveTest.java    | 45 +++++------
 .../features/NetworkApiLiveTest.java            |  2 +-
 .../features/NetworkApiMockTest.java            | 12 ++-
 .../features/RouteApiLiveTest.java              |  3 +-
 .../features/SubnetworkApiLiveTest.java         | 80 ++++++++++++++++++++
 .../features/SubnetworkApiMockTest.java         |  3 +-
 .../features/TargetInstanceApiLiveTest.java     |  5 +-
 .../features/TargetPoolApiLiveTest.java         |  8 +-
 .../BaseGoogleComputeEngineApiLiveTest.java     | 13 ++++
 .../parse/ParseNetworkTest.java                 |  5 +-
 .../parse/ParseSubnetworkListTest.java          |  2 +-
 .../parse/ParseSubnetworkTest.java              |  4 +-
 .../src/test/resources/firewall_insert_3.json   | 28 +++++++
 .../test/resources/instance_insert_subnet.json  | 46 +++++++++++
 .../src/test/resources/network_get.json         |  3 +-
 .../test/resources/network_insert_custom.json   |  1 +
 .../src/test/resources/subnetwork_get.json      |  2 +-
 .../src/test/resources/subnetwork_insert.json   |  3 +-
 .../src/test/resources/subnetwork_list.json     |  2 +-
 39 files changed, 554 insertions(+), 232 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java
index 1e31890..57fca7b 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java
@@ -17,13 +17,11 @@
 package org.jclouds.googlecomputeengine;
 
 import java.io.Closeable;
-import java.net.URI;
 
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 
 import org.jclouds.googlecloud.config.CurrentProject;
-import org.jclouds.googlecomputeengine.domain.Subnetwork;
 import org.jclouds.googlecomputeengine.features.AddressApi;
 import org.jclouds.googlecomputeengine.features.AggregatedListApi;
 import org.jclouds.googlecomputeengine.features.BackendServiceApi;
@@ -46,12 +44,10 @@ import 
org.jclouds.googlecomputeengine.features.SubnetworkApi;
 import org.jclouds.googlecomputeengine.features.TargetHttpProxyApi;
 import org.jclouds.googlecomputeengine.features.TargetInstanceApi;
 import org.jclouds.googlecomputeengine.features.TargetPoolApi;
-import org.jclouds.googlecomputeengine.features.TargetHttpProxyApi;
 import org.jclouds.googlecomputeengine.features.UrlMapApi;
 import org.jclouds.googlecomputeengine.features.ZoneApi;
 import org.jclouds.rest.annotations.Delegate;
 import org.jclouds.rest.annotations.Endpoint;
-import org.jclouds.rest.annotations.EndpointParam;
 
 public interface GoogleComputeEngineApi extends Closeable {
 

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
index c2b180f..523c1b0 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
@@ -22,10 +22,11 @@ import static com.google.common.collect.Iterables.filter;
 import static com.google.common.collect.Lists.newArrayList;
 import static java.lang.String.format;
 import static org.jclouds.googlecloud.internal.ListPages.concat;
+import static 
org.jclouds.googlecomputeengine.compute.domain.internal.RegionAndName.fromRegionAndName;
+import static 
org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet.nameFromNetworkString;
 import static 
org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.IMAGE_PROJECTS;
 
 import java.net.URI;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicReference;
@@ -34,6 +35,7 @@ import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.domain.Hardware;
 import org.jclouds.compute.domain.NodeMetadata;
 import org.jclouds.compute.domain.OsFamily;
 import org.jclouds.compute.domain.Template;
@@ -43,7 +45,7 @@ import org.jclouds.domain.LocationBuilder;
 import org.jclouds.domain.LocationScope;
 import org.jclouds.domain.LoginCredentials;
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
-import 
org.jclouds.googlecomputeengine.compute.functions.FirewallTagNamingConvention;
+import org.jclouds.googlecomputeengine.compute.domain.internal.RegionAndName;
 import org.jclouds.googlecomputeengine.compute.functions.Resources;
 import 
org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions;
 import org.jclouds.googlecomputeengine.domain.AttachDisk;
@@ -56,6 +58,7 @@ import org.jclouds.googlecomputeengine.domain.MachineType;
 import org.jclouds.googlecomputeengine.domain.NewInstance;
 import org.jclouds.googlecomputeengine.domain.Operation;
 import org.jclouds.googlecomputeengine.domain.Region;
+import org.jclouds.googlecomputeengine.domain.Subnetwork;
 import org.jclouds.googlecomputeengine.domain.Tags;
 import org.jclouds.googlecomputeengine.domain.Zone;
 import org.jclouds.googlecomputeengine.features.InstanceApi;
@@ -95,34 +98,32 @@ public final class GoogleComputeEngineServiceAdapter
    private final Predicate<AtomicReference<Operation>> operationDone;
    private final Predicate<AtomicReference<Instance>> instanceVisible;
    private final Function<Map<String, ?>, String> windowsPasswordGenerator;
-   private final FirewallTagNamingConvention.Factory 
firewallTagNamingConvention;
    private final List<String> imageProjects;
    private final LoadingCache<URI, Optional<Image>> diskURIToImage;
-
-   @Inject GoogleComputeEngineServiceAdapter(JustProvider justProvider, 
GoogleComputeEngineApi api,
-                                            
Predicate<AtomicReference<Operation>> operationDone,
-                                            
Predicate<AtomicReference<Instance>> instanceVisible,
-                                            Function<Map<String, ?>, String> 
windowsPasswordGenerator,
-                                            Resources resources,
-                                            
FirewallTagNamingConvention.Factory firewallTagNamingConvention,
-                                            @Named(IMAGE_PROJECTS) String 
imageProjects,
-                                            LoadingCache<URI, Optional<Image>> 
diskURIToImage) {
+   private final LoadingCache<RegionAndName, Optional<Subnetwork>> 
subnetworksMap;
+
+   @Inject
+   GoogleComputeEngineServiceAdapter(JustProvider justProvider, 
GoogleComputeEngineApi api,
+         Predicate<AtomicReference<Operation>> operationDone, 
Predicate<AtomicReference<Instance>> instanceVisible,
+         Function<Map<String, ?>, String> windowsPasswordGenerator, Resources 
resources,
+         @Named(IMAGE_PROJECTS) String imageProjects, LoadingCache<URI, 
Optional<Image>> diskURIToImage,
+         LoadingCache<RegionAndName, Optional<Subnetwork>> subnetworksMap) {
       this.justProvider = justProvider;
       this.api = api;
       this.operationDone = operationDone;
       this.instanceVisible = instanceVisible;
       this.windowsPasswordGenerator = windowsPasswordGenerator;
       this.resources = resources;
-      this.firewallTagNamingConvention = firewallTagNamingConvention;
       this.imageProjects = 
Splitter.on(',').omitEmptyStrings().splitToList(imageProjects);
       this.diskURIToImage = diskURIToImage;
+      this.subnetworksMap = subnetworksMap;
    }
 
    @Override public NodeAndInitialCredentials<Instance> 
createNodeWithGroupEncodedIntoName(String group, String name,
          Template template) {
       GoogleComputeEngineTemplateOptions options = 
GoogleComputeEngineTemplateOptions.class.cast(template.getOptions());
 
-      checkNotNull(options.getNetworks(), "template options must specify a 
network");
+      checkNotNull(options.getNetworks(), "template options must specify a 
network or subnetwork");
       checkNotNull(template.getHardware().getUri(), "hardware must have a 
URI");
       checkNotNull(template.getImage().getUri(), "image URI is null");
 
@@ -131,15 +132,19 @@ public final class GoogleComputeEngineServiceAdapter
       List<AttachDisk> disks = Lists.newArrayList();
       disks.add(AttachDisk.newBootDisk(template.getImage().getUri(), 
getDiskTypeArgument(options, zone)));
 
-      Iterator<String> networks = options.getNetworks().iterator();
-
-      URI network = URI.create(networks.next());
-      assert !networks.hasNext() : "Error: Options should specify only one 
network";
-
-      Iterator<String> subnetworks = options.getSubnetworks().iterator();
-
-      URI subnetwork = subnetworks.hasNext() ? URI.create(subnetworks.next()) 
: null;
-      assert !subnetworks.hasNext() : "Error: Options should specify only one 
subnetwork";
+      URI network = URI.create(options.getNetworks().iterator().next());
+      URI subnetwork = null;
+      
+      if (isSubnetwork(network)) {
+         String region = template.getLocation().getParent().getId();
+         RegionAndName subnetRef = fromRegionAndName(region, 
nameFromNetworkString(network.toString()));
+         // This must be present, since the subnet is validated and its URI
+         // obtained in the CreateNodesWithGroupEncodedIntoNameThenAddToSet
+         // strategy
+         Optional<Subnetwork> subnet = subnetworksMap.getUnchecked(subnetRef);
+         network = subnet.get().network();
+         subnetwork = subnet.get().selfLink();
+      }
 
       Scheduling scheduling = getScheduling(options);
 
@@ -342,4 +347,8 @@ public final class GoogleComputeEngineServiceAdapter
 
       return Scheduling.create(onHostMaintenance, automaticRestart, 
options.preemptible());
    }
+   
+   private static boolean isSubnetwork(URI uri) {
+      return uri.toString().contains("/subnetworks/");
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java
index 6a9772e..ec0af35 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java
@@ -55,6 +55,7 @@ import 
org.jclouds.googlecomputeengine.compute.functions.OrphanedGroupsFromDeadN
 import org.jclouds.googlecomputeengine.compute.functions.Resources;
 import org.jclouds.googlecomputeengine.compute.functions.ResetWindowsPassword;
 import org.jclouds.googlecomputeengine.compute.loaders.DiskURIToImage;
+import org.jclouds.googlecomputeengine.compute.loaders.SubnetworkLoader;
 import 
org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions;
 import 
org.jclouds.googlecomputeengine.compute.predicates.AtomicInstanceVisible;
 import org.jclouds.googlecomputeengine.compute.predicates.AtomicOperationDone;
@@ -64,6 +65,7 @@ import org.jclouds.googlecomputeengine.domain.Image;
 import org.jclouds.googlecomputeengine.domain.Instance;
 import org.jclouds.googlecomputeengine.domain.MachineType;
 import org.jclouds.googlecomputeengine.domain.Operation;
+import org.jclouds.googlecomputeengine.domain.Subnetwork;
 import org.jclouds.location.suppliers.ImplicitLocationSupplier;
 import org.jclouds.location.suppliers.implicit.FirstZone;
 
@@ -84,6 +86,7 @@ import 
org.jclouds.compute.domain.internal.TemplateBuilderImpl;
 import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatement;
 import 
org.jclouds.compute.functions.NodeAndTemplateOptionsToStatementWithoutPublicKey;
 import 
org.jclouds.googlecomputeengine.compute.domain.internal.GoogleComputeEngineArbitraryCpuRamTemplateBuilderImpl;
+import org.jclouds.googlecomputeengine.compute.domain.internal.RegionAndName;
 
 public final class GoogleComputeEngineServiceContextModule
       extends ComputeServiceAdapterContextModule<Instance, MachineType, Image, 
Location> {
@@ -137,6 +140,9 @@ public final class GoogleComputeEngineServiceContextModule
 
       bind(new TypeLiteral<CacheLoader<URI, Optional<Image>>>() {
       }).to(DiskURIToImage.class);
+      
+      bind(new TypeLiteral<CacheLoader<RegionAndName, Optional<Subnetwork>>>() 
{
+      }).to(SubnetworkLoader.class);
 
       bindHttpApi(binder(), Resources.class);
    }
@@ -203,8 +209,14 @@ public final class GoogleComputeEngineServiceContextModule
 
    @Provides
    @Singleton
-   protected LoadingCache<URI, Optional<Image>> diskURIToImageMap(
-         CacheLoader<URI, Optional<Image>> in) {
+   protected LoadingCache<URI, Optional<Image>> 
diskURIToImageMap(CacheLoader<URI, Optional<Image>> in) {
+      return CacheBuilder.newBuilder().build(in);
+   }
+
+   @Provides
+   @Singleton
+   protected LoadingCache<RegionAndName, Optional<Subnetwork>> subnetworksMap(
+         CacheLoader<RegionAndName, Optional<Subnetwork>> in) {
       return CacheBuilder.newBuilder().build(in);
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/domain/internal/RegionAndName.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/domain/internal/RegionAndName.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/domain/internal/RegionAndName.java
new file mode 100644
index 0000000..b1622ca
--- /dev/null
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/domain/internal/RegionAndName.java
@@ -0,0 +1,53 @@
+/*
+ * 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.googlecomputeengine.compute.domain.internal;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
+
+/**
+ * Helpful when looking for resources by region and name
+ */
+@AutoValue
+public abstract class RegionAndName {
+
+   public abstract String regionId();
+   public abstract String name();
+   
+   RegionAndName() {
+      
+   }
+   
+   public static RegionAndName fromSlashEncoded(String name) {
+      Iterable<String> parts = Splitter.on('/').split(checkNotNull(name, 
"name"));
+      checkArgument(Iterables.size(parts) == 2, "name must be in format 
regionId/name");
+      return fromRegionAndName(Iterables.get(parts, 0), Iterables.get(parts, 
1));
+   }
+
+   public static RegionAndName fromRegionAndName(String regionId, String name) 
{
+      return new AutoValue_RegionAndName(regionId, name);
+   }
+   
+   public String slashEncode() {
+      return regionId() + "/" + name();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/loaders/SubnetworkLoader.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/loaders/SubnetworkLoader.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/loaders/SubnetworkLoader.java
index 6377a05..26670bc 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/loaders/SubnetworkLoader.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/loaders/SubnetworkLoader.java
@@ -16,42 +16,38 @@
  */
 package org.jclouds.googlecomputeengine.compute.loaders;
 
-import java.net.URI;
 import java.util.concurrent.ExecutionException;
 
-import javax.annotation.Resource;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
-import org.jclouds.googlecomputeengine.compute.functions.Resources;
+import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
+import org.jclouds.googlecomputeengine.compute.domain.internal.RegionAndName;
 import org.jclouds.googlecomputeengine.domain.Subnetwork;
-import org.jclouds.logging.Logger;
 
+import com.google.common.base.Optional;
 import com.google.common.cache.CacheLoader;
 
-
 @Singleton
-public class SubnetworkLoader extends CacheLoader<URI, Subnetwork> {
-   @Resource
-   protected Logger logger = Logger.NULL;
+public class SubnetworkLoader extends CacheLoader<RegionAndName, 
Optional<Subnetwork>> {
 
-   private final Resources resources;
+   private final GoogleComputeEngineApi api;
 
    @Inject
-   SubnetworkLoader(Resources resources) {
-      this.resources = resources;
+   SubnetworkLoader(GoogleComputeEngineApi api) {
+      this.api = api;
    }
 
    @Override
-   public Subnetwork load(URI key) throws ExecutionException {
+   public Optional<Subnetwork> load(RegionAndName key) throws 
ExecutionException {
       try {
-         return resources.subnetwork(key);
-      } catch (Exception e) {
-         throw new ExecutionException(message(key, e), e);
+         return 
Optional.fromNullable(api.subnetworksInRegion(key.regionId()).get(key.name()));
+      } catch (Exception ex) {
+         throw new ExecutionException(message(key, ex), ex);
       }
    }
 
-   public static String message(URI key, Exception e) {
-      return String.format("could not find image for disk %s: %s", 
key.toString(), e.getMessage());
+   public static String message(RegionAndName key, Exception ex) {
+      return String.format("could not find subnet %s in region %s: %s", 
key.name(), key.regionId(), ex.getMessage());
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java
index 987c2a8..288a35f 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/options/GoogleComputeEngineTemplateOptions.java
@@ -18,14 +18,12 @@ package org.jclouds.googlecomputeengine.compute.options;
 
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import org.jclouds.compute.options.TemplateOptions;
 import org.jclouds.domain.LoginCredentials;
 import org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount;
 import org.jclouds.scriptbuilder.domain.Statement;
 
-import com.google.common.collect.ImmutableSet;
 
 /** Instance options specific to Google Compute Engine. */
 public final class GoogleComputeEngineTemplateOptions extends TemplateOptions {
@@ -35,7 +33,6 @@ public final class GoogleComputeEngineTemplateOptions extends 
TemplateOptions {
    private List<ServiceAccount> serviceAccounts;
    private String bootDiskType;
    private boolean preemptible = false;
-   private Set<String> subnetworks;
 
    @Override
    public GoogleComputeEngineTemplateOptions clone() {
@@ -138,11 +135,6 @@ public final class GoogleComputeEngineTemplateOptions 
extends TemplateOptions {
       return serviceAccounts;
    }
 
-   public Set<String> getSubnetworks() {
-      return subnetworks;
-   }
-
-
    /**
     * {@inheritDoc}
     */
@@ -296,22 +288,6 @@ public final class GoogleComputeEngineTemplateOptions 
extends TemplateOptions {
    }
 
    /**
-    * Assigns subnetworks to the machine.
-    */
-   public GoogleComputeEngineTemplateOptions subnetworks(Iterable<String> 
networks) {
-      this.subnetworks = ImmutableSet.copyOf(networks);
-      return this;
-   }
-
-   /**
-    * Assigns subnetworks to the machine.
-    */
-   public GoogleComputeEngineTemplateOptions subnetworks(String... networks) {
-      this.subnetworks = ImmutableSet.copyOf(networks);
-      return this;
-   }
-
-   /**
     * {@inheritDoc}
     */
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
index 5e6cda7..b60a5f0 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
@@ -19,6 +19,8 @@ package org.jclouds.googlecomputeengine.compute.strategy;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.ImmutableList.of;
+import static org.jclouds.domain.LocationScope.ZONE;
+import static 
org.jclouds.googlecomputeengine.compute.domain.internal.RegionAndName.fromRegionAndName;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -41,20 +43,26 @@ import 
org.jclouds.compute.reference.ComputeServiceConstants;
 import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName;
 import 
org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
 import org.jclouds.compute.strategy.ListNodesStrategy;
+import org.jclouds.domain.Location;
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
+import org.jclouds.googlecomputeengine.compute.domain.internal.RegionAndName;
 import 
org.jclouds.googlecomputeengine.compute.functions.FirewallTagNamingConvention;
+import org.jclouds.googlecomputeengine.compute.functions.Resources;
 import 
org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions;
 import org.jclouds.googlecomputeengine.domain.Firewall;
 import org.jclouds.googlecomputeengine.domain.Firewall.Rule;
 import org.jclouds.googlecomputeengine.domain.Network;
 import org.jclouds.googlecomputeengine.domain.Operation;
+import org.jclouds.googlecomputeengine.domain.Subnetwork;
 import org.jclouds.googlecomputeengine.features.FirewallApi;
 import org.jclouds.googlecomputeengine.options.FirewallOptions;
 import org.jclouds.logging.Logger;
 import org.jclouds.ssh.SshKeyPairGenerator;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Strings;
+import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Multimap;
@@ -72,9 +80,11 @@ public final class 
CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
    public static final String DEFAULT_NETWORK_NAME = "default";
 
    private final GoogleComputeEngineApi api;
+   private final Resources resources;
    private final Predicate<AtomicReference<Operation>> operationDone;
    private final FirewallTagNamingConvention.Factory 
firewallTagNamingConvention;
    private final SshKeyPairGenerator keyGenerator;
+   private final LoadingCache<RegionAndName, Optional<Subnetwork>> 
subnetworksMap;
 
    @Resource
    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
@@ -87,14 +97,17 @@ public final class 
CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
          GroupNamingConvention.Factory namingConvention,
          @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService 
userExecutor,
          CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory 
customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
-         GoogleComputeEngineApi api, Predicate<AtomicReference<Operation>> 
operationDone,
-         FirewallTagNamingConvention.Factory firewallTagNamingConvention, 
SshKeyPairGenerator keyGenerator) {
+         GoogleComputeEngineApi api, Resources resources, 
Predicate<AtomicReference<Operation>> operationDone,
+         FirewallTagNamingConvention.Factory firewallTagNamingConvention, 
SshKeyPairGenerator keyGenerator,
+         LoadingCache<RegionAndName, Optional<Subnetwork>> subnetworksMap) {
       super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, 
userExecutor,
             customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
       this.api = api;
+      this.resources = resources;
       this.operationDone = operationDone;
       this.firewallTagNamingConvention = firewallTagNamingConvention;
       this.keyGenerator = keyGenerator;
+      this.subnetworksMap = subnetworksMap;
    }
 
    @Override
@@ -102,16 +115,13 @@ public final class 
CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
          Set<NodeMetadata> goodNodes, Map<NodeMetadata, Exception> badNodes,
          Multimap<NodeMetadata, CustomizationResponse> customizationResponses) 
{
 
-            Template mutableTemplate = template.clone();
       GoogleComputeEngineTemplateOptions templateOptions = 
GoogleComputeEngineTemplateOptions.class
-            .cast(mutableTemplate.getOptions());
+            .cast(template.getOptions());
       assert template.getOptions().equals(templateOptions) : "options didn't 
clone properly";
 
-      // Get Network
-      Network network = getNetwork(templateOptions.getNetworks());
-      // Setup Firewall rules
-      getOrCreateFirewalls(templateOptions, network, 
firewallTagNamingConvention.get(group));
-      templateOptions.networks(ImmutableSet.of(network.selfLink().toString()));
+      // Configure networking
+      configureNetworking(group, templateOptions, template.getLocation());
+      
       templateOptions.userMetadata(ComputeServiceConstants.NODE_GROUP_KEY, 
group);
 
       // Configure the default credentials, if needed
@@ -123,30 +133,48 @@ public final class 
CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
       }
 
       if (templateOptions.getRunScript() != null && 
templateOptions.getLoginPrivateKey() == null) {
-         logger.warn(">> A runScript has been configured but no SSH key has 
been provided."
+         logger.warn(">> a runScript has been configured but no SSH key has 
been provided."
                + " Authentication will delegate to the ssh-agent");
       }
 
-      return super.execute(group, count, mutableTemplate, goodNodes, badNodes, 
customizationResponses);
+      return super.execute(group, count, template, goodNodes, badNodes, 
customizationResponses);
    }
 
    /**
-    * Try and find a network previously created by the user.
+    * Configure the networks taking into account that users may have configured
+    * a custom subnet or a legacy network.
     */
-   private Network getNetwork(Set<String> networks) {
-      String networkName;
-      if (networks == null || networks.isEmpty()){
+   private void configureNetworking(String group, 
GoogleComputeEngineTemplateOptions options, Location location) {
+      String networkName = null;
+      Network network = null;
+
+      if (options.getNetworks().isEmpty()) {
          networkName = DEFAULT_NETWORK_NAME;
-      }
-      else {
-         Iterator<String> iterator = networks.iterator();
+      } else {
+         Iterator<String> iterator = options.getNetworks().iterator();
          networkName = nameFromNetworkString(iterator.next());
-         checkArgument(!iterator.hasNext(), "Error: Please specify only one 
network in TemplateOptions when using GCE.");
+         checkArgument(!iterator.hasNext(),
+               "Error: Please specify only one network/subnetwork in 
TemplateOptions when using GCE.");
+      }
 
+      String region = ZONE == location.getScope() ? 
location.getParent().getId() : location.getId();
+      Optional<Subnetwork> subnet = 
subnetworksMap.getUnchecked(fromRegionAndName(region, networkName));
+      if (subnet.isPresent()) {
+         network = resources.network(subnet.get().network());
+         options.networks(ImmutableSet.of(subnet.get().selfLink().toString()));
+         logger.debug(">> attaching nodes to subnet(%s) in region(%s)", 
subnet.get().name(), region);
+      } else {
+         logger.warn(">> subnet(%s) was not found in region(%s). Trying to 
find a matching legacy network...",
+               networkName, region);
+         network = api.networks().get(networkName);
+         options.networks(ImmutableSet.of(network.selfLink().toString()));
+         logger.debug(">> attaching nodes to legacy network(%s)", 
network.name());
       }
-      Network network = api.networks().get(networkName);
+
       checkArgument(network != null, "Error: no network with name %s was 
found", networkName);
-      return network;
+
+      // Setup Firewall rules
+      getOrCreateFirewalls(options, network, subnet, 
firewallTagNamingConvention.get(group));
    }
 
    /**
@@ -162,7 +190,7 @@ public final class 
CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
     *      org.jclouds.googlecomputeengine.options.FirewallOptions)
     */
    private void getOrCreateFirewalls(GoogleComputeEngineTemplateOptions 
templateOptions, Network network,
-         FirewallTagNamingConvention naming) {
+         Optional<Subnetwork> subnet, FirewallTagNamingConvention naming) {
 
       Set<String> tags = Sets.newLinkedHashSet(templateOptions.getTags());
 
@@ -188,11 +216,14 @@ public final class 
CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
       String name = naming.name(ports);
       Firewall firewall = firewallApi.get(name);
       AtomicReference<Operation> operation = null;
+      
+      String interiorRange = subnet.isPresent() ? subnet.get().ipCidrRange() : 
DEFAULT_INTERNAL_NETWORK_RANGE;
+      
       if (firewall == null) {
          List<Rule> rules = ImmutableList.of(Rule.create("tcp", ports), 
Rule.create("udp", ports));
          FirewallOptions firewallOptions = new 
FirewallOptions().name(name).network(network.selfLink())
                   .allowedRules(rules).sourceTags(templateOptions.getTags())
-                  .sourceRanges(of(DEFAULT_INTERNAL_NETWORK_RANGE, 
EXTERIOR_RANGE))
+                  .sourceRanges(of(interiorRange, EXTERIOR_RANGE))
                   .targetTags(ImmutableList.of(name));
 
          operation = Atomics.newReference(firewallApi

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
index 2a813d1..1525d1f 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
@@ -126,13 +126,11 @@ public final class GoogleComputeEngineHttpApiModule 
extends HttpApiModule<Google
 
       private final GetProject api;
       private final Supplier<URI> defaultEndpoint;
-      private final String identityName;
 
       @Inject
       UseApiToResolveProjectName(GetProject api, @Provider Supplier<URI> 
defaultEndpoint, ProviderMetadata metadata) {
          this.api = api;
          this.defaultEndpoint = defaultEndpoint;
-         this.identityName = metadata.getApiMetadata().getIdentityName();
       }
 
       @Override public URI apply(Credentials in) {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Network.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Network.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Network.java
index bf89e38..0fc03b2 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Network.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Network.java
@@ -25,6 +25,7 @@ import org.jclouds.json.SerializedNames;
 
 import com.google.auto.value.AutoValue;
 import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
 
 /**
  * Represents a network used to enable instance communication.
@@ -46,8 +47,6 @@ public abstract class Network {
 
    public abstract String name();
 
-   public abstract NetworkType type();
-
    @Nullable public abstract String description();
 
    /**
@@ -61,26 +60,24 @@ public abstract class Network {
     * If not specified, the default value is the first usable address in 
IPv4Range.
     */
    @Nullable public abstract String gatewayIPv4();
+   
+   public abstract boolean autoCreateSubnetworks();
 
-   @Nullable public abstract List<URI> subnetworks();
+   public abstract List<URI> subnetworks();
 
-   public static Network create(String id, Date creationTimestamp, URI 
selfLink, String name, String description, String rangeIPv4,
-                                String gatewayIPv4) {
-      return new AutoValue_Network(id, creationTimestamp, selfLink, name, 
NetworkType.LegacyNetwork, description,
-              rangeIPv4, gatewayIPv4, null);
+   @SerializedNames({ "id", "creationTimestamp", "selfLink", "name", 
"description", "IPv4Range", "gatewayIPv4",
+         "autoCreateSubnetworks", "subnetworks" })
+   public static Network create(String id, Date creationTimestamp, URI 
selfLink, String name, String description,
+         String rangeIPv4, String gatewayIPv4, boolean autoCreateSubnetworks, 
List<URI> subnetworks) {
+      return new AutoValue_Network(id, creationTimestamp, selfLink, name, 
description, rangeIPv4, gatewayIPv4,
+            autoCreateSubnetworks, subnetworks == null ? ImmutableList.<URI> 
of() : ImmutableList.copyOf(subnetworks));
    }
 
-   @SerializedNames({ "id", "creationTimestamp", "selfLink", "name", 
"description", "IPv4Range", "gatewayIPv4", "autoCreateSubnetworks", 
"subnetworks" })
-   public static Network create(String id, Date creationTimestamp, URI 
selfLink, String name, String description, String rangeIPv4,
-         String gatewayIPv4, String autoCreateSubnetworks, List<URI> 
subnetworks) {
-      NetworkType type;
-      type = !Strings.isNullOrEmpty(rangeIPv4) ? NetworkType.LegacyNetwork
-              : (autoCreateSubnetworks.equals("true") ? 
NetworkType.AutoSubnetwork
-                  : NetworkType.CustomNetwork);
-      return new AutoValue_Network(id, creationTimestamp, selfLink, name, 
type, description, rangeIPv4, gatewayIPv4,
-              subnetworks);
+   Network() {
    }
 
-   Network() {
+   public NetworkType type() {
+      return !Strings.isNullOrEmpty(rangeIPv4()) ? NetworkType.LegacyNetwork
+            : (autoCreateSubnetworks() ? NetworkType.AutoSubnetwork : 
NetworkType.CustomNetwork);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/NewInstance.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/NewInstance.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/NewInstance.java
index d64d1ed..67d9925 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/NewInstance.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/NewInstance.java
@@ -43,20 +43,11 @@ public abstract class NewInstance {
 
       abstract List<AccessConfig> accessConfigs();
 
-      static NetworkInterface create(URI network) {
-         return create(network, Arrays.asList(AccessConfig.create(null, 
Type.ONE_TO_ONE_NAT, null)));
-      }
-
       static NetworkInterface create(URI network, URI subnetwork) {
          return create(network, subnetwork,
              Arrays.asList(AccessConfig.create(null, Type.ONE_TO_ONE_NAT, 
null)));
       }
 
-      @SerializedNames({ "network", "accessConfigs" })
-      static NetworkInterface create(URI network, List<AccessConfig> 
accessConfigs) {
-         return new AutoValue_NewInstance_NetworkInterface(network, null, 
accessConfigs);
-      }
-
       @SerializedNames({ "network", "subnetwork", "accessConfigs" })
       static NetworkInterface create(URI network, URI subnetwork, 
List<AccessConfig> accessConfigs) {
          return new AutoValue_NewInstance_NetworkInterface(network, 
subnetwork, accessConfigs);
@@ -88,20 +79,11 @@ public abstract class NewInstance {
    @Nullable public abstract Scheduling scheduling();
 
    /** Convenience for creating a new instance with only a boot disk and 
minimal parameters. */
-   public static NewInstance create(String name, URI machineType, URI network, 
URI sourceImage) {
-      return create(name, machineType, network, 
Arrays.asList(AttachDisk.newBootDisk(sourceImage)), null, null);
-   }
-
    public static NewInstance create(String name, URI machineType, URI network, 
URI subnetwork, URI sourceImage) {
       return create(name, machineType, network, subnetwork, 
Arrays.asList(AttachDisk.newBootDisk(sourceImage)), null,
               null);
    }
 
-   public static NewInstance create(String name, URI machineType, URI network, 
List<AttachDisk> disks,
-                                    @Nullable String description, @Nullable 
Tags tags) {
-      return create(name, machineType, network, null, disks, description, 
tags);
-   }
-
    public static NewInstance create(String name, URI machineType, URI network, 
@Nullable URI subnetwork,
                                     List<AttachDisk> disks, @Nullable String 
description, @Nullable Tags tags) {
       checkArgument(disks.get(0).boot(), "disk 0 must be a boot disk! %s", 
disks);
@@ -112,8 +94,9 @@ public abstract class NewInstance {
             foundBoot = true;
          }
       }
-      return create(name, machineType, null, 
ImmutableList.of(NetworkInterface.create(network)), ImmutableList.copyOf(disks),
-            description, tags != null ? tags : Tags.create(), 
Metadata.create(), null, null);
+      return create(name, machineType, null, 
ImmutableList.of(NetworkInterface.create(network, subnetwork)),
+            ImmutableList.copyOf(disks), description, tags != null ? tags : 
Tags.create(), Metadata.create(), null,
+            null);
    }
 
    @SerializedNames({ "name", "machineType", "canIpForward", 
"networkInterfaces", "disks", "description",
@@ -140,14 +123,6 @@ public abstract class NewInstance {
       private List<ServiceAccount> serviceAccounts;
       private Scheduling scheduling;
 
-      public Builder(String name, URI machineType, URI network, 
List<AttachDisk> disks) {
-         checkNotNull(name, "NewInstance name cannot be null");
-         this.name = name;
-         this.machineType = machineType;
-         this.networkInterfaces = 
ImmutableList.of(NetworkInterface.create(network));
-         this.disks = disks;
-      }
-
       public Builder(String name, URI machineType, URI network, URI 
subnetwork, List<AttachDisk> disks) {
          checkNotNull(name, "NewInstance name cannot be null");
          this.name = name;
@@ -156,14 +131,6 @@ public abstract class NewInstance {
          this.disks = disks;
       }
 
-      public Builder(String name, URI machineType, URI network, URI 
sourceImage) {
-         checkNotNull(name, "NewInstance name cannot be null");
-         this.name = name;
-         this.machineType = machineType;
-         this.networkInterfaces = 
ImmutableList.of(NetworkInterface.create(network));
-         this.disks = Arrays.asList(AttachDisk.newBootDisk(sourceImage));
-      }
-
       public Builder(String name, URI machineType, URI network, URI 
subnetwork, URI sourceImage) {
          checkNotNull(name, "NewInstance name cannot be null");
          this.name = name;

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Subnetwork.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Subnetwork.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Subnetwork.java
index a696a8c..8dcd85b 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Subnetwork.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Subnetwork.java
@@ -48,13 +48,12 @@ public abstract class Subnetwork {
 
    public abstract URI region();
 
-   @SerializedNames({ "id", "creationTimestamp", "selfLink", "name",
-                      "description", "gatewayAddress", "network", 
"ipCidrRange", "region" })
-   public static Subnetwork create(String id, Date creationTimestamp, URI 
selfLink, String name,
-                                   String description, String gatewayAddress, 
URI network,
-                                   String ipCidrRange, URI region) {
-      return new AutoValue_Subnetwork(id, creationTimestamp, selfLink, name, 
description,
-              gatewayAddress, network, ipCidrRange, region);
+   @SerializedNames({ "id", "creationTimestamp", "selfLink", "name", 
"description", "gatewayAddress", "network",
+         "ipCidrRange", "region" })
+   public static Subnetwork create(String id, Date creationTimestamp, URI 
selfLink, String name, String description,
+         String gatewayAddress, URI network, String ipCidrRange, URI region) {
+      return new AutoValue_Subnetwork(id, creationTimestamp, selfLink, name, 
description, gatewayAddress, network,
+            ipCidrRange, region);
    }
 
    Subnetwork() {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java
index c67b64c..532c207 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java
@@ -43,7 +43,7 @@ import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.oauth.v2.filters.OAuthFilter;
 import org.jclouds.rest.annotations.BinderParam;
 import org.jclouds.rest.annotations.Fallback;
-import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.Payload;
 import org.jclouds.rest.annotations.PayloadParam;
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.SkipEncoding;
@@ -66,7 +66,7 @@ public interface NetworkApi {
    Network get(@PathParam("network") String networkName);
 
    /**
-    * Creates a persistent network resource in the specified project with the 
specified range.
+    * Creates a legacy persistent network resource in the specified project 
with the specified range.
     *
     * @param networkName the network name
     * @param IPv4Range   the range of the network to be inserted.
@@ -76,21 +76,33 @@ public interface NetworkApi {
    @Named("Networks:insert")
    @POST
    @Produces(APPLICATION_JSON)
-   @MapBinder(BindToJsonPayload.class)
-   Operation createInIPv4Range(@PayloadParam("name") String networkName,
-                               @PayloadParam("IPv4Range") String IPv4Range);
+   @Payload("%7B\"name\":\"{name}\",\"IPv4Range\":\"{IPv4Range}\"%7D")
+   Operation createLegacy(@PayloadParam("name") String networkName, 
@PayloadParam("IPv4Range") String IPv4Range);
+   
+   /**
+    * Creates a custom persistent network resource in the specified project 
with the specified range.
+    *
+    * @param networkName the network name
+    * @return an Operation resource. To check on the status of an operation, 
poll the Operations resource returned to
+    *         you, and look for the status field.
+    */
+   @Named("Networks:insert")
+   @POST
+   @Produces(APPLICATION_JSON)
+   @Payload("%7B\"autoCreateSubnetworks\":false,\"name\":\"{name}\"%7D")
+   Operation createCustom(@PayloadParam("name") String networkName);
 
    /**
-    * Creates a persistent network resource in the specified project with the 
specified range and specified gateway.
+    * Creates a persistent network resource in the specified project with the 
specified options.
     *
-    * @param options the options to create the network.
+    * @param options the network options.
     * @return an Operation resource. To check on the status of an operation, 
poll the Operations resource returned to
     *         you, and look for the status field.
     */
    @Named("Networks:insert")
    @POST
    @Produces(APPLICATION_JSON)
-   Operation createInIPv4Range(@BinderParam(BindToJsonPayload.class) 
NetworkCreationOptions options);
+   Operation create(@BinderParam(BindToJsonPayload.class) 
NetworkCreationOptions options);
 
    /** Deletes a network by name and returns the operation in progress, or 
null if not found. */
    @Named("Networks:delete")
@@ -124,7 +136,7 @@ public interface NetworkApi {
    @Transform(NetworkPages.class)
    Iterator<ListPage<Network>> list(ListOptions options);
 
-   final class NetworkPages extends BaseToIteratorOfListPage<Network, 
NetworkPages> {
+   static final class NetworkPages extends BaseToIteratorOfListPage<Network, 
NetworkPages> {
 
       private final GoogleComputeEngineApi api;
 

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/SubnetworkApi.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/SubnetworkApi.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/SubnetworkApi.java
index 1d52989..576c36f 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/SubnetworkApi.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/SubnetworkApi.java
@@ -18,7 +18,6 @@ package org.jclouds.googlecomputeengine.features;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
-import java.net.URI;
 import java.util.Iterator;
 
 import javax.inject.Inject;
@@ -43,11 +42,7 @@ import 
org.jclouds.googlecomputeengine.options.SubnetworkCreationOptions;
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.oauth.v2.filters.OAuthFilter;
 import org.jclouds.rest.annotations.BinderParam;
-import org.jclouds.rest.annotations.Delegate;
-import org.jclouds.rest.annotations.EndpointParam;
 import org.jclouds.rest.annotations.Fallback;
-import org.jclouds.rest.annotations.MapBinder;
-import org.jclouds.rest.annotations.PayloadParam;
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.SkipEncoding;
 import org.jclouds.rest.annotations.Transform;
@@ -107,6 +102,12 @@ public interface SubnetworkApi {
    @GET
    @Transform(SubnetworkPages.class)
    Iterator<ListPage<Subnetwork>> list();
+   
+   /** @see #listPage(String, ListOptions) */
+   @Named("Subnetworks:list")
+   @GET
+   @Transform(SubnetworkPages.class)
+   Iterator<ListPage<Subnetwork>> list(ListOptions options);
 
    static final class SubnetworkPages extends 
BaseCallerArg0ToIteratorOfListPage<Subnetwork, SubnetworkPages> {
 

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/options/NetworkCreationOptions.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/options/NetworkCreationOptions.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/options/NetworkCreationOptions.java
index 3003322..bf0110f 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/options/NetworkCreationOptions.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/options/NetworkCreationOptions.java
@@ -37,18 +37,20 @@ public abstract class NetworkCreationOptions {
     * The range of internal addresses that are legal on this network. This 
range is a CIDR
     * specification, for example: {@code 192.168.0.0/16}.
     */
-   public abstract String rangeIPv4();
+   @Nullable public abstract String rangeIPv4();
 
    /**
     * This must be within the range specified by IPv4Range, and is typically 
the first usable address in that range.
     * If not specified, the default value is the first usable address in 
IPv4Range.
     */
    @Nullable public abstract String gatewayIPv4();
+   
+   @Nullable public abstract Boolean autoCreateSubnetworks();
 
-   @SerializedNames({ "name", "description", "IPv4Range", "gatewayIPv4" })
+   @SerializedNames({ "name", "description", "IPv4Range", "gatewayIPv4", 
"autoCreateSubnetworks" })
    public static NetworkCreationOptions create(String name, String 
description, String rangeIPv4,
-         String gatewayIPv4) {
-      return new AutoValue_NetworkCreationOptions(name, description, 
rangeIPv4, gatewayIPv4);
+         String gatewayIPv4, Boolean autoCreateSubnetworks) {
+      return new AutoValue_NetworkCreationOptions(name, description, 
rangeIPv4, gatewayIPv4, autoCreateSubnetworks);
    }
 
    NetworkCreationOptions() {
@@ -59,10 +61,15 @@ public abstract class NetworkCreationOptions {
       private String description;
       private String rangeIPv4;
       private String gatewayIPv4;
-
-      public Builder(String name, String rangeIPv4){
+      private Boolean autoCreateSubnetworks;
+      
+      public Builder(String name) {
          this.name = name;
+      }
+      
+      public Builder rangeIPv4(String rangeIPv4) {
          this.rangeIPv4 = rangeIPv4;
+         return this;
       }
 
       public Builder description(String description) {
@@ -74,11 +81,15 @@ public abstract class NetworkCreationOptions {
          this.gatewayIPv4 = gatewayIPv4;
          return this;
       }
+      
+      public Builder autoCreateSubnetworks(Boolean autoCreateSubnetworks) {
+         this.autoCreateSubnetworks = autoCreateSubnetworks;
+         return this;
+      }
 
       public NetworkCreationOptions build() {
          checkNotNull(name, "NetworkCreationOptions name cannot be null");
-         checkNotNull(rangeIPv4, "NetworkCreationOptions rangeIPv4 cannot be 
null");
-         return create(name, description, rangeIPv4, gatewayIPv4);
+         return create(name, description, rangeIPv4, gatewayIPv4, 
autoCreateSubnetworks);
       }
 
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/options/SubnetworkCreationOptions.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/options/SubnetworkCreationOptions.java
 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/options/SubnetworkCreationOptions.java
index d90901b..0657661 100644
--- 
a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/options/SubnetworkCreationOptions.java
+++ 
b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/options/SubnetworkCreationOptions.java
@@ -16,8 +16,6 @@
  */
 package org.jclouds.googlecomputeengine.options;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 import java.net.URI;
 
 import org.jclouds.javax.annotation.Nullable;
@@ -33,7 +31,8 @@ public abstract class SubnetworkCreationOptions {
 
    public abstract String name();
 
-   @Nullable public abstract String description();
+   @Nullable
+   public abstract String description();
 
    public abstract URI network();
 
@@ -41,12 +40,16 @@ public abstract class SubnetworkCreationOptions {
 
    public abstract URI region();
 
-   @SerializedNames({ "name", "description", "network", "ipCidrRange", 
"region" })
-   public static SubnetworkCreationOptions create(String name, String 
description, URI network,
-                                                  String ipCidrRange, URI 
region) {
-      return new AutoValue_SubnetworkCreationOptions(name, description, 
network, ipCidrRange, region);
+   public abstract boolean privateIpGoogleAccess();
+
+   @SerializedNames({ "name", "description", "network", "ipCidrRange", 
"region", "privateIpGoogleAccess" })
+   public static SubnetworkCreationOptions create(String name, String 
description, URI network, String ipCidrRange,
+         URI region, boolean privateIpGoogleAccess) {
+      return new AutoValue_SubnetworkCreationOptions(name, description, 
network, ipCidrRange, region,
+            privateIpGoogleAccess);
    }
 
    SubnetworkCreationOptions() {
+      
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceMockTest.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceMockTest.java
 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceMockTest.java
index 279f09d..38c6a4d 100644
--- 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceMockTest.java
+++ 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceMockTest.java
@@ -173,6 +173,7 @@ public class GoogleComputeEngineServiceMockTest extends 
BaseGoogleComputeEngineA
       server.enqueue(jsonResponse("/image_list.json"));
       server.enqueue(jsonResponse("/image_list_debian.json")); // per 
IMAGE_PROJECTS = "debian-cloud"
       server.enqueue(jsonResponse("/aggregated_machinetype_list.json"));
+      server.enqueue(new MockResponse().setResponseCode(404)); // Get Subnet
       server.enqueue(jsonResponse("/network_get_default.json"));
       server.enqueue(new MockResponse().setResponseCode(404)); // Get Firewall
       server.enqueue(jsonResponse("/operation.json")); // Create Firewall
@@ -199,6 +200,7 @@ public class GoogleComputeEngineServiceMockTest extends 
BaseGoogleComputeEngineA
       assertSent(server, "GET", "/projects/party/global/images");
       assertSent(server, "GET", "/projects/debian-cloud/global/images");
       assertSent(server, "GET", "/projects/party/aggregated/machineTypes");
+      assertSent(server, "GET", 
"/projects/party/regions/us-central1/subnetworks/default");
       assertSent(server, "GET", "/projects/party/global/networks/default");
       assertSent(server, "GET", 
"/projects/party/global/firewalls/jclouds-test-65f"); // Get Firewall
       assertSent(server, "POST", "/projects/party/global/firewalls", // Create 
Firewall
@@ -219,6 +221,7 @@ public class GoogleComputeEngineServiceMockTest extends 
BaseGoogleComputeEngineA
       server.enqueue(jsonResponse("/image_list.json"));
       server.enqueue(jsonResponse("/image_list_debian.json")); // per 
IMAGE_PROJECTS = "debian-cloud"
       server.enqueue(jsonResponse("/aggregated_machinetype_list.json"));
+      server.enqueue(new MockResponse().setResponseCode(404)); // Get Subnet
       server.enqueue(jsonResponse("/network_get_default.json"));
       server.enqueue(new MockResponse().setResponseCode(404)); // Get Firewall
       server.enqueue(jsonResponse("/operation.json")); // Create Firewall
@@ -248,6 +251,7 @@ public class GoogleComputeEngineServiceMockTest extends 
BaseGoogleComputeEngineA
       assertSent(server, "GET", "/projects/party/global/images");
       assertSent(server, "GET", "/projects/debian-cloud/global/images");
       assertSent(server, "GET", "/projects/party/aggregated/machineTypes");
+      assertSent(server, "GET", 
"/projects/party/regions/us-central1/subnetworks/default");
       assertSent(server, "GET", "/projects/party/global/networks/default");
       assertSent(server, "GET", 
"/projects/party/global/firewalls/jclouds-test-65f"); // Get Firewall
       assertSent(server, "POST", "/projects/party/global/firewalls", // Create 
Firewall
@@ -263,6 +267,58 @@ public class GoogleComputeEngineServiceMockTest extends 
BaseGoogleComputeEngineA
 
       assertSent(server, "GET", 
"/projects/party/zones/us-central1-a/instances/test-1");
    }
+   
+   public void createNodeWithCustomSubnetwork() throws Exception {
+      server.enqueue(singleRegionSingleZoneResponse());
+      server.enqueue(jsonResponse("/image_list.json"));
+      server.enqueue(jsonResponse("/image_list_debian.json")); // per 
IMAGE_PROJECTS = "debian-cloud"
+      server.enqueue(jsonResponse("/aggregated_machinetype_list.json"));
+      server.enqueue(jsonResponse("/subnetwork_get.json"));
+      server.enqueue(jsonResponse("/network_get.json"));
+      server.enqueue(new MockResponse().setResponseCode(404)); // Get Firewall
+      server.enqueue(jsonResponse("/operation.json")); // Create Firewall
+      server.enqueue(jsonResponse("/zone_operation.json"));
+      server.enqueue(aggregatedListWithInstanceNetworkAndStatus("test-0", 
"test-network", RUNNING));
+      server.enqueue(jsonResponse("/disk_get_with_source_image.json"));
+      server.enqueue(jsonResponse("/image_get_for_source_image.json"));
+      server.enqueue(jsonResponse("/disktype_ssd.json"));
+      server.enqueue(jsonResponse("/operation.json")); // Create Instance
+      server.enqueue(instanceWithNetworkAndStatusAndSsd("test-1", 
"test-network", RUNNING));
+
+      ComputeService computeService = computeService();
+
+      GoogleComputeEngineTemplateOptions options = 
computeService.templateOptions()
+            
.as(GoogleComputeEngineTemplateOptions.class).autoCreateKeyPair(false)
+            .tags(ImmutableSet.of("aTag")).blockUntilRunning(false)
+            .bootDiskType("pd-ssd").networks("jclouds-test");
+
+      Template template = 
computeService.templateBuilder().options(options).build();
+      NodeMetadata node = 
getOnlyElement(computeService.createNodesInGroup("test", 1, template));
+
+      // prove our caching works.
+      assertEquals(node.getImageId(), template.getImage().getId());
+      assertEquals(node.getLocation().getId(), template.getLocation().getId());
+
+      assertSent(server, "GET", "/projects/party/regions");
+      assertSent(server, "GET", "/projects/party/global/images");
+      assertSent(server, "GET", "/projects/debian-cloud/global/images");
+      assertSent(server, "GET", "/projects/party/aggregated/machineTypes");
+      assertSent(server, "GET", 
"/projects/party/regions/us-central1/subnetworks/jclouds-test");
+      assertSent(server, "GET", "/projects/party/global/networks/mynetwork");
+      assertSent(server, "GET", 
"/projects/party/global/firewalls/jclouds-test-65f"); // Get Firewall
+      assertSent(server, "POST", "/projects/party/global/firewalls", // Create 
Firewall
+            stringFromResource("/firewall_insert_3.json"));
+
+      assertSent(server, "GET", 
"/projects/party/zones/us-central1-a/operations/operation-1354084865060");
+      assertSent(server, "GET", "/projects/party/aggregated/instances");
+      assertSent(server, "GET", 
"/projects/party/zones/us-central1-a/disks/test");
+      assertSent(server, "GET", 
"/projects/debian-cloud/global/images/debian-7-wheezy-v20140718");
+      assertSent(server, "GET", 
"/projects/party/zones/us-central1-a/diskTypes/pd-ssd");
+      assertSent(server, "POST", 
"/projects/party/zones/us-central1-a/instances",
+            String.format(stringFromResource("/instance_insert_subnet.json"), 
template.getHardware().getId(), template.getImage().getId()));
+
+      assertSent(server, "GET", 
"/projects/party/zones/us-central1-a/instances/test-1");
+   }
 
    private MockResponse instanceWithNetworkAndStatus(String instanceName, 
String networkName, Instance.Status status) {
       return new MockResponse().setBody(

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/ResourcesMockTest.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/ResourcesMockTest.java
 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/ResourcesMockTest.java
index fb2ed04..3ace7f2 100644
--- 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/ResourcesMockTest.java
+++ 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/ResourcesMockTest.java
@@ -24,12 +24,14 @@ import org.jclouds.googlecomputeengine.domain.Image;
 import org.jclouds.googlecomputeengine.domain.Instance;
 import org.jclouds.googlecomputeengine.domain.Network;
 import org.jclouds.googlecomputeengine.domain.Operation;
+import org.jclouds.googlecomputeengine.domain.Subnetwork;
 import 
org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiMockTest;
 import org.jclouds.googlecomputeengine.parse.ParseDiskTest;
 import org.jclouds.googlecomputeengine.parse.ParseImageTest;
 import org.jclouds.googlecomputeengine.parse.ParseInstanceTest;
 import org.jclouds.googlecomputeengine.parse.ParseNetworkTest;
 import org.jclouds.googlecomputeengine.parse.ParseOperationTest;
+import org.jclouds.googlecomputeengine.parse.ParseSubnetworkTest;
 import org.testng.annotations.Test;
 
 @Test(groups = "unit", testName = "ResourcesMockTest", singleThreaded = true)
@@ -155,6 +157,22 @@ public class ResourcesMockTest extends 
BaseGoogleComputeEngineApiMockTest {
       assertSent(server, "POST", "/foo/bar/start");
    }
    
+   public void testSubnetwork() throws Exception {
+      server.enqueue(jsonResponse("/subnetwork_get.json"));
+
+      Subnetwork subnet = 
resourceApi().subnetwork(server.getUrl("/foo/bar").toURI());
+      assertEquals(subnet, new 
ParseSubnetworkTest().expected(url("/projects")));
+      assertSent(server, "GET", "/foo/bar");
+   }
+   
+   public void testSubnetworkReturns404() throws Exception {
+      server.enqueue(response404());
+
+      Subnetwork subnet = 
resourceApi().subnetwork(server.getUrl("/foo/bar").toURI());
+      assertNull(subnet);
+      assertSent(server, "GET", "/foo/bar");
+   }
+   
    private Resources resourceApi() {
       return builder().build().utils().injector().getInstance(Resources.class);
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java
 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java
index a56cc3e..794f27e 100644
--- 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java
+++ 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java
@@ -45,8 +45,7 @@ public class FirewallApiLiveTest extends 
BaseGoogleComputeEngineApiLiveTest {
    @Test(groups = "live")
    public void testInsertFirewall() {
       // need to insert the network first
-      assertOperationDoneSuccessfully(
-            api.networks().createInIPv4Range(FIREWALL_NETWORK_NAME, 
IPV4_RANGE));
+      
assertOperationDoneSuccessfully(api.networks().createLegacy(FIREWALL_NETWORK_NAME,
 IPV4_RANGE));
 
       FirewallOptions firewall = new FirewallOptions()
               .addAllowedRule(Firewall.Rule.create("tcp", 
ImmutableList.of("22")))

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java
 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java
index 9f202e2..7b56456 100644
--- 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java
+++ 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java
@@ -30,18 +30,18 @@ import java.util.Properties;
 
 import org.jclouds.googlecloud.domain.ListPage;
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
+import org.jclouds.googlecomputeengine.domain.AttachDisk;
 import org.jclouds.googlecomputeengine.domain.Image;
 import org.jclouds.googlecomputeengine.domain.Instance;
 import org.jclouds.googlecomputeengine.domain.Instance.AttachedDisk;
+import 
org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig;
 import 
org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig.Type;
 import org.jclouds.googlecomputeengine.domain.Instance.Scheduling;
 import 
org.jclouds.googlecomputeengine.domain.Instance.Scheduling.OnHostMaintenance;
 import org.jclouds.googlecomputeengine.domain.Instance.SerialPortOutput;
 import org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount;
-import 
org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig;
 import org.jclouds.googlecomputeengine.domain.Metadata;
 import org.jclouds.googlecomputeengine.domain.NewInstance;
-import org.jclouds.googlecomputeengine.domain.AttachDisk;
 import org.jclouds.googlecomputeengine.domain.Operation;
 import org.jclouds.googlecomputeengine.domain.Tags;
 import 
org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest;
@@ -96,6 +96,7 @@ public class InstanceApiLiveTest extends 
BaseGoogleComputeEngineApiLiveTest {
             INSTANCE_NAME, // name
             getDefaultMachineTypeUrl(), // machineType
             getNetworkUrl(INSTANCE_NETWORK_NAME), // network
+            null, // subnetwork
             Arrays.asList(AttachDisk.newBootDisk(imageUri),
                   AttachDisk.existingDisk(getDiskUrl(DISK_NAME))), // disks
             "a description", // description
@@ -106,6 +107,7 @@ public class InstanceApiLiveTest extends 
BaseGoogleComputeEngineApiLiveTest {
       instance2 = new NewInstance.Builder(INSTANCE_NAME2, // name
             getDefaultMachineTypeUrl(), // machineType
             getNetworkUrl(INSTANCE_NETWORK_NAME), // network
+            null, // subnetwork
             imageUri) // sourceImage
             .canIpForward(true)
             .description("description")
@@ -141,8 +143,7 @@ public class InstanceApiLiveTest extends 
BaseGoogleComputeEngineApiLiveTest {
    @Test(groups = "live")
    public void testInsertInstance() {
       // need to insert the network first
-      assertOperationDoneSuccessfully(api.networks().createInIPv4Range
-              (INSTANCE_NETWORK_NAME, IPV4_RANGE));
+      
assertOperationDoneSuccessfully(api.networks().createLegacy(INSTANCE_NETWORK_NAME,
 IPV4_RANGE));
 
       assertOperationDoneSuccessfully(diskApi().create(DISK_NAME,
             new 
DiskCreationOptions.Builder().sizeGb(DEFAULT_DISK_SIZE_GB).build()));

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiMockTest.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiMockTest.java
 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiMockTest.java
index 22a5c9b..123e350 100644
--- 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiMockTest.java
+++ 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiMockTest.java
@@ -86,6 +86,7 @@ public class InstanceApiMockTest extends 
BaseGoogleComputeEngineApiMockTest {
             "test-1", // name
             
URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")),
 // machineType
             URI.create(url("/projects/party/global/networks/default")), // 
network
+            null, // subnetwork
             
URI.create(url("/projects/party/global/images/centos-6-2-v20120326")) // 
sourceImage
       );
 
@@ -101,6 +102,7 @@ public class InstanceApiMockTest extends 
BaseGoogleComputeEngineApiMockTest {
             "test-1", // name
             
URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")),
 // machineType
             URI.create(url("/projects/party/global/networks/default")), // 
network
+            null, // subnetwork
             
Arrays.asList(AttachDisk.existingBootDisk(URI.create(url("/projects/party/zones/us-central1-a/disks/test")))),
             "desc", // description
             null // tags
@@ -270,6 +272,7 @@ public class InstanceApiMockTest extends 
BaseGoogleComputeEngineApiMockTest {
       NewInstance newInstance = new NewInstance.Builder("test-1", // name
             
URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")),
 // machineType
             URI.create(url("/projects/party/global/networks/default")), // 
network
+            null, // subnetwork
             
URI.create(url("/projects/party/global/images/centos-6-2-v20120326"))).build(); 
// sourceImage)
 
       assertEquals(instanceApi().create(newInstance), new 
ParseZoneOperationTest().expected(url("/projects")));
@@ -284,6 +287,7 @@ public class InstanceApiMockTest extends 
BaseGoogleComputeEngineApiMockTest {
             "test-1", // name
             
URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")),
 // machineType
             URI.create(url("/projects/party/global/networks/default")), // 
network
+            null, // subnetwork
             
Arrays.asList(AttachDisk.existingBootDisk(URI.create(url("/projects/party/zones/us-central1-a/disks/test")))))
             .canIpForward(true)
             .description("desc")

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiWindowsLiveTest.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiWindowsLiveTest.java
 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiWindowsLiveTest.java
index 3fb043c..381711a 100644
--- 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiWindowsLiveTest.java
+++ 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiWindowsLiveTest.java
@@ -16,24 +16,8 @@
  */
 package org.jclouds.googlecomputeengine.features;
 
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.base.Strings;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.inject.Key;
-import com.google.inject.Module;
-import com.google.inject.TypeLiteral;
-import org.jclouds.encryption.bouncycastle.config.BouncyCastleCryptoModule;
-import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
-import org.jclouds.googlecomputeengine.domain.Image;
-import org.jclouds.googlecomputeengine.domain.Instance;
-import org.jclouds.googlecomputeengine.domain.NewInstance;
-import 
org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest;
-import org.jclouds.googlecomputeengine.options.DiskCreationOptions;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.Test;
+import static 
org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
+import static org.testng.Assert.assertFalse;
 
 import java.net.URI;
 import java.security.NoSuchAlgorithmException;
@@ -44,8 +28,25 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicReference;
 
-import static 
org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
-import static org.testng.Assert.assertFalse;
+import org.jclouds.encryption.bouncycastle.config.BouncyCastleCryptoModule;
+import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
+import org.jclouds.googlecomputeengine.domain.Image;
+import org.jclouds.googlecomputeengine.domain.Instance;
+import org.jclouds.googlecomputeengine.domain.NewInstance;
+import 
org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest;
+import org.jclouds.googlecomputeengine.options.DiskCreationOptions;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.TypeLiteral;
 
 @Test(groups = "live", testName = "InstanceApiWindowsLiveTest")
 public class InstanceApiWindowsLiveTest extends 
BaseGoogleComputeEngineApiLiveTest {
@@ -80,6 +81,7 @@ public class InstanceApiWindowsLiveTest extends 
BaseGoogleComputeEngineApiLiveTe
               INSTANCE_NAME,
               getDefaultMachineTypeUrl(),
               getNetworkUrl(INSTANCE_NETWORK_NAME),
+              null,
               imageUri
       );
 
@@ -102,8 +104,7 @@ public class InstanceApiWindowsLiveTest extends 
BaseGoogleComputeEngineApiLiveTe
    @Test(groups = "live")
    public void testInsertInstanceWindows() {
       // need to insert the network first
-      assertOperationDoneSuccessfully(api.networks().createInIPv4Range
-              (INSTANCE_NETWORK_NAME, IPV4_RANGE));
+      
assertOperationDoneSuccessfully(api.networks().createLegacy(INSTANCE_NETWORK_NAME,
 IPV4_RANGE));
 
       assertOperationDoneSuccessfully(diskApi().create(DISK_NAME,
             new 
DiskCreationOptions.Builder().sizeGb(DEFAULT_DISK_SIZE_GB).build()));

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java
 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java
index 5fac64c..cec92de 100644
--- 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java
+++ 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java
@@ -40,7 +40,7 @@ public class NetworkApiLiveTest extends 
BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live")
    public void testInsertNetwork() {
-      assertOperationDoneSuccessfully(api().createInIPv4Range(NETWORK_NAME, 
IPV4_RANGE));
+      assertOperationDoneSuccessfully(api().createLegacy(NETWORK_NAME, 
IPV4_RANGE));
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertNetwork")

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiMockTest.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiMockTest.java
 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiMockTest.java
index 240ae07..a4b7062 100644
--- 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiMockTest.java
+++ 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiMockTest.java
@@ -44,13 +44,21 @@ public class NetworkApiMockTest extends 
BaseGoogleComputeEngineApiMockTest {
       assertSent(server, "GET", 
"/projects/party/global/networks/jclouds-test");
    }
 
-   public void insert() throws Exception {
+   public void insertLegacy() throws Exception {
       server.enqueue(jsonResponse("/operation.json"));
 
-      assertEquals(networkApi().createInIPv4Range("test-network", 
"10.0.0.0/8"), new ParseOperationTest().expected(url("/projects")));
+      assertEquals(networkApi().createLegacy("test-network", "10.0.0.0/8"), 
new ParseOperationTest().expected(url("/projects")));
       assertSent(server, "POST", "/projects/party/global/networks",
             stringFromResource("/network_insert.json"));
    }
+   
+   public void insertCustom() throws Exception {
+      server.enqueue(jsonResponse("/operation.json"));
+
+      assertEquals(networkApi().createCustom("test-network"), new 
ParseOperationTest().expected(url("/projects")));
+      assertSent(server, "POST", "/projects/party/global/networks",
+            stringFromResource("/network_insert_custom.json"));
+   }
 
    public void delete() throws Exception {
       server.enqueue(jsonResponse("/operation.json"));

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java
 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java
index 8e87712..002a79e 100644
--- 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java
+++ 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java
@@ -43,8 +43,7 @@ public class RouteApiLiveTest extends 
BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live")
    public void testInsertRoute() {
-      assertOperationDoneSuccessfully(api.networks().createInIPv4Range
-              (ROUTE_NETWORK_NAME, IPV4_RANGE));
+      
assertOperationDoneSuccessfully(api.networks().createLegacy(ROUTE_NETWORK_NAME, 
IPV4_RANGE));
       assertOperationDoneSuccessfully(api().createInNetwork(ROUTE_NAME,
               getNetworkUrl(ROUTE_NETWORK_NAME),
               new RouteOptions().addTag("footag")

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SubnetworkApiLiveTest.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SubnetworkApiLiveTest.java
 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SubnetworkApiLiveTest.java
new file mode 100644
index 0000000..c6ced34
--- /dev/null
+++ 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SubnetworkApiLiveTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.googlecomputeengine.features;
+
+import static 
org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.jclouds.googlecloud.domain.ListPage;
+import org.jclouds.googlecomputeengine.domain.Network;
+import org.jclouds.googlecomputeengine.domain.Subnetwork;
+import 
org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest;
+import org.jclouds.googlecomputeengine.options.SubnetworkCreationOptions;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "SubnetworkApiLiveTest")
+public class SubnetworkApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
+
+   private static final String SUBNETWORK_NAME = 
"subnetwork-api-live-test-network";
+   private static final String SUBNETWORK_RANGE = "10.0.0.0/8";
+
+   private SubnetworkApi api() {
+      return api.subnetworksInRegion(DEFAULT_REGION_NAME);
+   }
+
+   @Test
+   public void testInsertSubnetwork() {
+      
assertOperationDoneSuccessfully(api.networks().createCustom(SUBNETWORK_NAME));
+      Network network = api.networks().get(SUBNETWORK_NAME);
+      assertNotNull(network);
+
+      SubnetworkCreationOptions opts = 
SubnetworkCreationOptions.create(SUBNETWORK_NAME, SUBNETWORK_NAME,
+            network.selfLink(), SUBNETWORK_RANGE, getDefaultRegionUrl(), 
false);
+      assertOperationDoneSuccessfully(api().createInNetwork(opts));
+   }
+
+   @Test(dependsOnMethods = "testInsertSubnetwork")
+   public void testGetSubnetwork() {
+      Subnetwork subnet = api().get(SUBNETWORK_NAME);
+      assertNotNull(subnet);
+      assertSubnetworkEquals(subnet);
+   }
+
+   @Test(dependsOnMethods = "testInsertSubnetwork")
+   public void testListSubnetworks() {
+      Iterator<ListPage<Subnetwork>> subnets = api().list(filter("name eq " + 
SUBNETWORK_NAME));
+      List<Subnetwork> subnetsAsList = subnets.next();
+
+      assertEquals(subnetsAsList.size(), 1);
+      assertSubnetworkEquals(subnetsAsList.get(0));
+   }
+
+   @Test(dependsOnMethods = { "testListSubnetworks", "testGetSubnetwork" }, 
alwaysRun = true)
+   public void testDeleteSubnetwork() {
+      assertOperationDoneSuccessfully(api().delete(SUBNETWORK_NAME));
+      assertOperationDoneSuccessfully(api.networks().delete(SUBNETWORK_NAME));
+   }
+
+   private void assertSubnetworkEquals(Subnetwork result) {
+      assertEquals(result.name(), SUBNETWORK_NAME);
+      assertEquals(result.ipCidrRange(), SUBNETWORK_RANGE);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/c83a08a8/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SubnetworkApiMockTest.java
----------------------------------------------------------------------
diff --git 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SubnetworkApiMockTest.java
 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SubnetworkApiMockTest.java
index f99f5d3..4a13680 100644
--- 
a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SubnetworkApiMockTest.java
+++ 
b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SubnetworkApiMockTest.java
@@ -55,7 +55,8 @@ public class SubnetworkApiMockTest extends 
BaseGoogleComputeEngineApiMockTest {
               "my subnetwork",
               URI.create(url("/projects/party/global/networks/mynetwork")),
               "10.0.0.0/24",
-              URI.create(url("/projects/party/regions/someregion")))), new 
ParseOperationTest().expected(url("/projects")));
+              URI.create(url("/projects/party/regions/someregion")),
+              false)), new ParseOperationTest().expected(url("/projects")));
       assertSent(server, "POST", 
"/projects/party/regions/someregion/subnetworks",
             stringFromResource("/subnetwork_insert.json"));
    }

Reply via email to