diff --git a/plugins/module_utils/vendor/hcloud/_client.py b/plugins/module_utils/vendor/hcloud/_client.py index c7068f0..c2c6fde 100644 --- a/plugins/module_utils/vendor/hcloud/_client.py +++ b/plugins/module_utils/vendor/hcloud/_client.py @@ -29,6 +29,7 @@ from .server_types import ServerTypesClient from .servers import ServersClient from .ssh_keys import SSHKeysClient from .volumes import VolumesClient +from .zones import ZonesClient class BackoffFunction(Protocol): @@ -257,6 +258,12 @@ class Client: :type: :class:`PlacementGroupsClient ` """ + self.zones = ZonesClient(self) + """ZonesClient Instance + + :type: :class:`ZonesClient ` + """ + def request( # type: ignore[no-untyped-def] self, method: str, diff --git a/plugins/module_utils/vendor/hcloud/_version.py b/plugins/module_utils/vendor/hcloud/_version.py index c99e801..e9a32ab 100644 --- a/plugins/module_utils/vendor/hcloud/_version.py +++ b/plugins/module_utils/vendor/hcloud/_version.py @@ -1,3 +1,3 @@ from __future__ import annotations -__version__ = "2.7.0" # x-releaser-pleaser-version +__version__ = "2.8.0" # x-releaser-pleaser-version diff --git a/plugins/module_utils/vendor/hcloud/certificates/client.py b/plugins/module_utils/vendor/hcloud/certificates/client.py index 9b75d9f..9404513 100644 --- a/plugins/module_utils/vendor/hcloud/certificates/client.py +++ b/plugins/module_utils/vendor/hcloud/certificates/client.py @@ -53,7 +53,13 @@ class BoundCertificate(BoundModelBase, Certificate): Specifies how many results are returned by page :return: (List[:class:`BoundAction `], :class:`Meta `) """ - return self._client.get_actions_list(self, status, sort, page, per_page) + return self._client.get_actions_list( + self, + status=status, + sort=sort, + page=page, + per_page=per_page, + ) def get_actions( self, @@ -68,7 +74,11 @@ class BoundCertificate(BoundModelBase, Certificate): Specify how the results are sorted. Choices: `id` `id:asc` `id:desc` `command` `command:asc` `command:desc` `status` `status:asc` `status:desc` `progress` `progress:asc` `progress:desc` `started` `started:asc` `started:desc` `finished` `finished:asc` `finished:desc` :return: List[:class:`BoundAction `] """ - return self._client.get_actions(self, status, sort) + return self._client.get_actions( + self, + status=status, + sort=sort, + ) def update( self, @@ -83,7 +93,11 @@ class BoundCertificate(BoundModelBase, Certificate): User-defined labels (key-value pairs) :return: :class:`BoundCertificate ` """ - return self._client.update(self, name, labels) + return self._client.update( + self, + name=name, + labels=labels, + ) def delete(self) -> bool: """Deletes a certificate. diff --git a/plugins/module_utils/vendor/hcloud/firewalls/client.py b/plugins/module_utils/vendor/hcloud/firewalls/client.py index 8453518..771f384 100644 --- a/plugins/module_utils/vendor/hcloud/firewalls/client.py +++ b/plugins/module_utils/vendor/hcloud/firewalls/client.py @@ -109,7 +109,13 @@ class BoundFirewall(BoundModelBase, Firewall): Specifies how many results are returned by page :return: (List[:class:`BoundAction `], :class:`Meta `) """ - return self._client.get_actions_list(self, status, sort, page, per_page) + return self._client.get_actions_list( + self, + status=status, + sort=sort, + page=page, + per_page=per_page, + ) def get_actions( self, @@ -125,7 +131,11 @@ class BoundFirewall(BoundModelBase, Firewall): :return: List[:class:`BoundAction `] """ - return self._client.get_actions(self, status, sort) + return self._client.get_actions( + self, + status=status, + sort=sort, + ) def update( self, @@ -140,7 +150,7 @@ class BoundFirewall(BoundModelBase, Firewall): New Name to set :return: :class:`BoundFirewall ` """ - return self._client.update(self, labels, name) + return self._client.update(self, name=name, labels=labels) def delete(self) -> bool: """Deletes a Firewall. @@ -155,7 +165,7 @@ class BoundFirewall(BoundModelBase, Firewall): :return: List[:class:`BoundAction `] """ - return self._client.set_rules(self, rules) + return self._client.set_rules(self, rules=rules) def apply_to_resources( self, @@ -165,7 +175,7 @@ class BoundFirewall(BoundModelBase, Firewall): :param resources: List[:class:`FirewallResource `] :return: List[:class:`BoundAction `] """ - return self._client.apply_to_resources(self, resources) + return self._client.apply_to_resources(self, resources=resources) def remove_from_resources( self, @@ -175,7 +185,7 @@ class BoundFirewall(BoundModelBase, Firewall): :param resources: List[:class:`FirewallResource `] :return: List[:class:`BoundAction `] """ - return self._client.remove_from_resources(self, resources) + return self._client.remove_from_resources(self, resources=resources) class FirewallsPageResult(NamedTuple): diff --git a/plugins/module_utils/vendor/hcloud/firewalls/domain.py b/plugins/module_utils/vendor/hcloud/firewalls/domain.py index ed24d88..a38fb48 100644 --- a/plugins/module_utils/vendor/hcloud/firewalls/domain.py +++ b/plugins/module_utils/vendor/hcloud/firewalls/domain.py @@ -100,7 +100,7 @@ class FirewallRule(BaseDomain): self, direction: str, protocol: str, - source_ips: list[str], + source_ips: list[str] | None = None, port: str | None = None, destination_ips: list[str] | None = None, description: str | None = None, @@ -108,7 +108,7 @@ class FirewallRule(BaseDomain): self.direction = direction self.port = port self.protocol = protocol - self.source_ips = source_ips + self.source_ips = source_ips or [] self.destination_ips = destination_ips or [] self.description = description @@ -119,8 +119,9 @@ class FirewallRule(BaseDomain): payload: dict[str, Any] = { "direction": self.direction, "protocol": self.protocol, - "source_ips": self.source_ips, } + if len(self.source_ips) > 0: + payload["source_ips"] = self.source_ips if len(self.destination_ips) > 0: payload["destination_ips"] = self.destination_ips if self.port is not None: diff --git a/plugins/module_utils/vendor/hcloud/floating_ips/client.py b/plugins/module_utils/vendor/hcloud/floating_ips/client.py index cc87680..15432d1 100644 --- a/plugins/module_utils/vendor/hcloud/floating_ips/client.py +++ b/plugins/module_utils/vendor/hcloud/floating_ips/client.py @@ -55,7 +55,13 @@ class BoundFloatingIP(BoundModelBase, FloatingIP): Specifies how many results are returned by page :return: (List[:class:`BoundAction `], :class:`Meta `) """ - return self._client.get_actions_list(self, status, sort, page, per_page) + return self._client.get_actions_list( + self, + status=status, + sort=sort, + page=page, + per_page=per_page, + ) def get_actions( self, @@ -70,7 +76,7 @@ class BoundFloatingIP(BoundModelBase, FloatingIP): Specify how the results are sorted. Choices: `id` `id:asc` `id:desc` `command` `command:asc` `command:desc` `status` `status:asc` `status:desc` `progress` `progress:asc` `progress:desc` `started` `started:asc` `started:desc` `finished` `finished:asc` `finished:desc` :return: List[:class:`BoundAction `] """ - return self._client.get_actions(self, status, sort) + return self._client.get_actions(self, status=status, sort=sort) def update( self, @@ -88,7 +94,9 @@ class BoundFloatingIP(BoundModelBase, FloatingIP): New Name to set :return: :class:`BoundFloatingIP ` """ - return self._client.update(self, description, labels, name) + return self._client.update( + self, description=description, labels=labels, name=name + ) def delete(self) -> bool: """Deletes a Floating IP. If it is currently assigned to a server it will automatically get unassigned. @@ -104,7 +112,7 @@ class BoundFloatingIP(BoundModelBase, FloatingIP): If true, prevents the Floating IP from being deleted :return: :class:`BoundAction ` """ - return self._client.change_protection(self, delete) + return self._client.change_protection(self, delete=delete) def assign(self, server: Server | BoundServer) -> BoundAction: """Assigns a Floating IP to a server. @@ -113,7 +121,7 @@ class BoundFloatingIP(BoundModelBase, FloatingIP): Server the Floating IP shall be assigned to :return: :class:`BoundAction ` """ - return self._client.assign(self, server) + return self._client.assign(self, server=server) def unassign(self) -> BoundAction: """Unassigns a Floating IP, resulting in it being unreachable. You may assign it to a server again at a later time. @@ -131,7 +139,7 @@ class BoundFloatingIP(BoundModelBase, FloatingIP): Hostname to set as a reverse DNS PTR entry, will reset to original default value if `None` :return: :class:`BoundAction ` """ - return self._client.change_dns_ptr(self, ip, dns_ptr) + return self._client.change_dns_ptr(self, ip=ip, dns_ptr=dns_ptr) class FloatingIPsPageResult(NamedTuple): diff --git a/plugins/module_utils/vendor/hcloud/images/client.py b/plugins/module_utils/vendor/hcloud/images/client.py index 5d99333..3933ebe 100644 --- a/plugins/module_utils/vendor/hcloud/images/client.py +++ b/plugins/module_utils/vendor/hcloud/images/client.py @@ -53,7 +53,11 @@ class BoundImage(BoundModelBase, Image): :return: (List[:class:`BoundAction `], :class:`Meta `) """ return self._client.get_actions_list( - self, sort=sort, page=page, per_page=per_page, status=status + self, + sort=sort, + page=page, + per_page=per_page, + status=status, ) def get_actions( @@ -69,7 +73,11 @@ class BoundImage(BoundModelBase, Image): Specify how the results are sorted. Choices: `id` `id:asc` `id:desc` `command` `command:asc` `command:desc` `status` `status:asc` `status:desc` `progress` `progress:asc` `progress:desc` `started` `started:asc` `started:desc` `finished` `finished:asc` `finished:desc` :return: List[:class:`BoundAction `] """ - return self._client.get_actions(self, status=status, sort=sort) + return self._client.get_actions( + self, + status=status, + sort=sort, + ) def update( self, @@ -88,7 +96,9 @@ class BoundImage(BoundModelBase, Image): User-defined labels (key-value pairs) :return: :class:`BoundImage ` """ - return self._client.update(self, description, type, labels) + return self._client.update( + self, description=description, type=type, labels=labels + ) def delete(self) -> bool: """Deletes an Image. Only images of type snapshot and backup can be deleted. @@ -104,7 +114,7 @@ class BoundImage(BoundModelBase, Image): If true, prevents the snapshot from being deleted :return: :class:`BoundAction ` """ - return self._client.change_protection(self, delete) + return self._client.change_protection(self, delete=delete) class ImagesPageResult(NamedTuple): diff --git a/plugins/module_utils/vendor/hcloud/load_balancers/client.py b/plugins/module_utils/vendor/hcloud/load_balancers/client.py index e8bbc50..f1c2d8e 100644 --- a/plugins/module_utils/vendor/hcloud/load_balancers/client.py +++ b/plugins/module_utils/vendor/hcloud/load_balancers/client.py @@ -177,7 +177,7 @@ class BoundLoadBalancer(BoundModelBase, LoadBalancer): User-defined labels (key-value pairs) :return: :class:`BoundLoadBalancer ` """ - return self._client.update(self, name, labels) + return self._client.update(self, name=name, labels=labels) def delete(self) -> bool: """Deletes a Load Balancer. @@ -227,7 +227,13 @@ class BoundLoadBalancer(BoundModelBase, LoadBalancer): Specifies how many results are returned by page :return: (List[:class:`BoundAction `], :class:`Meta `) """ - return self._client.get_actions_list(self, status, sort, page, per_page) + return self._client.get_actions_list( + self, + status=status, + sort=sort, + page=page, + per_page=per_page, + ) def get_actions( self, @@ -242,7 +248,7 @@ class BoundLoadBalancer(BoundModelBase, LoadBalancer): Specify how the results are sorted. Choices: `id` `id:asc` `id:desc` `command` `command:asc` `command:desc` `status` `status:asc` `status:desc` `progress` `progress:asc` `progress:desc` `started` `started:asc` `started:desc` `finished` `finished:asc` `finished:desc` :return: List[:class:`BoundAction `] """ - return self._client.get_actions(self, status, sort) + return self._client.get_actions(self, status=status, sort=sort) def add_service(self, service: LoadBalancerService) -> BoundAction: """Adds a service to a Load Balancer. @@ -269,7 +275,7 @@ class BoundLoadBalancer(BoundModelBase, LoadBalancer): The LoadBalancerService you want to delete from the Load Balancer :return: :class:`BoundAction ` """ - return self._client.delete_service(self, service) + return self._client.delete_service(self, service=service) def add_target(self, target: LoadBalancerTarget) -> BoundAction: """Adds a target to a Load Balancer. @@ -278,7 +284,7 @@ class BoundLoadBalancer(BoundModelBase, LoadBalancer): The LoadBalancerTarget you want to add to the Load Balancer :return: :class:`BoundAction ` """ - return self._client.add_target(self, target) + return self._client.add_target(self, target=target) def remove_target(self, target: LoadBalancerTarget) -> BoundAction: """Removes a target from a Load Balancer. @@ -287,7 +293,7 @@ class BoundLoadBalancer(BoundModelBase, LoadBalancer): The LoadBalancerTarget you want to remove from the Load Balancer :return: :class:`BoundAction ` """ - return self._client.remove_target(self, target) + return self._client.remove_target(self, target=target) def change_algorithm(self, algorithm: LoadBalancerAlgorithm) -> BoundAction: """Changes the algorithm used by the Load Balancer @@ -296,7 +302,7 @@ class BoundLoadBalancer(BoundModelBase, LoadBalancer): The LoadBalancerAlgorithm you want to use :return: :class:`BoundAction ` """ - return self._client.change_algorithm(self, algorithm) + return self._client.change_algorithm(self, algorithm=algorithm) def change_dns_ptr(self, ip: str, dns_ptr: str) -> BoundAction: """Changes the hostname that will appear when getting the hostname belonging to the public IPs (IPv4 and IPv6) of this Load Balancer. @@ -307,7 +313,7 @@ class BoundLoadBalancer(BoundModelBase, LoadBalancer): Hostname to set as a reverse DNS PTR entry, will reset to original default value if `None` :return: :class:`BoundAction ` """ - return self._client.change_dns_ptr(self, ip, dns_ptr) + return self._client.change_dns_ptr(self, ip=ip, dns_ptr=dns_ptr) def change_protection(self, delete: bool) -> BoundAction: """Changes the protection configuration of a Load Balancer. @@ -316,21 +322,29 @@ class BoundLoadBalancer(BoundModelBase, LoadBalancer): If True, prevents the Load Balancer from being deleted :return: :class:`BoundAction ` """ - return self._client.change_protection(self, delete) + return self._client.change_protection(self, delete=delete) def attach_to_network( self, network: Network | BoundNetwork, ip: str | None = None, + ip_range: str | None = None, ) -> BoundAction: """Attaches a Load Balancer to a Network :param network: :class:`BoundNetwork ` or :class:`Network ` :param ip: str IP to request to be assigned to this Load Balancer + :param ip_range: str + IP range in CIDR block notation of the subnet to attach to. :return: :class:`BoundAction ` """ - return self._client.attach_to_network(self, network, ip) + return self._client.attach_to_network( + self, + network=network, + ip=ip, + ip_range=ip_range, + ) def detach_from_network(self, network: Network | BoundNetwork) -> BoundAction: """Detaches a Load Balancer from a Network. @@ -338,7 +352,7 @@ class BoundLoadBalancer(BoundModelBase, LoadBalancer): :param network: :class:`BoundNetwork ` or :class:`Network ` :return: :class:`BoundAction ` """ - return self._client.detach_from_network(self, network) + return self._client.detach_from_network(self, network=network) def enable_public_interface(self) -> BoundAction: """Enables the public interface of a Load Balancer. @@ -364,7 +378,7 @@ class BoundLoadBalancer(BoundModelBase, LoadBalancer): Load Balancer type the Load Balancer should migrate to :return: :class:`BoundAction ` """ - return self._client.change_type(self, load_balancer_type) + return self._client.change_type(self, load_balancer_type=load_balancer_type) class LoadBalancersPageResult(NamedTuple): @@ -843,6 +857,7 @@ class LoadBalancersClient(ResourceClientBase): load_balancer: LoadBalancer | BoundLoadBalancer, network: Network | BoundNetwork, ip: str | None = None, + ip_range: str | None = None, ) -> BoundAction: """Attach a Load Balancer to a Network. @@ -850,11 +865,15 @@ class LoadBalancersClient(ResourceClientBase): :param network: :class:`BoundNetwork ` or :class:`Network ` :param ip: str IP to request to be assigned to this Load Balancer + :param ip_range: str + IP range in CIDR block notation of the subnet to attach to. :return: :class:`BoundAction ` """ data: dict[str, Any] = {"network": network.id} if ip is not None: data.update({"ip": ip}) + if ip_range is not None: + data.update({"ip_range": ip_range}) response = self._client.request( url=f"{self._base_url}/{load_balancer.id}/actions/attach_to_network", diff --git a/plugins/module_utils/vendor/hcloud/networks/client.py b/plugins/module_utils/vendor/hcloud/networks/client.py index 5ac1b9d..7c6846a 100644 --- a/plugins/module_utils/vendor/hcloud/networks/client.py +++ b/plugins/module_utils/vendor/hcloud/networks/client.py @@ -89,7 +89,13 @@ class BoundNetwork(BoundModelBase, Network): Specifies how many results are returned by page :return: (List[:class:`BoundAction `], :class:`Meta `) """ - return self._client.get_actions_list(self, status, sort, page, per_page) + return self._client.get_actions_list( + self, + status=status, + sort=sort, + page=page, + per_page=per_page, + ) def get_actions( self, @@ -104,7 +110,7 @@ class BoundNetwork(BoundModelBase, Network): Specify how the results are sorted. Choices: `id` `id:asc` `id:desc` `command` `command:asc` `command:desc` `status` `status:asc` `status:desc` `progress` `progress:asc` `progress:desc` `started` `started:asc` `started:desc` `finished` `finished:asc` `finished:desc` :return: List[:class:`BoundAction `] """ - return self._client.get_actions(self, status, sort) + return self._client.get_actions(self, status=status, sort=sort) def add_subnet(self, subnet: NetworkSubnet) -> BoundAction: """Adds a subnet entry to a network. diff --git a/plugins/module_utils/vendor/hcloud/placement_groups/client.py b/plugins/module_utils/vendor/hcloud/placement_groups/client.py index dbae26d..de61330 100644 --- a/plugins/module_utils/vendor/hcloud/placement_groups/client.py +++ b/plugins/module_utils/vendor/hcloud/placement_groups/client.py @@ -25,7 +25,7 @@ class BoundPlacementGroup(BoundModelBase, PlacementGroup): New Name to set :return: :class:`BoundPlacementGroup ` """ - return self._client.update(self, labels, name) + return self._client.update(self, labels=labels, name=name) def delete(self) -> bool: """Deletes a Placement Group diff --git a/plugins/module_utils/vendor/hcloud/primary_ips/client.py b/plugins/module_utils/vendor/hcloud/primary_ips/client.py index 497e8a5..c6acf6e 100644 --- a/plugins/module_utils/vendor/hcloud/primary_ips/client.py +++ b/plugins/module_utils/vendor/hcloud/primary_ips/client.py @@ -43,7 +43,10 @@ class BoundPrimaryIP(BoundModelBase, PrimaryIP): :return: :class:`BoundPrimaryIP ` """ return self._client.update( - self, auto_delete=auto_delete, labels=labels, name=name + self, + auto_delete=auto_delete, + labels=labels, + name=name, ) def delete(self) -> bool: @@ -60,7 +63,7 @@ class BoundPrimaryIP(BoundModelBase, PrimaryIP): If true, prevents the Primary IP from being deleted :return: :class:`BoundAction ` """ - return self._client.change_protection(self, delete) + return self._client.change_protection(self, delete=delete) def assign(self, assignee_id: int, assignee_type: str) -> BoundAction: """Assigns a Primary IP to a assignee. @@ -71,7 +74,9 @@ class BoundPrimaryIP(BoundModelBase, PrimaryIP): Assignee type (e.g server) the Primary IP shall be assigned to :return: :class:`BoundAction ` """ - return self._client.assign(self, assignee_id, assignee_type) + return self._client.assign( + self, assignee_id=assignee_id, assignee_type=assignee_type + ) def unassign(self) -> BoundAction: """Unassigns a Primary IP, resulting in it being unreachable. You may assign it to a server again at a later time. @@ -89,7 +94,7 @@ class BoundPrimaryIP(BoundModelBase, PrimaryIP): Hostname to set as a reverse DNS PTR entry, will reset to original default value if `None` :return: :class:`BoundAction ` """ - return self._client.change_dns_ptr(self, ip, dns_ptr) + return self._client.change_dns_ptr(self, ip=ip, dns_ptr=dns_ptr) class PrimaryIPsPageResult(NamedTuple): diff --git a/plugins/module_utils/vendor/hcloud/servers/client.py b/plugins/module_utils/vendor/hcloud/servers/client.py index 403a15b..4472ab4 100644 --- a/plugins/module_utils/vendor/hcloud/servers/client.py +++ b/plugins/module_utils/vendor/hcloud/servers/client.py @@ -186,7 +186,13 @@ class BoundServer(BoundModelBase, Server): Specifies how many results are returned by page :return: (List[:class:`BoundAction `], :class:`Meta `) """ - return self._client.get_actions_list(self, status, sort, page, per_page) + return self._client.get_actions_list( + self, + status=status, + sort=sort, + page=page, + per_page=per_page, + ) def get_actions( self, @@ -201,7 +207,7 @@ class BoundServer(BoundModelBase, Server): Specify how the results are sorted. Choices: `id` `id:asc` `id:desc` `command` `command:asc` `command:desc` `status` `status:asc` `status:desc` `progress` `progress:asc` `progress:desc` `started` `started:asc` `started:desc` `finished` `finished:asc` `finished:desc` :return: List[:class:`BoundAction `] """ - return self._client.get_actions(self, status, sort) + return self._client.get_actions(self, status=status, sort=sort) def update( self, @@ -216,7 +222,7 @@ class BoundServer(BoundModelBase, Server): User-defined labels (key-value pairs) :return: :class:`BoundServer ` """ - return self._client.update(self, name, labels) + return self._client.update(self, name=name, labels=labels) def get_metrics( self, @@ -330,7 +336,9 @@ class BoundServer(BoundModelBase, Server): User-defined labels (key-value pairs) :return: :class:`CreateImageResponse ` """ - return self._client.create_image(self, description, type, labels) + return self._client.create_image( + self, description=description, type=type, labels=labels + ) def rebuild( self, @@ -342,7 +350,7 @@ class BoundServer(BoundModelBase, Server): :param image: Image to use for the rebuilt server """ - return self._client.rebuild(self, image) + return self._client.rebuild(self, image=image) def change_type( self, @@ -357,7 +365,9 @@ class BoundServer(BoundModelBase, Server): If false, do not upgrade the disk. This allows downgrading the server type later. :return: :class:`BoundAction ` """ - return self._client.change_type(self, server_type, upgrade_disk) + return self._client.change_type( + self, server_type=server_type, upgrade_disk=upgrade_disk + ) def enable_backup(self) -> BoundAction: """Enables and configures the automatic daily backup option for the server. Enabling automatic backups will increase the price of the server by 20%. @@ -379,7 +389,7 @@ class BoundServer(BoundModelBase, Server): :param iso: :class:`BoundIso ` or :class:`Server ` :return: :class:`BoundAction ` """ - return self._client.attach_iso(self, iso) + return self._client.attach_iso(self, iso=iso) def detach_iso(self) -> BoundAction: """Detaches an ISO from a server. @@ -397,7 +407,7 @@ class BoundServer(BoundModelBase, Server): Hostname to set as a reverse DNS PTR entry, will reset to original default value if `None` :return: :class:`BoundAction ` """ - return self._client.change_dns_ptr(self, ip, dns_ptr) + return self._client.change_dns_ptr(self, ip=ip, dns_ptr=dns_ptr) def change_protection( self, @@ -413,7 +423,7 @@ class BoundServer(BoundModelBase, Server): If true, prevents the server from being rebuilt (currently delete and rebuild attribute needs to have the same value) :return: :class:`BoundAction ` """ - return self._client.change_protection(self, delete, rebuild) + return self._client.change_protection(self, delete=delete, rebuild=rebuild) def request_console(self) -> RequestConsoleResponse: """Requests credentials for remote access via vnc over websocket to keyboard, monitor, and mouse for a server. @@ -427,6 +437,7 @@ class BoundServer(BoundModelBase, Server): network: Network | BoundNetwork, ip: str | None = None, alias_ips: list[str] | None = None, + ip_range: str | None = None, ) -> BoundAction: """Attaches a server to a network @@ -435,9 +446,17 @@ class BoundServer(BoundModelBase, Server): IP to request to be assigned to this server :param alias_ips: List[str] New alias IPs to set for this server. + :param ip_range: str + IP range in CIDR block notation of the subnet to attach to. :return: :class:`BoundAction ` """ - return self._client.attach_to_network(self, network, ip, alias_ips) + return self._client.attach_to_network( + self, + network=network, + ip=ip, + alias_ips=alias_ips, + ip_range=ip_range, + ) def detach_from_network(self, network: Network | BoundNetwork) -> BoundAction: """Detaches a server from a network. @@ -445,7 +464,7 @@ class BoundServer(BoundModelBase, Server): :param network: :class:`BoundNetwork ` or :class:`Network ` :return: :class:`BoundAction ` """ - return self._client.detach_from_network(self, network) + return self._client.detach_from_network(self, network=network) def change_alias_ips( self, @@ -459,7 +478,7 @@ class BoundServer(BoundModelBase, Server): New alias IPs to set for this server. :return: :class:`BoundAction ` """ - return self._client.change_alias_ips(self, network, alias_ips) + return self._client.change_alias_ips(self, network=network, alias_ips=alias_ips) def add_to_placement_group( self, @@ -470,7 +489,9 @@ class BoundServer(BoundModelBase, Server): :param placement_group: :class:`BoundPlacementGroup ` or :class:`Network ` :return: :class:`BoundAction ` """ - return self._client.add_to_placement_group(self, placement_group) + return self._client.add_to_placement_group( + self, placement_group=placement_group + ) def remove_from_placement_group(self) -> BoundAction: """Removes a server from a placement group. @@ -1157,6 +1178,7 @@ class ServersClient(ResourceClientBase): network: Network | BoundNetwork, ip: str | None = None, alias_ips: list[str] | None = None, + ip_range: str | None = None, ) -> BoundAction: """Attaches a server to a network @@ -1166,6 +1188,8 @@ class ServersClient(ResourceClientBase): IP to request to be assigned to this server :param alias_ips: List[str] New alias IPs to set for this server. + :param ip_range: str + IP range in CIDR block notation of the subnet to attach to. :return: :class:`BoundAction ` """ data: dict[str, Any] = {"network": network.id} @@ -1173,6 +1197,9 @@ class ServersClient(ResourceClientBase): data.update({"ip": ip}) if alias_ips is not None: data.update({"alias_ips": alias_ips}) + if ip_range is not None: + data.update({"ip_range": ip_range}) + response = self._client.request( url=f"{self._base_url}/{server.id}/actions/attach_to_network", method="POST", diff --git a/plugins/module_utils/vendor/hcloud/ssh_keys/client.py b/plugins/module_utils/vendor/hcloud/ssh_keys/client.py index d992c2f..4fc541f 100644 --- a/plugins/module_utils/vendor/hcloud/ssh_keys/client.py +++ b/plugins/module_utils/vendor/hcloud/ssh_keys/client.py @@ -24,7 +24,7 @@ class BoundSSHKey(BoundModelBase, SSHKey): User-defined labels (key-value pairs) :return: :class:`BoundSSHKey ` """ - return self._client.update(self, name, labels) + return self._client.update(self, name=name, labels=labels) def delete(self) -> bool: """Deletes an SSH key. It cannot be used anymore. diff --git a/plugins/module_utils/vendor/hcloud/volumes/client.py b/plugins/module_utils/vendor/hcloud/volumes/client.py index dd5b745..0b1b966 100644 --- a/plugins/module_utils/vendor/hcloud/volumes/client.py +++ b/plugins/module_utils/vendor/hcloud/volumes/client.py @@ -52,7 +52,9 @@ class BoundVolume(BoundModelBase, Volume): Specifies how many results are returned by page :return: (List[:class:`BoundAction `], :class:`Meta `) """ - return self._client.get_actions_list(self, status, sort, page, per_page) + return self._client.get_actions_list( + self, status=status, sort=sort, page=page, per_page=per_page + ) def get_actions( self, @@ -67,7 +69,7 @@ class BoundVolume(BoundModelBase, Volume): Specify how the results are sorted. Choices: `id` `id:asc` `id:desc` `command` `command:asc` `command:desc` `status` `status:asc` `status:desc` `progress` `progress:asc` `progress:desc` `started` `started:asc` `started:desc` `finished` `finished:asc` `finished:desc` :return: List[:class:`BoundAction `] """ - return self._client.get_actions(self, status, sort) + return self._client.get_actions(self, status=status, sort=sort) def update( self, @@ -82,7 +84,7 @@ class BoundVolume(BoundModelBase, Volume): User-defined labels (key-value pairs) :return: :class:`BoundAction ` """ - return self._client.update(self, name, labels) + return self._client.update(self, name=name, labels=labels) def delete(self) -> bool: """Deletes a volume. All volume data is irreversibly destroyed. The volume must not be attached to a server and it must not have delete protection enabled. @@ -102,7 +104,7 @@ class BoundVolume(BoundModelBase, Volume): :param automount: boolean :return: :class:`BoundAction ` """ - return self._client.attach(self, server, automount) + return self._client.attach(self, server=server, automount=automount) def detach(self) -> BoundAction: """Detaches a volume from the server it’s attached to. You may attach it to a server again at a later time. @@ -118,7 +120,7 @@ class BoundVolume(BoundModelBase, Volume): New volume size in GB (must be greater than current size) :return: :class:`BoundAction ` """ - return self._client.resize(self, size) + return self._client.resize(self, size=size) def change_protection(self, delete: bool | None = None) -> BoundAction: """Changes the protection configuration of a volume. @@ -127,7 +129,7 @@ class BoundVolume(BoundModelBase, Volume): If True, prevents the volume from being deleted :return: :class:`BoundAction ` """ - return self._client.change_protection(self, delete) + return self._client.change_protection(self, delete=delete) class VolumesPageResult(NamedTuple): diff --git a/plugins/module_utils/vendor/hcloud/zones/__init__.py b/plugins/module_utils/vendor/hcloud/zones/__init__.py new file mode 100644 index 0000000..7871e10 --- /dev/null +++ b/plugins/module_utils/vendor/hcloud/zones/__init__.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from .client import ( + BoundZone, + BoundZoneRRSet, + ZonesClient, + ZonesPageResult, +) +from .domain import ( + CreateZoneResponse, + Zone, + ZoneAuthoritativeNameservers, + ZonePrimaryNameserver, + ZoneRecord, + ZoneRRSet, +) + +__all__ = [ + "BoundZone", + "BoundZoneRRSet", + "CreateZoneResponse", + "Zone", + "ZoneAuthoritativeNameservers", + "ZonePrimaryNameserver", + "ZoneRecord", + "ZoneRRSet", + "ZonesClient", + "ZonesPageResult", +] diff --git a/plugins/module_utils/vendor/hcloud/zones/client.py b/plugins/module_utils/vendor/hcloud/zones/client.py new file mode 100644 index 0000000..09fbd27 --- /dev/null +++ b/plugins/module_utils/vendor/hcloud/zones/client.py @@ -0,0 +1,1428 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, NamedTuple + +from ..actions import ActionsPageResult, BoundAction, ResourceActionsClient +from ..core import BoundModelBase, Meta, ResourceClientBase +from .domain import ( + CreateZoneResponse, + CreateZoneRRSetResponse, + DeleteZoneResponse, + DeleteZoneRRSetResponse, + ExportZonefileResponse, + Zone, + ZoneAuthoritativeNameservers, + ZoneMode, + ZonePrimaryNameserver, + ZoneRecord, + ZoneRRSet, + ZoneRRSetType, +) + +if TYPE_CHECKING: + from .._client import Client + + +class BoundZone(BoundModelBase, Zone): + _client: ZonesClient + + model = Zone + + def __init__( + self, + client: ZonesClient, + data: dict[str, Any], + complete: bool = True, + ): + raw = data.get("primary_nameservers") + if raw is not None: + data["primary_nameservers"] = [ + ZonePrimaryNameserver.from_dict(o) for o in raw + ] + + raw = data.get("authoritative_nameservers") + if raw: + data["authoritative_nameservers"] = ZoneAuthoritativeNameservers.from_dict( + raw + ) + + super().__init__(client, data, complete) + + def update( + self, + *, + labels: dict[str, str] | None = None, + ) -> BoundZone: + """ + Updates the Zone. + + See https://docs.hetzner.cloud/reference/cloud#zones-update-a-zone + + :param labels: User-defined labels (key/value pairs) for the Resource. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.update(self, labels=labels) + + def delete(self) -> DeleteZoneResponse: + """ + Deletes the Zone. + + See https://docs.hetzner.cloud/reference/cloud#zones-delete-a-zone + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.delete(self) + + def export_zonefile(self) -> ExportZonefileResponse: + """ + Returns a generated Zone file in BIND (RFC 1034/1035) format. + + See https://docs.hetzner.cloud/reference/cloud#zones-export-a-zone-file + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.export_zonefile(self) + + def get_actions_list( + self, + *, + status: list[str] | None = None, + sort: list[str] | None = None, + page: int | None = None, + per_page: int | None = None, + ) -> ActionsPageResult: + """ + Returns all Actions for the Zone for a specific page. + + See https://docs.hetzner.cloud/reference/cloud#zones-list-zones + + :param status: Filter the actions by status. The response will only contain actions matching the specified statuses. + :param sort: Sort resources by field and direction. + :param page: Page number to return. + :param per_page: Maximum number of entries returned per page. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.get_actions_list( + self, + status=status, + sort=sort, + page=page, + per_page=per_page, + ) + + def get_actions( + self, + *, + status: list[str] | None = None, + sort: list[str] | None = None, + ) -> list[BoundAction]: + """ + Returns all Actions for the Zone. + + See https://docs.hetzner.cloud/reference/cloud#zones-list-zones + + :param status: Filter the actions by status. The response will only contain actions matching the specified statuses. + :param sort: Sort resources by field and direction. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.get_actions( + self, + status=status, + sort=sort, + ) + + def import_zonefile( + self, + zonefile: str, + ) -> BoundAction: + """ + Imports a zone file, replacing all resource record sets (ZoneRRSet). + + See https://docs.hetzner.cloud/reference/cloud#zone-actions-import-a-zone-file + + :param zonefile: Zone file to import. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.import_zonefile(self, zonefile=zonefile) + + def change_protection( + self, + *, + delete: bool | None = None, + ) -> BoundAction: + """ + Changes the protection of the Zone. + + See https://docs.hetzner.cloud/reference/cloud#zone-actions-change-a-zones-protection + + :param delete: Prevents the Zone from being deleted. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.change_protection(self, delete=delete) + + def change_ttl( + self, + ttl: int, + ) -> BoundAction: + """ + Changes the TTL of the Zone. + + See https://docs.hetzner.cloud/reference/cloud#zone-actions-change-a-zones-default-ttl + + :param ttl: Default Time To Live (TTL) of the Zone. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.change_ttl(self, ttl=ttl) + + def change_primary_nameservers( + self, + primary_nameservers: list[ZonePrimaryNameserver], + ) -> BoundAction: + """ + Changes the primary nameservers of the Zone. + + See https://docs.hetzner.cloud/reference/cloud#zone-actions-change-a-zones-primary-nameservers + + :param primary_nameservers: Primary nameservers of the Zone. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.change_primary_nameservers( + self, + primary_nameservers=primary_nameservers, + ) + + def get_rrset( + self, + name: str, + type: ZoneRRSetType, + ) -> BoundZoneRRSet: + """ + Returns a single ZoneRRSet from the Zone. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-get-an-rrset + + :param name: Name of the RRSet. + :param type: Type of the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.get_rrset(self, name=name, type=type) + + def get_rrset_list( + self, + *, + name: str | None = None, + type: list[ZoneRRSetType] | None = None, + label_selector: str | None = None, + sort: list[str] | None = None, + page: int | None = None, + per_page: int | None = None, + ) -> ZoneRRSetsPageResult: + """ + Returns all ZoneRRSet in the Zone for a specific page. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-list-rrsets + + :param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name. + :param type: Filter resources by their type. The response will only contain the resources matching exactly the specified type. + :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector. + :param sort: Sort resources by field and direction. + :param page: Page number to return. + :param per_page: Maximum number of entries returned per page. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.get_rrset_list( + self, + name=name, + type=type, + label_selector=label_selector, + sort=sort, + page=page, + per_page=per_page, + ) + + def get_rrset_all( + self, + *, + name: str | None = None, + type: list[ZoneRRSetType] | None = None, + label_selector: str | None = None, + sort: list[str] | None = None, + ) -> list[BoundZoneRRSet]: + """ + Returns all ZoneRRSet in the Zone. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-list-rrsets + + :param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name. + :param type: Filter resources by their type. The response will only contain the resources matching exactly the specified type. + :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector. + :param sort: Sort resources by field and direction. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.get_rrset_all( + self, + name=name, + type=type, + label_selector=label_selector, + sort=sort, + ) + + def create_rrset( + self, + *, + name: str, + type: ZoneRRSetType, + ttl: int | None = None, + labels: dict[str, str] | None = None, + records: list[ZoneRecord] | None = None, + ) -> CreateZoneRRSetResponse: + """ + Creates a ZoneRRSet in the Zone. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-create-an-rrset + + :param name: Name of the RRSet. + :param type: Type of the RRSet. + :param ttl: Time To Live (TTL) of the RRSet. + :param labels: User-defined labels (key/value pairs) for the Resource. + :param records: Records of the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.create_rrset( + self, + name=name, + type=type, + ttl=ttl, + labels=labels, + records=records, + ) + + def update_rrset( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + *, + labels: dict[str, str] | None = None, + ) -> BoundZoneRRSet: + """ + Updates a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-update-an-rrset + + :param rrset: RRSet to update. + :param labels: User-defined labels (key/value pairs) for the Resource. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.update_rrset(rrset, labels=labels) + + def delete_rrset( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + ) -> DeleteZoneRRSetResponse: + """ + Deletes a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-delete-an-rrset + + :param rrset: RRSet to delete. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.delete_rrset(rrset) + + def change_rrset_protection( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + *, + change: bool | None = None, + ) -> BoundAction: + """ + Changes the protection of a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-change-an-rrsets-protection + + :param rrset: RRSet to update. + :param change: Prevent the Zone from being changed (deletion and updates). + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.change_rrset_protection(rrset, change=change) + + def change_rrset_ttl( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + ttl: int | None, + ) -> BoundAction: + """ + Changes the TTL of a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-change-an-rrsets-ttl + + :param rrset: RRSet to update. + :param change: Time To Live (TTL) of the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.change_rrset_ttl(rrset, ttl=ttl) + + def add_rrset_records( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + records: list[ZoneRecord], + ttl: int | None = None, + ) -> BoundAction: + """ + Adds records to a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-add-records-to-an-rrset + + :param rrset: RRSet to update. + :param records: Records to add to the RRSet. + :param ttl: Time To Live (TTL) of the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.add_rrset_records(rrset, records=records, ttl=ttl) + + def remove_rrset_records( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + records: list[ZoneRecord], + ) -> BoundAction: + """ + Removes records from a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-remove-records-from-an-rrset + + :param rrset: RRSet to update. + :param records: Records to remove from the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.remove_rrset_records(rrset, records=records) + + def set_rrset_records( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + records: list[ZoneRecord], + ) -> BoundAction: + """ + Sets the records of a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-set-records-of-an-rrset + + :param rrset: RRSet to update. + :param records: Records to set in the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.set_rrset_records(rrset, records=records) + + +class BoundZoneRRSet(BoundModelBase, ZoneRRSet): + _client: ZonesClient + + model = ZoneRRSet + + def __init__(self, client: ZonesClient, data: dict, complete: bool = True): + raw = data.get("zone") + if raw is not None: + data["zone"] = BoundZone(client, data={"id": raw}, complete=False) + + raw = data.get("records") + if raw is not None: + data["records"] = [ZoneRecord.from_dict(o) for o in raw] + + super().__init__(client, data, complete) + + def update_rrset( + self, + *, + labels: dict[str, str] | None = None, + ) -> BoundZoneRRSet: + """ + Updates the ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-update-an-rrset + + :param labels: User-defined labels (key/value pairs) for the Resource. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.update_rrset(self, labels=labels) + + def delete_rrset( + self, + ) -> DeleteZoneRRSetResponse: + """ + Deletes the ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-delete-an-rrset + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.delete_rrset(self) + + def change_rrset_protection( + self, + *, + change: bool | None = None, + ) -> BoundAction: + """ + Changes the protection of the ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-change-an-rrsets-protection + + :param change: Prevent the Zone from being changed (deletion and updates). + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.change_rrset_protection(self, change=change) + + def change_rrset_ttl( + self, + ttl: int | None, + ) -> BoundAction: + """ + Changes the TTL of the ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-change-an-rrsets-ttl + + :param change: Time To Live (TTL) of the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.change_rrset_ttl(self, ttl=ttl) + + def add_rrset_records( + self, + records: list[ZoneRecord], + ttl: int | None = None, + ) -> BoundAction: + """ + Adds records to the ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-add-records-to-an-rrset + + :param records: Records to add to the RRSet. + :param ttl: Time To Live (TTL) of the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.add_rrset_records(self, records=records, ttl=ttl) + + def remove_rrset_records( + self, + records: list[ZoneRecord], + ) -> BoundAction: + """ + Removes records from the ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-remove-records-from-an-rrset + + :param records: Records to remove from the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.remove_rrset_records(self, records=records) + + def set_rrset_records( + self, + records: list[ZoneRecord], + ) -> BoundAction: + """ + Sets the records of the ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-set-records-of-an-rrset + + :param records: Records to set in the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._client.set_rrset_records(self, records=records) + + +class ZonesPageResult(NamedTuple): + zones: list[BoundZone] + meta: Meta + + +class ZoneRRSetsPageResult(NamedTuple): + rrsets: list[BoundZoneRRSet] + meta: Meta + + +class ZonesClient(ResourceClientBase): + """ + ZoneClient is a client for the Zone (DNS) API. + + See https://docs.hetzner.cloud/reference/cloud#zones and https://docs.hetzner.cloud/reference/cloud#zone-rrsets. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + + _base_url = "/zones" + + actions: ResourceActionsClient + """Zones scoped actions client + + :type: :class:`ResourceActionsClient ` + """ + + def __init__(self, client: Client): + super().__init__(client) + self.actions = ResourceActionsClient(client, self._base_url) + + def get(self, id_or_name: int | str) -> BoundZone: + """ + Returns a single Zone. + + See https://docs.hetzner.cloud/reference/cloud#zones-get-a-zone + + :param id_or_name: ID or Name of the Zone. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + response = self._client.request( + method="GET", + url=f"{self._base_url}/{id_or_name}", + ) + return BoundZone(self, response["zone"]) + + def get_list( + self, + *, + name: str | None = None, + mode: ZoneMode | None = None, + label_selector: str | None = None, + sort: list[str] | None = None, + page: int | None = None, + per_page: int | None = None, + ) -> ZonesPageResult: + """ + Returns a list of Zone for a specific page. + + See https://docs.hetzner.cloud/reference/cloud#zones-list-zones + + :param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name. + :param mode: Filter resources by their mode. The response will only contain the resources matching exactly the specified mode. + :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector. + :param sort: Sort resources by field and direction. + :param page: Page number to return. + :param per_page: Maximum number of entries returned per page. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + params: dict[str, Any] = {} + if name is not None: + params["name"] = name + if mode is not None: + params["mode"] = mode + if label_selector is not None: + params["label_selector"] = label_selector + if sort is not None: + params["sort"] = sort + if page is not None: + params["page"] = page + if per_page is not None: + params["per_page"] = per_page + + response = self._client.request( + method="GET", + url=f"{self._base_url}", + params=params, + ) + return ZonesPageResult( + zones=[BoundZone(self, item) for item in response["zones"]], + meta=Meta.parse_meta(response), + ) + + def get_all( + self, + *, + name: str | None = None, + mode: ZoneMode | None = None, + label_selector: str | None = None, + sort: list[str] | None = None, + ) -> list[BoundZone]: + """ + Returns a list of all Zone. + + See https://docs.hetzner.cloud/reference/cloud#zones-list-zones + + :param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name. + :param mode: Filter resources by their mode. The response will only contain the resources matching exactly the specified mode. + :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector. + :param sort: Sort resources by field and direction. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._iter_pages( + self.get_list, + name=name, + mode=mode, + label_selector=label_selector, + sort=sort, + ) + + def create( + self, + *, + name: str, + mode: ZoneMode, + ttl: int | None = None, + labels: dict[str, str] | None = None, + primary_nameservers: list[ZonePrimaryNameserver] | None = None, + rrsets: list[ZoneRRSet] | None = None, + zonefile: str | None = None, + ) -> CreateZoneResponse: + """ + Creates a Zone. + + A default SOA and three NS resource records with the assigned Hetzner nameservers are created automatically. + + See https://docs.hetzner.cloud/reference/cloud#zones-create-a-zone + + :param name: Name of the Zone. + :param mode: Mode of the Zone. + :param ttl: Default Time To Live (TTL) of the Zone. + :param labels: User-defined labels (key/value pairs) for the Resource. + :param primary_nameservers: Primary nameservers of the Zone. + :param rrsets: RRSets to be added to the Zone. + :param zonefile: Zone file to import. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + data: dict[str, Any] = { + "name": name, + "mode": mode, + } + if ttl is not None: + data["ttl"] = ttl + if labels is not None: + data["labels"] = labels + if primary_nameservers is not None: + data["primary_nameservers"] = [o.to_payload() for o in primary_nameservers] + if rrsets is not None: + data["rrsets"] = [o.to_payload() for o in rrsets] + if zonefile is not None: + data["zonefile"] = zonefile + + response = self._client.request( + method="POST", + url=f"{self._base_url}", + json=data, + ) + + return CreateZoneResponse( + zone=BoundZone(self, response["zone"]), + action=BoundAction(self._parent.actions, response["action"]), + ) + + def update( + self, + zone: Zone | BoundZone, + *, + labels: dict[str, str] | None = None, + ) -> BoundZone: + """ + Updates a Zone. + + See https://docs.hetzner.cloud/reference/cloud#zones-update-a-zone + + :param zone: Zone to update. + :param labels: User-defined labels (key/value pairs) for the Resource. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + data: dict[str, Any] = {} + if labels is not None: + data["labels"] = labels + + response = self._client.request( + method="PUT", + url=f"{self._base_url}/{zone.id_or_name}", + json=data, + ) + return BoundZone(self, response["zone"]) + + def delete( + self, + zone: Zone | BoundZone, + ) -> DeleteZoneResponse: + """ + Deletes a Zone. + + See https://docs.hetzner.cloud/reference/cloud#zones-delete-a-zone + + :param zone: Zone to delete. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + response = self._client.request( + method="DELETE", + url=f"{self._base_url}/{zone.id_or_name}", + ) + + return DeleteZoneResponse( + action=BoundAction(self._parent.actions, response["action"]), + ) + + def export_zonefile( + self, + zone: Zone | BoundZone, + ) -> ExportZonefileResponse: + """ + Returns a generated Zone file in BIND (RFC 1034/1035) format. + + See https://docs.hetzner.cloud/reference/cloud#zones-export-a-zone-file + + :param zone: Zone to export the zone file from. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + response = self._client.request( + method="GET", + url=f"{self._base_url}/{zone.id_or_name}/zonefile", + ) + return ExportZonefileResponse(response["zonefile"]) + + def get_actions_list( + self, + zone: Zone | BoundZone, + *, + status: list[str] | None = None, + sort: list[str] | None = None, + page: int | None = None, + per_page: int | None = None, + ) -> ActionsPageResult: + """ + Returns all Actions for a Zone for a specific page. + + See https://docs.hetzner.cloud/reference/cloud#zones-list-zones + + :param zone: Zone to fetch the Actions from. + :param status: Filter the actions by status. The response will only contain actions matching the specified statuses. + :param sort: Sort resources by field and direction. + :param page: Page number to return. + :param per_page: Maximum number of entries returned per page. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + params: dict[str, Any] = {} + if status is not None: + params["status"] = status + if sort is not None: + params["sort"] = sort + if page is not None: + params["page"] = page + if per_page is not None: + params["per_page"] = per_page + + response = self._client.request( + method="GET", + url=f"{self._base_url}/{zone.id_or_name}/actions", + params=params, + ) + return ActionsPageResult( + actions=[BoundAction(self._parent.actions, o) for o in response["actions"]], + meta=Meta.parse_meta(response), + ) + + def get_actions( + self, + zone: Zone | BoundZone, + *, + status: list[str] | None = None, + sort: list[str] | None = None, + ) -> list[BoundAction]: + """ + Returns all Actions for a Zone. + + See https://docs.hetzner.cloud/reference/cloud#zones-list-zones + + :param zone: Zone to fetch the Actions from. + :param status: Filter the actions by status. The response will only contain actions matching the specified statuses. + :param sort: Sort resources by field and direction. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._iter_pages( + self.get_actions_list, + zone, + status=status, + sort=sort, + ) + + def import_zonefile( + self, + zone: Zone | BoundZone, + zonefile: str, + ) -> BoundAction: + """ + Imports a zone file, replacing all resource record sets (ZoneRRSet). + + See https://docs.hetzner.cloud/reference/cloud#zone-actions-import-a-zone-file + + :param zone: Zone to import the zone file into. + :param zonefile: Zone file to import. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + data: dict[str, Any] = { + "zonefile": zonefile, + } + + response = self._client.request( + method="POST", + url=f"{self._base_url}/{zone.id_or_name}/actions/import_zonefile", + json=data, + ) + return BoundAction(self._parent.actions, response["action"]) + + def change_protection( + self, + zone: Zone | BoundZone, + *, + delete: bool | None = None, + ) -> BoundAction: + """ + Changes the protection of a Zone. + + See https://docs.hetzner.cloud/reference/cloud#zone-actions-change-a-zones-protection + + :param zone: Zone to update. + :param delete: Prevents the Zone from being deleted. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + data: dict[str, Any] = {} + if delete is not None: + data["delete"] = delete + + response = self._client.request( + method="POST", + url=f"{self._base_url}/{zone.id_or_name}/actions/change_protection", + json=data, + ) + return BoundAction(self._parent.actions, response["action"]) + + def change_ttl( + self, + zone: Zone | BoundZone, + ttl: int, + ) -> BoundAction: + """ + Changes the TTL of a Zone. + + See https://docs.hetzner.cloud/reference/cloud#zone-actions-change-a-zones-default-ttl + + :param zone: Zone to update. + :param ttl: Default Time To Live (TTL) of the Zone. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + data: dict[str, Any] = { + "ttl": ttl, + } + + response = self._client.request( + method="POST", + url=f"{self._base_url}/{zone.id_or_name}/actions/change_ttl", + json=data, + ) + return BoundAction(self._parent.actions, response["action"]) + + def change_primary_nameservers( + self, + zone: Zone | BoundZone, + primary_nameservers: list[ZonePrimaryNameserver], + ) -> BoundAction: + """ + Changes the primary nameservers of a Zone. + + See https://docs.hetzner.cloud/reference/cloud#zone-actions-change-a-zones-primary-nameservers + + :param zone: Zone to update. + :param primary_nameservers: Primary nameservers of the Zone. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + data: dict[str, Any] = { + "primary_nameservers": [o.to_payload() for o in primary_nameservers], + } + + response = self._client.request( + method="POST", + url=f"{self._base_url}/{zone.id_or_name}/actions/change_primary_nameservers", + json=data, + ) + return BoundAction(self._parent.actions, response["action"]) + + def get_rrset( + self, + zone: Zone | BoundZone, + name: str, + type: ZoneRRSetType, + ) -> BoundZoneRRSet: + """ + Returns a single ZoneRRSet from the Zone. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-get-an-rrset + + :param zone: Zone to fetch the RRSet from. + :param name: Name of the RRSet. + :param type: Type of the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + response = self._client.request( + method="GET", + url=f"{self._base_url}/{zone.id_or_name}/rrsets/{name}/{type}", + ) + return BoundZoneRRSet(self, response["rrset"]) + + def get_rrset_list( + self, + zone: Zone | BoundZone, + *, + name: str | None = None, + type: list[ZoneRRSetType] | None = None, + label_selector: str | None = None, + sort: list[str] | None = None, + page: int | None = None, + per_page: int | None = None, + ) -> ZoneRRSetsPageResult: + """ + Returns all ZoneRRSet in the Zone for a specific page. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-list-rrsets + + :param zone: Zone to fetch the RRSets from. + :param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name. + :param type: Filter resources by their type. The response will only contain the resources matching exactly the specified type. + :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector. + :param sort: Sort resources by field and direction. + :param page: Page number to return. + :param per_page: Maximum number of entries returned per page. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + params: dict[str, Any] = {} + if name is not None: + params["name"] = name + if type is not None: + params["type"] = type + if label_selector is not None: + params["label_selector"] = label_selector + if sort is not None: + params["sort"] = sort + if page is not None: + params["page"] = page + if per_page is not None: + params["per_page"] = per_page + + response = self._client.request( + method="GET", + url=f"{self._base_url}/{zone.id_or_name}/rrsets", + params=params, + ) + return ZoneRRSetsPageResult( + rrsets=[BoundZoneRRSet(self, item) for item in response["rrsets"]], + meta=Meta.parse_meta(response), + ) + + def get_rrset_all( + self, + zone: Zone | BoundZone, + *, + name: str | None = None, + type: list[ZoneRRSetType] | None = None, + label_selector: str | None = None, + sort: list[str] | None = None, + ) -> list[BoundZoneRRSet]: + """ + Returns all ZoneRRSet in the Zone. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-list-rrsets + + :param zone: Zone to fetch the RRSets from. + :param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name. + :param type: Filter resources by their type. The response will only contain the resources matching exactly the specified type. + :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector. + :param sort: Sort resources by field and direction. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + return self._iter_pages( + self.get_rrset_list, + zone, + name=name, + type=type, + label_selector=label_selector, + sort=sort, + ) + + def create_rrset( + self, + zone: Zone | BoundZone, + *, + name: str, + type: ZoneRRSetType, + ttl: int | None = None, + labels: dict[str, str] | None = None, + records: list[ZoneRecord] | None = None, + ) -> CreateZoneRRSetResponse: + """ + Creates a ZoneRRSet in the Zone. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-create-an-rrset + + :param zone: Zone to create the RRSets in. + :param name: Name of the RRSet. + :param type: Type of the RRSet. + :param ttl: Time To Live (TTL) of the RRSet. + :param labels: User-defined labels (key/value pairs) for the Resource. + :param records: Records of the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + data: dict[str, Any] = { + "name": name, + "type": type, + } + if ttl is not None: + data["ttl"] = ttl + if labels is not None: + data["labels"] = labels + if records is not None: + data["records"] = [o.to_payload() for o in records] + + response = self._client.request( + method="POST", + url=f"{self._base_url}/{zone.id_or_name}/rrsets", + json=data, + ) + return CreateZoneRRSetResponse( + rrset=BoundZoneRRSet(self, response["rrset"]), + action=BoundAction(self._parent.actions, response["action"]), + ) + + def update_rrset( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + *, + labels: dict[str, str] | None = None, + ) -> BoundZoneRRSet: + """ + Updates a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-update-an-rrset + + :param rrset: RRSet to update. + :param labels: User-defined labels (key/value pairs) for the Resource. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + if rrset.zone is None: + raise ValueError("rrset zone property is none") + + data: dict[str, Any] = {} + if labels is not None: + data["labels"] = labels + + response = self._client.request( + method="PUT", + url=f"{self._base_url}/{rrset.zone.id_or_name}/rrsets/{rrset.name}/{rrset.type}", + json=data, + ) + return BoundZoneRRSet(self, response["rrset"]) + + def delete_rrset( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + ) -> DeleteZoneRRSetResponse: + """ + Deletes a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets-delete-an-rrset + + :param rrset: RRSet to delete. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + if rrset.zone is None: + raise ValueError("rrset zone property is none") + + response = self._client.request( + method="DELETE", + url=f"{self._base_url}/{rrset.zone.id_or_name}/rrsets/{rrset.name}/{rrset.type}", + ) + return DeleteZoneRRSetResponse( + action=BoundAction(self._parent.actions, response["action"]), + ) + + def change_rrset_protection( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + *, + change: bool | None = None, + ) -> BoundAction: + """ + Changes the protection of a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-change-an-rrsets-protection + + :param rrset: RRSet to update. + :param change: Prevent the Zone from being changed (deletion and updates). + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + if rrset.zone is None: + raise ValueError("rrset zone property is none") + + data: dict[str, Any] = {} + if change is not None: + data["change"] = change + + response = self._client.request( + method="POST", + url=f"{self._base_url}/{rrset.zone.id_or_name}/rrsets/{rrset.name}/{rrset.type}/actions/change_protection", + json=data, + ) + return BoundAction(self._parent.actions, response["action"]) + + def change_rrset_ttl( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + ttl: int | None, + ) -> BoundAction: + """ + Changes the TTL of a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-change-an-rrsets-ttl + + :param rrset: RRSet to update. + :param change: Time To Live (TTL) of the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + if rrset.zone is None: + raise ValueError("rrset zone property is none") + + data: dict[str, Any] = { + "ttl": ttl, + } + + response = self._client.request( + method="POST", + url=f"{self._base_url}/{rrset.zone.id_or_name}/rrsets/{rrset.name}/{rrset.type}/actions/change_ttl", + json=data, + ) + return BoundAction(self._parent.actions, response["action"]) + + def add_rrset_records( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + records: list[ZoneRecord], + ttl: int | None = None, + ) -> BoundAction: + """ + Adds records to a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-add-records-to-an-rrset + + :param rrset: RRSet to update. + :param records: Records to add to the RRSet. + :param ttl: Time To Live (TTL) of the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + if rrset.zone is None: + raise ValueError("rrset zone property is none") + + data: dict[str, Any] = { + "records": [o.to_payload() for o in records], + } + if ttl is not None: + data["ttl"] = ttl + + response = self._client.request( + method="POST", + url=f"{self._base_url}/{rrset.zone.id_or_name}/rrsets/{rrset.name}/{rrset.type}/actions/add_records", + json=data, + ) + return BoundAction(self._parent.actions, response["action"]) + + def remove_rrset_records( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + records: list[ZoneRecord], + ) -> BoundAction: + """ + Removes records from a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-remove-records-from-an-rrset + + :param rrset: RRSet to update. + :param records: Records to remove from the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + if rrset.zone is None: + raise ValueError("rrset zone property is none") + + data: dict[str, Any] = { + "records": [o.to_payload() for o in records], + } + + response = self._client.request( + method="POST", + url=f"{self._base_url}/{rrset.zone.id_or_name}/rrsets/{rrset.name}/{rrset.type}/actions/remove_records", + json=data, + ) + return BoundAction(self._parent.actions, response["action"]) + + def set_rrset_records( + self, + rrset: ZoneRRSet | BoundZoneRRSet, + records: list[ZoneRecord], + ) -> BoundAction: + """ + Sets the records of a ZoneRRSet. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-set-records-of-an-rrset + + :param rrset: RRSet to update. + :param records: Records to set in the RRSet. + + Experimental: + DNS API is in beta, breaking changes may occur within minor releases. + See https://docs.hetzner.cloud/changelog#2025-10-07-dns-beta for more details. + """ + if rrset.zone is None: + raise ValueError("rrset zone property is none") + + data: dict[str, Any] = { + "records": [o.to_payload() for o in records], + } + + response = self._client.request( + method="POST", + url=f"{self._base_url}/{rrset.zone.id_or_name}/rrsets/{rrset.name}/{rrset.type}/actions/set_records", + json=data, + ) + return BoundAction(self._parent.actions, response["action"]) diff --git a/plugins/module_utils/vendor/hcloud/zones/domain.py b/plugins/module_utils/vendor/hcloud/zones/domain.py new file mode 100644 index 0000000..726641e --- /dev/null +++ b/plugins/module_utils/vendor/hcloud/zones/domain.py @@ -0,0 +1,433 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Literal, TypedDict + +try: + from dateutil.parser import isoparse +except ImportError: + isoparse = None + +from ..core import BaseDomain, DomainIdentityMixin + +if TYPE_CHECKING: + from ..actions import BoundAction + from .client import BoundZone, BoundZoneRRSet + + +ZoneMode = Literal["primary", "secondary"] +ZoneStatus = Literal["ok", "updating", "error"] +ZoneRegistrar = Literal["hetzner", "other", "unknown"] + + +class Zone(BaseDomain, DomainIdentityMixin): + """ + Zone Domain. + + See https://docs.hetzner.cloud/reference/cloud#zones. + """ + + MODE_PRIMARY = "primary" + """ + Zone in primary mode, resource record sets (RRSets) and resource records (RRs) are + managed via the Cloud API or Cloud Console. + """ + MODE_SECONDARY = "secondary" + """ + Zone in secondary mode, Hetzner's nameservers query RRSets and RRs from given + primary nameservers via AXFR. + """ + + STATUS_OK = "ok" + """The Zone is pushed to the authoritative nameservers.""" + STATUS_UPDATING = "updating" + """The Zone is currently being published to the authoritative nameservers.""" + STATUS_ERROR = "error" + """The Zone could not be published to the authoritative nameservers.""" + + REGISTRAR_HETZNER = "hetzner" + REGISTRAR_OTHER = "other" + REGISTRAR_UNKNOWN = "unknown" + + __api_properties__ = ( + "id", + "name", + "created", + "mode", + "ttl", + "labels", + "protection", + "status", + "record_count", + "registrar", + "primary_nameservers", + "authoritative_nameservers", + ) + __slots__ = __api_properties__ + + def __init__( + self, + id: int | None = None, + name: str | None = None, + created: str | None = None, + mode: ZoneMode | None = None, + ttl: int | None = None, + labels: dict[str, str] | None = None, + protection: ZoneProtection | None = None, + status: ZoneStatus | None = None, + record_count: int | None = None, + registrar: ZoneRegistrar | None = None, + primary_nameservers: list[ZonePrimaryNameserver] | None = None, + authoritative_nameservers: ZoneAuthoritativeNameservers | None = None, + ): + self.id = id + self.name = name + self.created = isoparse(created) if created else None + self.mode = mode + self.ttl = ttl + self.labels = labels + self.protection = protection + self.status = status + self.record_count = record_count + self.registrar = registrar + self.primary_nameservers = primary_nameservers + self.authoritative_nameservers = authoritative_nameservers + + +ZonePrimaryNameserverTSIGAlgorithm = Literal[ + "hmac-md5", + "hmac-sha1", + "hmac-sha256", +] + + +class ZonePrimaryNameserver(BaseDomain): + """ + Zone Primary Nameserver Domain. + """ + + TSIG_ALGORITHM_HMAC_MD5 = "hmac-md5" + """Transaction signature (TSIG) algorithm used to generate the TSIG key.""" + TSIG_ALGORITHM_HMAC_SHA1 = "hmac-sha1" + """Transaction signature (TSIG) algorithm used to generate the TSIG key.""" + TSIG_ALGORITHM_HMAC_SHA256 = "hmac-sha256" + """Transaction signature (TSIG) algorithm used to generate the TSIG key.""" + + __api_properties__ = ( + "address", + "port", + "tsig_algorithm", + "tsig_key", + ) + __slots__ = __api_properties__ + + def __init__( + self, + address: str, + port: int | None = None, + tsig_algorithm: ZonePrimaryNameserverTSIGAlgorithm | None = None, + tsig_key: str | None = None, + ): + self.address = address + self.port = port + self.tsig_algorithm = tsig_algorithm + self.tsig_key = tsig_key + + def to_payload(self) -> dict[str, Any]: + """ + Generates the request payload from this domain object. + """ + payload: dict[str, Any] = { + "address": self.address, + } + if self.port is not None: + payload["port"] = self.port + if self.tsig_algorithm is not None: + payload["tsig_algorithm"] = self.tsig_algorithm + if self.tsig_key is not None: + payload["tsig_key"] = self.tsig_key + + return payload + + +ZoneAuthoritativeNameserversDelegationStatus = Literal[ + "valid", + "partially-valid", + "invalid", + "lame", + "unregistered", + "unknown", +] + + +class ZoneAuthoritativeNameservers(BaseDomain): + """ + Zone Authoritative Nameservers Domain. + """ + + DELEGATION_STATUS_VALID = "valid" + DELEGATION_STATUS_PARTIALLY_VALID = "partially-valid" + DELEGATION_STATUS_INVALID = "invalid" + DELEGATION_STATUS_LAME = "lame" + DELEGATION_STATUS_UNREGISTERED = "unregistered" + DELEGATION_STATUS_UNKNOWN = "unknown" + + __api_properties__ = ( + "assigned", + "delegated", + "delegation_last_check", + "delegation_status", + ) + __slots__ = __api_properties__ + + def __init__( + self, + assigned: list[str] | None = None, + delegated: list[str] | None = None, + delegation_last_check: str | None = None, + delegation_status: ZoneAuthoritativeNameserversDelegationStatus | None = None, + ): + self.assigned = assigned + self.delegated = delegated + self.delegation_last_check = ( + isoparse(delegation_last_check) + if delegation_last_check is not None + else None + ) + self.delegation_status = delegation_status + + +class ZoneProtection(TypedDict): + """ + Zone Protection. + """ + + delete: bool + + +class CreateZoneResponse(BaseDomain): + """ + Create Zone Response Domain. + """ + + __api_properties__ = ("zone", "action") + __slots__ = __api_properties__ + + def __init__( + self, + zone: BoundZone, + action: BoundAction, + ): + self.zone = zone + self.action = action + + +class DeleteZoneResponse(BaseDomain): + """ + Delete Zone Response Domain. + """ + + __api_properties__ = ("action",) + __slots__ = __api_properties__ + + def __init__( + self, + action: BoundAction, + ): + self.action = action + + +class ExportZonefileResponse(BaseDomain): + """ + Export Zonefile Response Domain. + """ + + __api_properties__ = ("zonefile",) + __slots__ = __api_properties__ + + def __init__( + self, + zonefile: str, + ): + self.zonefile = zonefile + + +ZoneRRSetType = Literal[ + "A", + "AAAA", + "CAA", + "CNAME", + "DS", + "HINFO", + "HTTPS", + "MX", + "NS", + "PTR", + "RP", + "SOA", + "SRV", + "SVCB", + "TLSA", + "TXT", +] + + +class ZoneRRSet(BaseDomain): + """ + Zone RRSet Domain. + + See https://docs.hetzner.cloud/reference/cloud#zone-rrsets + """ + + TYPE_A = "A" + TYPE_AAAA = "AAAA" + TYPE_CAA = "CAA" + TYPE_CNAME = "CNAME" + TYPE_DS = "DS" + TYPE_HINFO = "HINFO" + TYPE_HTTPS = "HTTPS" + TYPE_MX = "MX" + TYPE_NS = "NS" + TYPE_PTR = "PTR" + TYPE_RP = "RP" + TYPE_SOA = "SOA" + TYPE_SRV = "SRV" + TYPE_SVCB = "SVCB" + TYPE_TLSA = "TLSA" + TYPE_TXT = "TXT" + + __api_properties__ = ( + "name", + "type", + "ttl", + "labels", + "protection", + "records", + "id", + "zone", + ) + __slots__ = __api_properties__ + + def __init__( + self, + name: str | None = None, + type: ZoneRRSetType | None = None, + ttl: int | None = None, + labels: dict[str, str] | None = None, + protection: ZoneRRSetProtection | None = None, + records: list[ZoneRecord] | None = None, + id: str | None = None, + zone: BoundZone | Zone | None = None, + ): + # Ensure that 'id', 'name' and 'type' are always populated. + if name is not None and type is not None: + if id is None: + id = f"{name}/{type}" + else: + if id is not None: + name, _, type = id.partition("/") # type: ignore[assignment] + else: + raise ValueError("id or name and type must be set") + + self.name = name + self.type = type + self.ttl = ttl + self.labels = labels + self.protection = protection + self.records = records + + self.id = id + self.zone = zone + + def to_payload(self) -> dict[str, Any]: + """ + Generates the request payload from this domain object. + """ + payload: dict[str, Any] = { + "name": self.name, + "type": self.type, + } + if self.ttl is not None: + payload["ttl"] = self.ttl + if self.labels is not None: + payload["labels"] = self.labels + if self.protection is not None: + payload["protection"] = self.protection + if self.records is not None: + payload["records"] = [o.to_payload() for o in self.records] + + return payload + + +class ZoneRRSetProtection(TypedDict): + """ + Zone RRSet Protection. + """ + + change: bool + + +class ZoneRecord(BaseDomain): + """ + Zone Record Domain. + """ + + __api_properties__ = ( + "value", + "comment", + ) + __slots__ = __api_properties__ + + def __init__( + self, + value: str, + comment: str | None = None, + ): + self.value = value + self.comment = comment + + def to_payload(self) -> dict[str, Any]: + """ + Generates the request payload from this domain object. + """ + payload: dict[str, Any] = { + "value": self.value, + } + if self.comment is not None: + payload["comment"] = self.comment + + return payload + + +class CreateZoneRRSetResponse(BaseDomain): + """ + Create Zone RRSet Response Domain. + """ + + __api_properties__ = ( + "rrset", + "action", + ) + __slots__ = __api_properties__ + + def __init__( + self, + rrset: BoundZoneRRSet, + action: BoundAction, + ): + self.rrset = rrset + self.action = action + + +class DeleteZoneRRSetResponse(BaseDomain): + """ + Delete Zone RRSet Response Domain. + """ + + __api_properties__ = ("action",) + __slots__ = __api_properties__ + + def __init__( + self, + action: BoundAction, + ): + self.action = action diff --git a/scripts/vendor.py b/scripts/vendor.py index ee29974..0122839 100755 --- a/scripts/vendor.py +++ b/scripts/vendor.py @@ -22,7 +22,7 @@ from textwrap import dedent logger = logging.getLogger("vendor") HCLOUD_SOURCE_URL = "https://github.com/hetznercloud/hcloud-python" -HCLOUD_VERSION = "v2.7.0" +HCLOUD_VERSION = "v2.8.0" HCLOUD_VENDOR_PATH = "plugins/module_utils/vendor/hcloud"