Skip to content
This repository has been archived by the owner on Dec 3, 2023. It is now read-only.

feat: support setting ServiceOption for quota project #92

Merged
merged 7 commits into from
Dec 13, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ ApiClientHeaderProvider.Builder getInternalHeaderProviderBuilder(
builder.setClientLibToken(
ServiceOptions.getGoogApiClientLibName(),
GaxProperties.getLibraryVersion(serviceOptions.getClass()));
builder.setQuotaProjectIdToken(serviceOptions.getQuotaProjectId());
return builder;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import com.google.api.gax.rpc.NoHeaderProvider;
import com.google.auth.Credentials;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.QuotaProjectIdProvider;
import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.cloud.spi.ServiceRpcFactory;
import com.google.common.base.Preconditions;
Expand Down Expand Up @@ -102,6 +103,7 @@ public abstract class ServiceOptions<
protected Credentials credentials;
private final TransportOptions transportOptions;
private final HeaderProvider headerProvider;
private final String quotaProjectId;

private transient ServiceRpcFactory<OptionsT> serviceRpcFactory;
private transient ServiceFactory<ServiceT, OptionsT> serviceFactory;
Expand Down Expand Up @@ -132,6 +134,7 @@ public abstract static class Builder<
private TransportOptions transportOptions;
private HeaderProvider headerProvider;
private String clientLibToken = ServiceOptions.getGoogApiClientLibName();
private String quotaProjectId;

@InternalApi("This class should only be extended within google-cloud-java")
protected Builder() {}
Expand All @@ -147,6 +150,7 @@ protected Builder(ServiceOptions<ServiceT, OptionsT> options) {
clock = options.clock;
transportOptions = options.transportOptions;
clientLibToken = options.clientLibToken;
quotaProjectId = options.quotaProjectId;
}

protected abstract ServiceOptions<ServiceT, OptionsT> build();
Expand Down Expand Up @@ -212,6 +216,10 @@ public B setCredentials(Credentials credentials) {
if (this.projectId == null && credentials instanceof ServiceAccountCredentials) {
this.projectId = ((ServiceAccountCredentials) credentials).getProjectId();
}

chingor13 marked this conversation as resolved.
Show resolved Hide resolved
if (this.quotaProjectId == null && credentials instanceof QuotaProjectIdProvider) {
this.quotaProjectId = ((ServiceAccountCredentials) credentials).getQuotaProjectId();
}
return self();
}

Expand Down Expand Up @@ -269,6 +277,17 @@ public B setClientLibToken(String clientLibToken) {
return self();
}

/**
* Sets the quotaProjectId that specifies the project used for quota and billing purposes.
*
* @see <a href="https://cloud.google.com/apis/docs/system-parameters">See system parameter
* $userProject</a>
*/
public B setQuotaProjectId(String quotaProjectId) {
this.quotaProjectId = quotaProjectId;
return self();
}

protected Set<String> getAllowedClientLibTokens() {
return allowedClientLibTokens;
}
Expand Down Expand Up @@ -305,6 +324,10 @@ protected ServiceOptions(
firstNonNull(builder.transportOptions, serviceDefaults.getDefaultTransportOptions());
headerProvider = firstNonNull(builder.headerProvider, new NoHeaderProvider());
clientLibToken = builder.clientLibToken;
quotaProjectId =
builder.quotaProjectId != null
? builder.quotaProjectId
: getValueFromCredentialsFile(System.getenv(CREDENTIAL_ENV_NAME), "quota_project_id");
}

/**
Expand Down Expand Up @@ -488,24 +511,24 @@ static boolean headerContainsMetadataFlavor(HttpResponse response) {
}

protected static String getServiceAccountProjectId() {
return getServiceAccountProjectId(System.getenv(CREDENTIAL_ENV_NAME));
return getValueFromCredentialsFile(System.getenv(CREDENTIAL_ENV_NAME), "project_id");
}

@InternalApi("Visible for testing")
static String getServiceAccountProjectId(String credentialsPath) {
String project = null;
static String getValueFromCredentialsFile(String credentialsPath, String key) {
String value = null;
if (credentialsPath != null) {
try (InputStream credentialsStream = new FileInputStream(credentialsPath)) {
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
JsonObjectParser parser = new JsonObjectParser(jsonFactory);
GenericJson fileContents =
parser.parseAndClose(credentialsStream, Charsets.UTF_8, GenericJson.class);
project = (String) fileContents.get("project_id");
value = (String) fileContents.get(key);
} catch (IOException e) {
// ignore
}
}
return project;
return value;
}

/**
Expand Down Expand Up @@ -664,7 +687,8 @@ protected int baseHashCode() {
retrySettings,
serviceFactoryClassName,
serviceRpcFactoryClassName,
clock);
clock,
quotaProjectId);
}

protected boolean baseEquals(ServiceOptions<?, ?> other) {
Expand All @@ -674,7 +698,8 @@ protected boolean baseEquals(ServiceOptions<?, ?> other) {
&& Objects.equals(retrySettings, other.retrySettings)
&& Objects.equals(serviceFactoryClassName, other.serviceFactoryClassName)
&& Objects.equals(serviceRpcFactoryClassName, other.serviceRpcFactoryClassName)
&& Objects.equals(clock, clock);
&& Objects.equals(clock, clock)
&& Objects.equals(quotaProjectId, other.quotaProjectId);
}

private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException {
Expand Down Expand Up @@ -734,4 +759,9 @@ public static <T> T getFromServiceLoader(Class<? extends T> clazz, T defaultInst
public String getClientLibToken() {
return clientLibToken;
}

/** Returns the quotaProjectId that specifies the project used for quota and billing purposes. */
public String getQuotaProjectId() {
return quotaProjectId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ public class ServiceOptionsTest {
+ " \"project_id\": \"someprojectid\",\n"
+ " \"client_email\": \"someclientid@developer.gserviceaccount.com\",\n"
+ " \"client_id\": \"someclientid.apps.googleusercontent.com\",\n"
+ " \"type\": \"service_account\"\n"
+ " \"type\": \"service_account\",\n"
+ " \"quota_project_id\": \"some-quota-project-id\"\n"
codyoss marked this conversation as resolved.
Show resolved Hide resolved
+ "}";
private static GoogleCredentials credentialsWithProjectId;

Expand All @@ -138,6 +139,7 @@ public class ServiceOptionsTest {
.setHost("host")
.setProjectId("project-id")
.setRetrySettings(ServiceOptions.getNoRetrySettings())
.setQuotaProjectId("quota-project-id")
.build();
private static final TestServiceOptions OPTIONS_NO_CREDENTIALS =
TestServiceOptions.newBuilder()
Expand Down Expand Up @@ -281,6 +283,7 @@ public void testBuilder() {
assertSame(CurrentMillisClock.getDefaultClock(), DEFAULT_OPTIONS.getClock());
assertEquals("https://www.googleapis.com", DEFAULT_OPTIONS.getHost());
assertSame(ServiceOptions.getDefaultRetrySettings(), DEFAULT_OPTIONS.getRetrySettings());
assertEquals("quota-project-id", OPTIONS.getQuotaProjectId());
}

@Test
Expand All @@ -293,6 +296,7 @@ public void testBuilderNoCredentials() {
assertEquals("host", OPTIONS_NO_CREDENTIALS.getHost());
assertEquals("project-id", OPTIONS_NO_CREDENTIALS.getProjectId());
assertSame(ServiceOptions.getNoRetrySettings(), OPTIONS_NO_CREDENTIALS.getRetrySettings());
assertEquals("quota-project-id", OPTIONS.getQuotaProjectId());
}

@Test
Expand All @@ -308,6 +312,13 @@ public void testBuilderServiceAccount_setsProjectId() {
assertEquals("someprojectid", options.getProjectId());
}

@Test
public void testBuilderServiceAccount_setsQuotaProjectId() {
TestServiceOptions options =
TestServiceOptions.newBuilder().setCredentials(credentialsWithProjectId).build();
assertEquals("some-quota-project-id", options.getQuotaProjectId());
}

@Test
public void testBuilderServiceAccount_explicitSetProjectIdBefore() {
TestServiceOptions options =
Expand Down Expand Up @@ -372,7 +383,8 @@ public void testGetServiceAccountProjectId() throws Exception {
Files.write("{\"project_id\":\"my-project-id\"}".getBytes(), credentialsFile);

assertEquals(
"my-project-id", ServiceOptions.getServiceAccountProjectId(credentialsFile.getPath()));
"my-project-id",
ServiceOptions.getValueFromCredentialsFile(credentialsFile.getPath(), "project_id"));
}

@Test
Expand All @@ -381,14 +393,14 @@ public void testGetServiceAccountProjectId_badJson() throws Exception {
credentialsFile.deleteOnExit();
Files.write("asdfghj".getBytes(), credentialsFile);

assertNull(ServiceOptions.getServiceAccountProjectId(credentialsFile.getPath()));
assertNull(ServiceOptions.getValueFromCredentialsFile(credentialsFile.getPath(), "project_id"));
}

@Test
public void testGetServiceAccountProjectId_nonExistentFile() throws Exception {
File credentialsFile = new File("/doesnotexist");

assertNull(ServiceOptions.getServiceAccountProjectId(credentialsFile.getPath()));
assertNull(ServiceOptions.getValueFromCredentialsFile(credentialsFile.getPath(), "project_id"));
}

@Test
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,11 @@
<github.global.server>github</github.global.server>
<site.installationModule>google-cloud-core-parent</site.installationModule>

<gax.version>1.51.0</gax.version>
<gax.version>1.52.0</gax.version>
<google.api-common.version>1.8.1</google.api-common.version>
<google.common-protos.version>1.17.0</google.common-protos.version>
<google.iam.version>0.13.0</google.iam.version>
<google.auth.version>0.18.0</google.auth.version>
<google.auth.version>0.19.0</google.auth.version>
<google.api.version>1.30.6</google.api.version>
<google.http.version>1.33.0</google.http.version>
<grpc.version>1.25.0</grpc.version>
Expand Down