Skip to content

Commit 8bff743

Browse files
authored
feat: add name to Storage Box Subaccount (#621)
Related to https://docs.hetzner.cloud/changelog#2026-01-15-storage-box-subaccount-name
1 parent 0d7b27e commit 8bff743

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

hcloud/storage_boxes/client.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,22 @@ def get_subaccount_by_id(
452452
"""
453453
return self._client.get_subaccount_by_id(self, id=id)
454454

455+
def get_subaccount_by_name(
456+
self,
457+
name: str,
458+
) -> BoundStorageBoxSubaccount | None:
459+
"""
460+
Returns a single Subaccount from a Storage Box.
461+
462+
See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
463+
464+
:param name: Name of the Subaccount.
465+
466+
Experimental:
467+
Storage Box support is experimental, breaking changes may occur within minor releases.
468+
"""
469+
return self._client.get_subaccount_by_name(self, name=name)
470+
455471
def get_subaccount_by_username(
456472
self,
457473
username: str,
@@ -471,6 +487,7 @@ def get_subaccount_by_username(
471487
def get_subaccount_list(
472488
self,
473489
*,
490+
name: str | None = None,
474491
username: str | None = None,
475492
label_selector: str | None = None,
476493
sort: list[str] | None = None,
@@ -480,6 +497,7 @@ def get_subaccount_list(
480497
481498
See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
482499
500+
:param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name.
483501
:param username: Filter resources by their username. The response will only contain the resources matching exactly the specified username.
484502
:param label_selector: Filter resources by labels. The response will only contain resources matching the label selector.
485503
:param sort: Sort resources by field and direction.
@@ -489,6 +507,7 @@ def get_subaccount_list(
489507
"""
490508
return self._client.get_subaccount_list(
491509
self,
510+
name=name,
492511
username=username,
493512
label_selector=label_selector,
494513
sort=sort,
@@ -497,6 +516,7 @@ def get_subaccount_list(
497516
def get_subaccount_all(
498517
self,
499518
*,
519+
name: str | None = None,
500520
username: str | None = None,
501521
label_selector: str | None = None,
502522
sort: list[str] | None = None,
@@ -506,6 +526,7 @@ def get_subaccount_all(
506526
507527
See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
508528
529+
:param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name.
509530
:param username: Filter resources by their username. The response will only contain the resources matching exactly the specified username.
510531
:param label_selector: Filter resources by labels. The response will only contain resources matching the label selector.
511532
:param sort: Sort resources by field and direction.
@@ -515,6 +536,7 @@ def get_subaccount_all(
515536
"""
516537
return self._client.get_subaccount_all(
517538
self,
539+
name=name,
518540
username=username,
519541
label_selector=label_selector,
520542
sort=sort,
@@ -523,6 +545,7 @@ def get_subaccount_all(
523545
def create_subaccount(
524546
self,
525547
*,
548+
name: str | None = None,
526549
home_directory: str,
527550
password: str,
528551
access_settings: StorageBoxSubaccountAccessSettings | None = None,
@@ -535,6 +558,7 @@ def create_subaccount(
535558
See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-create-a-subaccount
536559
537560
:param storage_box: Storage Box to create a Subaccount for.
561+
:param name: Name of the Subaccount.
538562
:param home_directory: Home directory of the Subaccount.
539563
:param password: Password of the Subaccount.
540564
:param access_settings: Access settings of the Subaccount.
@@ -546,6 +570,7 @@ def create_subaccount(
546570
"""
547571
return self._client.create_subaccount(
548572
self,
573+
name=name,
549574
home_directory=home_directory,
550575
password=password,
551576
access_settings=access_settings,
@@ -658,6 +683,7 @@ def _get_self(self) -> BoundStorageBoxSubaccount:
658683
def update(
659684
self,
660685
*,
686+
name: str | None = None,
661687
description: str | None = None,
662688
labels: dict[str, str] | None = None,
663689
) -> BoundStorageBoxSubaccount:
@@ -666,6 +692,7 @@ def update(
666692
667693
See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-update-a-subaccount
668694
695+
:param name: Name of the Subaccount.
669696
:param description: Description of the Subaccount.
670697
:param labels: User-defined labels (key/value pairs) for the Subaccount.
671698
@@ -674,6 +701,7 @@ def update(
674701
"""
675702
return self._client.update_subaccount(
676703
self,
704+
name=name,
677705
description=description,
678706
labels=labels,
679707
)
@@ -1510,6 +1538,28 @@ def get_subaccount_by_id(
15101538
)
15111539
return BoundStorageBoxSubaccount(self, response["subaccount"])
15121540

1541+
def get_subaccount_by_name(
1542+
self,
1543+
storage_box: StorageBox | BoundStorageBox,
1544+
name: str,
1545+
) -> BoundStorageBoxSubaccount | None:
1546+
"""
1547+
Returns a single Subaccount from a Storage Box.
1548+
1549+
See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
1550+
1551+
:param storage_box: Storage Box to get the Subaccount from.
1552+
:param name: Name of the Subaccount.
1553+
1554+
Experimental:
1555+
Storage Box support is experimental, breaking changes may occur within minor releases.
1556+
"""
1557+
return self._get_first_by(
1558+
self.get_subaccount_list,
1559+
storage_box,
1560+
name=name,
1561+
)
1562+
15131563
def get_subaccount_by_username(
15141564
self,
15151565
storage_box: StorageBox | BoundStorageBox,
@@ -1536,6 +1586,7 @@ def get_subaccount_list(
15361586
self,
15371587
storage_box: StorageBox | BoundStorageBox,
15381588
*,
1589+
name: str | None = None,
15391590
username: str | None = None,
15401591
label_selector: str | None = None,
15411592
sort: list[str] | None = None,
@@ -1546,6 +1597,7 @@ def get_subaccount_list(
15461597
See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
15471598
15481599
:param storage_box: Storage Box to get the Subaccount from.
1600+
:param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name.
15491601
:param username: Filter resources by their username. The response will only contain the resources matching exactly the specified username.
15501602
:param label_selector: Filter resources by labels. The response will only contain resources matching the label selector.
15511603
:param sort: Sort resources by field and direction.
@@ -1554,6 +1606,8 @@ def get_subaccount_list(
15541606
Storage Box support is experimental, breaking changes may occur within minor releases.
15551607
"""
15561608
params: dict[str, Any] = {}
1609+
if name is not None:
1610+
params["name"] = name
15571611
if username is not None:
15581612
params["username"] = username
15591613
if label_selector is not None:
@@ -1578,6 +1632,7 @@ def get_subaccount_all(
15781632
self,
15791633
storage_box: StorageBox | BoundStorageBox,
15801634
*,
1635+
name: str | None = None,
15811636
username: str | None = None,
15821637
label_selector: str | None = None,
15831638
sort: list[str] | None = None,
@@ -1588,6 +1643,7 @@ def get_subaccount_all(
15881643
See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
15891644
15901645
:param storage_box: Storage Box to get the Subaccount from.
1646+
:param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name.
15911647
:param username: Filter resources by their username. The response will only contain the resources matching exactly the specified username.
15921648
:param label_selector: Filter resources by labels. The response will only contain resources matching the label selector.
15931649
:param sort: Sort resources by field and direction.
@@ -1598,6 +1654,7 @@ def get_subaccount_all(
15981654
# The endpoint does not have pagination, forward to the list method.
15991655
result, _ = self.get_subaccount_list(
16001656
storage_box,
1657+
name=name,
16011658
username=username,
16021659
label_selector=label_selector,
16031660
sort=sort,
@@ -1608,6 +1665,7 @@ def create_subaccount(
16081665
self,
16091666
storage_box: StorageBox | BoundStorageBox,
16101667
*,
1668+
name: str | None = None,
16111669
home_directory: str,
16121670
password: str,
16131671
access_settings: StorageBoxSubaccountAccessSettings | None = None,
@@ -1620,6 +1678,7 @@ def create_subaccount(
16201678
See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-create-a-subaccount
16211679
16221680
:param storage_box: Storage Box to create a Subaccount for.
1681+
:param name: Name of the Subaccount.
16231682
:param home_directory: Home directory of the Subaccount.
16241683
:param password: Password of the Subaccount.
16251684
:param access_settings: Access settings of the Subaccount.
@@ -1633,6 +1692,8 @@ def create_subaccount(
16331692
"home_directory": home_directory,
16341693
"password": password,
16351694
}
1695+
if name is not None:
1696+
data["name"] = name
16361697
if access_settings is not None:
16371698
data["access_settings"] = access_settings.to_payload()
16381699
if description is not None:
@@ -1659,6 +1720,7 @@ def update_subaccount(
16591720
self,
16601721
subaccount: StorageBoxSubaccount | BoundStorageBoxSubaccount,
16611722
*,
1723+
name: str | None = None,
16621724
description: str | None = None,
16631725
labels: dict[str, str] | None = None,
16641726
) -> BoundStorageBoxSubaccount:
@@ -1668,6 +1730,7 @@ def update_subaccount(
16681730
See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-update-a-subaccount
16691731
16701732
:param subaccount: Storage Box Subaccount to update.
1733+
:param name: Name of the Subaccount.
16711734
:param description: Description of the Subaccount.
16721735
:param labels: User-defined labels (key/value pairs) for the Subaccount.
16731736
@@ -1678,6 +1741,8 @@ def update_subaccount(
16781741
raise ValueError("subaccount storage_box property is none")
16791742

16801743
data: dict[str, Any] = {}
1744+
if name is not None:
1745+
data["name"] = name
16811746
if description is not None:
16821747
data["description"] = description
16831748
if labels is not None:

hcloud/storage_boxes/domain.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ class StorageBoxSubaccount(BaseDomain, DomainIdentityMixin):
373373

374374
__api_properties__ = (
375375
"id",
376+
"name",
376377
"username",
377378
"description",
378379
"server",
@@ -387,6 +388,7 @@ class StorageBoxSubaccount(BaseDomain, DomainIdentityMixin):
387388
def __init__(
388389
self,
389390
id: int | None = None,
391+
name: str | None = None,
390392
username: str | None = None,
391393
description: str | None = None,
392394
server: str | None = None,
@@ -397,6 +399,7 @@ def __init__(
397399
created: str | None = None,
398400
):
399401
self.id = id
402+
self.name = name
400403
self.username = username
401404
self.description = description
402405
self.server = server

tests/unit/storage_boxes/test_client.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class TestBoundStorageBox(BoundModelTestCase):
7878
BoundStorageBox.create_subaccount,
7979
BoundStorageBox.get_subaccount_all,
8080
BoundStorageBox.get_subaccount_by_id,
81+
BoundStorageBox.get_subaccount_by_name,
8182
BoundStorageBox.get_subaccount_by_username,
8283
BoundStorageBox.get_subaccount_list,
8384
]
@@ -899,9 +900,28 @@ def test_get_subaccount_by_id(
899900

900901
assert_bound_storage_box_subaccount(result, resource_client)
901902

903+
def test_get_subaccount_by_name(
904+
self,
905+
request_mock: mock.MagicMock,
906+
resource_client: StorageBoxesClient,
907+
storage_box_subaccount1,
908+
):
909+
request_mock.return_value = {"subaccounts": [storage_box_subaccount1]}
910+
911+
result = resource_client.get_subaccount_by_name(StorageBox(42), "subaccount1")
912+
913+
request_mock.assert_called_with(
914+
method="GET",
915+
url="/storage_boxes/42/subaccounts",
916+
params={"name": "subaccount1"},
917+
)
918+
919+
assert_bound_storage_box_subaccount(result, resource_client)
920+
902921
@pytest.mark.parametrize(
903922
"params",
904923
[
924+
{"name": "subaccount1"},
905925
{"username": "u42-sub1"},
906926
{"label_selector": "key=value"},
907927
# {"page": 1, "per_page": 10} # No pagination
@@ -950,6 +970,7 @@ def test_get_subaccount_list(
950970
@pytest.mark.parametrize(
951971
"params",
952972
[
973+
{"name": "subaccount1"},
953974
{"username": "u42-sub1"},
954975
{"label_selector": "key=value"},
955976
{"sort": ["id:asc"]},
@@ -1029,6 +1050,7 @@ def test_create_subaccount(
10291050

10301051
result = resource_client.create_subaccount(
10311052
StorageBox(42),
1053+
name="subaccount1",
10321054
home_directory="tmp",
10331055
password="secret",
10341056
access_settings=StorageBoxSubaccountAccessSettings(
@@ -1044,6 +1066,7 @@ def test_create_subaccount(
10441066
method="POST",
10451067
url="/storage_boxes/42/subaccounts",
10461068
json={
1069+
"name": "subaccount1",
10471070
"home_directory": "tmp",
10481071
"password": "secret",
10491072
"access_settings": {

0 commit comments

Comments
 (0)