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: adds bucket restore support #2806

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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 @@ -744,6 +744,24 @@ public Builder setSoftDeletePolicy(SoftDeletePolicy softDeletePolicy) {
return this;
}

@Override
BucketInfo.Builder setGeneration(long generation) {
infoBuilder.setGeneration(generation);
return this;
}

@Override
BucketInfo.Builder setSoftDeleteTime(OffsetDateTime softDeleteTime) {
infoBuilder.setSoftDeleteTime(softDeleteTime);
return this;
}

@Override
BucketInfo.Builder setHardDeleteTime(OffsetDateTime hardDeleteTime) {
infoBuilder.setHardDeleteTime(hardDeleteTime);
return this;
}

@Override
public Builder setHierarchicalNamespace(HierarchicalNamespace hierarchicalNamespace) {
infoBuilder.setHierarchicalNamespace(hierarchicalNamespace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,10 @@ public class BucketInfo implements Serializable {
private final CustomPlacementConfig customPlacementConfig;
private final ObjectRetention objectRetention;
private final HierarchicalNamespace hierarchicalNamespace;

private final SoftDeletePolicy softDeletePolicy;
private final long generation;
private final OffsetDateTime softDeleteTime;
private final OffsetDateTime hardDeleteTime;

private final transient ImmutableSet<NamedField> modifiedFields;

Expand Down Expand Up @@ -1841,6 +1843,12 @@ public Builder setRetentionPeriodDuration(Duration retentionPeriod) {

public abstract Builder setSoftDeletePolicy(SoftDeletePolicy softDeletePolicy);

abstract Builder setGeneration(long generation);

abstract Builder setSoftDeleteTime(OffsetDateTime softDeleteTime);

abstract Builder setHardDeleteTime(OffsetDateTime hardDeleteTime);

/** Creates a {@code BucketInfo} object. */
public abstract BucketInfo build();

Expand Down Expand Up @@ -1939,9 +1947,11 @@ static final class BuilderImpl extends Builder {
private Logging logging;
private CustomPlacementConfig customPlacementConfig;
private ObjectRetention objectRetention;

private SoftDeletePolicy softDeletePolicy;
private HierarchicalNamespace hierarchicalNamespace;
private long generation;
private OffsetDateTime softDeleteTime;
private OffsetDateTime hardDeleteTime;
private final ImmutableSet.Builder<NamedField> modifiedFields = ImmutableSet.builder();

BuilderImpl(String name) {
Expand Down Expand Up @@ -1983,6 +1993,9 @@ static final class BuilderImpl extends Builder {
objectRetention = bucketInfo.objectRetention;
softDeletePolicy = bucketInfo.softDeletePolicy;
hierarchicalNamespace = bucketInfo.hierarchicalNamespace;
generation = bucketInfo.getGeneration();
softDeleteTime = bucketInfo.getSoftDeleteTime();
hardDeleteTime = bucketInfo.getHardDeleteTime();
}

@Override
Expand Down Expand Up @@ -2366,6 +2379,33 @@ public Builder setHierarchicalNamespace(HierarchicalNamespace hierarchicalNamesp
return this;
}

@Override
Builder setGeneration(long generation) {
if (!Objects.equals(this.generation, generation)) {
modifiedFields.add(BucketField.GENERATION);
}
this.generation = generation;
return this;
}

@Override
Builder setSoftDeleteTime(OffsetDateTime softDeleteTime) {
if (!Objects.equals(this.softDeleteTime, softDeleteTime)) {
modifiedFields.add(BucketField.SOFT_DELETE_TIME);
}
this.softDeleteTime = softDeleteTime;
return this;
}

@Override
Builder setHardDeleteTime(OffsetDateTime hardDeleteTime) {
if (!Objects.equals(this.hardDeleteTime, hardDeleteTime)) {
modifiedFields.add(BucketField.HARD_DELETE_TIME);
}
this.hardDeleteTime = hardDeleteTime;
return this;
}

@Override
Builder setLocationType(String locationType) {
if (!Objects.equals(this.locationType, locationType)) {
Expand Down Expand Up @@ -2609,6 +2649,9 @@ private Builder clearDeleteLifecycleRules() {
objectRetention = builder.objectRetention;
softDeletePolicy = builder.softDeletePolicy;
hierarchicalNamespace = builder.hierarchicalNamespace;
generation = builder.generation;
softDeleteTime = builder.softDeleteTime;
hardDeleteTime = builder.hardDeleteTime;
modifiedFields = builder.modifiedFields.build();
}

Expand Down Expand Up @@ -2959,6 +3002,21 @@ public HierarchicalNamespace getHierarchicalNamespace() {
return hierarchicalNamespace;
}

/** Returns the generation of this bucket */
public long getGeneration() {
return generation;
}

/** If this bucket is soft-deleted, returns the time it was soft-deleted */
public OffsetDateTime getSoftDeleteTime() {
return softDeleteTime;
}

/** If this bucket is soft-deleted, returns the time it will be hard-deleted */
public OffsetDateTime getHardDeleteTime() {
return hardDeleteTime;
}

/** Returns a builder for the current bucket. */
public Builder toBuilder() {
return new BuilderImpl(this);
Expand Down Expand Up @@ -2998,6 +3056,9 @@ public int hashCode() {
objectRetention,
softDeletePolicy,
hierarchicalNamespace,
generation,
softDeleteTime,
hardDeleteTime,
logging);
}

Expand Down Expand Up @@ -3041,6 +3102,9 @@ public boolean equals(Object o) {
&& Objects.equals(objectRetention, that.objectRetention)
&& Objects.equals(softDeletePolicy, that.softDeletePolicy)
&& Objects.equals(hierarchicalNamespace, that.hierarchicalNamespace)
&& Objects.equals(generation, that.getGeneration())
&& Objects.equals(softDeleteTime, that.getSoftDeleteTime())
&& Objects.equals(hardDeleteTime, that.getHardDeleteTime())
&& Objects.equals(logging, that.logging);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,11 @@ public Blob restore(BlobId blob, BlobRestoreOption... options) {
return internalObjectRestore(blob, unwrap);
}

@Override
public void restore(String bucket, long generation, BucketRestoreOption... options) {
// todo: implement when grpc is available
}

private Blob internalObjectRestore(BlobId blobId, Opts<ObjectSourceOpt> opts) {
Opts<ObjectSourceOpt> finalOpts = opts.prepend(defaultOpts).prepend(ALL_BLOB_FIELDS);
GrpcCallContext grpcCallContext =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ public ResultRetryAlgorithm<?> getForObjectsRestore(
return retryStrategy.getIdempotentHandler();
}

public ResultRetryAlgorithm<?> getForBucketRestore(
String bucket, Map<StorageRpc.Option, ?> optionsMap) {
return retryStrategy.getIdempotentHandler();
}

public ResultRetryAlgorithm<?> getForObjectsUpdate(
StorageObject pb, Map<StorageRpc.Option, ?> optionsMap) {
return optionsMap.containsKey(StorageRpc.Option.IF_METAGENERATION_MATCH)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,9 @@ private Bucket bucketInfoEncode(BucketInfo from) {
ifNonNull(from.getStorageClass(), StorageClass::toString, to::setStorageClass);
ifNonNull(from.getUpdateTimeOffsetDateTime(), dateTimeCodec::encode, to::setUpdated);
ifNonNull(from.versioningEnabled(), b -> new Versioning().setEnabled(b), to::setVersioning);
ifNonNull(from.getGeneration(), to::setGeneration);
ifNonNull(from.getSoftDeleteTime(), dateTimeCodec::encode, to::setSoftDeleteTime);
ifNonNull(from.getHardDeleteTime(), dateTimeCodec::encode, to::setHardDeleteTime);
to.setEtag(from.getEtag());
to.setId(from.getGeneratedId());
to.setName(from.getName());
Expand Down Expand Up @@ -527,6 +530,9 @@ private BucketInfo bucketInfoDecode(com.google.api.services.storage.model.Bucket
to::setHierarchicalNamespace);
ifNonNull(from.getObjectRetention(), this::objectRetentionDecode, to::setObjectRetention);
ifNonNull(from.getSoftDeletePolicy(), this::softDeletePolicyDecode, to::setSoftDeletePolicy);
ifNonNull(from.getGeneration(), to::setGeneration);
ifNonNull(from.getSoftDeleteTime(), dateTimeCodec::decode, to::setSoftDeleteTime);
ifNonNull(from.getHardDeleteTime(), dateTimeCodec::decode, to::setHardDeleteTime);
return to.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Objects.requireNonNull;

import com.google.api.client.util.DateTime;
import com.google.api.core.BetaApi;
import com.google.api.core.InternalApi;
import com.google.api.core.InternalExtensionOnly;
Expand Down Expand Up @@ -187,7 +188,16 @@ enum BucketField implements FieldSelector, NamedField {
SOFT_DELETE_POLICY(
"softDeletePolicy",
"soft_delete_policy",
com.google.api.services.storage.model.Bucket.SoftDeletePolicy.class);
com.google.api.services.storage.model.Bucket.SoftDeletePolicy.class),

@TransportCompatibility({Transport.HTTP, Transport.GRPC})
GENERATION("generation", "generation", Long.class),

@TransportCompatibility({Transport.HTTP, Transport.GRPC})
SOFT_DELETE_TIME("softDeleteTime", "soft_delete_time", DateTime.class),

@TransportCompatibility({Transport.HTTP, Transport.GRPC})
HARD_DELETE_TIME("hardDeleteTime", "hard_delete_time", DateTime.class);

static final List<BucketField> REQUIRED_FIELDS = ImmutableList.of(NAME);
private static final Map<String, BucketField> JSON_FIELD_NAME_INDEX;
Expand Down Expand Up @@ -910,6 +920,21 @@ public static BucketGetOption userProject(@NonNull String userProject) {
return new BucketGetOption(UnifiedOpts.userProject(userProject));
}

/**
* Returns an option for this bucket's generation. Should only be specified when getting a
* soft-deleted bucket
*/
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
public static BucketGetOption generation(long generation) {
return new BucketGetOption(UnifiedOpts.generation(generation));
}

/** Returns an option that must be true if getting a soft-deleted bucket. */
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
public static BucketGetOption softDeleted(boolean softDeleted) {
return new BucketGetOption(UnifiedOpts.softDeleted(softDeleted));
}

/**
* Returns an option to specify the bucket's fields to be returned by the RPC call. If this
* option is not provided all bucket's fields are returned. {@code BucketGetOption.fields}) can
Expand Down Expand Up @@ -1743,6 +1768,49 @@ public static BlobRestoreOption copySourceAcl(boolean copySourceAcl) {
}
}

class BucketRestoreOption extends Option<BucketSourceOpt> {
private static final long serialVersionUID = 1422014464162702152L;

BucketRestoreOption(BucketSourceOpt opt) {
super(opt);
}

/**
* Returns an option to define the projection in the API request. In some cases this option may
* be needed to be set to `noAcl` to omit ACL data from the response. The default value is
* `full`
*/
public static BucketRestoreOption projection(String projection) {
return new BucketRestoreOption(UnifiedOpts.projection(projection));
}

/**
* Returns an option to specify the bucket's fields to be returned by the RPC call. If this
* option is not provided all bucket's fields are returned. {@code BucketGetOption.fields}) can
* be used to specify only the fields of interest. Bucket name is always returned, even if not
* specified.
*/
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
public static BucketRestoreOption fields(BucketField... fields) {
requireNonNull(fields, "fields must be non null");
ImmutableSet<NamedField> set =
ImmutableSet.<NamedField>builder()
.addAll(BucketField.REQUIRED_FIELDS)
.add(fields)
.build();
return new BucketRestoreOption(UnifiedOpts.fields(set));
}

/**
* Returns an option for bucket's billing user project. This option is only used by the buckets
* with 'requester_pays' flag.
*/
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
public static BucketRestoreOption userProject(@NonNull String userProject) {
return new BucketRestoreOption(UnifiedOpts.userProject(userProject));
}
}

/** Class for specifying bucket list options. */
class BucketListOption extends Option<BucketListOpt> {

Expand Down Expand Up @@ -1782,6 +1850,12 @@ public static BucketListOption userProject(@NonNull String userProject) {
return new BucketListOption(UnifiedOpts.userProject(userProject));
}

/** Returns an option for whether to return soft-deleted buckets. */
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
public static BucketListOption softDeleted(boolean softDeleted) {
return new BucketListOption(UnifiedOpts.softDeleted(softDeleted));
}

/**
* Returns an option to specify the bucket's fields to be returned by the RPC call. If this
* option is not provided all bucket's fields are returned. {@code BucketListOption.fields}) can
Expand Down Expand Up @@ -3193,6 +3267,20 @@ Blob createFrom(
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
Blob restore(BlobId blob, BlobRestoreOption... options);

/**
* Restores a soft-deleted bucket to full bucket status.
*
* <p>Example of restoring a bucket.
*
* <pre>{@code
* String bucketName = "my-unique-bucket";
* long generation = 42;
* storage.restore(bucketName, generation);
* }</pre>
*/
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
void restore(String bucket, long generation, BucketRestoreOption... options);

/**
* Lists the project's buckets.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,19 @@ public Page<Blob> list(final String bucket, BlobListOption... options) {
return listBlobs(bucket, getOptions(), optionsMap);
}

@Override
public void restore(String bucket, long generation, BucketRestoreOption... options) {
ImmutableMap<StorageRpc.Option, ?> optionsMap = Opts.unwrap(options).getRpcOptions();

final com.google.api.services.storage.model.Bucket bucketPb =
codecs.bucketInfo().encode(BucketInfo.of(bucket)).setGeneration(generation);

ResultRetryAlgorithm<?> algorithm =
retryAlgorithmManager.getForBucketRestore(bucket, optionsMap);

run(algorithm, callable(() -> storageRpc.restore(bucketPb, optionsMap)), Function.identity());
}

private static Page<Bucket> listBuckets(
final HttpStorageOptions serviceOptions, final Map<StorageRpc.Option, ?> optionsMap) {
ResultRetryAlgorithm<?> algorithm =
Expand Down
Loading
Loading