Skip to content

Commit dcf0227

Browse files
Added support for OBJ Gen 2
1 parent bf1b659 commit dcf0227

File tree

7 files changed

+137
-43
lines changed

7 files changed

+137
-43
lines changed

linode_api4/groups/object_storage.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55

66
from deprecated import deprecated
77

8-
from linode_api4 import ObjectStorageEndpoint, ObjectStorageEndpointType
8+
from linode_api4 import (
9+
ObjectStorageEndpoint,
10+
ObjectStorageEndpointType,
11+
PaginatedList,
12+
)
913
from linode_api4.errors import UnexpectedResponseError
1014
from linode_api4.groups import Group
1115
from linode_api4.objects import (
@@ -273,10 +277,15 @@ def transfer(self):
273277

274278
return MappedObject(**result)
275279

276-
def endpoints(self, *filters):
280+
def endpoints(self, *filters) -> PaginatedList:
277281
"""
278282
Returns a paginated list of all Object Storage endpoints available in your account.
279283
284+
This is intended to be called from the :any:`LinodeClient`
285+
class, like this::
286+
287+
endpoints = client.object_storage.endpoints()
288+
280289
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-object-storage-endpoints
281290
282291
:param filters: Any number of filters to apply to this query.
@@ -286,7 +295,11 @@ def endpoints(self, *filters):
286295
:returns: A list of Object Storage Endpoints that matched the query.
287296
:rtype: PaginatedList of ObjectStorageEndpoint
288297
"""
289-
return self.client._get_and_filter(ObjectStorageEndpoint, *filters)
298+
return self.client._get_and_filter(
299+
ObjectStorageEndpoint,
300+
*filters,
301+
endpoint="/object-storage/endpoints",
302+
)
290303

291304
def buckets(self, *filters):
292305
"""

linode_api4/objects/object_storage.py

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
Property,
1313
Region,
1414
)
15-
from linode_api4.objects.serializable import StrEnum
15+
from linode_api4.objects.serializable import JSONObject, StrEnum
1616
from linode_api4.util import drop_null_keys
1717

1818

@@ -36,23 +36,18 @@ class ObjectStorageEndpointType(StrEnum):
3636
E3 = "E3"
3737

3838

39-
class ObjectStorageEndpoint(Base):
39+
@dataclass
40+
class ObjectStorageEndpoint(JSONObject):
4041
"""
41-
.. note:: At this time, the Linode API only supports listing ObjectStorageEndpoints.
42+
ObjectStorageEndpoint contains the core fields of an object storage endpoint object.
4243
43-
An instance of an ObjectStorageEndpoint.
44-
ObjectStorageEndpoints determine which S3 endpoints or types of endpoints are available to the requesting customer when using the API to create a bucket in a particular region
45-
46-
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-object-storage-endpoints
44+
NOTE: This is not implemented as a typical API object (Base) because Object Storage Endpoints
45+
cannot be refreshed, as there is no singular GET endpoint.
4746
"""
4847

49-
api_endpoint = "/object-storage/endpoints"
50-
51-
properties = {
52-
"region": Property(),
53-
"s3_endpoint": Property(),
54-
"endpoint_type": Property(),
55-
}
48+
region: str = ""
49+
endpoint_type: str = ""
50+
s3_endpoint: Optional[str] = None
5651

5752

5853
class ObjectStorageBucket(DerivedBase):
@@ -92,13 +87,10 @@ def make_instance(cls, id, client, parent_id=None, json=None):
9287
Override this method to pass in the parent_id from the _raw_json object
9388
when it's available.
9489
"""
95-
if json is None:
96-
return None
97-
98-
cluster_or_region = json.get("region") or json.get("cluster")
99-
100-
if parent_id is None and cluster_or_region:
101-
parent_id = cluster_or_region
90+
if json is not None:
91+
cluster_or_region = json.get("region") or json.get("cluster")
92+
if parent_id is None and cluster_or_region:
93+
parent_id = cluster_or_region
10294

10395
if parent_id:
10496
return super().make(id, client, cls, parent_id=parent_id, json=json)
@@ -114,14 +106,17 @@ def access_get(self):
114106
API Documentation: TODO
115107
116108
:returns: A result object which wraps the access that this ObjectStorageBucket is currently configured with.
117-
:rtype: dict
109+
:rtype: MappedObject
118110
"""
119111
result = self._client.get(
120112
"{}/access".format(self.api_endpoint),
121113
model=self,
122114
)
123115

124-
if not any(key in result for key in ["acl", "acl_xml", "cors_enabled", "cors_xml"]):
116+
if not any(
117+
key in result
118+
for key in ["acl", "acl_xml", "cors_enabled", "cors_xml"]
119+
):
125120
raise UnexpectedResponseError(
126121
"Unexpected response when getting the bucket access config of a bucket!",
127122
json=result,

test/fixtures/object-storage_buckets_us-east-1.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
"hostname": "example-bucket.us-east-1.linodeobjects.com",
77
"label": "example-bucket",
88
"objects": 4,
9-
"size": 188318981
9+
"size": 188318981,
10+
"endpoint_type": "E1",
11+
"s3_endpoint": "us-east-12.linodeobjects.com"
1012
}
1113
],
1214
"page": 1,

test/fixtures/object-storage_buckets_us-east-1_example-bucket.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,7 @@
55
"hostname": "example-bucket.us-east-1.linodeobjects.com",
66
"label": "example-bucket",
77
"objects": 4,
8-
"size": 188318981
8+
"size": 188318981,
9+
"endpoint_type": "E1",
10+
"s3_endpoint": "us-east-12.linodeobjects.com"
911
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"acl": "authenticated-read",
3+
"acl_xml": "<AccessControlPolicy...",
4+
"cors_enabled": true,
5+
"cors_xml": "<CORSConfiguration>..."
6+
}

test/integration/models/object_storage/test_obj.py

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
ObjectStorageACL,
99
ObjectStorageBucket,
1010
ObjectStorageCluster,
11+
ObjectStorageEndpointType,
1112
ObjectStorageKeyPermission,
1213
ObjectStorageKeys,
1314
)
@@ -19,7 +20,14 @@ def region(test_linode_client: LinodeClient):
1920

2021

2122
@pytest.fixture(scope="session")
22-
def bucket(test_linode_client: LinodeClient, region: str) -> ObjectStorageBucket:
23+
def endpoints(test_linode_client: LinodeClient):
24+
return test_linode_client.object_storage.endpoints()
25+
26+
27+
@pytest.fixture(scope="session")
28+
def bucket(
29+
test_linode_client: LinodeClient, region: str
30+
) -> ObjectStorageBucket:
2331
bucket = test_linode_client.object_storage.bucket_create(
2432
cluster_or_region=region,
2533
label="bucket-" + str(time.time_ns()),
@@ -31,6 +39,31 @@ def bucket(test_linode_client: LinodeClient, region: str) -> ObjectStorageBucket
3139
bucket.delete()
3240

3341

42+
@pytest.fixture(scope="session")
43+
def bucket_with_endpoint(
44+
test_linode_client: LinodeClient, endpoints
45+
) -> ObjectStorageBucket:
46+
selected_endpoint = next(
47+
(
48+
e
49+
for e in endpoints
50+
if e.endpoint_type == ObjectStorageEndpointType.E1
51+
),
52+
None,
53+
)
54+
55+
bucket = test_linode_client.object_storage.bucket_create(
56+
cluster_or_region=selected_endpoint.region,
57+
label="bucket-" + str(time.time_ns()),
58+
acl=ObjectStorageACL.PRIVATE,
59+
cors_enabled=False,
60+
endpoint_type=selected_endpoint.endpoint_type,
61+
)
62+
63+
yield bucket
64+
bucket.delete()
65+
66+
3467
@pytest.fixture(scope="session")
3568
def obj_key(test_linode_client: LinodeClient):
3669
key = test_linode_client.object_storage.keys_create(
@@ -71,28 +104,36 @@ def test_keys(
71104

72105
assert loaded_key.label == obj_key.label
73106
assert loaded_limited_key.label == obj_limited_key.label
107+
assert (
108+
loaded_limited_key.regions[0].endpoint_type
109+
in ObjectStorageEndpointType.__members__.values()
110+
)
74111

75112

76113
def test_bucket(test_linode_client: LinodeClient, bucket: ObjectStorageBucket):
77-
print("The bucket's region is:", bucket.region)
78-
print("The bucket's cluster is:", bucket.cluster)
79-
80114
loaded_bucket = test_linode_client.load(
81-
ObjectStorageBucket, target_id=bucket.label, target_parent_id=bucket.region
115+
ObjectStorageBucket,
116+
target_id=bucket.label,
117+
target_parent_id=bucket.region,
82118
)
83119

84120
assert loaded_bucket.label == bucket.label
85-
assert loaded_bucket.cluster == bucket.cluster
121+
assert loaded_bucket.region == bucket.region
86122

87-
# def test_bucket(test_linode_client: LinodeClient, bucket: ObjectStorageBucket):
88-
# buckets = test_linode_client.object_storage.buckets()
89-
#
90-
# target_bucket = next((b for b in buckets if b.id == bucket.id), None)
91-
#
92-
# assert target_bucket is not None, f"Bucket with ID {bucket.id} not found"
93-
#
94-
# assert target_bucket.label == bucket.label
95-
# assert target_bucket.region == bucket.region
123+
124+
def test_bucket_with_endpoint(
125+
test_linode_client: LinodeClient, bucket_with_endpoint: ObjectStorageBucket
126+
):
127+
loaded_bucket = test_linode_client.load(
128+
ObjectStorageBucket,
129+
target_id=bucket_with_endpoint.label,
130+
target_parent_id=bucket_with_endpoint.region,
131+
)
132+
133+
assert loaded_bucket.label == bucket_with_endpoint.label
134+
assert loaded_bucket.region == bucket_with_endpoint.region
135+
assert loaded_bucket.s3_endpoint is not None
136+
assert loaded_bucket.endpoint_type == "E1"
96137

97138

98139
def test_buckets_in_region(
@@ -115,6 +156,14 @@ def test_list_obj_storage_bucket(
115156
assert any(target_bucket_id == b.id for b in buckets)
116157

117158

159+
def test_bucket_access_get(bucket: ObjectStorageBucket):
160+
access = bucket.access_get()
161+
162+
assert access.acl is not None
163+
assert access.acl_xml is not None
164+
assert access.cors_enabled is not None
165+
166+
118167
def test_bucket_access_modify(bucket: ObjectStorageBucket):
119168
bucket.access_modify(ObjectStorageACL.PRIVATE, cors_enabled=True)
120169

test/unit/objects/object_storage_test.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from datetime import datetime
22
from test.unit.base import ClientBaseCase
33

4+
from linode_api4 import ObjectStorageEndpointType
45
from linode_api4.objects import (
56
ObjectStorageACL,
67
ObjectStorageBucket,
@@ -35,6 +36,14 @@ def test_object_storage_bucket_api_get(self):
3536
)
3637
self.assertEqual(object_storage_bucket.objects, 4)
3738
self.assertEqual(object_storage_bucket.size, 188318981)
39+
self.assertEqual(
40+
object_storage_bucket.endpoint_type,
41+
ObjectStorageEndpointType.E1,
42+
)
43+
self.assertEqual(
44+
object_storage_bucket.s3_endpoint,
45+
"us-east-12.linodeobjects.com",
46+
)
3847
self.assertEqual(m.call_url, object_storage_bucket_api_get_url)
3948

4049
def test_object_storage_bucket_delete(self):
@@ -48,6 +57,22 @@ def test_object_storage_bucket_delete(self):
4857
object_storage_bucket.delete()
4958
self.assertEqual(m.call_url, object_storage_bucket_delete_url)
5059

60+
def test_bucket_access_get(self):
61+
bucket_access_get_url = (
62+
"/object-storage/buckets/us-east/example-bucket/access"
63+
)
64+
with self.mock_get(bucket_access_get_url) as m:
65+
object_storage_bucket = ObjectStorageBucket(
66+
self.client, "example-bucket", "us-east"
67+
)
68+
result = object_storage_bucket.access_get()
69+
self.assertIsNotNone(result)
70+
self.assertEqual(m.call_url, bucket_access_get_url)
71+
self.assertEqual(result.acl, "authenticated-read")
72+
self.assertEqual(result.cors_enabled, True)
73+
self.assertEqual(result.acl_xml, "<AccessControlPolicy...")
74+
self.assertEqual(result.cors_xml, "<CORSConfiguration>...")
75+
5176
def test_bucket_access_modify(self):
5277
"""
5378
Test that you can modify bucket access settings.
@@ -115,6 +140,8 @@ def test_buckets_in_cluster(self):
115140
self.assertEqual(bucket.label, "example-bucket")
116141
self.assertEqual(bucket.objects, 4)
117142
self.assertEqual(bucket.size, 188318981)
143+
self.assertEqual(bucket.endpoint_type, ObjectStorageEndpointType.E1)
144+
self.assertEqual(bucket.s3_endpoint, "us-east-12.linodeobjects.com")
118145

119146
def test_ssl_cert_delete(self):
120147
"""

0 commit comments

Comments
 (0)