From 3667197efb7b18ec842efd504785965911f8ac4b Mon Sep 17 00:00:00 2001
From: Daniel Baumann <daniel.baumann@progress-linux.org>
Date: Wed, 5 Jun 2024 18:18:34 +0200
Subject: Adding upstream version 10.0.0+dfsg.

Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
---
 .../hetzner/hcloud/plugins/modules/certificate.py  |  21 +-
 .../hcloud/plugins/modules/certificate_info.py     |  33 +-
 .../hcloud/plugins/modules/datacenter_info.py      |   9 +-
 .../hetzner/hcloud/plugins/modules/firewall.py     |  29 +-
 .../hcloud/plugins/modules/firewall_info.py        |  29 +-
 .../hcloud/plugins/modules/firewall_resource.py    |   7 +-
 .../hetzner/hcloud/plugins/modules/floating_ip.py  |  25 +-
 .../hcloud/plugins/modules/floating_ip_info.py     |  34 +-
 .../hetzner/hcloud/plugins/modules/image_info.py   |  31 +-
 .../hetzner/hcloud/plugins/modules/iso_info.py     |   9 +-
 .../hcloud/plugins/modules/load_balancer.py        |  50 +-
 .../hcloud/plugins/modules/load_balancer_info.py   |  79 ++-
 .../plugins/modules/load_balancer_network.py       |  15 +-
 .../plugins/modules/load_balancer_service.py       |  39 +-
 .../hcloud/plugins/modules/load_balancer_target.py |  17 +-
 .../plugins/modules/load_balancer_type_info.py     |  27 +-
 .../hcloud/plugins/modules/location_info.py        |  23 +-
 .../hetzner/hcloud/plugins/modules/network.py      |  23 +-
 .../hetzner/hcloud/plugins/modules/network_info.py |  99 ++-
 .../hcloud/plugins/modules/placement_group.py      |   7 +-
 .../hetzner/hcloud/plugins/modules/primary_ip.py   |  97 ++-
 .../hcloud/plugins/modules/primary_ip_info.py      |  44 +-
 .../hetzner/hcloud/plugins/modules/rdns.py         |  19 +-
 .../hetzner/hcloud/plugins/modules/route.py        |  11 +-
 .../hetzner/hcloud/plugins/modules/server.py       | 675 +++++++++++----------
 .../hetzner/hcloud/plugins/modules/server_info.py  |  56 +-
 .../hcloud/plugins/modules/server_network.py       |  18 +-
 .../hcloud/plugins/modules/server_type_info.py     |  49 +-
 .../hetzner/hcloud/plugins/modules/ssh_key.py      |   9 +-
 .../hetzner/hcloud/plugins/modules/ssh_key_info.py |  27 +-
 .../hetzner/hcloud/plugins/modules/subnetwork.py   |  15 +-
 .../hetzner/hcloud/plugins/modules/volume.py       |  33 +-
 .../hetzner/hcloud/plugins/modules/volume_info.py  |  32 +-
 33 files changed, 884 insertions(+), 807 deletions(-)

(limited to 'ansible_collections/hetzner/hcloud/plugins/modules')

diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/certificate.py b/ansible_collections/hetzner/hcloud/plugins/modules/certificate.py
index ea39be6ca..53466e48f 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/certificate.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/certificate.py
@@ -146,7 +146,6 @@ hcloud_certificate:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -160,14 +159,14 @@ class AnsibleHCloudCertificate(AnsibleHCloud):
 
     def _prepare_result(self):
         return {
-            "id": to_native(self.hcloud_certificate.id),
-            "name": to_native(self.hcloud_certificate.name),
-            "type": to_native(self.hcloud_certificate.type),
-            "fingerprint": to_native(self.hcloud_certificate.fingerprint),
-            "certificate": to_native(self.hcloud_certificate.certificate),
-            "not_valid_before": to_native(self.hcloud_certificate.not_valid_before),
-            "not_valid_after": to_native(self.hcloud_certificate.not_valid_after),
-            "domain_names": [to_native(domain) for domain in self.hcloud_certificate.domain_names],
+            "id": str(self.hcloud_certificate.id),
+            "name": self.hcloud_certificate.name,
+            "type": self.hcloud_certificate.type,
+            "fingerprint": self.hcloud_certificate.fingerprint,
+            "certificate": self.hcloud_certificate.certificate,
+            "not_valid_before": self.hcloud_certificate.not_valid_before.isoformat(),
+            "not_valid_after": self.hcloud_certificate.not_valid_after.isoformat(),
+            "domain_names": self.hcloud_certificate.domain_names,
             "labels": self.hcloud_certificate.labels,
         }
 
@@ -203,7 +202,9 @@ class AnsibleHCloudCertificate(AnsibleHCloud):
             if not self.module.check_mode:
                 try:
                     resp = self.client.certificates.create_managed(**params)
-                    resp.action.wait_until_finished(max_retries=1000)
+                    # Action should take 60 to 90 seconds on average, wait for 5m to
+                    # allow DNS or Let's Encrypt slowdowns.
+                    resp.action.wait_until_finished(max_retries=300)
                 except HCloudException as exception:
                     self.fail_json_hcloud(exception)
 
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/certificate_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/certificate_info.py
index e074046fd..37b944341 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/certificate_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/certificate_info.py
@@ -87,7 +87,6 @@ hcloud_certificate_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -100,23 +99,25 @@ class AnsibleHCloudCertificateInfo(AnsibleHCloud):
     hcloud_certificate_info: list[BoundCertificate] | None = None
 
     def _prepare_result(self):
-        certificates = []
+        tmp = []
 
         for certificate in self.hcloud_certificate_info:
-            if certificate:
-                certificates.append(
-                    {
-                        "id": to_native(certificate.id),
-                        "name": to_native(certificate.name),
-                        "fingerprint": to_native(certificate.fingerprint),
-                        "certificate": to_native(certificate.certificate),
-                        "not_valid_before": to_native(certificate.not_valid_before),
-                        "not_valid_after": to_native(certificate.not_valid_after),
-                        "domain_names": [to_native(domain) for domain in certificate.domain_names],
-                        "labels": certificate.labels,
-                    }
-                )
-        return certificates
+            if certificate is None:
+                continue
+
+            tmp.append(
+                {
+                    "id": str(certificate.id),
+                    "name": certificate.name,
+                    "fingerprint": certificate.fingerprint,
+                    "certificate": certificate.certificate,
+                    "not_valid_before": certificate.not_valid_before.isoformat(),
+                    "not_valid_after": certificate.not_valid_after.isoformat(),
+                    "domain_names": certificate.domain_names,
+                    "labels": certificate.labels,
+                }
+            )
+        return tmp
 
     def get_certificates(self):
         try:
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/datacenter_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/datacenter_info.py
index f6665a6fb..85475dd44 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/datacenter_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/datacenter_info.py
@@ -118,7 +118,6 @@ hcloud_datacenter_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -139,10 +138,10 @@ class AnsibleHCloudDatacenterInfo(AnsibleHCloud):
 
             tmp.append(
                 {
-                    "id": to_native(datacenter.id),
-                    "name": to_native(datacenter.name),
-                    "description": to_native(datacenter.description),
-                    "location": to_native(datacenter.location.name),
+                    "id": str(datacenter.id),
+                    "name": datacenter.name,
+                    "description": datacenter.description,
+                    "location": datacenter.location.name,
                     "server_types": {
                         "available": [o.id for o in datacenter.server_types.available],
                         "available_for_migration": [o.id for o in datacenter.server_types.available_for_migration],
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/firewall.py b/ansible_collections/hetzner/hcloud/plugins/modules/firewall.py
index 3c51b5c0a..30f17eb9b 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/firewall.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/firewall.py
@@ -219,7 +219,6 @@ hcloud_firewall:
 import time
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import APIException, HCloudException
@@ -237,8 +236,8 @@ class AnsibleHCloudFirewall(AnsibleHCloud):
 
     def _prepare_result(self):
         return {
-            "id": to_native(self.hcloud_firewall.id),
-            "name": to_native(self.hcloud_firewall.name),
+            "id": str(self.hcloud_firewall.id),
+            "name": self.hcloud_firewall.name,
             "rules": [self._prepare_result_rule(rule) for rule in self.hcloud_firewall.rules],
             "labels": self.hcloud_firewall.labels,
             "applied_to": [self._prepare_result_applied_to(resource) for resource in self.hcloud_firewall.applied_to],
@@ -246,27 +245,25 @@ class AnsibleHCloudFirewall(AnsibleHCloud):
 
     def _prepare_result_rule(self, rule: FirewallRule):
         return {
-            "direction": to_native(rule.direction),
-            "protocol": to_native(rule.protocol),
-            "port": to_native(rule.port) if rule.port is not None else None,
-            "source_ips": [to_native(cidr) for cidr in rule.source_ips],
-            "destination_ips": [to_native(cidr) for cidr in rule.destination_ips],
-            "description": to_native(rule.description) if rule.description is not None else None,
+            "direction": rule.direction,
+            "protocol": rule.protocol,
+            "port": rule.port,
+            "source_ips": rule.source_ips,
+            "destination_ips": rule.destination_ips,
+            "description": rule.description,
         }
 
     def _prepare_result_applied_to(self, resource: FirewallResource):
         result = {
-            "type": to_native(resource.type),
-            "server": to_native(resource.server.id) if resource.server is not None else None,
-            "label_selector": (
-                to_native(resource.label_selector.selector) if resource.label_selector is not None else None
-            ),
+            "type": resource.type,
+            "server": str(resource.server.id) if resource.server is not None else None,
+            "label_selector": resource.label_selector.selector if resource.label_selector is not None else None,
         }
         if resource.applied_to_resources is not None:
             result["applied_to_resources"] = [
                 {
-                    "type": to_native(item.type),
-                    "server": to_native(item.server.id) if item.server is not None else None,
+                    "type": item.type,
+                    "server": str(item.server.id) if item.server is not None else None,
                 }
                 for item in resource.applied_to_resources
             ]
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/firewall_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/firewall_info.py
index 7e7a623d0..a07d9ec54 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/firewall_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/firewall_info.py
@@ -142,7 +142,6 @@ hcloud_firewall_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -167,8 +166,8 @@ class AnsibleHCloudFirewallInfo(AnsibleHCloud):
 
             tmp.append(
                 {
-                    "id": to_native(firewall.id),
-                    "name": to_native(firewall.name),
+                    "id": str(firewall.id),
+                    "name": firewall.name,
                     "labels": firewall.labels,
                     "rules": [self._prepare_result_rule(rule) for rule in firewall.rules],
                     "applied_to": [self._prepare_result_applied_to(resource) for resource in firewall.applied_to],
@@ -179,27 +178,25 @@ class AnsibleHCloudFirewallInfo(AnsibleHCloud):
 
     def _prepare_result_rule(self, rule: FirewallRule):
         return {
-            "description": to_native(rule.description) if rule.description is not None else None,
-            "direction": to_native(rule.direction),
-            "protocol": to_native(rule.protocol),
-            "port": to_native(rule.port) if rule.port is not None else None,
-            "source_ips": [to_native(cidr) for cidr in rule.source_ips],
-            "destination_ips": [to_native(cidr) for cidr in rule.destination_ips],
+            "description": rule.description,
+            "direction": rule.direction,
+            "protocol": rule.protocol,
+            "port": rule.port,
+            "source_ips": rule.source_ips,
+            "destination_ips": rule.destination_ips,
         }
 
     def _prepare_result_applied_to(self, resource: FirewallResource):
         result = {
-            "type": to_native(resource.type),
-            "server": to_native(resource.server.id) if resource.server is not None else None,
-            "label_selector": (
-                to_native(resource.label_selector.selector) if resource.label_selector is not None else None
-            ),
+            "type": resource.type,
+            "server": str(resource.server.id) if resource.server is not None else None,
+            "label_selector": resource.label_selector.selector if resource.label_selector is not None else None,
         }
         if resource.applied_to_resources is not None:
             result["applied_to_resources"] = [
                 {
-                    "type": to_native(item.type),
-                    "server": to_native(item.server.id) if item.server is not None else None,
+                    "type": item.type,
+                    "server": str(item.server.id) if item.server is not None else None,
                 }
                 for item in resource.applied_to_resources
             ]
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/firewall_resource.py b/ansible_collections/hetzner/hcloud/plugins/modules/firewall_resource.py
index 207f27092..7c0271ba3 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/firewall_resource.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/firewall_resource.py
@@ -103,7 +103,6 @@ hcloud_firewall_resource:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -125,12 +124,12 @@ class AnsibleHCloudFirewallResource(AnsibleHCloud):
         label_selectors = []
         for resource in self.hcloud_firewall_resource.applied_to:
             if resource.type == FirewallResource.TYPE_SERVER:
-                servers.append(to_native(resource.server.name))
+                servers.append(resource.server.name)
             elif resource.type == FirewallResource.TYPE_LABEL_SELECTOR:
-                label_selectors.append(to_native(resource.label_selector.selector))
+                label_selectors.append(resource.label_selector.selector)
 
         return {
-            "firewall": to_native(self.hcloud_firewall_resource.name),
+            "firewall": self.hcloud_firewall_resource.name,
             "servers": servers,
             "label_selectors": label_selectors,
         }
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/floating_ip.py b/ansible_collections/hetzner/hcloud/plugins/modules/floating_ip.py
index e037dd7a1..022036124 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/floating_ip.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/floating_ip.py
@@ -160,7 +160,6 @@ hcloud_floating_ip:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -173,19 +172,15 @@ class AnsibleHCloudFloatingIP(AnsibleHCloud):
     hcloud_floating_ip: BoundFloatingIP | None = None
 
     def _prepare_result(self):
-        server = None
-
-        if self.hcloud_floating_ip.server is not None:
-            server = to_native(self.hcloud_floating_ip.server.name)
         return {
-            "id": to_native(self.hcloud_floating_ip.id),
-            "name": to_native(self.hcloud_floating_ip.name),
-            "description": to_native(self.hcloud_floating_ip.description),
-            "ip": to_native(self.hcloud_floating_ip.ip),
-            "type": to_native(self.hcloud_floating_ip.type),
-            "home_location": to_native(self.hcloud_floating_ip.home_location.name),
+            "id": str(self.hcloud_floating_ip.id),
+            "name": self.hcloud_floating_ip.name,
+            "description": self.hcloud_floating_ip.description,
+            "ip": self.hcloud_floating_ip.ip,
+            "type": self.hcloud_floating_ip.type,
+            "home_location": self.hcloud_floating_ip.home_location.name,
             "labels": self.hcloud_floating_ip.labels,
-            "server": server,
+            "server": self.hcloud_floating_ip.server.name if self.hcloud_floating_ip.server is not None else None,
             "delete_protection": self.hcloud_floating_ip.protection["delete"],
         }
 
@@ -221,7 +216,8 @@ class AnsibleHCloudFloatingIP(AnsibleHCloud):
 
                 delete_protection = self.module.params.get("delete_protection")
                 if delete_protection is not None:
-                    self.hcloud_floating_ip.change_protection(delete=delete_protection).wait_until_finished()
+                    action = self.hcloud_floating_ip.change_protection(delete=delete_protection)
+                    action.wait_until_finished()
         except HCloudException as exception:
             self.fail_json_hcloud(exception)
         self._mark_as_changed()
@@ -266,7 +262,8 @@ class AnsibleHCloudFloatingIP(AnsibleHCloud):
             delete_protection = self.module.params.get("delete_protection")
             if delete_protection is not None and delete_protection != self.hcloud_floating_ip.protection["delete"]:
                 if not self.module.check_mode:
-                    self.hcloud_floating_ip.change_protection(delete=delete_protection).wait_until_finished()
+                    action = self.hcloud_floating_ip.change_protection(delete=delete_protection)
+                    action.wait_until_finished()
                 self._mark_as_changed()
 
             self._get_floating_ip()
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/floating_ip_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/floating_ip_info.py
index 663d29622..6595799ba 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/floating_ip_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/floating_ip_info.py
@@ -100,7 +100,6 @@ hcloud_floating_ip_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -116,23 +115,22 @@ class AnsibleHCloudFloatingIPInfo(AnsibleHCloud):
         tmp = []
 
         for floating_ip in self.hcloud_floating_ip_info:
-            if floating_ip is not None:
-                server_name = None
-                if floating_ip.server is not None:
-                    server_name = floating_ip.server.name
-                tmp.append(
-                    {
-                        "id": to_native(floating_ip.id),
-                        "name": to_native(floating_ip.name),
-                        "description": to_native(floating_ip.description),
-                        "ip": to_native(floating_ip.ip),
-                        "type": to_native(floating_ip.type),
-                        "server": to_native(server_name),
-                        "home_location": to_native(floating_ip.home_location.name),
-                        "labels": floating_ip.labels,
-                        "delete_protection": floating_ip.protection["delete"],
-                    }
-                )
+            if floating_ip is None:
+                continue
+
+            tmp.append(
+                {
+                    "id": str(floating_ip.id),
+                    "name": floating_ip.name,
+                    "description": floating_ip.description,
+                    "ip": floating_ip.ip,
+                    "type": floating_ip.type,
+                    "server": floating_ip.server.name if floating_ip.server is not None else None,
+                    "home_location": floating_ip.home_location.name,
+                    "labels": floating_ip.labels,
+                    "delete_protection": floating_ip.protection["delete"],
+                }
+            )
 
         return tmp
 
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/image_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/image_info.py
index b0d7fc482..a3a1331c5 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/image_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/image_info.py
@@ -112,7 +112,6 @@ hcloud_image_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -128,20 +127,22 @@ class AnsibleHCloudImageInfo(AnsibleHCloud):
         tmp = []
 
         for image in self.hcloud_image_info:
-            if image is not None:
-                tmp.append(
-                    {
-                        "id": to_native(image.id),
-                        "status": to_native(image.status),
-                        "type": to_native(image.type),
-                        "name": to_native(image.name),
-                        "description": to_native(image.description),
-                        "os_flavor": to_native(image.os_flavor),
-                        "os_version": to_native(image.os_version),
-                        "architecture": to_native(image.architecture),
-                        "labels": image.labels,
-                    }
-                )
+            if image is None:
+                continue
+
+            tmp.append(
+                {
+                    "id": str(image.id),
+                    "status": image.status,
+                    "type": image.type,
+                    "name": image.name,
+                    "description": image.description,
+                    "os_flavor": image.os_flavor,
+                    "os_version": image.os_version,
+                    "architecture": image.architecture,
+                    "labels": image.labels,
+                }
+            )
         return tmp
 
     def get_images(self):
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/iso_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/iso_info.py
index e623d1714..aab33cab2 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/iso_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/iso_info.py
@@ -122,7 +122,6 @@ hcloud_iso_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -143,13 +142,13 @@ class AnsibleHCloudIsoInfo(AnsibleHCloud):
 
             tmp.append(
                 {
-                    "id": to_native(iso_info.id),
-                    "name": to_native(iso_info.name),
-                    "description": to_native(iso_info.description),
+                    "id": str(iso_info.id),
+                    "name": iso_info.name,
+                    "description": iso_info.description,
                     "type": iso_info.type,
                     "architecture": iso_info.architecture,
                     "deprecated": (
-                        iso_info.deprecation.unavailable_after if iso_info.deprecation is not None else None
+                        iso_info.deprecation.unavailable_after.isoformat() if iso_info.deprecation is not None else None
                     ),
                     "deprecation": (
                         {
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer.py b/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer.py
index 1a0d8712a..11dbf96fb 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer.py
@@ -152,7 +152,6 @@ hcloud_load_balancer:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -168,23 +167,20 @@ class AnsibleHCloudLoadBalancer(AnsibleHCloud):
     hcloud_load_balancer: BoundLoadBalancer | None = None
 
     def _prepare_result(self):
-        private_ipv4_address = (
-            None
-            if len(self.hcloud_load_balancer.private_net) == 0
-            else to_native(self.hcloud_load_balancer.private_net[0].ip)
-        )
         return {
-            "id": to_native(self.hcloud_load_balancer.id),
-            "name": to_native(self.hcloud_load_balancer.name),
-            "ipv4_address": to_native(self.hcloud_load_balancer.public_net.ipv4.ip),
-            "ipv6_address": to_native(self.hcloud_load_balancer.public_net.ipv6.ip),
-            "private_ipv4_address": private_ipv4_address,
-            "load_balancer_type": to_native(self.hcloud_load_balancer.load_balancer_type.name),
-            "algorithm": to_native(self.hcloud_load_balancer.algorithm.type),
-            "location": to_native(self.hcloud_load_balancer.location.name),
+            "id": str(self.hcloud_load_balancer.id),
+            "name": self.hcloud_load_balancer.name,
+            "ipv4_address": self.hcloud_load_balancer.public_net.ipv4.ip,
+            "ipv6_address": self.hcloud_load_balancer.public_net.ipv6.ip,
+            "private_ipv4_address": (
+                self.hcloud_load_balancer.private_net[0].ip if len(self.hcloud_load_balancer.private_net) else None
+            ),
+            "load_balancer_type": self.hcloud_load_balancer.load_balancer_type.name,
+            "algorithm": self.hcloud_load_balancer.algorithm.type,
+            "location": self.hcloud_load_balancer.location.name,
             "labels": self.hcloud_load_balancer.labels,
             "delete_protection": self.hcloud_load_balancer.protection["delete"],
-            "disable_public_interface": False if self.hcloud_load_balancer.public_net.enabled else True,
+            "disable_public_interface": not self.hcloud_load_balancer.public_net.enabled,
         }
 
     def _get_load_balancer(self):
@@ -217,12 +213,13 @@ class AnsibleHCloudLoadBalancer(AnsibleHCloud):
 
             if not self.module.check_mode:
                 resp = self.client.load_balancers.create(**params)
-                resp.action.wait_until_finished(max_retries=1000)
+                resp.action.wait_until_finished()
 
                 delete_protection = self.module.params.get("delete_protection")
                 if delete_protection is not None:
                     self._get_load_balancer()
-                    self.hcloud_load_balancer.change_protection(delete=delete_protection).wait_until_finished()
+                    action = self.hcloud_load_balancer.change_protection(delete=delete_protection)
+                    action.wait_until_finished()
         except HCloudException as exception:
             self.fail_json_hcloud(exception)
         self._mark_as_changed()
@@ -239,7 +236,8 @@ class AnsibleHCloudLoadBalancer(AnsibleHCloud):
             delete_protection = self.module.params.get("delete_protection")
             if delete_protection is not None and delete_protection != self.hcloud_load_balancer.protection["delete"]:
                 if not self.module.check_mode:
-                    self.hcloud_load_balancer.change_protection(delete=delete_protection).wait_until_finished()
+                    action = self.hcloud_load_balancer.change_protection(delete=delete_protection)
+                    action.wait_until_finished()
                 self._mark_as_changed()
             self._get_load_balancer()
 
@@ -249,9 +247,11 @@ class AnsibleHCloudLoadBalancer(AnsibleHCloud):
             ):
                 if not self.module.check_mode:
                     if disable_public_interface is True:
-                        self.hcloud_load_balancer.disable_public_interface().wait_until_finished()
+                        action = self.hcloud_load_balancer.disable_public_interface()
+                        action.wait_until_finished()
                     else:
-                        self.hcloud_load_balancer.enable_public_interface().wait_until_finished()
+                        action = self.hcloud_load_balancer.enable_public_interface()
+                        action.wait_until_finished()
                 self._mark_as_changed()
 
             load_balancer_type = self.module.params.get("load_balancer_type")
@@ -263,17 +263,17 @@ class AnsibleHCloudLoadBalancer(AnsibleHCloud):
                 if not new_load_balancer_type:
                     self.module.fail_json(msg="unknown load balancer type")
                 if not self.module.check_mode:
-                    self.hcloud_load_balancer.change_type(
+                    action = self.hcloud_load_balancer.change_type(
                         load_balancer_type=new_load_balancer_type,
-                    ).wait_until_finished(max_retries=1000)
+                    )
+                    action.wait_until_finished()
 
                 self._mark_as_changed()
 
             algorithm = self.module.params.get("algorithm")
             if algorithm is not None and self.hcloud_load_balancer.algorithm.type != algorithm:
-                self.hcloud_load_balancer.change_algorithm(
-                    algorithm=LoadBalancerAlgorithm(type=algorithm)
-                ).wait_until_finished()
+                action = self.hcloud_load_balancer.change_algorithm(algorithm=LoadBalancerAlgorithm(type=algorithm))
+                action.wait_until_finished()
                 self._mark_as_changed()
 
             self._get_load_balancer()
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_info.py
index 19ead98c2..4ed5f134b 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_info.py
@@ -277,11 +277,14 @@ hcloud_load_balancer_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
-from ..module_utils.vendor.hcloud.load_balancers import BoundLoadBalancer
+from ..module_utils.vendor.hcloud.load_balancers import (
+    BoundLoadBalancer,
+    LoadBalancerService,
+    LoadBalancerTarget,
+)
 
 
 class AnsibleHCloudLoadBalancerInfo(AnsibleHCloud):
@@ -293,44 +296,40 @@ class AnsibleHCloudLoadBalancerInfo(AnsibleHCloud):
         tmp = []
 
         for load_balancer in self.hcloud_load_balancer_info:
-            if load_balancer is not None:
-                services = [self._prepare_service_result(service) for service in load_balancer.services]
-                targets = [self._prepare_target_result(target) for target in load_balancer.targets]
-
-                private_ipv4_address = (
-                    None if len(load_balancer.private_net) == 0 else to_native(load_balancer.private_net[0].ip)
-                )
-                tmp.append(
-                    {
-                        "id": to_native(load_balancer.id),
-                        "name": to_native(load_balancer.name),
-                        "ipv4_address": to_native(load_balancer.public_net.ipv4.ip),
-                        "ipv6_address": to_native(load_balancer.public_net.ipv6.ip),
-                        "private_ipv4_address": private_ipv4_address,
-                        "load_balancer_type": to_native(load_balancer.load_balancer_type.name),
-                        "location": to_native(load_balancer.location.name),
-                        "labels": load_balancer.labels,
-                        "delete_protection": load_balancer.protection["delete"],
-                        "disable_public_interface": False if load_balancer.public_net.enabled else True,
-                        "targets": targets,
-                        "services": services,
-                    }
-                )
+            if load_balancer is None:
+                continue
+
+            tmp.append(
+                {
+                    "id": str(load_balancer.id),
+                    "name": load_balancer.name,
+                    "ipv4_address": load_balancer.public_net.ipv4.ip,
+                    "ipv6_address": load_balancer.public_net.ipv6.ip,
+                    "private_ipv4_address": load_balancer.private_net[0].ip if len(load_balancer.private_net) else None,
+                    "load_balancer_type": load_balancer.load_balancer_type.name,
+                    "location": load_balancer.location.name,
+                    "labels": load_balancer.labels,
+                    "delete_protection": load_balancer.protection["delete"],
+                    "disable_public_interface": False if load_balancer.public_net.enabled else True,
+                    "targets": [self._prepare_target_result(target) for target in load_balancer.targets],
+                    "services": [self._prepare_service_result(service) for service in load_balancer.services],
+                }
+            )
         return tmp
 
     @staticmethod
-    def _prepare_service_result(service):
+    def _prepare_service_result(service: LoadBalancerService):
         http = None
         if service.protocol != "tcp":
             http = {
-                "cookie_name": to_native(service.http.cookie_name),
-                "cookie_lifetime": service.http.cookie_name,
+                "cookie_name": service.http.cookie_name,
+                "cookie_lifetime": service.http.cookie_lifetime,
                 "redirect_http": service.http.redirect_http,
                 "sticky_sessions": service.http.sticky_sessions,
-                "certificates": [to_native(certificate.name) for certificate in service.http.certificates],
+                "certificates": [certificate.name for certificate in service.http.certificates],
             }
         health_check = {
-            "protocol": to_native(service.health_check.protocol),
+            "protocol": service.health_check.protocol,
             "port": service.health_check.port,
             "interval": service.health_check.interval,
             "timeout": service.health_check.timeout,
@@ -338,14 +337,14 @@ class AnsibleHCloudLoadBalancerInfo(AnsibleHCloud):
         }
         if service.health_check.protocol != "tcp":
             health_check["http"] = {
-                "domain": to_native(service.health_check.http.domain),
-                "path": to_native(service.health_check.http.path),
-                "response": to_native(service.health_check.http.response),
-                "certificates": [to_native(status_code) for status_code in service.health_check.http.status_codes],
+                "domain": service.health_check.http.domain,
+                "path": service.health_check.http.path,
+                "response": service.health_check.http.response,
+                "certificates": service.health_check.http.status_codes,
                 "tls": service.health_check.http.tls,
             }
         return {
-            "protocol": to_native(service.protocol),
+            "protocol": service.protocol,
             "listen_port": service.listen_port,
             "destination_port": service.destination_port,
             "proxyprotocol": service.proxyprotocol,
@@ -354,17 +353,17 @@ class AnsibleHCloudLoadBalancerInfo(AnsibleHCloud):
         }
 
     @staticmethod
-    def _prepare_target_result(target):
+    def _prepare_target_result(target: LoadBalancerTarget):
         result = {
-            "type": to_native(target.type),
+            "type": target.type,
             "use_private_ip": target.use_private_ip,
         }
         if target.type == "server":
-            result["server"] = to_native(target.server.name)
+            result["server"] = target.server.name
         elif target.type == "label_selector":
-            result["label_selector"] = to_native(target.label_selector.selector)
+            result["label_selector"] = target.label_selector.selector
         elif target.type == "ip":
-            result["ip"] = to_native(target.ip.ip)
+            result["ip"] = target.ip.ip
 
         if target.health_status is not None:
             result["health_status"] = [
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_network.py b/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_network.py
index 4560f8735..b6ec486ed 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_network.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_network.py
@@ -90,7 +90,6 @@ hcloud_load_balancer_network:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -107,9 +106,9 @@ class AnsibleHCloudLoadBalancerNetwork(AnsibleHCloud):
 
     def _prepare_result(self):
         return {
-            "network": to_native(self.hcloud_network.name),
-            "load_balancer": to_native(self.hcloud_load_balancer.name),
-            "ip": to_native(self.hcloud_load_balancer_network.ip),
+            "network": self.hcloud_network.name,
+            "load_balancer": self.hcloud_load_balancer.name,
+            "ip": self.hcloud_load_balancer_network.ip,
         }
 
     def _get_load_balancer_and_network(self):
@@ -140,7 +139,8 @@ class AnsibleHCloudLoadBalancerNetwork(AnsibleHCloud):
 
         if not self.module.check_mode:
             try:
-                self.hcloud_load_balancer.attach_to_network(**params).wait_until_finished()
+                action = self.hcloud_load_balancer.attach_to_network(**params)
+                action.wait_until_finished()
             except HCloudException as exception:
                 self.fail_json_hcloud(exception)
 
@@ -160,9 +160,8 @@ class AnsibleHCloudLoadBalancerNetwork(AnsibleHCloud):
         if self.hcloud_load_balancer_network is not None and self.hcloud_load_balancer is not None:
             if not self.module.check_mode:
                 try:
-                    self.hcloud_load_balancer.detach_from_network(
-                        self.hcloud_load_balancer_network.network
-                    ).wait_until_finished()
+                    action = self.hcloud_load_balancer.detach_from_network(self.hcloud_load_balancer_network.network)
+                    action.wait_until_finished()
                     self._mark_as_changed()
                 except HCloudException as exception:
                     self.fail_json_hcloud(exception)
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_service.py b/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_service.py
index 1fc18deef..29e37083c 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_service.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_service.py
@@ -279,7 +279,6 @@ hcloud_load_balancer_service:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import APIException, HCloudException
@@ -302,16 +301,16 @@ class AnsibleHCloudLoadBalancerService(AnsibleHCloud):
         http = None
         if self.hcloud_load_balancer_service.protocol != "tcp":
             http = {
-                "cookie_name": to_native(self.hcloud_load_balancer_service.http.cookie_name),
-                "cookie_lifetime": self.hcloud_load_balancer_service.http.cookie_name,
+                "cookie_name": self.hcloud_load_balancer_service.http.cookie_name,
+                "cookie_lifetime": self.hcloud_load_balancer_service.http.cookie_lifetime,
                 "redirect_http": self.hcloud_load_balancer_service.http.redirect_http,
                 "sticky_sessions": self.hcloud_load_balancer_service.http.sticky_sessions,
                 "certificates": [
-                    to_native(certificate.name) for certificate in self.hcloud_load_balancer_service.http.certificates
+                    certificate.name for certificate in self.hcloud_load_balancer_service.http.certificates
                 ],
             }
         health_check = {
-            "protocol": to_native(self.hcloud_load_balancer_service.health_check.protocol),
+            "protocol": self.hcloud_load_balancer_service.health_check.protocol,
             "port": self.hcloud_load_balancer_service.health_check.port,
             "interval": self.hcloud_load_balancer_service.health_check.interval,
             "timeout": self.hcloud_load_balancer_service.health_check.timeout,
@@ -319,18 +318,15 @@ class AnsibleHCloudLoadBalancerService(AnsibleHCloud):
         }
         if self.hcloud_load_balancer_service.health_check.protocol != "tcp":
             health_check["http"] = {
-                "domain": to_native(self.hcloud_load_balancer_service.health_check.http.domain),
-                "path": to_native(self.hcloud_load_balancer_service.health_check.http.path),
-                "response": to_native(self.hcloud_load_balancer_service.health_check.http.response),
-                "status_codes": [
-                    to_native(status_code)
-                    for status_code in self.hcloud_load_balancer_service.health_check.http.status_codes
-                ],
+                "domain": self.hcloud_load_balancer_service.health_check.http.domain,
+                "path": self.hcloud_load_balancer_service.health_check.http.path,
+                "response": self.hcloud_load_balancer_service.health_check.http.response,
+                "status_codes": self.hcloud_load_balancer_service.health_check.http.status_codes,
                 "tls": self.hcloud_load_balancer_service.health_check.http.tls,
             }
         return {
-            "load_balancer": to_native(self.hcloud_load_balancer.name),
-            "protocol": to_native(self.hcloud_load_balancer_service.protocol),
+            "load_balancer": self.hcloud_load_balancer.name,
+            "protocol": self.hcloud_load_balancer_service.protocol,
             "listen_port": self.hcloud_load_balancer_service.listen_port,
             "destination_port": self.hcloud_load_balancer_service.destination_port,
             "proxyprotocol": self.hcloud_load_balancer_service.proxyprotocol,
@@ -372,9 +368,8 @@ class AnsibleHCloudLoadBalancerService(AnsibleHCloud):
 
         if not self.module.check_mode:
             try:
-                self.hcloud_load_balancer.add_service(LoadBalancerService(**params)).wait_until_finished(
-                    max_retries=1000
-                )
+                action = self.hcloud_load_balancer.add_service(LoadBalancerService(**params))
+                action.wait_until_finished()
             except HCloudException as exception:
                 self.fail_json_hcloud(exception)
         self._mark_as_changed()
@@ -468,9 +463,8 @@ class AnsibleHCloudLoadBalancerService(AnsibleHCloud):
                 changed = True
 
             if not self.module.check_mode:
-                self.hcloud_load_balancer.update_service(LoadBalancerService(**params)).wait_until_finished(
-                    max_retries=1000
-                )
+                action = self.hcloud_load_balancer.update_service(LoadBalancerService(**params))
+                action.wait_until_finished()
         except HCloudException as exception:
             self.fail_json_hcloud(exception)
         self._get_load_balancer()
@@ -496,9 +490,8 @@ class AnsibleHCloudLoadBalancerService(AnsibleHCloud):
             if self.hcloud_load_balancer_service is not None:
                 if not self.module.check_mode:
                     try:
-                        self.hcloud_load_balancer.delete_service(self.hcloud_load_balancer_service).wait_until_finished(
-                            max_retries=1000
-                        )
+                        action = self.hcloud_load_balancer.delete_service(self.hcloud_load_balancer_service)
+                        action.wait_until_finished()
                     except HCloudException as exception:
                         self.fail_json_hcloud(exception)
                 self._mark_as_changed()
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_target.py b/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_target.py
index 36e7f608f..c392ae712 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_target.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_target.py
@@ -134,7 +134,6 @@ hcloud_load_balancer_target:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import APIException, HCloudException
@@ -156,17 +155,17 @@ class AnsibleHCloudLoadBalancerTarget(AnsibleHCloud):
 
     def _prepare_result(self):
         result = {
-            "type": to_native(self.hcloud_load_balancer_target.type),
-            "load_balancer": to_native(self.hcloud_load_balancer.name),
+            "type": self.hcloud_load_balancer_target.type,
+            "load_balancer": self.hcloud_load_balancer.name,
             "use_private_ip": self.hcloud_load_balancer_target.use_private_ip,
         }
 
         if self.hcloud_load_balancer_target.type == "server":
-            result["server"] = to_native(self.hcloud_load_balancer_target.server.name)
+            result["server"] = self.hcloud_load_balancer_target.server.name
         elif self.hcloud_load_balancer_target.type == "label_selector":
-            result["label_selector"] = to_native(self.hcloud_load_balancer_target.label_selector.selector)
+            result["label_selector"] = self.hcloud_load_balancer_target.label_selector.selector
         elif self.hcloud_load_balancer_target.type == "ip":
-            result["ip"] = to_native(self.hcloud_load_balancer_target.ip.ip)
+            result["ip"] = self.hcloud_load_balancer_target.ip.ip
         return result
 
     def _get_load_balancer_and_target(self):
@@ -225,7 +224,8 @@ class AnsibleHCloudLoadBalancerTarget(AnsibleHCloud):
 
         if not self.module.check_mode:
             try:
-                self.hcloud_load_balancer.add_target(**params).wait_until_finished()
+                action = self.hcloud_load_balancer.add_target(**params)
+                action.wait_until_finished()
             except APIException as exception:
                 if exception.code == "locked" or exception.code == "conflict":
                     self._create_load_balancer_target()
@@ -270,7 +270,8 @@ class AnsibleHCloudLoadBalancerTarget(AnsibleHCloud):
                         use_private_ip=False,
                     )
                 try:
-                    self.hcloud_load_balancer.remove_target(target).wait_until_finished()
+                    action = self.hcloud_load_balancer.remove_target(target)
+                    action.wait_until_finished()
                 except HCloudException as exception:
                     self.fail_json_hcloud(exception)
             self._mark_as_changed()
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_type_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_type_info.py
index 67feafd59..90505651c 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_type_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/load_balancer_type_info.py
@@ -88,7 +88,6 @@ hcloud_load_balancer_type_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -104,18 +103,20 @@ class AnsibleHCloudLoadBalancerTypeInfo(AnsibleHCloud):
         tmp = []
 
         for load_balancer_type in self.hcloud_load_balancer_type_info:
-            if load_balancer_type is not None:
-                tmp.append(
-                    {
-                        "id": to_native(load_balancer_type.id),
-                        "name": to_native(load_balancer_type.name),
-                        "description": to_native(load_balancer_type.description),
-                        "max_connections": load_balancer_type.max_connections,
-                        "max_services": load_balancer_type.max_services,
-                        "max_targets": load_balancer_type.max_targets,
-                        "max_assigned_certificates": load_balancer_type.max_assigned_certificates,
-                    }
-                )
+            if load_balancer_type is None:
+                continue
+
+            tmp.append(
+                {
+                    "id": str(load_balancer_type.id),
+                    "name": load_balancer_type.name,
+                    "description": load_balancer_type.description,
+                    "max_connections": load_balancer_type.max_connections,
+                    "max_services": load_balancer_type.max_services,
+                    "max_targets": load_balancer_type.max_targets,
+                    "max_assigned_certificates": load_balancer_type.max_assigned_certificates,
+                }
+            )
         return tmp
 
     def get_load_balancer_types(self):
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/location_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/location_info.py
index ac495c6c8..676917bfc 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/location_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/location_info.py
@@ -78,7 +78,6 @@ hcloud_location_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -94,16 +93,18 @@ class AnsibleHCloudLocationInfo(AnsibleHCloud):
         tmp = []
 
         for location in self.hcloud_location_info:
-            if location is not None:
-                tmp.append(
-                    {
-                        "id": to_native(location.id),
-                        "name": to_native(location.name),
-                        "description": to_native(location.description),
-                        "city": to_native(location.city),
-                        "country": to_native(location.country),
-                    }
-                )
+            if location is None:
+                continue
+
+            tmp.append(
+                {
+                    "id": str(location.id),
+                    "name": location.name,
+                    "description": location.description,
+                    "city": location.city,
+                    "country": location.country,
+                }
+            )
         return tmp
 
     def get_locations(self):
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/network.py b/ansible_collections/hetzner/hcloud/plugins/modules/network.py
index 24e45a48d..92fe9461e 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/network.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/network.py
@@ -115,7 +115,6 @@ hcloud_network:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -129,9 +128,9 @@ class AnsibleHCloudNetwork(AnsibleHCloud):
 
     def _prepare_result(self):
         return {
-            "id": to_native(self.hcloud_network.id),
-            "name": to_native(self.hcloud_network.name),
-            "ip_range": to_native(self.hcloud_network.ip_range),
+            "id": str(self.hcloud_network.id),
+            "name": self.hcloud_network.name,
+            "ip_range": self.hcloud_network.ip_range,
             "expose_routes_to_vswitch": self.hcloud_network.expose_routes_to_vswitch,
             "delete_protection": self.hcloud_network.protection["delete"],
             "labels": self.hcloud_network.labels,
@@ -165,7 +164,8 @@ class AnsibleHCloudNetwork(AnsibleHCloud):
                 delete_protection = self.module.params.get("delete_protection")
                 if delete_protection is not None:
                     self._get_network()
-                    self.hcloud_network.change_protection(delete=delete_protection).wait_until_finished()
+                    action = self.hcloud_network.change_protection(delete=delete_protection)
+                    action.wait_until_finished()
         except HCloudException as exception:
             self.fail_json_hcloud(exception)
         self._mark_as_changed()
@@ -173,6 +173,13 @@ class AnsibleHCloudNetwork(AnsibleHCloud):
 
     def _update_network(self):
         try:
+            name = self.module.params.get("name")
+            if name is not None and self.hcloud_network.name != name:
+                self.module.fail_on_missing_params(required_params=["id"])
+                if not self.module.check_mode:
+                    self.hcloud_network.update(name=name)
+                self._mark_as_changed()
+
             labels = self.module.params.get("labels")
             if labels is not None and labels != self.hcloud_network.labels:
                 if not self.module.check_mode:
@@ -182,7 +189,8 @@ class AnsibleHCloudNetwork(AnsibleHCloud):
             ip_range = self.module.params.get("ip_range")
             if ip_range is not None and ip_range != self.hcloud_network.ip_range:
                 if not self.module.check_mode:
-                    self.hcloud_network.change_ip_range(ip_range=ip_range).wait_until_finished()
+                    action = self.hcloud_network.change_ip_range(ip_range=ip_range)
+                    action.wait_until_finished()
                 self._mark_as_changed()
 
             expose_routes_to_vswitch = self.module.params.get("expose_routes_to_vswitch")
@@ -197,7 +205,8 @@ class AnsibleHCloudNetwork(AnsibleHCloud):
             delete_protection = self.module.params.get("delete_protection")
             if delete_protection is not None and delete_protection != self.hcloud_network.protection["delete"]:
                 if not self.module.check_mode:
-                    self.hcloud_network.change_protection(delete=delete_protection).wait_until_finished()
+                    action = self.hcloud_network.change_protection(delete=delete_protection)
+                    action.wait_until_finished()
                 self._mark_as_changed()
         except HCloudException as exception:
             self.fail_json_hcloud(exception)
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/network_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/network_info.py
index 4008352b4..8f1e5fbf7 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/network_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/network_info.py
@@ -185,7 +185,6 @@ hcloud_network_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -201,55 +200,55 @@ class AnsibleHCloudNetworkInfo(AnsibleHCloud):
         tmp = []
 
         for network in self.hcloud_network_info:
-            if network is not None:
-                subnets = []
-                for subnet in network.subnets:
-                    prepared_subnet = {
-                        "type": subnet.type,
-                        "ip_range": subnet.ip_range,
-                        "network_zone": subnet.network_zone,
-                        "gateway": subnet.gateway,
-                    }
-                    subnets.append(prepared_subnet)
-                routes = []
-                for route in network.routes:
-                    prepared_route = {"destination": route.destination, "gateway": route.gateway}
-                    routes.append(prepared_route)
-
-                servers = []
-                for server in network.servers:
-                    image = None if server.image is None else to_native(server.image.name)
-                    ipv4_address = None if server.public_net.ipv4 is None else to_native(server.public_net.ipv4.ip)
-                    ipv6 = None if server.public_net.ipv6 is None else to_native(server.public_net.ipv6.ip)
-                    prepared_server = {
-                        "id": to_native(server.id),
-                        "name": to_native(server.name),
-                        "ipv4_address": ipv4_address,
-                        "ipv6": ipv6,
-                        "image": image,
-                        "server_type": to_native(server.server_type.name),
-                        "datacenter": to_native(server.datacenter.name),
-                        "location": to_native(server.datacenter.location.name),
-                        "rescue_enabled": server.rescue_enabled,
-                        "backup_window": to_native(server.backup_window),
-                        "labels": server.labels,
-                        "status": to_native(server.status),
-                    }
-                    servers.append(prepared_server)
-
-                tmp.append(
-                    {
-                        "id": to_native(network.id),
-                        "name": to_native(network.name),
-                        "ip_range": to_native(network.ip_range),
-                        "subnetworks": subnets,
-                        "routes": routes,
-                        "expose_routes_to_vswitch": network.expose_routes_to_vswitch,
-                        "servers": servers,
-                        "labels": network.labels,
-                        "delete_protection": network.protection["delete"],
-                    }
-                )
+            if network is None:
+                continue
+
+            subnets = []
+            for subnet in network.subnets:
+                prepared_subnet = {
+                    "type": subnet.type,
+                    "ip_range": subnet.ip_range,
+                    "network_zone": subnet.network_zone,
+                    "gateway": subnet.gateway,
+                }
+                subnets.append(prepared_subnet)
+
+            routes = []
+            for route in network.routes:
+                prepared_route = {"destination": route.destination, "gateway": route.gateway}
+                routes.append(prepared_route)
+
+            servers = []
+            for server in network.servers:
+                prepared_server = {
+                    "id": str(server.id),
+                    "name": server.name,
+                    "ipv4_address": server.public_net.ipv4.ip if server.public_net.ipv4 is not None else None,
+                    "ipv6": server.public_net.ipv6.ip if server.public_net.ipv6 is not None else None,
+                    "image": server.image.name if server.image is not None else None,
+                    "server_type": server.server_type.name,
+                    "datacenter": server.datacenter.name,
+                    "location": server.datacenter.location.name,
+                    "rescue_enabled": server.rescue_enabled,
+                    "backup_window": server.backup_window,
+                    "labels": server.labels,
+                    "status": server.status,
+                }
+                servers.append(prepared_server)
+
+            tmp.append(
+                {
+                    "id": str(network.id),
+                    "name": network.name,
+                    "ip_range": network.ip_range,
+                    "subnetworks": subnets,
+                    "routes": routes,
+                    "expose_routes_to_vswitch": network.expose_routes_to_vswitch,
+                    "servers": servers,
+                    "labels": network.labels,
+                    "delete_protection": network.protection["delete"],
+                }
+            )
         return tmp
 
     def get_networks(self):
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/placement_group.py b/ansible_collections/hetzner/hcloud/plugins/modules/placement_group.py
index ba26fad22..45a0cd76b 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/placement_group.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/placement_group.py
@@ -107,7 +107,6 @@ hcloud_placement_group:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -121,10 +120,10 @@ class AnsibleHCloudPlacementGroup(AnsibleHCloud):
 
     def _prepare_result(self):
         return {
-            "id": to_native(self.hcloud_placement_group.id),
-            "name": to_native(self.hcloud_placement_group.name),
+            "id": str(self.hcloud_placement_group.id),
+            "name": self.hcloud_placement_group.name,
             "labels": self.hcloud_placement_group.labels,
-            "type": to_native(self.hcloud_placement_group.type),
+            "type": self.hcloud_placement_group.type,
             "servers": self.hcloud_placement_group.servers,
         }
 
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/primary_ip.py b/ansible_collections/hetzner/hcloud/plugins/modules/primary_ip.py
index 607f6c7e1..08bcea493 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/primary_ip.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/primary_ip.py
@@ -35,6 +35,12 @@ options:
             - Home Location of the Hetzner Cloud Primary IP.
             - Required if no I(server) is given and Primary IP does not exist.
         type: str
+    server:
+        description:
+            - Name or ID of the Hetzner Cloud Server the Primary IP should be assigned to.
+            - The Primary IP cannot be assigned to a running server.
+            - Required if no O(datacenter) is given and the Primary IP does not exist.
+        type: str
     type:
         description:
             - Type of the Primary IP.
@@ -43,9 +49,9 @@ options:
         type: str
     auto_delete:
         description:
-            - Delete this Primary IP when the resource it is assigned to is deleted
+            - Delete the Primary IP when the resource it is assigned to is deleted.
         type: bool
-        default: no
+        default: false
     delete_protection:
         description:
             - Protect the Primary IP for deletion.
@@ -66,22 +72,39 @@ extends_documentation_fragment:
 """
 
 EXAMPLES = """
-- name: Create a basic IPv4 Primary IP
+- name: Create a IPv4 Primary IP
   hetzner.hcloud.primary_ip:
     name: my-primary-ip
     datacenter: fsn1-dc14
     type: ipv4
     state: present
-- name: Create a basic IPv6 Primary IP
+
+- name: Create a IPv6 Primary IP
   hetzner.hcloud.primary_ip:
     name: my-primary-ip
     datacenter: fsn1-dc14
     type: ipv6
     state: present
-- name: Primary IP should be absent
+
+- name: Delete a Primary IP
   hetzner.hcloud.primary_ip:
     name: my-primary-ip
     state: absent
+
+- name: Ensure the server is stopped
+  hetzner.hcloud.server:
+    name: my-server
+    state: stopped
+- name: Create a Primary IP attached to a Server
+  hetzner.hcloud.primary_ip:
+    name: my-primary-ip
+    server: my-server
+    type: ipv4
+    state: present
+- name: Ensure the server is started
+  hetzner.hcloud.server:
+    name: my-server
+    state: started
 """
 
 RETURN = """
@@ -127,10 +150,24 @@ hcloud_primary_ip:
             sample:
                 key: value
                 mylabel: 123
+        assignee_id:
+            description: ID of the resource the Primary IP is assigned to, null if it is not assigned.
+            type: int
+            returned: always
+            sample: 1937415
+        assignee_type:
+            description: Resource type the Primary IP can be assigned to.
+            type: str
+            returned: always
+            sample: server
+        auto_delete:
+            description: Delete the Primary IP when the resource it is assigned to is deleted.
+            type: bool
+            returned: always
+            sample: false
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -144,13 +181,18 @@ class AnsibleHCloudPrimaryIP(AnsibleHCloud):
 
     def _prepare_result(self):
         return {
-            "id": to_native(self.hcloud_primary_ip.id),
-            "name": to_native(self.hcloud_primary_ip.name),
-            "ip": to_native(self.hcloud_primary_ip.ip),
-            "type": to_native(self.hcloud_primary_ip.type),
-            "datacenter": to_native(self.hcloud_primary_ip.datacenter.name),
+            "id": str(self.hcloud_primary_ip.id),
+            "name": self.hcloud_primary_ip.name,
+            "ip": self.hcloud_primary_ip.ip,
+            "type": self.hcloud_primary_ip.type,
+            "datacenter": self.hcloud_primary_ip.datacenter.name,
             "labels": self.hcloud_primary_ip.labels,
             "delete_protection": self.hcloud_primary_ip.protection["delete"],
+            "assignee_id": (
+                str(self.hcloud_primary_ip.assignee_id) if self.hcloud_primary_ip.assignee_id is not None else None
+            ),
+            "assignee_type": self.hcloud_primary_ip.assignee_type,
+            "auto_delete": self.hcloud_primary_ip.auto_delete,
         }
 
     def _get_primary_ip(self):
@@ -163,23 +205,35 @@ class AnsibleHCloudPrimaryIP(AnsibleHCloud):
             self.fail_json_hcloud(exception)
 
     def _create_primary_ip(self):
-        self.module.fail_on_missing_params(required_params=["type", "datacenter"])
+        self.fail_on_invalid_params(
+            required=["type", "name"],
+            required_one_of=[["server", "datacenter"]],
+        )
         try:
             params = {
                 "type": self.module.params.get("type"),
                 "name": self.module.params.get("name"),
-                "datacenter": self.client.datacenters.get_by_name(self.module.params.get("datacenter")),
+                "auto_delete": self.module.params.get("auto_delete"),
+                "datacenter": None,  # TODO: https://github.com/hetznercloud/hcloud-python/pull/363
             }
 
+            if self.module.params.get("datacenter") is not None:
+                params["datacenter"] = self.client.datacenters.get_by_name(self.module.params.get("datacenter"))
+            elif self.module.params.get("server") is not None:
+                params["assignee_id"] = self._client_get_by_name_or_id("servers", self.module.params.get("server")).id
+
             if self.module.params.get("labels") is not None:
                 params["labels"] = self.module.params.get("labels")
             if not self.module.check_mode:
                 resp = self.client.primary_ips.create(**params)
+                if resp.action is not None:
+                    resp.action.wait_until_finished()
                 self.hcloud_primary_ip = resp.primary_ip
 
                 delete_protection = self.module.params.get("delete_protection")
                 if delete_protection is not None:
-                    self.hcloud_primary_ip.change_protection(delete=delete_protection).wait_until_finished()
+                    action = self.hcloud_primary_ip.change_protection(delete=delete_protection)
+                    action.wait_until_finished()
         except HCloudException as exception:
             self.fail_json_hcloud(exception)
         self._mark_as_changed()
@@ -187,16 +241,26 @@ class AnsibleHCloudPrimaryIP(AnsibleHCloud):
 
     def _update_primary_ip(self):
         try:
+            changes = {}
+
+            auto_delete = self.module.params.get("auto_delete")
+            if auto_delete is not None and auto_delete != self.hcloud_primary_ip.auto_delete:
+                changes["auto_delete"] = auto_delete
+
             labels = self.module.params.get("labels")
             if labels is not None and labels != self.hcloud_primary_ip.labels:
+                changes["labels"] = labels
+
+            if changes:
                 if not self.module.check_mode:
-                    self.hcloud_primary_ip.update(labels=labels)
+                    self.hcloud_primary_ip.update(**changes)
                 self._mark_as_changed()
 
             delete_protection = self.module.params.get("delete_protection")
             if delete_protection is not None and delete_protection != self.hcloud_primary_ip.protection["delete"]:
                 if not self.module.check_mode:
-                    self.hcloud_primary_ip.change_protection(delete=delete_protection).wait_until_finished()
+                    action = self.hcloud_primary_ip.change_protection(delete=delete_protection)
+                    action.wait_until_finished()
                 self._mark_as_changed()
 
             self._get_primary_ip()
@@ -228,6 +292,7 @@ class AnsibleHCloudPrimaryIP(AnsibleHCloud):
                 id={"type": "int"},
                 name={"type": "str"},
                 datacenter={"type": "str"},
+                server={"type": "str"},
                 auto_delete={"type": "bool", "default": False},
                 type={"choices": ["ipv4", "ipv6"]},
                 labels={"type": "dict"},
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/primary_ip_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/primary_ip_info.py
index c0bfdbb35..72e359ae2 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/primary_ip_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/primary_ip_info.py
@@ -117,10 +117,14 @@ hcloud_primary_ip_info:
             description: True if the Primary IP is protected for deletion
             returned: always
             type: bool
+        auto_delete:
+            description: Delete the Primary IP when the resource it is assigned to is deleted.
+            type: bool
+            returned: always
+            sample: false
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -136,26 +140,24 @@ class AnsibleHCloudPrimaryIPInfo(AnsibleHCloud):
         tmp = []
 
         for primary_ip in self.hcloud_primary_ip_info:
-            if primary_ip is not None:
-                dns_ptr = None
-                if len(primary_ip.dns_ptr) > 0:
-                    dns_ptr = primary_ip.dns_ptr[0]["dns_ptr"]
-                tmp.append(
-                    {
-                        "id": to_native(primary_ip.id),
-                        "name": to_native(primary_ip.name),
-                        "ip": to_native(primary_ip.ip),
-                        "type": to_native(primary_ip.type),
-                        "assignee_id": (
-                            to_native(primary_ip.assignee_id) if primary_ip.assignee_id is not None else None
-                        ),
-                        "assignee_type": to_native(primary_ip.assignee_type),
-                        "home_location": to_native(primary_ip.datacenter.name),
-                        "dns_ptr": to_native(dns_ptr) if dns_ptr is not None else None,
-                        "labels": primary_ip.labels,
-                        "delete_protection": primary_ip.protection["delete"],
-                    }
-                )
+            if primary_ip is None:
+                continue
+
+            tmp.append(
+                {
+                    "id": str(primary_ip.id),
+                    "name": primary_ip.name,
+                    "ip": primary_ip.ip,
+                    "type": primary_ip.type,
+                    "assignee_id": str(primary_ip.assignee_id) if primary_ip.assignee_id is not None else None,
+                    "assignee_type": primary_ip.assignee_type,
+                    "auto_delete": primary_ip.auto_delete,
+                    "home_location": primary_ip.datacenter.name,
+                    "dns_ptr": primary_ip.dns_ptr[0]["dns_ptr"] if len(primary_ip.dns_ptr) else None,
+                    "labels": primary_ip.labels,
+                    "delete_protection": primary_ip.protection["delete"],
+                }
+            )
 
         return tmp
 
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/rdns.py b/ansible_collections/hetzner/hcloud/plugins/modules/rdns.py
index b2decdec8..4e21f3e92 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/rdns.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/rdns.py
@@ -136,7 +136,6 @@ import ipaddress
 from typing import Any
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -157,18 +156,18 @@ class AnsibleHCloudReverseDNS(AnsibleHCloud):
             "server": None,
             "floating_ip": None,
             "load_balancer": None,
-            "ip_address": to_native(self.hcloud_rdns["ip_address"]),
-            "dns_ptr": to_native(self.hcloud_rdns["dns_ptr"]),
+            "ip_address": self.hcloud_rdns["ip_address"],
+            "dns_ptr": self.hcloud_rdns["dns_ptr"],
         }
 
         if self.module.params.get("server"):
-            result["server"] = to_native(self.hcloud_resource.name)
+            result["server"] = self.hcloud_resource.name
         elif self.module.params.get("floating_ip"):
-            result["floating_ip"] = to_native(self.hcloud_resource.name)
+            result["floating_ip"] = self.hcloud_resource.name
         elif self.module.params.get("load_balancer"):
-            result["load_balancer"] = to_native(self.hcloud_resource.name)
+            result["load_balancer"] = self.hcloud_resource.name
         elif self.module.params.get("primary_ip"):
-            result["primary_ip"] = to_native(self.hcloud_resource.name)
+            result["primary_ip"] = self.hcloud_resource.name
         return result
 
     def _get_resource(self):
@@ -277,7 +276,8 @@ class AnsibleHCloudReverseDNS(AnsibleHCloud):
 
         if not self.module.check_mode:
             try:
-                self.hcloud_resource.change_dns_ptr(**params).wait_until_finished()
+                action = self.hcloud_resource.change_dns_ptr(**params)
+                action.wait_until_finished()
             except HCloudException as exception:
                 self.fail_json_hcloud(exception)
         self._mark_as_changed()
@@ -294,7 +294,8 @@ class AnsibleHCloudReverseDNS(AnsibleHCloud):
 
             if not self.module.check_mode:
                 try:
-                    self.hcloud_resource.change_dns_ptr(**params).wait_until_finished()
+                    action = self.hcloud_resource.change_dns_ptr(**params)
+                    action.wait_until_finished()
                 except HCloudException as exception:
                     self.fail_json_hcloud(exception)
             self._mark_as_changed()
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/route.py b/ansible_collections/hetzner/hcloud/plugins/modules/route.py
index 3c96a7382..37ff50b07 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/route.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/route.py
@@ -86,7 +86,6 @@ hcloud_route:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -101,8 +100,8 @@ class AnsibleHCloudRoute(AnsibleHCloud):
 
     def _prepare_result(self):
         return {
-            "network": to_native(self.hcloud_network.name),
-            "destination": to_native(self.hcloud_route.destination),
+            "network": self.hcloud_network.name,
+            "destination": self.hcloud_route.destination,
             "gateway": self.hcloud_route.gateway,
         }
 
@@ -130,7 +129,8 @@ class AnsibleHCloudRoute(AnsibleHCloud):
 
         if not self.module.check_mode:
             try:
-                self.hcloud_network.add_route(route=route).wait_until_finished()
+                action = self.hcloud_network.add_route(route=route)
+                action.wait_until_finished()
             except HCloudException as exception:
                 self.fail_json_hcloud(exception)
 
@@ -150,7 +150,8 @@ class AnsibleHCloudRoute(AnsibleHCloud):
         if self.hcloud_route is not None and self.hcloud_network is not None:
             if not self.module.check_mode:
                 try:
-                    self.hcloud_network.delete_route(self.hcloud_route).wait_until_finished()
+                    action = self.hcloud_network.delete_route(self.hcloud_route)
+                    action.wait_until_finished()
                 except HCloudException as exception:
                     self.fail_json_hcloud(exception)
             self._mark_as_changed()
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/server.py b/ansible_collections/hetzner/hcloud/plugins/modules/server.py
index f5cadb807..d7bae3fc1 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/server.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/server.py
@@ -22,50 +22,58 @@ author:
 options:
     id:
         description:
-            - The ID of the Hetzner Cloud server to manage.
-            - Only required if no server I(name) is given
+            - ID of the Hetzner Cloud Server to manage.
+            - Only required if no server O(name) is given
         type: int
     name:
         description:
-            - The Name of the Hetzner Cloud server to manage.
-            - Only required if no server I(id) is given or a server does not exist.
+            - Name of the Hetzner Cloud Server to manage.
+            - Only required if no server O(id) is given or a server does not exist.
         type: str
     server_type:
         description:
-            - The Server Type of the Hetzner Cloud server to manage.
+            - Hetzner Cloud Server Type (name or ID) of the server.
             - Required if server does not exist.
         type: str
     ssh_keys:
         description:
-            - List of SSH key names
-            - The key names correspond to the SSH keys configured for your
-              Hetzner Cloud account access.
+            - List of Hetzner Cloud SSH Keys (name or ID) to create the server with.
+            - Only used during the server creation.
         type: list
         elements: str
     volumes:
         description:
-            - List of Volumes IDs that should be attached to the server on server creation.
+            - List of Hetzner Cloud Volumes (name or ID) that should be attached to the server.
+            - Only used during the server creation.
         type: list
         elements: str
     firewalls:
         description:
-            - List of Firewall IDs that should be attached to the server on server creation.
+            - List of Hetzner Cloud Firewalls (name or ID) that should be attached to the server.
         type: list
         elements: str
     image:
         description:
-            - Image the server should be created from.
-            - Required if server does not exist.
+            - Hetzner Cloud Image (name or ID) to create the server from.
+            - Required if server does not exist or when O(state=rebuild).
         type: str
+    image_allow_deprecated:
+        description:
+            - Allows the creation of servers with deprecated images.
+        type: bool
+        default: false
+        aliases: [allow_deprecated_image]
     location:
         description:
-            - Location of Server.
-            - Required if no I(datacenter) is given and server does not exist.
+            - Hetzner Cloud Location (name or ID) to create the server in.
+            - Required if no O(datacenter) is given and server does not exist.
+            - Only used during the server creation.
         type: str
     datacenter:
         description:
-            - Datacenter of Server.
-            - Required if no I(location) is given and server does not exist.
+            - Hetzner Cloud Datacenter (name or ID) to create the server in.
+            - Required if no O(location) is given and server does not exist.
+            - Only used during the server creation.
         type: str
     backups:
         description:
@@ -79,50 +87,42 @@ options:
         default: false
     enable_ipv4:
         description:
-            - Enables the public ipv4 address
+            - Enables the public ipv4 address.
         type: bool
         default: true
     enable_ipv6:
         description:
-            - Enables the public ipv6 address
+            - Enables the public ipv6 address.
         type: bool
         default: true
     ipv4:
         description:
-            - ID of the ipv4 Primary IP to use. If omitted and enable_ipv4 is true, a new ipv4 Primary IP will automatically be created
+            - Hetzner Cloud Primary IPv4 (name or ID) to use.
+            - If omitted and O(enable_ipv4=true), a new ipv4 Primary IP will automatically be created.
         type: str
     ipv6:
         description:
-            - ID of the ipv6 Primary IP to use. If omitted and enable_ipv6 is true, a new ipv6 Primary IP will automatically be created.
+            - Hetzner Cloud Primary IPv6 (name or ID) to use.
+            - If omitted and O(enable_ipv6=true), a new ipv6 Primary IP will automatically be created.
         type: str
     private_networks:
         description:
-            - List of private networks the server is attached to (name or ID)
+            - List of Hetzner Cloud Networks (name or ID) the server should be attached to.
             - If None, private networks are left as they are (e.g. if previously added by hcloud_server_network),
               if it has any other value (including []), only those networks are attached to the server.
         type: list
         elements: str
-    force_upgrade:
-        description:
-            - Deprecated
-            - Force the upgrade of the server.
-            - Power off the server if it is running on upgrade.
-        type: bool
     force:
         description:
             - Force the update of the server.
-            - May power off the server if update.
-        type: bool
-        default: false
-    allow_deprecated_image:
-        description:
-            - Allows the creation of servers with deprecated images.
+            - May power off the server if update is applied.
         type: bool
         default: false
+        aliases: [force_upgrade]
     user_data:
         description:
             - User Data to be passed to the server on creation.
-            - Only used if server does not exist.
+            - Only used during the server creation.
         type: str
     rescue_mode:
         description:
@@ -135,16 +135,16 @@ options:
     delete_protection:
         description:
             - Protect the Server for deletion.
-            - Needs to be the same as I(rebuild_protection).
+            - Needs to be the same as O(rebuild_protection).
         type: bool
     rebuild_protection:
         description:
             - Protect the Server for rebuild.
-            - Needs to be the same as I(delete_protection).
+            - Needs to be the same as O(delete_protection).
         type: bool
     placement_group:
         description:
-            - Placement Group of the server.
+            - Hetzner Cloud Placement Group (name or ID) to create the server in.
         type: str
     state:
         description:
@@ -336,9 +336,9 @@ hcloud_server:
 """
 
 from datetime import datetime, timedelta, timezone
+from typing import TYPE_CHECKING, Literal
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -348,8 +348,14 @@ from ..module_utils.vendor.hcloud.servers import (
     Server,
     ServerCreatePublicNetwork,
 )
-from ..module_utils.vendor.hcloud.ssh_keys import SSHKey
-from ..module_utils.vendor.hcloud.volumes import Volume
+
+if TYPE_CHECKING:
+    from ..module_utils.vendor.hcloud.actions import BoundAction
+    from ..module_utils.vendor.hcloud.firewalls import BoundFirewall
+    from ..module_utils.vendor.hcloud.networks import BoundNetwork
+    from ..module_utils.vendor.hcloud.placement_groups import BoundPlacementGroup
+    from ..module_utils.vendor.hcloud.primary_ips import PrimaryIP
+    from ..module_utils.vendor.hcloud.server_types import ServerType
 
 
 class AnsibleHCloudServer(AnsibleHCloud):
@@ -358,38 +364,31 @@ class AnsibleHCloudServer(AnsibleHCloud):
     hcloud_server: BoundServer | None = None
 
     def _prepare_result(self):
-        image = None if self.hcloud_server.image is None else to_native(self.hcloud_server.image.name)
-        placement_group = (
-            None if self.hcloud_server.placement_group is None else to_native(self.hcloud_server.placement_group.name)
-        )
-        ipv4_address = (
-            None if self.hcloud_server.public_net.ipv4 is None else to_native(self.hcloud_server.public_net.ipv4.ip)
-        )
-        ipv6 = None if self.hcloud_server.public_net.ipv6 is None else to_native(self.hcloud_server.public_net.ipv6.ip)
-        backup_window = (
-            None if self.hcloud_server.backup_window is None else to_native(self.hcloud_server.backup_window)
-        )
         return {
-            "id": to_native(self.hcloud_server.id),
-            "name": to_native(self.hcloud_server.name),
-            "created": to_native(self.hcloud_server.created.isoformat()),
-            "ipv4_address": ipv4_address,
-            "ipv6": ipv6,
-            "private_networks": [to_native(net.network.name) for net in self.hcloud_server.private_net],
+            "id": str(self.hcloud_server.id),
+            "name": self.hcloud_server.name,
+            "created": self.hcloud_server.created.isoformat(),
+            "ipv4_address": (
+                self.hcloud_server.public_net.ipv4.ip if self.hcloud_server.public_net.ipv4 is not None else None
+            ),
+            "ipv6": self.hcloud_server.public_net.ipv6.ip if self.hcloud_server.public_net.ipv6 is not None else None,
+            "private_networks": [net.network.name for net in self.hcloud_server.private_net],
             "private_networks_info": [
-                {"name": to_native(net.network.name), "ip": net.ip} for net in self.hcloud_server.private_net
+                {"name": net.network.name, "ip": net.ip} for net in self.hcloud_server.private_net
             ],
-            "image": image,
-            "server_type": to_native(self.hcloud_server.server_type.name),
-            "datacenter": to_native(self.hcloud_server.datacenter.name),
-            "location": to_native(self.hcloud_server.datacenter.location.name),
-            "placement_group": placement_group,
+            "image": self.hcloud_server.image.name if self.hcloud_server.image is not None else None,
+            "server_type": self.hcloud_server.server_type.name,
+            "datacenter": self.hcloud_server.datacenter.name,
+            "location": self.hcloud_server.datacenter.location.name,
+            "placement_group": (
+                self.hcloud_server.placement_group.name if self.hcloud_server.placement_group is not None else None
+            ),
             "rescue_enabled": self.hcloud_server.rescue_enabled,
-            "backup_window": backup_window,
+            "backup_window": self.hcloud_server.backup_window,
             "labels": self.hcloud_server.labels,
             "delete_protection": self.hcloud_server.protection["delete"],
             "rebuild_protection": self.hcloud_server.protection["rebuild"],
-            "status": to_native(self.hcloud_server.status),
+            "status": self.hcloud_server.status,
         }
 
     def _get_server(self):
@@ -405,73 +404,76 @@ class AnsibleHCloudServer(AnsibleHCloud):
         self.module.fail_on_missing_params(required_params=["name", "server_type", "image"])
 
         server_type = self._get_server_type()
+        image = self._get_image(server_type)
 
         params = {
             "name": self.module.params.get("name"),
+            "labels": self.module.params.get("labels"),
             "server_type": server_type,
+            "image": image,
             "user_data": self.module.params.get("user_data"),
-            "labels": self.module.params.get("labels"),
-            "image": self._get_image(server_type),
-            "placement_group": self._get_placement_group(),
             "public_net": ServerCreatePublicNetwork(
                 enable_ipv4=self.module.params.get("enable_ipv4"),
                 enable_ipv6=self.module.params.get("enable_ipv6"),
             ),
         }
 
+        if self.module.params.get("placement_group") is not None:
+            params["placement_group"] = self._client_get_by_name_or_id(
+                "placement_groups", self.module.params.get("placement_group")
+            )
+
         if self.module.params.get("ipv4") is not None:
-            primary_ip = self.client.primary_ips.get_by_name(self.module.params.get("ipv4"))
-            if not primary_ip:
-                primary_ip = self.client.primary_ips.get_by_id(self.module.params.get("ipv4"))
-            params["public_net"].ipv4 = primary_ip
+            params["public_net"].ipv4 = self._client_get_by_name_or_id("primary_ips", self.module.params.get("ipv4"))
 
         if self.module.params.get("ipv6") is not None:
-            primary_ip = self.client.primary_ips.get_by_name(self.module.params.get("ipv6"))
-            if not primary_ip:
-                primary_ip = self.client.primary_ips.get_by_id(self.module.params.get("ipv6"))
-            params["public_net"].ipv6 = primary_ip
+            params["public_net"].ipv6 = self._client_get_by_name_or_id("primary_ips", self.module.params.get("ipv6"))
 
         if self.module.params.get("private_networks") is not None:
-            _networks = []
-            for network_name_or_id in self.module.params.get("private_networks"):
-                _networks.append(
-                    self.client.networks.get_by_name(network_name_or_id)
-                    or self.client.networks.get_by_id(network_name_or_id)
-                )
-            params["networks"] = _networks
+            params["networks"] = [
+                self._client_get_by_name_or_id("networks", name_or_id)
+                for name_or_id in self.module.params.get("private_networks")
+            ]
 
         if self.module.params.get("ssh_keys") is not None:
-            params["ssh_keys"] = [SSHKey(name=ssh_key_name) for ssh_key_name in self.module.params.get("ssh_keys")]
+            params["ssh_keys"] = [
+                self._client_get_by_name_or_id("ssh_keys", name_or_id)
+                for name_or_id in self.module.params.get("ssh_keys")
+            ]
 
         if self.module.params.get("volumes") is not None:
-            params["volumes"] = [Volume(id=volume_id) for volume_id in self.module.params.get("volumes")]
+            params["volumes"] = [
+                self._client_get_by_name_or_id("volumes", name_or_id)
+                for name_or_id in self.module.params.get("volumes")
+            ]
+
         if self.module.params.get("firewalls") is not None:
-            params["firewalls"] = []
-            for firewall_param in self.module.params.get("firewalls"):
-                firewall = self.client.firewalls.get_by_name(firewall_param)
-                if firewall is not None:
-                    # When firewall name is not available look for id instead
-                    params["firewalls"].append(firewall)
-                else:
-                    params["firewalls"].append(self.client.firewalls.get_by_id(firewall_param))
+            params["firewalls"] = [
+                self._client_get_by_name_or_id("firewalls", name_or_id)
+                for name_or_id in self.module.params.get("firewalls")
+            ]
 
         if self.module.params.get("location") is None and self.module.params.get("datacenter") is None:
             # When not given, the API will choose the location.
             params["location"] = None
             params["datacenter"] = None
         elif self.module.params.get("location") is not None and self.module.params.get("datacenter") is None:
-            params["location"] = self.client.locations.get_by_name(self.module.params.get("location"))
+            params["location"] = self._client_get_by_name_or_id("locations", self.module.params.get("location"))
         elif self.module.params.get("location") is None and self.module.params.get("datacenter") is not None:
-            params["datacenter"] = self.client.datacenters.get_by_name(self.module.params.get("datacenter"))
+            params["datacenter"] = self._client_get_by_name_or_id("datacenters", self.module.params.get("datacenter"))
 
         if self.module.params.get("state") == "stopped":
             params["start_after_create"] = False
+
         if not self.module.check_mode:
             try:
                 resp = self.client.servers.create(**params)
                 self.result["root_password"] = resp.root_password
-                resp.action.wait_until_finished(max_retries=1000)
-                [action.wait_until_finished() for action in resp.next_actions]
+                # Action should take 60 to 90 seconds on average, but can be >10m when creating a
+                # server from a custom images
+                resp.action.wait_until_finished(max_retries=1800)
+                for action in resp.next_actions:
+                    action.wait_until_finished()
 
                 rescue_mode = self.module.params.get("rescue_mode")
                 if rescue_mode:
@@ -481,40 +483,35 @@ class AnsibleHCloudServer(AnsibleHCloud):
                 backups = self.module.params.get("backups")
                 if backups:
                     self._get_server()
-                    self.hcloud_server.enable_backup().wait_until_finished()
+                    action = self.hcloud_server.enable_backup()
+                    action.wait_until_finished()
 
                 delete_protection = self.module.params.get("delete_protection")
                 rebuild_protection = self.module.params.get("rebuild_protection")
                 if delete_protection is not None and rebuild_protection is not None:
                     self._get_server()
-                    self.hcloud_server.change_protection(
+                    action = self.hcloud_server.change_protection(
                         delete=delete_protection,
                         rebuild=rebuild_protection,
-                    ).wait_until_finished()
+                    )
+                    action.wait_until_finished()
             except HCloudException as exception:
                 self.fail_json_hcloud(exception)
         self._mark_as_changed()
         self._get_server()
 
-    def _get_image(self, server_type):
-        image_resp = self.client.images.get_list(
+    def _get_image(self, server_type: ServerType):
+        image = self.client.images.get_by_name_and_architecture(
             name=self.module.params.get("image"),
             architecture=server_type.architecture,
             include_deprecated=True,
         )
-        images = getattr(image_resp, "images")
-        image = None
-        if images is not None and len(images) > 0:
-            # If image name is not available look for id instead
-            image = images[0]
-        else:
-            try:
-                image = self.client.images.get_by_id(self.module.params.get("image"))
-            except HCloudException as exception:
-                self.fail_json_hcloud(exception, msg=f"Image {self.module.params.get('image')} was not found")
+        if image is None:
+            image = self.client.images.get_by_id(self.module.params.get("image"))
+
         if image.deprecated is not None:
             available_until = image.deprecated + timedelta(days=90)
-            if self.module.params.get("allow_deprecated_image"):
+            if self.module.params.get("image_allow_deprecated"):
                 self.module.warn(
                     f"You try to use a deprecated image. The image {image.name} will "
                     f"continue to be available until {available_until.strftime('%Y-%m-%d')}."
@@ -524,27 +521,18 @@ class AnsibleHCloudServer(AnsibleHCloud):
                     msg=(
                         f"You try to use a deprecated image. The image {image.name} will "
                         f"continue to be available until {available_until.strftime('%Y-%m-%d')}. "
-                        "If you want to use this image use allow_deprecated_image=true."
+                        "If you want to use this image use image_allow_deprecated=true."
                     )
                 )
         return image
 
-    def _get_server_type(self):
-        server_type = self.client.server_types.get_by_name(self.module.params.get("server_type"))
-        if server_type is None:
-            try:
-                server_type = self.client.server_types.get_by_id(self.module.params.get("server_type"))
-            except HCloudException as exception:
-                self.fail_json_hcloud(
-                    exception,
-                    msg=f"server_type {self.module.params.get('server_type')} was not found",
-                )
+    def _get_server_type(self) -> ServerType:
+        server_type = self._client_get_by_name_or_id("server_types", self.module.params.get("server_type"))
 
         self._check_and_warn_deprecated_server(server_type)
-
         return server_type
 
-    def _check_and_warn_deprecated_server(self, server_type):
+    def _check_and_warn_deprecated_server(self, server_type: ServerType) -> None:
         if server_type.deprecation is None:
             return
 
@@ -567,42 +555,16 @@ class AnsibleHCloudServer(AnsibleHCloud):
                 "the server_type parameter on the hetzner.hcloud.server module."
             )
 
-    def _get_placement_group(self):
-        if self.module.params.get("placement_group") is None:
-            return None
-
-        placement_group = self.client.placement_groups.get_by_name(self.module.params.get("placement_group"))
-        if placement_group is None:
-            try:
-                placement_group = self.client.placement_groups.get_by_id(self.module.params.get("placement_group"))
-            except HCloudException as exception:
-                self.fail_json_hcloud(
-                    exception,
-                    msg=f"placement_group {self.module.params.get('placement_group')} was not found",
-                )
-
-        return placement_group
-
-    def _get_primary_ip(self, field):
-        if self.module.params.get(field) is None:
-            return None
-
-        primary_ip = self.client.primary_ips.get_by_name(self.module.params.get(field))
-        if primary_ip is None:
-            try:
-                primary_ip = self.client.primary_ips.get_by_id(self.module.params.get(field))
-            except HCloudException as exception:
-                self.fail_json_hcloud(exception, msg=f"primary_ip {self.module.params.get(field)} was not found")
-
-        return primary_ip
-
-    def _update_server(self):
-        if "force_upgrade" in self.module.params and self.module.params.get("force_upgrade") is not None:
-            self.module.warn("force_upgrade is deprecated, use force instead")
-
+    def _update_server(self) -> None:
         try:
             previous_server_status = self.hcloud_server.status
 
+            labels = self.module.params.get("labels")
+            if labels is not None and labels != self.hcloud_server.labels:
+                if not self.module.check_mode:
+                    self.hcloud_server.update(labels=labels)
+                self._mark_as_changed()
+
             rescue_mode = self.module.params.get("rescue_mode")
             if rescue_mode and self.hcloud_server.rescue_enabled is False:
                 if not self.module.check_mode:
@@ -610,167 +572,39 @@ class AnsibleHCloudServer(AnsibleHCloud):
                 self._mark_as_changed()
             elif not rescue_mode and self.hcloud_server.rescue_enabled is True:
                 if not self.module.check_mode:
-                    self.hcloud_server.disable_rescue().wait_until_finished()
+                    action = self.hcloud_server.disable_rescue()
+                    action.wait_until_finished()
                 self._mark_as_changed()
 
             backups = self.module.params.get("backups")
             if backups and self.hcloud_server.backup_window is None:
                 if not self.module.check_mode:
-                    self.hcloud_server.enable_backup().wait_until_finished()
+                    action = self.hcloud_server.enable_backup()
+                    action.wait_until_finished()
                 self._mark_as_changed()
             elif backups is not None and not backups and self.hcloud_server.backup_window is not None:
                 if not self.module.check_mode:
-                    self.hcloud_server.disable_backup().wait_until_finished()
+                    action = self.hcloud_server.disable_backup()
+                    action.wait_until_finished()
                 self._mark_as_changed()
 
-            labels = self.module.params.get("labels")
-            if labels is not None and labels != self.hcloud_server.labels:
-                if not self.module.check_mode:
-                    self.hcloud_server.update(labels=labels)
-                self._mark_as_changed()
+            if self.module.params.get("firewalls") is not None:
+                self._update_server_firewalls()
 
-            wanted_firewalls = self.module.params.get("firewalls")
-            if wanted_firewalls is not None:
-                # Removing existing but not wanted firewalls
-                for current_firewall in self.hcloud_server.public_net.firewalls:
-                    if current_firewall.firewall.name not in wanted_firewalls:
-                        self._mark_as_changed()
-                        if self.module.check_mode:
-                            continue
-
-                        firewall_resource = FirewallResource(type="server", server=self.hcloud_server)
-                        actions = self.client.firewalls.remove_from_resources(
-                            current_firewall.firewall,
-                            [firewall_resource],
-                        )
-                        for action in actions:
-                            action.wait_until_finished()
-
-                # Adding wanted firewalls that doesn't exist yet
-                for firewall_name in wanted_firewalls:
-                    found = False
-                    for firewall in self.hcloud_server.public_net.firewalls:
-                        if firewall.firewall.name == firewall_name:
-                            found = True
-                            break
-
-                    if not found:
-                        self._mark_as_changed()
-                        if not self.module.check_mode:
-                            firewall = self.client.firewalls.get_by_name(firewall_name)
-                            if firewall is None:
-                                self.module.fail_json(msg=f"firewall {firewall_name} was not found")
-                            firewall_resource = FirewallResource(type="server", server=self.hcloud_server)
-                            actions = self.client.firewalls.apply_to_resources(firewall, [firewall_resource])
-                            for action in actions:
-                                action.wait_until_finished()
-
-            if "placement_group" in self.module.params:
-                if self.module.params["placement_group"] is None and self.hcloud_server.placement_group is not None:
-                    if not self.module.check_mode:
-                        self.hcloud_server.remove_from_placement_group().wait_until_finished()
-                    self._mark_as_changed()
-                else:
-                    placement_group = self._get_placement_group()
-                    if placement_group is not None and (
-                        self.hcloud_server.placement_group is None
-                        or self.hcloud_server.placement_group.id != placement_group.id
-                    ):
-                        self.stop_server_if_forced()
-                        if not self.module.check_mode:
-                            self.hcloud_server.add_to_placement_group(placement_group).wait_until_finished()
-                        self._mark_as_changed()
-
-            if "ipv4" in self.module.params:
-                if (
-                    self.module.params["ipv4"] is None
-                    and self.hcloud_server.public_net.primary_ipv4 is not None
-                    and not self.module.params.get("enable_ipv4")
-                ):
-                    self.stop_server_if_forced()
-                    if not self.module.check_mode:
-                        self.hcloud_server.public_net.primary_ipv4.unassign().wait_until_finished()
-                    self._mark_as_changed()
-                else:
-                    primary_ip = self._get_primary_ip("ipv4")
-                    if primary_ip is not None and (
-                        self.hcloud_server.public_net.primary_ipv4 is None
-                        or self.hcloud_server.public_net.primary_ipv4.id != primary_ip.id
-                    ):
-                        self.stop_server_if_forced()
-                        if not self.module.check_mode:
-                            if self.hcloud_server.public_net.primary_ipv4:
-                                self.hcloud_server.public_net.primary_ipv4.unassign().wait_until_finished()
-                            primary_ip.assign(self.hcloud_server.id, "server").wait_until_finished()
-                        self._mark_as_changed()
-            if "ipv6" in self.module.params:
-                if (
-                    (self.module.params["ipv6"] is None or self.module.params["ipv6"] == "")
-                    and self.hcloud_server.public_net.primary_ipv6 is not None
-                    and not self.module.params.get("enable_ipv6")
-                ):
-                    self.stop_server_if_forced()
-                    if not self.module.check_mode:
-                        self.hcloud_server.public_net.primary_ipv6.unassign().wait_until_finished()
-                    self._mark_as_changed()
-                else:
-                    primary_ip = self._get_primary_ip("ipv6")
-                    if primary_ip is not None and (
-                        self.hcloud_server.public_net.primary_ipv6 is None
-                        or self.hcloud_server.public_net.primary_ipv6.id != primary_ip.id
-                    ):
-                        self.stop_server_if_forced()
-                        if not self.module.check_mode:
-                            if self.hcloud_server.public_net.primary_ipv6 is not None:
-                                self.hcloud_server.public_net.primary_ipv6.unassign().wait_until_finished()
-                            primary_ip.assign(self.hcloud_server.id, "server").wait_until_finished()
-                        self._mark_as_changed()
-            if "private_networks" in self.module.params and self.module.params["private_networks"] is not None:
-                if not bool(self.module.params["private_networks"]):
-                    # This handles None, "" and []
-                    networks_target = {}
-                else:
-                    _networks = {}
-                    for network_name_or_id in self.module.params.get("private_networks"):
-                        _found_network = self.client.networks.get_by_name(
-                            network_name_or_id
-                        ) or self.client.networks.get_by_id(network_name_or_id)
-                        _networks.update({_found_network.id: _found_network})
-                    networks_target = _networks
-                networks_is = dict()
-                for p_network in self.hcloud_server.private_net:
-                    networks_is.update({p_network.network.id: p_network.network})
-                for network_id in set(list(networks_is) + list(networks_target)):
-                    if network_id in networks_is and network_id not in networks_target:
-                        self.stop_server_if_forced()
-                        if not self.module.check_mode:
-                            self.hcloud_server.detach_from_network(networks_is[network_id]).wait_until_finished()
-                        self._mark_as_changed()
-                    elif network_id in networks_target and network_id not in networks_is:
-                        self.stop_server_if_forced()
-                        if not self.module.check_mode:
-                            self.hcloud_server.attach_to_network(networks_target[network_id]).wait_until_finished()
-                        self._mark_as_changed()
-
-            server_type = self.module.params.get("server_type")
-            if server_type is not None:
-                if self.hcloud_server.server_type.name == server_type:
-                    # Check if we should warn for using an deprecated server type
-                    self._check_and_warn_deprecated_server(self.hcloud_server.server_type)
-
-                else:
-                    # Server type should be changed
-                    self.stop_server_if_forced()
-
-                    timeout = 100
-                    if self.module.params.get("upgrade_disk"):
-                        timeout = 1000  # When we upgrade the disk to the resize progress takes some more time.
-                    if not self.module.check_mode:
-                        self.hcloud_server.change_type(
-                            server_type=self._get_server_type(),
-                            upgrade_disk=self.module.params.get("upgrade_disk"),
-                        ).wait_until_finished(timeout)
-                    self._mark_as_changed()
+            if self.module.params.get("placement_group") is not None:
+                self._update_server_placement_group()
+
+            if self.module.params.get("ipv4") is not None:
+                self._update_server_ip("ipv4")
+
+            if self.module.params.get("ipv6") is not None:
+                self._update_server_ip("ipv6")
+
+            if self.module.params.get("private_networks") is not None:
+                self._update_server_networks()
+
+            if self.module.params.get("server_type") is not None:
+                self._update_server_server_type()
 
             if not self.module.check_mode and (
                 (self.module.params.get("state") == "present" and previous_server_status == Server.STATUS_RUNNING)
@@ -785,15 +619,197 @@ class AnsibleHCloudServer(AnsibleHCloud):
                 or rebuild_protection != self.hcloud_server.protection["rebuild"]
             ):
                 if not self.module.check_mode:
-                    self.hcloud_server.change_protection(
+                    action = self.hcloud_server.change_protection(
                         delete=delete_protection,
                         rebuild=rebuild_protection,
-                    ).wait_until_finished()
+                    )
+                    action.wait_until_finished()
                 self._mark_as_changed()
             self._get_server()
         except HCloudException as exception:
             self.fail_json_hcloud(exception)
 
+    def _update_server_placement_group(self) -> None:
+        current: BoundPlacementGroup | None = self.hcloud_server.placement_group
+        wanted = self.module.params.get("placement_group")
+
+        # Return if nothing changed
+        if current is not None and current.has_id_or_name(wanted):
+            return
+
+        # Fetch resource if parameter is truthy
+        if wanted:
+            placement_group = self._client_get_by_name_or_id("placement_groups", wanted)
+
+        # Remove if current is defined
+        if current is not None:
+            if not self.module.check_mode:
+                action = self.hcloud_server.remove_from_placement_group()
+                action.wait_until_finished()
+            self._mark_as_changed()
+
+        # Return if parameter is falsy
+        if not wanted:
+            return
+
+        # Assign new
+        self.stop_server_if_forced()
+        if not self.module.check_mode:
+            action = self.hcloud_server.add_to_placement_group(placement_group)
+            action.wait_until_finished()
+        self._mark_as_changed()
+
+    def _update_server_server_type(self) -> None:
+        current: ServerType = self.hcloud_server.server_type
+        wanted = self.module.params.get("server_type")
+
+        # Return if nothing changed
+        if current.has_id_or_name(wanted):
+            # Check if we should warn for using an deprecated server type
+            self._check_and_warn_deprecated_server(self.hcloud_server.server_type)
+            return
+
+        self.stop_server_if_forced()
+
+        upgrade_disk = self.module.params.get("upgrade_disk")
+        # Upgrading a server takes 160 seconds on average, upgrading the disk should
+        # take more time
+        upgrade_timeout = 600 if upgrade_disk else 180
+
+        if not self.module.check_mode:
+            action = self.hcloud_server.change_type(
+                server_type=self._get_server_type(),
+                upgrade_disk=upgrade_disk,
+            )
+            action.wait_until_finished(max_retries=upgrade_timeout)
+        self._mark_as_changed()
+
+    def _update_server_ip(self, kind: Literal["ipv4", "ipv6"]) -> None:
+        current: PrimaryIP | None = getattr(self.hcloud_server.public_net, f"primary_{kind}")
+        wanted = self.module.params.get(kind)
+        enable = self.module.params.get(f"enable_{kind}")
+
+        # Return if nothing changed
+        if current is not None and current.has_id_or_name(wanted) and enable:
+            return
+
+        # Fetch resource if parameter is truthy
+        if wanted:
+            primary_ip = self._client_get_by_name_or_id("primary_ips", wanted)
+
+        # Remove if current is defined
+        if current is not None:
+            self.stop_server_if_forced()
+            if not self.module.check_mode:
+                action = self.client.primary_ips.unassign(current)
+                action.wait_until_finished()
+            self._mark_as_changed()
+
+        # Return if parameter is falsy or resource is disabled
+        if not wanted or not enable:
+            return
+
+        # Assign new
+        self.stop_server_if_forced()
+        if not self.module.check_mode:
+            action = self.client.primary_ips.assign(
+                primary_ip,
+                assignee_id=self.hcloud_server.id,
+                assignee_type="server",
+            )
+            action.wait_until_finished()
+        self._mark_as_changed()
+
+    def _update_server_networks(self) -> None:
+        current: list[BoundNetwork] = [item.network for item in self.hcloud_server.private_net]
+        wanted: list[BoundNetwork] = [
+            self._client_get_by_name_or_id("networks", name_or_id)
+            for name_or_id in self.module.params.get("private_networks")
+        ]
+
+        current_ids = {item.id for item in current}
+        wanted_ids = {item.id for item in wanted}
+
+        # Removing existing but not wanted networks
+        actions: list[BoundAction] = []
+        for current_network in current:
+            if current_network.id in wanted_ids:
+                continue
+
+            self._mark_as_changed()
+            if self.module.check_mode:
+                continue
+
+            actions.append(self.hcloud_server.detach_from_network(current_network))
+
+        for action in actions:
+            action.wait_until_finished()
+
+        # Adding wanted networks that doesn't exist yet
+        actions: list[BoundAction] = []
+        for wanted_network in wanted:
+            if wanted_network.id in current_ids:
+                continue
+
+            self._mark_as_changed()
+            if self.module.check_mode:
+                continue
+
+            actions.append(self.hcloud_server.attach_to_network(wanted_network))
+
+        for action in actions:
+            action.wait_until_finished()
+
+    def _update_server_firewalls(self) -> None:
+        current: list[BoundFirewall] = [item.firewall for item in self.hcloud_server.public_net.firewalls]
+        wanted: list[BoundFirewall] = [
+            self._client_get_by_name_or_id("firewalls", name_or_id)
+            for name_or_id in self.module.params.get("firewalls")
+        ]
+
+        current_ids = {item.id for item in current}
+        wanted_ids = {item.id for item in wanted}
+
+        # Removing existing but not wanted firewalls
+        actions: list[BoundAction] = []
+        for current_firewall in current:
+            if current_firewall.id in wanted_ids:
+                continue
+
+            self._mark_as_changed()
+            if self.module.check_mode:
+                continue
+
+            actions.extend(
+                self.client.firewalls.remove_from_resources(
+                    current_firewall,
+                    [FirewallResource(type="server", server=self.hcloud_server)],
+                )
+            )
+
+        for action in actions:
+            action.wait_until_finished()
+
+        # Adding wanted firewalls that doesn't exist yet
+        actions: list[BoundAction] = []
+        for wanted_firewall in wanted:
+            if wanted_firewall.id in current_ids:
+                continue
+
+            self._mark_as_changed()
+            if self.module.check_mode:
+                continue
+
+            actions.extend(
+                self.client.firewalls.apply_to_resources(
+                    wanted_firewall,
+                    [FirewallResource(type="server", server=self.hcloud_server)],
+                )
+            )
+
+        for action in actions:
+            action.wait_until_finished()
+
     def _set_rescue_mode(self, rescue_mode):
         if self.module.params.get("ssh_keys"):
             resp = self.hcloud_server.enable_rescue(
@@ -813,7 +829,8 @@ class AnsibleHCloudServer(AnsibleHCloud):
             if self.hcloud_server:
                 if self.hcloud_server.status != Server.STATUS_RUNNING:
                     if not self.module.check_mode:
-                        self.client.servers.power_on(self.hcloud_server).wait_until_finished()
+                        action = self.client.servers.power_on(self.hcloud_server)
+                        action.wait_until_finished()
                     self._mark_as_changed()
                 self._get_server()
         except HCloudException as exception:
@@ -824,7 +841,8 @@ class AnsibleHCloudServer(AnsibleHCloud):
             if self.hcloud_server:
                 if self.hcloud_server.status != Server.STATUS_OFF:
                     if not self.module.check_mode:
-                        self.client.servers.power_off(self.hcloud_server).wait_until_finished()
+                        action = self.client.servers.power_off(self.hcloud_server)
+                        action.wait_until_finished()
                     self._mark_as_changed()
                 self._get_server()
         except HCloudException as exception:
@@ -833,18 +851,14 @@ class AnsibleHCloudServer(AnsibleHCloud):
     def stop_server_if_forced(self):
         previous_server_status = self.hcloud_server.status
         if previous_server_status == Server.STATUS_RUNNING and not self.module.check_mode:
-            if (
-                self.module.params.get("force_upgrade")
-                or self.module.params.get("force")
-                or self.module.params.get("state") == "stopped"
-            ):
+            if self.module.params.get("force") or self.module.params.get("state") == "stopped":
                 self.stop_server()  # Only stopped server can be upgraded
                 return previous_server_status
-            else:
-                self.module.warn(
-                    f"You can not upgrade a running instance {self.hcloud_server.name}. "
-                    "You need to stop the instance or use force=true."
-                )
+
+            self.module.warn(
+                f"You can not upgrade a running instance {self.hcloud_server.name}. "
+                "You need to stop the instance or use force=true."
+            )
 
         return None
 
@@ -874,7 +888,8 @@ class AnsibleHCloudServer(AnsibleHCloud):
             self._get_server()
             if self.hcloud_server is not None:
                 if not self.module.check_mode:
-                    self.client.servers.delete(self.hcloud_server).wait_until_finished()
+                    action = self.client.servers.delete(self.hcloud_server)
+                    action.wait_until_finished()
                 self._mark_as_changed()
             self.hcloud_server = None
         except HCloudException as exception:
@@ -887,6 +902,7 @@ class AnsibleHCloudServer(AnsibleHCloud):
                 id={"type": "int"},
                 name={"type": "str"},
                 image={"type": "str"},
+                image_allow_deprecated={"type": "bool", "default": False, "aliases": ["allow_deprecated_image"]},
                 server_type={"type": "str"},
                 location={"type": "str"},
                 datacenter={"type": "str"},
@@ -902,9 +918,14 @@ class AnsibleHCloudServer(AnsibleHCloud):
                 ipv4={"type": "str"},
                 ipv6={"type": "str"},
                 private_networks={"type": "list", "elements": "str", "default": None},
-                force={"type": "bool", "default": False},
-                force_upgrade={"type": "bool"},
-                allow_deprecated_image={"type": "bool", "default": False},
+                force={
+                    "type": "bool",
+                    "default": False,
+                    "aliases": ["force_upgrade"],
+                    "deprecated_aliases": [
+                        {"collection_name": "hetzner.hcloud", "name": "force_upgrade", "version": "4.0.0"}
+                    ],
+                },
                 rescue_mode={"type": "str"},
                 delete_protection={"type": "bool"},
                 rebuild_protection={"type": "bool"},
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/server_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/server_info.py
index cee1634cb..3417e58af 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/server_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/server_info.py
@@ -146,7 +146,6 @@ hcloud_server_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -162,36 +161,31 @@ class AnsibleHCloudServerInfo(AnsibleHCloud):
         tmp = []
 
         for server in self.hcloud_server_info:
-            if server is not None:
-                image = None if server.image is None else to_native(server.image.name)
-                placement_group = None if server.placement_group is None else to_native(server.placement_group.name)
-                ipv4_address = None if server.public_net.ipv4 is None else to_native(server.public_net.ipv4.ip)
-                ipv6 = None if server.public_net.ipv6 is None else to_native(server.public_net.ipv6.ip)
-                backup_window = None if server.backup_window is None else to_native(server.backup_window)
-                tmp.append(
-                    {
-                        "id": to_native(server.id),
-                        "name": to_native(server.name),
-                        "created": to_native(server.created.isoformat()),
-                        "ipv4_address": ipv4_address,
-                        "ipv6": ipv6,
-                        "private_networks": [to_native(net.network.name) for net in server.private_net],
-                        "private_networks_info": [
-                            {"name": to_native(net.network.name), "ip": net.ip} for net in server.private_net
-                        ],
-                        "image": image,
-                        "server_type": to_native(server.server_type.name),
-                        "datacenter": to_native(server.datacenter.name),
-                        "location": to_native(server.datacenter.location.name),
-                        "placement_group": placement_group,
-                        "rescue_enabled": server.rescue_enabled,
-                        "backup_window": backup_window,
-                        "labels": server.labels,
-                        "status": to_native(server.status),
-                        "delete_protection": server.protection["delete"],
-                        "rebuild_protection": server.protection["rebuild"],
-                    }
-                )
+            if server is None:
+                continue
+
+            tmp.append(
+                {
+                    "id": str(server.id),
+                    "name": server.name,
+                    "created": server.created.isoformat(),
+                    "ipv4_address": server.public_net.ipv4.ip if server.public_net.ipv4 is not None else None,
+                    "ipv6": server.public_net.ipv6.ip if server.public_net.ipv6 is not None else None,
+                    "private_networks": [net.network.name for net in server.private_net],
+                    "private_networks_info": [{"name": net.network.name, "ip": net.ip} for net in server.private_net],
+                    "image": server.image.name if server.image is not None else None,
+                    "server_type": server.server_type.name,
+                    "datacenter": server.datacenter.name,
+                    "location": server.datacenter.location.name,
+                    "placement_group": server.placement_group.name if server.placement_group is not None else None,
+                    "rescue_enabled": server.rescue_enabled,
+                    "backup_window": server.backup_window,
+                    "labels": server.labels,
+                    "status": server.status,
+                    "delete_protection": server.protection["delete"],
+                    "rebuild_protection": server.protection["rebuild"],
+                }
+            )
         return tmp
 
     def get_servers(self):
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/server_network.py b/ansible_collections/hetzner/hcloud/plugins/modules/server_network.py
index ca80a8a76..bc6dec428 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/server_network.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/server_network.py
@@ -111,7 +111,6 @@ hcloud_server_network:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import APIException, HCloudException
@@ -128,10 +127,10 @@ class AnsibleHCloudServerNetwork(AnsibleHCloud):
 
     def _prepare_result(self):
         return {
-            "network": to_native(self.hcloud_network.name),
-            "server": to_native(self.hcloud_server.name),
-            "ip": to_native(self.hcloud_server_network.ip),
-            "alias_ips": self.hcloud_server_network.alias_ips,
+            "network": self.hcloud_network.name,
+            "server": self.hcloud_server.name,
+            "ip": self.hcloud_server_network.ip,
+            "alias_ips": list(sorted(self.hcloud_server_network.alias_ips)),
         }
 
     def _get_server_and_network(self):
@@ -165,7 +164,8 @@ class AnsibleHCloudServerNetwork(AnsibleHCloud):
 
         if not self.module.check_mode:
             try:
-                self.hcloud_server.attach_to_network(**params).wait_until_finished()
+                action = self.hcloud_server.attach_to_network(**params)
+                action.wait_until_finished()
             except HCloudException as exception:
                 self.fail_json_hcloud(exception)
 
@@ -183,7 +183,8 @@ class AnsibleHCloudServerNetwork(AnsibleHCloud):
 
             if not self.module.check_mode:
                 try:
-                    self.hcloud_server.change_alias_ips(**params).wait_until_finished()
+                    action = self.hcloud_server.change_alias_ips(**params)
+                    action.wait_until_finished()
                 except APIException as exception:
                     self.fail_json_hcloud(exception)
 
@@ -205,7 +206,8 @@ class AnsibleHCloudServerNetwork(AnsibleHCloud):
         if self.hcloud_server_network is not None and self.hcloud_server is not None:
             if not self.module.check_mode:
                 try:
-                    self.hcloud_server.detach_from_network(self.hcloud_server_network.network).wait_until_finished()
+                    action = self.hcloud_server.detach_from_network(self.hcloud_server_network.network)
+                    action.wait_until_finished()
                 except HCloudException as exception:
                     self.fail_json_hcloud(exception)
             self._mark_as_changed()
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/server_type_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/server_type_info.py
index 61f1f5011..4f16b52fe 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/server_type_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/server_type_info.py
@@ -124,7 +124,6 @@ hcloud_server_type_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -140,29 +139,31 @@ class AnsibleHCloudServerTypeInfo(AnsibleHCloud):
         tmp = []
 
         for server_type in self.hcloud_server_type_info:
-            if server_type is not None:
-                tmp.append(
-                    {
-                        "id": to_native(server_type.id),
-                        "name": to_native(server_type.name),
-                        "description": to_native(server_type.description),
-                        "cores": server_type.cores,
-                        "memory": server_type.memory,
-                        "disk": server_type.disk,
-                        "storage_type": to_native(server_type.storage_type),
-                        "cpu_type": to_native(server_type.cpu_type),
-                        "architecture": to_native(server_type.architecture),
-                        "included_traffic": server_type.included_traffic,
-                        "deprecation": (
-                            {
-                                "announced": server_type.deprecation.announced.isoformat(),
-                                "unavailable_after": server_type.deprecation.unavailable_after.isoformat(),
-                            }
-                            if server_type.deprecation is not None
-                            else None
-                        ),
-                    }
-                )
+            if server_type is None:
+                continue
+
+            tmp.append(
+                {
+                    "id": str(server_type.id),
+                    "name": server_type.name,
+                    "description": server_type.description,
+                    "cores": server_type.cores,
+                    "memory": server_type.memory,
+                    "disk": server_type.disk,
+                    "storage_type": server_type.storage_type,
+                    "cpu_type": server_type.cpu_type,
+                    "architecture": server_type.architecture,
+                    "included_traffic": server_type.included_traffic,
+                    "deprecation": (
+                        {
+                            "announced": server_type.deprecation.announced.isoformat(),
+                            "unavailable_after": server_type.deprecation.unavailable_after.isoformat(),
+                        }
+                        if server_type.deprecation is not None
+                        else None
+                    ),
+                }
+            )
         return tmp
 
     def get_server_types(self):
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/ssh_key.py b/ansible_collections/hetzner/hcloud/plugins/modules/ssh_key.py
index 349c52c68..e33987c44 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/ssh_key.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/ssh_key.py
@@ -113,7 +113,6 @@ hcloud_ssh_key:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -127,10 +126,10 @@ class AnsibleHCloudSSHKey(AnsibleHCloud):
 
     def _prepare_result(self):
         return {
-            "id": to_native(self.hcloud_ssh_key.id),
-            "name": to_native(self.hcloud_ssh_key.name),
-            "fingerprint": to_native(self.hcloud_ssh_key.fingerprint),
-            "public_key": to_native(self.hcloud_ssh_key.public_key),
+            "id": str(self.hcloud_ssh_key.id),
+            "name": self.hcloud_ssh_key.name,
+            "fingerprint": self.hcloud_ssh_key.fingerprint,
+            "public_key": self.hcloud_ssh_key.public_key,
             "labels": self.hcloud_ssh_key.labels,
         }
 
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/ssh_key_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/ssh_key_info.py
index 7a4ab5928..b6b22ff35 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/ssh_key_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/ssh_key_info.py
@@ -79,7 +79,6 @@ hcloud_ssh_key_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -92,20 +91,22 @@ class AnsibleHCloudSSHKeyInfo(AnsibleHCloud):
     hcloud_ssh_key_info: list[BoundSSHKey] | None = None
 
     def _prepare_result(self):
-        ssh_keys = []
+        tmp = []
 
         for ssh_key in self.hcloud_ssh_key_info:
-            if ssh_key:
-                ssh_keys.append(
-                    {
-                        "id": to_native(ssh_key.id),
-                        "name": to_native(ssh_key.name),
-                        "fingerprint": to_native(ssh_key.fingerprint),
-                        "public_key": to_native(ssh_key.public_key),
-                        "labels": ssh_key.labels,
-                    }
-                )
-        return ssh_keys
+            if ssh_key is None:
+                continue
+
+            tmp.append(
+                {
+                    "id": str(ssh_key.id),
+                    "name": ssh_key.name,
+                    "fingerprint": ssh_key.fingerprint,
+                    "public_key": ssh_key.public_key,
+                    "labels": ssh_key.labels,
+                }
+            )
+        return tmp
 
     def get_ssh_keys(self):
         try:
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/subnetwork.py b/ansible_collections/hetzner/hcloud/plugins/modules/subnetwork.py
index aea40bb13..6f7feeaad 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/subnetwork.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/subnetwork.py
@@ -123,7 +123,6 @@ hcloud_subnetwork:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -138,10 +137,10 @@ class AnsibleHCloudSubnetwork(AnsibleHCloud):
 
     def _prepare_result(self):
         return {
-            "network": to_native(self.hcloud_network.name),
-            "ip_range": to_native(self.hcloud_subnetwork.ip_range),
-            "type": to_native(self.hcloud_subnetwork.type),
-            "network_zone": to_native(self.hcloud_subnetwork.network_zone),
+            "network": self.hcloud_network.name,
+            "ip_range": self.hcloud_subnetwork.ip_range,
+            "type": self.hcloud_subnetwork.type,
+            "network_zone": self.hcloud_subnetwork.network_zone,
             "gateway": self.hcloud_subnetwork.gateway,
             "vswitch_id": self.hcloud_subnetwork.vswitch_id,
         }
@@ -174,7 +173,8 @@ class AnsibleHCloudSubnetwork(AnsibleHCloud):
 
         if not self.module.check_mode:
             try:
-                self.hcloud_network.add_subnet(subnet=NetworkSubnet(**params)).wait_until_finished()
+                action = self.hcloud_network.add_subnet(subnet=NetworkSubnet(**params))
+                action.wait_until_finished()
             except HCloudException as exception:
                 self.fail_json_hcloud(exception)
 
@@ -194,7 +194,8 @@ class AnsibleHCloudSubnetwork(AnsibleHCloud):
         if self.hcloud_subnetwork is not None and self.hcloud_network is not None:
             if not self.module.check_mode:
                 try:
-                    self.hcloud_network.delete_subnet(self.hcloud_subnetwork).wait_until_finished()
+                    action = self.hcloud_network.delete_subnet(self.hcloud_subnetwork)
+                    action.wait_until_finished()
                 except HCloudException as exception:
                     self.fail_json_hcloud(exception)
             self._mark_as_changed()
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/volume.py b/ansible_collections/hetzner/hcloud/plugins/modules/volume.py
index 8442ed90b..1bcb44253 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/volume.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/volume.py
@@ -160,7 +160,6 @@ hcloud_volume:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -173,18 +172,14 @@ class AnsibleHCloudVolume(AnsibleHCloud):
     hcloud_volume: BoundVolume | None = None
 
     def _prepare_result(self):
-        server_name = None
-        if self.hcloud_volume.server is not None:
-            server_name = to_native(self.hcloud_volume.server.name)
-
         return {
-            "id": to_native(self.hcloud_volume.id),
-            "name": to_native(self.hcloud_volume.name),
+            "id": str(self.hcloud_volume.id),
+            "name": self.hcloud_volume.name,
             "size": self.hcloud_volume.size,
-            "location": to_native(self.hcloud_volume.location.name),
+            "location": self.hcloud_volume.location.name,
             "labels": self.hcloud_volume.labels,
-            "server": server_name,
-            "linux_device": to_native(self.hcloud_volume.linux_device),
+            "server": self.hcloud_volume.server.name if self.hcloud_volume.server is not None else None,
+            "linux_device": self.hcloud_volume.linux_device,
             "delete_protection": self.hcloud_volume.protection["delete"],
         }
 
@@ -221,7 +216,8 @@ class AnsibleHCloudVolume(AnsibleHCloud):
                 delete_protection = self.module.params.get("delete_protection")
                 if delete_protection is not None:
                     self._get_volume()
-                    self.hcloud_volume.change_protection(delete=delete_protection).wait_until_finished()
+                    action = self.hcloud_volume.change_protection(delete=delete_protection)
+                    action.wait_until_finished()
             except HCloudException as exception:
                 self.fail_json_hcloud(exception)
         self._mark_as_changed()
@@ -233,7 +229,8 @@ class AnsibleHCloudVolume(AnsibleHCloud):
             if size:
                 if self.hcloud_volume.size < size:
                     if not self.module.check_mode:
-                        self.hcloud_volume.resize(size).wait_until_finished()
+                        action = self.hcloud_volume.resize(size)
+                        action.wait_until_finished()
                     self._mark_as_changed()
                 elif self.hcloud_volume.size > size:
                     self.module.warn("Shrinking of volumes is not supported")
@@ -244,12 +241,14 @@ class AnsibleHCloudVolume(AnsibleHCloud):
                 if self.hcloud_volume.server is None or self.hcloud_volume.server.name != server.name:
                     if not self.module.check_mode:
                         automount = self.module.params.get("automount", False)
-                        self.hcloud_volume.attach(server, automount=automount).wait_until_finished()
+                        action = self.hcloud_volume.attach(server, automount=automount)
+                        action.wait_until_finished()
                     self._mark_as_changed()
             else:
                 if self.hcloud_volume.server is not None:
                     if not self.module.check_mode:
-                        self.hcloud_volume.detach().wait_until_finished()
+                        action = self.hcloud_volume.detach()
+                        action.wait_until_finished()
                     self._mark_as_changed()
 
             labels = self.module.params.get("labels")
@@ -261,7 +260,8 @@ class AnsibleHCloudVolume(AnsibleHCloud):
             delete_protection = self.module.params.get("delete_protection")
             if delete_protection is not None and delete_protection != self.hcloud_volume.protection["delete"]:
                 if not self.module.check_mode:
-                    self.hcloud_volume.change_protection(delete=delete_protection).wait_until_finished()
+                    action = self.hcloud_volume.change_protection(delete=delete_protection)
+                    action.wait_until_finished()
                 self._mark_as_changed()
 
             self._get_volume()
@@ -281,7 +281,8 @@ class AnsibleHCloudVolume(AnsibleHCloud):
             if self.hcloud_volume is not None:
                 if not self.module.check_mode:
                     if self.hcloud_volume.server is not None:
-                        self.hcloud_volume.detach().wait_until_finished()
+                        action = self.hcloud_volume.detach()
+                        action.wait_until_finished()
                     self.client.volumes.delete(self.hcloud_volume)
                 self._mark_as_changed()
             self.hcloud_volume = None
diff --git a/ansible_collections/hetzner/hcloud/plugins/modules/volume_info.py b/ansible_collections/hetzner/hcloud/plugins/modules/volume_info.py
index 1e507690e..b30956d74 100644
--- a/ansible_collections/hetzner/hcloud/plugins/modules/volume_info.py
+++ b/ansible_collections/hetzner/hcloud/plugins/modules/volume_info.py
@@ -95,7 +95,6 @@ hcloud_volume_info:
 """
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
 
 from ..module_utils.hcloud import AnsibleHCloud
 from ..module_utils.vendor.hcloud import HCloudException
@@ -111,22 +110,21 @@ class AnsibleHCloudVolumeInfo(AnsibleHCloud):
         tmp = []
 
         for volume in self.hcloud_volume_info:
-            if volume is not None:
-                server_name = None
-                if volume.server is not None:
-                    server_name = to_native(volume.server.name)
-                tmp.append(
-                    {
-                        "id": to_native(volume.id),
-                        "name": to_native(volume.name),
-                        "size": volume.size,
-                        "location": to_native(volume.location.name),
-                        "labels": volume.labels,
-                        "server": server_name,
-                        "linux_device": to_native(volume.linux_device),
-                        "delete_protection": volume.protection["delete"],
-                    }
-                )
+            if volume is None:
+                continue
+
+            tmp.append(
+                {
+                    "id": str(volume.id),
+                    "name": volume.name,
+                    "size": volume.size,
+                    "location": volume.location.name,
+                    "labels": volume.labels,
+                    "server": volume.server.name if volume.server is not None else None,
+                    "linux_device": volume.linux_device,
+                    "delete_protection": volume.protection["delete"],
+                }
+            )
 
         return tmp
 
-- 
cgit v1.2.3