Skip to content

Commit

Permalink
feat: allow returning root_password with servers rebuild
Browse files Browse the repository at this point in the history
  • Loading branch information
jooola committed Aug 8, 2023
1 parent c5447ab commit 4344358
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 17 deletions.
45 changes: 34 additions & 11 deletions hcloud/servers/client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import warnings
from typing import TYPE_CHECKING, Any, NamedTuple

from ..actions import ActionsPageResult, BoundAction
Expand All @@ -9,8 +10,7 @@
from ..floating_ips import BoundFloatingIP
from ..images import BoundImage, CreateImageResponse
from ..isos import BoundIso
from ..networks import BoundNetwork # noqa
from ..networks import Network # noqa
from ..networks import BoundNetwork, Network
from ..placement_groups import BoundPlacementGroup
from ..primary_ips import BoundPrimaryIP
from ..server_types import BoundServerType
Expand All @@ -23,6 +23,7 @@
PrivateNet,
PublicNetwork,
PublicNetworkFirewall,
RebuildResponse,
RequestConsoleResponse,
ResetPasswordResponse,
Server,
Expand Down Expand Up @@ -296,13 +297,18 @@ def create_image(
"""
return self._client.create_image(self, description, type, labels)

def rebuild(self, image: Image | BoundImage) -> BoundAction:
def rebuild(
self,
image: Image | BoundImage,
*,
return_response: bool = False,
) -> RebuildResponse | BoundAction:
"""Rebuilds a server overwriting its disk with the content of an image, thereby destroying all data on the target server.
:param image: :class:`BoundImage <hcloud.images.client.BoundImage>` or :class:`Image <hcloud.servers.domain.Image>`
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
:param image: Image to use for the builded server
:param return_response: Whether to return the full response or only the action.
"""
return self._client.rebuild(self, image)
return self._client.rebuild(self, image, return_response=return_response)

def change_type(
self,
Expand Down Expand Up @@ -916,20 +922,37 @@ def rebuild(
self,
server: Server | BoundServer,
image: Image | BoundImage,
) -> BoundAction:
*,
return_response: bool = False,
) -> RebuildResponse | BoundAction:
"""Rebuilds a server overwriting its disk with the content of an image, thereby destroying all data on the target server.
:param server: :class:`BoundServer <hcloud.servers.client.BoundServer>` or :class:`Server <hcloud.servers.domain.Server>`
:param image: :class:`BoundImage <hcloud.images.client.BoundImage>` or :class:`Image <hcloud.servers.domain.Image>`
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
:param server: Server to rebuild
:param image: Image to use for the builded server
:param return_response: Whether to return the full response or only the action.
"""
data: dict[str, Any] = {"image": image.id_or_name}
response = self._client.request(
url=f"/servers/{server.id}/actions/rebuild",
method="POST",
json=data,
)
return BoundAction(self._client.actions, response["action"])

rebuild_response = RebuildResponse(
action=BoundAction(self._client.actions, response["action"]),
root_password=response.get("root_password"),
)

if not return_response:
warnings.warn(
"Returning only the 'action' is deprecated, please set the "
"'return_response' keyword argument to 'True' to return the full "
"rebuild response and update your code accordingly.",
DeprecationWarning,
stacklevel=2,
)
return rebuild_response.action
return rebuild_response

def enable_backup(self, server: Server | BoundServer) -> BoundAction:
"""Enables and configures the automatic daily backup option for the server. Enabling automatic backups will increase the price of the server by 20%.
Expand Down
18 changes: 18 additions & 0 deletions hcloud/servers/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,24 @@ def __init__(
self.password = password


class RebuildResponse(BaseDomain):
"""Rebuild Response Domain
:param action: Shows the progress of the server rebuild action
:param root_password: The root password of the server when not using SSH keys
"""

__slots__ = ("action", "root_password")

def __init__(
self,
action: BoundAction,
root_password: str | None,
):
self.action = action
self.root_password = root_password


class PublicNetwork(BaseDomain):
"""Public Network Domain
Expand Down
26 changes: 20 additions & 6 deletions tests/unit/servers/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,15 +305,19 @@ def test_create_image(

def test_rebuild(self, hetzner_client, bound_server, generic_action):
hetzner_client.request.return_value = generic_action
action = bound_server.rebuild(Image(name="ubuntu-20.04"))
response = bound_server.rebuild(
Image(name="ubuntu-20.04"),
return_response=True,
)
hetzner_client.request.assert_called_with(
url="/servers/14/actions/rebuild",
method="POST",
json={"image": "ubuntu-20.04"},
)

assert action.id == 1
assert action.progress == 0
assert response.action.id == 1
assert response.action.progress == 0
assert isinstance(response.root_password, str | None)

def test_enable_backup(self, hetzner_client, bound_server, generic_action):
hetzner_client.request.return_value = generic_action
Expand Down Expand Up @@ -1032,15 +1036,25 @@ def test_create_image(self, servers_client, server, response_server_create_image
)
def test_rebuild(self, servers_client, server, generic_action):
servers_client._client.request.return_value = generic_action
action = servers_client.rebuild(server, Image(name="ubuntu-20.04"))
response = servers_client.rebuild(
server,
Image(name="ubuntu-20.04"),
return_response=True,
)
servers_client._client.request.assert_called_with(
url="/servers/1/actions/rebuild",
method="POST",
json={"image": "ubuntu-20.04"},
)

assert action.id == 1
assert action.progress == 0
assert response.action.id == 1
assert response.action.progress == 0
assert isinstance(response.root_password, str | None)

def test_rebuild_return_response_deprecation(self, servers_client, generic_action):
servers_client._client.request.return_value = generic_action
with pytest.deprecated_call():
servers_client.rebuild(Server(id=1), Image(name="ubuntu-20.04"))

@pytest.mark.parametrize(
"server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]
Expand Down

0 comments on commit 4344358

Please sign in to comment.