Skip to content

Commit 93b4faf

Browse files
Merge pull request #545 from linode/dev
Release v5.30.0
2 parents 79f73cf + a8fa1d7 commit 93b4faf

File tree

9 files changed

+207
-3
lines changed

9 files changed

+207
-3
lines changed

.github/workflows/publish-pypi.yaml

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ on:
55
types: [ published ]
66
jobs:
77
pypi-release:
8+
permissions:
9+
# IMPORTANT: this permission is mandatory for trusted publishing
10+
id-token: write
811
runs-on: ubuntu-latest
12+
environment: pypi-release
913
steps:
1014
- name: Checkout
1115
uses: actions/checkout@v4
@@ -25,5 +29,3 @@ jobs:
2529

2630
- name: Publish the release artifacts to PyPI
2731
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # pin@release/v1.12.4
28-
with:
29-
password: ${{ secrets.PYPI_API_TOKEN }}

linode_api4/groups/object_storage.py

+16
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
ObjectStorageCluster,
2222
ObjectStorageKeyPermission,
2323
ObjectStorageKeys,
24+
ObjectStorageQuota,
2425
)
2526
from linode_api4.util import drop_null_keys
2627

@@ -517,3 +518,18 @@ def object_url_create(
517518
)
518519

519520
return MappedObject(**result)
521+
522+
def quotas(self, *filters):
523+
"""
524+
Lists the active ObjectStorage-related quotas applied to your account.
525+
526+
API Documentation: https://techdocs.akamai.com/linode-api/reference/get-object-storage-quotas
527+
528+
:param filters: Any number of filters to apply to this query.
529+
See :doc:`Filtering Collections</linode_api4/objects/filtering>`
530+
for more details on filtering.
531+
532+
:returns: A list of Object Storage Quotas that matched the query.
533+
:rtype: PaginatedList of ObjectStorageQuota
534+
"""
535+
return self.client._get_and_filter(ObjectStorageQuota, *filters)

linode_api4/objects/object_storage.py

+49
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ class ObjectStorageEndpoint(JSONObject):
5151
s3_endpoint: Optional[str] = None
5252

5353

54+
@dataclass
55+
class ObjectStorageQuotaUsage(JSONObject):
56+
"""
57+
ObjectStorageQuotaUsage contains the fields of an object storage quota usage information.
58+
"""
59+
60+
quota_limit: int = 0
61+
usage: int = 0
62+
63+
5464
class ObjectStorageType(Base):
5565
"""
5666
An ObjectStorageType represents the structure of a valid Object Storage type.
@@ -566,3 +576,42 @@ class ObjectStorageKeys(Base):
566576
"limited": Property(),
567577
"regions": Property(unordered=True),
568578
}
579+
580+
581+
class ObjectStorageQuota(Base):
582+
"""
583+
An Object Storage related quota information on your account.
584+
Object Storage Quota related features are under v4beta and may not currently be available to all users.
585+
586+
API documentation: https://techdocs.akamai.com/linode-api/reference/get-object-storage-quota
587+
"""
588+
589+
api_endpoint = "/object-storage/quotas/{quota_id}"
590+
id_attribute = "quota_id"
591+
592+
properties = {
593+
"quota_id": Property(identifier=True),
594+
"quota_name": Property(),
595+
"endpoint_type": Property(),
596+
"s3_endpoint": Property(),
597+
"description": Property(),
598+
"quota_limit": Property(),
599+
"resource_metric": Property(),
600+
}
601+
602+
def usage(self):
603+
"""
604+
Gets usage data for a specific ObjectStorage Quota resource you can have on your account and the current usage for that resource.
605+
606+
API documentation: https://techdocs.akamai.com/linode-api/reference/get-object-storage-quota-usage
607+
608+
:returns: The Object Storage Quota usage.
609+
:rtype: ObjectStorageQuotaUsage
610+
"""
611+
612+
result = self._client.get(
613+
f"{type(self).api_endpoint}/usage",
614+
model=self,
615+
)
616+
617+
return ObjectStorageQuotaUsage.from_json(result)
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"data": [
3+
{
4+
"quota_id": "obj-objects-us-ord-1",
5+
"quota_name": "Object Storage Maximum Objects",
6+
"description": "Maximum number of Objects this customer is allowed to have on this endpoint.",
7+
"endpoint_type": "E1",
8+
"s3_endpoint": "us-iad-1.linodeobjects.com",
9+
"quota_limit": 50,
10+
"resource_metric": "object"
11+
},
12+
{
13+
"quota_id": "obj-bucket-us-ord-1",
14+
"quota_name": "Object Storage Maximum Buckets",
15+
"description": "Maximum number of buckets this customer is allowed to have on this endpoint.",
16+
"endpoint_type": "E1",
17+
"s3_endpoint": "us-iad-1.linodeobjects.com",
18+
"quota_limit": 50,
19+
"resource_metric": "bucket"
20+
}
21+
],
22+
"page": 1,
23+
"pages": 1,
24+
"results": 2
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"quota_id": "obj-objects-us-ord-1",
3+
"quota_name": "Object Storage Maximum Objects",
4+
"description": "Maximum number of Objects this customer is allowed to have on this endpoint.",
5+
"endpoint_type": "E1",
6+
"s3_endpoint": "us-iad-1.linodeobjects.com",
7+
"quota_limit": 50,
8+
"resource_metric": "object"
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"quota_limit": 100,
3+
"usage": 10
4+
}

test/integration/models/lke/test_lke.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,10 @@ def _to_comparable(p: LKENodePool) -> Dict[str, Any]:
208208

209209
assert _to_comparable(cluster.pools[0]) == _to_comparable(pool)
210210

211-
assert pool.disk_encryption == InstanceDiskEncryptionType.disabled
211+
assert pool.disk_encryption in (
212+
InstanceDiskEncryptionType.enabled,
213+
InstanceDiskEncryptionType.disabled,
214+
)
212215

213216

214217
def test_cluster_dashboard_url_view(lke_cluster):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import pytest
2+
3+
from linode_api4.objects.object_storage import (
4+
ObjectStorageQuota,
5+
ObjectStorageQuotaUsage,
6+
)
7+
8+
9+
def test_list_and_get_obj_storage_quotas(test_linode_client):
10+
quotas = test_linode_client.object_storage.quotas()
11+
12+
if len(quotas) < 1:
13+
pytest.skip("No available quota for testing. Skipping now...")
14+
15+
found_quota = quotas[0]
16+
17+
get_quota = test_linode_client.load(
18+
ObjectStorageQuota, found_quota.quota_id
19+
)
20+
21+
assert found_quota.quota_id == get_quota.quota_id
22+
assert found_quota.quota_name == get_quota.quota_name
23+
assert found_quota.endpoint_type == get_quota.endpoint_type
24+
assert found_quota.s3_endpoint == get_quota.s3_endpoint
25+
assert found_quota.description == get_quota.description
26+
assert found_quota.quota_limit == get_quota.quota_limit
27+
assert found_quota.resource_metric == get_quota.resource_metric
28+
29+
30+
def test_get_obj_storage_quota_usage(test_linode_client):
31+
quotas = test_linode_client.object_storage.quotas()
32+
33+
if len(quotas) < 1:
34+
pytest.skip("No available quota for testing. Skipping now...")
35+
36+
quota_id = quotas[0].quota_id
37+
quota = test_linode_client.load(ObjectStorageQuota, quota_id)
38+
39+
quota_usage = quota.usage()
40+
41+
assert isinstance(quota_usage, ObjectStorageQuotaUsage)
42+
assert quota_usage.quota_limit >= 0
43+
44+
if quota_usage.usage is not None:
45+
assert quota_usage.usage >= 0

test/unit/objects/object_storage_test.py

+51
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
ObjectStorageACL,
77
ObjectStorageBucket,
88
ObjectStorageCluster,
9+
ObjectStorageQuota,
910
)
1011

1112

@@ -284,3 +285,53 @@ def test_object_acl_config_update(self):
284285
"name": "example",
285286
},
286287
)
288+
289+
def test_quota_get_and_list(self):
290+
"""
291+
Test that you can get and list an Object storage quota and usage information.
292+
"""
293+
quota = ObjectStorageQuota(
294+
self.client,
295+
"obj-objects-us-ord-1",
296+
)
297+
298+
self.assertIsNotNone(quota)
299+
self.assertEqual(quota.quota_id, "obj-objects-us-ord-1")
300+
self.assertEqual(quota.quota_name, "Object Storage Maximum Objects")
301+
self.assertEqual(
302+
quota.description,
303+
"Maximum number of Objects this customer is allowed to have on this endpoint.",
304+
)
305+
self.assertEqual(quota.endpoint_type, "E1")
306+
self.assertEqual(quota.s3_endpoint, "us-iad-1.linodeobjects.com")
307+
self.assertEqual(quota.quota_limit, 50)
308+
self.assertEqual(quota.resource_metric, "object")
309+
310+
quota_usage_url = "/object-storage/quotas/obj-objects-us-ord-1/usage"
311+
with self.mock_get(quota_usage_url) as m:
312+
usage = quota.usage()
313+
self.assertIsNotNone(usage)
314+
self.assertEqual(m.call_url, quota_usage_url)
315+
self.assertEqual(usage.quota_limit, 100)
316+
self.assertEqual(usage.usage, 10)
317+
318+
quota_list_url = "/object-storage/quotas"
319+
with self.mock_get(quota_list_url) as m:
320+
quotas = self.client.object_storage.quotas()
321+
self.assertIsNotNone(quotas)
322+
self.assertEqual(m.call_url, quota_list_url)
323+
self.assertEqual(len(quotas), 2)
324+
self.assertEqual(quotas[0].quota_id, "obj-objects-us-ord-1")
325+
self.assertEqual(
326+
quotas[0].quota_name, "Object Storage Maximum Objects"
327+
)
328+
self.assertEqual(
329+
quotas[0].description,
330+
"Maximum number of Objects this customer is allowed to have on this endpoint.",
331+
)
332+
self.assertEqual(quotas[0].endpoint_type, "E1")
333+
self.assertEqual(
334+
quotas[0].s3_endpoint, "us-iad-1.linodeobjects.com"
335+
)
336+
self.assertEqual(quotas[0].quota_limit, 50)
337+
self.assertEqual(quotas[0].resource_metric, "object")

0 commit comments

Comments
 (0)