You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ad...@apache.org on 2014/11/10 18:19:42 UTC

[6/6] jclouds-labs-google git commit: * Removed the need for users to manually specify the current project name everywhere. * Documented why we implicitly lookup project name using project id; corrected README, pom, ApiMetadata and added tests. * I

  * Removed the need for users to manually specify the current project name everywhere.
  * Documented why we implicitly lookup project name using project id; corrected README, pom, ApiMetadata and added tests.
  * Introduced jclouds.google-compute-engine.project-name property used to adjust the project commands affect.
  * Flattened quasi-generated pagination classes into package-private members of their callers.
  * Removed invalid fallbacks for lists. List responses are empty; they don't return 4xx!
  * Adjusted test configuration to allow bearer token properly.


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

Branch: refs/heads/master
Commit: 37e0397d9407da694413b5c647b79f9532f10cd1
Parents: 6b5643c
Author: Adrian Cole <ac...@twitter.com>
Authored: Sun Nov 9 12:26:53 2014 -0800
Committer: Adrian Cole <ac...@twitter.com>
Committed: Mon Nov 10 09:19:14 2014 -0800

----------------------------------------------------------------------
 google-compute-engine/README.md                 |  70 ++++++
 google-compute-engine/README.txt                |  63 -----
 google-compute-engine/pom.xml                   |  26 +-
 .../GoogleComputeEngineApi.java                 | 247 +++++++------------
 .../GoogleComputeEngineApiMetadata.java         |  16 +-
 .../GoogleComputeEngineConstants.java           |  41 ---
 .../GoogleComputeEngineFallbacks.java           |  18 --
 .../compute/GoogleComputeEngineService.java     |  11 +-
 .../GoogleComputeEngineServiceAdapter.java      |  25 +-
 ...GoogleComputeEngineServiceContextModule.java |   4 +-
 ...ogleComputeEngineSecurityGroupExtension.java |  36 ++-
 .../functions/CreateNetworkIfNeeded.java        |  15 +-
 .../compute/functions/FindNetworkOrCreate.java  |   9 +-
 .../functions/NetworkToSecurityGroup.java       |  13 +-
 .../compute/functions/Resources.java            |  11 +-
 ...desWithGroupEncodedIntoNameThenAddToSet.java |   8 +-
 .../config/CurrentProject.java                  |  31 +++
 .../GoogleComputeEngineHttpApiModule.java       | 116 ++++++---
 .../config/GoogleComputeEngineProperties.java   |  52 ++++
 .../config/GoogleComputeEngineScopes.java       |  28 +++
 .../googlecomputeengine/config/UserProject.java |  33 ---
 .../googlecomputeengine/domain/NewInstance.java |  22 +-
 .../features/AddressApi.java                    |  55 +++--
 .../features/AggregatedListApi.java             |  71 ++----
 .../googlecomputeengine/features/DiskApi.java   |  53 ++--
 .../features/DiskTypeApi.java                   |  56 +++--
 .../features/FirewallApi.java                   |  54 ++--
 .../features/ForwardingRuleApi.java             |  55 +++--
 .../features/HttpHealthCheckApi.java            |  52 ++--
 .../googlecomputeengine/features/ImageApi.java  | 132 ++++++++--
 .../features/InstanceApi.java                   |  97 ++++----
 .../features/MachineTypeApi.java                |  51 ++--
 .../features/NetworkApi.java                    |  52 ++--
 .../features/OperationApi.java                  | 165 ++++++++-----
 .../features/ProjectApi.java                    |  19 +-
 .../googlecomputeengine/features/RegionApi.java |  55 +++--
 .../googlecomputeengine/features/RouteApi.java  |  52 ++--
 .../features/SnapshotApi.java                   |  52 ++--
 .../features/TargetPoolApi.java                 |  54 ++--
 .../googlecomputeengine/features/ZoneApi.java   |  55 +++--
 .../functions/internal/AdvancingIterator.java   |  48 ----
 .../internal/BaseToIteratorOfListPage.java      |  61 -----
 .../BaseWithRegionToIteratorOfListPage.java     |  67 -----
 .../BaseWithZoneToIteratorOfListPage.java       |  68 -----
 .../functions/internal/PATCH.java               |  35 ---
 .../functions/internal/ParseAddresses.java      |  55 -----
 .../functions/internal/ParseDiskTypes.java      |  55 -----
 .../functions/internal/ParseDisks.java          |  56 -----
 .../functions/internal/ParseFirewalls.java      |  55 -----
 .../internal/ParseForwardingRules.java          |  57 -----
 .../internal/ParseGlobalOperations.java         |  56 -----
 .../internal/ParseHttpHealthChecks.java         |  58 -----
 .../functions/internal/ParseImages.java         |  55 -----
 .../functions/internal/ParseInstances.java      |  56 -----
 .../functions/internal/ParseMachineTypes.java   |  56 -----
 .../functions/internal/ParseNetworks.java       |  55 -----
 .../internal/ParseRegionOperations.java         |  77 ------
 .../functions/internal/ParseRegions.java        |  55 -----
 .../functions/internal/ParseRoutes.java         |  56 -----
 .../functions/internal/ParseSnapshots.java      |  55 -----
 .../functions/internal/ParseTargetPools.java    |  60 -----
 .../functions/internal/ParseZoneOperations.java |  77 ------
 .../functions/internal/ParseZones.java          |  56 -----
 .../internal/AdvancingIterator.java             |  48 ++++
 .../internal/BaseArg0ToIteratorOfListPage.java  |  63 +++++
 .../BaseCallerArg0ToIteratorOfListPage.java     |  63 +++++
 .../internal/BaseToIteratorOfListPage.java      |  54 ++++
 .../googlecomputeengine/internal/ListPages.java |  14 ++
 .../googlecomputeengine/internal/PATCH.java     |  35 +++
 ...eEngineAuthenticatedRestContextLiveTest.java |  10 +-
 .../GoogleComputeEngineServiceLiveTest.java     |  22 +-
 .../GoogleComputeEngineServiceMockTest.java     |  19 +-
 ...uteEngineSecurityGroupExtensionLiveTest.java |   7 +
 .../functions/CreateNetworkIfNeededTest.java    |  20 +-
 .../functions/FindNetworkOrCreateTest.java      |  15 +-
 .../functions/NetworkToSecurityGroupTest.java   |   9 +-
 .../UseApiToResolveProjectNameMockTest.java     |  76 ++++++
 .../features/AddressApiExpectTest.java          |  52 ++--
 .../features/AddressApiLiveTest.java            |   2 +-
 .../features/AggregatedListApiLiveTest.java     |   2 +-
 .../features/AggregatedListApiMockTest.java     |   8 +-
 .../features/DiskApiExpectTest.java             |  62 +++--
 .../features/DiskApiLiveTest.java               |  10 +-
 .../features/DiskTypeApiExpectTest.java         |  27 +-
 .../features/DiskTypeApiLiveTest.java           |   2 +-
 .../features/FirewallApiExpectTest.java         |  54 ++--
 .../features/FirewallApiLiveTest.java           |  14 +-
 .../features/ForwardingRuleApiExpectTest.java   |  54 ++--
 .../features/ForwardingRuleApiLiveTest.java     |   6 +-
 .../features/HttpHealthCheckApiExpectTest.java  |  62 +++--
 .../features/HttpHealthCheckApiLiveTest.java    |   2 +-
 .../features/ImageApiExpectTest.java            | 146 ++++++-----
 .../features/ImageApiLiveTest.java              |  30 +--
 .../features/InstanceApiExpectTest.java         |  73 +++---
 .../features/InstanceApiLiveTest.java           |  20 +-
 .../features/MachineTypeApiExpectTest.java      |  26 +-
 .../features/MachineTypeApiLiveTest.java        |   2 +-
 .../features/NetworkApiExpectTest.java          |  52 ++--
 .../features/NetworkApiLiveTest.java            |   2 +-
 .../features/OperationApiExpectTest.java        | 140 +++++------
 .../features/OperationApiLiveTest.java          |   8 +-
 .../features/ProjectApiExpectTest.java          |  17 +-
 .../features/ProjectApiLiveTest.java            |  71 ++----
 .../features/RegionApiExpectTest.java           |  25 +-
 .../features/RegionApiLiveTest.java             |   2 +-
 .../features/RouteApiExpectTest.java            |  52 ++--
 .../features/RouteApiLiveTest.java              |  12 +-
 .../features/SnapshotApiExpectTest.java         |  28 +--
 .../features/SnapshotApiLiveTest.java           |   4 +-
 .../features/TargetPoolApiExpectTest.java       |  98 ++++----
 .../features/TargetPoolApiLiveTest.java         |  25 +-
 .../features/ZoneApiExpectTest.java             |  25 +-
 .../features/ZoneApiLiveTest.java               |   2 +-
 .../ToIteratorOfListPageExpectTest.java         |  11 +-
 .../BaseGoogleComputeEngineApiLiveTest.java     |  61 ++---
 .../BaseGoogleComputeEngineApiMockTest.java     |  17 +-
 .../BaseGoogleComputeEngineExpectTest.java      |  21 +-
 .../internal/TestProperties.java                |  58 +++++
 .../parse/ParseProjectTest.java                 |   2 +-
 .../test/resources/instance_insert_simple.json  |   2 +-
 .../src/test/resources/list_empty.json          |   5 +
 .../src/test/resources/project.json             |   2 +-
 122 files changed, 2160 insertions(+), 3095 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/README.md
----------------------------------------------------------------------
diff --git a/google-compute-engine/README.md b/google-compute-engine/README.md
new file mode 100644
index 0000000..47ff426
--- /dev/null
+++ b/google-compute-engine/README.md
@@ -0,0 +1,70 @@
+jclouds Google Compute Engine Provider
+======
+
+
+Authenticating into the instances:
+--------
+
+User:
+If no user is provided in GoogleComputeEngineTemplateOptions when launching an instance by default "jclouds" is used.
+
+Credential:
+
+GCE uses exclusively ssh keys to login into instances.
+In order for an instance to be sshable a public key must be installed. Public keys are installed if they are present in the project or instance's metatada.
+
+For an instance to be ssable one of the following must happen:
+1 - the project's metadata has an adequately built "sshKeys" entry and a corresponding private key is provided in GoogleComputeEngineTemplateOptions when createNodesInGroup is called.
+2 - an instance of GoogleComputeEngineTemplateOptions with an adequate public and private key is provided.
+
+NOTE: if methods 2 is chosen the global project keys will not be installed in the instance.
+
+Please refer to Google's documentation on how to form valid project wide ssh keys metadata entries.
+
+FAQ:
+--------
+
+* Q. What is the identity for GCE?
+
+A. the identity is the developer email which can be obtained from the admin GUI. Its usually something in the form: [PROJECT_ID](https://cloud.google.com/compute/docs/overview#projectids)@developer.gserviceaccount.com
+
+* Q. What is the credential for GCE
+
+A. the credential is a private key, in pem format. It can be extracted from the p12 keystore that is obtained when creating a "Service Account" (in the GUI: Google apis console > Api Access > Create another client ID > "Service Account"
+
+* Q. How to convert a p12 keystore into a pem format jclouds Google Compute Engine can handle:
+
+A.
+
+1. Convert the p12 file into pem format (it will ask for the keystore password, which is usually "notasecret"):
+ openssl pkcs12 -in <my_keystore>.p12 -out <my_keystore>.pem -nodes
+
+2. Extract only the pk and remove passphrase
+ openssl rsa -in <my_keystore>.pem -out <my_key>.pem
+
+The last file (<my_key>.pem) should contain the pk that needs to be passed to `ContextBuilder.credential()` for the provider `google-compute-engine`.
+
+
+Running the live tests:
+--------
+
+1. Place the following in your ~/.m2/settings.xml in a profile enabled when live:
+```
+    <test.google-compute-engine.identity>PROJECT_ID@developer.gserviceaccount.com</test.google-compute-engine.identity>
+    <test.google-compute-engine.credential>-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQRRbRqVDtJLN1MO/xJoKqZuphDeBh5jIKueW3aNIiWs1XFcct+h
+-- this text is literally from your <my_key>.pem
+aH7xmpHSTbbXmQkuuv+z8EKijigprd/FoJpTX1f5/R+4wQ==
+-----END RSA PRIVATE KEY-----</test.google-compute-engine.credential>
+  </properties>
+```
+Or, if using an existing OAuth Bearer Token for authentication.
+```
+    <test.google-compute-engine.identity>PROJECT_ID@developer.gserviceaccount.com</test.google-compute-engine.identity>
+    <test.google-compute-engine.credential>EXISTING_BEARER_TOKEN</test.google-compute-engine.credential>
+    <test.jclouds.oauth.credential-type>bearerTokenCredentials</test.jclouds.oauth.credential-type>
+  </properties>
+```
+
+2. mvn clean install -Plive 
+

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/README.txt
----------------------------------------------------------------------
diff --git a/google-compute-engine/README.txt b/google-compute-engine/README.txt
deleted file mode 100644
index 7c23784..0000000
--- a/google-compute-engine/README.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-jclouds Google Compute Engine Provider
-======
-
-
-Authenticating into the instances:
---------
-
-User:
-If no user is provided in GoogleComputeEngineTemplateOptions when launching an instance by default "jclouds" is used.
-
-Credential:
-
-GCE uses exclusively ssh keys to login into instances.
-In order for an instance to be sshable a public key must be installed. Public keys are installed if they are present in the project or instance's metatada.
-
-For an instance to be ssable one of the following must happen:
-1 - the project's metadata has an adequately built "sshKeys" entry and a corresponding private key is provided in GoogleComputeEngineTemplateOptions when createNodesInGroup is called.
-2 - an instance of GoogleComputeEngineTemplateOptions with an adequate public and private key is provided.
-
-NOTE: if methods 2 is chosen the global project keys will not be installed in the instance.
-
-Please refer to Google's documentation on how to form valid project wide ssh keys metadata entries.
-
-FAQ:
---------
-
-* Q. What is the identity for GCE?
-
-A. the identity is the developer email which can be obtained from the admin GUI. Its usually something in the form: <my account id>@developer.gserviceaccount.com
-
-* Q. What is the credential for GCE
-
-A. the credential is a private key, in pem format. It can be extracted from the p12 keystore that is obtained when creating a "Service Account" (in the GUI: Google apis console > Api Access > Create another client ID > "Service Account"
-
-* Q. How to convert a p12 keystore into a pem format jclouds Google Compute Engine can handle:
-
-A.
-
-1. Convert the p12 file into pem format (it will ask for the keystore password, which is usually "notasecret"):
- openssl pkcs12 -in <my_keystore>.p12 -out <my_keystore>.pem -nodes
-
-2. Extract only the pk and remove passphrase
- openssl rsa -in <my_keystore>.pem -out <my_key>.pem
-
-The last file (<my_key>.pem) should contain the pk that needs to be passed to `ContextBuilder.credential()` for the provider `google-compute-engine`.
-
-
-Running the live tests:
---------
-
-1. Place the following in your ~/.m2/settings.xml in a profile enabled when live:
-```
-    <test.google-compute-engine.identity>YOUR_ACCOUNT_NUMBER@developer.gserviceaccount.com</test.google-compute-engine.identity>
-    <test.google-compute-engine.credential>-----BEGIN RSA PRIVATE KEY-----
-MIICXgIBAAKBgQRRbRqVDtJLN1MO/xJoKqZuphDeBh5jIKueW3aNIiWs1XFcct+h
--- this text is literally from your <my_key>.pem
-aH7xmpHSTbbXmQkuuv+z8EKijigprd/FoJpTX1f5/R+4wQ==
------END RSA PRIVATE KEY-----</test.google-compute-engine.credential>
-  </properties>
-```
-
-2. mvn clean install -Plive 
-

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/pom.xml
----------------------------------------------------------------------
diff --git a/google-compute-engine/pom.xml b/google-compute-engine/pom.xml
index 3ca9004..38de821 100644
--- a/google-compute-engine/pom.xml
+++ b/google-compute-engine/pom.xml
@@ -33,10 +33,11 @@
     <description>jclouds components to access GoogleCompute</description>
 
     <properties>
-        <test.google-compute-engine.identity>Email associated with the Google API client_id
-        </test.google-compute-engine.identity>
-        <test.google-compute-engine.credential>Private key (PKCS12 file) associated with the Google API client_id
-        </test.google-compute-engine.credential>
+        <test.google-compute-engine.identity>client_email which usually looks like project_id@developer.gserviceaccount.com</test.google-compute-engine.identity>
+        <test.google-compute-engine.credential>Private key (PEM encoded PKCS12 file or literal) associated with the client_email</test.google-compute-engine.credential>
+        <!-- Add this property to use a different project, or avoid looking up the project for each test. -->
+        <test.jclouds.google-compute-engine.project-name></test.jclouds.google-compute-engine.project-name>
+        <test.jclouds.oauth.credential-type>serviceAccountCredentials</test.jclouds.oauth.credential-type>
         <test.google-compute-engine.api-version>v1</test.google-compute-engine.api-version>
         <test.google-compute-engine.build-version/>
         <test.google-compute-engine.template>imageNameMatches=debian-7-wheezy-v[0-9]*,locationId=us-central1-a,minRam=2048</test.google-compute-engine.template>
@@ -139,17 +140,12 @@
                                 <configuration>
                                     <threadCount>1</threadCount>
                                     <systemPropertyVariables>
-                                        <test.google-compute-engine.identity>${test.google-compute-engine.identity}
-                                        </test.google-compute-engine.identity>
-                                        <test.google-compute-engine.credential>
-                                            ${test.google-compute-engine.credential}
-                                        </test.google-compute-engine.credential>
-                                        <test.google-compute-engine.api-version>
-                                            ${test.google-compute-engine.api-version}
-                                        </test.google-compute-engine.api-version>
-                                        <test.google-compute-engine.build-version>
-                                            ${test.google-compute-engine.build-version}
-                                        </test.google-compute-engine.build-version>
+                                        <test.google-compute-engine.identity>${test.google-compute-engine.identity}</test.google-compute-engine.identity>
+                                        <test.google-compute-engine.credential>${test.google-compute-engine.credential}</test.google-compute-engine.credential>
+                                        <test.jclouds.google-compute-engine.project-name>${test.jclouds.google-compute-engine.project-name}</test.jclouds.google-compute-engine.project-name>
+                                        <test.jclouds.oauth.credential-type>${test.jclouds.oauth.credential-type}</test.jclouds.oauth.credential-type>
+                                        <test.google-compute-engine.api-version>${test.google-compute-engine.api-version}</test.google-compute-engine.api-version>
+                                        <test.google-compute-engine.build-version>${test.google-compute-engine.build-version}</test.google-compute-engine.build-version>
                                         <test.google-compute-engine.template>${test.google-compute-engine.template}</test.google-compute-engine.template>
                                     </systemPropertyVariables>
                                 </configuration>

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java
index 89d465b..4757c9d 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java
@@ -21,6 +21,7 @@ import java.io.Closeable;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 
+import org.jclouds.googlecomputeengine.config.CurrentProject;
 import org.jclouds.googlecomputeengine.features.AddressApi;
 import org.jclouds.googlecomputeengine.features.AggregatedListApi;
 import org.jclouds.googlecomputeengine.features.DiskApi;
@@ -40,171 +41,89 @@ import org.jclouds.googlecomputeengine.features.SnapshotApi;
 import org.jclouds.googlecomputeengine.features.TargetPoolApi;
 import org.jclouds.googlecomputeengine.features.ZoneApi;
 import org.jclouds.rest.annotations.Delegate;
+import org.jclouds.rest.annotations.Endpoint;
 
 public interface GoogleComputeEngineApi extends Closeable {
 
-   /**
-    * Provides access to Address features
-    *
-    * @param projectName the name of the project
-    * @param region      the name of the region scoping this request.
-    */
-   @Delegate
-   @Path("/projects/{project}/regions/{region}")
-   AddressApi getAddressApi(@PathParam("project") String projectName, @PathParam("region") String region);
-
-   /**
-    * Provides access to Aggregated list features
-    *
-    * @param projectName the name of the project
-    */
-   @Delegate
-   @Path("/projects/{project}")
-   AggregatedListApi aggregatedList(@PathParam("project") String projectName);
-
-   /**
-    * Provides access to Disk features
-    *
-    * @param projectName the name of the project
-    * @param zone        the name of the zone scoping this request.
-    */
-   @Delegate
-   @Path("/projects/{project}/zones/{zone}")
-   DiskApi getDiskApi(@PathParam("project") String projectName, @PathParam("zone") String zone);
-
-   /**
-    * Provides access to DiskType features
-    *
-    * @param projectName the name of the project
-    * @param zone        the name of the zone scoping this request.
-    */
-   @Delegate
-   @Path("/projects/{project}/zones/{zone}")
-   DiskTypeApi getDiskTypeApi(@PathParam("project") String projectName, @PathParam("zone") String zone);
-
-   /**
-    * Provides access to Firewall features
-    *
-    * @param projectName the name of the project
-    */
-   @Delegate
-   @Path("/projects/{project}/global")
-   FirewallApi getFirewallApi(@PathParam("project") String projectName);
-
-   /**
-    * Provides access to ForwardingRule features
-    *
-    * @param projectName the name of the project
-    * @param region     the name of the region scoping this request.
-    */
-   @Delegate
-   @Path("/projects/{project}/regions/{region}")
-   ForwardingRuleApi getForwardingRuleApi(@PathParam("project") String projectName, @PathParam("region") String region);
-
-   /**
-    * Provides access to HttpHealthCheck features
-    *
-    * @param projectName the name of the project
-    */
-   @Delegate
-   @Path("/projects/{project}/global")
-   HttpHealthCheckApi getHttpHealthCheckApi(@PathParam("project") String projectName);
-
-   /**
-    * Provides access to Image features
-    *
-    * @param projectName the name of the project
-    */
-   @Delegate
-   @Path("/projects/{project}/global")
-   ImageApi getImageApi(@PathParam("project") String projectName);
-
-   /**
-    * Provides access to Instance features
-    *
-    * @param projectName the name of the project
-    * @param zone zone the instances are in.
-    */
-   @Delegate
-   @Path("/projects/{project}/zones/{zone}")
-   InstanceApi getInstanceApi(@PathParam("project") String projectName, @PathParam("zone") String zone);
-
-   /**
-    * Provides access to MachineType features
-    *
-    * @param projectName the name of the project
-    * @param zone        the name of the zone scoping this request.
-    */
-   @Delegate
-   @Path("/projects/{project}/zones/{zone}")
-   MachineTypeApi getMachineTypeApi(@PathParam("project") String projectName, @PathParam("zone") String zone);
-
-   /**
-    * Provides access to Network features
-    *
-    * @param projectName the name of the project
-    */
-   @Delegate
-   @Path("/projects/{project}/global")
-   NetworkApi getNetworkApi(@PathParam("project") String projectName);
-
-   /**
-    * Provides access to Operation features
-    *
-    * @param projectName the name of the project
-    */
-   @Delegate
-   OperationApi getOperationApi(@PathParam("project") String projectName);
-
-   /**
-    * Provides access to Project features
-    */
-   @Delegate
-   ProjectApi getProjectApi();
-
-   /**
-    * Provides access to Region features
-    *
-    * @param projectName the name of the project
-    */
-   @Delegate
-   @Path("/projects/{project}")
-   RegionApi getRegionApi(@PathParam("project") String projectName);
-
-   /**
-    * Provides access to Route features
-    *
-    * @param projectName the name of the project
-    */
-   @Delegate
-   @Path("/projects/{project}/global")
-   RouteApi getRouteApi(@PathParam("project") String projectName);
-
-   /**
-    * Provides access to Snapshot features
-    *
-    * @param projectName the name of the project
-    */
-   @Delegate
-   @Path("/projects/{project}/global")
-   SnapshotApi getSnapshotApi(@PathParam("project") String projectName);
-
-   /**
-    * Provides access to TargetPool features
-    *
-    * @param projectName the name of the project
-    * @param region     the name of the region scoping this request.
-   */
-   @Delegate
-   @Path("/projects/{project}/regions/{region}")
-   TargetPoolApi getTargetPoolApi(@PathParam("project") String projectName, @PathParam("region") String region);
-
-   /**
-    * Provides access to Zone features
-    *
-    * @param projectName the name of the project
-    */
-   @Delegate
-   @Path("/projects/{project}")
-   ZoneApi getZoneApi(@PathParam("project") String projectName);
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   @Path("/regions/{region}")
+   AddressApi addressesInRegion(@PathParam("region") String region);
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   AggregatedListApi aggregatedList();
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   @Path("/zones/{zone}")
+   DiskApi disksInZone(@PathParam("zone") String zone);
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   @Path("/zones/{zone}")
+   DiskTypeApi diskTypesInZone(@PathParam("zone") String zone);
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   @Path("/global")
+   FirewallApi firewalls();
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   @Path("/regions/{region}")
+   ForwardingRuleApi forwardingRulesInRegion(@PathParam("region") String region);
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   @Path("/global")
+   HttpHealthCheckApi httpHeathChecks();
+
+   @Delegate
+   ImageApi images();
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   @Path("/zones/{zone}")
+   InstanceApi instancesInZone(@PathParam("zone") String zone);
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   @Path("/zones/{zone}")
+   MachineTypeApi machineTypesInZone(@PathParam("zone") String zone);
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   @Path("/global")
+   NetworkApi networks();
+
+   @Delegate
+   OperationApi operations();
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   ProjectApi project();
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   RegionApi regions();
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   @Path("/global")
+   RouteApi routes();
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   @Path("/global")
+   SnapshotApi snapshots();
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   @Path("/regions/{region}")
+   TargetPoolApi targetPoolsInRegion(@PathParam("region") String region);
+
+   @Delegate
+   @Endpoint(CurrentProject.class)
+   ZoneApi zones();
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadata.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadata.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadata.java
index 0c9a23c..32da0eb 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadata.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadata.java
@@ -18,9 +18,10 @@ package org.jclouds.googlecomputeengine;
 
 import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
 import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_IMAGE_PROJECTS;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT;
+import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.IMAGE_PROJECTS;
+import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.OPERATION_COMPLETE_INTERVAL;
+import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.OPERATION_COMPLETE_TIMEOUT;
+import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.PROJECT_NAME;
 import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE;
 import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM;
 import static org.jclouds.reflect.Reflection2.typeToken;
@@ -40,7 +41,6 @@ import com.google.common.collect.ImmutableSet;
 import com.google.inject.Module;
 
 public class GoogleComputeEngineApiMetadata extends BaseHttpApiMetadata<GoogleComputeEngineApi> {
-
    @Override
    public Builder toBuilder() {
       return new Builder().fromApiMetadata(this);
@@ -63,7 +63,8 @@ public class GoogleComputeEngineApiMetadata extends BaseHttpApiMetadata<GoogleCo
       properties.put(OPERATION_COMPLETE_INTERVAL, 500);
       properties.put(OPERATION_COMPLETE_TIMEOUT, 600000);
       properties.put(TEMPLATE, "osFamily=DEBIAN,osVersionMatches=7\\..*,locationId=us-central1-a,loginUser=jclouds");
-      properties.put(GCE_IMAGE_PROJECTS, "centos-cloud,debian-cloud,rhel-cloud,suse-cloud,opensuse-cloud,gce-nvme,coreos-cloud");
+      properties.put(PROJECT_NAME, ""); // Defaulting to empty helps avoid temptation for optional inject!
+      properties.put(IMAGE_PROJECTS, "centos-cloud,debian-cloud,rhel-cloud,suse-cloud,opensuse-cloud,gce-nvme,coreos-cloud");
       return properties;
    }
 
@@ -72,8 +73,9 @@ public class GoogleComputeEngineApiMetadata extends BaseHttpApiMetadata<GoogleCo
       protected Builder() {
          id("google-compute-engine")
            .name("Google Compute Engine Api")
-           .identityName("Email associated with the Google API client_id")
-           .credentialName("Private key literal associated with the Google API client_id")
+           .identityName("client_email which usually looks like project_id@developer.gserviceaccount.com or " //
+                 + "project_id-extended_uid@developer.gserviceaccount.com")
+           .credentialName("PEM encoded P12 private key associated with client_email")
            .documentation(URI.create("https://developers.google.com/compute/docs"))
            .version("v1")
            .defaultEndpoint("https://www.googleapis.com/compute/v1")

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineConstants.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineConstants.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineConstants.java
deleted file mode 100644
index 5bce914..0000000
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineConstants.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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;
-
-import com.google.common.annotations.Beta;
-
-public final class GoogleComputeEngineConstants {
-
-   public static final String COMPUTE_SCOPE = "https://www.googleapis.com/auth/compute";
-
-   public static final String COMPUTE_READONLY_SCOPE = "https://www.googleapis.com/auth/compute.readonly";
-
-   /** The total time, in msecs, to wait for an operation to complete. */
-   @Beta
-   public static final String OPERATION_COMPLETE_TIMEOUT = "jclouds.google-compute-engine.operation-complete-timeout";
-
-   /** The interval, in msecs, between calls to check whether an operation has completed.  */
-   @Beta
-   public static final String OPERATION_COMPLETE_INTERVAL = "jclouds.google-compute-engine.operation-complete-interval";
-
-   /** The list of projects that will be scanned looking for images. */
-   @Beta
-   public static final String GCE_IMAGE_PROJECTS = "jclouds.google-compute-engine.image-projects";
-
-   private GoogleComputeEngineConstants() {
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineFallbacks.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineFallbacks.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineFallbacks.java
index 4ba6eae..105da4d 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineFallbacks.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineFallbacks.java
@@ -20,15 +20,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Predicates.in;
 import static com.google.common.base.Throwables.propagate;
 import static com.google.common.primitives.Ints.asList;
-import static org.jclouds.Fallbacks.valOnNotFoundOr404;
 import static org.jclouds.http.HttpUtils.returnValueOnCodeOrNull;
 
-import java.util.Iterator;
-
 import org.jclouds.Fallback;
-import org.jclouds.googlecomputeengine.domain.ListPage;
-
-import com.google.common.collect.Iterators;
 
 public final class GoogleComputeEngineFallbacks {
    public static class NullOn400or404 implements Fallback<Object> {
@@ -39,16 +33,4 @@ public final class GoogleComputeEngineFallbacks {
          throw propagate(t);
       }
    }
-
-   public static final class EmptyListPageOnNotFoundOr404 implements Fallback<Object> {
-      @Override public ListPage<Object> createOrPropagate(Throwable t) throws Exception {
-         return valOnNotFoundOr404(ListPage.create(null, null), t);
-      }
-   }
-
-   public static final class EmptyIteratorOnNotFoundOr404 implements Fallback<Object> {
-      @Override public Iterator<Object> createOrPropagate(Throwable t) throws Exception {
-         return valOnNotFoundOr404(Iterators.emptyIterator(), t);
-      }
-   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java
index 9abd6e7..cd1816c 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java
@@ -57,7 +57,6 @@ import org.jclouds.domain.Credentials;
 import org.jclouds.domain.Location;
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
 import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions;
-import org.jclouds.googlecomputeengine.config.UserProject;
 import org.jclouds.googlecomputeengine.domain.Firewall;
 import org.jclouds.googlecomputeengine.domain.Network;
 import org.jclouds.googlecomputeengine.domain.Operation;
@@ -76,7 +75,6 @@ public final class GoogleComputeEngineService extends BaseComputeService {
    private final Function<Set<? extends NodeMetadata>, Set<String>> findOrphanedGroups;
    private final GroupNamingConvention.Factory namingConvention;
    private final GoogleComputeEngineApi api;
-   private final Supplier<String> project;
    private final Predicate<AtomicReference<Operation>> operationDone;
 
    @Inject GoogleComputeEngineService(ComputeServiceContext context,
@@ -111,7 +109,6 @@ public final class GoogleComputeEngineService extends BaseComputeService {
                                         Function<Set<? extends NodeMetadata>, Set<String>> findOrphanedGroups,
                                         GroupNamingConvention.Factory namingConvention,
                                         GoogleComputeEngineApi api,
-                                        @UserProject Supplier<String> project,
                                         Predicate<AtomicReference<Operation>> operationDone) {
       super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getImageStrategy,
               getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy,
@@ -121,7 +118,6 @@ public final class GoogleComputeEngineService extends BaseComputeService {
       this.findOrphanedGroups = findOrphanedGroups;
       this.namingConvention = namingConvention;
       this.api = api;
-      this.project = project;
       this.operationDone = operationDone;
    }
 
@@ -135,8 +131,8 @@ public final class GoogleComputeEngineService extends BaseComputeService {
 
    private void cleanUpNetworksAndFirewallsForGroup(final String groupName) {
       String resourceName = namingConvention.create().sharedNameForGroup(groupName);
-      Network network = api.getNetworkApi(project.get()).get(resourceName);
-      FirewallApi firewallApi = api.getFirewallApi(project.get());
+      Network network = api.networks().get(resourceName);
+      FirewallApi firewallApi = api.firewalls();
 
       for (Firewall firewall : concat(firewallApi.list())) {
          if (firewall == null || !firewall.network().equals(network.selfLink())) {
@@ -152,8 +148,7 @@ public final class GoogleComputeEngineService extends BaseComputeService {
          }
       }
 
-      AtomicReference<Operation> operation = Atomics
-            .newReference(api.getNetworkApi(project.get()).delete(resourceName));
+      AtomicReference<Operation> operation = Atomics.newReference(api.networks().delete(resourceName));
 
       operationDone.apply(operation);
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
index 6406c06..7f15ebb 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
@@ -21,7 +21,7 @@ import static com.google.common.base.Preconditions.checkState;
 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.googlecomputeengine.GoogleComputeEngineConstants.GCE_IMAGE_PROJECTS;
+import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.IMAGE_PROJECTS;
 import static org.jclouds.googlecomputeengine.domain.NewInstance.Disk;
 import static org.jclouds.googlecomputeengine.internal.ListPages.concat;
 
@@ -45,7 +45,6 @@ import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
 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.config.UserProject;
 import org.jclouds.googlecomputeengine.domain.Image;
 import org.jclouds.googlecomputeengine.domain.Instance;
 import org.jclouds.googlecomputeengine.domain.MachineType;
@@ -58,7 +57,6 @@ import org.jclouds.location.suppliers.all.JustProvider;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Splitter;
-import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
@@ -82,7 +80,6 @@ public final class GoogleComputeEngineServiceAdapter
 
    private final JustProvider justProvider;
    private final GoogleComputeEngineApi api;
-   private final Supplier<String> userProject;
    private final Resources resources;
    private final Map<URI, URI> diskToSourceImage;
    private final Predicate<AtomicReference<Operation>> operationDone;
@@ -91,16 +88,14 @@ public final class GoogleComputeEngineServiceAdapter
    private final List<String> imageProjects;
 
    @Inject GoogleComputeEngineServiceAdapter(JustProvider justProvider, GoogleComputeEngineApi api,
-                                            @UserProject Supplier<String> userProject,
                                             Predicate<AtomicReference<Operation>> operationDone,
                                             Predicate<AtomicReference<Instance>> instanceVisible,
                                             Map<URI, URI> diskToSourceImage,
                                             Resources resources,
                                             FirewallTagNamingConvention.Factory firewallTagNamingConvention,
-                                            @Named(GCE_IMAGE_PROJECTS) String imageProjects) {
+                                            @Named(IMAGE_PROJECTS) String imageProjects) {
       this.justProvider = justProvider;
       this.api = api;
-      this.userProject = userProject;
       this.operationDone = operationDone;
       this.instanceVisible = instanceVisible;
       this.diskToSourceImage = diskToSourceImage;
@@ -128,8 +123,8 @@ public final class GoogleComputeEngineServiceAdapter
       }
 
       NewInstance newInstance = NewInstance.create(
-            hardware.getUri(), // machineType
             name, // name
+            hardware.getUri(), // machineType
             options.network(), // network
             disks, // disks
             group // description
@@ -150,7 +145,7 @@ public final class GoogleComputeEngineServiceAdapter
       }
 
       String zone = template.getLocation().getId();
-      InstanceApi instanceApi = api.getInstanceApi(userProject.get(), zone);
+      InstanceApi instanceApi = api.instancesInZone(zone);
       Operation create = instanceApi.create(newInstance);
 
       // We need to see the created instance so that we can access the newly created disk.
@@ -179,7 +174,7 @@ public final class GoogleComputeEngineServiceAdapter
    }
 
    @Override public Iterable<MachineType> listHardwareProfiles() {
-      return filter(concat(api.aggregatedList(userProject.get()).machineTypes()), new Predicate<MachineType>() {
+      return filter(concat(api.aggregatedList().machineTypes()), new Predicate<MachineType>() {
          @Override public boolean apply(MachineType input) {
             return input.deprecated() == null;
          }
@@ -189,24 +184,24 @@ public final class GoogleComputeEngineServiceAdapter
    @Override public Iterable<Image> listImages() {
       List<Iterable<Image>> images = newArrayList();
 
-      images.add(concat(api.getImageApi(userProject.get()).list()));
+      images.add(concat(api.images().list()));
 
       for (String project : imageProjects) {
-         images.add(concat(api.getImageApi(project).list()));
+         images.add(concat(api.images().listInProject(project)));
       }
 
       return Iterables.concat(images);
    }
 
    @Override public Image getImage(String selfLink) {
-      return resources.image(URI.create(checkNotNull(selfLink, "id")));
+      return api.images().get(URI.create(checkNotNull(selfLink, "id")));
    }
 
    /**  Unlike EC2, you cannot default GCE instances to a region. Hence, we constrain to zones. */
    @Override public Iterable<Location> listLocations() {
       Location provider = justProvider.get().iterator().next();
       ImmutableList.Builder<Location> zones = ImmutableList.builder();
-      for (Region region : concat(api.getRegionApi(userProject.get()).list())) {
+      for (Region region : concat(api.regions().list())) {
          Location regionLocation = new LocationBuilder()
                .scope(LocationScope.REGION)
                .id(region.name())
@@ -229,7 +224,7 @@ public final class GoogleComputeEngineServiceAdapter
    }
 
    @Override public Iterable<Instance> listNodes() {
-      return concat(api.aggregatedList(userProject.get()).instances());
+      return concat(api.aggregatedList().instances());
    }
 
    @Override public Iterable<Instance> listNodesByIds(final Iterable<String> selfLinks) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java
index 74ce1ae..47d10a9 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java
@@ -20,8 +20,8 @@ import static com.google.common.base.Suppliers.memoizeWithExpiration;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT;
+import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.OPERATION_COMPLETE_INTERVAL;
+import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.OPERATION_COMPLETE_TIMEOUT;
 import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
 import static org.jclouds.util.Predicates2.retry;
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java
index 01892eb..f98c894 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java
@@ -19,11 +19,11 @@ package org.jclouds.googlecomputeengine.compute.extensions;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT;
 import static org.jclouds.googlecomputeengine.compute.predicates.NetworkFirewallPredicates.equalsIpPermission;
 import static org.jclouds.googlecomputeengine.compute.predicates.NetworkFirewallPredicates.providesIpPermission;
 import static org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet.DEFAULT_INTERNAL_NETWORK_RANGE;
+import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.OPERATION_COMPLETE_INTERVAL;
+import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.OPERATION_COMPLETE_TIMEOUT;
 import static org.jclouds.googlecomputeengine.internal.ListPages.concat;
 import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
 import static org.jclouds.util.Predicates2.retry;
@@ -44,7 +44,6 @@ import org.jclouds.domain.Location;
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
 import org.jclouds.googlecomputeengine.compute.domain.NetworkAndAddressRange;
 import org.jclouds.googlecomputeengine.compute.functions.Resources;
-import org.jclouds.googlecomputeengine.config.UserProject;
 import org.jclouds.googlecomputeengine.domain.Firewall;
 import org.jclouds.googlecomputeengine.domain.Instance;
 import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface;
@@ -58,7 +57,6 @@ import org.jclouds.net.domain.IpProtocol;
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
-import com.google.common.base.Supplier;
 import com.google.common.cache.LoadingCache;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableSet;
@@ -72,7 +70,6 @@ public final class GoogleComputeEngineSecurityGroupExtension implements Security
 
    private final GoogleComputeEngineApi api;
    private final Resources resources;
-   private final Supplier<String> userProject;
    private final GroupNamingConvention.Factory namingConvention;
    private final LoadingCache<NetworkAndAddressRange, Network> networkCreator;
    private final Function<Network, SecurityGroup> groupConverter;
@@ -81,14 +78,13 @@ public final class GoogleComputeEngineSecurityGroupExtension implements Security
    private final long operationCompleteCheckTimeout;
 
    @Inject GoogleComputeEngineSecurityGroupExtension(GoogleComputeEngineApi api, Resources resources,
-         @UserProject Supplier<String> userProject, GroupNamingConvention.Factory namingConvention,
+         GroupNamingConvention.Factory namingConvention,
          LoadingCache<NetworkAndAddressRange, Network> networkCreator, Function<Network, SecurityGroup> groupConverter,
          Predicate<AtomicReference<Operation>> operationDone,
          @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval,
          @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout) {
       this.api = api;
       this.resources = resources;
-      this.userProject = userProject;
       this.namingConvention = namingConvention;
       this.networkCreator = networkCreator;
       this.groupConverter = groupConverter;
@@ -99,7 +95,7 @@ public final class GoogleComputeEngineSecurityGroupExtension implements Security
 
    @Override
    public Set<SecurityGroup> listSecurityGroups() {
-      return FluentIterable.from(concat(api.getNetworkApi(userProject.get()).list())).transform(groupConverter).toSet();
+      return FluentIterable.from(concat(api.networks().list())).transform(groupConverter).toSet();
    }
 
    @Override
@@ -132,7 +128,7 @@ public final class GoogleComputeEngineSecurityGroupExtension implements Security
    @Override
    public SecurityGroup getSecurityGroupById(String id) {
       checkNotNull(id, "id");
-      Network network = api.getNetworkApi(userProject.get()).get(id);
+      Network network = api.networks().get(id);
 
       if (network == null) {
          return null;
@@ -159,17 +155,17 @@ public final class GoogleComputeEngineSecurityGroupExtension implements Security
    @Override
    public boolean removeSecurityGroup(String id) {
       checkNotNull(id, "id");
-      if (api.getNetworkApi(userProject.get()).get(id) == null) {
+      if (api.networks().get(id) == null) {
          return false;
       }
 
       ListOptions options = filter("network eq .*/" + id);
 
-      FluentIterable<Firewall> fws = FluentIterable.from(concat(api.getFirewallApi(userProject.get()).list(options)));
+      FluentIterable<Firewall> fws = FluentIterable.from(concat(api.firewalls().list(options)));
 
       for (Firewall fw : fws) {
          AtomicReference<Operation> operation = Atomics
-               .newReference(api.getFirewallApi(userProject.get()).delete(fw.name()));
+               .newReference(api.firewalls().delete(fw.name()));
 
          retry(operationDone, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
                .apply(operation);
@@ -178,7 +174,7 @@ public final class GoogleComputeEngineSecurityGroupExtension implements Security
                "Could not delete firewall, operation failed" + operation);
       }
 
-      AtomicReference<Operation> operation = Atomics.newReference(api.getNetworkApi(userProject.get()).delete(id));
+      AtomicReference<Operation> operation = Atomics.newReference(api.networks().delete(id));
 
       retry(operationDone, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
             .apply(operation);
@@ -194,12 +190,12 @@ public final class GoogleComputeEngineSecurityGroupExtension implements Security
       checkNotNull(group, "group");
       checkNotNull(ipPermission, "ipPermission");
 
-      checkNotNull(api.getNetworkApi(userProject.get()).get(group.getId()) == null, "network for group is null");
+      checkNotNull(api.networks().get(group.getId()) == null, "network for group is null");
 
       ListOptions options = filter("network eq .*/" + group.getName());
 
       if (Iterables
-            .any(concat(api.getFirewallApi(userProject.get()).list(options)), providesIpPermission(ipPermission))) {
+            .any(concat(api.firewalls().list(options)), providesIpPermission(ipPermission))) {
          // Permission already exists.
          return group;
       }
@@ -225,7 +221,7 @@ public final class GoogleComputeEngineSecurityGroupExtension implements Security
       fwOptions.addAllowedRule(Firewall.Rule.create(ipPermission.getIpProtocol().value().toLowerCase(), ports));
 
       AtomicReference<Operation> operation = Atomics.newReference(
-            api.getFirewallApi(userProject.get()).createInNetwork(uniqueFwName, group.getUri(), fwOptions));
+            api.firewalls().createInNetwork(uniqueFwName, group.getUri(), fwOptions));
 
       retry(operationDone, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
             .apply(operation);
@@ -255,16 +251,16 @@ public final class GoogleComputeEngineSecurityGroupExtension implements Security
       checkNotNull(group, "group");
       checkNotNull(ipPermission, "ipPermission");
 
-      checkNotNull(api.getNetworkApi(userProject.get()).get(group.getId()) == null, "network for group is null");
+      checkNotNull(api.networks().get(group.getId()) == null, "network for group is null");
 
       ListOptions options = filter("network eq .*/" + group.getName());
 
-      FluentIterable<Firewall> fws = FluentIterable.from(concat(api.getFirewallApi(userProject.get()).list(options)));
+      FluentIterable<Firewall> fws = FluentIterable.from(concat(api.firewalls().list(options)));
 
       for (Firewall fw : fws) {
          if (equalsIpPermission(ipPermission).apply(fw)) {
             AtomicReference<Operation> operation = Atomics
-                  .newReference(api.getFirewallApi(userProject.get()).delete(fw.name()));
+                  .newReference(api.firewalls().delete(fw.name()));
 
             retry(operationDone, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
                   .apply(operation);
@@ -320,7 +316,7 @@ public final class GoogleComputeEngineSecurityGroupExtension implements Security
 
    private SecurityGroup groupForTagsInNetwork(Network nw, final Collection<String> tags) {
       ListOptions opts = filter("network eq .*/" + nw.name());
-      List<Firewall> fws = FluentIterable.from(concat(api.getFirewallApi(userProject.get()).list(opts)))
+      List<Firewall> fws = FluentIterable.from(concat(api.firewalls().list(opts)))
             .filter(new Predicate<Firewall>() {
                @Override public boolean apply(final Firewall input) {
                   // If any of the targetTags on the firewall apply or the firewall has no target tags...

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeeded.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeeded.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeeded.java
index 338b731..7030c75 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeeded.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeeded.java
@@ -25,24 +25,19 @@ import javax.inject.Inject;
 
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
 import org.jclouds.googlecomputeengine.compute.domain.NetworkAndAddressRange;
-import org.jclouds.googlecomputeengine.config.UserProject;
 import org.jclouds.googlecomputeengine.domain.Network;
 import org.jclouds.googlecomputeengine.domain.Operation;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
 import com.google.common.util.concurrent.Atomics;
 
 public final class CreateNetworkIfNeeded implements Function<NetworkAndAddressRange, Network> {
    private final GoogleComputeEngineApi api;
-   private final Supplier<String> userProject;
    private final Predicate<AtomicReference<Operation>> operationDone;
 
-   @Inject CreateNetworkIfNeeded(GoogleComputeEngineApi api, @UserProject Supplier<String> userProject,
-         Predicate<AtomicReference<Operation>> operationDone) {
+   @Inject CreateNetworkIfNeeded(GoogleComputeEngineApi api, Predicate<AtomicReference<Operation>> operationDone) {
       this.api = api;
-      this.userProject = userProject;
       this.operationDone = operationDone;
    }
 
@@ -50,13 +45,13 @@ public final class CreateNetworkIfNeeded implements Function<NetworkAndAddressRa
    public Network apply(NetworkAndAddressRange input) {
       checkNotNull(input, "input");
 
-      Network nw = api.getNetworkApi(userProject.get()).get(input.name());
+      Network nw = api.networks().get(input.name());
       if (nw != null) {
          return nw;
       }
 
       if (input.gateway() != null) {
-         AtomicReference<Operation> operation = Atomics.newReference(api.getNetworkApi(userProject.get())
+         AtomicReference<Operation> operation = Atomics.newReference(api.networks()
                .createInIPv4RangeWithGateway(input.name(), input.rangeIPv4(), input.gateway()));
          operationDone.apply(operation);
 
@@ -64,13 +59,13 @@ public final class CreateNetworkIfNeeded implements Function<NetworkAndAddressRa
                "Could not insert network, operation failed" + operation);
       } else {
          AtomicReference<Operation> operation = Atomics
-               .newReference(api.getNetworkApi(userProject.get()).createInIPv4Range(input.name(), input.rangeIPv4()));
+               .newReference(api.networks().createInIPv4Range(input.name(), input.rangeIPv4()));
          operationDone.apply(operation);
 
          checkState(operation.get().httpErrorStatusCode() == null,
                "Could not insert network, operation failed" + operation);
       }
-      return checkNotNull(api.getNetworkApi(userProject.get()).get(input.name()), "no network with name %s was found",
+      return checkNotNull(api.networks().get(input.name()), "no network with name %s was found",
             input.name());
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FindNetworkOrCreate.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FindNetworkOrCreate.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FindNetworkOrCreate.java
index 2f4c7a4..1137ef9 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FindNetworkOrCreate.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FindNetworkOrCreate.java
@@ -20,27 +20,22 @@ import javax.inject.Inject;
 
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
 import org.jclouds.googlecomputeengine.compute.domain.NetworkAndAddressRange;
-import org.jclouds.googlecomputeengine.config.UserProject;
 import org.jclouds.googlecomputeengine.domain.Network;
 
 import com.google.common.base.Function;
-import com.google.common.base.Supplier;
 import com.google.common.cache.CacheLoader;
 
 public final class FindNetworkOrCreate extends CacheLoader<NetworkAndAddressRange, Network> {
    private final GoogleComputeEngineApi api;
    private final Function<NetworkAndAddressRange, Network> networkCreator;
-   private final Supplier<String> userProject;
 
-   @Inject FindNetworkOrCreate(GoogleComputeEngineApi api, Function<NetworkAndAddressRange, Network> networkCreator,
-         @UserProject Supplier<String> userProject) {
+   @Inject FindNetworkOrCreate(GoogleComputeEngineApi api, Function<NetworkAndAddressRange, Network> networkCreator) {
       this.api = api;
       this.networkCreator = networkCreator;
-      this.userProject = userProject;
    }
 
    @Override public Network load(NetworkAndAddressRange in) {
-      Network network = api.getNetworkApi(userProject.get()).get(in.name());
+      Network network = api.networks().get(in.name());
       if (network != null) {
          return network;
       } else {

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroup.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroup.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroup.java
index 1bd4811..8306f8b 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroup.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroup.java
@@ -24,32 +24,23 @@ import javax.inject.Inject;
 import org.jclouds.compute.domain.SecurityGroup;
 import org.jclouds.compute.domain.SecurityGroupBuilder;
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
-import org.jclouds.googlecomputeengine.config.UserProject;
 import org.jclouds.googlecomputeengine.domain.Firewall;
 import org.jclouds.googlecomputeengine.domain.Network;
 import org.jclouds.googlecomputeengine.options.ListOptions;
 import org.jclouds.net.domain.IpPermission;
 
 import com.google.common.base.Function;
-import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
 
-/**
- * A function for transforming a GCE-specific Network into a generic
- * SecurityGroup object.
- */
 public final class NetworkToSecurityGroup implements Function<Network, SecurityGroup> {
 
    private final Function<Firewall, Iterable<IpPermission>> firewallToPerms;
    private final GoogleComputeEngineApi api;
-   private final Supplier<String> project;
 
    @Inject NetworkToSecurityGroup(Function<Firewall, Iterable<IpPermission>> firewallToPerms,
-                                 GoogleComputeEngineApi api,
-                                 @UserProject Supplier<String> project) {
+         GoogleComputeEngineApi api) {
       this.firewallToPerms = firewallToPerms;
       this.api = api;
-      this.project = project;
    }
 
    @Override public SecurityGroup apply(Network network)  {
@@ -64,7 +55,7 @@ public final class NetworkToSecurityGroup implements Function<Network, SecurityG
 
       ListOptions options = filter("network eq .*/" + network.name());
 
-      for (Firewall fw : concat(api.getFirewallApi(project.get()).list(options))) {
+      for (Firewall fw : concat(api.firewalls().list(options))) {
          permBuilder.addAll(firewallToPerms.apply(fw));
       }
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/Resources.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/Resources.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/Resources.java
index 34d7d54..34ddd50 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/Resources.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/Resources.java
@@ -18,8 +18,8 @@ package org.jclouds.googlecomputeengine.compute.functions;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 import static org.jclouds.Fallbacks.NullOnNotFoundOr404;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE;
+import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineScopes.COMPUTE_READONLY_SCOPE;
+import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineScopes.COMPUTE_SCOPE;
 
 import java.net.URI;
 
@@ -30,7 +30,6 @@ import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 
-import org.jclouds.googlecomputeengine.domain.Image;
 import org.jclouds.googlecomputeengine.domain.Instance;
 import org.jclouds.googlecomputeengine.domain.Network;
 import org.jclouds.googlecomputeengine.domain.Operation;
@@ -47,12 +46,6 @@ import org.jclouds.rest.annotations.SkipEncoding;
 @Consumes(APPLICATION_JSON)
 public interface Resources {
 
-   /** Returns an image by self-link or null if not found. */
-   @Named("Images:get")
-   @GET
-   @OAuthScopes(COMPUTE_READONLY_SCOPE)
-   @Fallback(NullOnNotFoundOr404.class) @Nullable Image image(@EndpointParam URI selfLink);
-
    /** Returns an instance by self-link or null if not found. */
    @Named("Instances:get")
    @GET

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
index 3900c46..8c889d2 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
@@ -41,7 +41,6 @@ import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
 import org.jclouds.googlecomputeengine.compute.domain.NetworkAndAddressRange;
 import org.jclouds.googlecomputeengine.compute.functions.FirewallTagNamingConvention;
 import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions;
-import org.jclouds.googlecomputeengine.config.UserProject;
 import org.jclouds.googlecomputeengine.domain.Firewall;
 import org.jclouds.googlecomputeengine.domain.Firewall.Rule;
 import org.jclouds.googlecomputeengine.domain.Network;
@@ -50,7 +49,6 @@ import org.jclouds.googlecomputeengine.features.FirewallApi;
 import org.jclouds.googlecomputeengine.options.FirewallOptions;
 
 import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
 import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -66,7 +64,6 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
    public static final String DEFAULT_INTERNAL_NETWORK_RANGE = "10.0.0.0/8";
 
    private final GoogleComputeEngineApi api;
-   private final Supplier<String> userProject;
    private final LoadingCache<NetworkAndAddressRange, Network> networkMap;
    private final Predicate<AtomicReference<Operation>> operationDone;
    private final FirewallTagNamingConvention.Factory firewallTagNamingConvention;
@@ -80,14 +77,12 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
            CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory
                    customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
            GoogleComputeEngineApi api,
-           @UserProject Supplier<String> userProject,
            Predicate<AtomicReference<Operation>> operationDone,
            LoadingCache<NetworkAndAddressRange, Network> networkMap,
            FirewallTagNamingConvention.Factory firewallTagNamingConvention) {
       super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor,
               customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
       this.api = api;
-      this.userProject = userProject;
       this.operationDone = operationDone;
       this.networkMap = networkMap;
       this.firewallTagNamingConvention = firewallTagNamingConvention;
@@ -134,8 +129,7 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
    private void getOrCreateFirewalls(GoogleComputeEngineTemplateOptions templateOptions, Network network,
                                      FirewallTagNamingConvention naming) {
 
-      String projectName = userProject.get();
-      FirewallApi firewallApi = api.getFirewallApi(projectName);
+      FirewallApi firewallApi = api.firewalls();
       List<AtomicReference<Operation>> operations = Lists.newArrayList();
 
       for (Integer port : templateOptions.getInboundPorts()) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/CurrentProject.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/CurrentProject.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/CurrentProject.java
new file mode 100644
index 0000000..52d1817
--- /dev/null
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/CurrentProject.java
@@ -0,0 +1,31 @@
+/*
+ * 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.config;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+/** Associated bindings with the current <a href="https://cloud.google.com/compute/docs/projects">project</a>. */
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
+@Qualifier
+public @interface CurrentProject {
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
index 4b14d7a..d37c162 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
@@ -16,32 +16,51 @@
  */
 package org.jclouds.googlecomputeengine.config;
 
+import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Suppliers.compose;
 import static java.util.concurrent.TimeUnit.SECONDS;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
+import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.PROJECT_NAME;
+import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineScopes.COMPUTE_READONLY_SCOPE;
+import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
 
+import java.net.URI;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
+import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
 
 import org.jclouds.domain.Credentials;
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
+import org.jclouds.googlecomputeengine.domain.Project;
 import org.jclouds.googlecomputeengine.handlers.GoogleComputeEngineErrorHandler;
 import org.jclouds.http.HttpErrorHandler;
 import org.jclouds.http.annotation.ClientError;
 import org.jclouds.http.annotation.Redirection;
 import org.jclouds.http.annotation.ServerError;
 import org.jclouds.location.Provider;
+import org.jclouds.oauth.v2.config.OAuthScopes;
+import org.jclouds.oauth.v2.filters.OAuthAuthenticationFilter;
+import org.jclouds.providers.ProviderMetadata;
 import org.jclouds.rest.AuthorizationException;
 import org.jclouds.rest.ConfiguresHttpApi;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SkipEncoding;
 import org.jclouds.rest.config.HttpApiModule;
 import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
 
 import com.google.common.base.Function;
-import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
 import com.google.common.base.Supplier;
-import com.google.common.collect.Iterables;
+import com.google.common.base.Suppliers;
 import com.google.inject.Provides;
 
 @ConfiguresHttpApi
@@ -49,40 +68,79 @@ public final class GoogleComputeEngineHttpApiModule extends HttpApiModule<Google
    public GoogleComputeEngineHttpApiModule() {
    }
 
+   @Override protected void configure() {
+      super.configure();
+      bindHttpApi(binder(), UseApiToResolveProjectName.GetProject.class);
+   }
+
    @Override protected void bindErrorHandlers() {
       bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(GoogleComputeEngineErrorHandler.class);
       bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(GoogleComputeEngineErrorHandler.class);
       bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(GoogleComputeEngineErrorHandler.class);
    }
 
+   @Provides @Singleton @CurrentProject Supplier<URI> project(@Named(PROJECT_NAME) final String projectName,
+         @Provider Supplier<URI> defaultEndpoint, final UseApiToResolveProjectName useApiToResolveProjectName,
+         @Provider final Supplier<Credentials> creds, AtomicReference<AuthorizationException> authException,
+         @Named(PROPERTY_SESSION_INTERVAL) long seconds) {
+      // Try to avoid a runtime lookup by accepting a project name supplied in context overrides.
+      if (Strings.emptyToNull(projectName) != null) {
+         return Suppliers.memoizeWithExpiration(Suppliers.compose(new Function<URI, URI>() {
+            @Override public URI apply(URI input) {
+               return URI.create(String.format("%s/projects/%s", input, projectName));
+            }
+         }, defaultEndpoint), seconds, SECONDS);
+      }
+
+      // If the project name wasn't explicitly supplied, then we lookup via api.
+      // This supplier must be defensive against any auth exception.
+      return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier
+            .create(authException, compose(useApiToResolveProjectName, creds), seconds, SECONDS);
+   }
+
    /**
-    * Since this is caching a direct api call, we memoize, but short-circuit on any auth exception. This prevents
-    * excessive errors when things occur in parallel, or as peers on a function graph.
+    * Parse the project ID from the identity, use it to lookup the project name, return the project-scoped uri.
+    *
+    * <h3>Why are we looking up the project name? We already have the project ID!</h3>
+    * <a href="https://cloud.google.com/compute/docs/overview#projectids">Documentation</a> suggests that the
+    * project name is interchangeable with the project ID, which we already have. However, in practice, using the
+    * project ID leads to problems in POST requests.
+    *
+    * <p/> For example, inserting an instance using the project ID in the instances url, but the project name in
+    * the machineType url results in an error of
+    * <pre>{@code Cross-project references for this resource type are not allowed}.</pre>
+    *
+    * <p/>Similar errors occur in POST requests to other resources including at least forwardingRules, images,
+    * targetPools.
     */
-   @Provides
-   @Singleton
-   @UserProject Supplier<String> projectName(@Provider final Supplier<Credentials> creds,
-                                             final GoogleComputeEngineApi api,
-                                             AtomicReference<AuthorizationException> authException,
-                                             @Named(PROPERTY_SESSION_INTERVAL) long seconds) {
-      return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException,
-              compose(new Function<Credentials, String>() {
-                 public String apply(Credentials in) {
-                    // ID should be of the form project_id@developer.gserviceaccount.com 
-                    // OR (increasingly often) project_id-extended_uid@developer.gserviceaccount.com
-                    // where project_id is the NUMBER;
-                    // HERE we also accept simply "project" as the identity, if no "@" is present;
-                    // this is used in tests, but not sure if it is valid in the wild.
-                    String projectName = in.identity;
-                    if (projectName.indexOf("@") != -1) {
-                       projectName = Iterables.get(Splitter.on("@").split(projectName), 0);
-                       if (projectName.indexOf("-") != -1) {
-                          // if ID is of the form project_id-extended_uid@developer.gserviceaccount.com
-                          projectName = Iterables.get(Splitter.on("-").split(projectName), 0);
-                       }
-                    }
-                    return api.getProjectApi().get(projectName).name();
-                 }
-              }, creds), seconds, SECONDS);
+   static final class UseApiToResolveProjectName implements Function<Credentials, URI> {
+      public static final Pattern PROJECT_NUMBER_PATTERN = Pattern.compile("^([0-9]+)[@-].*");
+
+      @SkipEncoding({ '/', '=' })
+      @RequestFilters(OAuthAuthenticationFilter.class)
+      @OAuthScopes(COMPUTE_READONLY_SCOPE)
+      @Consumes(APPLICATION_JSON)
+      interface GetProject {
+         @Named("Projects:get")
+         @GET
+         @Path("/projects/{projectNumber}") Project get(@PathParam("projectNumber") String projectNumber);
+      }
+
+      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) {
+         Matcher matcher = PROJECT_NUMBER_PATTERN.matcher(in.identity);
+         checkArgument(matcher.find(), "Identity %s is malformed. Should be %s", in.identity, identityName);
+         return URI.create(defaultEndpoint.get() + "/projects/" + api.get(matcher.group(1)).name());
+      }
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineProperties.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineProperties.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineProperties.java
new file mode 100644
index 0000000..4f2be3d
--- /dev/null
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineProperties.java
@@ -0,0 +1,52 @@
+/*
+ * 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.config;
+
+import org.jclouds.oauth.v2.config.OAuthProperties;
+
+import com.google.common.annotations.Beta;
+
+/** Configuration properties keys used in {@link org.jclouds.ContextBuilder#overrides(java.util.Properties)}. */
+public final class GoogleComputeEngineProperties {
+
+   /**
+    * How requests are authorized using OAuth. Defaults to {@link org.jclouds.oauth.v2.config.CredentialType#SERVICE_ACCOUNT_CREDENTIALS}.
+    *
+    * @see org.jclouds.oauth.v2.config.CredentialType
+    */
+   public static final String CREDENTIAL_TYPE = OAuthProperties.CREDENTIAL_TYPE;
+
+   /**
+    * Set this property to specify the <a href="https://cloud.google.com/compute/docs/projects">project name</a> this
+    * context applies to.
+    * <p/> This is an alternative to looking up the project name at runtime.
+    */
+   public static final String PROJECT_NAME = "jclouds.google-compute-engine.project-name";
+
+   /** The total time, in msecs, to wait for an operation to complete. */
+   @Beta
+   public static final String OPERATION_COMPLETE_TIMEOUT = "jclouds.google-compute-engine.operation-complete-timeout";
+   /** The interval, in msecs, between calls to check whether an operation has completed. */
+   @Beta
+   public static final String OPERATION_COMPLETE_INTERVAL = "jclouds.google-compute-engine.operation-complete-interval";
+   /** The list of projects that will be scanned looking for images. */
+   @Beta
+   public static final String IMAGE_PROJECTS = "jclouds.google-compute-engine.image-projects";
+
+   private GoogleComputeEngineProperties() {
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/37e0397d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineScopes.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineScopes.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineScopes.java
new file mode 100644
index 0000000..7f5eaae
--- /dev/null
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineScopes.java
@@ -0,0 +1,28 @@
+/*
+ * 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.config;
+
+/** OAuth scopes needed for requests. */
+public final class GoogleComputeEngineScopes {
+
+   public static final String COMPUTE_SCOPE = "https://www.googleapis.com/auth/compute";
+
+   public static final String COMPUTE_READONLY_SCOPE = "https://www.googleapis.com/auth/compute.readonly";
+
+   private GoogleComputeEngineScopes() {
+   }
+}