diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java index 099bfd475..4160327a8 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java @@ -1326,7 +1326,7 @@ public Acl updateDefaultAcl(Acl acl) { * * @throws StorageException upon failure */ - @TransportCompatibility({Transport.HTTP}) + @TransportCompatibility({Transport.HTTP, Transport.GRPC}) public List listDefaultAcls() { return storage.listDefaultAcls(getName()); } diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcStorageImpl.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcStorageImpl.java index 7e8181a15..73e56bbe2 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcStorageImpl.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcStorageImpl.java @@ -907,31 +907,12 @@ public List listAcls(String bucket) { @Override public Acl getDefaultAcl(String bucket, Entity entity) { - // Specify the read-mask to explicitly include defaultObjectAcl - Fields fields = - UnifiedOpts.fields( - ImmutableSet.of( - BucketField.ACL, // workaround for b/261771961 - BucketField.DEFAULT_OBJECT_ACL)); - GrpcCallContext grpcCallContext = GrpcCallContext.createDefault(); - GetBucketRequest req = - fields - .getBucket() - .apply(GetBucketRequest.newBuilder()) - .setName(bucketNameCodec.encode(bucket)) - .build(); try { - com.google.storage.v2.Bucket resp = - Retrying.run( - getOptions(), - retryAlgorithmManager.getFor(req), - () -> storageClient.getBucketCallable().call(req, grpcCallContext), - Decoder.identity()); + com.google.storage.v2.Bucket resp = getBucketDefaultAcls(bucket); Predicate entityPredicate = objectAclEntityOrAltEq(codecs.entity().encode(entity)); - //noinspection DataFlowIssue Optional first = resp.getDefaultObjectAclList().stream().filter(entityPredicate).findFirst(); @@ -965,7 +946,14 @@ public Acl updateDefaultAcl(String bucket, Acl acl) { @Override public List listDefaultAcls(String bucket) { - return throwNotYetImplemented(fmtMethodName("listDefaultAcls", String.class)); + try { + com.google.storage.v2.Bucket resp = getBucketDefaultAcls(bucket); + return resp.getDefaultObjectAclList().stream() + .map(codecs.objectAcl()::decode) + .collect(ImmutableList.toImmutableList()); + } catch (NotFoundException e) { + throw StorageException.coalesce(e); + } } @Override @@ -1430,4 +1418,26 @@ private SourceObject sourceObjectEncode(SourceBlob from) { ifNonNull(from.getGeneration(), to::setGeneration); return to.build(); } + + private com.google.storage.v2.Bucket getBucketDefaultAcls(String bucketName) { + Fields fields = + UnifiedOpts.fields( + ImmutableSet.of( + BucketField.ACL, // workaround for b/261771961 + BucketField.DEFAULT_OBJECT_ACL, + BucketField.METAGENERATION)); + GrpcCallContext grpcCallContext = GrpcCallContext.createDefault(); + GetBucketRequest req = + fields + .getBucket() + .apply(GetBucketRequest.newBuilder()) + .setName(bucketNameCodec.encode(bucketName)) + .build(); + + return Retrying.run( + getOptions(), + retryAlgorithmManager.getFor(req), + () -> storageClient.getBucketCallable().call(req, grpcCallContext), + Decoder.identity()); + } } diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java index 6e4fc2ea6..ad92aae59 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java @@ -3570,7 +3570,7 @@ PostPolicyV4 generateSignedPostPolicyV4( * * @throws StorageException upon failure */ - @TransportCompatibility({Transport.HTTP}) + @TransportCompatibility({Transport.HTTP, Transport.GRPC}) List listDefaultAcls(String bucket); /** diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITAccessTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITAccessTest.java index bc4e8b3b9..7351227dd 100644 --- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITAccessTest.java +++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITAccessTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -29,6 +30,7 @@ import com.google.cloud.Identity; import com.google.cloud.Policy; import com.google.cloud.RetryHelper; +import com.google.cloud.RetryHelper.RetryHelperException; import com.google.cloud.http.BaseHttpServiceException; import com.google.cloud.storage.Acl; import com.google.cloud.storage.Acl.Role; @@ -158,15 +160,38 @@ public void bucket_defaultAcl_get_bucket404() { assertThat(acl).isNull(); } + @Test + public void bucket_defaultAcl_list() { + String bucketName = bucket.getName(); + // lookup an entity from the bucket which is known to exist + Bucket bucketWithAcls = + storage.get( + bucketName, BucketGetOption.fields(BucketField.ACL, BucketField.DEFAULT_OBJECT_ACL)); + + Acl actual = bucketWithAcls.getDefaultAcl().iterator().next(); + + List acls = retry429s(() -> storage.listDefaultAcls(bucketName), storage); + + assertThat(acls).contains(actual); + } + + @Test + public void bucket_defaultAcl_list_bucket404() { + StorageException storageException = + assertThrows( + StorageException.class, + () -> retry429s(() -> storage.listDefaultAcls(bucket.getName() + "x"), storage)); + + assertThat(storageException.getCode()).isEqualTo(404); + } + @Test @CrossRun.Ignore(transports = Transport.GRPC) public void testBucketDefaultAcl() { // TODO: break this test up into each of the respective scenarios - // DONE ~1. get default ACL for specific entity~ // 2. Delete a default ACL for a specific entity // 3. Create a default ACL for specific entity // 4. Update default ACL to change role of a specific entity - // 5. List default ACLs // according to https://cloud.google.com/storage/docs/access-control/lists#default // it can take up to 30 seconds for default acl updates to propagate @@ -976,19 +1001,29 @@ public void testBlobAcl() { } static T retry429s(Callable c, Storage storage) { - return RetryHelper.runWithRetries( - c, - storage.getOptions().getRetrySettings(), - new BasicResultRetryAlgorithm() { - @Override - public boolean shouldRetry(Throwable previousThrowable, Object previousResponse) { - if (previousThrowable instanceof BaseHttpServiceException) { - BaseHttpServiceException httpException = (BaseHttpServiceException) previousThrowable; - return httpException.getCode() == 429; + try { + return RetryHelper.runWithRetries( + c, + storage.getOptions().getRetrySettings(), + new BasicResultRetryAlgorithm() { + @Override + public boolean shouldRetry(Throwable previousThrowable, Object previousResponse) { + if (previousThrowable instanceof BaseHttpServiceException) { + BaseHttpServiceException httpException = + (BaseHttpServiceException) previousThrowable; + return httpException.getCode() == 429; + } + return false; } - return false; - } - }, - storage.getOptions().getClock()); + }, + storage.getOptions().getClock()); + } catch (RetryHelperException e) { + Throwable cause = e.getCause(); + if (cause instanceof RuntimeException) { + throw (RuntimeException) cause; + } else { + throw e; + } + } } }