diff --git a/plugins/module_utils/vendor/hcloud/__init__.py b/plugins/module_utils/vendor/hcloud/__init__.py index 2cf9921..95709bb 100644 --- a/plugins/module_utils/vendor/hcloud/__init__.py +++ b/plugins/module_utils/vendor/hcloud/__init__.py @@ -1,6 +1,10 @@ from __future__ import annotations -from ._client import Client as Client # noqa pylint: disable=C0414 +from ._client import ( # noqa pylint: disable=C0414 + Client as Client, + constant_backoff_function as constant_backoff_function, + exponential_backoff_function as exponential_backoff_function, +) from ._exceptions import ( # noqa pylint: disable=C0414 APIException as APIException, HCloudException as HCloudException, diff --git a/plugins/module_utils/vendor/hcloud/_client.py b/plugins/module_utils/vendor/hcloud/_client.py index 842c5d0..73b7872 100644 --- a/plugins/module_utils/vendor/hcloud/_client.py +++ b/plugins/module_utils/vendor/hcloud/_client.py @@ -1,6 +1,7 @@ from __future__ import annotations import time +from random import uniform from typing import Protocol try: @@ -29,7 +30,7 @@ from .ssh_keys import SSHKeysClient from .volumes import VolumesClient -class PollIntervalFunction(Protocol): +class BackoffFunction(Protocol): def __call__(self, retries: int) -> float: """ Return a interval in seconds to wait between each API call. @@ -38,20 +39,65 @@ class PollIntervalFunction(Protocol): """ +def constant_backoff_function(interval: float) -> BackoffFunction: + """ + Return a backoff function, implementing a constant backoff. + + :param interval: Constant interval to return. + """ + + # pylint: disable=unused-argument + def func(retries: int) -> float: + return interval + + return func + + +def exponential_backoff_function( + *, + base: float, + multiplier: int, + cap: float, + jitter: bool = False, +) -> BackoffFunction: + """ + Return a backoff function, implementing a truncated exponential backoff with + optional full jitter. + + :param base: Base for the exponential backoff algorithm. + :param multiplier: Multiplier for the exponential backoff algorithm. + :param cap: Value at which the interval is truncated. + :param jitter: Whether to add jitter. + """ + + def func(retries: int) -> float: + interval = base * multiplier**retries # Exponential backoff + interval = min(cap, interval) # Cap backoff + if jitter: + interval = uniform(base, interval) # Add jitter + return interval + + return func + + class Client: """Base Client for accessing the Hetzner Cloud API""" _version = __version__ - _retry_wait_time = 0.5 __user_agent_prefix = "hcloud-python" + _retry_interval = exponential_backoff_function( + base=1.0, multiplier=2, cap=60.0, jitter=True + ) + _retry_max_retries = 5 + def __init__( self, token: str, api_endpoint: str = "https://api.hetzner.cloud/v1", application_name: str | None = None, application_version: str | None = None, - poll_interval: int | float | PollIntervalFunction = 1.0, + poll_interval: int | float | BackoffFunction = 1.0, poll_max_retries: int = 120, timeout: float | tuple[float, float] | None = None, ): @@ -76,7 +122,7 @@ class Client: self._requests_timeout = timeout if isinstance(poll_interval, (int, float)): - self._poll_interval_func = lambda _: poll_interval # Constant poll interval + self._poll_interval_func = constant_backoff_function(poll_interval) else: self._poll_interval_func = poll_interval self._poll_max_retries = poll_max_retries @@ -197,8 +243,6 @@ class Client: self, method: str, url: str, - *, - _tries: int = 1, **kwargs, ) -> dict: """Perform a request to the Hetzner Cloud API, wrapper around requests.request @@ -208,50 +252,58 @@ class Client: :param timeout: Requests timeout in seconds :return: Response """ - timeout = kwargs.pop("timeout", self._requests_timeout) + kwargs.setdefault("timeout", self._requests_timeout) - response = self._requests_session.request( - method=method, - url=self._api_endpoint + url, - headers=self._get_headers(), - timeout=timeout, - **kwargs, - ) + url = self._api_endpoint + url + headers = self._get_headers() - correlation_id = response.headers.get("X-Correlation-Id") - payload = {} - try: - if len(response.content) > 0: - payload = response.json() - except (TypeError, ValueError) as exc: - raise APIException( - code=response.status_code, - message=response.reason, - details={"content": response.content}, - correlation_id=correlation_id, - ) from exc + retries = 0 + while True: + response = self._requests_session.request( + method=method, + url=url, + headers=headers, + **kwargs, + ) - if not response.ok: - if not payload or "error" not in payload: + correlation_id = response.headers.get("X-Correlation-Id") + payload = {} + try: + if len(response.content) > 0: + payload = response.json() + except (TypeError, ValueError) as exc: raise APIException( code=response.status_code, message=response.reason, details={"content": response.content}, correlation_id=correlation_id, + ) from exc + + if not response.ok: + if not payload or "error" not in payload: + raise APIException( + code=response.status_code, + message=response.reason, + details={"content": response.content}, + correlation_id=correlation_id, + ) + + error: dict = payload["error"] + + if ( + error["code"] == "rate_limit_exceeded" + and retries < self._retry_max_retries + ): + # pylint: disable=too-many-function-args + time.sleep(self._retry_interval(retries)) + retries += 1 + continue + + raise APIException( + code=error["code"], + message=error["message"], + details=error.get("details"), + correlation_id=correlation_id, ) - error: dict = payload["error"] - - if error["code"] == "rate_limit_exceeded" and _tries < 5: - time.sleep(_tries * self._retry_wait_time) - _tries = _tries + 1 - return self.request(method, url, _tries=_tries, **kwargs) - - raise APIException( - code=error["code"], - message=error["message"], - details=error.get("details"), - correlation_id=correlation_id, - ) - - return payload + return payload diff --git a/plugins/module_utils/vendor/hcloud/_version.py b/plugins/module_utils/vendor/hcloud/_version.py index bf6f151..4e4565f 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.0.1" # x-release-please-version +__version__ = "2.1.0" # x-release-please-version diff --git a/plugins/module_utils/vendor/hcloud/actions/domain.py b/plugins/module_utils/vendor/hcloud/actions/domain.py index 16b74ac..af2b298 100644 --- a/plugins/module_utils/vendor/hcloud/actions/domain.py +++ b/plugins/module_utils/vendor/hcloud/actions/domain.py @@ -34,7 +34,7 @@ class Action(BaseDomain): STATUS_ERROR = "error" """Action Status error""" - __slots__ = ( + __api_properties__ = ( "id", "command", "status", @@ -44,6 +44,7 @@ class Action(BaseDomain): "started", "finished", ) + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/certificates/domain.py b/plugins/module_utils/vendor/hcloud/certificates/domain.py index c09c288..390af07 100644 --- a/plugins/module_utils/vendor/hcloud/certificates/domain.py +++ b/plugins/module_utils/vendor/hcloud/certificates/domain.py @@ -34,7 +34,7 @@ class Certificate(BaseDomain, DomainIdentityMixin): :param status: ManagedCertificateStatus Current status of a type managed Certificate, always none for type uploaded Certificates """ - __slots__ = ( + __api_properties__ = ( "id", "name", "certificate", @@ -47,6 +47,8 @@ class Certificate(BaseDomain, DomainIdentityMixin): "type", "status", ) + __slots__ = __api_properties__ + TYPE_UPLOADED = "uploaded" TYPE_MANAGED = "managed" @@ -122,7 +124,8 @@ class CreateManagedCertificateResponse(BaseDomain): Shows the progress of the certificate creation """ - __slots__ = ("certificate", "action") + __api_properties__ = ("certificate", "action") + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/core/domain.py b/plugins/module_utils/vendor/hcloud/core/domain.py index bba954f..d848525 100644 --- a/plugins/module_utils/vendor/hcloud/core/domain.py +++ b/plugins/module_utils/vendor/hcloud/core/domain.py @@ -2,23 +2,22 @@ from __future__ import annotations class BaseDomain: - __slots__ = () + __api_properties__: tuple @classmethod def from_dict(cls, data: dict): # type: ignore[no-untyped-def] """ Build the domain object from the data dict. """ - supported_data = {k: v for k, v in data.items() if k in cls.__slots__} + supported_data = {k: v for k, v in data.items() if k in cls.__api_properties__} return cls(**supported_data) def __repr__(self) -> str: - kwargs = [f"{key}={getattr(self, key)!r}" for key in self.__slots__] # type: ignore[var-annotated] + kwargs = [f"{key}={getattr(self, key)!r}" for key in self.__api_properties__] # type: ignore[var-annotated] return f"{self.__class__.__qualname__}({', '.join(kwargs)})" class DomainIdentityMixin: - __slots__ = () id: int | None name: str | None @@ -54,7 +53,7 @@ class DomainIdentityMixin: class Pagination(BaseDomain): - __slots__ = ( + __api_properties__ = ( "page", "per_page", "previous_page", @@ -62,6 +61,7 @@ class Pagination(BaseDomain): "last_page", "total_entries", ) + __slots__ = __api_properties__ def __init__( self, @@ -81,7 +81,8 @@ class Pagination(BaseDomain): class Meta(BaseDomain): - __slots__ = ("pagination",) + __api_properties__ = ("pagination",) + __slots__ = __api_properties__ def __init__(self, pagination: Pagination | None = None): self.pagination = pagination diff --git a/plugins/module_utils/vendor/hcloud/datacenters/domain.py b/plugins/module_utils/vendor/hcloud/datacenters/domain.py index 05d5f79..badd335 100644 --- a/plugins/module_utils/vendor/hcloud/datacenters/domain.py +++ b/plugins/module_utils/vendor/hcloud/datacenters/domain.py @@ -19,7 +19,8 @@ class Datacenter(BaseDomain, DomainIdentityMixin): :param server_types: :class:`DatacenterServerTypes ` """ - __slots__ = ("id", "name", "description", "location", "server_types") + __api_properties__ = ("id", "name", "description", "location", "server_types") + __slots__ = __api_properties__ def __init__( self, @@ -47,7 +48,8 @@ class DatacenterServerTypes(BaseDomain): All available for migration (change type) server types for this datacenter """ - __slots__ = ("available", "supported", "available_for_migration") + __api_properties__ = ("available", "supported", "available_for_migration") + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/deprecation/domain.py b/plugins/module_utils/vendor/hcloud/deprecation/domain.py index b79e709..3eb7d50 100644 --- a/plugins/module_utils/vendor/hcloud/deprecation/domain.py +++ b/plugins/module_utils/vendor/hcloud/deprecation/domain.py @@ -20,10 +20,11 @@ class DeprecationInfo(BaseDomain): new servers with this image after the mentioned date. """ - __slots__ = ( + __api_properties__ = ( "announced", "unavailable_after", ) + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/firewalls/domain.py b/plugins/module_utils/vendor/hcloud/firewalls/domain.py index d637231..231dbf4 100644 --- a/plugins/module_utils/vendor/hcloud/firewalls/domain.py +++ b/plugins/module_utils/vendor/hcloud/firewalls/domain.py @@ -32,7 +32,8 @@ class Firewall(BaseDomain, DomainIdentityMixin): Point in time when the image was created """ - __slots__ = ("id", "name", "labels", "rules", "applied_to", "created") + __api_properties__ = ("id", "name", "labels", "rules", "applied_to", "created") + __slots__ = __api_properties__ def __init__( self, @@ -69,7 +70,7 @@ class FirewallRule(BaseDomain): Short description of the firewall rule """ - __slots__ = ( + __api_properties__ = ( "direction", "port", "protocol", @@ -77,6 +78,7 @@ class FirewallRule(BaseDomain): "destination_ips", "description", ) + __slots__ = __api_properties__ DIRECTION_IN = "in" """Firewall Rule Direction In""" @@ -141,7 +143,8 @@ class FirewallResource(BaseDomain): applied to. """ - __slots__ = ("type", "server", "label_selector", "applied_to_resources") + __api_properties__ = ("type", "server", "label_selector", "applied_to_resources") + __slots__ = __api_properties__ TYPE_SERVER = "server" """Firewall Used By Type Server""" @@ -180,7 +183,8 @@ class FirewallResourceAppliedToResources(BaseDomain): :param server: Server the Firewall is applied to """ - __slots__ = ("type", "server") + __api_properties__ = ("type", "server") + __slots__ = __api_properties__ def __init__( self, @@ -210,7 +214,8 @@ class CreateFirewallResponse(BaseDomain): The Action which shows the progress of the Firewall Creation """ - __slots__ = ("firewall", "actions") + __api_properties__ = ("firewall", "actions") + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/floating_ips/domain.py b/plugins/module_utils/vendor/hcloud/floating_ips/domain.py index abd2c13..e2ef74a 100644 --- a/plugins/module_utils/vendor/hcloud/floating_ips/domain.py +++ b/plugins/module_utils/vendor/hcloud/floating_ips/domain.py @@ -45,7 +45,7 @@ class FloatingIP(BaseDomain, DomainIdentityMixin): Name of the Floating IP """ - __slots__ = ( + __api_properties__ = ( "id", "type", "description", @@ -59,6 +59,7 @@ class FloatingIP(BaseDomain, DomainIdentityMixin): "name", "created", ) + __slots__ = __api_properties__ def __init__( self, @@ -98,7 +99,8 @@ class CreateFloatingIPResponse(BaseDomain): The Action which shows the progress of the Floating IP Creation """ - __slots__ = ("floating_ip", "action") + __api_properties__ = ("floating_ip", "action") + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/images/domain.py b/plugins/module_utils/vendor/hcloud/images/domain.py index 9a58a3c..907fa7b 100644 --- a/plugins/module_utils/vendor/hcloud/images/domain.py +++ b/plugins/module_utils/vendor/hcloud/images/domain.py @@ -54,7 +54,7 @@ class Image(BaseDomain, DomainIdentityMixin): User-defined labels (key-value pairs) """ - __slots__ = ( + __api_properties__ = ( "id", "name", "type", @@ -73,6 +73,7 @@ class Image(BaseDomain, DomainIdentityMixin): "created", "deprecated", ) + __slots__ = __api_properties__ # pylint: disable=too-many-locals def __init__( @@ -123,7 +124,8 @@ class CreateImageResponse(BaseDomain): The Action which shows the progress of the Floating IP Creation """ - __slots__ = ("action", "image") + __api_properties__ = ("action", "image") + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/isos/domain.py b/plugins/module_utils/vendor/hcloud/isos/domain.py index b2f4d30..2a5667e 100644 --- a/plugins/module_utils/vendor/hcloud/isos/domain.py +++ b/plugins/module_utils/vendor/hcloud/isos/domain.py @@ -27,7 +27,7 @@ class Iso(BaseDomain, DomainIdentityMixin): deprecated. If it has a value, it is considered deprecated. """ - __slots__ = ( + __api_properties__ = ( "id", "name", "type", @@ -35,6 +35,7 @@ class Iso(BaseDomain, DomainIdentityMixin): "description", "deprecation", ) + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/load_balancer_types/domain.py b/plugins/module_utils/vendor/hcloud/load_balancer_types/domain.py index 35719db..6ef4c28 100644 --- a/plugins/module_utils/vendor/hcloud/load_balancer_types/domain.py +++ b/plugins/module_utils/vendor/hcloud/load_balancer_types/domain.py @@ -25,7 +25,7 @@ class LoadBalancerType(BaseDomain, DomainIdentityMixin): """ - __slots__ = ( + __api_properties__ = ( "id", "name", "description", @@ -35,6 +35,7 @@ class LoadBalancerType(BaseDomain, DomainIdentityMixin): "max_assigned_certificates", "prices", ) + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/load_balancers/domain.py b/plugins/module_utils/vendor/hcloud/load_balancers/domain.py index 76e8db3..22a03bf 100644 --- a/plugins/module_utils/vendor/hcloud/load_balancers/domain.py +++ b/plugins/module_utils/vendor/hcloud/load_balancers/domain.py @@ -55,7 +55,7 @@ class LoadBalancer(BaseDomain, DomainIdentityMixin): Free Traffic for the current billing period in bytes """ - __slots__ = ( + __api_properties__ = ( "id", "name", "public_net", @@ -72,6 +72,7 @@ class LoadBalancer(BaseDomain, DomainIdentityMixin): "ingoing_traffic", "included_traffic", ) + __slots__ = __api_properties__ # pylint: disable=too-many-locals def __init__( @@ -425,7 +426,8 @@ class PublicNetwork(BaseDomain): :param enabled: boolean """ - __slots__ = ("ipv4", "ipv6", "enabled") + __api_properties__ = ("ipv4", "ipv6", "enabled") + __slots__ = __api_properties__ def __init__( self, @@ -445,7 +447,8 @@ class IPv4Address(BaseDomain): The IPv4 Address """ - __slots__ = ("ip", "dns_ptr") + __api_properties__ = ("ip", "dns_ptr") + __slots__ = __api_properties__ def __init__( self, @@ -463,7 +466,8 @@ class IPv6Network(BaseDomain): The IPv6 Network as CIDR Notation """ - __slots__ = ("ip", "dns_ptr") + __api_properties__ = ("ip", "dns_ptr") + __slots__ = __api_properties__ def __init__( self, @@ -483,7 +487,8 @@ class PrivateNet(BaseDomain): The main IP Address of the LoadBalancer in the Network """ - __slots__ = ("network", "ip") + __api_properties__ = ("network", "ip") + __slots__ = __api_properties__ def __init__( self, @@ -503,7 +508,8 @@ class CreateLoadBalancerResponse(BaseDomain): Shows the progress of the Load Balancer creation """ - __slots__ = ("load_balancer", "action") + __api_properties__ = ("load_balancer", "action") + __slots__ = __api_properties__ def __init__( self, @@ -528,7 +534,8 @@ class GetMetricsResponse(BaseDomain): :param metrics: The Load Balancer metrics """ - __slots__ = ("metrics",) + __api_properties__ = ("metrics",) + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/locations/domain.py b/plugins/module_utils/vendor/hcloud/locations/domain.py index 7d4af22..dcdf7a9 100644 --- a/plugins/module_utils/vendor/hcloud/locations/domain.py +++ b/plugins/module_utils/vendor/hcloud/locations/domain.py @@ -24,7 +24,7 @@ class Location(BaseDomain, DomainIdentityMixin): Name of network zone this location resides in """ - __slots__ = ( + __api_properties__ = ( "id", "name", "description", @@ -34,6 +34,7 @@ class Location(BaseDomain, DomainIdentityMixin): "longitude", "network_zone", ) + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/metrics/domain.py b/plugins/module_utils/vendor/hcloud/metrics/domain.py index a9e7377..940283a 100644 --- a/plugins/module_utils/vendor/hcloud/metrics/domain.py +++ b/plugins/module_utils/vendor/hcloud/metrics/domain.py @@ -29,12 +29,13 @@ class Metrics(BaseDomain): step: float time_series: TimeSeries - __slots__ = ( + __api_properties__ = ( "start", "end", "step", "time_series", ) + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/networks/domain.py b/plugins/module_utils/vendor/hcloud/networks/domain.py index e04de27..7dac858 100644 --- a/plugins/module_utils/vendor/hcloud/networks/domain.py +++ b/plugins/module_utils/vendor/hcloud/networks/domain.py @@ -38,7 +38,7 @@ class Network(BaseDomain, DomainIdentityMixin): User-defined labels (key-value pairs) """ - __slots__ = ( + __api_properties__ = ( "id", "name", "ip_range", @@ -50,6 +50,7 @@ class Network(BaseDomain, DomainIdentityMixin): "labels", "created", ) + __slots__ = __api_properties__ def __init__( self, @@ -97,7 +98,9 @@ class NetworkSubnet(BaseDomain): """Subnet Type cloud""" TYPE_VSWITCH = "vswitch" """Subnet Type vSwitch""" - __slots__ = ("type", "ip_range", "network_zone", "gateway", "vswitch_id") + + __api_properties__ = ("type", "ip_range", "network_zone", "gateway", "vswitch_id") + __slots__ = __api_properties__ def __init__( self, @@ -123,7 +126,8 @@ class NetworkRoute(BaseDomain): Gateway for the route. """ - __slots__ = ("destination", "gateway") + __api_properties__ = ("destination", "gateway") + __slots__ = __api_properties__ def __init__(self, destination: str, gateway: str): self.destination = destination @@ -139,7 +143,8 @@ class CreateNetworkResponse(BaseDomain): The Action which shows the progress of the network Creation """ - __slots__ = ("network", "action") + __api_properties__ = ("network", "action") + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/placement_groups/domain.py b/plugins/module_utils/vendor/hcloud/placement_groups/domain.py index 1c6fc04..950eeba 100644 --- a/plugins/module_utils/vendor/hcloud/placement_groups/domain.py +++ b/plugins/module_utils/vendor/hcloud/placement_groups/domain.py @@ -31,7 +31,8 @@ class PlacementGroup(BaseDomain, DomainIdentityMixin): Point in time when the image was created """ - __slots__ = ("id", "name", "labels", "servers", "type", "created") + __api_properties__ = ("id", "name", "labels", "servers", "type", "created") + __slots__ = __api_properties__ """Placement Group type spread spreads all servers in the group on different vhosts @@ -64,7 +65,8 @@ class CreatePlacementGroupResponse(BaseDomain): The Action which shows the progress of the Placement Group Creation """ - __slots__ = ("placement_group", "action") + __api_properties__ = ("placement_group", "action") + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/primary_ips/domain.py b/plugins/module_utils/vendor/hcloud/primary_ips/domain.py index 2eebace..83e5d7b 100644 --- a/plugins/module_utils/vendor/hcloud/primary_ips/domain.py +++ b/plugins/module_utils/vendor/hcloud/primary_ips/domain.py @@ -46,7 +46,7 @@ class PrimaryIP(BaseDomain, DomainIdentityMixin): Delete the Primary IP when the Assignee it is assigned to is deleted. """ - __slots__ = ( + __api_properties__ = ( "id", "ip", "type", @@ -61,6 +61,7 @@ class PrimaryIP(BaseDomain, DomainIdentityMixin): "assignee_type", "auto_delete", ) + __slots__ = __api_properties__ def __init__( self, @@ -102,7 +103,8 @@ class CreatePrimaryIPResponse(BaseDomain): The Action which shows the progress of the Primary IP Creation """ - __slots__ = ("primary_ip", "action") + __api_properties__ = ("primary_ip", "action") + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/server_types/domain.py b/plugins/module_utils/vendor/hcloud/server_types/domain.py index ab2553b..d026f86 100644 --- a/plugins/module_utils/vendor/hcloud/server_types/domain.py +++ b/plugins/module_utils/vendor/hcloud/server_types/domain.py @@ -1,5 +1,7 @@ from __future__ import annotations +import warnings + from ..core import BaseDomain, DomainIdentityMixin from ..deprecation import DeprecationInfo @@ -36,7 +38,7 @@ class ServerType(BaseDomain, DomainIdentityMixin): Free traffic per month in bytes """ - __slots__ = ( + __properties__ = ( "id", "name", "description", @@ -49,8 +51,15 @@ class ServerType(BaseDomain, DomainIdentityMixin): "architecture", "deprecated", "deprecation", + ) + __api_properties__ = ( + *__properties__, "included_traffic", ) + __slots__ = ( + *__properties__, + "_included_traffic", + ) def __init__( self, @@ -83,3 +92,25 @@ class ServerType(BaseDomain, DomainIdentityMixin): DeprecationInfo.from_dict(deprecation) if deprecation is not None else None ) self.included_traffic = included_traffic + + @property + def included_traffic(self) -> int | None: + """ + .. deprecated:: 2.1.0 + The 'included_traffic' property is deprecated and will be set to 'None' on 5 August 2024. + Please refer to the 'prices' property instead. + + See https://docs.hetzner.cloud/changelog#2024-07-25-cloud-api-returns-traffic-information-in-different-format. + """ + warnings.warn( + "The 'included_traffic' property is deprecated and will be set to 'None' on 5 August 2024. " + "Please refer to the 'prices' property instead. " + "See https://docs.hetzner.cloud/changelog#2024-07-25-cloud-api-returns-traffic-information-in-different-format", + DeprecationWarning, + stacklevel=2, + ) + return self._included_traffic + + @included_traffic.setter + def included_traffic(self, value: int | None) -> None: + self._included_traffic = value diff --git a/plugins/module_utils/vendor/hcloud/servers/domain.py b/plugins/module_utils/vendor/hcloud/servers/domain.py index d5e769e..349c8dc 100644 --- a/plugins/module_utils/vendor/hcloud/servers/domain.py +++ b/plugins/module_utils/vendor/hcloud/servers/domain.py @@ -84,7 +84,8 @@ class Server(BaseDomain, DomainIdentityMixin): """Server Status rebuilding""" STATUS_UNKNOWN = "unknown" """Server Status unknown""" - __slots__ = ( + + __api_properties__ = ( "id", "name", "status", @@ -107,6 +108,7 @@ class Server(BaseDomain, DomainIdentityMixin): "primary_disk_size", "placement_group", ) + __slots__ = __api_properties__ # pylint: disable=too-many-locals def __init__( @@ -169,7 +171,8 @@ class CreateServerResponse(BaseDomain): The root password of the server if no SSH-Key was given on server creation """ - __slots__ = ("server", "action", "next_actions", "root_password") + __api_properties__ = ("server", "action", "next_actions", "root_password") + __slots__ = __api_properties__ def __init__( self, @@ -193,7 +196,8 @@ class ResetPasswordResponse(BaseDomain): The root password of the server """ - __slots__ = ("action", "root_password") + __api_properties__ = ("action", "root_password") + __slots__ = __api_properties__ def __init__( self, @@ -213,7 +217,8 @@ class EnableRescueResponse(BaseDomain): The root password of the server in the rescue mode """ - __slots__ = ("action", "root_password") + __api_properties__ = ("action", "root_password") + __slots__ = __api_properties__ def __init__( self, @@ -235,7 +240,8 @@ class RequestConsoleResponse(BaseDomain): VNC password to use for this connection. This password only works in combination with a wss_url with valid token. """ - __slots__ = ("action", "wss_url", "password") + __api_properties__ = ("action", "wss_url", "password") + __slots__ = __api_properties__ def __init__( self, @@ -255,7 +261,8 @@ class RebuildResponse(BaseDomain): :param root_password: The root password of the server when not using SSH keys """ - __slots__ = ("action", "root_password") + __api_properties__ = ("action", "root_password") + __slots__ = __api_properties__ def __init__( self, @@ -277,7 +284,7 @@ class PublicNetwork(BaseDomain): :param firewalls: List[:class:`PublicNetworkFirewall `] """ - __slots__ = ( + __api_properties__ = ( "ipv4", "ipv6", "floating_ips", @@ -285,6 +292,7 @@ class PublicNetwork(BaseDomain): "primary_ipv4", "primary_ipv6", ) + __slots__ = __api_properties__ def __init__( self, @@ -310,7 +318,8 @@ class PublicNetworkFirewall(BaseDomain): :param status: str """ - __slots__ = ("firewall", "status") + __api_properties__ = ("firewall", "status") + __slots__ = __api_properties__ STATUS_APPLIED = "applied" """Public Network Firewall Status applied""" @@ -337,7 +346,8 @@ class IPv4Address(BaseDomain): DNS PTR for the ip """ - __slots__ = ("ip", "blocked", "dns_ptr") + __api_properties__ = ("ip", "blocked", "dns_ptr") + __slots__ = __api_properties__ def __init__( self, @@ -365,7 +375,8 @@ class IPv6Network(BaseDomain): The network mask """ - __slots__ = ("ip", "blocked", "dns_ptr", "network", "network_mask") + __api_properties__ = ("ip", "blocked", "dns_ptr", "network", "network_mask") + __slots__ = __api_properties__ def __init__( self, @@ -394,7 +405,8 @@ class PrivateNet(BaseDomain): The mac address of the interface on the server """ - __slots__ = ("network", "ip", "alias_ips", "mac_address") + __api_properties__ = ("network", "ip", "alias_ips", "mac_address") + __slots__ = __api_properties__ def __init__( self, @@ -418,7 +430,8 @@ class ServerCreatePublicNetwork(BaseDomain): :param enable_ipv6: bool """ - __slots__ = ("ipv4", "ipv6", "enable_ipv4", "enable_ipv6") + __api_properties__ = ("ipv4", "ipv6", "enable_ipv4", "enable_ipv6") + __slots__ = __api_properties__ def __init__( self, @@ -446,7 +459,8 @@ class GetMetricsResponse(BaseDomain): :param metrics: The Server metrics """ - __slots__ = ("metrics",) + __api_properties__ = ("metrics",) + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/ssh_keys/domain.py b/plugins/module_utils/vendor/hcloud/ssh_keys/domain.py index 3c880c4..2297b6b 100644 --- a/plugins/module_utils/vendor/hcloud/ssh_keys/domain.py +++ b/plugins/module_utils/vendor/hcloud/ssh_keys/domain.py @@ -25,7 +25,15 @@ class SSHKey(BaseDomain, DomainIdentityMixin): Point in time when the SSH Key was created """ - __slots__ = ("id", "name", "fingerprint", "public_key", "labels", "created") + __api_properties__ = ( + "id", + "name", + "fingerprint", + "public_key", + "labels", + "created", + ) + __slots__ = __api_properties__ def __init__( self, diff --git a/plugins/module_utils/vendor/hcloud/volumes/domain.py b/plugins/module_utils/vendor/hcloud/volumes/domain.py index 7eb5440..adfd661 100644 --- a/plugins/module_utils/vendor/hcloud/volumes/domain.py +++ b/plugins/module_utils/vendor/hcloud/volumes/domain.py @@ -48,7 +48,7 @@ class Volume(BaseDomain, DomainIdentityMixin): STATUS_AVAILABLE = "available" """Volume Status available""" - __slots__ = ( + __api_properties__ = ( "id", "name", "server", @@ -61,6 +61,7 @@ class Volume(BaseDomain, DomainIdentityMixin): "status", "created", ) + __slots__ = __api_properties__ def __init__( self, @@ -100,7 +101,8 @@ class CreateVolumeResponse(BaseDomain): List of actions that are performed after the creation, like attaching to a server """ - __slots__ = ("volume", "action", "next_actions") + __api_properties__ = ("volume", "action", "next_actions") + __slots__ = __api_properties__ def __init__( self, diff --git a/scripts/vendor.py b/scripts/vendor.py index 6ff12ad..aaff31a 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.0.1" +HCLOUD_VERSION = "v2.1.0" HCLOUD_VENDOR_PATH = "plugins/module_utils/vendor/hcloud"