Skip to content

Commit d38adb6

Browse files
authoredOct 30, 2023
feat: add Autoclass v2.1 support (#1117)
* feat: add Autoclass v2.1 support * update tests and coverage * update samples with v2.1 additions * fix lint * update samples
1 parent 4c30d62 commit d38adb6

File tree

6 files changed

+133
-22
lines changed

6 files changed

+133
-22
lines changed
 

‎google/cloud/storage/bucket.py

+45-6
Original file line numberDiff line numberDiff line change
@@ -2689,13 +2689,10 @@ def autoclass_enabled(self, value):
26892689
:type value: convertible to boolean
26902690
:param value: If true, enable Autoclass for this bucket.
26912691
If false, disable Autoclass for this bucket.
2692-
2693-
.. note::
2694-
To enable autoclass, you must set it at bucket creation time.
2695-
Currently, only patch requests that disable autoclass are supported.
2696-
26972692
"""
2698-
self._patch_property("autoclass", {"enabled": bool(value)})
2693+
autoclass = self._properties.get("autoclass", {})
2694+
autoclass["enabled"] = bool(value)
2695+
self._patch_property("autoclass", autoclass)
26992696

27002697
@property
27012698
def autoclass_toggle_time(self):
@@ -2709,6 +2706,48 @@ def autoclass_toggle_time(self):
27092706
if timestamp is not None:
27102707
return _rfc3339_nanos_to_datetime(timestamp)
27112708

2709+
@property
2710+
def autoclass_terminal_storage_class(self):
2711+
"""The storage class that objects in an Autoclass bucket eventually transition to if
2712+
they are not read for a certain length of time. Valid values are NEARLINE and ARCHIVE.
2713+
2714+
See https://cloud.google.com/storage/docs/using-autoclass for details.
2715+
2716+
:setter: Set the terminal storage class for Autoclass configuration.
2717+
:getter: Get the terminal storage class for Autoclass configuration.
2718+
2719+
:rtype: str
2720+
:returns: The terminal storage class if Autoclass is enabled, else ``None``.
2721+
"""
2722+
autoclass = self._properties.get("autoclass", {})
2723+
return autoclass.get("terminalStorageClass", None)
2724+
2725+
@autoclass_terminal_storage_class.setter
2726+
def autoclass_terminal_storage_class(self, value):
2727+
"""The storage class that objects in an Autoclass bucket eventually transition to if
2728+
they are not read for a certain length of time. Valid values are NEARLINE and ARCHIVE.
2729+
2730+
See https://cloud.google.com/storage/docs/using-autoclass for details.
2731+
2732+
:type value: str
2733+
:param value: The only valid values are `"NEARLINE"` and `"ARCHIVE"`.
2734+
"""
2735+
autoclass = self._properties.get("autoclass", {})
2736+
autoclass["terminalStorageClass"] = value
2737+
self._patch_property("autoclass", autoclass)
2738+
2739+
@property
2740+
def autoclass_terminal_storage_class_update_time(self):
2741+
"""The time at which the Autoclass terminal_storage_class field was last updated for this bucket
2742+
:rtype: datetime.datetime or ``NoneType``
2743+
:returns: point-in time at which the bucket's terminal_storage_class is last updated, or ``None`` if the property is not set locally.
2744+
"""
2745+
autoclass = self._properties.get("autoclass")
2746+
if autoclass is not None:
2747+
timestamp = autoclass.get("terminalStorageClassUpdateTime")
2748+
if timestamp is not None:
2749+
return _rfc3339_nanos_to_datetime(timestamp)
2750+
27122751
def configure_website(self, main_page_suffix=None, not_found_page=None):
27132752
"""Configure website-related properties.
27142753

‎samples/snippets/snippets_test.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -449,23 +449,27 @@ def test_get_set_autoclass(new_bucket_obj, test_bucket, capsys):
449449
out, _ = capsys.readouterr()
450450
assert "Autoclass enabled is set to False" in out
451451
assert bucket.autoclass_toggle_time is None
452+
assert bucket.autoclass_terminal_storage_class_update_time is None
452453

453454
# Test enabling Autoclass at bucket creation
454455
new_bucket_obj.autoclass_enabled = True
455456
bucket = storage.Client().create_bucket(new_bucket_obj)
456457
assert bucket.autoclass_enabled is True
458+
assert bucket.autoclass_terminal_storage_class == "NEARLINE"
457459

458-
# Test disabling Autoclass
459-
bucket = storage_set_autoclass.set_autoclass(bucket.name, False)
460+
# Test set terminal_storage_class to ARCHIVE
461+
bucket = storage_set_autoclass.set_autoclass(bucket.name)
460462
out, _ = capsys.readouterr()
461-
assert "Autoclass enabled is set to False" in out
462-
assert bucket.autoclass_enabled is False
463+
assert "Autoclass enabled is set to True" in out
464+
assert bucket.autoclass_enabled is True
465+
assert bucket.autoclass_terminal_storage_class == "ARCHIVE"
463466

464467
# Test get Autoclass
465468
bucket = storage_get_autoclass.get_autoclass(bucket.name)
466469
out, _ = capsys.readouterr()
467-
assert "Autoclass enabled is set to False" in out
470+
assert "Autoclass enabled is set to True" in out
468471
assert bucket.autoclass_toggle_time is not None
472+
assert bucket.autoclass_terminal_storage_class_update_time is not None
469473

470474

471475
def test_bucket_lifecycle_management(test_bucket, capsys):

‎samples/snippets/storage_get_autoclass.py

+3
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@ def get_autoclass(bucket_name):
2929
bucket = storage_client.get_bucket(bucket_name)
3030
autoclass_enabled = bucket.autoclass_enabled
3131
autoclass_toggle_time = bucket.autoclass_toggle_time
32+
terminal_storage_class = bucket.autoclass_terminal_storage_class
33+
tsc_update_time = bucket.autoclass_terminal_storage_class_update_time
3234

3335
print(f"Autoclass enabled is set to {autoclass_enabled} for {bucket.name} at {autoclass_toggle_time}.")
36+
print(f"Autoclass terminal storage class is set to {terminal_storage_class} for {bucket.name} at {tsc_update_time}.")
3437

3538
return bucket
3639

‎samples/snippets/storage_set_autoclass.py

+12-8
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,32 @@
2020
from google.cloud import storage
2121

2222

23-
def set_autoclass(bucket_name, toggle):
24-
"""Disable Autoclass for a bucket.
23+
def set_autoclass(bucket_name):
24+
"""Configure the Autoclass setting for a bucket.
2525
26-
Note: Only patch requests that disable autoclass are currently supported.
27-
To enable autoclass, you must set it at bucket creation time.
26+
terminal_storage_class field is optional and defaults to NEARLINE if not otherwise specified.
27+
Valid terminal_storage_class values are NEARLINE and ARCHIVE.
2828
"""
2929
# The ID of your GCS bucket
3030
# bucket_name = "my-bucket"
31-
# Boolean toggle - if true, enables Autoclass; if false, disables Autoclass
32-
# toggle = False
31+
# Enable Autoclass for a bucket. Set enabled to false to disable Autoclass.
32+
# Set Autoclass.TerminalStorageClass, valid values are NEARLINE and ARCHIVE.
33+
enabled = True
34+
terminal_storage_class = "ARCHIVE"
3335

3436
storage_client = storage.Client()
3537
bucket = storage_client.bucket(bucket_name)
3638

37-
bucket.autoclass_enabled = toggle
39+
bucket.autoclass_enabled = enabled
40+
bucket.autoclass_terminal_storage_class = terminal_storage_class
3841
bucket.patch()
3942
print(f"Autoclass enabled is set to {bucket.autoclass_enabled} for {bucket.name} at {bucket.autoclass_toggle_time}.")
43+
print(f"Autoclass terminal storage class is {bucket.autoclass_terminal_storage_class}.")
4044

4145
return bucket
4246

4347

4448
# [END storage_set_autoclass]
4549

4650
if __name__ == "__main__":
47-
set_autoclass(bucket_name=sys.argv[1], toggle=sys.argv[2])
51+
set_autoclass(bucket_name=sys.argv[1])

‎tests/system/test_bucket.py

+37-1
Original file line numberDiff line numberDiff line change
@@ -1047,19 +1047,55 @@ def test_new_bucket_with_autoclass(
10471047
storage_client,
10481048
buckets_to_delete,
10491049
):
1050-
# Autoclass can be enabled/disabled via bucket create
1050+
from google.cloud.storage import constants
1051+
1052+
# Autoclass can be enabled via bucket create
10511053
bucket_name = _helpers.unique_name("new-w-autoclass")
10521054
bucket_obj = storage_client.bucket(bucket_name)
10531055
bucket_obj.autoclass_enabled = True
10541056
bucket = storage_client.create_bucket(bucket_obj)
10551057
previous_toggle_time = bucket.autoclass_toggle_time
10561058
buckets_to_delete.append(bucket)
10571059

1060+
# Autoclass terminal_storage_class is defaulted to NEARLINE if not specified
10581061
assert bucket.autoclass_enabled is True
1062+
assert bucket.autoclass_terminal_storage_class == constants.NEARLINE_STORAGE_CLASS
10591063

10601064
# Autoclass can be enabled/disabled via bucket patch
10611065
bucket.autoclass_enabled = False
10621066
bucket.patch(if_metageneration_match=bucket.metageneration)
10631067

10641068
assert bucket.autoclass_enabled is False
10651069
assert bucket.autoclass_toggle_time != previous_toggle_time
1070+
1071+
1072+
def test_config_autoclass_w_existing_bucket(
1073+
storage_client,
1074+
buckets_to_delete,
1075+
):
1076+
from google.cloud.storage import constants
1077+
1078+
bucket_name = _helpers.unique_name("for-autoclass")
1079+
bucket = storage_client.create_bucket(bucket_name)
1080+
buckets_to_delete.append(bucket)
1081+
assert bucket.autoclass_enabled is False
1082+
assert bucket.autoclass_toggle_time is None
1083+
assert bucket.autoclass_terminal_storage_class is None
1084+
assert bucket.autoclass_terminal_storage_class_update_time is None
1085+
1086+
# Enable Autoclass on existing buckets with terminal_storage_class set to ARCHIVE
1087+
bucket.autoclass_enabled = True
1088+
bucket.autoclass_terminal_storage_class = constants.ARCHIVE_STORAGE_CLASS
1089+
bucket.patch(if_metageneration_match=bucket.metageneration)
1090+
previous_tsc_update_time = bucket.autoclass_terminal_storage_class_update_time
1091+
assert bucket.autoclass_enabled is True
1092+
assert bucket.autoclass_terminal_storage_class == constants.ARCHIVE_STORAGE_CLASS
1093+
1094+
# Configure Autoclass terminal_storage_class to NEARLINE
1095+
bucket.autoclass_terminal_storage_class = constants.NEARLINE_STORAGE_CLASS
1096+
bucket.patch(if_metageneration_match=bucket.metageneration)
1097+
assert bucket.autoclass_enabled is True
1098+
assert bucket.autoclass_terminal_storage_class == constants.NEARLINE_STORAGE_CLASS
1099+
assert (
1100+
bucket.autoclass_terminal_storage_class_update_time != previous_tsc_update_time
1101+
)

‎tests/unit/test_bucket.py

+27-2
Original file line numberDiff line numberDiff line change
@@ -2659,15 +2659,19 @@ def test_autoclass_enabled_getter_and_setter(self):
26592659
self.assertIn("autoclass", bucket._changes)
26602660
self.assertFalse(bucket.autoclass_enabled)
26612661

2662-
def test_autoclass_toggle_time_missing(self):
2662+
def test_autoclass_config_unset(self):
26632663
bucket = self._make_one()
26642664
self.assertIsNone(bucket.autoclass_toggle_time)
2665+
self.assertIsNone(bucket.autoclass_terminal_storage_class)
2666+
self.assertIsNone(bucket.autoclass_terminal_storage_class_update_time)
26652667

26662668
properties = {"autoclass": {}}
26672669
bucket = self._make_one(properties=properties)
26682670
self.assertIsNone(bucket.autoclass_toggle_time)
2671+
self.assertIsNone(bucket.autoclass_terminal_storage_class)
2672+
self.assertIsNone(bucket.autoclass_terminal_storage_class_update_time)
26692673

2670-
def test_autoclass_toggle_time(self):
2674+
def test_autoclass_toggle_and_tsc_update_time(self):
26712675
import datetime
26722676
from google.cloud._helpers import _datetime_to_rfc3339
26732677
from google.cloud._helpers import UTC
@@ -2677,10 +2681,31 @@ def test_autoclass_toggle_time(self):
26772681
"autoclass": {
26782682
"enabled": True,
26792683
"toggleTime": _datetime_to_rfc3339(effective_time),
2684+
"terminalStorageClass": "NEARLINE",
2685+
"terminalStorageClassUpdateTime": _datetime_to_rfc3339(effective_time),
26802686
}
26812687
}
26822688
bucket = self._make_one(properties=properties)
26832689
self.assertEqual(bucket.autoclass_toggle_time, effective_time)
2690+
self.assertEqual(
2691+
bucket.autoclass_terminal_storage_class_update_time, effective_time
2692+
)
2693+
2694+
def test_autoclass_tsc_getter_and_setter(self):
2695+
from google.cloud.storage import constants
2696+
2697+
properties = {
2698+
"autoclass": {"terminalStorageClass": constants.ARCHIVE_STORAGE_CLASS}
2699+
}
2700+
bucket = self._make_one(properties=properties)
2701+
self.assertEqual(
2702+
bucket.autoclass_terminal_storage_class, constants.ARCHIVE_STORAGE_CLASS
2703+
)
2704+
bucket.autoclass_terminal_storage_class = constants.NEARLINE_STORAGE_CLASS
2705+
self.assertIn("autoclass", bucket._changes)
2706+
self.assertEqual(
2707+
bucket.autoclass_terminal_storage_class, constants.NEARLINE_STORAGE_CLASS
2708+
)
26842709

26852710
def test_get_logging_w_prefix(self):
26862711
NAME = "name"

0 commit comments

Comments
 (0)
Please sign in to comment.