Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement GrpcStorageImpl#listDefaultAcl #1805

Merged
merged 1 commit into from
Dec 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -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
Original file line number Diff line number Diff line change
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());
}
}
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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;
}
}
}
}