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

chore(revert): Revert "feat: add support for restore token (#1369)" #1373

Merged
merged 1 commit into from
Nov 7, 2024
Merged
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
10 changes: 0 additions & 10 deletions google/cloud/storage/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,6 @@ def reload(
timeout=_DEFAULT_TIMEOUT,
retry=DEFAULT_RETRY,
soft_deleted=None,
restore_token=None,
):
"""Reload properties from Cloud Storage.

Expand Down Expand Up @@ -279,13 +278,6 @@ def reload(
the object metadata if the object exists and is in a soft-deleted state.
:attr:`generation` is required to be set on the blob if ``soft_deleted`` is set to True.
See: https://cloud.google.com/storage/docs/soft-delete

:type restore_token: str
:param restore_token:
(Optional) The restore_token is required to retrieve a soft-deleted object only if
its name and generation value do not uniquely identify it, and hierarchical namespace
is enabled on the bucket. Otherwise, this parameter is optional.
See: https://cloud.google.com/storage/docs/json_api/v1/objects/get
"""
client = self._require_client(client)
query_params = self._query_params
Expand All @@ -304,8 +296,6 @@ def reload(
# Soft delete reload requires a generation, even for targets
# that don't include them in default query params (buckets).
query_params["generation"] = self.generation
if restore_token is not None:
query_params["restoreToken"] = restore_token
headers = self._encryption_headers()
_add_etag_match_headers(
headers, if_etag_match=if_etag_match, if_etag_not_match=if_etag_not_match
Expand Down
23 changes: 0 additions & 23 deletions google/cloud/storage/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,6 @@ def exists(
timeout=_DEFAULT_TIMEOUT,
retry=DEFAULT_RETRY,
soft_deleted=None,
restore_token=None,
):
"""Determines whether or not this blob exists.

Expand Down Expand Up @@ -705,13 +704,6 @@ def exists(
:attr:`generation` is required to be set on the blob if ``soft_deleted`` is set to True.
See: https://cloud.google.com/storage/docs/soft-delete

:type restore_token: str
:param restore_token:
(Optional) The restore_token is required to retrieve a soft-deleted object only if
its name and generation value do not uniquely identify it, and hierarchical namespace
is enabled on the bucket. Otherwise, this parameter is optional.
See: https://cloud.google.com/storage/docs/json_api/v1/objects/get

:rtype: bool
:returns: True if the blob exists in Cloud Storage.
"""
Expand All @@ -722,8 +714,6 @@ def exists(
query_params["fields"] = "name"
if soft_deleted is not None:
query_params["softDeleted"] = soft_deleted
if restore_token is not None:
query_params["restoreToken"] = restore_token

_add_generation_match_parameters(
query_params,
Expand Down Expand Up @@ -4804,19 +4794,6 @@ def hard_delete_time(self):
if hard_delete_time is not None:
return _rfc3339_nanos_to_datetime(hard_delete_time)

@property
def restore_token(self):
"""The restore token, a universally unique identifier (UUID), along with the object's
name and generation value, uniquely identifies a soft-deleted object.
This field is only returned for soft-deleted objects in hierarchical namespace buckets.

:rtype: string or ``NoneType``
:returns:
(readonly) The restore token used to differentiate soft-deleted objects with the same name and generation.
This field is only returned for soft-deleted objects in hierarchical namespace buckets.
"""
return self._properties.get("restoreToken")


def _get_host_name(connection):
"""Returns the host name from the given connection.
Expand Down
19 changes: 0 additions & 19 deletions google/cloud/storage/bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -1256,7 +1256,6 @@ def get_blob(
timeout=_DEFAULT_TIMEOUT,
retry=DEFAULT_RETRY,
soft_deleted=None,
restore_token=None,
**kwargs,
):
"""Get a blob object by name.
Expand Down Expand Up @@ -1324,13 +1323,6 @@ def get_blob(
Object ``generation`` is required if ``soft_deleted`` is set to True.
See: https://cloud.google.com/storage/docs/soft-delete

:type restore_token: str
:param restore_token:
(Optional) The restore_token is required to retrieve a soft-deleted object only if
its name and generation value do not uniquely identify it, and hierarchical namespace
is enabled on the bucket. Otherwise, this parameter is optional.
See: https://cloud.google.com/storage/docs/json_api/v1/objects/get

:param kwargs: Keyword arguments to pass to the
:class:`~google.cloud.storage.blob.Blob` constructor.

Expand Down Expand Up @@ -1359,7 +1351,6 @@ def get_blob(
if_metageneration_not_match=if_metageneration_not_match,
retry=retry,
soft_deleted=soft_deleted,
restore_token=restore_token,
)
except NotFound:
return None
Expand Down Expand Up @@ -2208,7 +2199,6 @@ def restore_blob(
generation=None,
copy_source_acl=None,
projection=None,
restore_token=None,
if_generation_match=None,
if_generation_not_match=None,
if_metageneration_match=None,
Expand Down Expand Up @@ -2239,13 +2229,6 @@ def restore_blob(
:param projection: (Optional) Specifies the set of properties to return.
If used, must be 'full' or 'noAcl'.

:type restore_token: str
:param restore_token:
(Optional) The restore_token is required to restore a soft-deleted object
only if its name and generation value do not uniquely identify it, and hierarchical namespace
is enabled on the bucket. Otherwise, this parameter is optional.
See: https://cloud.google.com/storage/docs/json_api/v1/objects/restore

:type if_generation_match: long
:param if_generation_match:
(Optional) See :ref:`using-if-generation-match`
Expand Down Expand Up @@ -2293,8 +2276,6 @@ def restore_blob(
query_params["copySourceAcl"] = copy_source_acl
if projection is not None:
query_params["projection"] = projection
if restore_token is not None:
query_params["restoreToken"] = restore_token

_add_generation_match_parameters(
query_params,
Expand Down
54 changes: 1 addition & 53 deletions tests/system/test_bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -1232,7 +1232,7 @@ def test_soft_delete_policy(
assert restored_blob.generation != gen

# Patch the soft delete policy on an existing bucket.
new_duration_secs = 0
new_duration_secs = 10 * 86400
bucket.soft_delete_policy.retention_duration_seconds = new_duration_secs
bucket.patch()
assert bucket.soft_delete_policy.retention_duration_seconds == new_duration_secs
Expand Down Expand Up @@ -1265,55 +1265,3 @@ def test_new_bucket_with_hierarchical_namespace(
bucket = storage_client.create_bucket(bucket_obj)
buckets_to_delete.append(bucket)
assert bucket.hierarchical_namespace_enabled is True


def test_restore_token(
storage_client,
buckets_to_delete,
blobs_to_delete,
):
# Create HNS bucket with soft delete policy.
duration_secs = 7 * 86400
bucket = storage_client.bucket(_helpers.unique_name("w-soft-delete"))
bucket.hierarchical_namespace_enabled = True
bucket.iam_configuration.uniform_bucket_level_access_enabled = True
bucket.soft_delete_policy.retention_duration_seconds = duration_secs
bucket = _helpers.retry_429_503(storage_client.create_bucket)(bucket)
buckets_to_delete.append(bucket)

# Insert an object and delete it to enter soft-deleted state.
payload = b"DEADBEEF"
blob_name = _helpers.unique_name("soft-delete")
blob = bucket.blob(blob_name)
blob.upload_from_string(payload)
# blob = bucket.get_blob(blob_name)
gen = blob.generation
blob.delete()

# Get the soft-deleted object and restore token.
blob = bucket.get_blob(blob_name, generation=gen, soft_deleted=True)
restore_token = blob.restore_token

# List and get soft-deleted object that includes restore token.
all_blobs = list(bucket.list_blobs(soft_deleted=True))
assert all_blobs[0].restore_token is not None
blob_w_restore_token = bucket.get_blob(
blob_name, generation=gen, soft_deleted=True, restore_token=restore_token
)
assert blob_w_restore_token.soft_delete_time is not None
assert blob_w_restore_token.hard_delete_time is not None
assert blob_w_restore_token.restore_token is not None

# Restore the soft-deleted object using the restore token.
restored_blob = bucket.restore_blob(
blob_name, generation=gen, restore_token=restore_token
)
blobs_to_delete.append(restored_blob)
assert restored_blob.exists() is True
assert restored_blob.generation != gen

# Patch the soft delete policy on the bucket.
new_duration_secs = 0
bucket.soft_delete_policy.retention_duration_seconds = new_duration_secs
bucket.patch()
assert bucket.soft_delete_policy.retention_duration_seconds == new_duration_secs
18 changes: 2 additions & 16 deletions tests/unit/test_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -784,25 +784,21 @@ def test_exists_hit_w_generation_w_retry(self):
_target_object=None,
)

def test_exists_hit_w_gen_soft_deleted_restore_token(self):
def test_exists_hit_w_generation_w_soft_deleted(self):
blob_name = "blob-name"
generation = 123456
restore_token = "88ba0d97-639e-5902"
api_response = {"name": blob_name}
client = mock.Mock(spec=["_get_resource"])
client._get_resource.return_value = api_response
bucket = _Bucket(client)
blob = self._make_one(blob_name, bucket=bucket, generation=generation)

self.assertTrue(
blob.exists(retry=None, soft_deleted=True, restore_token=restore_token)
)
self.assertTrue(blob.exists(retry=None, soft_deleted=True))

expected_query_params = {
"fields": "name",
"generation": generation,
"softDeleted": True,
"restoreToken": restore_token,
}
expected_headers = {}
client._get_resource.assert_called_once_with(
Expand Down Expand Up @@ -5874,16 +5870,6 @@ def test_soft_hard_delete_time_getter(self):
self.assertEqual(blob.soft_delete_time, soft_timstamp)
self.assertEqual(blob.hard_delete_time, hard_timstamp)

def test_restore_token_getter(self):
BLOB_NAME = "blob-name"
bucket = _Bucket()
restore_token = "88ba0d97-639e-5902"
properties = {
"restoreToken": restore_token,
}
blob = self._make_one(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.restore_token, restore_token)

def test_soft_hard_delte_time_unset(self):
BUCKET = object()
blob = self._make_one("blob-name", bucket=BUCKET)
Expand Down
19 changes: 3 additions & 16 deletions tests/unit/test_bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -1018,24 +1018,18 @@ def test_get_blob_hit_w_user_project(self):
_target_object=blob,
)

def test_get_blob_hit_w_gen_soft_deleted_restore_token(self):
def test_get_blob_hit_w_generation_w_soft_deleted(self):
from google.cloud.storage.blob import Blob

name = "name"
blob_name = "blob-name"
generation = 1512565576797178
restore_token = "88ba0d97-639e-5902"
api_response = {"name": blob_name, "generation": generation}
client = mock.Mock(spec=["_get_resource"])
client._get_resource.return_value = api_response
bucket = self._make_one(client, name=name)

blob = bucket.get_blob(
blob_name,
generation=generation,
soft_deleted=True,
restore_token=restore_token,
)
blob = bucket.get_blob(blob_name, generation=generation, soft_deleted=True)

self.assertIsInstance(blob, Blob)
self.assertIs(blob.bucket, bucket)
Expand All @@ -1047,7 +1041,6 @@ def test_get_blob_hit_w_gen_soft_deleted_restore_token(self):
"generation": generation,
"projection": "noAcl",
"softDeleted": True,
"restoreToken": restore_token,
}
expected_headers = {}
client._get_resource.assert_called_once_with(
Expand Down Expand Up @@ -4224,10 +4217,8 @@ def test_restore_blob_w_explicit(self):
user_project = "user-project-123"
bucket_name = "restore_bucket"
blob_name = "restore_blob"
new_generation = 987655
generation = 123456
restore_token = "88ba0d97-639e-5902"
api_response = {"name": blob_name, "generation": new_generation}
api_response = {"name": blob_name, "generation": generation}
client = mock.Mock(spec=["_post_resource"])
client._post_resource.return_value = api_response
bucket = self._make_one(
Expand All @@ -4242,8 +4233,6 @@ def test_restore_blob_w_explicit(self):
restored_blob = bucket.restore_blob(
blob_name,
client=client,
generation=generation,
restore_token=restore_token,
if_generation_match=if_generation_match,
if_generation_not_match=if_generation_not_match,
if_metageneration_match=if_metageneration_match,
Expand All @@ -4256,8 +4245,6 @@ def test_restore_blob_w_explicit(self):
expected_path = f"/b/{bucket_name}/o/{blob_name}/restore"
expected_data = None
expected_query_params = {
"generation": generation,
"restoreToken": restore_token,
"userProject": user_project,
"projection": projection,
"ifGenerationMatch": if_generation_match,
Expand Down