diff --git a/hcloud/storage_boxes/client.py b/hcloud/storage_boxes/client.py index 4d258b97..e0c76798 100644 --- a/hcloud/storage_boxes/client.py +++ b/hcloud/storage_boxes/client.py @@ -452,6 +452,22 @@ def get_subaccount_by_id( """ return self._client.get_subaccount_by_id(self, id=id) + def get_subaccount_by_name( + self, + name: str, + ) -> BoundStorageBoxSubaccount | None: + """ + Returns a single Subaccount from a Storage Box. + + See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts + + :param name: Name of the Subaccount. + + Experimental: + Storage Box support is experimental, breaking changes may occur within minor releases. + """ + return self._client.get_subaccount_by_name(self, name=name) + def get_subaccount_by_username( self, username: str, @@ -471,6 +487,7 @@ def get_subaccount_by_username( def get_subaccount_list( self, *, + name: str | None = None, username: str | None = None, label_selector: str | None = None, sort: list[str] | None = None, @@ -480,6 +497,7 @@ def get_subaccount_list( See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts + :param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name. :param username: Filter resources by their username. The response will only contain the resources matching exactly the specified username. :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector. :param sort: Sort resources by field and direction. @@ -489,6 +507,7 @@ def get_subaccount_list( """ return self._client.get_subaccount_list( self, + name=name, username=username, label_selector=label_selector, sort=sort, @@ -497,6 +516,7 @@ def get_subaccount_list( def get_subaccount_all( self, *, + name: str | None = None, username: str | None = None, label_selector: str | None = None, sort: list[str] | None = None, @@ -506,6 +526,7 @@ def get_subaccount_all( See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts + :param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name. :param username: Filter resources by their username. The response will only contain the resources matching exactly the specified username. :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector. :param sort: Sort resources by field and direction. @@ -515,6 +536,7 @@ def get_subaccount_all( """ return self._client.get_subaccount_all( self, + name=name, username=username, label_selector=label_selector, sort=sort, @@ -523,6 +545,7 @@ def get_subaccount_all( def create_subaccount( self, *, + name: str | None = None, home_directory: str, password: str, access_settings: StorageBoxSubaccountAccessSettings | None = None, @@ -535,6 +558,7 @@ def create_subaccount( See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-create-a-subaccount :param storage_box: Storage Box to create a Subaccount for. + :param name: Name of the Subaccount. :param home_directory: Home directory of the Subaccount. :param password: Password of the Subaccount. :param access_settings: Access settings of the Subaccount. @@ -546,6 +570,7 @@ def create_subaccount( """ return self._client.create_subaccount( self, + name=name, home_directory=home_directory, password=password, access_settings=access_settings, @@ -658,6 +683,7 @@ def _get_self(self) -> BoundStorageBoxSubaccount: def update( self, *, + name: str | None = None, description: str | None = None, labels: dict[str, str] | None = None, ) -> BoundStorageBoxSubaccount: @@ -666,6 +692,7 @@ def update( See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-update-a-subaccount + :param name: Name of the Subaccount. :param description: Description of the Subaccount. :param labels: User-defined labels (key/value pairs) for the Subaccount. @@ -674,6 +701,7 @@ def update( """ return self._client.update_subaccount( self, + name=name, description=description, labels=labels, ) @@ -1510,6 +1538,28 @@ def get_subaccount_by_id( ) return BoundStorageBoxSubaccount(self, response["subaccount"]) + def get_subaccount_by_name( + self, + storage_box: StorageBox | BoundStorageBox, + name: str, + ) -> BoundStorageBoxSubaccount | None: + """ + Returns a single Subaccount from a Storage Box. + + See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts + + :param storage_box: Storage Box to get the Subaccount from. + :param name: Name of the Subaccount. + + Experimental: + Storage Box support is experimental, breaking changes may occur within minor releases. + """ + return self._get_first_by( + self.get_subaccount_list, + storage_box, + name=name, + ) + def get_subaccount_by_username( self, storage_box: StorageBox | BoundStorageBox, @@ -1536,6 +1586,7 @@ def get_subaccount_list( self, storage_box: StorageBox | BoundStorageBox, *, + name: str | None = None, username: str | None = None, label_selector: str | None = None, sort: list[str] | None = None, @@ -1546,6 +1597,7 @@ def get_subaccount_list( See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts :param storage_box: Storage Box to get the Subaccount from. + :param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name. :param username: Filter resources by their username. The response will only contain the resources matching exactly the specified username. :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector. :param sort: Sort resources by field and direction. @@ -1554,6 +1606,8 @@ def get_subaccount_list( Storage Box support is experimental, breaking changes may occur within minor releases. """ params: dict[str, Any] = {} + if name is not None: + params["name"] = name if username is not None: params["username"] = username if label_selector is not None: @@ -1578,6 +1632,7 @@ def get_subaccount_all( self, storage_box: StorageBox | BoundStorageBox, *, + name: str | None = None, username: str | None = None, label_selector: str | None = None, sort: list[str] | None = None, @@ -1588,6 +1643,7 @@ def get_subaccount_all( See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts :param storage_box: Storage Box to get the Subaccount from. + :param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name. :param username: Filter resources by their username. The response will only contain the resources matching exactly the specified username. :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector. :param sort: Sort resources by field and direction. @@ -1598,6 +1654,7 @@ def get_subaccount_all( # The endpoint does not have pagination, forward to the list method. result, _ = self.get_subaccount_list( storage_box, + name=name, username=username, label_selector=label_selector, sort=sort, @@ -1608,6 +1665,7 @@ def create_subaccount( self, storage_box: StorageBox | BoundStorageBox, *, + name: str | None = None, home_directory: str, password: str, access_settings: StorageBoxSubaccountAccessSettings | None = None, @@ -1620,6 +1678,7 @@ def create_subaccount( See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-create-a-subaccount :param storage_box: Storage Box to create a Subaccount for. + :param name: Name of the Subaccount. :param home_directory: Home directory of the Subaccount. :param password: Password of the Subaccount. :param access_settings: Access settings of the Subaccount. @@ -1633,6 +1692,8 @@ def create_subaccount( "home_directory": home_directory, "password": password, } + if name is not None: + data["name"] = name if access_settings is not None: data["access_settings"] = access_settings.to_payload() if description is not None: @@ -1659,6 +1720,7 @@ def update_subaccount( self, subaccount: StorageBoxSubaccount | BoundStorageBoxSubaccount, *, + name: str | None = None, description: str | None = None, labels: dict[str, str] | None = None, ) -> BoundStorageBoxSubaccount: @@ -1668,6 +1730,7 @@ def update_subaccount( See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-update-a-subaccount :param subaccount: Storage Box Subaccount to update. + :param name: Name of the Subaccount. :param description: Description of the Subaccount. :param labels: User-defined labels (key/value pairs) for the Subaccount. @@ -1678,6 +1741,8 @@ def update_subaccount( raise ValueError("subaccount storage_box property is none") data: dict[str, Any] = {} + if name is not None: + data["name"] = name if description is not None: data["description"] = description if labels is not None: diff --git a/hcloud/storage_boxes/domain.py b/hcloud/storage_boxes/domain.py index 03eaab1f..8d2237a2 100644 --- a/hcloud/storage_boxes/domain.py +++ b/hcloud/storage_boxes/domain.py @@ -373,6 +373,7 @@ class StorageBoxSubaccount(BaseDomain, DomainIdentityMixin): __api_properties__ = ( "id", + "name", "username", "description", "server", @@ -387,6 +388,7 @@ class StorageBoxSubaccount(BaseDomain, DomainIdentityMixin): def __init__( self, id: int | None = None, + name: str | None = None, username: str | None = None, description: str | None = None, server: str | None = None, @@ -397,6 +399,7 @@ def __init__( created: str | None = None, ): self.id = id + self.name = name self.username = username self.description = description self.server = server diff --git a/tests/unit/storage_boxes/test_client.py b/tests/unit/storage_boxes/test_client.py index 0daff945..53d3302f 100644 --- a/tests/unit/storage_boxes/test_client.py +++ b/tests/unit/storage_boxes/test_client.py @@ -78,6 +78,7 @@ class TestBoundStorageBox(BoundModelTestCase): BoundStorageBox.create_subaccount, BoundStorageBox.get_subaccount_all, BoundStorageBox.get_subaccount_by_id, + BoundStorageBox.get_subaccount_by_name, BoundStorageBox.get_subaccount_by_username, BoundStorageBox.get_subaccount_list, ] @@ -899,9 +900,28 @@ def test_get_subaccount_by_id( assert_bound_storage_box_subaccount(result, resource_client) + def test_get_subaccount_by_name( + self, + request_mock: mock.MagicMock, + resource_client: StorageBoxesClient, + storage_box_subaccount1, + ): + request_mock.return_value = {"subaccounts": [storage_box_subaccount1]} + + result = resource_client.get_subaccount_by_name(StorageBox(42), "subaccount1") + + request_mock.assert_called_with( + method="GET", + url="/storage_boxes/42/subaccounts", + params={"name": "subaccount1"}, + ) + + assert_bound_storage_box_subaccount(result, resource_client) + @pytest.mark.parametrize( "params", [ + {"name": "subaccount1"}, {"username": "u42-sub1"}, {"label_selector": "key=value"}, # {"page": 1, "per_page": 10} # No pagination @@ -950,6 +970,7 @@ def test_get_subaccount_list( @pytest.mark.parametrize( "params", [ + {"name": "subaccount1"}, {"username": "u42-sub1"}, {"label_selector": "key=value"}, {"sort": ["id:asc"]}, @@ -1029,6 +1050,7 @@ def test_create_subaccount( result = resource_client.create_subaccount( StorageBox(42), + name="subaccount1", home_directory="tmp", password="secret", access_settings=StorageBoxSubaccountAccessSettings( @@ -1044,6 +1066,7 @@ def test_create_subaccount( method="POST", url="/storage_boxes/42/subaccounts", json={ + "name": "subaccount1", "home_directory": "tmp", "password": "secret", "access_settings": {