Skip to content

Commit 8fd605b

Browse files
committed
feat: implement GrpcStorageImpl#createDefaultAcl & GrpcStorageImpl#updateDefaultAcl
1 parent a1b6e66 commit 8fd605b

File tree

5 files changed

+133
-8
lines changed

5 files changed

+133
-8
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,7 +1285,7 @@ public boolean deleteDefaultAcl(Entity entity) {
12851285
*
12861286
* @throws StorageException upon failure
12871287
*/
1288-
@TransportCompatibility({Transport.HTTP})
1288+
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
12891289
public Acl createDefaultAcl(Acl acl) {
12901290
return storage.createDefaultAcl(getName(), acl);
12911291
}
@@ -1304,7 +1304,7 @@ public Acl createDefaultAcl(Acl acl) {
13041304
*
13051305
* @throws StorageException upon failure
13061306
*/
1307-
@TransportCompatibility({Transport.HTTP})
1307+
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
13081308
public Acl updateDefaultAcl(Acl acl) {
13091309
return storage.updateDefaultAcl(getName(), acl);
13101310
}

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

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import com.google.common.annotations.VisibleForTesting;
6969
import com.google.common.collect.ImmutableList;
7070
import com.google.common.collect.ImmutableSet;
71+
import com.google.common.collect.Streams;
7172
import com.google.common.io.BaseEncoding;
7273
import com.google.common.io.ByteStreams;
7374
import com.google.iam.v1.GetIamPolicyRequest;
@@ -936,12 +937,59 @@ public boolean deleteDefaultAcl(String bucket, Entity entity) {
936937

937938
@Override
938939
public Acl createDefaultAcl(String bucket, Acl acl) {
939-
return throwNotYetImplemented(fmtMethodName("createDefaultAcl", String.class, Acl.class));
940+
return updateDefaultAcl(bucket, acl);
940941
}
941942

942943
@Override
943944
public Acl updateDefaultAcl(String bucket, Acl acl) {
944-
return throwNotYetImplemented(fmtMethodName("updateDefaultAcl", String.class, Acl.class));
945+
try {
946+
com.google.storage.v2.Bucket resp = getBucketDefaultAcls(bucket);
947+
ObjectAccessControl encode = codecs.objectAcl().encode(acl);
948+
String entity = encode.getEntity();
949+
950+
Predicate<ObjectAccessControl> entityPredicate = objectAclEntityOrAltEq(entity);
951+
952+
ImmutableList<ObjectAccessControl> collect =
953+
Streams.concat(
954+
resp.getDefaultObjectAclList().stream().filter(entityPredicate.negate()),
955+
Stream.of(encode))
956+
.collect(ImmutableList.toImmutableList());
957+
958+
com.google.storage.v2.Bucket update =
959+
com.google.storage.v2.Bucket.newBuilder()
960+
.setName(bucketNameCodec.encode(bucket))
961+
.addAllDefaultObjectAcl(collect)
962+
.build();
963+
Opts<BucketTargetOpt> opts =
964+
Opts.from(
965+
UnifiedOpts.fields(ImmutableSet.of(BucketField.DEFAULT_OBJECT_ACL)),
966+
UnifiedOpts.metagenerationMatch(resp.getMetageneration()));
967+
UpdateBucketRequest req =
968+
opts.updateBucketsRequest()
969+
.apply(UpdateBucketRequest.newBuilder())
970+
.setBucket(update)
971+
.build();
972+
973+
GrpcCallContext grpcCallContext = GrpcCallContext.createDefault();
974+
com.google.storage.v2.Bucket updateResult =
975+
Retrying.run(
976+
getOptions(),
977+
retryAlgorithmManager.getFor(req),
978+
() -> storageClient.updateBucketCallable().call(req, grpcCallContext),
979+
Decoder.identity());
980+
981+
//noinspection DataFlowIssue
982+
Optional<Acl> first =
983+
updateResult.getDefaultObjectAclList().stream()
984+
.filter(entityPredicate)
985+
.findFirst()
986+
.map(codecs.objectAcl()::decode);
987+
988+
return first.orElseThrow(
989+
() -> new StorageException(404, "Acl update call success, but not in response"));
990+
} catch (NotFoundException e) {
991+
throw StorageException.coalesce(e);
992+
}
945993
}
946994

947995
@Override

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3530,7 +3530,7 @@ PostPolicyV4 generateSignedPostPolicyV4(
35303530
*
35313531
* @throws StorageException upon failure
35323532
*/
3533-
@TransportCompatibility({Transport.HTTP})
3533+
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
35343534
Acl createDefaultAcl(String bucket, Acl acl);
35353535

35363536
/**
@@ -3549,7 +3549,7 @@ PostPolicyV4 generateSignedPostPolicyV4(
35493549
*
35503550
* @throws StorageException upon failure
35513551
*/
3552-
@TransportCompatibility({Transport.HTTP})
3552+
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
35533553
Acl updateDefaultAcl(String bucket, Acl acl);
35543554

35553555
/**

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ public Mapper<ListObjectsRequest.Builder> listObjects() {
713713
}
714714

715715
static final class Fields extends RpcOptVal<ImmutableSet<NamedField>>
716-
implements ObjectSourceOpt, ObjectListOpt, BucketSourceOpt, BucketListOpt {
716+
implements ObjectSourceOpt, ObjectListOpt, BucketSourceOpt, BucketTargetOpt, BucketListOpt {
717717

718718
/**
719719
* Apiary and gRPC have differing handling of where the field selector is evaluated relative to
@@ -752,6 +752,11 @@ public Mapper<ListBucketsRequest.Builder> listBuckets() {
752752
return b -> b.setReadMask(FieldMask.newBuilder().addAllPaths(getPaths()).build());
753753
}
754754

755+
@Override
756+
public Mapper<UpdateBucketRequest.Builder> updateBucket() {
757+
return b -> b.setUpdateMask(FieldMask.newBuilder().addAllPaths(getPaths()).build());
758+
}
759+
755760
@Override
756761
public Mapper<GetObjectRequest.Builder> getObject() {
757762
return b -> b.setReadMask(FieldMask.newBuilder().addAllPaths(getPaths()).build());

google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITAccessTest.java

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,78 @@ public void bucket_defaultAcl_list_bucket404() {
185185
assertThat(storageException.getCode()).isEqualTo(404);
186186
}
187187

188+
@Test
189+
public void bucket_defaultAcl_create() throws Exception {
190+
BucketInfo bucketInfo = BucketInfo.newBuilder(generator.randomBucketName()).build();
191+
try (TemporaryBucket tempB =
192+
TemporaryBucket.newBuilder().setBucketInfo(bucketInfo).setStorage(storage).build()) {
193+
BucketInfo bucket = tempB.getBucket();
194+
195+
Acl readAll = Acl.of(User.ofAllAuthenticatedUsers(), Role.READER);
196+
Acl actual = retry429s(() -> storage.createDefaultAcl(bucket.getName(), readAll), storage);
197+
198+
assertThat(actual.getEntity()).isEqualTo(readAll.getEntity());
199+
assertThat(actual.getRole()).isEqualTo(readAll.getRole());
200+
assertThat(actual.getEtag()).isNotEmpty();
201+
202+
Bucket bucketUpdated =
203+
storage.get(bucket.getName(), BucketGetOption.fields(BucketField.values()));
204+
assertThat(bucketUpdated.getMetageneration()).isNotEqualTo(bucket.getMetageneration());
205+
206+
// etags change when updates happen, drop before our comparison
207+
List<Acl> expectedAcls = dropEtags(bucket.getDefaultAcl());
208+
List<Acl> actualAcls = dropEtags(bucketUpdated.getDefaultAcl());
209+
assertThat(actualAcls).containsAtLeastElementsIn(expectedAcls);
210+
}
211+
}
212+
213+
@Test
214+
public void bucket_defaultAcl_create_bucket404() {
215+
Acl readAll = Acl.of(User.ofAllAuthenticatedUsers(), Role.READER);
216+
StorageException storageException =
217+
assertThrows(
218+
StorageException.class,
219+
() ->
220+
retry429s(
221+
() -> storage.createDefaultAcl(bucket.getName() + "x", readAll), storage));
222+
223+
assertThat(storageException.getCode()).isEqualTo(404);
224+
}
225+
226+
@Test
227+
public void bucket_defaultAcl_update() throws Exception {
228+
BucketInfo bucketInfo = BucketInfo.newBuilder(generator.randomBucketName()).build();
229+
try (TemporaryBucket tempB =
230+
TemporaryBucket.newBuilder().setBucketInfo(bucketInfo).setStorage(storage).build()) {
231+
BucketInfo bucket = tempB.getBucket();
232+
233+
Acl readAll = Acl.of(User.ofAllAuthenticatedUsers(), Role.READER);
234+
Acl actual = retry429s(() -> storage.updateDefaultAcl(bucket.getName(), readAll), storage);
235+
236+
assertThat(actual.getEntity()).isEqualTo(readAll.getEntity());
237+
assertThat(actual.getRole()).isEqualTo(readAll.getRole());
238+
assertThat(actual.getEtag()).isNotEmpty();
239+
}
240+
}
241+
242+
@Test
243+
public void bucket_defaultAcl_update_bucket404() {
244+
Acl readAll = Acl.of(User.ofAllAuthenticatedUsers(), Role.READER);
245+
StorageException storageException =
246+
assertThrows(
247+
StorageException.class,
248+
() ->
249+
retry429s(
250+
() -> storage.updateDefaultAcl(bucket.getName() + "x", readAll), storage));
251+
252+
assertThat(storageException.getCode()).isEqualTo(404);
253+
}
254+
188255
@Test
189256
@CrossRun.Ignore(transports = Transport.GRPC)
190257
public void testBucketDefaultAcl() {
191258
// TODO: break this test up into each of the respective scenarios
192259
// 2. Delete a default ACL for a specific entity
193-
// 3. Create a default ACL for specific entity
194260
// 4. Update default ACL to change role of a specific entity
195261

196262
// according to https://cloud.google.com/storage/docs/access-control/lists#default
@@ -1026,4 +1092,10 @@ public boolean shouldRetry(Throwable previousThrowable, Object previousResponse)
10261092
}
10271093
}
10281094
}
1095+
1096+
private static ImmutableList<Acl> dropEtags(List<Acl> defaultAcls) {
1097+
return defaultAcls.stream()
1098+
.map(acl -> Acl.of(acl.getEntity(), acl.getRole()))
1099+
.collect(ImmutableList.toImmutableList());
1100+
}
10291101
}

0 commit comments

Comments
 (0)