Skip to content

Commit 5c52079

Browse files
authored
feat: implement GrpcStorageImpl BucketAccessControl operations (#1816)
Newly implemented methods (including any overloads): 1. GrpcStorageImpl#createAcl 2. GrpcStorageImpl#getAcl 3. GrpcStorageImpl#listAcl 4. GrpcStorageImpl#updateAcl 5. GrpcStorageImpl#deleteAcl 6. Bucket#createAcl 7. Bucket#getAcl 8. Bucket#listAcl 9. Bucket#updateAcl 10. Bucket#deleteAcl
1 parent c783277 commit 5c52079

File tree

7 files changed

+502
-73
lines changed

7 files changed

+502
-73
lines changed

google-cloud-storage/src/main/java/com/google/cloud/storage/Bucket.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,7 +1148,7 @@ public Blob create(String blob, InputStream content, BlobWriteOption... options)
11481148
*
11491149
* @throws StorageException upon failure
11501150
*/
1151-
@TransportCompatibility({Transport.HTTP})
1151+
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
11521152
public Acl getAcl(Entity entity) {
11531153
return storage.getAcl(getName(), entity);
11541154
}
@@ -1170,7 +1170,7 @@ public Acl getAcl(Entity entity) {
11701170
* @return {@code true} if the ACL was deleted, {@code false} if it was not found
11711171
* @throws StorageException upon failure
11721172
*/
1173-
@TransportCompatibility({Transport.HTTP})
1173+
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
11741174
public boolean deleteAcl(Entity entity) {
11751175
return storage.deleteAcl(getName(), entity);
11761176
}
@@ -1186,7 +1186,7 @@ public boolean deleteAcl(Entity entity) {
11861186
*
11871187
* @throws StorageException upon failure
11881188
*/
1189-
@TransportCompatibility({Transport.HTTP})
1189+
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
11901190
public Acl createAcl(Acl acl) {
11911191
return storage.createAcl(getName(), acl);
11921192
}
@@ -1202,7 +1202,7 @@ public Acl createAcl(Acl acl) {
12021202
*
12031203
* @throws StorageException upon failure
12041204
*/
1205-
@TransportCompatibility({Transport.HTTP})
1205+
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
12061206
public Acl updateAcl(Acl acl) {
12071207
return storage.updateAcl(getName(), acl);
12081208
}
@@ -1221,7 +1221,7 @@ public Acl updateAcl(Acl acl) {
12211221
*
12221222
* @throws StorageException upon failure
12231223
*/
1224-
@TransportCompatibility({Transport.HTTP})
1224+
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
12251225
public List<Acl> listAcls() {
12261226
return storage.listAcls(getName());
12271227
}

google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcStorageImpl.java

Lines changed: 148 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static com.google.cloud.storage.ByteSizeConstants._16MiB;
2020
import static com.google.cloud.storage.ByteSizeConstants._256KiB;
2121
import static com.google.cloud.storage.GrpcToHttpStatusCodeTranslation.resultRetryAlgorithmToCodes;
22+
import static com.google.cloud.storage.StorageV2ProtoUtils.bucketAclEntityOrAltEq;
2223
import static com.google.cloud.storage.StorageV2ProtoUtils.objectAclEntityOrAltEq;
2324
import static com.google.cloud.storage.Utils.bucketNameCodec;
2425
import static com.google.cloud.storage.Utils.ifNonNull;
@@ -76,6 +77,7 @@
7677
import com.google.iam.v1.TestIamPermissionsRequest;
7778
import com.google.protobuf.ByteString;
7879
import com.google.protobuf.FieldMask;
80+
import com.google.storage.v2.BucketAccessControl;
7981
import com.google.storage.v2.ComposeObjectRequest;
8082
import com.google.storage.v2.ComposeObjectRequest.SourceObject;
8183
import com.google.storage.v2.CreateBucketRequest;
@@ -152,6 +154,7 @@ final class GrpcStorageImpl extends BaseService<StorageOptions> implements Stora
152154
StandardOpenOption.WRITE,
153155
StandardOpenOption.CREATE,
154156
StandardOpenOption.TRUNCATE_EXISTING);
157+
private static final BucketSourceOption[] EMPTY_BUCKET_SOURCE_OPTIONS = new BucketSourceOption[0];
155158

156159
final StorageClient storageClient;
157160
final GrpcConversions codecs;
@@ -853,63 +856,148 @@ public List<Boolean> delete(Iterable<BlobId> blobIds) {
853856

854857
@Override
855858
public Acl getAcl(String bucket, Entity entity, BucketSourceOption... options) {
856-
return throwNotYetImplemented(
857-
fmtMethodName("getAcl", String.class, Entity.class, BucketSourceOption[].class));
859+
try {
860+
Opts<BucketSourceOpt> opts = Opts.unwrap(options);
861+
com.google.storage.v2.Bucket resp = getBucketWithAcls(bucket, opts);
862+
863+
Predicate<BucketAccessControl> entityPredicate =
864+
bucketAclEntityOrAltEq(codecs.entity().encode(entity));
865+
866+
Optional<BucketAccessControl> first =
867+
resp.getAclList().stream().filter(entityPredicate).findFirst();
868+
869+
// HttpStorageRpc defaults to null if Not Found
870+
return first.map(codecs.bucketAcl()::decode).orElse(null);
871+
} catch (NotFoundException e) {
872+
return null;
873+
} catch (StorageException se) {
874+
if (se.getCode() == 404) {
875+
return null;
876+
} else {
877+
throw se;
878+
}
879+
}
858880
}
859881

860882
@Override
861883
public Acl getAcl(String bucket, Entity entity) {
862-
return throwNotYetImplemented(fmtMethodName("getAcl", String.class, Entity.class));
884+
return getAcl(bucket, entity, EMPTY_BUCKET_SOURCE_OPTIONS);
863885
}
864886

865887
@Override
866888
public boolean deleteAcl(String bucket, Entity entity, BucketSourceOption... options) {
867-
return throwNotYetImplemented(
868-
fmtMethodName("deleteAcl", String.class, Entity.class, BucketSourceOption[].class));
889+
try {
890+
Opts<BucketSourceOpt> opts = Opts.unwrap(options);
891+
com.google.storage.v2.Bucket resp = getBucketWithAcls(bucket, opts);
892+
String encode = codecs.entity().encode(entity);
893+
894+
Predicate<BucketAccessControl> entityPredicate = bucketAclEntityOrAltEq(encode);
895+
896+
List<BucketAccessControl> currentAcls = resp.getAclList();
897+
ImmutableList<BucketAccessControl> newAcls =
898+
currentAcls.stream()
899+
.filter(entityPredicate.negate())
900+
.collect(ImmutableList.toImmutableList());
901+
if (newAcls.equals(currentAcls)) {
902+
// we didn't actually filter anything out, no need to send an RPC, simply return false
903+
return false;
904+
}
905+
long metageneration = resp.getMetageneration();
906+
907+
UpdateBucketRequest req = createUpdateAclRequest(bucket, newAcls, metageneration);
908+
909+
com.google.storage.v2.Bucket updateResult = updateBucket(req);
910+
// read the response to ensure there is no longer an acl for the specified entity
911+
Optional<BucketAccessControl> first =
912+
updateResult.getAclList().stream().filter(entityPredicate).findFirst();
913+
return !first.isPresent();
914+
} catch (NotFoundException e) {
915+
// HttpStorageRpc returns false if the bucket doesn't exist :(
916+
return false;
917+
} catch (StorageException se) {
918+
if (se.getCode() == 404) {
919+
return false;
920+
} else {
921+
throw se;
922+
}
923+
}
869924
}
870925

871926
@Override
872927
public boolean deleteAcl(String bucket, Entity entity) {
873-
return throwNotYetImplemented(fmtMethodName("deleteAcl", String.class, Entity.class));
928+
return deleteAcl(bucket, entity, EMPTY_BUCKET_SOURCE_OPTIONS);
874929
}
875930

876931
@Override
877932
public Acl createAcl(String bucket, Acl acl, BucketSourceOption... options) {
878-
return throwNotYetImplemented(
879-
fmtMethodName("createAcl", String.class, Acl.class, BucketSourceOption[].class));
933+
return updateAcl(bucket, acl, options);
880934
}
881935

882936
@Override
883937
public Acl createAcl(String bucket, Acl acl) {
884-
return throwNotYetImplemented(fmtMethodName("createAcl", String.class, Acl.class));
938+
return createAcl(bucket, acl, EMPTY_BUCKET_SOURCE_OPTIONS);
885939
}
886940

887941
@Override
888942
public Acl updateAcl(String bucket, Acl acl, BucketSourceOption... options) {
889-
return throwNotYetImplemented(
890-
fmtMethodName("updateAcl", String.class, Acl.class, BucketSourceOption[].class));
943+
try {
944+
Opts<BucketSourceOpt> opts = Opts.unwrap(options);
945+
com.google.storage.v2.Bucket resp = getBucketWithAcls(bucket, opts);
946+
BucketAccessControl encode = codecs.bucketAcl().encode(acl);
947+
String entity = encode.getEntity();
948+
949+
Predicate<BucketAccessControl> entityPredicate = bucketAclEntityOrAltEq(entity);
950+
951+
ImmutableList<BucketAccessControl> newDefaultAcls =
952+
Streams.concat(
953+
resp.getAclList().stream().filter(entityPredicate.negate()), Stream.of(encode))
954+
.collect(ImmutableList.toImmutableList());
955+
956+
UpdateBucketRequest req =
957+
createUpdateAclRequest(bucket, newDefaultAcls, resp.getMetageneration());
958+
959+
com.google.storage.v2.Bucket updateResult = updateBucket(req);
960+
961+
Optional<Acl> first =
962+
updateResult.getAclList().stream()
963+
.filter(entityPredicate)
964+
.findFirst()
965+
.map(codecs.bucketAcl()::decode);
966+
967+
return first.orElseThrow(
968+
() -> new StorageException(0, "Acl update call success, but not in response"));
969+
} catch (NotFoundException e) {
970+
throw StorageException.coalesce(e);
971+
}
891972
}
892973

893974
@Override
894975
public Acl updateAcl(String bucket, Acl acl) {
895-
return throwNotYetImplemented(fmtMethodName("updateAcl", String.class, Acl.class));
976+
return updateAcl(bucket, acl, EMPTY_BUCKET_SOURCE_OPTIONS);
896977
}
897978

898979
@Override
899980
public List<Acl> listAcls(String bucket, BucketSourceOption... options) {
900-
return throwNotYetImplemented(
901-
fmtMethodName("listAcls", String.class, BucketSourceOption[].class));
981+
try {
982+
Opts<BucketSourceOpt> opts = Opts.unwrap(options);
983+
com.google.storage.v2.Bucket resp = getBucketWithAcls(bucket, opts);
984+
return resp.getAclList().stream()
985+
.map(codecs.bucketAcl()::decode)
986+
.collect(ImmutableList.toImmutableList());
987+
} catch (NotFoundException e) {
988+
throw StorageException.coalesce(e);
989+
}
902990
}
903991

904992
@Override
905993
public List<Acl> listAcls(String bucket) {
906-
return throwNotYetImplemented(fmtMethodName("listAcls", String.class));
994+
return listAcls(bucket, EMPTY_BUCKET_SOURCE_OPTIONS);
907995
}
908996

909997
@Override
910998
public Acl getDefaultAcl(String bucket, Entity entity) {
911999
try {
912-
com.google.storage.v2.Bucket resp = getBucketDefaultAcls(bucket);
1000+
com.google.storage.v2.Bucket resp = getBucketWithDefaultAcls(bucket);
9131001

9141002
Predicate<ObjectAccessControl> entityPredicate =
9151003
objectAclEntityOrAltEq(codecs.entity().encode(entity));
@@ -933,7 +1021,7 @@ public Acl getDefaultAcl(String bucket, Entity entity) {
9331021
@Override
9341022
public boolean deleteDefaultAcl(String bucket, Entity entity) {
9351023
try {
936-
com.google.storage.v2.Bucket resp = getBucketDefaultAcls(bucket);
1024+
com.google.storage.v2.Bucket resp = getBucketWithDefaultAcls(bucket);
9371025
String encode = codecs.entity().encode(entity);
9381026

9391027
Predicate<ObjectAccessControl> entityPredicate = objectAclEntityOrAltEq(encode);
@@ -949,7 +1037,8 @@ public boolean deleteDefaultAcl(String bucket, Entity entity) {
9491037
}
9501038
long metageneration = resp.getMetageneration();
9511039

952-
UpdateBucketRequest req = createUpdateRequest(bucket, newDefaultAcls, metageneration);
1040+
UpdateBucketRequest req =
1041+
createUpdateDefaultAclRequest(bucket, newDefaultAcls, metageneration);
9531042

9541043
com.google.storage.v2.Bucket updateResult = updateBucket(req);
9551044
// read the response to ensure there is no longer an acl for the specified entity
@@ -976,7 +1065,7 @@ public Acl createDefaultAcl(String bucket, Acl acl) {
9761065
@Override
9771066
public Acl updateDefaultAcl(String bucket, Acl acl) {
9781067
try {
979-
com.google.storage.v2.Bucket resp = getBucketDefaultAcls(bucket);
1068+
com.google.storage.v2.Bucket resp = getBucketWithDefaultAcls(bucket);
9801069
ObjectAccessControl encode = codecs.objectAcl().encode(acl);
9811070
String entity = encode.getEntity();
9821071

@@ -989,7 +1078,7 @@ public Acl updateDefaultAcl(String bucket, Acl acl) {
9891078
.collect(ImmutableList.toImmutableList());
9901079

9911080
UpdateBucketRequest req =
992-
createUpdateRequest(bucket, newDefaultAcls, resp.getMetageneration());
1081+
createUpdateDefaultAclRequest(bucket, newDefaultAcls, resp.getMetageneration());
9931082

9941083
com.google.storage.v2.Bucket updateResult = updateBucket(req);
9951084

@@ -1009,7 +1098,7 @@ public Acl updateDefaultAcl(String bucket, Acl acl) {
10091098
@Override
10101099
public List<Acl> listDefaultAcls(String bucket) {
10111100
try {
1012-
com.google.storage.v2.Bucket resp = getBucketDefaultAcls(bucket);
1101+
com.google.storage.v2.Bucket resp = getBucketWithDefaultAcls(bucket);
10131102
return resp.getDefaultObjectAclList().stream()
10141103
.map(codecs.objectAcl()::decode)
10151104
.collect(ImmutableList.toImmutableList());
@@ -1481,7 +1570,7 @@ private SourceObject sourceObjectEncode(SourceBlob from) {
14811570
return to.build();
14821571
}
14831572

1484-
private com.google.storage.v2.Bucket getBucketDefaultAcls(String bucketName) {
1573+
private com.google.storage.v2.Bucket getBucketWithDefaultAcls(String bucketName) {
14851574
Fields fields =
14861575
UnifiedOpts.fields(
14871576
ImmutableSet.of(
@@ -1503,6 +1592,25 @@ private com.google.storage.v2.Bucket getBucketDefaultAcls(String bucketName) {
15031592
Decoder.identity());
15041593
}
15051594

1595+
private com.google.storage.v2.Bucket getBucketWithAcls(
1596+
String bucketName, Opts<BucketSourceOpt> opts) {
1597+
Fields fields =
1598+
UnifiedOpts.fields(ImmutableSet.of(BucketField.ACL, BucketField.METAGENERATION));
1599+
GrpcCallContext grpcCallContext = GrpcCallContext.createDefault();
1600+
Mapper<GetBucketRequest.Builder> mapper = opts.getBucketsRequest().andThen(fields.getBucket());
1601+
GetBucketRequest req =
1602+
mapper
1603+
.apply(GetBucketRequest.newBuilder())
1604+
.setName(bucketNameCodec.encode(bucketName))
1605+
.build();
1606+
1607+
return Retrying.run(
1608+
getOptions(),
1609+
retryAlgorithmManager.getFor(req),
1610+
() -> storageClient.getBucketCallable().call(req, grpcCallContext),
1611+
Decoder.identity());
1612+
}
1613+
15061614
private com.google.storage.v2.Bucket updateBucket(UpdateBucketRequest req) {
15071615
GrpcCallContext grpcCallContext = GrpcCallContext.createDefault();
15081616
return Retrying.run(
@@ -1512,7 +1620,7 @@ private com.google.storage.v2.Bucket updateBucket(UpdateBucketRequest req) {
15121620
Decoder.identity());
15131621
}
15141622

1515-
private static UpdateBucketRequest createUpdateRequest(
1623+
private static UpdateBucketRequest createUpdateDefaultAclRequest(
15161624
String bucket, ImmutableList<ObjectAccessControl> newDefaultAcls, long metageneration) {
15171625
com.google.storage.v2.Bucket update =
15181626
com.google.storage.v2.Bucket.newBuilder()
@@ -1528,4 +1636,21 @@ private static UpdateBucketRequest createUpdateRequest(
15281636
.setBucket(update)
15291637
.build();
15301638
}
1639+
1640+
private static UpdateBucketRequest createUpdateAclRequest(
1641+
String bucket, ImmutableList<BucketAccessControl> newDefaultAcls, long metageneration) {
1642+
com.google.storage.v2.Bucket update =
1643+
com.google.storage.v2.Bucket.newBuilder()
1644+
.setName(bucketNameCodec.encode(bucket))
1645+
.addAllAcl(newDefaultAcls)
1646+
.build();
1647+
Opts<BucketTargetOpt> opts =
1648+
Opts.from(
1649+
UnifiedOpts.fields(ImmutableSet.of(BucketField.ACL)),
1650+
UnifiedOpts.metagenerationMatch(metageneration));
1651+
return opts.updateBucketsRequest()
1652+
.apply(UpdateBucketRequest.newBuilder())
1653+
.setBucket(update)
1654+
.build();
1655+
}
15311656
}

0 commit comments

Comments
 (0)