Skip to content

gRPC: use of userProject options results in error from gcs when used with credentials which define quota_project_id #1736

@BenWhitehead

Description

@BenWhitehead

Affected version(s): 2.14.0+

Steps to reproduce

  1. Set project via gcloud config set project $projectId

  2. Create adc following instructions from https://google.aip.dev/auth/4113

  3. JUnit tests to repro failure
     import static com.google.common.truth.Truth.assertThat;
     
     import com.google.cloud.storage.Bucket;
     import com.google.cloud.storage.BucketFixture;
     import com.google.cloud.storage.BucketInfo;
     import com.google.cloud.storage.Storage;
     import com.google.cloud.storage.Storage.BucketField;
     import com.google.cloud.storage.Storage.BucketGetOption;
     import com.google.cloud.storage.Storage.BucketSourceOption;
     import com.google.cloud.storage.Storage.BucketTargetOption;
     import com.google.cloud.storage.StorageFixture;
     import com.google.cloud.storage.conformance.retry.CleanupStrategy;
     import org.junit.AfterClass;
     import org.junit.BeforeClass;
     import org.junit.ClassRule;
     import org.junit.Test;
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     import org.slf4j.Marker;
     import org.slf4j.MarkerFactory;
     import org.slf4j.bridge.SLF4JBridgeHandler;
     
     public final class ITRequesterPaysTest {
       static {
         SLF4JBridgeHandler.removeHandlersForRootLogger();
         SLF4JBridgeHandler.install();
       }
       private static final Logger LOGGER = LoggerFactory.getLogger(ITRequesterPaysTest.class);
       private static final Marker TRACE_ENTER = MarkerFactory.getMarker("enter");
       private static final Marker TRACE_EXIT = MarkerFactory.getMarker("exit");
     
       @ClassRule
       public static final StorageFixture sfGadc = StorageFixture.defaultGrpc();
     
       private static final BucketFixture bf =
           BucketFixture.newBuilder()
               .setCleanupStrategy(CleanupStrategy.NEVER)
               .setBucketNameFmtString("java-storage-grpc-%s")
               .setHandle(sfJadc::getInstance)
               .build();
     
       private static final String bucketName = bf.newBucketName();
     
       @BeforeClass
       public static void beforeClass() {
         LOGGER.trace(TRACE_ENTER, "beforeClass()");
         try {
           BucketInfo info1 = BucketInfo.newBuilder(bucketName).setRequesterPays(true).build();
           Bucket bucket = sfJadc.getInstance().create(info1, BucketTargetOption.projection("noAcl"));
           assertThat(bucket.requesterPays()).isTrue();
         } finally {
           LOGGER.trace(TRACE_EXIT, "beforeClass()");
         }
       }
     
       @AfterClass
       public static void afterClass() {
         LOGGER.trace(TRACE_ENTER, "afterClass()");
         try {
           String projectId = sfJadc.getInstance().getOptions().getProjectId();
           sfJadc.getInstance().delete(bucketName, BucketSourceOption.userProject(projectId));
         } finally {
           LOGGER.trace(TRACE_EXIT, "afterClass()");
         }
       }
     
       @Test
       public void grpc_adc() {
         LOGGER.trace(TRACE_ENTER, "grpc_adc()");
         try {
           doTest(sfGadc.getInstance());
         } finally {
           LOGGER.trace(TRACE_EXIT, "grpc_adc()");
         }
       }
     
       private static void doTest(Storage storage) {
         LOGGER.trace(TRACE_ENTER, "doTest(storage : {})", storage);
         try {
           String projectId = storage.getOptions().getProjectId();
           doGet(storage, projectId);
           // doList(storage, projectId);
         } finally {
           LOGGER.trace(TRACE_EXIT, "doTest(storage : {})", storage);
         }
       }
     
       private static void doGet(Storage storage, String projectId) {
         Bucket bucket =
             storage
                 .get(
                     bucketName,
                     BucketGetOption.fields(BucketField.ID, BucketField.BILLING),
                     BucketGetOption.userProject(projectId));
         assertThat(bucket.requesterPays()).isTrue();
       }
     }

Stack trace

com.google.cloud.storage.StorageException: INVALID_ARGUMENT: User project specified in the request is invalid.

	at com.google.cloud.storage.StorageException.asStorageException(StorageException.java:144)
	at com.google.cloud.storage.StorageException.coalesce(StorageException.java:117)
	at com.google.cloud.storage.Retrying.run(Retrying.java:96)
	at com.google.cloud.storage.GrpcStorageImpl.get(GrpcStorageImpl.java:376)
	at com.google.cloud.storage.it.ITObjectTest.unsetRequesterPays(ITObjectTest.java:154)
	at com.google.cloud.storage.it.ITObjectTest.testListBlobRequesterPays(ITObjectTest.java:504)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:299)
	at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:293)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.lang.Thread.run(Thread.java:748)
Caused by: com.google.api.gax.rpc.InvalidArgumentException: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: User project specified in the request is invalid.
	at com.google.api.gax.rpc.ApiExceptionFactory.createException(ApiExceptionFactory.java:92)
	at com.google.api.gax.grpc.GrpcApiExceptionFactory.create(GrpcApiExceptionFactory.java:98)
	at com.google.api.gax.grpc.GrpcApiExceptionFactory.create(GrpcApiExceptionFactory.java:66)
	at com.google.api.gax.grpc.GrpcExceptionCallable$ExceptionTransformingFuture.onFailure(GrpcExceptionCallable.java:97)
	at com.google.api.core.ApiFutures$1.onFailure(ApiFutures.java:67)
	at com.google.common.util.concurrent.Futures$CallbackListener.run(Futures.java:1132)
	at com.google.common.util.concurrent.DirectExecutor.execute(DirectExecutor.java:31)
	at com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1270)
	at com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:1038)
	at com.google.common.util.concurrent.AbstractFuture.setException(AbstractFuture.java:808)
	at io.grpc.stub.ClientCalls$GrpcFuture.setException(ClientCalls.java:574)
	at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:544)
	at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
	at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
	at com.google.api.gax.grpc.ChannelPool$ReleasingClientCall$1.onClose(ChannelPool.java:535)
	at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:563)
	at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:70)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:744)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:723)
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	... 1 more
	Suppressed: com.google.api.gax.rpc.AsyncTaskException: Asynchronous task failed
		at com.google.api.gax.rpc.ApiExceptions.callAndTranslateApiException(ApiExceptions.java:57)
		at com.google.api.gax.rpc.UnaryCallable.call(UnaryCallable.java:100)
		at com.google.cloud.storage.GrpcStorageImpl.lambda$get$2(GrpcStorageImpl.java:379)
		at com.google.api.gax.retrying.DirectRetryingExecutor.submit(DirectRetryingExecutor.java:103)
		at com.google.cloud.RetryHelper.run(RetryHelper.java:76)
		at com.google.cloud.RetryHelper.runWithRetries(RetryHelper.java:50)
		at com.google.cloud.storage.Retrying.run(Retrying.java:93)
		at com.google.cloud.storage.GrpcStorageImpl.get(GrpcStorageImpl.java:376)
		at com.google.cloud.storage.it.ITObjectTest.unsetRequesterPays(ITObjectTest.java:154)
		at com.google.cloud.storage.it.ITObjectTest.testListBlobRequesterPays(ITObjectTest.java:504)
		at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
		at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
		at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
		at java.lang.reflect.Method.invoke(Method.java:498)
		at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
		at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
		at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
		at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
		at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:299)
		at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:293)
		at java.util.concurrent.FutureTask.run(FutureTask.java:266)
		... 1 more
Caused by: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: User project specified in the request is invalid.
	at io.grpc.Status.asRuntimeException(Status.java:535)
	... 14 more

Current Workaround

Decorate default credentials to hide quota_project_id

Storage s = StorageOptions.grpc()
  .setCredentials(new QuotaProjectIdHidingCredentials(GoogleCredentials.getApplicationDefault()))
  .build()
  .getService();

Internal reference bug: b/248605515

Metadata

Metadata

Assignees

No one assigned

    Labels

    api: storageIssues related to the googleapis/java-storage API.priority: p3Desirable enhancement or fix. May not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions