Skip to content

Commit 9ccdc5f

Browse files
authored
feat: add Autoclass support and sample (#791)
This adds support and samples for Autoclass For more info, see Internal: [go/gcs-dpe-autoclass](http://go/gcs-dpe-autoclass) Fixes #797
1 parent 9dcc684 commit 9ccdc5f

File tree

6 files changed

+223
-0
lines changed

6 files changed

+223
-0
lines changed

google/cloud/storage/bucket.py

+44
Original file line numberDiff line numberDiff line change
@@ -2660,6 +2660,50 @@ def requester_pays(self, value):
26602660
"""
26612661
self._patch_property("billing", {"requesterPays": bool(value)})
26622662

2663+
@property
2664+
def autoclass_enabled(self):
2665+
"""Whether Autoclass is enabled for this bucket.
2666+
2667+
See https://cloud.google.com/storage/docs/using-autoclass for details.
2668+
2669+
:setter: Update whether autoclass is enabled for this bucket.
2670+
:getter: Query whether autoclass is enabled for this bucket.
2671+
2672+
:rtype: bool
2673+
:returns: True if enabled, else False.
2674+
"""
2675+
autoclass = self._properties.get("autoclass", {})
2676+
return autoclass.get("enabled", False)
2677+
2678+
@autoclass_enabled.setter
2679+
def autoclass_enabled(self, value):
2680+
"""Enable or disable Autoclass at the bucket-level.
2681+
2682+
See https://cloud.google.com/storage/docs/using-autoclass for details.
2683+
2684+
:type value: convertible to boolean
2685+
:param value: If true, enable Autoclass for this bucket.
2686+
If false, disable Autoclass for this bucket.
2687+
2688+
.. note::
2689+
To enable autoclass, you must set it at bucket creation time.
2690+
Currently, only patch requests that disable autoclass are supported.
2691+
2692+
"""
2693+
self._patch_property("autoclass", {"enabled": bool(value)})
2694+
2695+
@property
2696+
def autoclass_toggle_time(self):
2697+
"""Retrieve the toggle time when Autoclaass was last enabled or disabled for the bucket.
2698+
:rtype: datetime.datetime or ``NoneType``
2699+
:returns: point-in time at which the bucket's autoclass is toggled, or ``None`` if the property is not set locally.
2700+
"""
2701+
autoclass = self._properties.get("autoclass")
2702+
if autoclass is not None:
2703+
timestamp = autoclass.get("toggleTime")
2704+
if timestamp is not None:
2705+
return _rfc3339_nanos_to_datetime(timestamp)
2706+
26632707
def configure_website(self, main_page_suffix=None, not_found_page=None):
26642708
"""Configure website-related properties.
26652709

samples/snippets/snippets_test.py

+38
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import storage_generate_signed_url_v2
5454
import storage_generate_signed_url_v4
5555
import storage_generate_upload_signed_url_v4
56+
import storage_get_autoclass
5657
import storage_get_bucket_labels
5758
import storage_get_bucket_metadata
5859
import storage_get_metadata
@@ -67,6 +68,7 @@
6768
import storage_remove_bucket_label
6869
import storage_remove_cors_configuration
6970
import storage_rename_file
71+
import storage_set_autoclass
7072
import storage_set_bucket_default_kms_key
7173
import storage_set_client_endpoint
7274
import storage_set_metadata
@@ -136,6 +138,17 @@ def test_public_bucket():
136138
os.environ['GOOGLE_CLOUD_PROJECT'] = original_value
137139

138140

141+
@pytest.fixture(scope="module")
142+
def new_bucket_obj():
143+
"""Yields a new bucket object that is deleted after the test completes."""
144+
bucket = None
145+
while bucket is None or bucket.exists():
146+
bucket_name = f"storage-snippets-test-{uuid.uuid4()}"
147+
bucket = storage.Client().bucket(bucket_name)
148+
yield bucket
149+
bucket.delete(force=True)
150+
151+
139152
@pytest.fixture
140153
def test_blob(test_bucket):
141154
"""Yields a blob that is deleted after the test completes."""
@@ -408,6 +421,31 @@ def test_versioning(test_bucket, capsys):
408421
assert bucket.versioning_enabled is False
409422

410423

424+
def test_get_set_autoclass(new_bucket_obj, test_bucket, capsys):
425+
# Test default values when Autoclass is unset
426+
bucket = storage_get_autoclass.get_autoclass(test_bucket.name)
427+
out, _ = capsys.readouterr()
428+
assert "Autoclass enabled is set to False" in out
429+
assert bucket.autoclass_toggle_time is None
430+
431+
# Test enabling Autoclass at bucket creation
432+
new_bucket_obj.autoclass_enabled = True
433+
bucket = storage.Client().create_bucket(new_bucket_obj)
434+
assert bucket.autoclass_enabled is True
435+
436+
# Test disabling Autoclass
437+
bucket = storage_set_autoclass.set_autoclass(bucket.name, False)
438+
out, _ = capsys.readouterr()
439+
assert "Autoclass enabled is set to False" in out
440+
assert bucket.autoclass_enabled is False
441+
442+
# Test get Autoclass
443+
bucket = storage_get_autoclass.get_autoclass(bucket.name)
444+
out, _ = capsys.readouterr()
445+
assert "Autoclass enabled is set to False" in out
446+
assert bucket.autoclass_toggle_time is not None
447+
448+
411449
def test_bucket_lifecycle_management(test_bucket, capsys):
412450
bucket = storage_enable_bucket_lifecycle_management.enable_bucket_lifecycle_management(
413451
test_bucket
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2022 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the 'License');
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import sys
18+
19+
# [START storage_get_autoclass]
20+
from google.cloud import storage
21+
22+
23+
def get_autoclass(bucket_name):
24+
"""Get the Autoclass setting for a bucket."""
25+
# The ID of your GCS bucket
26+
# bucket_name = "my-bucket"
27+
28+
storage_client = storage.Client()
29+
bucket = storage_client.get_bucket(bucket_name)
30+
autoclass_enabled = bucket.autoclass_enabled
31+
autoclass_toggle_time = bucket.autoclass_toggle_time
32+
33+
print(f"Autoclass enabled is set to {autoclass_enabled} for {bucket.name} at {autoclass_toggle_time}.")
34+
35+
return bucket
36+
37+
38+
# [END storage_get_autoclass]
39+
40+
if __name__ == "__main__":
41+
get_autoclass(bucket_name=sys.argv[1])
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2022 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the 'License');
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import sys
18+
19+
# [START storage_set_autoclass]
20+
from google.cloud import storage
21+
22+
23+
def set_autoclass(bucket_name, toggle):
24+
"""Disable Autoclass for a bucket.
25+
26+
Note: Only patch requests that disable autoclass are currently supported.
27+
To enable autoclass, you must set it at bucket creation time.
28+
"""
29+
# The ID of your GCS bucket
30+
# bucket_name = "my-bucket"
31+
# Boolean toggle - if true, enables Autoclass; if false, disables Autoclass
32+
# toggle = False
33+
34+
storage_client = storage.Client()
35+
bucket = storage_client.bucket(bucket_name)
36+
37+
bucket.autoclass_enabled = toggle
38+
bucket.patch()
39+
print(f"Autoclass enabled is set to {bucket.autoclass_enabled} for {bucket.name} at {bucket.autoclass_toggle_time}.")
40+
41+
return bucket
42+
43+
44+
# [END storage_set_autoclass]
45+
46+
if __name__ == "__main__":
47+
set_autoclass(bucket_name=sys.argv[1], toggle=sys.argv[2])

tests/system/test_bucket.py

+22
Original file line numberDiff line numberDiff line change
@@ -996,3 +996,25 @@ def test_new_bucket_with_rpo(
996996
bucket_from_server = storage_client.get_bucket(bucket_name)
997997

998998
assert bucket_from_server.rpo == constants.RPO_ASYNC_TURBO
999+
1000+
1001+
def test_new_bucket_with_autoclass(
1002+
storage_client,
1003+
buckets_to_delete,
1004+
):
1005+
# Autoclass can be enabled/disabled via bucket create
1006+
bucket_name = _helpers.unique_name("new-w-autoclass")
1007+
bucket_obj = storage_client.bucket(bucket_name)
1008+
bucket_obj.autoclass_enabled = True
1009+
bucket = storage_client.create_bucket(bucket_obj)
1010+
previous_toggle_time = bucket.autoclass_toggle_time
1011+
buckets_to_delete.append(bucket)
1012+
1013+
assert bucket.autoclass_enabled is True
1014+
1015+
# Autoclass can be enabled/disabled via bucket patch
1016+
bucket.autoclass_enabled = False
1017+
bucket.patch()
1018+
1019+
assert bucket.autoclass_enabled is False
1020+
assert bucket.autoclass_toggle_time != previous_toggle_time

tests/unit/test_bucket.py

+31
Original file line numberDiff line numberDiff line change
@@ -2644,6 +2644,37 @@ def test_rpo_getter_and_setter(self):
26442644
self.assertIn("rpo", bucket._changes)
26452645
self.assertEqual(bucket.rpo, RPO_DEFAULT)
26462646

2647+
def test_autoclass_enabled_getter_and_setter(self):
2648+
properties = {"autoclass": {"enabled": True}}
2649+
bucket = self._make_one(properties=properties)
2650+
self.assertTrue(bucket.autoclass_enabled)
2651+
bucket.autoclass_enabled = False
2652+
self.assertIn("autoclass", bucket._changes)
2653+
self.assertFalse(bucket.autoclass_enabled)
2654+
2655+
def test_autoclass_toggle_time_missing(self):
2656+
bucket = self._make_one()
2657+
self.assertIsNone(bucket.autoclass_toggle_time)
2658+
2659+
properties = {"autoclass": {}}
2660+
bucket = self._make_one(properties=properties)
2661+
self.assertIsNone(bucket.autoclass_toggle_time)
2662+
2663+
def test_autoclass_toggle_time(self):
2664+
import datetime
2665+
from google.cloud._helpers import _datetime_to_rfc3339
2666+
from google.cloud._helpers import UTC
2667+
2668+
effective_time = datetime.datetime.utcnow().replace(tzinfo=UTC)
2669+
properties = {
2670+
"autoclass": {
2671+
"enabled": True,
2672+
"toggleTime": _datetime_to_rfc3339(effective_time),
2673+
}
2674+
}
2675+
bucket = self._make_one(properties=properties)
2676+
self.assertEqual(bucket.autoclass_toggle_time, effective_time)
2677+
26472678
def test_get_logging_w_prefix(self):
26482679
NAME = "name"
26492680
LOG_BUCKET = "logs"

0 commit comments

Comments
 (0)