From a13499453932189d3b4efdbb8d774e6d15a96cc1 Mon Sep 17 00:00:00 2001 From: BenWhitehead Date: Wed, 18 Oct 2023 14:39:20 -0400 Subject: [PATCH] feat: add Autoclass v2.1 support (#2258) --- .../cloud/storage/ApiaryConversions.java | 10 +++ .../com/google/cloud/storage/BucketInfo.java | 79 ++++++++++++++++--- .../google/cloud/storage/GrpcConversions.java | 14 ++++ .../google/cloud/storage/it/ITBucketTest.java | 47 +++++++++++ 4 files changed, 137 insertions(+), 13 deletions(-) diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/ApiaryConversions.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/ApiaryConversions.java index 2fd275e8b..7226267e3 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/ApiaryConversions.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/ApiaryConversions.java @@ -484,6 +484,11 @@ private Bucket.Autoclass autoclassEncode(Autoclass from) { Bucket.Autoclass to = new Bucket.Autoclass(); ifNonNull(from.getEnabled(), to::setEnabled); ifNonNull(from.getToggleTime(), dateTimeCodec::encode, to::setToggleTime); + ifNonNull(from.getTerminalStorageClass(), StorageClass::toString, to::setTerminalStorageClass); + ifNonNull( + from.getTerminalStorageClassUpdateTime(), + dateTimeCodec::encode, + to::setTerminalStorageClassUpdateTime); return to; } @@ -491,6 +496,11 @@ private Autoclass autoclassDecode(Bucket.Autoclass from) { Autoclass.Builder to = Autoclass.newBuilder(); to.setEnabled(from.getEnabled()); ifNonNull(from.getToggleTime(), dateTimeCodec::decode, to::setToggleTime); + ifNonNull(from.getTerminalStorageClass(), StorageClass::valueOf, to::setTerminalStorageClass); + ifNonNull( + from.getTerminalStorageClassUpdateTime(), + dateTimeCodec::decode, + to::setTerminalStorageClassUpdateTime); return to.build(); } 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 bb7780c01..a4d526291 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 @@ -344,11 +344,26 @@ public String toString() { } } + /** + * Configuration for the Autoclass settings of a bucket. + * + * @see https://cloud.google.com/storage/docs/autoclass + */ public static final class Autoclass implements Serializable { private static final long serialVersionUID = -2378172222188072439L; - private Boolean enabled; - private OffsetDateTime toggleTime; + private final Boolean enabled; + private final OffsetDateTime toggleTime; + private final StorageClass terminalStorageClass; + private final OffsetDateTime terminalStorageClassUpdateTime; + + private Autoclass(Builder builder) { + this.enabled = builder.enabled; + this.toggleTime = builder.toggleTime; + this.terminalStorageClass = builder.terminalStorageClass; + this.terminalStorageClassUpdateTime = builder.terminalStorageClassUpdateTime; + } public Boolean getEnabled() { return enabled; @@ -358,6 +373,14 @@ public OffsetDateTime getToggleTime() { return toggleTime; } + public StorageClass getTerminalStorageClass() { + return terminalStorageClass; + } + + public OffsetDateTime getTerminalStorageClassUpdateTime() { + return terminalStorageClassUpdateTime; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -366,13 +389,18 @@ public boolean equals(Object o) { if (!(o instanceof Autoclass)) { return false; } - Autoclass that = (Autoclass) o; - return Objects.equals(enabled, that.enabled) && Objects.equals(toggleTime, that.toggleTime); + Autoclass autoclass = (Autoclass) o; + return Objects.equals(enabled, autoclass.enabled) + && Objects.equals(toggleTime, autoclass.toggleTime) + && Objects.equals(terminalStorageClass, autoclass.terminalStorageClass) + && Objects.equals( + terminalStorageClassUpdateTime, autoclass.terminalStorageClassUpdateTime); } @Override public int hashCode() { - return Objects.hash(enabled, toggleTime); + return Objects.hash( + enabled, toggleTime, terminalStorageClass, terminalStorageClassUpdateTime); } @Override @@ -380,27 +408,28 @@ public String toString() { return MoreObjects.toStringHelper(this) .add("enabled", enabled) .add("toggleTime", toggleTime) + .add("terminalStorageClass", terminalStorageClass) + .add("terminalStorageClassUpdateTime", terminalStorageClassUpdateTime) .toString(); } - private Autoclass() {} - - private Autoclass(Builder builder) { - this.enabled = builder.enabled; - this.toggleTime = builder.toggleTime; - } - public static Builder newBuilder() { return new Builder(); } public Builder toBuilder() { - return newBuilder().setEnabled(enabled).setToggleTime(toggleTime); + return newBuilder() + .setEnabled(enabled) + .setToggleTime(toggleTime) + .setTerminalStorageClass(terminalStorageClass) + .setTerminalStorageClassUpdateTime(terminalStorageClassUpdateTime); } public static final class Builder { private Boolean enabled; private OffsetDateTime toggleTime; + private StorageClass terminalStorageClass; + private OffsetDateTime terminalStorageClassUpdateTime; /** * Sets whether Autoclass is enabled for this bucket. Currently, autoclass can only be enabled @@ -421,6 +450,30 @@ Builder setToggleTime(OffsetDateTime toggleTime) { return this; } + /** + * When set to {@link StorageClass#NEARLINE}, Autoclass restricts transitions between Standard + * and Nearline storage classes only. + * + *

When set to {@link StorageClass#ARCHIVE}, Autoclass allows transitions to Coldline and + * Archive as well. + * + *

Only valid values are {@code NEARLINE} and {@code ARCHIVE}. + */ + public Builder setTerminalStorageClass(StorageClass terminalStorageClass) { + this.terminalStorageClass = terminalStorageClass; + return this; + } + + /** + * The time at which Autoclass terminal storage class was last updated for this bucket. + * + *

This is auto populated when the feature is enabled. + */ + Builder setTerminalStorageClassUpdateTime(OffsetDateTime terminalStorageClassUpdateTime) { + this.terminalStorageClassUpdateTime = terminalStorageClassUpdateTime; + return this; + } + public Autoclass build() { return new Autoclass(this); } diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcConversions.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcConversions.java index 38766b946..9ddf229c5 100644 --- a/google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcConversions.java +++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcConversions.java @@ -565,6 +565,15 @@ private BucketInfo.Autoclass autoclassDecode(Bucket.Autoclass from) { BucketInfo.Autoclass.Builder to = BucketInfo.Autoclass.newBuilder(); to.setEnabled(from.getEnabled()); ifNonNull(from.getToggleTime(), timestampCodec::decode, to::setToggleTime); + + String terminalStorageClass = from.getTerminalStorageClass(); + if (!terminalStorageClass.isEmpty()) { + to.setTerminalStorageClass(StorageClass.valueOf(terminalStorageClass)); + } + ifNonNull( + from.getTerminalStorageClassUpdateTime(), + timestampCodec::decode, + to::setTerminalStorageClassUpdateTime); return to.build(); } @@ -572,6 +581,11 @@ private Bucket.Autoclass autoclassEncode(BucketInfo.Autoclass from) { Bucket.Autoclass.Builder to = Bucket.Autoclass.newBuilder(); ifNonNull(from.getEnabled(), to::setEnabled); ifNonNull(from.getToggleTime(), timestampCodec::encode, to::setToggleTime); + ifNonNull(from.getTerminalStorageClass(), StorageClass::toString, to::setTerminalStorageClass); + ifNonNull( + from.getTerminalStorageClassUpdateTime(), + timestampCodec::encode, + to::setTerminalStorageClassUpdateTime); return to.build(); } diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITBucketTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITBucketTest.java index 240f5d6ca..f5b2b00c5 100644 --- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITBucketTest.java +++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITBucketTest.java @@ -42,6 +42,7 @@ import com.google.cloud.storage.Storage.BucketGetOption; import com.google.cloud.storage.Storage.BucketListOption; import com.google.cloud.storage.Storage.BucketTargetOption; +import com.google.cloud.storage.StorageClass; import com.google.cloud.storage.TransportCompatibility.Transport; import com.google.cloud.storage.it.runner.StorageITRunner; import com.google.cloud.storage.it.runner.annotations.Backend; @@ -58,6 +59,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.StreamSupport; import org.junit.Ignore; import org.junit.Test; @@ -417,6 +419,51 @@ public void testCreateBucketWithAutoclass() { } } + @Test + public void testCreateBucketWithAutoclass_ARCHIVE() throws Exception { + String bucketName = generator.randomBucketName(); + Autoclass autoclass = + Autoclass.newBuilder() + .setEnabled(true) + .setTerminalStorageClass(StorageClass.ARCHIVE) + .build(); + BucketInfo info = BucketInfo.newBuilder(bucketName).setAutoclass(autoclass).build(); + try (TemporaryBucket tmpb = + TemporaryBucket.newBuilder().setStorage(storage).setBucketInfo(info).build()) { + BucketInfo remoteBucket = tmpb.getBucket(); + + Autoclass remoteBucketAutoclass = remoteBucket.getAutoclass(); + assertThat(remoteBucketAutoclass).isNotNull(); + assertThat(remoteBucketAutoclass.getEnabled()).isTrue(); + assertThat(remoteBucketAutoclass.getToggleTime()).isNotNull(); + assertThat(remoteBucketAutoclass.getTerminalStorageClassUpdateTime()).isNotNull(); + assertThat(remoteBucketAutoclass.getTerminalStorageClass()).isEqualTo(StorageClass.ARCHIVE); + + Page bucketPage = storage.list(BucketListOption.prefix(bucketName)); + ImmutableList buckets = ImmutableList.copyOf(bucketPage.iterateAll()); + + Optional first = + buckets.stream().filter(b -> bucketName.equals(b.getName())).findFirst(); + + assertThat(first.isPresent()).isTrue(); + assertThat(first.get().getAutoclass().getTerminalStorageClass()) + .isEqualTo(StorageClass.ARCHIVE); + + BucketInfo disabled = + remoteBucket + .toBuilder() + .setAutoclass(Autoclass.newBuilder().setEnabled(false).build()) + .build(); + Bucket updated = storage.update(disabled, BucketTargetOption.metagenerationMatch()); + + Autoclass updatedAutoclass = updated.getAutoclass(); + assertThat(updatedAutoclass.getEnabled()).isFalse(); + assertThat(updatedAutoclass.getTerminalStorageClass()).isNull(); + + assertThat(updatedAutoclass).isNotEqualTo(remoteBucketAutoclass); + } + } + @Test public void testUpdateBucket_noModification() throws Exception { String bucketName = generator.randomBucketName();