Skip to content

Commit

Permalink
feat: implement GrpcStorageImpl#listDefaultAcl (#1805)
Browse files Browse the repository at this point in the history
  • Loading branch information
BenWhitehead committed Dec 13, 2022
1 parent f113d15 commit 03c2e66
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 38 deletions.
Expand Up @@ -1326,7 +1326,7 @@ public Acl updateDefaultAcl(Acl acl) {
*
* @throws StorageException upon failure
*/
@TransportCompatibility({Transport.HTTP})
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
public List<Acl> listDefaultAcls() {
return storage.listDefaultAcls(getName());
}
Expand Down
Expand Up @@ -907,31 +907,12 @@ public List<Acl> 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<ObjectAccessControl> entityPredicate =
objectAclEntityOrAltEq(codecs.entity().encode(entity));

//noinspection DataFlowIssue
Optional<ObjectAccessControl> first =
resp.getDefaultObjectAclList().stream().filter(entityPredicate).findFirst();

Expand Down Expand Up @@ -965,7 +946,14 @@ public Acl updateDefaultAcl(String bucket, Acl acl) {

@Override
public List<Acl> 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
Expand Down Expand Up @@ -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());
}
}
Expand Up @@ -3570,7 +3570,7 @@ PostPolicyV4 generateSignedPostPolicyV4(
*
* @throws StorageException upon failure
*/
@TransportCompatibility({Transport.HTTP})
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
List<Acl> listDefaultAcls(String bucket);

/**
Expand Down
Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -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<Acl> 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
Expand Down Expand Up @@ -976,19 +1001,29 @@ public void testBlobAcl() {
}

static <T> T retry429s(Callable<T> c, Storage storage) {
return RetryHelper.runWithRetries(
c,
storage.getOptions().getRetrySettings(),
new BasicResultRetryAlgorithm<Object>() {
@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<Object>() {
@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;
}
}
}
}

0 comments on commit 03c2e66

Please sign in to comment.