From f3c40da368d2e825bbd337c554f6f9bd33a00bdb Mon Sep 17 00:00:00 2001 From: JesseLovelace <43148100+JesseLovelace@users.noreply.github.com> Date: Wed, 13 Oct 2021 13:52:59 -0700 Subject: [PATCH 1/6] (feat) Add RPO metadata settings --- .../clirr-ignored-differences.xml | 5 ++ .../java/com/google/cloud/storage/Bucket.java | 6 +++ .../com/google/cloud/storage/BucketInfo.java | 22 ++++++++ .../java/com/google/cloud/storage/Rpo.java | 53 +++++++++++++++++++ .../cloud/storage/it/ITStorageTest.java | 39 +++++++------- 5 files changed, 106 insertions(+), 19 deletions(-) create mode 100644 google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java diff --git a/google-cloud-storage/clirr-ignored-differences.xml b/google-cloud-storage/clirr-ignored-differences.xml index 85c4887d6..14d4e43e2 100644 --- a/google-cloud-storage/clirr-ignored-differences.xml +++ b/google-cloud-storage/clirr-ignored-differences.xml @@ -21,6 +21,11 @@ com.google.cloud.storage.BucketInfo$Builder deleteLifecycleRules() 7013 + + com/google/cloud/storage/BucketInfo$Builder + com.google.cloud.storage.BucketInfo$Builder setRpo(com.google.cloud.storage.Rpo) + 7013 + com/google/cloud/storage/BucketInfo$Builder com.google.cloud.storage.BucketInfo$Builder setUpdateTime(java.lang.Long) 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 3714e6e94..95acd19d6 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 @@ -577,6 +577,12 @@ public Builder deleteLifecycleRules() { return this; } + @Override + public Builder setRpo(Rpo rpo) { + infoBuilder.setRpo(rpo); + return this; + } + @Override public Builder setStorageClass(StorageClass storageClass) { infoBuilder.setStorageClass(storageClass); diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java index 83a836f78..d5d87f443 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java @@ -92,6 +92,7 @@ public com.google.api.services.storage.model.Bucket apply(BucketInfo bucketInfo) private final List acl; private final List defaultAcl; private final String location; + private final Rpo rpo; private final StorageClass storageClass; private final Map labels; private final String defaultKmsKeyName; @@ -1185,6 +1186,8 @@ public abstract static class Builder { /** Deletes the lifecycle rules of this bucket. */ public abstract Builder deleteLifecycleRules(); + public abstract Builder setRpo(Rpo rpo); + /** * Sets the bucket's storage class. This defines how blobs in the bucket are stored and * determines the SLA and the cost of storage. A list of supported values is available deleteRules; private List lifecycleRules; + private Rpo rpo; private StorageClass storageClass; private String location; private String etag; @@ -1317,6 +1321,7 @@ static final class BuilderImpl extends Builder { updateTime = bucketInfo.updateTime; metageneration = bucketInfo.metageneration; location = bucketInfo.location; + rpo = bucketInfo.rpo; storageClass = bucketInfo.storageClass; cors = bucketInfo.cors; acl = bucketInfo.acl; @@ -1410,6 +1415,12 @@ public Builder deleteLifecycleRules() { return this; } + @Override + public Builder setRpo(Rpo rpo) { + this.rpo = rpo; + return this; + } + @Override public Builder setStorageClass(StorageClass storageClass) { this.storageClass = storageClass; @@ -1548,6 +1559,7 @@ public BucketInfo build() { updateTime = builder.updateTime; metageneration = builder.metageneration; location = builder.location; + rpo = builder.rpo; storageClass = builder.storageClass; cors = builder.cors; acl = builder.acl; @@ -1709,6 +1721,10 @@ public String getLocationType() { return locationType; } + public Rpo getRpo() { + return rpo; + } + /** * Returns the bucket's storage class. This defines how blobs in the bucket are stored and * determines the SLA and the cost of storage. @@ -1879,6 +1895,9 @@ com.google.api.services.storage.model.Bucket toPb() { if (locationType != null) { bucketPb.setLocationType(locationType); } + if (rpo != null) { + bucketPb.setRpo(rpo.toString()); + } if (storageClass != null) { bucketPb.setStorageClass(storageClass.toString()); } @@ -2042,6 +2061,9 @@ static BucketInfo fromPb(com.google.api.services.storage.model.Bucket bucketPb) if (bucketPb.getLocation() != null) { builder.setLocation(bucketPb.getLocation()); } + if (bucketPb.getRpo() != null) { + builder.setRpo(Rpo.valueOf(bucketPb.getRpo())); + } if (bucketPb.getStorageClass() != null) { builder.setStorageClass(StorageClass.valueOf(bucketPb.getStorageClass())); } diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java new file mode 100644 index 000000000..6454d8662 --- /dev/null +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java @@ -0,0 +1,53 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.storage; + +import com.google.api.core.ApiFunction; +import com.google.cloud.StringEnumType; +import com.google.cloud.StringEnumValue; + +public class Rpo extends StringEnumValue { + + private Rpo(String constant) { + super(constant); + } + + private static final ApiFunction CONSTRUCTOR = Rpo::new; + + private static final StringEnumType type = new StringEnumType(Rpo.class, CONSTRUCTOR); + + public static final Rpo DEFAULT = type.createAndRegister("DEFAULT"); + + public static final Rpo ASYNC_TURBO = type.createAndRegister("ASYNC_TURBO"); + + /** + * Get the Rpo for the given String constant, and throw an exception if the constant is not + * recognized. + */ + public static Rpo valueOfStrict(String constant) { + return type.valueOfStrict(constant); + } + + /** Get the Rpo for the given String constant, and allow unrecognized values. */ + public static Rpo valueOf(String constant) { + return type.valueOf(constant); + } + + /** Return the known values for Rpo. */ + public static Rpo[] values() { + return type.values(); + } +} diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java index 73ef7e9b8..52510562c 100644 --- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java +++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java @@ -54,34 +54,16 @@ import com.google.cloud.kms.v1.KeyManagementServiceGrpc.KeyManagementServiceBlockingStub; import com.google.cloud.kms.v1.KeyRingName; import com.google.cloud.kms.v1.LocationName; -import com.google.cloud.storage.Acl; +import com.google.cloud.storage.*; import com.google.cloud.storage.Acl.Role; import com.google.cloud.storage.Acl.User; -import com.google.cloud.storage.Blob; -import com.google.cloud.storage.BlobId; -import com.google.cloud.storage.BlobInfo; -import com.google.cloud.storage.Bucket; -import com.google.cloud.storage.BucketInfo; import com.google.cloud.storage.BucketInfo.LifecycleRule; import com.google.cloud.storage.BucketInfo.LifecycleRule.LifecycleAction; import com.google.cloud.storage.BucketInfo.LifecycleRule.LifecycleCondition; -import com.google.cloud.storage.CopyWriter; -import com.google.cloud.storage.Cors; -import com.google.cloud.storage.HmacKey; -import com.google.cloud.storage.HttpMethod; -import com.google.cloud.storage.PostPolicyV4; import com.google.cloud.storage.PostPolicyV4.PostFieldsV4; -import com.google.cloud.storage.ServiceAccount; -import com.google.cloud.storage.Storage; import com.google.cloud.storage.Storage.BlobField; import com.google.cloud.storage.Storage.BlobWriteOption; import com.google.cloud.storage.Storage.BucketField; -import com.google.cloud.storage.StorageBatch; -import com.google.cloud.storage.StorageBatchResult; -import com.google.cloud.storage.StorageClass; -import com.google.cloud.storage.StorageException; -import com.google.cloud.storage.StorageOptions; -import com.google.cloud.storage.StorageRoles; import com.google.cloud.storage.spi.StorageRpcFactory; import com.google.cloud.storage.spi.v1.StorageRpc; import com.google.cloud.storage.spi.v1.StorageRpc.Option; @@ -3940,6 +3922,25 @@ protected Object handleInvocation( assertArrayEquals(randStringBytes, actualData.toByteArray()); } + @Test + public void testRpoConfig() { + String rpoBucket = RemoteStorageHelper.generateBucketName(); + try { + Bucket bucket = storage.create( + BucketInfo.newBuilder(rpoBucket) + .setLocation("NAM4") + .setRpo(Rpo.ASYNC_TURBO) + .build()); + assertEquals("ASYNC_TURBO", bucket.getRpo().toString()); + + bucket.toBuilder().setRpo(Rpo.DEFAULT).build().update(); + + assertEquals("DEFAULT", storage.get(rpoBucket).getRpo().toString()); + } finally { + storage.delete(rpoBucket); + } + } + private static String randString(Random rand, int length) { final StringBuilder sb = new StringBuilder(); while (sb.length() < length) { From 682736279c7f166dd4df010053a66c43f9bd0983 Mon Sep 17 00:00:00 2001 From: JesseLovelace <43148100+JesseLovelace@users.noreply.github.com> Date: Thu, 14 Oct 2021 14:06:52 -0700 Subject: [PATCH 2/6] Add javadoc --- .../com/google/cloud/storage/BucketInfo.java | 13 +++++++++ .../java/com/google/cloud/storage/Rpo.java | 17 +++++++++++ .../cloud/storage/it/ITStorageTest.java | 29 +++++++++++++++---- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java index d5d87f443..b7f915908 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java @@ -1186,6 +1186,13 @@ public abstract static class Builder { /** Deletes the lifecycle rules of this bucket. */ public abstract Builder deleteLifecycleRules(); + /** + * Sets the bucket's Recovery Point Objective (RPO). This can only be set for a dual-region + * bucket, and determines the speed at which data will be replicated between regions. See the + * {@code Rpo} class for supported values, and here for additional + * details. + */ public abstract Builder setRpo(Rpo rpo); /** @@ -1721,6 +1728,12 @@ public String getLocationType() { return locationType; } + /** + * Returns the bucket's recovery point objective (RPO). This defines how quickly data is + * replicated between regions in a dual-region bucket. Not defined for single-region buckets. + * + * @see + */ public Rpo getRpo() { return rpo; } diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java index 6454d8662..b99c7cec0 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java @@ -19,8 +19,17 @@ import com.google.cloud.StringEnumType; import com.google.cloud.StringEnumValue; +/** + * Enums for the Recovery Point Objective (RPO) of dual-region buckets, which determines how fast + * data is replicated betweens regions. + * + * @see https://cloud.google.com/storage/docs/turbo-replication + */ public class Rpo extends StringEnumValue { + private static final long serialVersionUID = -3954216195295821508L; + private Rpo(String constant) { super(constant); } @@ -29,8 +38,16 @@ private Rpo(String constant) { private static final StringEnumType type = new StringEnumType(Rpo.class, CONSTRUCTOR); + /** + * Default recovery point objective. With this setting, there is no guarantee on the amount of + * time it takes for data to replicate between regions. + */ public static final Rpo DEFAULT = type.createAndRegister("DEFAULT"); + /** + * Turbo recovery point objective. With this setting, data in a dual-region bucket will replicate + * between regions within 15 minutes. + */ public static final Rpo ASYNC_TURBO = type.createAndRegister("ASYNC_TURBO"); /** diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java index 52510562c..4b4865f79 100644 --- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java +++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java @@ -54,16 +54,35 @@ import com.google.cloud.kms.v1.KeyManagementServiceGrpc.KeyManagementServiceBlockingStub; import com.google.cloud.kms.v1.KeyRingName; import com.google.cloud.kms.v1.LocationName; -import com.google.cloud.storage.*; +import com.google.cloud.storage.Acl; import com.google.cloud.storage.Acl.Role; import com.google.cloud.storage.Acl.User; +import com.google.cloud.storage.Blob; +import com.google.cloud.storage.BlobId; +import com.google.cloud.storage.BlobInfo; +import com.google.cloud.storage.Bucket; +import com.google.cloud.storage.BucketInfo; import com.google.cloud.storage.BucketInfo.LifecycleRule; import com.google.cloud.storage.BucketInfo.LifecycleRule.LifecycleAction; import com.google.cloud.storage.BucketInfo.LifecycleRule.LifecycleCondition; +import com.google.cloud.storage.CopyWriter; +import com.google.cloud.storage.Cors; +import com.google.cloud.storage.HmacKey; +import com.google.cloud.storage.HttpMethod; +import com.google.cloud.storage.PostPolicyV4; import com.google.cloud.storage.PostPolicyV4.PostFieldsV4; +import com.google.cloud.storage.Rpo; +import com.google.cloud.storage.ServiceAccount; +import com.google.cloud.storage.Storage; import com.google.cloud.storage.Storage.BlobField; import com.google.cloud.storage.Storage.BlobWriteOption; import com.google.cloud.storage.Storage.BucketField; +import com.google.cloud.storage.StorageBatch; +import com.google.cloud.storage.StorageBatchResult; +import com.google.cloud.storage.StorageClass; +import com.google.cloud.storage.StorageException; +import com.google.cloud.storage.StorageOptions; +import com.google.cloud.storage.StorageRoles; import com.google.cloud.storage.spi.StorageRpcFactory; import com.google.cloud.storage.spi.v1.StorageRpc; import com.google.cloud.storage.spi.v1.StorageRpc.Option; @@ -3926,11 +3945,9 @@ protected Object handleInvocation( public void testRpoConfig() { String rpoBucket = RemoteStorageHelper.generateBucketName(); try { - Bucket bucket = storage.create( - BucketInfo.newBuilder(rpoBucket) - .setLocation("NAM4") - .setRpo(Rpo.ASYNC_TURBO) - .build()); + Bucket bucket = + storage.create( + BucketInfo.newBuilder(rpoBucket).setLocation("NAM4").setRpo(Rpo.ASYNC_TURBO).build()); assertEquals("ASYNC_TURBO", bucket.getRpo().toString()); bucket.toBuilder().setRpo(Rpo.DEFAULT).build().update(); From 1edd21687690e0423593dccbff1d07f630cb7da8 Mon Sep 17 00:00:00 2001 From: JesseLovelace <43148100+JesseLovelace@users.noreply.github.com> Date: Mon, 25 Oct 2021 14:41:58 -0700 Subject: [PATCH 3/6] Apply suggestions from code review Co-authored-by: BenWhitehead --- .../src/main/java/com/google/cloud/storage/Rpo.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java index b99c7cec0..b4c8e4104 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java @@ -26,7 +26,7 @@ * @see https://cloud.google.com/storage/docs/turbo-replication */ -public class Rpo extends StringEnumValue { +public final class Rpo extends StringEnumValue { private static final long serialVersionUID = -3954216195295821508L; @@ -36,7 +36,7 @@ private Rpo(String constant) { private static final ApiFunction CONSTRUCTOR = Rpo::new; - private static final StringEnumType type = new StringEnumType(Rpo.class, CONSTRUCTOR); + private static final StringEnumType type = new StringEnumType<>(Rpo.class, CONSTRUCTOR); /** * Default recovery point objective. With this setting, there is no guarantee on the amount of From 3861b3764c410d9a454c8295221945ee55dc6c4e Mon Sep 17 00:00:00 2001 From: JesseLovelace <43148100+JesseLovelace@users.noreply.github.com> Date: Fri, 19 Nov 2021 14:57:05 -0800 Subject: [PATCH 4/6] typo --- .../src/main/java/com/google/cloud/storage/Rpo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java index b99c7cec0..1e155abb5 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Rpo.java @@ -21,7 +21,7 @@ /** * Enums for the Recovery Point Objective (RPO) of dual-region buckets, which determines how fast - * data is replicated betweens regions. + * data is replicated between regions. * * @see https://cloud.google.com/storage/docs/turbo-replication From ce47c976088d1916b6800e2ae9929ebbb5e5dedc Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Mon, 10 Jan 2022 21:12:40 +0000 Subject: [PATCH 5/6] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 42a0678cd..9c0c0ab4a 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ If you are using Maven without BOM, add this to your dependencies: If you are using Gradle 5.x or later, add this to your dependencies ```Groovy -implementation platform('com.google.cloud:libraries-bom:24.1.2') +implementation platform('com.google.cloud:libraries-bom:24.2.0') implementation 'com.google.cloud:google-cloud-storage' ``` From 38d38e8afc7327e64637e0bd3f109fdbdc53b548 Mon Sep 17 00:00:00 2001 From: JesseLovelace <43148100+JesseLovelace@users.noreply.github.com> Date: Wed, 12 Jan 2022 11:30:49 -0800 Subject: [PATCH 6/6] fix clirr --- google-cloud-storage/clirr-ignored-differences.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/google-cloud-storage/clirr-ignored-differences.xml b/google-cloud-storage/clirr-ignored-differences.xml index 44f6eb201..c45b439cc 100644 --- a/google-cloud-storage/clirr-ignored-differences.xml +++ b/google-cloud-storage/clirr-ignored-differences.xml @@ -5,6 +5,7 @@ com/google/cloud/storage/BucketInfo$Builder com.google.cloud.storage.BucketInfo$Builder setRpo(com.google.cloud.storage.Rpo) 7013 + com/google/cloud/storage/BucketInfo$LifecycleRule$LifecycleAction BucketInfo$LifecycleRule$LifecycleAction()